109 lines
3.3 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"errors"
"fmt"
"time"
"bindbox-game/internal/repository/mysql/model"
"gorm.io/gorm"
)
func (s *service) AddCoupon(ctx context.Context, userID int64, couponID int64) error {
tpl, err := s.readDB.SystemCoupons.WithContext(ctx).Where(s.readDB.SystemCoupons.ID.Eq(couponID)).First()
if err != nil {
return err
}
if tpl == nil || tpl.Status != 1 {
// 模板不存在或未启用
fmt.Printf("[发券] 模板不可用 coupon_id=%d status=%d\n", couponID, func() int32 {
if tpl != nil {
return tpl.Status
}
return -1
}())
return errors.New("coupon not found or disabled")
}
// 配额检查:若 TotalQuantity > 0 则限制发放总量
if tpl.TotalQuantity > 0 {
issued, ierr := s.readDB.UserCoupons.WithContext(ctx).Where(s.readDB.UserCoupons.CouponID.Eq(couponID)).Count()
if ierr != nil {
return ierr
}
if issued >= tpl.TotalQuantity {
fmt.Printf("[发券] 模板配额已满 coupon_id=%d issued=%d total=%d\n", couponID, issued, tpl.TotalQuantity)
return gorm.ErrInvalidData
}
}
// 允许用户重复持有相同模板的未使用优惠券
item := &model.UserCoupons{UserID: userID, CouponID: couponID, Status: 1}
if !tpl.ValidStart.IsZero() {
item.ValidStart = tpl.ValidStart
} else {
item.ValidStart = time.Now()
}
if !tpl.ValidEnd.IsZero() {
item.ValidEnd = tpl.ValidEnd
}
do := s.writeDB.UserCoupons.WithContext(ctx).Omit(s.readDB.UserCoupons.UsedAt, s.readDB.UserCoupons.UsedOrderID)
if tpl.ValidEnd.IsZero() {
do = do.Omit(s.writeDB.UserCoupons.ValidEnd)
}
if err := do.Create(item); err != nil {
return err
}
// 直减金额券初始化余额其他类型余额置0
if tpl.DiscountType == 1 && tpl.DiscountValue > 0 {
_, _ = s.writeDB.UserCoupons.WithContext(ctx).Where(s.writeDB.UserCoupons.ID.Eq(item.ID)).Updates(map[string]any{"balance_amount": tpl.DiscountValue})
} else {
_, _ = s.writeDB.UserCoupons.WithContext(ctx).Where(s.writeDB.UserCoupons.ID.Eq(item.ID)).Updates(map[string]any{"balance_amount": 0})
}
return nil
}
func (s *service) VoidUserCoupon(ctx context.Context, adminID int64, userID int64, userCouponID int64) error {
if userID <= 0 || userCouponID <= 0 {
return fmt.Errorf("invalid_params")
}
uc, err := s.readDB.UserCoupons.WithContext(ctx).
Where(s.readDB.UserCoupons.ID.Eq(userCouponID)).
Where(s.readDB.UserCoupons.UserID.Eq(userID)).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("not_found")
}
return err
}
if uc.Status != 1 {
return fmt.Errorf("invalid_status")
}
db := s.repo.GetDbW()
if uc.BalanceAmount > 0 {
nb := int64(0)
if err := db.Exec("UPDATE user_coupons SET status=?, balance_amount=?, updated_at=NOW(3) WHERE id=? AND user_id=? AND status=1", 3, nb, userCouponID, userID).Error; err != nil {
return err
}
ledger := &model.UserCouponLedger{
UserID: userID,
UserCouponID: userCouponID,
ChangeAmount: -uc.BalanceAmount,
BalanceAfter: nb,
OrderID: 0,
Action: "void_by_admin",
CreatedAt: time.Now(),
}
if err := db.Create(ledger).Error; err != nil {
return err
}
return nil
}
if err := db.Exec("UPDATE user_coupons SET status=?, updated_at=NOW(3) WHERE id=? AND user_id=? AND status=1", 3, userCouponID, userID).Error; err != nil {
return err
}
_ = adminID
return nil
}