优化结构
This commit is contained in:
@@ -1,204 +0,0 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"kra/internal/biz"
|
||||
|
||||
gopayWechatV3 "github.com/go-pay/gopay/wechat/v3"
|
||||
)
|
||||
|
||||
func TestWechatV3CodePayUsesGoPaySDK(t *testing.T) {
|
||||
platformKey, _, platformPublicPEM := testRSAKeyPair(t)
|
||||
_, merchantPrivatePEM, _ := testRSAKeyPair(t)
|
||||
const (
|
||||
platformSerial = "PLATFORM-SERIAL"
|
||||
timestamp = "1787068800"
|
||||
nonce = "codepay-response-nonce"
|
||||
)
|
||||
response := []byte(`{"appid":"wx-test","mchid":"mch-test","out_trade_no":"T-WECHAT-CODEPAY","transaction_id":"WX-CODEPAY-1","trade_type":"MICROPAY","trade_state":"SUCCESS","amount":{"total":123,"payer_total":100,"currency":"CNY","payer_currency":"CNY"},"promotion_detail":[{"coupon_id":"COUPON-1","amount":23}]}`)
|
||||
signature := testRSA2Sign(t, platformKey, []byte(timestamp+"\n"+nonce+"\n"+string(response)+"\n"))
|
||||
|
||||
var requestBody map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost || r.URL.Path != "/v3/pay/transactions/codepay" {
|
||||
t.Errorf("request = %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
if strings.TrimSpace(r.Header.Get("Authorization")) == "" {
|
||||
t.Error("missing GoPay authorization header")
|
||||
}
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("read request: %v", err)
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(body, &requestBody); err != nil {
|
||||
t.Errorf("decode request: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(gopayWechatV3.HeaderTimestamp, timestamp)
|
||||
w.Header().Set(gopayWechatV3.HeaderNonce, nonce)
|
||||
w.Header().Set(gopayWechatV3.HeaderSerial, platformSerial)
|
||||
w.Header().Set(gopayWechatV3.HeaderSignature, signature)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write(response)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
result, err := (&wechatV3Adapter{}).Create(context.Background(), &biz.PaymentRequest{
|
||||
Provider: biz.PaymentWechatV3,
|
||||
TradeNo: "T-WECHAT-CODEPAY",
|
||||
Subject: "subject",
|
||||
Amount: 123,
|
||||
Currency: "CNY",
|
||||
NotifyURL: "https://merchant.test/payment/callback",
|
||||
Extra: map[string]any{
|
||||
"method": "codepay",
|
||||
"auth_code": "AUTH-CODE-1",
|
||||
"payer": map[string]any{"auth_code": "OVERRIDE"},
|
||||
},
|
||||
}, map[string]any{
|
||||
"app_id": "wx-test",
|
||||
"merchant_id": "mch-test",
|
||||
"serial_no": "merchant-serial",
|
||||
"private_key": merchantPrivatePEM,
|
||||
"api_v3_key": "01234567890123456789012345678901",
|
||||
"platform_cert": platformPublicPEM,
|
||||
"platform_serial_no": platformSerial,
|
||||
"create_url": server.URL,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
payer, _ := requestBody["payer"].(map[string]any)
|
||||
amount, _ := requestBody["amount"].(map[string]any)
|
||||
if payer["auth_code"] != "AUTH-CODE-1" || requestBody["out_trade_no"] != "T-WECHAT-CODEPAY" {
|
||||
t.Fatalf("request identity = %#v", requestBody)
|
||||
}
|
||||
if amount["total"] != float64(123) || amount["currency"] != "CNY" {
|
||||
t.Fatalf("request amount = %#v", amount)
|
||||
}
|
||||
if result.Provider != biz.PaymentWechatV3 || result.Status != "success" || result.TradeNo != "T-WECHAT-CODEPAY" || result.ProviderTradeNo != "WX-CODEPAY-1" || result.QueryID != "" {
|
||||
t.Fatalf("result identity = %+v", result)
|
||||
}
|
||||
if result.Amount != 123 || result.Currency != "CNY" || result.PayerCurrency != "CNY" || !result.AmountBreakdownKnown || result.PayerPaidAmount != 100 || result.CashPaidAmount != 100 || result.DiscountAmount != 23 {
|
||||
t.Fatalf("result amount = %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayAliasesRequireAuthCode(t *testing.T) {
|
||||
_, merchantPrivatePEM, _ := testRSAKeyPair(t)
|
||||
_, _, platformPublicPEM := testRSAKeyPair(t)
|
||||
config := map[string]any{
|
||||
"app_id": "wx-test",
|
||||
"merchant_id": "mch-test",
|
||||
"serial_no": "merchant-serial",
|
||||
"private_key": merchantPrivatePEM,
|
||||
"api_v3_key": "01234567890123456789012345678901",
|
||||
"platform_cert": platformPublicPEM,
|
||||
"platform_serial_no": "platform-serial",
|
||||
}
|
||||
|
||||
for _, method := range []string{"micropay", "micro_pay", "micro-pay", "codepay", "code_pay", "code-pay", "barcode", "barcode_pay", "facepay", "face_pay"} {
|
||||
t.Run(method, func(t *testing.T) {
|
||||
_, err := (&wechatV3Adapter{}).Create(context.Background(), &biz.PaymentRequest{
|
||||
TradeNo: "T-WECHAT-CODEPAY", Subject: "subject", Amount: 1, Currency: "CNY",
|
||||
Extra: map[string]any{"method": method},
|
||||
}, config)
|
||||
if err == nil || !strings.Contains(err.Error(), "auth_code") {
|
||||
t.Fatalf("method %q error = %v", method, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayResultRejectsInvalidIdentity(t *testing.T) {
|
||||
_, err := wechatV3CodePayResult("T-WECHAT-CODEPAY", &gopayWechatV3.CodePayRsp{
|
||||
Code: gopayWechatV3.Success,
|
||||
Response: &gopayWechatV3.CodePay{
|
||||
OutTradeNo: "OTHER-ORDER",
|
||||
TradeState: "SUCCESS",
|
||||
Amount: &gopayWechatV3.Amount{Total: 1, Currency: "CNY"},
|
||||
},
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "商户订单号不匹配") {
|
||||
t.Fatalf("identity mismatch error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayResultRequiresMerchantOrderNumber(t *testing.T) {
|
||||
_, err := wechatV3CodePayResult("T-WECHAT-CODEPAY", &gopayWechatV3.CodePayRsp{
|
||||
Code: gopayWechatV3.Success,
|
||||
Response: &gopayWechatV3.CodePay{
|
||||
TradeState: "SUCCESS",
|
||||
TransactionId: "WX-CODEPAY-1",
|
||||
Amount: &gopayWechatV3.Amount{Total: 1, Currency: "CNY"},
|
||||
},
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "out_trade_no") {
|
||||
t.Fatalf("missing out_trade_no error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayResultPreservesFullyDiscountedBreakdown(t *testing.T) {
|
||||
result, err := wechatV3CodePayResult("T-WECHAT-CODEPAY", &gopayWechatV3.CodePayRsp{
|
||||
Code: gopayWechatV3.Success,
|
||||
Response: &gopayWechatV3.CodePay{
|
||||
OutTradeNo: "T-WECHAT-CODEPAY",
|
||||
TransactionId: "WX-CODEPAY-1",
|
||||
TradeState: "SUCCESS",
|
||||
Amount: &gopayWechatV3.Amount{
|
||||
Total: 100, PayerTotal: 0, Currency: "CNY", PayerCurrency: "CNY",
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !result.AmountBreakdownKnown || result.PayerPaidAmount != 0 || result.CashPaidAmount != 0 || result.DiscountAmount != 100 || result.PayerCurrency != "CNY" {
|
||||
t.Fatalf("fully discounted result = %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayDoesNotInferMissingPayerTotal(t *testing.T) {
|
||||
result, err := wechatV3CodePayResult("T-WECHAT-CODEPAY", &gopayWechatV3.CodePayRsp{
|
||||
Code: gopayWechatV3.Success,
|
||||
SignInfo: &gopayWechatV3.SignInfo{SignBody: `{"out_trade_no":"T-WECHAT-CODEPAY","transaction_id":"WX-CODEPAY-2","trade_state":"SUCCESS","amount":{"total":100,"currency":"CNY"}}`},
|
||||
Response: &gopayWechatV3.CodePay{
|
||||
OutTradeNo: "T-WECHAT-CODEPAY",
|
||||
TransactionId: "WX-CODEPAY-2",
|
||||
TradeState: "SUCCESS",
|
||||
Amount: &gopayWechatV3.Amount{Total: 100, Currency: "CNY"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.AmountBreakdownKnown || result.PayerPaidAmount != 0 || result.DiscountAmount != 0 {
|
||||
t.Fatalf("missing payer_total was treated as a complete breakdown: %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWechatV3CodePayUserPayingRemainsPending(t *testing.T) {
|
||||
result, err := wechatV3CodePayResult("T-WECHAT-CODEPAY", &gopayWechatV3.CodePayRsp{
|
||||
Code: gopayWechatV3.Success,
|
||||
Response: &gopayWechatV3.CodePay{
|
||||
OutTradeNo: "T-WECHAT-CODEPAY",
|
||||
TradeState: "USERPAYING",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Status != "pending" || result.TradeNo != "T-WECHAT-CODEPAY" || result.ProviderTradeNo != "" || result.QueryID != "" {
|
||||
t.Fatalf("pending result = %+v", result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user