bindbox-game/internal/service/user/points_consume.go

82 lines
3.0 KiB
Go
Executable File
Raw Permalink 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
}