优化一下自动提现接口就是user/tixian_shenhe_servers.py,tixian_shenhe_views.py,让文件以及对应的申请,回调,确认接口,让它更好用一点,允许用户多次提现审核,强化收款接口,及时更新数据库中的收款状态,其次,更新了客服提现审核接口,关于大于200元的提现,同意之后直接按驳回处理,微信官方不支持大于200元的提现申请去掉了订单24小时或48小时自动结算的定时任务,将订单广播通知的任务,名称改成和新代码一样

This commit is contained in:
XingQue
2026-06-15 22:24:32 +08:00
parent 653e127493
commit e8795ca9f2
7 changed files with 277 additions and 114 deletions

View File

@@ -3,11 +3,11 @@
自动提现审核流程业务服务层(仅服务于 zddksh 申请接口 与 tixiansq 收款接口)
流程:
① zddksh 提交审核:资格校验 → 扣款(shenqing_jine) → 写审核表+提现记录表(状态=1)
(不在申请阶段校验/占用每日限额)
② 后台审核通过:状态变为 6待收款—— 由原有后台接口处理,此处不改动
③ tixiansq 收款:资格校验 → 只读预估 → 事务内原子预占限额 → 新建打款记录 → 调微信
微信明确失败/取消则回滚预占;待查单期间保留预占防并发超额
① zddksh 提交审核:完整资格校验 → 扣款 → 写审核表+提现记录表(状态=1)
允许多笔并行申请;单笔实际到账(shijidaozhang)不得超过200元
② 后台审核通过:校验到账≤200 → 状态 6待收款
③ tixiansq 收款:严格资格+限额 → 到账>200则关单退款(不退手续费),不调微信
微信官方 FAIL 关单不退款SUCCESS 落库;进行中禁止新建打款单
④ 打款成功tixianqr/回调/查单):若收款前已预占则不再累加;未预占的旧单/查单直成则补记
状态码(与前端 TX_STATUS 一致):
@@ -65,9 +65,6 @@ LEIXING_RATE_KEY = {
6: '10',
}
# 进行中的审核状态(不允许重复提交申请)
PENDING_AUDIT_STATUSES = [1, 4, 6]
DAKUAN_MODE_MANUAL = 1
DAKUAN_MODE_AUTO = 2
@@ -81,6 +78,10 @@ RECONCILE_COMPLETED = 'completed'
RECONCILE_WAIT_CONFIRM = 'wait_confirm'
RECONCILE_ALLOW_NEW = 'allow_new'
RECONCILE_PENDING = 'pending_query'
RECONCILE_AUDIT_CLOSED = 'audit_closed'
# 单笔实际到账上限(仅收款时校验)
MAX_SINGLE_COLLECT_AMOUNT = decimal.Decimal('200')
# 查单失败且本地 zhuangtai=0 超过该分钟数,才允许新建打款记录
PENDING_QUERY_GRACE_MINUTES = 10
@@ -182,7 +183,8 @@ def check_dashou_has_valid_huiyuan(yonghuid):
def validate_withdraw_eligibility(user_main, leixing, jine):
"""
提现资格校验(对齐手动提现 TixianShenqingView
提现申请资格校验(完整基本条件;仅放宽「不限制并行申请笔数」)。
与手动提现 TixianShenqingView 对齐。
"""
yonghuid = user_main.yonghuid
@@ -199,7 +201,6 @@ def validate_withdraw_eligibility(user_main, leixing, jine):
return False, '打手账号已被封禁,无法提现', {}
if dashou.zhuangtai != 1:
return False, '有订单进行中,请完成后提现', {}
# 与手动提现一致:积分必须正好 10 分
if dashou.jifen != 10:
return False, '积分不足10分请补充积分后提现', {}
huiyuan_ok, huiyuan_msg = check_dashou_has_valid_huiyuan(yonghuid)
@@ -293,11 +294,23 @@ def validate_withdraw_eligibility(user_main, leixing, jine):
return False, '无效的提现类型', {}
def check_shijidaozhang_within_limit(shijidaozhang):
"""校验单笔实际到账不超过上限(申请/审核/收款共用)"""
if shijidaozhang > MAX_SINGLE_COLLECT_AMOUNT:
return False, f'单笔实际到账不能超过{MAX_SINGLE_COLLECT_AMOUNT}元,请调整提现金额后重新申请'
return True, ''
def validate_collect_amount(audit):
"""收款时校验单笔实际到账上限(超限将关单退款)"""
return check_shijidaozhang_within_limit(audit.shijidaozhang)
def validate_collect_eligibility(user_main, leixing):
"""
收款前二次校验(申请时已扣款,不再校余额/金额)。
打手佣金/押金:罚单、封禁、接单中、积分、会员等;
其他身份:账号状态、罚单/订单等(不含金额)
收款前严格校验(申请时已扣款,不再校余额)。
打手佣金/押金:罚单、封禁、接单中、积分、会员、订单等;
其他身份:账号状态、罚单/订单等。
"""
yonghuid = user_main.yonghuid
@@ -354,24 +367,6 @@ def validate_collect_eligibility(user_main, leixing):
return False, '管事账号已被封禁,无法收款'
return True, ''
if leixing == 3:
try:
zuzhang = UserZuzhang.objects.get(user=user_main)
except UserZuzhang.DoesNotExist:
return False, '您不是组长身份,无法收款'
if zuzhang.zhuangtai != 1:
return False, '组长账号已被封禁,无法收款'
return True, ''
if leixing == 4:
try:
kaoheguan = UserShenheguan.objects.get(user=user_main)
except UserShenheguan.DoesNotExist:
return False, '您不是考核官身份,无法收款'
if kaoheguan.zhuangtai != 1:
return False, '考核官账号已被封禁,无法收款'
return True, ''
if leixing == 6:
try:
shangjia = UserShangjia.objects.get(user=user_main)
@@ -392,6 +387,24 @@ def validate_collect_eligibility(user_main, leixing):
return False, '您发起的处罚尚未处理完毕,无法收款'
return True, ''
if leixing == 3:
try:
zuzhang = UserZuzhang.objects.get(user=user_main)
except UserZuzhang.DoesNotExist:
return False, '您不是组长身份,无法收款'
if zuzhang.zhuangtai != 1:
return False, '组长账号已被封禁,无法收款'
return True, ''
if leixing == 4:
try:
kaoheguan = UserShenheguan.objects.get(user=user_main)
except UserShenheguan.DoesNotExist:
return False, '您不是考核官身份,无法收款'
if kaoheguan.zhuangtai != 1:
return False, '考核官账号已被封禁,无法收款'
return True, ''
return False, '无效的提现类型'
@@ -891,13 +904,6 @@ def get_balance_response_data(user_main, leixing):
return data
def has_pending_audit(yonghuid):
return TixianShenheJilu.objects.filter(
yonghuid=yonghuid,
zhuangtai__in=PENDING_AUDIT_STATUSES,
).exists()
def sync_audit_and_jilu_status(audit, new_status, **extra_fields):
audit.zhuangtai = new_status
for k, v in extra_fields.items():
@@ -910,6 +916,69 @@ def sync_audit_and_jilu_status(audit, new_status, **extra_fields):
Tixianjilu.objects.filter(id=audit.tixianjilu_id).update(**update_fields)
def _close_auto_record_failed(auto_record, fail_reason):
"""标记打款记录失败并释放收款预占限额"""
if auto_record is None or auto_record.zhuangtai == 1:
return
reason = (fail_reason or '打款失败')[:500]
auto_record.zhuangtai = 2
auto_record.fail_reason = reason
auto_record.save(update_fields=['zhuangtai', 'fail_reason', 'update_time'])
release_collect_quota_for_record(auto_record)
def close_audit_wechat_failed(audit, auto_record=None, fail_reason='微信转账失败'):
"""
微信官方终态 FAIL/CANCELLED审核单关闭(3),不退款(申请时已扣款,手续费不退)。
须在 transaction.atomic 内调用。
"""
_close_auto_record_failed(auto_record, fail_reason)
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
if audit.zhuangtai in (2, 3, 5):
return False
reason = (fail_reason or '微信转账失败')[:500]
sync_audit_and_jilu_status(
audit, 3,
bhliyou=reason,
fail_reason=reason,
tixian_auto_id=None,
)
logger.warning(
'微信失败关单(不退款) yonghuid=%s shenhe_danhao=%s reason=%s',
audit.yonghuid, audit.shenhe_danhao, reason,
)
return True
def close_audit_over_limit_refund(audit, auto_record=None, fail_reason='单笔实际到账超过限额'):
"""
到账超过200元等审核单关闭(3) + 退还可到账金额 shijidaozhang手续费不退
须在 transaction.atomic 内调用。
"""
reason = (fail_reason or '单笔实际到账超过限额')[:500]
_close_auto_record_failed(auto_record, reason)
audit = TixianShenheJilu.objects.select_for_update().get(pk=audit.pk)
if audit.zhuangtai in (2, 3, 5):
return False
user_main = UserMain.objects.select_for_update().get(yonghuid=audit.yonghuid)
refund_balance(user_main, audit.leixing, audit.shijidaozhang)
sync_audit_and_jilu_status(
audit, 3,
bhliyou=reason,
fail_reason=reason,
tixian_auto_id=None,
)
logger.warning(
'超限关单并退款 yonghuid=%s shenhe_danhao=%s reason=%s',
audit.yonghuid, audit.shenhe_danhao, reason,
)
return True
def query_wechat_transfer_bill(out_bill_no):
"""
向微信查转账单状态
@@ -1066,14 +1135,24 @@ def _sync_record_from_wx_query(auto_record, wx_data):
}
if state in WX_STATE_FAIL:
fail_reason = (
wx_data.get('fail_reason') or wx_data.get('close_reason') or state
)[:500]
if auto_record.zhuangtai != 1:
auto_record.zhuangtai = 2
auto_record.fail_reason = (
wx_data.get('fail_reason') or wx_data.get('close_reason') or state
)[:500]
auto_record.fail_reason = fail_reason
auto_record.save(update_fields=['zhuangtai', 'fail_reason', 'update_time'])
release_collect_quota_for_record(auto_record)
return RECONCILE_ALLOW_NEW, {}
if auto_record.shenhe_danhao:
try:
audit = TixianShenheJilu.objects.get(shenhe_danhao=auto_record.shenhe_danhao)
with transaction.atomic():
close_audit_wechat_failed(audit, None, fail_reason)
except TixianShenheJilu.DoesNotExist:
logger.warning('微信失败但审核记录不存在: %s', auto_record.shenhe_danhao)
return RECONCILE_AUDIT_CLOSED, {
'msg': '微信已确认转账失败,该笔提现已关闭,请联系客服处理',
}
if auto_record.zhuangtai == 0:
return RECONCILE_PENDING, {
@@ -1145,6 +1224,8 @@ def reconcile_shenhe_wechat_bills(shenhe_danhao):
return action, payload
if action == RECONCILE_WAIT_CONFIRM:
return action, payload
if action == RECONCILE_AUDIT_CLOSED:
return action, payload
if action == RECONCILE_PENDING:
if pending_hit is None:
pending_hit = (action, payload)
@@ -1286,12 +1367,10 @@ def create_audit_application(user_main, leixing, jine):
"""
提交审核申请:校验 → 扣款 → 写审核表 + 提现记录表
不创建打款记录表TixianAutoRecord 仅在收款时创建)
允许多笔并行申请(不阻塞待收款/审核中单)
"""
yonghuid = user_main.yonghuid
if has_pending_audit(yonghuid):
raise ValueError('账户余额不足或您有进行中的提现申请请等待处理完成或10分钟后后再提交')
ok, msg, extra = validate_withdraw_eligibility(user_main, leixing, jine)
if not ok:
raise ValueError(msg)
@@ -1301,6 +1380,10 @@ def create_audit_application(user_main, leixing, jine):
if shijidaozhang <= 0:
raise ValueError('提现金额过低,扣除手续费后无实际到账')
ok, limit_msg = check_shijidaozhang_within_limit(shijidaozhang)
if not ok:
raise ValueError(limit_msg)
shenhe_danhao = generate_shenhe_danhao()
nicheng = extra.get('nicheng', '')