package payment import ( "context" "errors" "strings" "time" "kra/internal/biz" "github.com/go-pay/gopay" "github.com/go-pay/gopay/saobei" ) type saobeiAdapter struct{} func (a *saobeiAdapter) client(c map[string]any) (*saobei.Client, error) { return saobei.NewClient(text(c, "inst_no"), text(c, "key"), text(c, "merchant_no"), text(c, "terminal_id"), text(c, "access_token"), !strings.EqualFold(text(c, "environment"), "sandbox")) } func (a *saobeiAdapter) Create(ctx context.Context, req *biz.PaymentRequest, c map[string]any) (*biz.PaymentResult, error) { client, err := a.client(c) if err != nil { return nil, err } now := time.Now().Format("20060102150405") bm := gopay.BodyMap{"pay_type": firstAnyOr(req.Extra, "010", "pay_type", "payment_type"), "terminal_ip": req.ClientIP, "terminal_trace": req.TradeNo, "terminal_time": now, "total_fee": req.Amount} mergeGoPayExtras(bm, req.Extra, "pay_type", "payment_type", "terminal_ip", "terminal_trace", "terminal_time", "total_fee", "method", "pay_method", "trade_type") method := strings.ToLower(firstAny(req.Extra, "method", "pay_method", "trade_type")) if method == "barcode" || method == "micropay" { rsp, callErr := client.BarcodePay(ctx, bm) if callErr != nil { return nil, callErr } return &biz.PaymentResult{Provider: biz.PaymentSaobei, Status: "created", TradeNo: req.TradeNo, ProviderTradeNo: rsp.OutTradeNo, Payload: mustJSON(rsp)}, nil } rsp, err := client.MiniPay(ctx, bm) if err != nil { return nil, err } return &biz.PaymentResult{Provider: biz.PaymentSaobei, Status: "client_pending", TradeNo: req.TradeNo, ProviderTradeNo: rsp.OutTradeNo, QueryID: rsp.PackageStr, Payload: mustJSON(rsp)}, nil } func (a *saobeiAdapter) Query(ctx context.Context, tradeNo string, c map[string]any) (*biz.PaymentResult, error) { client, err := a.client(c) if err != nil { return nil, err } bm := gopay.BodyMap{"pay_type": firstAnyOr(c, "010", "pay_type", "payment_type"), "terminal_trace": tradeNo, "terminal_time": time.Now().Format("20060102150405"), "out_trade_no": tradeNo} mergeGoPayConfigExtras(bm, c, "query_extra", "pay_type", "terminal_trace", "terminal_time", "out_trade_no") rsp, err := client.Query(ctx, bm) if err != nil { return nil, err } result := &biz.PaymentResult{Provider: biz.PaymentSaobei, Status: normalizeSaobeiState(rsp.TradeState), TradeNo: rsp.OutTradeNo, ProviderTradeNo: rsp.ChannelTradeNo, Payload: mustJSON(rsp), Currency: strings.ToUpper(firstAnyOr(c, "CNY", "currency", "default_currency"))} if result.TradeNo == "" { result.TradeNo = tradeNo } if rsp.TotalFee != "" { result.Amount, err = parseIntegerAmount(rsp.TotalFee) } if rsp.BuyerPayFee != "" { result.PayerPaidAmount, _ = parseIntegerAmount(rsp.BuyerPayFee) result.CashPaidAmount = result.PayerPaidAmount if result.Amount >= result.PayerPaidAmount { result.DiscountAmount = result.Amount - result.PayerPaidAmount result.AmountBreakdownKnown = true } } return result, err } func (a *saobeiAdapter) Refund(ctx context.Context, req *biz.PaymentRefundRequest, c map[string]any) (*biz.PaymentResult, error) { if req == nil { return nil, errors.New("扫呗支付退款请求为空") } client, err := a.client(c) if err != nil { return nil, err } bm := gopay.BodyMap{"pay_type": firstAnyOr(c, "010", "pay_type", "payment_type"), "terminal_trace": req.TradeNo, "terminal_time": time.Now().Format("20060102150405"), "refund_fee": req.Amount, "out_trade_no": req.TradeNo, "out_refund_no": req.RefundNo} mergeGoPayConfigExtras(bm, c, "refund_extra", "pay_type", "terminal_trace", "terminal_time", "refund_fee", "out_trade_no", "out_refund_no") rsp, err := client.Refund(ctx, bm) if err != nil { return nil, err } if rsp == nil { return nil, errors.New("扫呗支付退款响应为空") } refundAmount, _ := parseIntegerAmount(rsp.RefundFee) return &biz.PaymentResult{Provider: biz.PaymentSaobei, Status: "pending", TradeNo: req.TradeNo, ProviderTradeNo: rsp.OutTradeNo, Amount: refundAmount, Currency: strings.ToUpper(req.Currency), Payload: mustJSON(rsp)}, nil } func (a *saobeiAdapter) Callback(_ context.Context, _ *biz.PaymentCallback, _ map[string]any) (*biz.PaymentResult, error) { return nil, errors.New("扫呗支付回调没有可复用的 GoPay 验签器,请改用主动查单") }