Files

113 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""模块:银行卡适配器
实现银行卡支付适配(银联/网银/快捷支付)。
支持银联全渠道、网银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': '生产环境需调用银行代付接口'},
)