feat(provider): 哪吒支付(nezha)RSA 聚合渠道 provider + 注册 + 测试

照 alipay adapter 的 RSA + redirect/qr + 表单请求模式实现哪吒(nzzf.org)聚合支付:
SHA256WithRSA + Base64 签名(商户私钥出站签名/平台公钥验响应及回调),Create 走
POST /api/pay/create,VerifyCallback 处理 GET 异步通知(handler 层新增 Query 透传
+ nezha 专属纯文本 success/fail 回复),Query 走 POST /api/pay/query。BuildRegistry
按凭证齐备与否决策注册,缺凭证只 log 跳过不 fatal。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
wangjia
2026-07-11 12:19:24 +08:00
parent a04947ad80
commit a6b068b070
9 changed files with 1393 additions and 5 deletions
+23
View File
@@ -13,6 +13,7 @@ package providerbuild
import (
"log"
"strings"
sw "github.com/smartwalle/alipay/v3"
stripeclient "github.com/stripe/stripe-go/v79/client"
@@ -23,6 +24,7 @@ import (
"github.com/wangjia/pay/internal/provider/alipay"
"github.com/wangjia/pay/internal/provider/crypto"
"github.com/wangjia/pay/internal/provider/fake"
"github.com/wangjia/pay/internal/provider/nezha"
"github.com/wangjia/pay/internal/provider/stripe"
)
@@ -68,6 +70,27 @@ func BuildRegistry(accts *accounts.Registry) *provider.Registry {
}
}
// nezha:RSA 聚合支付,首个 enabled 账户的 env 凭证 → *nezha.Provider。notify_url
// 与 alipay 不同——alipay notify_url 走支付宝开放平台应用级配置(per-request 可省略),
// 哪吒协议要求每次下单显式携带,这里据 config.C.Server.BaseURL 拼好传入。
if ns := accts.EnabledFor("nezha", ""); len(ns) > 0 {
n := ns[0]
pid := accts.Credential(n.AccountID, "PID")
priv := accts.Credential(n.AccountID, "PRIVATE_KEY")
pub := accts.Credential(n.AccountID, "PLATFORM_PUBLIC_KEY")
if pid == "" || priv == "" || pub == "" {
log.Printf("[providers] nezha 账户 %s 凭证不全,跳过", n.AccountID)
} else {
notifyURL := strings.TrimRight(config.C.Server.BaseURL, "/") + "/api/v2/callback/nezha"
if np, err := nezha.New(pid, priv, pub, notifyURL); err != nil {
log.Printf("[providers] nezha client 构建失败: %v", err)
} else {
reg.Register(np)
log.Println("[providers] nezha 已注册")
}
}
}
// stripe:首个 enabled 账户的 env 凭证 → *client.API。
if ss := accts.EnabledFor("stripe", ""); len(ss) > 0 {
s := ss[0]