fix(backend): 特惠限次 webhook 兜底——第二笔已支付特惠单只标 paid 不叠加时长
按 pay-contract 看板要求:续期入账前事务内再查本店是否已有另一笔 paid 的 promo_first_month(防绕过前端/并发双买);命中则跳过 entitle、记 ALERT 告警, 回调仍回 SUCCESS(钱已收,退款人工处理)。补对应测试(双买不叠加/正常套餐不受影响)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
@@ -311,6 +311,47 @@ func TestCreatePurchase_PromoOncePerShop(t *testing.T) {
|
||||
assert.False(t, used)
|
||||
}
|
||||
|
||||
// webhook 兜底(契约 INTEGRATION-BOARD):并发/绕过前端产生第二笔特惠单时,
|
||||
// 回调仍回 SUCCESS 并标 paid(钱已收),但不叠加时长,防止绕过购买接口的限购。
|
||||
func TestHandleCallback_PromoDoubleClaimNoEntitle(t *testing.T) {
|
||||
db := testutil.SetupTestDB()
|
||||
shop := testutil.CreateTestShop(db, "PAY011")
|
||||
svc := newTestPaySvc(db, "http://pay.invalid")
|
||||
|
||||
// 并发双买:两笔 pending 特惠单同时存在,先后收到回调
|
||||
createPendingPurchase(t, db, shop.ID, PromoBizCode, "1.00", "yanmei-promo-a")
|
||||
createPendingPurchase(t, db, shop.ID, PromoBizCode, "1.00", "yanmei-promo-b")
|
||||
|
||||
body := callbackBody("yanmei-promo-a", PromoBizCode, "1.00")
|
||||
ts, nonce, sign := signedCallbackArgs(body)
|
||||
require.NoError(t, svc.HandleCallback(body, ts, nonce, sign))
|
||||
|
||||
var lic model.License
|
||||
require.NoError(t, db.Where("shop_id = ?", shop.ID).Order("id DESC").First(&lic).Error)
|
||||
expires1 := *lic.ExpiresAt
|
||||
assert.InDelta(t, 30, daysFromNow(lic.ExpiresAt), 1, "第一笔正常续期 30 天")
|
||||
|
||||
// 第二笔回调:标 paid 但不再叠加
|
||||
body2 := callbackBody("yanmei-promo-b", PromoBizCode, "1.00")
|
||||
ts2, nonce2, sign2 := signedCallbackArgs(body2)
|
||||
require.NoError(t, svc.HandleCallback(body2, ts2, nonce2, sign2), "回调须回 SUCCESS,pay 停止重试")
|
||||
|
||||
var p2 model.LicensePurchase
|
||||
require.NoError(t, db.Where("out_trade_no = ?", "yanmei-promo-b").First(&p2).Error)
|
||||
assert.Equal(t, "paid", p2.Status, "第二笔仍标 paid(钱已收,退款人工处理)")
|
||||
|
||||
require.NoError(t, db.Where("shop_id = ?", shop.ID).Order("id DESC").First(&lic).Error)
|
||||
assert.True(t, lic.ExpiresAt.Equal(expires1), "第二笔特惠单不得叠加时长")
|
||||
|
||||
// 兜底只限特惠:同店正常套餐单不受影响
|
||||
createPendingPurchase(t, db, shop.ID, "monthly_standard", "299.00", "yanmei-normal-c")
|
||||
body3 := callbackBody("yanmei-normal-c", "monthly_standard", "299.00")
|
||||
ts3, nonce3, sign3 := signedCallbackArgs(body3)
|
||||
require.NoError(t, svc.HandleCallback(body3, ts3, nonce3, sign3))
|
||||
require.NoError(t, db.Where("shop_id = ?", shop.ID).Order("id DESC").First(&lic).Error)
|
||||
assert.InDelta(t, 60, daysFromNow(lic.ExpiresAt), 1, "正常套餐照常叠加")
|
||||
}
|
||||
|
||||
// ---------- Status ----------
|
||||
|
||||
func TestStatus_ScopedToShop(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user