fix: 收款不再预查微信,恢复早期「有package就调起」逻辑

接入多俱乐部后每次收款先查微信,V3查单失败会永久返回code12。
改为仅读本地:有package直接确认,无package立刻作废重试;转账失败返回明确错误。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-10 22:07:09 +08:00
parent 8bc0afb7f4
commit d6237ccc7b
2 changed files with 29 additions and 73 deletions

View File

@@ -105,7 +105,7 @@ RECONCILE_AUDIT_CLOSED = 'audit_closed'
# 单笔实际到账上限(仅收款时校验)
MAX_SINGLE_COLLECT_AMOUNT = decimal.Decimal('200')
# 查单失败且本地 zhuangtai=0 超过该秒数,才短暂提示「发起中」
# tixianqr 查单时:无 package 且微信 404 超过该秒数才提示处理中
PENDING_QUERY_GRACE_SECONDS = 20
@@ -1292,8 +1292,10 @@ def _collapse_stale_pending_records(shenhe_danhao):
def reconcile_shenhe_wechat_bills(shenhe_danhao):
"""
收款前对账:防双笔,但不因查单失败无限「处理中」
原则:有 package 就调起微信确认;无 package 的旧单作废;仅极短窗口内提示发起中。
收款前对账(仅读本地库,不阻塞查微信)
早期可用版本也是:有 package 直接调起确认;没有 package 就重新发起转账。
多俱乐部改造后「每次收款先查微信」在 V3 配置/查单异常时会永远返回处理中,已移除。
"""
records = list(
TixianAutoRecord.query.filter(shenhe_danhao=shenhe_danhao).order_by('-CreateTime')
@@ -1316,46 +1318,10 @@ def reconcile_shenhe_wechat_bills(shenhe_danhao):
if local_wait:
return local_wait
age = timezone.now() - pending.CreateTime
if not _parse_package_info(pending.wechat_package):
if age >= timedelta(seconds=PENDING_QUERY_GRACE_SECONDS):
_mark_transfer_attempt_failed(
pending, '上次发起未成功,请重新收款', close_audit=False,
)
return RECONCILE_ALLOW_NEW, {}
return RECONCILE_PENDING, {
'msg': '收款发起中,请稍后再试',
'tixian_id': pending.tixian_id,
}
wx_data = query_wechat_transfer_bill(
pending.tixian_id, club_id_for_tixian_yonghuid(pending.yonghuid),
# 进行中但无 package = 上次调微信没成功,立刻作废,允许本次重新发起
_mark_transfer_attempt_failed(
pending, '上次发起未成功,请重新收款', close_audit=False,
)
if wx_data is None:
logger.warning(
'查单不可用 bill=%s,使用本地 package 继续收款', pending.tixian_id,
)
return RECONCILE_WAIT_CONFIRM, _wait_confirm_payload(
pending, _parse_package_info(pending.wechat_package),
)
action, payload = _sync_record_from_wx_query(pending, wx_data)
if action == RECONCILE_COMPLETED:
return action, payload
if action == RECONCILE_WAIT_CONFIRM:
return action, payload
if action == RECONCILE_ALLOW_NEW:
return action, payload
if action == RECONCILE_AUDIT_CLOSED:
return action, payload
if action == RECONCILE_PENDING:
pkg = _parse_package_info(pending.wechat_package)
if pkg:
return RECONCILE_WAIT_CONFIRM, _wait_confirm_payload(pending, pkg)
if age >= timedelta(seconds=PENDING_QUERY_GRACE_SECONDS):
_mark_transfer_attempt_failed(pending, '收款超时,请重新发起', close_audit=False)
return RECONCILE_ALLOW_NEW, {}
return action, payload
return RECONCILE_ALLOW_NEW, {}
@@ -1429,30 +1395,20 @@ def resolve_collect_context(yonghuid, tixianjilu_id=None, shenhe_danhao='', shen
def handle_post_transfer_failure(tixian_id, shenhe_danhao, err_code='', err_msg=''):
"""
发起转账 HTTP 非成功先查微信再决定是否标失败P0禁止盲目标失败导致双笔
返回 (action, payload_or_user_msg)
发起转账 HTTP 非成功:本地已有 package 则继续调起确认;否则标失败并返回可重试。
"""
try:
ar = TixianAutoRecord.query.get(tixian_id=tixian_id)
except TixianAutoRecord.DoesNotExist:
return RECONCILE_PENDING, '收款处理中,请稍后再试'
wx_data = query_wechat_transfer_bill(tixian_id, club_id_for_tixian_yonghuid(ar.yonghuid))
if wx_data is None:
local = _maybe_wait_confirm_from_local(ar)
if local:
return local
_mark_transfer_attempt_failed(ar, err_msg or '微信发起转账失败', close_audit=False)
return RECONCILE_ALLOW_NEW, {'wx_err': err_msg or '微信发起转账失败'}
action, payload = _sync_record_from_wx_query(ar, wx_data)
if action == RECONCILE_ALLOW_NEW:
return RECONCILE_ALLOW_NEW, payload
if action == RECONCILE_WAIT_CONFIRM:
return RECONCILE_WAIT_CONFIRM, payload
if action == RECONCILE_COMPLETED:
return RECONCILE_COMPLETED, payload
return RECONCILE_PENDING, payload.get('msg', '收款处理中,请稍后再试')
local = _maybe_wait_confirm_from_local(ar)
if local:
return local
reason = (err_msg or err_code or '微信发起转账失败')[:500]
_mark_transfer_attempt_failed(ar, reason, close_audit=False)
return RECONCILE_ALLOW_NEW, {'wx_err': reason}
def get_audit_for_collect(shenhe_danhao, yonghuid, shenhe_jilu_id=None):

View File

@@ -272,11 +272,13 @@ def process_audit_collect(request):
return quota_resp
return _build_collect_success_response(payload)
if action == RECONCILE_PENDING:
msg = payload.get('msg') if isinstance(payload, dict) else payload
return Response({'code': 12, 'msg': msg or '有收款处理中,请稍后再试'})
logger.warning(
'收款对账不应再返回 PENDING shenhe_danhao=%s payload=%s',
shenhe_danhao, payload,
)
if action != RECONCILE_ALLOW_NEW:
return Response({'code': 12, 'msg': '收款处理中,请稍后再试'})
return Response({'code': 99, 'msg': '收款状态异常,请再次点击收款'})
with transaction.atomic():
audit, err = get_audit_for_collect(
@@ -344,8 +346,9 @@ def process_audit_collect(request):
err_code = wx_result.get('code', '')
err_msg = wx_result.get('message', wx_result.get('detail', '微信接口调用失败'))
logger.error(
'微信发起转账未进入待确认: bill=%s code=%s msg=%s HTTP%s',
tixian_id, err_code, err_msg, resp.status_code,
'微信发起转账未进入待确认: bill=%s club=%s appid=%s mch=%s code=%s msg=%s HTTP%s body=%s',
tixian_id, payout_club_id, wx_cfg.get('APPID'), wx_cfg.get('MCHID'),
err_code, err_msg, resp.status_code, json.dumps(wx_result, ensure_ascii=False)[:500],
)
is_balance_issue = _is_wx_balance_insufficient(err_code, err_msg)
@@ -376,14 +379,11 @@ def process_audit_collect(request):
'code': 400,
'msg': post_payload.get('msg', '该笔提现已关闭,请重新申请'),
})
if post_action == RECONCILE_PENDING:
pending_msg = (
post_payload.get('msg', post_payload)
if isinstance(post_payload, dict) else post_payload
)
return Response({'code': 12, 'msg': pending_msg or '有收款处理中,请稍后再试'})
user_msg = err_msg or '微信收款发起失败,请稍后重试'
user_msg = (
(post_payload.get('wx_err') if isinstance(post_payload, dict) else None)
or err_msg
or '微信收款发起失败,请稍后重试'
)
_mark_auto_record_failed(tixian_id, user_msg)
if quota_reserved:
release_collect_quota_for_record(