feat: 添加订单退款功能的测试用例及相关逻辑
This commit is contained in:
@@ -4,13 +4,17 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
jobs_args "quyun/v2/app/jobs/args"
|
||||
"quyun/v2/database"
|
||||
"quyun/v2/providers/job"
|
||||
"quyun/v2/providers/jwt"
|
||||
"quyun/v2/providers/postgres"
|
||||
|
||||
"github.com/riverqueue/river"
|
||||
"go.ipao.vip/atom"
|
||||
"go.ipao.vip/atom/container"
|
||||
"go.ipao.vip/atom/contracts"
|
||||
"go.ipao.vip/atom/opt"
|
||||
"go.uber.org/dig"
|
||||
|
||||
"github.com/rogeecn/fabfile"
|
||||
@@ -22,10 +26,33 @@ func Default(providers ...container.ProviderContainer) container.Providers {
|
||||
postgres.DefaultProvider(),
|
||||
jwt.DefaultProvider(),
|
||||
job.DefaultProvider(),
|
||||
testJobWorkersProvider(),
|
||||
database.DefaultProvider(),
|
||||
}, providers...)
|
||||
}
|
||||
|
||||
type orderRefundTestWorker struct {
|
||||
river.WorkerDefaults[jobs_args.OrderRefundJob]
|
||||
}
|
||||
|
||||
func (w *orderRefundTestWorker) Work(ctx context.Context, job *river.Job[jobs_args.OrderRefundJob]) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func testJobWorkersProvider() container.ProviderContainer {
|
||||
return container.ProviderContainer{
|
||||
Provider: func(opts ...opt.Option) error {
|
||||
return container.Container.Provide(func(__job *job.Job) (contracts.Initial, error) {
|
||||
obj := &orderRefundTestWorker{}
|
||||
if err := river.AddWorkerSafely(__job.Workers, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj, nil
|
||||
}, atom.GroupInitial)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func Serve(providers container.Providers, t *testing.T, invoke any) {
|
||||
Convey("tests boot up", t, func() {
|
||||
// 关键语义:测试用例可能会在同一进程内多次调用 Serve。
|
||||
|
||||
@@ -135,23 +135,25 @@ func (*orderAdmin) adminOrderDetail(
|
||||
return &dto.AdminOrderDetail{Order: m}, nil
|
||||
}
|
||||
|
||||
// adminRefund
|
||||
//
|
||||
// @Summary 订单退款(租户管理)
|
||||
// @Tags Tenant
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param tenantCode path string true "Tenant Code"
|
||||
// @Param orderID path int64 true "OrderID"
|
||||
// @Param form body dto.AdminOrderRefundForm true "Form"
|
||||
// @Success 200 {object} models.Order
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/admin/orders/:orderID/refund [post]
|
||||
// @Bind tenant local key(tenant)
|
||||
// @Bind tenantUser local key(tenant_user)
|
||||
// @Bind orderID path
|
||||
// @Bind form body
|
||||
func (*orderAdmin) adminRefund(
|
||||
// adminRefund
|
||||
//
|
||||
// @Summary 订单退款(租户管理)
|
||||
// @Description 该接口只负责将订单从 paid 推进到 refunding,并提交异步退款任务;退款入账与权益回收由 worker 异步完成。
|
||||
// @Description 重复请求幂等:订单处于 refunding/refunded 时会返回当前订单状态,不会重复入账/重复回收权益。
|
||||
// @Tags Tenant
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param tenantCode path string true "Tenant Code"
|
||||
// @Param orderID path int64 true "OrderID"
|
||||
// @Param form body dto.AdminOrderRefundForm true "Form"
|
||||
// @Success 200 {object} models.Order
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/admin/orders/:orderID/refund [post]
|
||||
// @Bind tenant local key(tenant)
|
||||
// @Bind tenantUser local key(tenant_user)
|
||||
// @Bind orderID path
|
||||
// @Bind form body
|
||||
func (*orderAdmin) adminRefund(
|
||||
ctx fiber.Ctx,
|
||||
tenant *models.Tenant,
|
||||
tenantUser *models.TenantUser,
|
||||
|
||||
@@ -1127,6 +1127,12 @@ func (s *OrderTestSuite) Test_AdminRefundOrder() {
|
||||
So(refunding, ShouldNotBeNil)
|
||||
So(refunding.Status, ShouldEqual, consts.OrderStatusRefunding)
|
||||
|
||||
// refunding 期间重复请求应幂等返回 refunding(并允许重复触发入队,不影响最终结果)。
|
||||
refunding2, err := Order.AdminRefundOrder(ctx, tenantID, operatorUserID, orderModel.ID, false, "原因2", "", now.Add(90*time.Second))
|
||||
So(err, ShouldBeNil)
|
||||
So(refunding2, ShouldNotBeNil)
|
||||
So(refunding2.Status, ShouldEqual, consts.OrderStatusRefunding)
|
||||
|
||||
refunded, err := Order.ProcessRefundingOrder(ctx, &ProcessRefundingOrderParams{
|
||||
TenantID: tenantID,
|
||||
OrderID: orderModel.ID,
|
||||
@@ -1139,6 +1145,19 @@ func (s *OrderTestSuite) Test_AdminRefundOrder() {
|
||||
So(refunded, ShouldNotBeNil)
|
||||
So(refunded.Status, ShouldEqual, consts.OrderStatusRefunded)
|
||||
|
||||
// worker 重试/重复执行应幂等:不重复入账、不重复回收权益。
|
||||
refundedRetry, err := Order.ProcessRefundingOrder(ctx, &ProcessRefundingOrderParams{
|
||||
TenantID: tenantID,
|
||||
OrderID: orderModel.ID,
|
||||
OperatorUserID: operatorUserID,
|
||||
Force: false,
|
||||
Reason: "原因",
|
||||
Now: now.Add(5 * time.Minute),
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
So(refundedRetry, ShouldNotBeNil)
|
||||
So(refundedRetry.Status, ShouldEqual, consts.OrderStatusRefunded)
|
||||
|
||||
var tu models.TenantUser
|
||||
So(_db.WithContext(ctx).Where("tenant_id = ? AND user_id = ?", tenantID, buyerUserID).First(&tu).Error, ShouldBeNil)
|
||||
So(tu.Balance, ShouldEqual, 300)
|
||||
@@ -1162,8 +1181,21 @@ func (s *OrderTestSuite) Test_AdminRefundOrder() {
|
||||
Find(&ledgers).Error, ShouldBeNil)
|
||||
So(len(ledgers), ShouldEqual, 1)
|
||||
})
|
||||
|
||||
Convey("不可重试错误分类应稳定", func() {
|
||||
So(IsRefundJobNonRetryableError(nil), ShouldBeFalse)
|
||||
So(IsRefundJobNonRetryableError(errors.New("x")), ShouldBeFalse)
|
||||
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrInvalidParameter), ShouldBeTrue)
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrRecordNotFound), ShouldBeTrue)
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrStatusConflict), ShouldBeTrue)
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrPreconditionFailed), ShouldBeTrue)
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrPermissionDenied), ShouldBeTrue)
|
||||
|
||||
So(IsRefundJobNonRetryableError(errorx.ErrInternalError), ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *OrderTestSuite) Test_PurchaseContent() {
|
||||
Convey("Order.PurchaseContent", s.T(), func() {
|
||||
|
||||
Reference in New Issue
Block a user