fix: 待收款驳回按业务单号查打款记录,避免 pk 误查导致 400
This commit is contained in:
@@ -1314,6 +1314,36 @@ def mark_transfer_success(auto_record, *, wechat_transfer_no=None, with_accounti
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _lock_auto_record_by_audit(audit):
|
||||||
|
"""
|
||||||
|
按审核单锁定关联打款记录。
|
||||||
|
audit.tixian_auto_id 存的是 TixianAutoRecord.tixian_id(业务单号),不是自增 pk。
|
||||||
|
"""
|
||||||
|
auto = None
|
||||||
|
auto_id = (getattr(audit, 'tixian_auto_id', None) or '').strip()
|
||||||
|
if auto_id:
|
||||||
|
auto = (
|
||||||
|
TixianAutoRecord.objects.select_for_update()
|
||||||
|
.filter(tixian_id=auto_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
# 兼容极少数历史数据误存自增 id
|
||||||
|
if auto is None and auto_id.isdigit():
|
||||||
|
auto = (
|
||||||
|
TixianAutoRecord.objects.select_for_update()
|
||||||
|
.filter(pk=int(auto_id))
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
if auto is None and getattr(audit, 'shenhe_danhao', None):
|
||||||
|
auto = (
|
||||||
|
TixianAutoRecord.objects.select_for_update()
|
||||||
|
.filter(shenhe_danhao=audit.shenhe_danhao)
|
||||||
|
.order_by('-CreateTime')
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return auto
|
||||||
|
|
||||||
|
|
||||||
def admin_mark_pending_collect_success(audit, tixian, kefu_uid, *, with_accounting=True):
|
def admin_mark_pending_collect_success(audit, tixian, kefu_uid, *, with_accounting=True):
|
||||||
"""
|
"""
|
||||||
客服强制:待收款(6) → 提现成功(2)。
|
客服强制:待收款(6) → 提现成功(2)。
|
||||||
@@ -1323,25 +1353,18 @@ def admin_mark_pending_collect_success(audit, tixian, kefu_uid, *, with_accounti
|
|||||||
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
|
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
|
||||||
tixian = Tixianjilu.objects.select_for_update().get(pk=tixian.pk)
|
tixian = Tixianjilu.objects.select_for_update().get(pk=tixian.pk)
|
||||||
if int(audit.zhuangtai) != 6 or int(tixian.zhuangtai) != 6:
|
if int(audit.zhuangtai) != 6 or int(tixian.zhuangtai) != 6:
|
||||||
raise ValueError('仅待收款状态可标记为已收款')
|
raise ValueError(
|
||||||
|
f'仅待收款状态可标记为已收款'
|
||||||
|
f'(当前提现单={tixian.zhuangtai},审核单={audit.zhuangtai})'
|
||||||
|
)
|
||||||
|
|
||||||
# 1) 先改状态
|
# 1) 先改状态
|
||||||
sync_audit_and_jilu_status(audit, 2, shenhe_ren_id=kefu_uid or '')
|
sync_audit_and_jilu_status(audit, 2, shenhe_ren_id=(kefu_uid or '')[:11])
|
||||||
tixian.shenheid = kefu_uid or tixian.shenheid or ''
|
tixian.shenheid = (kefu_uid or tixian.shenheid or '')[:11]
|
||||||
tixian.save(update_fields=['shenheid', 'UpdateTime'])
|
tixian.save(update_fields=['shenheid', 'UpdateTime'])
|
||||||
|
|
||||||
# 2) 关联打款单:处理中→成功;无打款单则直接按审核金额记账
|
# 2) 关联打款单:处理中→成功;无打款单则直接按审核金额记账
|
||||||
auto = None
|
auto = _lock_auto_record_by_audit(audit)
|
||||||
auto_id = (getattr(audit, 'tixian_auto_id', None) or '').strip()
|
|
||||||
if auto_id:
|
|
||||||
auto = TixianAutoRecord.objects.select_for_update().filter(pk=auto_id).first()
|
|
||||||
if auto is None and audit.shenhe_danhao:
|
|
||||||
auto = (
|
|
||||||
TixianAutoRecord.objects.select_for_update()
|
|
||||||
.filter(shenhe_danhao=audit.shenhe_danhao)
|
|
||||||
.order_by('-CreateTime')
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
if auto is not None:
|
if auto is not None:
|
||||||
if int(auto.zhuangtai) == 0:
|
if int(auto.zhuangtai) == 0:
|
||||||
@@ -1392,26 +1415,26 @@ def admin_reject_pending_or_auditing(
|
|||||||
"""
|
"""
|
||||||
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
|
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
|
||||||
tixian = Tixianjilu.objects.select_for_update().get(pk=tixian.pk)
|
tixian = Tixianjilu.objects.select_for_update().get(pk=tixian.pk)
|
||||||
cur = int(audit.zhuangtai)
|
jt = int(tixian.zhuangtai)
|
||||||
if cur not in (1, 6):
|
at = int(audit.zhuangtai)
|
||||||
raise ValueError('仅审核中/待收款可驳回')
|
if jt not in (1, 6) or at not in (1, 6):
|
||||||
if int(tixian.zhuangtai) != cur:
|
raise ValueError(
|
||||||
raise ValueError('提现单与审核单状态不一致')
|
f'仅审核中/待收款可驳回(当前提现单={jt},审核单={at})'
|
||||||
|
)
|
||||||
|
# 两边都可驳回但不同步时,以审核单为准对齐提现单后再驳回
|
||||||
|
if jt != at:
|
||||||
|
logger.warning(
|
||||||
|
'驳回前状态不一致,对齐提现单→审核单 tixian=%s jt=%s at=%s',
|
||||||
|
tixian.id, jt, at,
|
||||||
|
)
|
||||||
|
tixian.zhuangtai = at
|
||||||
|
tixian.save(update_fields=['zhuangtai', 'UpdateTime'])
|
||||||
|
|
||||||
reason = (reason or '').strip()[:500] or '客服驳回'
|
reason = (reason or '').strip()[:500] or '客服驳回'
|
||||||
|
kefu_uid = (kefu_uid or '')[:11]
|
||||||
|
|
||||||
# 待收款可能已有打款单:先失败释放限额,避免用户还能收款
|
# 待收款可能已有打款单:先失败释放限额,避免用户还能收款
|
||||||
auto_id = (getattr(audit, 'tixian_auto_id', None) or '').strip()
|
auto = _lock_auto_record_by_audit(audit)
|
||||||
auto = None
|
|
||||||
if auto_id:
|
|
||||||
auto = TixianAutoRecord.objects.select_for_update().filter(pk=auto_id).first()
|
|
||||||
if auto is None and audit.shenhe_danhao:
|
|
||||||
auto = (
|
|
||||||
TixianAutoRecord.objects.select_for_update()
|
|
||||||
.filter(shenhe_danhao=audit.shenhe_danhao, zhuangtai=0)
|
|
||||||
.order_by('-CreateTime')
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
if auto is not None and int(auto.zhuangtai) == 0:
|
if auto is not None and int(auto.zhuangtai) == 0:
|
||||||
_close_auto_record_failed(auto, reason)
|
_close_auto_record_failed(auto, reason)
|
||||||
|
|
||||||
@@ -1419,7 +1442,7 @@ def admin_reject_pending_or_auditing(
|
|||||||
sync_audit_and_jilu_status(
|
sync_audit_and_jilu_status(
|
||||||
audit, 5,
|
audit, 5,
|
||||||
bhliyou=reason,
|
bhliyou=reason,
|
||||||
bo_hui_ren_id=kefu_uid or '',
|
bo_hui_ren_id=kefu_uid or None,
|
||||||
tixian_auto_id=None,
|
tixian_auto_id=None,
|
||||||
)
|
)
|
||||||
tixian.shenheid = kefu_uid or tixian.shenheid or ''
|
tixian.shenheid = kefu_uid or tixian.shenheid or ''
|
||||||
@@ -1437,7 +1460,7 @@ def admin_reject_pending_or_auditing(
|
|||||||
shouxufei=audit.shouxufei,
|
shouxufei=audit.shouxufei,
|
||||||
refund_fee=bool(refund_fee),
|
refund_fee=bool(refund_fee),
|
||||||
apply_entry_freeze=bool(apply_entry_freeze),
|
apply_entry_freeze=bool(apply_entry_freeze),
|
||||||
biz_id=f'withdraw_reject:admin:{tixian.id}:{cur}',
|
biz_id=f'withdraw_reject:admin:{tixian.id}:{at}',
|
||||||
freeze_reason=f'提现驳回退款 #{tixian.id}',
|
freeze_reason=f'提现驳回退款 #{tixian.id}',
|
||||||
)
|
)
|
||||||
return refund_result
|
return refund_result
|
||||||
|
|||||||
@@ -728,7 +728,10 @@ class KefuWithdrawActionView(APIView):
|
|||||||
# action=2:审核中/待收款 → 驳回
|
# action=2:审核中/待收款 → 驳回
|
||||||
if action == 2:
|
if action == 2:
|
||||||
if cur not in (1, 6) or int(audit.zhuangtai) not in (1, 6):
|
if cur not in (1, 6) or int(audit.zhuangtai) not in (1, 6):
|
||||||
raise ValueError(f'提现记录{tixian_id}:仅审核中/待收款可驳回')
|
raise ValueError(
|
||||||
|
f'提现记录{tixian_id}:仅审核中/待收款可驳回'
|
||||||
|
f'(当前提现单={cur},审核单={audit.zhuangtai})'
|
||||||
|
)
|
||||||
admin_reject_pending_or_auditing(
|
admin_reject_pending_or_auditing(
|
||||||
audit, tixian, user, kefu_uid, reason,
|
audit, tixian, user, kefu_uid, reason,
|
||||||
refund_principal=refund_principal,
|
refund_principal=refund_principal,
|
||||||
@@ -902,6 +905,7 @@ class KefuWithdrawActionView(APIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
logger.warning('kefu_txsh_action 业务拒绝: %s data=%s', e, request.data)
|
||||||
return Response({'code': 400, 'msg': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'code': 400, 'msg': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'处理提现事务失败: {e}', exc_info=True)
|
logger.error(f'处理提现事务失败: {e}', exc_info=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user