feat(v2): 一次性收款管线 CreateOrder/GetOrder/Retry/Cancel + DBProductResolver

This commit is contained in:
wangjia
2026-07-10 11:08:03 +08:00
parent 31e354e31c
commit 0ab0713161
6 changed files with 387 additions and 3 deletions
+7 -2
View File
@@ -1,12 +1,16 @@
// Package fake is an in-process Provider used to exercise the pay v2 pipeline
// end-to-end without any real channel. Real adapters (crypto/alipay/stripe) land
// in P3. Deterministic: provider_ref = "FAKE-"+OutTradeNo; render_type = crypto_address.
// in P3. provider_ref = "FAKE-"+OutTradeNo+"-"+<nanosecond>; render_type = crypto_address.
// The nanosecond suffix is fake-only: Attempt has uniqueIndex(channel,provider_ref),
// and a retry on the same order/method would otherwise reuse the same OutTradeNo and
// collide. Real channels naturally mint a distinct ref per create call.
package fake
import (
"context"
"encoding/json"
"errors"
"strconv"
"sync"
"time"
@@ -33,8 +37,9 @@ func (p *Provider) Capabilities() provider.Capabilities {
func (p *Provider) Create(_ context.Context, req provider.CreateRequest) (*provider.Session, error) {
exp := time.Now().Add(15 * time.Minute)
ref := "FAKE-" + req.OutTradeNo + "-" + strconv.FormatInt(time.Now().UnixNano(), 36)
return &provider.Session{
ProviderRef: "FAKE-" + req.OutTradeNo,
ProviderRef: ref,
RenderType: provider.RenderCryptoAddress,
Payload: map[string]any{
"address": "TFake" + req.Account.AccountID + req.OutTradeNo,
+2 -1
View File
@@ -2,6 +2,7 @@ package fake_test
import (
"context"
"strings"
"testing"
"github.com/wangjia/pay/internal/provider"
@@ -18,7 +19,7 @@ func TestFakeCreateAndVerify(t *testing.T) {
if err != nil {
t.Fatalf("create: %v", err)
}
if sess.ProviderRef != "FAKE-PAY-1" || sess.RenderType != provider.RenderCryptoAddress {
if !strings.HasPrefix(sess.ProviderRef, "FAKE-PAY-1") || sess.RenderType != provider.RenderCryptoAddress {
t.Fatalf("session = %+v", sess)
}