修复管事双分红与押金分红:移除错误冲突校验、优化分成计算与建聊补偿

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-22 23:36:18 +08:00
parent bd821faf9d
commit 7daa05c8c6
4 changed files with 143 additions and 80 deletions

View File

@@ -38,6 +38,7 @@ def process_expired_order(self, dingdan_id):
return f'自动结算已禁用,跳过订单{dingdan_id}'
try:
guanshi_settle_ctx = None
# 使用select_for_update锁定记录防止并发修改
with transaction.atomic():
@@ -125,7 +126,19 @@ def process_expired_order(self, dingdan_id):
result_msg += ",商家信息已更新"
log_task_execution(f"自动结算订单 {dingdan_id}", True, result_msg)
return result_msg
if fadan_pingtai == 2 and dashou_id:
guanshi_settle_ctx = (dingdan_id, dashou_id)
if guanshi_settle_ctx:
try:
from dingdan.utils import settle_shangjia_order_guanshi_fenhong
settle_order = Dingdan.objects.get(dingdan_id=guanshi_settle_ctx[0])
settle_shangjia_order_guanshi_fenhong(settle_order, guanshi_settle_ctx[1])
except Exception as e:
logger.error(f"自动结算管事分红失败 订单{dingdan_id}: {e}", exc_info=True)
return result_msg
except Dingdan.DoesNotExist:
error_msg = f"订单{dingdan_id}不存在"
@@ -143,6 +156,27 @@ def process_expired_order(self, dingdan_id):
log_task_execution(f"自动结算订单 {dingdan_id}", False, error_msg)
return error_msg
@shared_task(bind=True, max_retries=3, default_retry_delay=15)
def retry_establish_order_chat_task(self, dingdan_id):
"""抢单后建聊失败时的延迟补偿任务"""
try:
from utils.chat_utils import establish_order_chat_with_retry
ok = establish_order_chat_with_retry(dingdan_id, max_rounds=5)
if ok:
logger.info(f"建聊补偿成功: 订单{dingdan_id}")
return f'chat ok {dingdan_id}'
logger.warning(f"建聊补偿仍失败: 订单{dingdan_id}")
if self.request.retries < self.max_retries:
raise self.retry()
return f'chat failed {dingdan_id}'
except Exception as e:
logger.error(f"建聊补偿任务异常 订单{dingdan_id}: {e}", exc_info=True)
if self.request.retries < self.max_retries:
raise self.retry(exc=e)
return str(e)
@shared_task
@rollback_on_failure("批量检查超时订单")
def check_order_expire_task():

View File

