feat(order): 重构退款全流程并新增申请退款中状态
- 订单状态新增「6 申请退款中」,用户申请退款原子流转并落待审核退款流水 - 退款失败回退订单至已支付并恢复被取消的权益发放任务 - 新增虚拟支付退款查单兜底任务,反查超时订单并自动订正 - 会员包来源额度不叠加,扣减/回退/回收口径统一为只取生效一份 - 退款回收流水按吊销前后有效剩余差值记账,避免无效回收记录 - 同步更新 README 与 Stitch 设计文档
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/mysqlmodel"
|
||||
)
|
||||
|
||||
// memberGrantFixture 构造会员包来源(source=1)额度凭证。
|
||||
func memberGrantFixture(id, amount, used int64) mysqlmodel.QuotaGrant {
|
||||
return mysqlmodel.QuotaGrant{ID: id, Source: QuotaGrantSourceMember, Amount: amount, Used: used}
|
||||
}
|
||||
|
||||
// otherGrantFixture 构造非会员包来源(加量包/广告/体验)额度凭证。
|
||||
func otherGrantFixture(id int64, source int8, amount, used int64) mysqlmodel.QuotaGrant {
|
||||
return mysqlmodel.QuotaGrant{ID: id, Source: source, Amount: amount, Used: used}
|
||||
}
|
||||
|
||||
func TestPickEffectiveMemberGrant(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
grants []mysqlmodel.QuotaGrant
|
||||
wantID int64 // 0 表示期望无生效份(nil)
|
||||
}{
|
||||
{
|
||||
name: "月度年度同额只取一份且保留正在使用的份",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 30), memberGrantFixture(2, 100, 0)},
|
||||
wantID: 1,
|
||||
},
|
||||
{
|
||||
name: "额度不同时取额度最大的一份",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 0), memberGrantFixture(2, 200, 0)},
|
||||
wantID: 2,
|
||||
},
|
||||
{
|
||||
name: "旧包用尽后顺延到新购的一份",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 100), memberGrantFixture(2, 100, 0)},
|
||||
wantID: 2,
|
||||
},
|
||||
{
|
||||
name: "同额同用量时优先新购",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 0), memberGrantFixture(2, 100, 0)},
|
||||
wantID: 2,
|
||||
},
|
||||
{
|
||||
name: "无会员包凭证时返回 nil",
|
||||
grants: []mysqlmodel.QuotaGrant{otherGrantFixture(1, QuotaGrantSourceAddon, 1000, 0), otherGrantFixture(2, QuotaGrantSourceTrial, 100, 0)},
|
||||
wantID: 0,
|
||||
},
|
||||
{
|
||||
name: "会员包全部用尽时返回 nil",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 100), memberGrantFixture(2, 50, 50)},
|
||||
wantID: 0,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := pickEffectiveMemberGrant(tc.grants)
|
||||
if tc.wantID == 0 {
|
||||
if got != nil {
|
||||
t.Fatalf("want nil, got id=%d", got.ID)
|
||||
}
|
||||
return
|
||||
}
|
||||
if got == nil || got.ID != tc.wantID {
|
||||
t.Fatalf("want id=%d, got %+v", tc.wantID, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPickMemberGrantForRefund(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
grants []mysqlmodel.QuotaGrant
|
||||
handled map[int64]bool
|
||||
wantID int64
|
||||
}{
|
||||
{
|
||||
name: "优先回退当前生效份",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 40), memberGrantFixture(2, 100, 10)},
|
||||
wantID: 1,
|
||||
},
|
||||
{
|
||||
name: "生效份未消耗时复活刚被扣尽的份",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 100), memberGrantFixture(2, 100, 0)},
|
||||
wantID: 1,
|
||||
},
|
||||
{
|
||||
name: "已处理的份不重复回退",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 40), memberGrantFixture(2, 100, 10)},
|
||||
handled: map[int64]bool{1: true},
|
||||
wantID: 2,
|
||||
},
|
||||
{
|
||||
name: "无可退额度时返回 nil",
|
||||
grants: []mysqlmodel.QuotaGrant{memberGrantFixture(1, 100, 0)},
|
||||
wantID: 0,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := pickMemberGrantForRefund(tc.grants, tc.handled)
|
||||
if tc.wantID == 0 {
|
||||
if got != nil {
|
||||
t.Fatalf("want nil, got id=%d", got.ID)
|
||||
}
|
||||
return
|
||||
}
|
||||
if got == nil || got.ID != tc.wantID {
|
||||
t.Fatalf("want id=%d, got %+v", tc.wantID, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user