支付相关
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
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 验签器,请改用主动查单")
|
||||
}
|
||||
Reference in New Issue
Block a user