feat(backend): pay 下单/查单切 v2 契约——sku 直用 biz_code、session 多态响应、金额 int64 分

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-10 20:33:51 +08:00
parent bc183ab7df
commit a5d7a1dc00
2 changed files with 116 additions and 100 deletions
+25 -13
View File
@@ -229,13 +229,10 @@ func TestCreatePurchase_HappyPath(t *testing.T) {
db := testutil.SetupTestDB()
shop := testutil.CreateTestShop(db, "PAY006")
// 假 pay 服务:/products 列表 + /orders 验签后返回 pay_url
// 假 pay v2 服务:POST /api/v2/orders 验签后返回 sessionredirect+ GET /api/v2/orders/:no 回填金额
mux := http.NewServeMux()
mux.HandleFunc("GET /api/v1/products", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"data":[{"id":3,"biz_code":"annual_standard"},{"id":4,"biz_code":"monthly_pro"}]}`)
})
var gotBizRef, gotClientType string
mux.HandleFunc("POST /api/v1/orders", func(w http.ResponseWriter, r *http.Request) {
var gotSku, gotMethod, gotBizSystem, gotBizRef string
mux.HandleFunc("POST /api/v2/orders", func(w http.ResponseWriter, r *http.Request) {
body := make([]byte, r.ContentLength)
_, _ = r.Body.Read(body)
if !util.PaySignVerify(testPaySecret, r.Header.Get("X-Pay-Sign"),
@@ -245,9 +242,14 @@ func TestCreatePurchase_HappyPath(t *testing.T) {
}
var req map[string]any
_ = json.Unmarshal(body, &req)
gotSku, _ = req["sku"].(string)
gotMethod, _ = req["method"].(string)
gotBizSystem, _ = req["biz_system"].(string)
gotBizRef, _ = req["biz_ref"].(string)
gotClientType, _ = req["client_type"].(string)
fmt.Fprint(w, `{"data":{"pay_url":"https://openapi.alipay.com/gateway","out_trade_no":"yanmei-new-1","amount":"2999.00","subject":"年付标准"}}`)
fmt.Fprint(w, `{"data":{"order_no":"pay-x1","session":{"render_type":"redirect","payload":{"url":"https://pay.test/cashier"},"expires_at":"2026-07-10T12:00:00Z"}}}`)
})
mux.HandleFunc("GET /api/v2/orders/pay-x1", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"data":{"order_no":"pay-x1","status":"pending","subject":"岩美酒库·标准版年付","amount_minor":299900,"currency":"CNY"}}`)
})
payServer := httptest.NewServer(mux)
defer payServer.Close()
@@ -255,15 +257,25 @@ func TestCreatePurchase_HappyPath(t *testing.T) {
svc := newTestPaySvc(db, payServer.URL)
res, err := svc.CreatePurchase(shop.ID, 1, "annual_standard", "mobile")
require.NoError(t, err)
assert.Equal(t, "https://openapi.alipay.com/gateway", res.PayURL)
assert.Equal(t, "yanmei-new-1", res.OutTradeNo)
assert.Equal(t, "pay-x1", res.OutTradeNo)
assert.Equal(t, "redirect", res.RenderType)
assert.Equal(t, "https://pay.test/cashier", res.Payload["url"])
assert.Equal(t, int64(299900), res.AmountMinor)
assert.Equal(t, "CNY", res.Currency)
assert.Equal(t, "https://pay.test/cashier", res.PayURL, "兼容字段:redirect 时 = payload.url")
assert.Equal(t, "2999.00", res.Amount, "兼容字段:分转元字符串")
assert.Equal(t, "annual_standard", gotSku, "sku 应直用 biz_code")
assert.Equal(t, "alipay", gotMethod)
assert.Equal(t, "jiu", gotBizSystem)
var p model.LicensePurchase
require.NoError(t, db.Where("out_trade_no = ?", "yanmei-new-1").First(&p).Error)
require.NoError(t, db.Where("out_trade_no = ?", "pay-x1").First(&p).Error)
assert.Equal(t, "pending", p.Status)
assert.Equal(t, "2999.00", p.Amount)
assert.Equal(t, int64(299900), p.AmountMinor)
assert.Equal(t, "CNY", p.Currency)
assert.Equal(t, "https://pay.test/cashier", p.PayURL)
assert.Equal(t, strconv.FormatUint(p.ID, 10), gotBizRef, "biz_ref 应为购买记录 id")
assert.Equal(t, "mobile", gotClientType, "client_type 应透传给 pay(契约 v1.1.0")
}
func TestCreatePurchase_UnknownPlanAndUnconfigured(t *testing.T) {