refactor(utils): 修复密码哈希比较逻辑错误 feat(user): 新增按状态筛选优惠券接口 docs: 添加虚拟发货与任务中心相关文档 fix(wechat): 修正Code2Session上下文传递问题 test: 补充订单折扣与积分转换测试用例 build: 更新配置文件与构建脚本 style: 清理多余的空行与注释
82 lines
3.0 KiB
Go
82 lines
3.0 KiB
Go
package user
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"time"
|
||
|
||
"bindbox-game/internal/repository/mysql/dao"
|
||
"bindbox-game/internal/repository/mysql/model"
|
||
|
||
"gorm.io/gorm/clause"
|
||
)
|
||
|
||
// ConsumePoints 扣减用户积分用于订单支付,按有效期优先扣减,返回扣减流水ID
|
||
func (s *service) ConsumePoints(ctx context.Context, userID int64, points int64, orderNo string) (int64, error) {
|
||
if points <= 0 {
|
||
return 0, nil
|
||
}
|
||
var ledgerID int64
|
||
err := s.writeDB.Transaction(func(tx *dao.Query) error {
|
||
rows, err := tx.UserPoints.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.UserPoints.UserID.Eq(userID)).Order(tx.UserPoints.ValidEnd.Asc()).Find()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
remain := points
|
||
now := time.Now()
|
||
for _, r := range rows {
|
||
if !r.ValidEnd.IsZero() && r.ValidEnd.Before(now) {
|
||
continue
|
||
}
|
||
if remain <= 0 {
|
||
break
|
||
}
|
||
use := r.Points
|
||
if use > remain {
|
||
use = remain
|
||
}
|
||
_, err := tx.UserPoints.WithContext(ctx).Where(tx.UserPoints.ID.Eq(r.ID)).Updates(map[string]any{"points": r.Points - use})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
remain -= use
|
||
}
|
||
if remain > 0 {
|
||
return errors.New("insufficient_points")
|
||
}
|
||
// 记录扣减流水(负数)
|
||
led := &model.UserPointsLedger{UserID: userID, Action: "consume_order", Points: -points, RefTable: "orders", RefID: orderNo, Remark: "consume by lottery"}
|
||
if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
|
||
return err
|
||
}
|
||
ledgerID = led.ID
|
||
return nil
|
||
})
|
||
return ledgerID, err
|
||
}
|
||
|
||
// RefundPoints 退款积分(退回扣减),返回退款流水ID
|
||
func (s *service) RefundPoints(ctx context.Context, userID int64, points int64, orderNo string, reason string) (int64, error) {
|
||
var ledgerID int64
|
||
err := s.writeDB.Transaction(func(tx *dao.Query) error {
|
||
// 累加到默认积分条目
|
||
existing, _ := tx.UserPoints.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.UserPoints.UserID.Eq(userID)).First()
|
||
if existing == nil {
|
||
if err := tx.UserPoints.WithContext(ctx).Omit(tx.UserPoints.ValidEnd).Create(&model.UserPoints{UserID: userID, Points: points}); err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
if _, err := tx.UserPoints.WithContext(ctx).Where(tx.UserPoints.ID.Eq(existing.ID)).Updates(map[string]any{"points": existing.Points + points}); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
led := &model.UserPointsLedger{UserID: userID, Action: "refund_points", Points: points, RefTable: "orders", RefID: orderNo, Remark: reason}
|
||
if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
|
||
return err
|
||
}
|
||
ledgerID = led.ID
|
||
return nil
|
||
})
|
||
return ledgerID, err
|
||
}
|