feat: add coupon support to orders and create user_coupons model

- Added CouponID field to Order model to track used coupons.
- Updated order query generation to include CouponID.
- Introduced UserCoupon model to manage user coupon associations.
- Implemented query methods for UserCoupon to facilitate CRUD operations.
- Updated query context and default query setup to include UserCoupon.
This commit is contained in:
2025-12-30 17:28:21 +08:00
parent 69d750800c
commit dbfb08ed37
14 changed files with 1454 additions and 35 deletions

View File

@@ -91,11 +91,30 @@ func (s *order) Create(ctx context.Context, form *transaction_dto.OrderCreateFor
price, err := models.ContentPriceQuery.WithContext(ctx).Where(models.ContentPriceQuery.ContentID.Eq(cid)).First()
if err != nil {
// If price missing, treat as error? Or maybe 0?
// Better to require price record.
return nil, errorx.ErrDataCorrupted.WithCause(err).WithMsg("价格信息缺失")
}
amountOriginal := price.PriceAmount
var amountDiscount int64 = 0
var couponID int64 = 0
// Validate Coupon
if form.UserCouponID != "" {
ucid := cast.ToInt64(form.UserCouponID)
discount, err := Coupon.Validate(ctx, uid, ucid, amountOriginal)
if err != nil {
return nil, err
}
amountDiscount = discount
uc, err := models.UserCouponQuery.WithContext(ctx).Where(models.UserCouponQuery.ID.Eq(ucid)).First()
if err == nil {
couponID = uc.CouponID
}
}
amountPaid := amountOriginal - amountDiscount
// 2. Create Order (Status: Created)
order := &models.Order{
TenantID: content.TenantID,
@@ -103,27 +122,46 @@ func (s *order) Create(ctx context.Context, form *transaction_dto.OrderCreateFor
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusCreated,
Currency: consts.Currency(price.Currency),
AmountOriginal: price.PriceAmount,
AmountDiscount: 0,
AmountPaid: price.PriceAmount,
AmountOriginal: amountOriginal,
AmountDiscount: amountDiscount,
AmountPaid: amountPaid,
CouponID: couponID,
IdempotencyKey: uuid.NewString(),
Snapshot: types.NewJSONType(fields.OrdersSnapshot{}),
}
if err := models.OrderQuery.WithContext(ctx).Create(order); err != nil {
return nil, errorx.ErrDatabaseError.WithCause(err)
}
err = models.Q.Transaction(func(tx *models.Query) error {
if err := tx.Order.WithContext(ctx).Create(order); err != nil {
return err
}
// 3. Create Order Item
item := &models.OrderItem{
TenantID: content.TenantID,
UserID: uid,
OrderID: order.ID,
ContentID: cid,
ContentUserID: content.UserID,
AmountPaid: order.AmountPaid,
}
if err := models.OrderItemQuery.WithContext(ctx).Create(item); err != nil {
// 3. Create Order Item
item := &models.OrderItem{
TenantID: content.TenantID,
UserID: uid,
OrderID: order.ID,
ContentID: cid,
ContentUserID: content.UserID,
AmountPaid: amountPaid,
}
if err := tx.OrderItem.WithContext(ctx).Create(item); err != nil {
return err
}
// Mark Coupon Used
if form.UserCouponID != "" {
if err := Coupon.MarkUsed(ctx, tx, cast.ToInt64(form.UserCouponID), order.ID); err != nil {
return err
}
}
return nil
})
if err != nil {
if _, ok := err.(*errorx.AppError); ok {
return nil, err
}
return nil, errorx.ErrDatabaseError.WithCause(err)
}