Files
kra-new/internal/data/payment/saobei.go
T
2026-08-19 18:06:03 +08:00

97 lines
4.2 KiB
Go

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 验签器,请改用主动查单")
}