8051b0fb16
1. CreateOrderInput/RetryOrder 加 Metadata 通道,handler 白名单过滤(is_mobile/render)
后原样传给 provider.CreateRequest;alipay adapter 据 is_mobile 选 wap/page。
2. alipay adapter 移植 v1 当面付(TradePreCreate):Metadata["render"]=="qr" → 二维码
render_type,payload={qr_content,display_amount,currency},默认 2 小时窗口。
3. NewOutTradeNo 随机部分 8→16 hex 防生日碰撞(仍 <=64 字符,合规 DB 列/支付宝上限);
v2 改状态端点(下单/重试/取消)加 per-IP 内存令牌桶限流,默认开 30/min,
config.rate_limit.disabled 可关;callback/GET 查询不限。
顺带修:internal/reconcile/sync_test.go 的 gateway.New 调用漏传 refunds store,
预先存在的编译期回归(与本次改动无关,但挡住 go test ./... 全绿,一并修掉)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
package util_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/wangjia/pay/internal/util"
|
|
)
|
|
|
|
// jiu 反馈波:随机部分 8→16 hex(64 位)加固防生日碰撞;断言新长度/格式,
|
|
// 并确认仍在 DB out_trade_no 列 size:64 与支付宝 out_trade_no ≤64 字符上限内。
|
|
func TestNewOutTradeNoSuffixLength(t *testing.T) {
|
|
no := util.NewOutTradeNo("yanmei")
|
|
parts := strings.Split(no, "-")
|
|
if len(parts) != 3 {
|
|
t.Fatalf("out_trade_no = %q, want 3 段(code-ts-suffix)", no)
|
|
}
|
|
suffix := parts[2]
|
|
if len(suffix) != 16 {
|
|
t.Fatalf("随机后缀长度 = %d, want 16", len(suffix))
|
|
}
|
|
if len(no) > 64 {
|
|
t.Fatalf("out_trade_no 长度 = %d, want <= 64", len(no))
|
|
}
|
|
}
|
|
|
|
// merchantCode 拉满 16 字符时,总长仍须 <= 64(alipay out_trade_no 上限)。
|
|
func TestNewOutTradeNoMaxLength(t *testing.T) {
|
|
no := util.NewOutTradeNo("0123456789abcdefEXTRA") // >16 字符,函数内部会截断到 16
|
|
if len(no) > 64 {
|
|
t.Fatalf("out_trade_no 长度 = %d, want <= 64: %q", len(no), no)
|
|
}
|
|
}
|
|
|
|
// 两次生成不应重复(随机后缀 + 时间戳兜底)。
|
|
func TestNewOutTradeNoUnique(t *testing.T) {
|
|
a := util.NewOutTradeNo("pay")
|
|
b := util.NewOutTradeNo("pay")
|
|
if a == b {
|
|
t.Fatalf("两次生成的 out_trade_no 相同: %q", a)
|
|
}
|
|
}
|