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