Files
full/module/ec/order/internal/logic/summary/cancel.go
2026-09-22 21:15:34 +08:00

95 lines
2.4 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 summary
import (
"context"
"errors"
"time"
"bsm/full/module/ec/order/internal/impl"
"bsm/full/module/ec/order/internal/models"
pb "bsm/full/module/ec/order/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
"gorm.io/gorm"
)
// 取消订单
func Cancel(ctx context.Context, in *pb.CancelRequest) (reply *pb.OrderStatusReply, err error) {
// parse authorization meta.
_, err = service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
var (
summary = new(models.OrderSummary)
)
err = impl.DBService.Where("order_no = ?", in.OrderNo).First(&summary).Error
if err != nil {
printer.Error(err.Error())
return nil, errcode.ErrDB
}
// 状态机约束:只有"未支付"status=1的订单允许取消其它状态拒绝避免非法状态跃迁。
if summary.Status != 1 {
return nil, errcode.ErrUnavailable
}
details := make([]*models.OrderDetails, 0)
err = impl.DBService.Transaction(func(tx *gorm.DB) error {
// 1. 以状态为条件更新订单,避免并发下重复取消。
result := tx.Model(&models.OrderSummary{}).Where("order_no = ? AND status = ?", in.OrderNo, 1).
Updates(map[string]any{
"status": -1,
"coupon_identity": "",
"coupon_amount": 0,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errcode.ErrUnavailable
}
// 2. 按订单明细的规格回补库存,避免取消后库存丢失。
if err := tx.Where("summary_identity = ?", summary.Identity).Find(&details).Error; err != nil {
return err
}
for _, d := range details {
if d.Number > 0 {
if err := tx.Table("mall_product_spec").Where("id = ?", d.SpecID).
UpdateColumn("stock", gorm.Expr("stock + ?", d.Number)).Error; err != nil {
return err
}
}
}
// 3. 退回已使用的优惠券,使其重新可用。
if summary.CouponIdentity != "" {
if err := tx.Model(&models.OrderCoupon{}).Where("identity = ?", summary.CouponIdentity).
Update("status", 2).Error; err != nil {
return err
}
}
return nil
})
if err != nil {
printer.Error(err.Error())
if errors.Is(err, errcode.ErrUnavailable) {
return nil, errcode.ErrUnavailable
}
return nil, errcode.ErrDB
}
return &pb.OrderStatusReply{
Code: 0,
Identity: summary.Identity,
Message: "OK",
Timeseq: time.Now().UnixNano(),
}, nil
}