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

83 lines
2.3 KiB
Go

package user
import (
"context"
"errors"
"time"
"bindbox-game/internal/repository/mysql/dao"
"bindbox-game/internal/repository/mysql/model"
"gorm.io/gorm/clause"
)
// CancelOrder 取消订单
func (s *service) CancelOrder(ctx context.Context, userID int64, orderID int64, reason string) (*model.Orders, error) {
var updatedOrder *model.Orders
err := s.writeDB.Transaction(func(tx *dao.Query) error {
// 1. 查询订单
order, err := tx.Orders.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.Orders.ID.Eq(orderID), tx.Orders.UserID.Eq(userID)).First()
if err != nil {
return err
}
if order == nil {
return errors.New("order not found")
}
// 2. 校验状态
if order.Status != 1 {
return errors.New("order cannot be cancelled")
}
// 3. 退还积分
if order.PointsAmount > 0 {
refundReason := "cancel_order"
if reason != "" {
refundReason = refundReason + ":" + reason
}
// Get Rate
ratePtsPerCent, _ := s.CentsToPoints(ctx, 1)
if ratePtsPerCent <= 0 {
ratePtsPerCent = 1
}
pointsToRefund := order.PointsAmount * ratePtsPerCent
// Update User Points
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: pointsToRefund}); 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 + pointsToRefund}); err != nil {
return err
}
}
// Log
led := &model.UserPointsLedger{UserID: userID, Action: "refund_points", Points: pointsToRefund, RefTable: "orders", RefID: order.OrderNo, Remark: refundReason}
if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
return err
}
}
// 4. 更新订单状态
updates := map[string]any{
tx.Orders.Status.ColumnName().String(): 3,
tx.Orders.CancelledAt.ColumnName().String(): time.Now(),
}
if _, err := tx.Orders.WithContext(ctx).Where(tx.Orders.ID.Eq(order.ID)).Updates(updates); err != nil {
return err
}
updatedOrder = order
updatedOrder.Status = 3
return nil
})
if err != nil {
return nil, err
}
return updatedOrder, nil
}