fix(distribution): 人工批次窗口期防退款穿透与退款中途金额单调性加固

This commit is contained in:
yml2213
2026-09-10 19:39:27 +08:00
parent 36ebe7a5f1
commit 140c538d4f
5 changed files with 318 additions and 17 deletions
+34 -15
View File
@@ -415,6 +415,15 @@ func (r *Repository) markRefundFailedOrderStatus(ctx context.Context, orderID ui
return r.markOrderRefundFailed(ctx, orderID, refundAmountCent)
}
func refundedTotalTx(tx *gorm.DB, orderID uint64) (int64, error) {
var refundedTotal int64
err := tx.Model(&model.PaymentOrder{}).
Where("order_id = ? AND status = ?", orderID, "refunded").
Where("biz_type IN ?", refundBizTypes).
Select("COALESCE(SUM(amount_cent), 0)").Scan(&refundedTotal).Error
return refundedTotal, err
}
func (r *Repository) updateOrderRefundStatus(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var order model.RentalOrder
@@ -424,11 +433,8 @@ func (r *Repository) updateOrderRefundStatus(ctx context.Context, orderID uint64
// 同一订单可能多笔退款,且退款结果查询会重复回调:
// 以已退款成功流水合计为口径,并取本次金额与累计额的较大值,
// 保证 order.RefundAmountCent 单调不回退、重复回调幂等。
var refundedTotal int64
if err := tx.Model(&model.PaymentOrder{}).
Where("order_id = ? AND status = ?", orderID, "refunded").
Where("biz_type IN ?", refundBizTypes).
Select("COALESCE(SUM(amount_cent), 0)").Scan(&refundedTotal).Error; err != nil {
refundedTotal, err := refundedTotalTx(tx, orderID)
if err != nil {
return err
}
cumulative := max(refundAmountCent, refundedTotal)
@@ -448,18 +454,31 @@ func (r *Repository) updateOrderRefundStatus(ctx context.Context, orderID uint64
})
}
func (r *Repository) markOrderRefunding(ctx context.Context, orderID uint64, refundAmountCent int64) error {
return r.db.WithContext(ctx).Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
"refund_status": "refunding",
"refund_amount_cent": refundAmountCent,
"refunded_at": nil,
}).Error
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
refundedTotal, err := refundedTotalTx(tx, orderID)
if err != nil {
return err
}
cumulative := max(refundAmountCent, refundedTotal)
return tx.Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
"refund_status": "refunding",
"refund_amount_cent": cumulative,
"refunded_at": nil,
}).Error
})
}
func (r *Repository) markOrderRefundFailed(ctx context.Context, orderID uint64, refundAmountCent int64) error {
return r.db.WithContext(ctx).Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
"refund_status": "failed",
"refund_amount_cent": refundAmountCent,
"refunded_at": nil,
}).Error
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
refundedTotal, err := refundedTotalTx(tx, orderID)
if err != nil {
return err
}
return tx.Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
"refund_status": "failed",
"refund_amount_cent": refundedTotal,
"refunded_at": nil,
}).Error
})
}
func (r *Repository) updateRefundRawRequest(ctx context.Context, paymentID uint64, rawRequest map[string]string) error {
if rawRequest == nil {