feat(backend): pay 下单/查单切 v2 契约——sku 直用 biz_code、session 多态响应、金额 int64 分
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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 验签后返回 session(redirect)+ 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) {
|
||||
|
||||
Reference in New Issue
Block a user