fix: 组队仅队长提交修改,组员可见交付;罚单聚合改撤联动

详情返回 can_submit/can_modify;交付图按订单聚合;组队均摊罚单展示总额并联动修改/撤销;罚单 ClubID 归属订单店。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-27 08:05:34 +08:00
parent c5ceacf3d3
commit 7d366e8075
4 changed files with 275 additions and 73 deletions

View File

@@ -81,6 +81,78 @@ def get_active_recruit(order_id: str):
).first()
def get_team_role_for_user(order_id: str, user_uid: str) -> dict:
"""
当前用户在本单组队中的角色。
返回: has_team, is_leader, is_member, leader_uid, my_share, recruit
"""
from orders.models import TeamMember, TeamRecruit
out = {
'has_team': False,
'is_leader': False,
'is_member': False,
'leader_uid': '',
'my_share': None,
'recruit': None,
}
oid = (order_id or '').strip()
uid = (user_uid or '').strip()
if not oid or not uid:
return out
rec = get_active_recruit(oid)
if not rec:
rec = TeamRecruit.query.filter(order_id=oid).order_by('-id').first()
if not rec:
return out
out['has_team'] = True
out['recruit'] = rec
out['leader_uid'] = rec.leader_uid or ''
out['is_leader'] = (rec.leader_uid or '') == uid
mem = TeamMember.query.filter(
recruit_id=rec.id, user_uid=uid, join_status=TeamMember.JOIN_ACTIVE,
).first()
if mem:
out['is_member'] = True
out['my_share'] = float(_d(mem.share_amount))
elif out['is_leader']:
out['is_member'] = True
return out
def ensure_team_leader_can_submit(order, user_uid: str) -> Optional[str]:
"""
有有效组队时:仅队长可提交/修改交付。
无组队时:须为订单 PlayerID。
返回错误文案;通过返回 None。
"""
oid = getattr(order, 'OrderID', None) or ''
uid = (user_uid or '').strip()
player = (getattr(order, 'PlayerID', None) or '').strip()
from orders.models import TeamRecruit
ctx = get_team_role_for_user(oid, uid)
if ctx['has_team'] and ctx['recruit'] and int(ctx['recruit'].status or 0) in (
TeamRecruit.STATUS_RECRUITING, TeamRecruit.STATUS_LOCKED,
):
if not ctx['is_leader']:
return '仅队长可提交或修改交付内容'
return None
if player and player != uid:
return '订单不存在或没有提交权限'
return None
def list_team_split_penalties(order_id: str, *, include_rejected=False):
"""同订单【组队均摊】罚单列表(按创建顺序)。"""
from orders.models import Penalty
qs = Penalty.query.filter(
RelatedOrderID=order_id,
Reason__startswith='【组队均摊】',
)
if not include_rejected:
qs = qs.exclude(Status=4)
return list(qs.order_by('id'))
def team_should_split(order) -> bool:
"""结单是否走组队分账已锁定或招募中但已有人——进8会强制锁且有在队成员。"""
from orders.models import TeamRecruit, TeamMember
@@ -702,7 +774,15 @@ def maybe_split_penalties(*, order_id: str, total_amount, reason: str, applicant
reason_text = f'【组队均摊】{reason or ""}'
created = []
cid = (club_id or rec.club_id or 'xq')[:16]
# 罚单归属订单俱乐部,避免跨店接单时记到错误店;利率仍按申请人俱乐部在 lock_penalty_bonus 锁定
order_club = ''
try:
from orders.models import Order
o = Order.query.filter(OrderID=order_id).only('ClubID').first()
order_club = (getattr(o, 'ClubID', None) or '').strip() if o else ''
except Exception:
order_club = ''
cid = (order_club or club_id or rec.club_id or 'xq')[:16]
for i, m in enumerate(members):
p = Penalty(
PenalizedUserID=m.user_uid,