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