115 lines
3.5 KiB
Go

package user
import (
"bindbox-game/internal/repository/mysql/dao"
"bindbox-game/internal/repository/mysql/model"
"context"
"fmt"
"time"
)
// RecordOrderCouponUsage 记录订单使用的用户券与本次抵扣金额
func (s *service) RecordOrderCouponUsage(ctx context.Context, orderID int64, userCouponID int64, appliedAmount int64) error {
if orderID <= 0 || userCouponID <= 0 || appliedAmount <= 0 {
return nil
}
return s.repo.GetDbW().Exec("INSERT INTO order_coupons (order_id, user_coupon_id, applied_amount, created_at) VALUES (?,?,?,NOW(3))", orderID, userCouponID, appliedAmount).Error
}
// DeductCouponsForPaidOrder 支付成功后扣减金额券余额或核销一次性券
func (s *service) DeductCouponsForPaidOrder(ctx context.Context, tx *dao.Query, userID int64, orderID int64, paidAt time.Time) error {
type row struct {
UserCouponID int64
AppliedAmount int64
Status int32
UsedOrderID int64
DiscountType int32
}
var rows []row
// 确定使用的数据库查询对象
db := s.writeDB
if tx != nil {
db = tx
}
readDb := s.readDB
if tx != nil {
readDb = tx
}
// 1. 获取该订单关联的所有优惠券使用记录
_ = readDb.OrderCoupons.WithContext(ctx).UnderlyingDB().Raw("SELECT oc.user_coupon_id AS user_coupon_id, oc.applied_amount AS applied_amount, uc.status AS status, uc.used_order_id AS used_order_id, sc.discount_type AS discount_type FROM order_coupons oc JOIN user_coupons uc ON uc.id=oc.user_coupon_id JOIN system_coupons sc ON sc.id=uc.coupon_id WHERE oc.order_id=?", orderID).Scan(&rows).Error
for _, r := range rows {
// 幂等校验:已核销且绑定本订单,则跳过
if r.Status == 2 && r.UsedOrderID == orderID {
continue
}
var currentBal int64
var ucUserID int64
uc, err := readDb.UserCoupons.WithContext(ctx).Where(readDb.UserCoupons.ID.Eq(r.UserCouponID)).First()
if err != nil || uc == nil {
continue // 或记录日志
}
currentBal = uc.BalanceAmount
ucUserID = uc.UserID
if r.DiscountType == 1 { // 金额券:按量扣减
nb := currentBal - r.AppliedAmount
if nb < 0 {
nb = 0
}
upd := map[string]any{
"balance_amount": nb,
"used_order_id": orderID,
"used_at": paidAt,
}
if nb == 0 {
upd["status"] = 2 // 余额扣完,标记为已完成
}
_, err = db.UserCoupons.WithContext(ctx).Where(db.UserCoupons.ID.Eq(r.UserCouponID)).Updates(upd)
if err != nil {
return fmt.Errorf("failed to update user coupon balance: %w", err)
}
// 记录账变流水
ledger := &model.UserCouponLedger{
UserID: ucUserID,
UserCouponID: r.UserCouponID,
ChangeAmount: -r.AppliedAmount,
BalanceAfter: nb,
OrderID: orderID,
Action: "apply",
CreatedAt: time.Now(),
}
_ = db.UserCouponLedger.WithContext(ctx).Create(ledger)
} else { // 满减/折扣券:一次性核销
_, err = db.UserCoupons.WithContext(ctx).Where(db.UserCoupons.ID.Eq(r.UserCouponID)).Updates(map[string]any{
"status": 2,
"used_order_id": orderID,
"used_at": paidAt,
})
if err != nil {
return fmt.Errorf("failed to verify user coupon: %w", err)
}
// 记录账变流水
ledger := &model.UserCouponLedger{
UserID: ucUserID,
UserCouponID: r.UserCouponID,
ChangeAmount: -r.AppliedAmount,
BalanceAfter: 0,
OrderID: orderID,
Action: "apply",
CreatedAt: time.Now(),
}
_ = db.UserCouponLedger.WithContext(ctx).Create(ledger)
}
}
return nil
}