bindbox-game/internal/service/user/points_consume.go
邹方成 45815bfb7d chore: 清理无用文件与优化代码结构
refactor(utils): 修复密码哈希比较逻辑错误
feat(user): 新增按状态筛选优惠券接口
docs: 添加虚拟发货与任务中心相关文档
fix(wechat): 修正Code2Session上下文传递问题
test: 补充订单折扣与积分转换测试用例
build: 更新配置文件与构建脚本
style: 清理多余的空行与注释
2025-12-18 17:35:55 +08:00

82 lines
3.0 KiB
Go
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"
"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
}