151 lines
4.7 KiB
Python
151 lines
4.7 KiB
Python
"""
|
||
支付专用商户配置(与提现收款 WechatPayMchConfig / wechat_mch_service 完全分离)。
|
||
|
||
读取优先级:
|
||
1) XcxSysPeizhi.pay_*
|
||
2) 过渡回退:旧 weixin_* / settings.WEIXIN_*
|
||
历史订单退款:若订单 pay_mch_id 与当前支付商户不一致,但等于旧 weixin_mchid,则用旧 weixin_* 退款。
|
||
"""
|
||
import logging
|
||
import os
|
||
|
||
from django.conf import settings
|
||
|
||
from utils.xcx_sys_config import wx_cfg, _val
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def pay_cert_base_dir():
|
||
base = getattr(settings, 'WECHAT_PAY_CERT_BASE_DIR', '') or ''
|
||
if base:
|
||
return base
|
||
return os.path.join(str(settings.BASE_DIR), 'zhifuzhengshu')
|
||
|
||
|
||
def _pay_val(pay_attr, legacy_db_attr, settings_attr, default=''):
|
||
"""pay_* 优先;空则回退旧 weixin_* / settings。"""
|
||
v = _val(pay_attr, None, None)
|
||
if v is not None and v != '':
|
||
return v
|
||
return _val(legacy_db_attr, settings_attr, default) or default
|
||
|
||
|
||
class PayWxConfig:
|
||
"""支付商户配置代理(属性名兼容旧 WEIXIN_*,便于替换调用点)。"""
|
||
|
||
@property
|
||
def WEIXIN_MCHID(self):
|
||
return _pay_val('pay_mch_id', 'weixin_mchid', 'WEIXIN_MCHID', '')
|
||
|
||
@property
|
||
def WEIXIN_SHANGHUMIYAO(self):
|
||
return _pay_val('pay_api_v2_key', 'weixin_shanghu_miyao', 'WEIXIN_SHANGHUMIYAO', '')
|
||
|
||
@property
|
||
def WEIXIN_NOTIFY_URL(self):
|
||
return _pay_val('pay_notify_url', 'weixin_notify_url', 'WEIXIN_NOTIFY_URL', '')
|
||
|
||
@property
|
||
def WEIXIN_CERT_PATH(self):
|
||
return _pay_val('pay_cert_path', 'weixin_cert_path', 'WEIXIN_CERT_PATH', '')
|
||
|
||
@property
|
||
def WEIXIN_KEY_PATH(self):
|
||
return _pay_val('pay_key_path', 'weixin_key_path', 'WEIXIN_KEY_PATH', '')
|
||
|
||
@property
|
||
def PAY_API_V3_KEY(self):
|
||
return _val('pay_api_v3_key', None, '') or ''
|
||
|
||
@property
|
||
def PAY_CERT_SERIAL_NO(self):
|
||
return _val('pay_cert_serial_no', None, '') or ''
|
||
|
||
# 别名,语义更清晰
|
||
@property
|
||
def PAY_MCH_ID(self):
|
||
return self.WEIXIN_MCHID
|
||
|
||
@property
|
||
def PAY_API_V2_KEY(self):
|
||
return self.WEIXIN_SHANGHUMIYAO
|
||
|
||
|
||
pay_cfg = PayWxConfig()
|
||
|
||
|
||
def get_current_pay_mch_id():
|
||
return (pay_cfg.PAY_MCH_ID or '').strip()
|
||
|
||
|
||
def pay_cfg_as_dict():
|
||
return {
|
||
'MCHID': pay_cfg.WEIXIN_MCHID,
|
||
'KEY': pay_cfg.WEIXIN_SHANGHUMIYAO,
|
||
'NOTIFY_URL': pay_cfg.WEIXIN_NOTIFY_URL,
|
||
'CERT_PATH': pay_cfg.WEIXIN_CERT_PATH,
|
||
'KEY_PATH': pay_cfg.WEIXIN_KEY_PATH,
|
||
'API_V3_KEY': pay_cfg.PAY_API_V3_KEY,
|
||
'CERT_SERIAL_NO': pay_cfg.PAY_CERT_SERIAL_NO,
|
||
}
|
||
|
||
|
||
def get_pay_wx_cfg(mch_id=None):
|
||
"""
|
||
按商户号取支付配置(用于退款反查)。
|
||
- mch_id 空 / 等于当前支付商户 → 当前 pay_cfg
|
||
- mch_id 等于旧 weixin_mchid 且与当前不同 → 用旧 weixin_*(换号后历史单退款)
|
||
- 否则若 zhifuzhengshu/{mch_id}/ 下有证书,拼路径但仍需密钥;密钥仅当前/旧库有,故仍回退当前并打日志
|
||
"""
|
||
current = pay_cfg_as_dict()
|
||
want = (mch_id or '').strip()
|
||
current_mch = (current.get('MCHID') or '').strip()
|
||
if not want or want == current_mch:
|
||
return current
|
||
|
||
legacy_mch = (wx_cfg.WEIXIN_MCHID or '').strip()
|
||
if want == legacy_mch and want != current_mch:
|
||
return {
|
||
'MCHID': wx_cfg.WEIXIN_MCHID,
|
||
'KEY': wx_cfg.WEIXIN_SHANGHUMIYAO,
|
||
'NOTIFY_URL': wx_cfg.WEIXIN_NOTIFY_URL,
|
||
'CERT_PATH': wx_cfg.WEIXIN_CERT_PATH,
|
||
'KEY_PATH': wx_cfg.WEIXIN_KEY_PATH,
|
||
'API_V3_KEY': '',
|
||
'CERT_SERIAL_NO': '',
|
||
}
|
||
|
||
cert_path = os.path.join(pay_cert_base_dir(), want, 'apiclient_cert.pem')
|
||
key_path = os.path.join(pay_cert_base_dir(), want, 'apiclient_key.pem')
|
||
if os.path.isfile(cert_path) and os.path.isfile(key_path):
|
||
logger.warning(
|
||
'支付商户 %s 与当前配置 %s 不一致,仅找到证书文件,密钥仍用当前配置,退款可能失败',
|
||
want, current_mch,
|
||
)
|
||
out = dict(current)
|
||
out['MCHID'] = want
|
||
out['CERT_PATH'] = cert_path
|
||
out['KEY_PATH'] = key_path
|
||
return out
|
||
|
||
logger.warning(
|
||
'订单支付商户 %s 无可用历史配置,回退当前支付商户 %s',
|
||
want, current_mch,
|
||
)
|
||
return current
|
||
|
||
|
||
def apply_pay_cfg_to_proxy(cfg_dict):
|
||
"""把 get_pay_wx_cfg 结果转成带 WEIXIN_* 属性的简单对象,兼容旧代码写法。"""
|
||
class _Cfg:
|
||
pass
|
||
|
||
o = _Cfg()
|
||
o.WEIXIN_MCHID = cfg_dict.get('MCHID') or ''
|
||
o.WEIXIN_SHANGHUMIYAO = cfg_dict.get('KEY') or ''
|
||
o.WEIXIN_NOTIFY_URL = cfg_dict.get('NOTIFY_URL') or ''
|
||
o.WEIXIN_CERT_PATH = cfg_dict.get('CERT_PATH') or ''
|
||
o.WEIXIN_KEY_PATH = cfg_dict.get('KEY_PATH') or ''
|
||
return o
|