优化结构

This commit is contained in:
Yvan
2026-08-28 00:29:40 +08:00
parent 04ff85116c
commit 03a4131f6e
118 changed files with 758 additions and 834 deletions
+130 -44
View File
@@ -12,37 +12,39 @@ import (
"sync"
"time"
"kra/pkg/paymentkit"
"github.com/google/uuid"
)
const (
PaymentAlipay = paymentutil.ProviderAlipay
PaymentAlipayV3 = paymentutil.ProviderAlipayV3
PaymentWechatV2 = paymentutil.ProviderWechatV2
PaymentWechatV3 = paymentutil.ProviderWechatV3
PaymentApple = paymentutil.ProviderApple
PaymentChinaums = paymentutil.ProviderChinaums
PaymentSFT = paymentutil.ProviderSFT
PaymentSuperPay = paymentutil.ProviderSuperPay
PaymentWechatGame = paymentutil.ProviderWechatGame
PaymentDouyinGame = paymentutil.ProviderDouyinGame
PaymentAlipay = "alipay"
PaymentAlipayV3 = "alipay-v3"
PaymentWechatV2 = "wechat-v2"
PaymentWechatV3 = "wechat-v3"
PaymentApple = "apple-iap"
PaymentChinaums = "chinaums"
PaymentSFT = "sft"
PaymentSuperPay = "supper-pay"
PaymentWechatGame = "wechat-game-pay"
PaymentDouyinGame = "douyin-game-pay"
// GoPay-backed providers. These are kept separate from the existing
// configuration-driven game/aggregator protocols above.
PaymentDouyin = paymentutil.ProviderDouyin
PaymentQQ = paymentutil.ProviderQQ
PaymentAllinPay = paymentutil.ProviderAllinPay
PaymentLakala = paymentutil.ProviderLakala
PaymentPayPal = paymentutil.ProviderPayPal
PaymentSaobei = paymentutil.ProviderSaobei
PaymentInternal = paymentutil.ProviderInternal
PaymentDouyin = "douyin"
PaymentQQ = "qq"
PaymentAllinPay = "allinpay"
PaymentLakala = "lakala"
PaymentPayPal = "paypal"
PaymentSaobei = "saobei"
PaymentInternal = "internal"
PaymentModeExternal = paymentutil.ModeExternal
PaymentModeInternal = paymentutil.ModeInternal
PaymentModeExternal = "external"
PaymentModeInternal = "internal"
)
var SupportedPaymentProviders = paymentutil.SupportedProviders()
var SupportedPaymentProviders = []string{
PaymentAlipay, PaymentAlipayV3, PaymentWechatV2, PaymentWechatV3, PaymentApple,
PaymentChinaums, PaymentSFT, PaymentSuperPay, PaymentWechatGame, PaymentDouyinGame,
PaymentDouyin, PaymentQQ, PaymentAllinPay, PaymentLakala, PaymentPayPal, PaymentSaobei,
}
var (
ErrPaymentProviderNotFound = errors.New("支付渠道未配置")
@@ -203,15 +205,74 @@ type PaymentTestResult struct {
Result *PaymentResult `json:"result,omitempty"`
}
type PaymentCallbackAck = paymentutil.CallbackAck
type PaymentCallbackError = paymentutil.CallbackError
type PaymentCallbackAck struct {
StatusCode int
ContentType string
Body []byte
}
type PaymentCallbackError struct {
Cause error
Ack PaymentCallbackAck
}
func (e *PaymentCallbackError) Error() string {
if e == nil || e.Cause == nil {
return "支付回调处理失败"
}
return e.Cause.Error()
}
func (e *PaymentCallbackError) Unwrap() error {
if e == nil {
return nil
}
return e.Cause
}
func CallbackFailure(err error, fallback PaymentCallbackAck) PaymentCallbackAck {
return paymentutil.CallbackFailure(err, fallback)
var callbackErr *PaymentCallbackError
if errors.As(err, &callbackErr) && callbackErr.Ack.StatusCode != 0 {
return callbackErr.Ack
}
return fallback
}
func DefaultPaymentCallbackAck(provider string, success bool) PaymentCallbackAck {
return paymentutil.DefaultCallbackAck(provider, success)
status := 200
if !success {
status = 500
}
switch provider {
case PaymentAlipay, PaymentAlipayV3:
body := "success"
if !success {
body = "failure"
}
return PaymentCallbackAck{StatusCode: status, ContentType: "text/plain; charset=utf-8", Body: []byte(body)}
case PaymentWechatV2:
code, message := "SUCCESS", "OK"
if !success {
code, message = "FAIL", "FAIL"
}
body := fmt.Sprintf("<xml><return_code><![CDATA[%s]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml>", code, message)
return PaymentCallbackAck{StatusCode: status, ContentType: "application/xml; charset=utf-8", Body: []byte(body)}
case PaymentWechatV3:
code, message := "SUCCESS", "成功"
if !success {
code, message = "FAIL", "失败"
}
body, _ := json.Marshal(map[string]string{"code": code, "message": message})
return PaymentCallbackAck{StatusCode: status, ContentType: "application/json; charset=utf-8", Body: body}
case PaymentApple:
return PaymentCallbackAck{StatusCode: status}
default:
body := "success"
if !success {
body = "failure"
}
return PaymentCallbackAck{StatusCode: status, ContentType: "text/plain; charset=utf-8", Body: []byte(body)}
}
}
type PaymentCallback struct {
@@ -228,6 +289,19 @@ type PaymentRepo interface {
HandleCallback(context.Context, *PaymentCallback) (*PaymentResult, error)
}
// PaymentAdapter is the integration boundary for provider protocols. SDK
// clients and wire formats stay outside the business and data packages.
type PaymentAdapter interface {
Create(context.Context, *PaymentRequest, map[string]any) (*PaymentResult, error)
Query(context.Context, string, map[string]any) (*PaymentResult, error)
Refund(context.Context, *PaymentRefundRequest, map[string]any) (*PaymentResult, error)
Callback(context.Context, *PaymentCallback, map[string]any) (*PaymentResult, error)
}
type PaymentAdapterFactory interface {
New(string) (PaymentAdapter, error)
}
type PaymentProviderTester interface {
TestProvider(context.Context, string) (*PaymentTestResult, error)
}
@@ -240,6 +314,8 @@ type NoopPaymentHooks struct{}
func (NoopPaymentHooks) BeforeCreate(context.Context, *PaymentRequest) error { return nil }
func NewPaymentHooks() PaymentHooks { return NoopPaymentHooks{} }
type PaymentFulfillmentHandler interface {
Type() string
Fulfill(context.Context, *PaymentConfirmation) error
@@ -273,6 +349,15 @@ func (r *PaymentFulfillmentRegistry) Handler(kind string) PaymentFulfillmentHand
return r.handlers[kind]
}
func (r *PaymentFulfillmentRegistry) Len() int {
if r == nil {
return 0
}
r.mu.RLock()
defer r.mu.RUnlock()
return len(r.handlers)
}
type PaymentUsecase struct {
repo PaymentRepo
orders PaymentOrderRepo
@@ -282,33 +367,34 @@ type PaymentUsecase struct {
logger PaymentLogger
}
func NewPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, appLogger *slog.Logger) *PaymentUsecase {
func NewPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, hooks PaymentHooks, sources *PaymentOrderSourceRegistry, fulfillments *PaymentFulfillmentRegistry, appLogger *slog.Logger) *PaymentUsecase {
if hooks == nil {
hooks = NoopPaymentHooks{}
}
if sources == nil {
sources = NewPaymentOrderSourceRegistry()
}
if fulfillments == nil {
fulfillments = NewPaymentFulfillmentRegistry()
}
return &PaymentUsecase{
repo: repo,
orders: orders,
hooks: NoopPaymentHooks{},
sources: NewPaymentOrderSourceRegistry(),
fulfillments: NewPaymentFulfillmentRegistry(),
hooks: hooks,
sources: sources,
fulfillments: fulfillments,
logger: NewPaymentLogger(appLogger),
}
}
func (uc *PaymentUsecase) SetHooks(hooks PaymentHooks) {
if hooks != nil {
uc.hooks = hooks
func NewConfiguredPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, hooks PaymentHooks, sources *PaymentOrderSourceRegistry, fulfillments *PaymentFulfillmentRegistry, appLogger *slog.Logger) (*PaymentUsecase, error) {
if sources == nil || sources.Len() == 0 {
return nil, errors.New("支付业务订单来源未注册,无法启动支付服务")
}
}
func (uc *PaymentUsecase) SetOrderSourceRegistry(registry *PaymentOrderSourceRegistry) {
if registry != nil {
uc.sources = registry
}
}
func (uc *PaymentUsecase) SetFulfillmentRegistry(registry *PaymentFulfillmentRegistry) {
if registry != nil {
uc.fulfillments = registry
if fulfillments == nil || fulfillments.Len() == 0 {
return nil, errors.New("支付发货 handler 未注册,无法启动支付服务")
}
return NewPaymentUsecase(repo, orders, hooks, sources, fulfillments, appLogger), nil
}
func (uc *PaymentUsecase) RegisterBusinessModule(module PaymentBusinessModule) error {