feat: 支持从失败状态重新发起退款,添加相关逻辑和测试用例

This commit is contained in:
2025-12-23 13:07:12 +08:00
parent d70a33e4f9
commit 39b541accd
4 changed files with 124 additions and 2 deletions

View File

@@ -942,6 +942,77 @@ func (s *OrderTestSuite) Test_AdminRefundOrder() {
So(len(ledgers), ShouldEqual, 1)
})
Convey("failed 状态允许重新发起退款paid/failed -> refunding", func() {
s.truncate(
ctx,
models.TableNameTenantLedger,
models.TableNameContentAccess,
models.TableNameOrderItem,
models.TableNameOrder,
models.TableNameTenantUser,
models.TableNameUser,
)
s.seedTenantUser(ctx, tenantID, buyerUserID, 0, 0)
contentID := int64(123)
orderModel := &models.Order{
TenantID: tenantID,
UserID: buyerUserID,
Type: consts.OrderTypeContentPurchase,
Status: consts.OrderStatusPaid,
Currency: consts.CurrencyCNY,
AmountOriginal: 300,
AmountDiscount: 0,
AmountPaid: 300,
Snapshot: newLegacyOrderSnapshot(),
PaidAt: now,
CreatedAt: now,
UpdatedAt: now,
}
So(orderModel.Create(ctx), ShouldBeNil)
item := &models.OrderItem{
TenantID: tenantID,
UserID: buyerUserID,
OrderID: orderModel.ID,
ContentID: contentID,
ContentUserID: 999,
AmountPaid: 300,
Snapshot: types.NewJSONType(fields.OrderItemsSnapshot{}),
CreatedAt: now,
UpdatedAt: now,
}
So(item.Create(ctx), ShouldBeNil)
access := &models.ContentAccess{
TenantID: tenantID,
UserID: buyerUserID,
ContentID: contentID,
OrderID: orderModel.ID,
Status: consts.ContentAccessStatusActive,
CreatedAt: now,
UpdatedAt: now,
RevokedAt: time.Time{},
}
So(access.Create(ctx), ShouldBeNil)
// 先发起一次退款进入 refunding再模拟异步失败进入 failed。
refunding, err := Order.AdminRefundOrder(ctx, tenantID, operatorUserID, orderModel.ID, false, "原因", "", now.Add(time.Minute))
So(err, ShouldBeNil)
So(refunding.Status, ShouldEqual, consts.OrderStatusRefunding)
So(Order.MarkRefundFailed(ctx, tenantID, orderModel.ID, now.Add(2*time.Minute)), ShouldBeNil)
var failed models.Order
So(_db.WithContext(ctx).Where("tenant_id = ? AND id = ?", tenantID, orderModel.ID).First(&failed).Error, ShouldBeNil)
So(failed.Status, ShouldEqual, consts.OrderStatusFailed)
// failed -> refunding 允许重新发起,并再次入队(幂等)。
refunding2, err := Order.AdminRefundOrder(ctx, tenantID, operatorUserID, orderModel.ID, false, "原因2", "", now.Add(3*time.Minute))
So(err, ShouldBeNil)
So(refunding2.Status, ShouldEqual, consts.OrderStatusRefunding)
})
Convey("不可重试错误分类应稳定", func() {
So(IsRefundJobNonRetryableError(nil), ShouldBeFalse)
So(IsRefundJobNonRetryableError(errors.New("x")), ShouldBeFalse)