Files
wangjia 8051b0fb16 fix(v2): jiu 反馈波——端型透传(wap/page)+ alipay qr(当面付移植)+ 单号增熵/挡板限流
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
2026-07-10 18:40:15 +08:00

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)
}
}