"""付呗支付结果确认:主动查单(轮询/复查兜底,不依赖回调)。""" from __future__ import annotations import logging from typing import Any, Dict, Optional, Tuple from jituan.constants import PAY_CHANNEL_FUBEI_WX_MINI from jituan.services.club_payment_channel import get_fubei_config from jituan.services import fubei_client from jituan.services.mini_pay_router import get_pay_ledger logger = logging.getLogger(__name__) def is_fubei_out_trade_no(out_trade_no: str) -> bool: ledger = get_pay_ledger(out_trade_no) return bool(ledger and ledger.channel == PAY_CHANNEL_FUBEI_WX_MINI) def query_fubei_trade( out_trade_no: str, club_id: Optional[str] = None, ) -> Optional[Dict[str, Any]]: """ 查询付呗订单。 非付呗单返回 None;付呗单返回 data 字典(含 trade_state 等)。 """ ledger = get_pay_ledger(out_trade_no) if not ledger or ledger.channel != PAY_CHANNEL_FUBEI_WX_MINI: return None cid = (club_id or ledger.club_id or '').strip() cfg = get_fubei_config(cid) if not cfg or not cfg.app_id or not cfg.api_key: logger.error('[FUBEI_QUERY] 配置缺失 club=%s out_trade_no=%s', cid, out_trade_no) raise Exception('付呗查单配置缺失') data = fubei_client.query_order( gateway_url=cfg.gateway_url, app_id=cfg.app_id, app_secret=cfg.api_key, merchant_order_sn=out_trade_no, order_sn=ledger.provider_order_sn or '', ) logger.info( '[FUBEI_QUERY] out_trade_no=%s trade_state=%s', out_trade_no, data.get('trade_state'), ) return data def fubei_trade_is_success(data: Optional[Dict[str, Any]]) -> bool: if not data: return False state = str(data.get('trade_state') or '').upper() return state == 'SUCCESS' def fubei_success_payload( out_trade_no: str, club_id: Optional[str] = None, ) -> Optional[Tuple[str, Any]]: """ 若是付呗单且已支付成功,返回 (transaction_id, total_fee); 若是付呗单但未成功,返回 ('', None) 且调用方可据此判断「支付中」; 若不是付呗单,返回 None(继续走微信/支付宝查单)。 """ try: data = query_fubei_trade(out_trade_no, club_id) except Exception as exc: # 明确是付呗单但查单失败:不要回落到微信直连(会永远查不到) ledger = get_pay_ledger(out_trade_no) if ledger and ledger.channel == PAY_CHANNEL_FUBEI_WX_MINI: logger.error('[FUBEI_QUERY] 付呗单查单异常 %s: %s', out_trade_no, exc, exc_info=True) return ('', None) return None if data is None: return None if not fubei_trade_is_success(data): return ('', None) txn = str( data.get('trade_no') or data.get('platform_order_no') or data.get('order_sn') or out_trade_no or 'FUBEI_PAID' ) total_fee = data.get('total_fee') or data.get('cash_fee') or data.get('order_price') return (txn, total_fee)