钱包结算所有, 第三方充值到钱包

This commit is contained in:
yml
2026-06-03 17:41:24 +08:00
parent eb7c0045cd
commit a1942c8453
9 changed files with 211 additions and 102 deletions
@@ -72,6 +72,14 @@ type QueryPaymentResponse struct {
Raw map[string]string
}
type VerifyNotifyResult struct {
OK bool
MatchedKey string
Got string
Expected map[string]string
ParamKeys []string
}
func NewClient(cfg config.LeshuaPaymentConfig) *Client {
return &Client{
cfg: cfg,
@@ -171,19 +179,60 @@ func (c *Client) QueryPayment(ctx context.Context, thirdOrderID, providerOrderID
}
func (c *Client) VerifyNotify(params map[string]string) bool {
key := firstNonEmpty(c.cfg.NotifyKey, c.cfg.SignKey)
if key == "" {
return false
}
return c.VerifyNotifyDetail(params).OK
}
func (c *Client) VerifyNotifyDetail(params map[string]string) VerifyNotifyResult {
got := strings.ToUpper(params["sign"])
if got == "" {
return false
result := VerifyNotifyResult{
Got: got,
Expected: map[string]string{},
ParamKeys: notifyParamKeys(params),
}
expected := Sign(params, key, SignOptions{
IncludeEmpty: true,
ExcludeKeys: []string{"error_code", "sign"},
})
return got == expected
if got == "" {
return result
}
for _, item := range c.notifyKeyCandidates() {
expected := Sign(params, item.key, SignOptions{
IncludeEmpty: true,
ExcludeKeys: []string{"error_code", "sign"},
})
result.Expected[item.name] = expected
if got == expected {
result.OK = true
result.MatchedKey = item.name
return result
}
}
return result
}
type notifyKeyCandidate struct {
name string
key string
}
func (c *Client) notifyKeyCandidates() []notifyKeyCandidate {
candidates := []notifyKeyCandidate{}
if c.cfg.NotifyKey != "" {
candidates = append(candidates, notifyKeyCandidate{name: "notify_key", key: c.cfg.NotifyKey})
}
if c.cfg.SignKey != "" && c.cfg.SignKey != c.cfg.NotifyKey {
candidates = append(candidates, notifyKeyCandidate{name: "sign_key", key: c.cfg.SignKey})
}
return candidates
}
func notifyParamKeys(params map[string]string) []string {
keys := make([]string, 0, len(params))
for key := range params {
if key == "sign" || key == "error_code" {
continue
}
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
func (c *Client) validate() error {
@@ -50,6 +50,32 @@ func TestVerifyNotifyIncludesEmptyAndExcludesErrorCode(t *testing.T) {
}
}
func TestVerifyNotifyFallsBackToSignKey(t *testing.T) {
client := NewClient(config.LeshuaPaymentConfig{
NotifyKey: "wrong-notify-secret",
SignKey: "sign-secret",
})
params := map[string]string{
"merchant_id": "1234567890",
"third_order_id": "NO1",
"leshua_order_id": "LS1",
"amount": "100",
"status": "2",
}
params["sign"] = Sign(params, "sign-secret", SignOptions{
IncludeEmpty: true,
ExcludeKeys: []string{"error_code", "sign"},
})
result := client.VerifyNotifyDetail(params)
if !result.OK {
t.Fatal("VerifyNotifyDetail().OK = false, want true")
}
if result.MatchedKey != "sign_key" {
t.Fatalf("MatchedKey = %s, want sign_key", result.MatchedKey)
}
}
func TestParsePayloadSupportsFormAndXML(t *testing.T) {
form, err := ParsePayload([]byte("third_order_id=NO1&status=2&amount=100"))
if err != nil {