From 8ee7814a45dac81b4ec18e1563a8378f06295d37 Mon Sep 17 00:00:00 2001 From: XingQue Date: Thu, 25 Jun 2026 16:21:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A4=84=E7=BD=9A/=E7=BD=9A=E6=AC=BE?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=BF=B1=E4=B9=90=E9=83=A8=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E4=B8=8E=E5=85=A8=E9=83=A8Tab=EF=BC=9B=E5=9B=9E=E5=A1=ABfadan?= =?UTF-8?q?=20club=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/view.py | 1 + .../backfill_penalty_record_club_id.py | 28 ++++++-- jituan/services/club_penalty.py | 67 ++++++++++++++----- users/views.py | 31 ++++++++- 4 files changed, 105 insertions(+), 22 deletions(-) diff --git a/backend/view.py b/backend/view.py index 14a384b..2b0ab7e 100644 --- a/backend/view.py +++ b/backend/view.py @@ -6348,6 +6348,7 @@ class FaKuanLieBiaoView(APIView): 'zhengju_tupian': zhengju_map.get(r.id, []), 'shensu_tupian': shensu_map.get(r.id, []), 'creat_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '', + 'create_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '', 'UpdateTime': r.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if r.UpdateTime else '', }) diff --git a/jituan/management/commands/backfill_penalty_record_club_id.py b/jituan/management/commands/backfill_penalty_record_club_id.py index 6688431..5f4ff9f 100644 --- a/jituan/management/commands/backfill_penalty_record_club_id.py +++ b/jituan/management/commands/backfill_penalty_record_club_id.py @@ -1,18 +1,23 @@ -"""回填 chufajilu / duoci_fenhong club_id。""" +"""回填 chufajilu / fadan / duoci_fenhong club_id。""" from django.core.management.base import BaseCommand from django.db import transaction from jituan.constants import CLUB_ID_DEFAULT -from jituan.services.club_penalty import resolve_gsfenhong_club_id, resolve_penalty_record_club_id -from orders.models import PenaltyRecord +from jituan.services.club_penalty import ( + resolve_gsfenhong_club_id, + resolve_penalty_club_id, + resolve_penalty_record_club_id, +) +from orders.models import Penalty, PenaltyRecord from products.models import DuociFenhong class Command(BaseCommand): - help = '回填 PenaltyRecord / DuociFenhong 的 club_id' + help = '回填 PenaltyRecord / Penalty / DuociFenhong 的 club_id' def handle(self, *args, **options): pr_updated = 0 + fd_updated = 0 df_updated = 0 with transaction.atomic(): for row in PenaltyRecord.query.all().only('id', 'OrderID', 'PlayerID', 'ClubID'): @@ -20,6 +25,19 @@ class Command(BaseCommand): if row.ClubID != cid: PenaltyRecord.query.filter(id=row.id).update(ClubID=cid) pr_updated += 1 + for row in Penalty.query.all().only('id', 'RelatedOrderID', 'PenalizedUserID', 'ClubID'): + cid = resolve_penalty_club_id( + order=None, + penalized_user_id=row.PenalizedUserID, + ) + if row.RelatedOrderID: + from orders.models import Order + o = Order.query.filter(OrderID=row.RelatedOrderID).first() + if o: + cid = resolve_penalty_club_id(order=o, penalized_user_id=row.PenalizedUserID) + if row.ClubID != cid: + Penalty.query.filter(id=row.id).update(ClubID=cid) + fd_updated += 1 for row in DuociFenhong.query.all().only('huiyuan', 'yonghuid', 'cishu', 'club_id'): cid = resolve_gsfenhong_club_id(dashouid=row.yonghuid) or CLUB_ID_DEFAULT if row.club_id != cid: @@ -31,5 +49,5 @@ class Command(BaseCommand): ).update(club_id=cid) df_updated += 1 self.stdout.write(self.style.SUCCESS( - f'PenaltyRecord={pr_updated}, DuociFenhong={df_updated}' + f'PenaltyRecord={pr_updated}, Penalty={fd_updated}, DuociFenhong={df_updated}' )) diff --git a/jituan/services/club_penalty.py b/jituan/services/club_penalty.py index 4d6ead0..8f4334e 100644 --- a/jituan/services/club_penalty.py +++ b/jituan/services/club_penalty.py @@ -4,7 +4,6 @@ from rest_framework.response import Response from jituan.constants import CLUB_ID_DEFAULT from jituan.services.club_context import ( DATA_SCOPE_ALL, - filter_queryset_by_club, resolve_club_id_from_request, resolve_club_scope, ) @@ -52,8 +51,55 @@ def resolve_gsfenhong_club_id(dingdan_id=None, dashouid=None, order=None, czjilu return CLUB_ID_DEFAULT +def _collect_club_user_ids(club_id): + """俱乐部下属用户 UID(User.ClubID + 微信绑定 club)。""" + from users.business_models import User + from jituan.models import UserWxOpenid + ids = set(User.query.filter(ClubID=club_id).values_list('UserUID', flat=True)) + ids.update(UserWxOpenid.query.filter(club_id=club_id).values_list('yonghuid', flat=True)) + return [x for x in ids if x] + + +def _filter_club_penalty_like_qs(qs, request, user_id_field, order_id_field): + """罚单/积分处罚共用:ClubID + 被罚人 + 关联订单 归属当前俱乐部。""" + if resolve_club_scope(request) == DATA_SCOPE_ALL: + return qs + club_id = resolve_club_id_from_request(request) + from django.db.models import Q + from orders.models import Order + + parts = [] + if hasattr(qs.model, 'ClubID'): + if club_id == CLUB_ID_DEFAULT: + parts.append( + Q(ClubID=club_id) | Q(ClubID__isnull=True) | Q(ClubID='') + ) + else: + parts.append(Q(ClubID=club_id)) + + user_ids = _collect_club_user_ids(club_id) + if user_ids: + parts.append(Q(**{f'{user_id_field}__in': user_ids})) + + order_q = Q(ClubID=club_id) + if club_id == CLUB_ID_DEFAULT: + order_q = Q(ClubID=club_id) | Q(ClubID__isnull=True) | Q(ClubID='') + order_ids = list(Order.query.filter(order_q).values_list('OrderID', flat=True)) + if order_ids: + parts.append(Q(**{f'{order_id_field}__in': order_ids})) + + if not parts: + return qs.none() + combined = parts[0] + for p in parts[1:]: + combined |= p + return qs.filter(combined) + + def filter_penalty_qs(qs, request): - return filter_queryset_by_club(qs, request, club_field='ClubID') + return _filter_club_penalty_like_qs( + qs, request, user_id_field='PenalizedUserID', order_id_field='RelatedOrderID' + ) def filter_gsfenhong_qs(qs, request): @@ -89,17 +135,6 @@ def resolve_penalty_record_club_id(order_id=None, player_id=None): def filter_penalty_record_qs(qs, request): """积分处罚记录(chufajilu)按俱乐部过滤。""" - if resolve_club_scope(request) == DATA_SCOPE_ALL: - return qs - club_id = resolve_club_id_from_request(request) - from django.db.models import Q - from orders.models import Order - from users.business_models import User - user_ids = User.query.filter(ClubID=club_id).values_list('UserUID', flat=True) - order_ids = Order.query.filter(ClubID=club_id).values_list('OrderID', flat=True) - # ClubID 命中,或历史数据 club_id 未回填时按打手/订单归属俱乐部 - if hasattr(qs.model, 'ClubID'): - return qs.filter( - Q(ClubID=club_id) | Q(PlayerID__in=user_ids) | Q(OrderID__in=order_ids) - ) - return qs.filter(Q(PlayerID__in=user_ids) | Q(OrderID__in=order_ids)) + return _filter_club_penalty_like_qs( + qs, request, user_id_field='PlayerID', order_id_field='OrderID' + ) diff --git a/users/views.py b/users/views.py index 9195804..3cbd216 100644 --- a/users/views.py +++ b/users/views.py @@ -8988,10 +8988,39 @@ class KefuPunishmentListView(APIView): permission_classes = [IsAuthenticated] parser_classes = [JSONParser] + @staticmethod + def _parse_status_list(raw): + """兼容 status=[0,3]、\"0,3\"、单数字;空/all 表示不过滤。""" + if raw is None: + return None + if isinstance(raw, str): + s = raw.strip().lower() + if not s or s in ('all', 'null', 'none'): + return None + if s.startswith('['): + import json + try: + raw = json.loads(s) + except (TypeError, ValueError): + return None + else: + raw = [x.strip() for x in s.split(',') if x.strip()] + if isinstance(raw, (int, float)): + return [int(raw)] + if isinstance(raw, list): + out = [] + for x in raw: + try: + out.append(int(x)) + except (TypeError, ValueError): + continue + return out or None + return None + def post(self, request): # 1. 获取参数 phone = request.data.get('phone', '').strip() - status_list = request.data.get('status') + status_list = self._parse_status_list(request.data.get('status')) dingdan_id = request.data.get('dingdan_id', '').strip() dashouid = request.data.get('dashouid', '').strip() try: