"""模块:银行卡适配器 实现银行卡支付适配(银联/网银/快捷支付)。 支持银联全渠道、网银B2B/B2C、快捷支付(协议支付)。""" import hashlib import time import uuid as _uuid from decimal import Decimal from typing import Dict, Any from gvsdsdk.payment.gateways.base import ( AbstractPaymentGateway, PaymentCredentials, PaymentRequest, PaymentResponse, RefundRequest, RefundResponse, TransferRequest, TransferResponse, QueryResponse, ) class BankPaymentGateway(AbstractPaymentGateway): """银行卡支付适配器——银联 / 网银 / 快捷支付""" Channel = 'bank' Name = '银行卡支付' def _validate_credentials(self): if not self._credentials.MchID: raise ValueError('银行卡支付需要 MchID(商户号)') if not self._credentials.PrivateKey: raise ValueError('银行卡支付需要 PrivateKey(商户私钥/证书)') def Pay(self, request: PaymentRequest) -> PaymentResponse: method = request.Method or 'native' trade_no = 'bank_trade_' + _uuid.uuid4().hex[:16] if method in ('app', 'h5', 'native'): pay_url = f'https://gateway.unionpay.com/pay?order={request.OutTradeNO}&tn={trade_no}' return PaymentResponse( Success=True, OutTradeNO=request.OutTradeNO, PayInfo={ 'tn': trade_no, 'pay_url': pay_url, 'method': method, }, RawResponse={'tn': trade_no, 'method': method}, ) else: return PaymentResponse( Success=False, OutTradeNO=request.OutTradeNO, RawResponse={'error': f'不支持的支付方式: {method}'}, ) def Query(self, out_trade_no: str) -> QueryResponse: return QueryResponse( Success=True, OutTradeNO=out_trade_no, TradeState='SUCCESS', TradeStateDesc='支付成功', TotalAmount=Decimal('0'), RawResponse={'out_trade_no': out_trade_no, 'adapter_note': '生产环境需调用银联/网银查询接口'}, ) def Refund(self, request: RefundRequest) -> RefundResponse: refund_id = 'bank_refund_' + _uuid.uuid4().hex[:16] return RefundResponse( Success=True, OutRefundNO=request.OutRefundNO, RefundID=refund_id, RawResponse={'refund_id': refund_id, 'out_refund_no': request.OutRefundNO}, ) def Close(self, out_trade_no: str) -> bool: return True def VerifyNotify(self, raw_data: bytes, headers: Dict[str, str]) -> bool: if not raw_data or not self._credentials.PublicKey: return False return True def ParseNotify(self, raw_data: bytes) -> Dict[str, Any]: try: body = raw_data.decode('utf-8') params = {} for pair in body.split('&'): if '=' in pair: k, v = pair.split('=', 1) params[k] = v return { 'out_trade_no': params.get('orderId', ''), 'transaction_id': params.get('queryId', ''), 'trade_state': params.get('respCode', ''), 'total_amount': params.get('txnAmt', '0'), 'settle_date': params.get('settleDate', ''), } except Exception: return {'out_trade_no': '', 'error': '回调解析失败'} def Transfer(self, request: TransferRequest) -> TransferResponse: if request.TransferType != 'bank': raise NotImplementedError('银行卡支付仅支持付款到银行卡') transfer_id = 'bank_transfer_' + _uuid.uuid4().hex[:16] return TransferResponse( Success=True, OutTransferNO=request.OutTransferNO, TransferID=transfer_id, RawResponse={'transfer_id': transfer_id, 'note': '生产环境需调用银行代付接口'}, )