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