fix: 星阙V3提现强制用全局证书配置,修复序列号与私钥不匹配
club表私钥路径/序列号错填会导致微信报证书序列号错误。 xq 提现改读 settings+写死序列号;build_authorization 双重兜底。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -379,7 +379,8 @@ WECHAT_PAY_V3_CONFIG = {
|
|||||||
'APPID': app_secrets.WECHAT_PAY_V3_APPID,
|
'APPID': app_secrets.WECHAT_PAY_V3_APPID,
|
||||||
'API_V3_KEY': app_secrets.WECHAT_PAY_V3_API_V3_KEY,
|
'API_V3_KEY': app_secrets.WECHAT_PAY_V3_API_V3_KEY,
|
||||||
'PRIVATE_KEY_PATH': app_secrets.WECHAT_PAY_V3_PRIVATE_KEY_PATH,
|
'PRIVATE_KEY_PATH': app_secrets.WECHAT_PAY_V3_PRIVATE_KEY_PATH,
|
||||||
'CERT_SERIAL_NO': app_secrets.WECHAT_PAY_V3_CERT_SERIAL_NO,
|
# 与服务器 apiclient_key.pem 对应;勿用 club 表错误值
|
||||||
|
'CERT_SERIAL_NO': '481784CF56E872D9D8122BAC64E6BC7390803582',
|
||||||
'PLATFORM_CERT_DIR': app_secrets.WECHAT_PAY_V3_PLATFORM_CERT_DIR,
|
'PLATFORM_CERT_DIR': app_secrets.WECHAT_PAY_V3_PLATFORM_CERT_DIR,
|
||||||
'NOTIFY_URL': 'https://www.abas.asia/hqhd/yonghu/tixiancallback',
|
'NOTIFY_URL': 'https://www.abas.asia/hqhd/yonghu/tixiancallback',
|
||||||
'TRANSFER_SCENE_ID': '1005',
|
'TRANSFER_SCENE_ID': '1005',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from django.conf import settings
|
|||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from jituan.constants import CLUB_ID_DEFAULT
|
from jituan.services.wechat_pay import WX_V3_CERT_SERIAL_NO_OVERRIDE
|
||||||
from jituan.models import (
|
from jituan.models import (
|
||||||
Club,
|
Club,
|
||||||
ClubHuiyuanPrice,
|
ClubHuiyuanPrice,
|
||||||
@@ -45,7 +45,7 @@ class Command(BaseCommand):
|
|||||||
'pay_app_id': wx_v3.get('APPID', '') or getattr(settings, 'WEIXIN_APPID', ''),
|
'pay_app_id': wx_v3.get('APPID', '') or getattr(settings, 'WEIXIN_APPID', ''),
|
||||||
'mch_key': getattr(settings, 'WEIXIN_SHANGHUMIYAO', ''),
|
'mch_key': getattr(settings, 'WEIXIN_SHANGHUMIYAO', ''),
|
||||||
'api_v3_key': wx_v3.get('API_V3_KEY', ''),
|
'api_v3_key': wx_v3.get('API_V3_KEY', ''),
|
||||||
'cert_serial_no': wx_v3.get('CERT_SERIAL_NO', ''),
|
'cert_serial_no': WX_V3_CERT_SERIAL_NO_OVERRIDE,
|
||||||
'private_key_path': wx_v3.get('PRIVATE_KEY_PATH', ''),
|
'private_key_path': wx_v3.get('PRIVATE_KEY_PATH', ''),
|
||||||
'platform_cert_dir': wx_v3.get('PLATFORM_CERT_DIR', ''),
|
'platform_cert_dir': wx_v3.get('PLATFORM_CERT_DIR', ''),
|
||||||
'config_json': {
|
'config_json': {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""各俱乐部微信支付 V2(MD5)配置与验签。"""
|
"""各俱乐部微信支付 V2(MD5)配置与验签。"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
@@ -209,10 +210,26 @@ def _apply_v3_cert_serial_override(cfg):
|
|||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
def _log_v3_config(cfg):
|
||||||
|
key_path = (cfg.get('PRIVATE_KEY_PATH') or '').strip()
|
||||||
|
logger.warning(
|
||||||
|
'[WX_V3_CONFIG] club=%s appid=%s mch=%s serial=%s key_path=%s key_exists=%s',
|
||||||
|
cfg.get('club_id'),
|
||||||
|
cfg.get('APPID'),
|
||||||
|
cfg.get('MCHID'),
|
||||||
|
cfg.get('CERT_SERIAL_NO'),
|
||||||
|
key_path,
|
||||||
|
bool(key_path and os.path.isfile(key_path)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_wechat_v3_config(club_id=None):
|
def get_wechat_v3_config(club_id=None):
|
||||||
"""
|
"""
|
||||||
微信 V3(转账/查单)配置。
|
微信 V3(转账/查单)配置。
|
||||||
各俱乐部(含 xq)优先读 club 表;字段为空时按项回落 settings.WECHAT_PAY_V3_CONFIG。
|
|
||||||
|
星阙(xq):证书序列号、私钥、api_v3_key、商户号强制用 settings 全局配置,
|
||||||
|
避免 club 表错填导致「证书序列号与私钥不匹配」。仅 AppID 读 club 小程序配置。
|
||||||
|
其他俱乐部仍读 club 表,但序列号统一写死覆盖。
|
||||||
"""
|
"""
|
||||||
cid = (club_id or '').strip() or CLUB_ID_DEFAULT
|
cid = (club_id or '').strip() or CLUB_ID_DEFAULT
|
||||||
wx = dict(getattr(settings, 'WECHAT_PAY_V3_CONFIG', {}) or {})
|
wx = dict(getattr(settings, 'WECHAT_PAY_V3_CONFIG', {}) or {})
|
||||||
@@ -220,35 +237,43 @@ def get_wechat_v3_config(club_id=None):
|
|||||||
'APPID': wx.get('APPID', ''),
|
'APPID': wx.get('APPID', ''),
|
||||||
'MCHID': wx.get('MCHID', ''),
|
'MCHID': wx.get('MCHID', ''),
|
||||||
'PRIVATE_KEY_PATH': wx.get('PRIVATE_KEY_PATH', ''),
|
'PRIVATE_KEY_PATH': wx.get('PRIVATE_KEY_PATH', ''),
|
||||||
'CERT_SERIAL_NO': wx.get('CERT_SERIAL_NO', ''),
|
'CERT_SERIAL_NO': WX_V3_CERT_SERIAL_NO_OVERRIDE,
|
||||||
'API_V3_KEY': wx.get('API_V3_KEY', ''),
|
'API_V3_KEY': wx.get('API_V3_KEY', ''),
|
||||||
'PLATFORM_CERT_DIR': wx.get('PLATFORM_CERT_DIR', ''),
|
'PLATFORM_CERT_DIR': wx.get('PLATFORM_CERT_DIR', ''),
|
||||||
'TRANSFER_SCENE_ID': wx.get('TRANSFER_SCENE_ID', '1005'),
|
'TRANSFER_SCENE_ID': wx.get('TRANSFER_SCENE_ID', '1005'),
|
||||||
'club_id': cid,
|
'club_id': cid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cid == CLUB_ID_DEFAULT:
|
||||||
|
cfg = dict(fallback)
|
||||||
|
try:
|
||||||
|
club = Club.query.get(club_id=cid)
|
||||||
|
mini_appid = get_club_miniapp_appid(club)
|
||||||
|
if mini_appid:
|
||||||
|
cfg['APPID'] = mini_appid
|
||||||
|
except Club.DoesNotExist:
|
||||||
|
pass
|
||||||
|
_log_v3_config(cfg)
|
||||||
|
return cfg
|
||||||
|
|
||||||
try:
|
try:
|
||||||
club = Club.query.get(club_id=cid)
|
club = Club.query.get(club_id=cid)
|
||||||
except Club.DoesNotExist:
|
except Club.DoesNotExist:
|
||||||
logger.warning('club %s 不存在,回落全局 V3 支付配置', cid)
|
logger.warning('club %s 不存在,回落全局 V3 支付配置', cid)
|
||||||
return _apply_v3_cert_serial_override(fallback)
|
cfg = _apply_v3_cert_serial_override(fallback)
|
||||||
|
_log_v3_config(cfg)
|
||||||
|
return cfg
|
||||||
|
|
||||||
cfg_json = club.config_json or {}
|
cfg_json = club.config_json or {}
|
||||||
return _apply_v3_cert_serial_override({
|
cfg = _apply_v3_cert_serial_override({
|
||||||
'APPID': get_club_miniapp_appid(club) or (
|
'APPID': get_club_miniapp_appid(club) or '',
|
||||||
fallback['APPID'] if cid == CLUB_ID_DEFAULT else ''
|
|
||||||
),
|
|
||||||
'MCHID': club.mch_id or fallback['MCHID'],
|
'MCHID': club.mch_id or fallback['MCHID'],
|
||||||
'PRIVATE_KEY_PATH': (
|
'PRIVATE_KEY_PATH': (
|
||||||
club.private_key_path
|
club.private_key_path
|
||||||
or cfg_json.get('private_key_path')
|
or cfg_json.get('private_key_path')
|
||||||
or fallback['PRIVATE_KEY_PATH']
|
or fallback['PRIVATE_KEY_PATH']
|
||||||
),
|
),
|
||||||
'CERT_SERIAL_NO': (
|
'CERT_SERIAL_NO': fallback['CERT_SERIAL_NO'],
|
||||||
club.cert_serial_no
|
|
||||||
or cfg_json.get('cert_serial_no')
|
|
||||||
or fallback['CERT_SERIAL_NO']
|
|
||||||
),
|
|
||||||
'API_V3_KEY': (
|
'API_V3_KEY': (
|
||||||
club.api_v3_key
|
club.api_v3_key
|
||||||
or cfg_json.get('api_v3_key')
|
or cfg_json.get('api_v3_key')
|
||||||
@@ -266,6 +291,8 @@ def get_wechat_v3_config(club_id=None):
|
|||||||
),
|
),
|
||||||
'club_id': cid,
|
'club_id': cid,
|
||||||
})
|
})
|
||||||
|
_log_v3_config(cfg)
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def club_id_for_tixian_yonghuid(yonghuid):
|
def club_id_for_tixian_yonghuid(yonghuid):
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ def build_authorization(method, url, body, club_id=None):
|
|||||||
cfg = _get_v3_config(club_id)
|
cfg = _get_v3_config(club_id)
|
||||||
private_key = load_private_key(club_id)
|
private_key = load_private_key(club_id)
|
||||||
mchid = cfg['MCHID']
|
mchid = cfg['MCHID']
|
||||||
serial_no = cfg['CERT_SERIAL_NO']
|
serial_no = (cfg.get('CERT_SERIAL_NO') or '').strip().upper()
|
||||||
|
if not serial_no:
|
||||||
|
from jituan.services.wechat_pay import WX_V3_CERT_SERIAL_NO_OVERRIDE
|
||||||
|
serial_no = WX_V3_CERT_SERIAL_NO_OVERRIDE
|
||||||
|
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
path = parsed.path
|
path = parsed.path
|
||||||
|
|||||||
Reference in New Issue
Block a user