优化一下自动提现接口就是user/tixian_shenhe_servers.py,tixian_shenhe_views.py,让文件以及对应的申请,回调,确认接口,让它更好用一点,允许用户多次提现审核,强化收款接口,及时更新数据库中的收款状态,其次,更新了客服提现审核接口,关于大于200元的提现,同意之后直接按驳回处理,微信官方不支持大于200元的提现申请去掉了订单24小时或48小时自动结算的定时任务,将订单广播通知的任务,名称改成和新代码一样
This commit is contained in:
@@ -42,12 +42,12 @@ app.conf.beat_schedule = {
|
||||
'options': {'queue': 'periodic_tasks', 'priority': 4},
|
||||
},
|
||||
|
||||
# 补偿检查任务(每5分钟运行)
|
||||
'check_order_expire_task': {
|
||||
'task': 'orders.tasks.check_order_expire_task',
|
||||
'schedule': crontab(minute='*/5000'),
|
||||
'options': {'queue': 'order_tasks', 'priority': 3},
|
||||
},
|
||||
# 补偿检查任务(订单自动结算已禁用)
|
||||
# 'check_order_expire_task': {
|
||||
# 'task': 'orders.tasks.check_order_expire_task',
|
||||
# 'schedule': crontab(minute='*/5000'),
|
||||
# 'options': {'queue': 'order_tasks', 'priority': 3},
|
||||
# },
|
||||
|
||||
# 1. 每日凌晨0点执行 - 清零任务
|
||||
'daily_reset_task': {
|
||||
|
||||
@@ -278,7 +278,7 @@ CELERY_TASK_SERIALIZER = 'json'
|
||||
CELERY_RESULT_SERIALIZER = 'json'
|
||||
CELERY_TIMEZONE = 'Asia/Shanghai'
|
||||
CELERY_ENABLE_UTC = True
|
||||
CELERY_IMPORTS = ('dingdan.notice_tasks',)
|
||||
CELERY_IMPORTS = ('orders.notice_tasks',)
|
||||
CELERY_TASK_TIME_LIMIT = 300
|
||||
CELERY_TASK_SOFT_TIME_LIMIT = 240
|
||||
CELERY_WORKER_CONCURRENCY = 4
|
||||
|
||||
@@ -56,36 +56,29 @@ def handle_order_status_8(sender, instance, **kwargs):
|
||||
|
||||
# 状态从 非8 变为 8
|
||||
if old != 8 and instance.zhuangtai == 8:
|
||||
#logger.info(f"📅 订单 {instance.dingdan_id} 状态变为8,提交定时任务")
|
||||
|
||||
# 设置时间标记
|
||||
# 订单自动结算已关闭:仅记录时间标记,不再提交 Celery 延时结算任务
|
||||
instance.status_8_time = timezone.now()
|
||||
instance.pending_dispatch = True
|
||||
|
||||
# 使用配置中的超时时间
|
||||
expire_seconds = getattr(settings, 'ORDER_EXPIRE_SECONDS', 48 * 60 * 60)
|
||||
|
||||
# 提交Celery任务
|
||||
try:
|
||||
from orders.tasks import process_expired_order
|
||||
|
||||
task_result = process_expired_order.apply_async(
|
||||
args=[instance.dingdan_id],
|
||||
countdown=expire_seconds,
|
||||
queue='order_tasks',
|
||||
priority=9
|
||||
)
|
||||
|
||||
#logger.info(f"✅ 任务提交成功,订单: {instance.dingdan_id}, 任务ID: {task_result.id}")
|
||||
|
||||
# 保存任务信息
|
||||
instance.auto_task_id = task_result.id
|
||||
instance.auto_expire_at = timezone.now() + timezone.timedelta(seconds=expire_seconds)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 任务提交失败: {e}")
|
||||
instance.pending_dispatch = True
|
||||
instance.auto_task_id = f"failed_{timezone.now().timestamp()}"
|
||||
instance.pending_dispatch = False
|
||||
instance.auto_task_id = ''
|
||||
instance.auto_expire_at = None
|
||||
logger.info(f"订单 {instance.dingdan_id} 状态变为8(自动结算已禁用,不提交结算任务)")
|
||||
|
||||
# --- 原自动结算逻辑(已禁用,保留代码备查)---
|
||||
# expire_seconds = getattr(settings, 'ORDER_EXPIRE_SECONDS', 48 * 60 * 60)
|
||||
# try:
|
||||
# from orders.tasks import process_expired_order
|
||||
# task_result = process_expired_order.apply_async(
|
||||
# args=[instance.dingdan_id],
|
||||
# countdown=expire_seconds,
|
||||
# queue='order_tasks',
|
||||
# priority=9
|
||||
# )
|
||||
# instance.auto_task_id = task_result.id
|
||||
# instance.auto_expire_at = timezone.now() + timezone.timedelta(seconds=expire_seconds)
|
||||
# except Exception as e:
|
||||
# logger.error(f"❌ 任务提交失败: {e}")
|
||||
# instance.pending_dispatch = True
|
||||
# instance.auto_task_id = f"failed_{timezone.now().timestamp()}"
|
||||
|
||||
# 状态从 8 变为 非8
|
||||
elif old == 8 and instance.zhuangtai != 8:
|
||||
|
||||
@@ -26,7 +26,12 @@ logger = logging.getLogger(__name__)
|
||||
def process_expired_order(self, dingdan_id):
|
||||
"""
|
||||
处理单个超时订单(订单状态=8,超过48小时未处理)
|
||||
【已禁用】保留任务定义避免 Celery 注册/引用报错,实际不执行结算逻辑
|
||||
"""
|
||||
logger.info(f"订单{dingdan_id}自动结算任务已禁用,跳过执行")
|
||||
return f"订单{dingdan_id}自动结算已禁用,跳过"
|
||||
|
||||
# --- 以下原结算逻辑保留备查 ---
|
||||
try:
|
||||
# 使用select_for_update锁定记录,防止并发修改
|
||||
with transaction.atomic():
|
||||
@@ -134,9 +139,12 @@ def process_expired_order(self, dingdan_id):
|
||||
def check_order_expire_task():
|
||||
"""
|
||||
批量检查超时订单(补偿机制)
|
||||
每5分钟执行一次,作为信号处理的备用方案
|
||||
查找状态为8且创建时间超过72小时的订单(宽松时间,防止误处理)
|
||||
【已禁用】保留任务定义避免 Beat/Worker 引用报错,实际不执行
|
||||
"""
|
||||
logger.info("订单自动结算补偿检查已禁用,跳过")
|
||||
return {"success": True, "message": "自动结算已禁用", "count": 0}
|
||||
|
||||
# --- 以下原补偿逻辑保留备查 ---
|
||||
try:
|
||||
# 计算更宽松的时间点:当前时间减去72小时(48+24小时)
|
||||
# 这样避免误处理刚变为状态8的订单
|
||||
|
||||
@@ -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', '')
|
||||
|
||||
|
||||
@@ -25,17 +25,21 @@ from utils.wechat_v3 import build_authorization
|
||||
from .models import TixianAutoRecord
|
||||
from .tixian_shenhe_services import (
|
||||
RECONCILE_ALLOW_NEW,
|
||||
RECONCILE_AUDIT_CLOSED,
|
||||
RECONCILE_COMPLETED,
|
||||
RECONCILE_PENDING,
|
||||
RECONCILE_WAIT_CONFIRM,
|
||||
check_collect_quota_limits,
|
||||
create_audit_application,
|
||||
close_audit_over_limit_refund,
|
||||
close_audit_wechat_failed,
|
||||
get_audit_for_collect,
|
||||
handle_post_transfer_failure,
|
||||
reconcile_shenhe_wechat_bills,
|
||||
release_collect_quota_for_record,
|
||||
reserve_collect_quota_limits,
|
||||
resolve_collect_context,
|
||||
validate_collect_amount,
|
||||
validate_collect_eligibility,
|
||||
)
|
||||
|
||||
@@ -217,7 +221,16 @@ def process_audit_collect(request):
|
||||
tixianjilu_id_val = ctx['jilu'].id if ctx.get('jilu') else audit.tixianjilu_id
|
||||
leixing = audit.leixing
|
||||
|
||||
# 二次资格校验:不通过仅返回错误,审核单保持待收款(6),不退款,用户补齐资质后可再点收款
|
||||
amount_ok, amount_msg = validate_collect_amount(audit)
|
||||
if not amount_ok:
|
||||
with transaction.atomic():
|
||||
close_audit_over_limit_refund(audit, None, amount_msg)
|
||||
return Response({
|
||||
'code': 400,
|
||||
'msg': f'{amount_msg},可到账金额已退回余额(手续费不退),请重新申请',
|
||||
})
|
||||
|
||||
# 收款前严格资格校验:不通过仅返回错误,审核单保持待收款(6),不退款
|
||||
collect_ok, collect_msg = validate_collect_eligibility(user_main, leixing)
|
||||
if not collect_ok:
|
||||
logger.warning(
|
||||
@@ -241,6 +254,11 @@ def process_audit_collect(request):
|
||||
action, payload = reconcile_shenhe_wechat_bills(shenhe_danhao)
|
||||
if action == RECONCILE_COMPLETED:
|
||||
return Response({'code': 8, 'msg': payload.get('msg', '该提现已完成,请勿重复操作')})
|
||||
if action == RECONCILE_AUDIT_CLOSED:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'msg': payload.get('msg', '该笔提现已关闭,请重新申请'),
|
||||
})
|
||||
if action == RECONCILE_WAIT_CONFIRM:
|
||||
quota_resp = _verify_collect_quota_or_response(user_main, audit, shenhe_danhao)
|
||||
if quota_resp:
|
||||
@@ -344,6 +362,11 @@ def process_audit_collect(request):
|
||||
return _build_collect_success_response(post_payload)
|
||||
if post_action == RECONCILE_COMPLETED:
|
||||
return Response({'code': 8, 'msg': '该提现已完成,请勿重复操作'})
|
||||
if post_action == RECONCILE_AUDIT_CLOSED:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'msg': post_payload.get('msg', '该笔提现已关闭,请重新申请'),
|
||||
})
|
||||
if post_action == RECONCILE_PENDING:
|
||||
pending_msg = (
|
||||
post_payload.get('msg', post_payload)
|
||||
|
||||
116
users/views.py
116
users/views.py
@@ -65,7 +65,10 @@ from .models import (
|
||||
)
|
||||
from .tixian_shenhe_services import (
|
||||
load_audit_meta_map, refund_balance, sync_audit_and_jilu_status,
|
||||
mark_transfer_success, release_collect_quota_for_record
|
||||
mark_transfer_success, release_collect_quota_for_record,
|
||||
close_audit_wechat_failed, query_wechat_transfer_bill,
|
||||
check_shijidaozhang_within_limit,
|
||||
WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING,
|
||||
)
|
||||
from .tixian_shenhe_views import process_audit_collect
|
||||
|
||||
@@ -10046,6 +10049,18 @@ class KefuWithdrawActionView(APIView):
|
||||
raise ValueError(f'用户{req_yonghuid}不存在')
|
||||
|
||||
if action == 1:
|
||||
limit_ok, limit_msg = check_shijidaozhang_within_limit(audit.shijidaozhang)
|
||||
if not limit_ok:
|
||||
sync_audit_and_jilu_status(
|
||||
audit, 5,
|
||||
bhliyou=limit_msg,
|
||||
bo_hui_ren_id=kefu_user.yonghuid,
|
||||
)
|
||||
refund_balance(user, audit.leixing, audit.shijidaozhang)
|
||||
tixian.shenheid = kefu_user.yonghuid
|
||||
tixian.bhliyou = limit_msg
|
||||
tixian.save(update_fields=['shenheid', 'bhliyou', 'update_time'])
|
||||
raise ValueError(f'提现记录{tixian_id}:{limit_msg},已自动驳回并退款')
|
||||
sync_audit_and_jilu_status(audit, 6, shenhe_ren_id=kefu_user.yonghuid)
|
||||
tixian.shenheid = kefu_user.yonghuid
|
||||
tixian.save(update_fields=['shenheid', 'update_time'])
|
||||
@@ -12788,21 +12803,20 @@ class TixianCallbackV3View(APIView):
|
||||
auto_record.zhuangtai = 2
|
||||
auto_record.fail_reason = fail_reason or '微信转账失败'
|
||||
auto_record.save(update_fields=['zhuangtai', 'fail_reason'])
|
||||
release_collect_quota_for_record(auto_record)
|
||||
|
||||
if not auto_record.shenhe_danhao:
|
||||
logger.error('回调失败但打款记录无审核单号 bill=%s', out_bill_no)
|
||||
else:
|
||||
# 申请时已扣款,回调失败不退余额,恢复待收款(6)可重试
|
||||
try:
|
||||
audit = TixianShenheJilu.objects.select_for_update().get(
|
||||
shenhe_danhao=auto_record.shenhe_danhao
|
||||
)
|
||||
audit.tixian_auto_id = None
|
||||
audit.fail_reason = auto_record.fail_reason
|
||||
sync_audit_and_jilu_status(audit, 6, fail_reason=auto_record.fail_reason)
|
||||
close_audit_wechat_failed(
|
||||
audit, None, auto_record.fail_reason,
|
||||
)
|
||||
except TixianShenheJilu.DoesNotExist:
|
||||
logger.warning(f'回调失败但审核记录不存在: {auto_record.shenhe_danhao}')
|
||||
release_collect_quota_for_record(auto_record)
|
||||
|
||||
return Response({'code': 'SUCCESS', 'message': 'ok'})
|
||||
|
||||
@@ -12812,7 +12826,7 @@ class TixianQueRenAutoView(APIView):
|
||||
"""
|
||||
用户确认提现结果
|
||||
POST /yonghu/tixianqr
|
||||
新审核流程:打款记录带 shenhe_danhao 时,确认成功同步审核表+提现记录表为 2;取消不退款(申请已扣),恢复待收款 6 可重试
|
||||
以微信官方查单状态为准:SUCCESS 落库成功;FAIL/CANCELLED 关闭审核单+退款;进行中则提示等待
|
||||
"""
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
@@ -12847,37 +12861,79 @@ class TixianQueRenAutoView(APIView):
|
||||
if auto_record.zhuangtai == 1:
|
||||
return Response({'code': 0, 'msg': '提现成功', 'data': None})
|
||||
|
||||
if auto_record.zhuangtai != 0:
|
||||
return Response({'code': 5, 'msg': '该提现已处理'})
|
||||
wx_data = query_wechat_transfer_bill(tixian_id)
|
||||
if wx_data is None:
|
||||
return Response({'code': 12, 'msg': '系统正在核对微信状态,请稍后再试'})
|
||||
|
||||
mark_transfer_success(auto_record, with_accounting=True)
|
||||
if wx_data.get('_not_found'):
|
||||
return Response({'code': 12, 'msg': '收款处理中,请稍后再试'})
|
||||
|
||||
state = (wx_data.get('state') or '').upper()
|
||||
if state in WX_STATE_SUCCESS:
|
||||
mark_transfer_success(
|
||||
auto_record,
|
||||
wechat_transfer_no=wx_data.get('transfer_bill_no') or wx_data.get('transfer_no'),
|
||||
with_accounting=True,
|
||||
)
|
||||
return Response({'code': 0, 'msg': '提现成功', 'data': None})
|
||||
|
||||
if state in WX_STATE_FAIL:
|
||||
fail_reason = wx_data.get('fail_reason') or wx_data.get('close_reason') or state
|
||||
auto_record.zhuangtai = 2
|
||||
auto_record.fail_reason = str(fail_reason)[:500]
|
||||
auto_record.save(update_fields=['zhuangtai', 'fail_reason'])
|
||||
release_collect_quota_for_record(auto_record)
|
||||
if auto_record.shenhe_danhao:
|
||||
audit = TixianShenheJilu.objects.select_for_update().get(
|
||||
shenhe_danhao=auto_record.shenhe_danhao,
|
||||
)
|
||||
close_audit_wechat_failed(audit, None, auto_record.fail_reason)
|
||||
return Response({'code': 400, 'msg': '微信已确认转账失败,该笔提现已关闭,请联系客服处理'})
|
||||
|
||||
if state in WX_STATE_WAIT or state in WX_STATE_CANCELING:
|
||||
return Response({'code': 12, 'msg': '收款处理中,请在微信中完成或稍后再试'})
|
||||
|
||||
return Response({'code': 12, 'msg': '系统正在核对微信状态,请稍后再试'})
|
||||
|
||||
# 用户报告取消/失败:以微信查单为准,不本地盲目标记
|
||||
if auto_record.zhuangtai == 2:
|
||||
return Response({'code': 0, 'msg': '提现已取消', 'data': None})
|
||||
if auto_record.zhuangtai == 1:
|
||||
return Response({'code': 0, 'msg': '提现成功', 'data': None})
|
||||
|
||||
# 用户取消或失败
|
||||
auto_record.zhuangtai = 2
|
||||
auto_record.fail_reason = '用户取消收款'
|
||||
auto_record.save(update_fields=['zhuangtai', 'fail_reason'])
|
||||
wx_data = query_wechat_transfer_bill(tixian_id)
|
||||
if wx_data is None:
|
||||
return Response({'code': 12, 'msg': '系统正在核对微信状态,请稍后再试,切勿重复操作'})
|
||||
|
||||
if not auto_record.shenhe_danhao:
|
||||
logger.error('确认取消但打款记录无审核单号 bill=%s', tixian_id)
|
||||
return Response({'code': 5, 'msg': '该提现已处理'})
|
||||
if wx_data.get('_not_found'):
|
||||
return Response({'code': 12, 'msg': '收款处理中,请稍后再试'})
|
||||
|
||||
# 申请时已扣款,取消不退余额,审核单恢复 6 待收款,可再次点收款
|
||||
try:
|
||||
audit = TixianShenheJilu.objects.select_for_update().get(
|
||||
shenhe_danhao=auto_record.shenhe_danhao,
|
||||
state = (wx_data.get('state') or '').upper()
|
||||
if state in WX_STATE_SUCCESS:
|
||||
mark_transfer_success(
|
||||
auto_record,
|
||||
wechat_transfer_no=wx_data.get('transfer_bill_no') or wx_data.get('transfer_no'),
|
||||
with_accounting=True,
|
||||
)
|
||||
audit.tixian_auto_id = None
|
||||
sync_audit_and_jilu_status(
|
||||
audit, 6,
|
||||
fail_reason='用户取消收款,可重新发起',
|
||||
)
|
||||
except TixianShenheJilu.DoesNotExist:
|
||||
logger.warning(f'确认取消但审核记录不存在: {auto_record.shenhe_danhao}')
|
||||
release_collect_quota_for_record(auto_record)
|
||||
return Response({'code': 0, 'msg': '提现成功', 'data': None})
|
||||
|
||||
return Response({'code': 0, 'msg': '提现已取消', 'data': None})
|
||||
if state in WX_STATE_FAIL:
|
||||
fail_reason = wx_data.get('fail_reason') or wx_data.get('close_reason') or '用户取消收款'
|
||||
auto_record.zhuangtai = 2
|
||||
auto_record.fail_reason = str(fail_reason)[:500]
|
||||
auto_record.save(update_fields=['zhuangtai', 'fail_reason'])
|
||||
release_collect_quota_for_record(auto_record)
|
||||
if auto_record.shenhe_danhao:
|
||||
audit = TixianShenheJilu.objects.select_for_update().get(
|
||||
shenhe_danhao=auto_record.shenhe_danhao,
|
||||
)
|
||||
close_audit_wechat_failed(audit, None, auto_record.fail_reason)
|
||||
return Response({'code': 0, 'msg': '提现已关闭,请联系客服处理'})
|
||||
|
||||
if state in WX_STATE_WAIT or state in WX_STATE_CANCELING:
|
||||
return Response({'code': 12, 'msg': '收款仍在进行中,请在微信中操作或稍后再试'})
|
||||
|
||||
return Response({'code': 12, 'msg': '系统正在核对微信状态,请稍后再试'})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'提现确认异常: {str(e)}', exc_info=True)
|
||||
|
||||
Reference in New Issue
Block a user