@@ -356,10 +356,10 @@ def _normalize_lilu_rate(raw):
def calc_shangjia_order_fencheng(jine):
"""
商家发单时计算打手/管事分成。
- 打手分成Lilubiao=3最高不超过订单金额
- 打手分成Lilubiao=3
- 管事打手接单分红Lilubiao=13
- 管事商家派单分红Lilubiao=15
打手优先;三项合计超过订单金额时,优先清零管事商家分红,再清零管事打手分红。
三项合计超过订单金额时,优先削减打手分成,再削减商家派单管事分红,最后削减打手接单管事分红。
"""
jine = Decimal(str(jine))
try:
@@ -387,14 +387,19 @@ def calc_shangjia_order_fencheng(jine):
guanshi_fencheng = (jine * rate_guanshi_dashou).quantize(Decimal('0.01'))
guanshi_shangjia_fencheng = (jine * rate_guanshi_shangjia).quantize(Decimal('0.01'))
if dashou_fencheng + guanshi_fencheng > jine:
guanshi_fencheng = Decimal('0.00')
if dashou_fencheng + guanshi_fencheng + guanshi_shangjia_fencheng > jine:
guanshi_shangjia_fencheng = Decimal('0.00')
if dashou_fencheng + guanshi_fencheng + guanshi_shangjia_fencheng > jine:
guanshi_fencheng = Decimal('0.00')
total = dashou_fencheng + guanshi_fencheng + guanshi_shangjia_fencheng
if total > jine:
overflow = total - jine
cut = min(overflow, dashou_fencheng)
dashou_fencheng -= cut
overflow -= cut
if overflow > 0:
cut = min(overflow, guanshi_shangjia_fencheng)
guanshi_shangjia_fencheng -= cut
overflow -= cut
if overflow > 0:
cut = min(overflow, guanshi_fencheng)
guanshi_fencheng -= cut
return dashou_fencheng, guanshi_fencheng, guanshi_shangjia_fencheng
@@ -413,17 +418,6 @@ def _pay_guanshi_order_fenhong(order, guanshi_id, amount, related_user_id, niche
logger.info(f"管事分红已处理: 订单{order.dingdan_id}, 类型{fenhong_leixing}")
return False
# 旧表结构 dingdan_id 全局唯一时,第二笔分红会插入失败
legacy_conflict = Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exclude(
fenhong_leixing=fenhong_leixing
).exists()
if legacy_conflict:
logger.error(
f"管事分红写入失败: 订单{order.dingdan_id} 已有其他类型分红记录,"
f"请执行 python manage.py migrate shangpin 0010 更新 gsfenhong 表唯一约束"
)
return False
try:
with transaction.atomic():
guanshi = UserGuanshi.objects.select_for_update().get(user__yonghuid=guanshi_id)
@@ -570,3 +564,75 @@ def settle_shangjia_order_guanshi_fenhong(order, dashou_id):
logger.info(
f"管事商家分红跳过: 商家{shangjia_id}打手身份无邀请管事(yaoqingren为空)"
)
def pay_deposit_guanshi_fenhong(dashou, order, recharge_amount):
"""
打手充值押金后向邀请管事发放分红幂等dingdan_id + fenhong_leixing=2
网络重试/微信重复回调时不会重复入账。
"""
from shangpin.models import Gsfenhong
from yonghu.models import UserGuanshi
guanshi_id = (dashou.yaoqingren or '').strip()
if not guanshi_id:
logger.info(f"押金分红跳过: 打手{dashou.user.yonghuid}无邀请管事")
return False
if Gsfenhong.objects.filter(dingdan_id=order.dingdan_id, fenhong_leixing=2).exists():
logger.info(f"押金分红已处理: 订单{order.dingdan_id}")
return True
lilu_obj = Lilubiao.objects.filter(fadanpingtai='12').first()
rate = lilu_obj.lilu if lilu_obj and lilu_obj.lilu is not None else Decimal('0')
rate = _normalize_lilu_rate(rate) if rate else Decimal('0')
if rate <= 0:
logger.info("押金分红跳过: 费率未配置或为0")
return False
recharge_amount = Decimal(str(recharge_amount))
fenhong_jine = (recharge_amount * rate).quantize(Decimal('0.01'))
if fenhong_jine <= 0:
return False
try:
with transaction.atomic():
guanshi = UserGuanshi.objects.select_for_update().get(user__yonghuid=guanshi_id)
UserGuanshi.objects.filter(pk=guanshi.pk).update(
yue=F('yue') + fenhong_jine,
chongzhifenrun=F('chongzhifenrun') + fenhong_jine,
)
user_main = dashou.user
Gsfenhong.objects.create(
dingdan_id=order.dingdan_id,
guanshi=guanshi_id,
dashouid=dashou.user.yonghuid,
shuoming='押金分红',
fenhong=fenhong_jine,
avatar=user_main.avatar if user_main else None,
nicheng=dashou.nicheng or '未知打手',
fenhong_leixing=2,
)
logger.info(
f"押金分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, "
f"打手{dashou.user.yonghuid}, 金额{fenhong_jine}"
)
try:
from houtai.utils import update_guanshi_daily_by_action
update_guanshi_daily_by_action(
yonghuid=guanshi_id,
action=4,
amount=fenhong_jine,
)
except Exception as e:
logger.error(f"押金分红管事日统计更新失败: {e}")
return True
except UserGuanshi.DoesNotExist:
logger.warning(f"押金分红跳过: 管事{guanshi_id}不存在")
return False
except IntegrityError:
logger.info(f"押金分红已处理(并发): 订单{order.dingdan_id}")
return True
except Exception as e:
logger.error(f"押金分红处理失败: {e}", exc_info=True)
return False

View File

@@ -4235,7 +4235,15 @@ class QiangdanView(APIView):
self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)
# 事务提交后再建群/建聊,避免长耗时 HTTP 拖住行锁,并支持重试
chat_success = establish_order_chat_with_retry(dingdan_id)
chat_success = establish_order_chat_with_retry(dingdan_id, max_rounds=5)
if not chat_success:
try:
from dingdan.tasks import retry_establish_order_chat_task
retry_establish_order_chat_task.apply_async(args=[dingdan_id], countdown=8)
retry_establish_order_chat_task.apply_async(args=[dingdan_id], countdown=30)
except Exception as chat_task_err:
logger.error(f"提交建聊补偿任务失败: {chat_task_err}")
try:
update_dashou_daily_by_action(

View File

@@ -680,7 +680,14 @@ class YajinHuitiao(View):
# 5. 检查订单状态是否为未支付9
if order.zhuangtai != 9:
logger.warning(f"订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
# 已处理过的订单直接返回成功,避免微信重复回调
# 已支付订单:补发可能因网络中断未成功的押金分红(幂等)
if order.zhuangtai == 3 and getattr(order, 'leixing', None) == 5:
try:
dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)
from dingdan.utils import pay_deposit_guanshi_fenhong
pay_deposit_guanshi_fenhong(dashou, order, order.jine)
except Exception as e:
logger.error(f"押金分红补发失败: {order.dingdan_id}, {e}", exc_info=True)
return self.wechat_response('SUCCESS', 'OK')
# 6. 验证金额(微信返回的是分,需要转换)
@@ -709,62 +716,10 @@ class YajinHuitiao(View):
logger.info(f"打手押金更新成功: 用户{order.yonghuid}, 增加{order_amount_yuan}元, 新押金{dashou.yajin}")
# 8b. 押金分红(微信确认到账后;费率 Lilubiao fadanpingtai=12
# 8b. 押金分红(微信确认到账后;幂等、可重试
try:
from decimal import Decimal
from django.db import transaction
from dingdan.models import Lilubiao
from shangpin.models import Gsfenhong
from yonghu.models import UserGuanshi
guanshi_id = dashou.yaoqingren
if not guanshi_id:
logger.info(f"押金分红跳过: 打手{order.yonghuid}无邀请管事")
elif Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exists():
logger.info(f"押金分红已处理: 订单{order.dingdan_id}")
else:
lilu_obj = Lilubiao.objects.filter(fadanpingtai='12').first()
rate = lilu_obj.lilu if lilu_obj and lilu_obj.lilu is not None else Decimal('0')
if rate <= 0:
logger.info(f"押金分红跳过: 费率未配置或为0")
else:
recharge_amount = Decimal(str(order_amount_yuan))
fenhong_jine = (recharge_amount * rate).quantize(Decimal('0.01'))
if fenhong_jine > 0:
with transaction.atomic():
guanshi = UserGuanshi.objects.select_for_update().get(
user__yonghuid=guanshi_id
)
guanshi.yue += fenhong_jine
guanshi.chongzhifenrun += fenhong_jine
guanshi.save(update_fields=['yue', 'chongzhifenrun'])
user_main = dashou.user
Gsfenhong.objects.create(
dingdan_id=order.dingdan_id,
guanshi=guanshi_id,
dashouid=order.yonghuid,
shuoming='押金分红',
fenhong=fenhong_jine,
avatar=user_main.avatar,
nicheng=dashou.nicheng or '未知打手',
fenhong_leixing=2,
)
logger.info(
f"押金分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, "
f"打手{order.yonghuid}, 金额{fenhong_jine}"
)
try:
from houtai.utils import update_guanshi_daily_by_action
update_guanshi_daily_by_action(
yonghuid=guanshi_id,
action=4,
amount=fenhong_jine,
)
except Exception as e:
logger.error(f"押金分红管事日统计更新失败: {e}")
except UserGuanshi.DoesNotExist:
logger.warning(f"押金分红跳过: 管事{guanshi_id}不存在")
from dingdan.utils import pay_deposit_guanshi_fenhong
pay_deposit_guanshi_fenhong(dashou, order, order_amount_yuan)
except Exception as e:
logger.error(f"押金分红处理失败: {str(e)}", exc_info=True)