140 lines
5.0 KiB
Go
140 lines
5.0 KiB
Go
package payment
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
|
|
"kra/internal/biz"
|
|
|
|
"github.com/go-pay/gopay"
|
|
"github.com/go-pay/gopay/allinpay"
|
|
)
|
|
|
|
type allinpayAdapter struct{}
|
|
|
|
func (a *allinpayAdapter) client(c map[string]any) (*allinpay.Client, error) {
|
|
client, err := allinpay.NewClient(text(c, "cus_id"), text(c, "app_id"), text(c, "private_key"), text(c, "public_key"), !strings.EqualFold(text(c, "environment"), "sandbox"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if org := text(c, "org_id"); org != "" {
|
|
client.SetOrgId(org)
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
func (a *allinpayAdapter) 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
|
|
}
|
|
bm := gopay.BodyMap{"reqsn": req.TradeNo, "trxamt": req.Amount, "body": req.Subject}
|
|
mergeGoPayExtras(bm, req.Extra, "reqsn", "trxamt", "body", "method", "pay_method", "trade_type")
|
|
method := strings.ToLower(firstAny(req.Extra, "method", "pay_method", "trade_type"))
|
|
if method == "scan" || method == "micropay" || method == "barcode" {
|
|
bm.Set("authcode", firstAny(req.Extra, "authcode", "auth_code"))
|
|
bm.SetBodyMap("terminfo", func(info gopay.BodyMap) {
|
|
info.Set("devicetype", firstAnyOr(req.Extra, "10", "device_type", "devicetype"))
|
|
info.Set("termno", firstAnyOr(req.Extra, "00000001", "termno", "terminal_no"))
|
|
})
|
|
rsp, callErr := client.ScanPay(ctx, bm)
|
|
if callErr != nil {
|
|
return nil, callErr
|
|
}
|
|
if rsp == nil {
|
|
return nil, errors.New("通联支付扫码下单响应为空")
|
|
}
|
|
return &biz.PaymentResult{Provider: biz.PaymentAllinPay, Status: normalizeAllinState(rsp.TrxStatus), TradeNo: req.TradeNo, ProviderTradeNo: rsp.Trxid, Payload: mustJSON(rsp)}, nil
|
|
}
|
|
if method == "native" || method == "qrcode" {
|
|
bm.Set("expiretime", firstAny(req.Extra, "expiretime", "expire_time"))
|
|
rsp, callErr := client.NativePay(ctx, bm)
|
|
if callErr != nil {
|
|
return nil, callErr
|
|
}
|
|
if rsp == nil {
|
|
return nil, errors.New("通联支付下单响应为空")
|
|
}
|
|
return &biz.PaymentResult{Provider: biz.PaymentAllinPay, Status: "created", TradeNo: req.TradeNo, ProviderTradeNo: rsp.ReqSn, QueryID: rsp.PayInfo, Payload: mustJSON(rsp)}, nil
|
|
}
|
|
payType := firstAny(req.Extra, "paytype", "pay_type")
|
|
if payType == "" {
|
|
payType = firstAny(c, "paytype", "pay_type")
|
|
}
|
|
if payType == "" {
|
|
payType = allinpay.PayTypeWXJS
|
|
}
|
|
bm.Set("paytype", payType)
|
|
rsp, err := client.Pay(ctx, bm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rsp == nil {
|
|
return nil, errors.New("通联支付下单响应为空")
|
|
}
|
|
return &biz.PaymentResult{Provider: biz.PaymentAllinPay, Status: "created", TradeNo: req.TradeNo, ProviderTradeNo: rsp.Trxid, QueryID: rsp.PayInfo, Payload: mustJSON(rsp)}, nil
|
|
}
|
|
|
|
func (a *allinpayAdapter) Query(ctx context.Context, tradeNo string, c map[string]any) (*biz.PaymentResult, error) {
|
|
client, err := a.client(c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
orderType := firstAny(c, "query_order_type", "order_type")
|
|
if orderType == "" {
|
|
orderType = allinpay.OrderTypeReqSN
|
|
}
|
|
rsp, err := client.Query(ctx, orderType, tradeNo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rsp == nil {
|
|
return nil, errors.New("通联支付查单响应为空")
|
|
}
|
|
result := &biz.PaymentResult{Provider: biz.PaymentAllinPay, Status: normalizeAllinState(rsp.TrxStatus), TradeNo: rsp.Reqsn, ProviderTradeNo: rsp.Trxid, Currency: strings.ToUpper(firstAny(c, "currency")), Payload: mustJSON(rsp)}
|
|
if result.TradeNo == "" {
|
|
result.TradeNo = tradeNo
|
|
}
|
|
if rsp.TrxAmt != "" {
|
|
result.Amount, err = parseIntegerAmount(rsp.TrxAmt)
|
|
if err != nil {
|
|
if scale := configuredInt64(c, "amount_scale", 100); scale != 1 {
|
|
result.Amount, err = parseDecimalAmount(rsp.TrxAmt, scale)
|
|
}
|
|
}
|
|
}
|
|
if result.Currency == "" {
|
|
result.Currency = "CNY"
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
func (a *allinpayAdapter) 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{"reqsn": req.RefundNo, "trxamt": req.Amount, "oldreqsn": req.TradeNo, "remark": firstAny(c, "refund_remark", "remark")}
|
|
mergeGoPayConfigExtras(bm, c, "refund_extra", "reqsn", "trxamt", "oldreqsn", "remark")
|
|
rsp, err := client.Refund(ctx, bm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rsp == nil {
|
|
return nil, errors.New("通联支付退款响应为空")
|
|
}
|
|
refundAmount, _ := parseIntegerAmount(rsp.Fee)
|
|
if refundAmount == 0 {
|
|
refundAmount = req.Amount
|
|
}
|
|
return &biz.PaymentResult{Provider: biz.PaymentAllinPay, Status: normalizeRefundState(rsp.TrxStatus), TradeNo: req.TradeNo, ProviderTradeNo: rsp.Trxid, Amount: refundAmount, Currency: strings.ToUpper(firstAny(c, "currency")), Payload: mustJSON(rsp)}, nil
|
|
}
|
|
|
|
func (a *allinpayAdapter) Callback(_ context.Context, _ *biz.PaymentCallback, _ map[string]any) (*biz.PaymentResult, error) {
|
|
return nil, errors.New("通联支付回调没有可复用的 GoPay 验签器,请改用主动查单")
|
|
}
|