feat: 支持从失败状态重新发起退款,添加相关逻辑和测试用例
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user