feat(jituan): 集团多俱乐部改造 — club 隔离、财务/提现/分红/展示配置
This commit is contained in:
487
backend/view.py
487
backend/view.py
@@ -38,7 +38,12 @@ from backend.utils import (
|
||||
update_dashou_daily_by_action,
|
||||
update_shangjia_daily
|
||||
)
|
||||
from orders.utils import update_daily_payout
|
||||
from jituan.services.club_context import filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request
|
||||
from jituan.services.club_penalty import (
|
||||
filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs,
|
||||
forbid_penalty_out_of_scope, resolve_penalty_record_club_id,
|
||||
)
|
||||
from jituan.services.club_user_access import forbid_if_user_out_of_scope, list_response_meta
|
||||
from shop.utils import update_dianpu_daily_stat
|
||||
from products.utils import update_shangpin_daily_stat
|
||||
from orders.notice_tasks import dingdan_guangbo
|
||||
@@ -743,7 +748,9 @@ class KefuGetDashouListView(APIView):
|
||||
return Response({'code': 403, 'msg': '您没有权限查看打手列表'})
|
||||
|
||||
# 4. 构建打手查询集(仅打手类型)
|
||||
dashou_qs = UserDashou.query.select_related('user').all()
|
||||
dashou_qs = filter_user_related_by_club(
|
||||
UserDashou.query.select_related('user').all(), request,
|
||||
)
|
||||
|
||||
# 关键词筛选(用户ID或昵称)
|
||||
if keyword:
|
||||
@@ -758,12 +765,12 @@ class KefuGetDashouListView(APIView):
|
||||
# 6. 统计有效打手数(有会员且未过期)
|
||||
dashou_user_ids = dashou_qs.values_list('user__UserUID', flat=True)
|
||||
now = timezone.now()
|
||||
valid_user_ids = Huiyuangoumai.query.filter(
|
||||
hy_qs = filter_queryset_by_club(Huiyuangoumai.query.all(), request)
|
||||
valid_dashou_count = hy_qs.filter(
|
||||
yonghu_id__in=dashou_user_ids,
|
||||
huiyuan_zhuangtai=1,
|
||||
daoqi_time__gt=now
|
||||
).values_list('yonghu_id', flat=True).distinct()
|
||||
valid_dashou_count = valid_user_ids.count()
|
||||
daoqi_time__gt=now,
|
||||
).values('yonghu_id').distinct().count()
|
||||
|
||||
# 7. 分页
|
||||
offset = (page - 1) * page_size
|
||||
@@ -784,8 +791,11 @@ class KefuGetDashouListView(APIView):
|
||||
|
||||
has_more = (offset + len(dashou_list)) < total_dashou
|
||||
|
||||
meta = list_response_meta(request)
|
||||
return Response({
|
||||
'code': 0,
|
||||
'club_id': meta['club_id'],
|
||||
'scope': meta['scope'],
|
||||
'data': {
|
||||
'list': result,
|
||||
'has_more': has_more,
|
||||
@@ -836,6 +846,10 @@ class KefuGetDashouDetailView(APIView):
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '打手不存在'})
|
||||
|
||||
denied = forbid_if_user_out_of_scope(request, user_main)
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
try:
|
||||
dashou = user_main.DashouProfile
|
||||
except ObjectDoesNotExist:
|
||||
@@ -1346,7 +1360,9 @@ class KefuGetShangjiaListView(APIView):
|
||||
return Response({'code': 403, 'msg': '您没有权限查看商家列表'})
|
||||
|
||||
# 4. 构建商家查询集(商家扩展表 + 关联用户主表)
|
||||
shangjia_qs = UserShangjia.query.select_related('user').all()
|
||||
shangjia_qs = filter_user_related_by_club(
|
||||
UserShangjia.query.select_related('user').all(), request,
|
||||
)
|
||||
|
||||
# 关键词筛选(用户ID或昵称)
|
||||
if keyword:
|
||||
@@ -1393,6 +1409,7 @@ class KefuGetShangjiaListView(APIView):
|
||||
|
||||
# 5. 统计总商家数(应用筛选后)
|
||||
total = shangjia_qs.count()
|
||||
valid_merchant_count = shangjia_qs.filter(zhuangtai=1).count()
|
||||
|
||||
# 6. 分页
|
||||
offset = (page - 1) * page_size
|
||||
@@ -1412,11 +1429,15 @@ class KefuGetShangjiaListView(APIView):
|
||||
'zhuangtai': shangjia.zhuangtai, # 1=正常,2=禁用
|
||||
})
|
||||
|
||||
meta = list_response_meta(request)
|
||||
return Response({
|
||||
'code': 0,
|
||||
'club_id': meta['club_id'],
|
||||
'scope': meta['scope'],
|
||||
'data': {
|
||||
'list': result,
|
||||
'total': total,
|
||||
'valid_merchant_count': valid_merchant_count,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1466,6 +1487,10 @@ class KefuGetShangjiaDetailView(APIView):
|
||||
except UserShangjia.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '商家不存在'})
|
||||
|
||||
denied = forbid_if_user_out_of_scope(request, shangjia.user)
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
user = shangjia.user
|
||||
|
||||
data = {
|
||||
@@ -2847,9 +2872,12 @@ class GetGuanliListView(APIView):
|
||||
status = request.data.get('status')
|
||||
|
||||
# 构建查询:从 User 开始,关联 UserGuanshi 和 UserBoss(左连接获取昵称)
|
||||
qs = User.query.filter(
|
||||
GuanshiProfile__isnull=False # 确保是管事
|
||||
).select_related('GuanshiProfile').select_related('BossProfile')
|
||||
qs = filter_user_qs_by_club(
|
||||
User.query.filter(
|
||||
GuanshiProfile__isnull=False # 确保是管事
|
||||
).select_related('GuanshiProfile').select_related('BossProfile'),
|
||||
request,
|
||||
)
|
||||
|
||||
# 关键词搜索(用户ID 或 昵称来自 boss_profile.nickname)
|
||||
if keyword:
|
||||
@@ -2929,7 +2957,11 @@ class GetGuanliListView(APIView):
|
||||
'chongzhifenrun': str(guanshi.chongzhifenrun),
|
||||
})
|
||||
|
||||
return Response({'code': 0, 'data': {'list': result, 'total': total}})
|
||||
return Response({
|
||||
'code': 0,
|
||||
**list_response_meta(request),
|
||||
'data': {'list': result, 'total': total},
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -2984,6 +3016,10 @@ class GetGuanliDetailView(APIView):
|
||||
except UserGuanshi.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '用户不是管事'})
|
||||
|
||||
denied = forbid_if_user_out_of_scope(request, user)
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
# 基础信息
|
||||
is_zuzhang = UserZuzhang.query.filter(user=user).exists()
|
||||
base_data = {
|
||||
@@ -3377,8 +3413,12 @@ class UpdateGuanliView(APIView):
|
||||
|
||||
# 4.2 首次定制分红(cishu=1)
|
||||
if custom_first is not None and isinstance(custom_first, dict):
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id
|
||||
guanshi_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
|
||||
# 获取当前所有首次定制记录
|
||||
existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1)
|
||||
existing_first = DuociFenhong.query.filter(
|
||||
club_id=guanshi_club, yonghuid=yonghuid, cishu=1,
|
||||
)
|
||||
# 前端传来的定制字典 {会员ID: 金额}
|
||||
for huiyuan_id, amount in custom_first.items():
|
||||
try:
|
||||
@@ -3386,17 +3426,19 @@ class UpdateGuanliView(APIView):
|
||||
except:
|
||||
continue
|
||||
if amount <= 0:
|
||||
# 金额为0或负数表示删除定制
|
||||
DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete()
|
||||
DuociFenhong.query.filter(
|
||||
club_id=guanshi_club, yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1,
|
||||
).delete()
|
||||
else:
|
||||
DuociFenhong.query.update_or_create(
|
||||
club_id=guanshi_club,
|
||||
yonghuid=yonghuid,
|
||||
huiyuan=huiyuan_id,
|
||||
cishu=1,
|
||||
defaults={
|
||||
'guanshi_fenhong': amount,
|
||||
'zuzhang_fenhong': Decimal('0')
|
||||
}
|
||||
'zuzhang_fenhong': Decimal('0'),
|
||||
},
|
||||
)
|
||||
# 删除那些在前端字典中不存在的首次定制记录(即已取消定制)
|
||||
for record in existing_first:
|
||||
@@ -3405,6 +3447,8 @@ class UpdateGuanliView(APIView):
|
||||
|
||||
# 4.3 额外次数分红(cishu >= 2)
|
||||
if extra_map is not None and isinstance(extra_map, dict):
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id
|
||||
guanshi_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
|
||||
# 收集需要保留的记录
|
||||
keep_set = set()
|
||||
for times_str, members in extra_map.items():
|
||||
@@ -3429,6 +3473,7 @@ class UpdateGuanliView(APIView):
|
||||
keep_set.add((cishu, huiyuan_id))
|
||||
# 更新或创建
|
||||
DuociFenhong.query.update_or_create(
|
||||
club_id=guanshi_club,
|
||||
yonghuid=yonghuid,
|
||||
huiyuan=huiyuan_id,
|
||||
cishu=cishu,
|
||||
@@ -3438,7 +3483,9 @@ class UpdateGuanliView(APIView):
|
||||
}
|
||||
)
|
||||
# 删除不在 keep_set 中的额外次数记录
|
||||
existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2)
|
||||
existing_extra = DuociFenhong.query.filter(
|
||||
club_id=guanshi_club, yonghuid=yonghuid, cishu__gte=2,
|
||||
)
|
||||
for record in existing_extra:
|
||||
if (record.cishu, record.huiyuan) not in keep_set:
|
||||
record.delete()
|
||||
@@ -3493,53 +3540,8 @@ class GetWithdrawSettingsView(APIView):
|
||||
if not any(p in permissions for p in ('5500a', '5500b', '5500c')):
|
||||
return Response({'code': 403, 'msg': '无权限查看提现设置'})
|
||||
|
||||
# 1. 手续费利率(CommissionRate:5打手/6管事/8组长/9审核官/10商家/11打手押金)
|
||||
rate_map = {}
|
||||
for leixing, code in [(1, '5'), (2, '6'), (3, '8'), (4, '9'), (5, '11'), (6, '10')]:
|
||||
obj = CommissionRate.query.filter(Platform=code).first()
|
||||
rate_map[leixing] = float(obj.Rate) if obj and obj.Rate is not None else 0.0
|
||||
|
||||
# 1b. 订单/押金分红费率(CommissionRate:1平台订单/3商家订单/12押金管事/13商家订单管事分红)
|
||||
order_rate_map = {}
|
||||
for leixing, code in [(1, '1'), (3, '3'), (12, '12'), (13, '13')]:
|
||||
obj = CommissionRate.query.filter(Platform=code).first()
|
||||
order_rate_map[leixing] = float(obj.Rate) if obj and obj.Rate is not None else 0.0
|
||||
|
||||
# 2. 个人每日限额 (leixing=1,2,3)
|
||||
quota_map = {}
|
||||
for leixing in [1, 2, 3]:
|
||||
obj = TixianQuotaDefault.query.filter(UserType=leixing).first()
|
||||
quota_map[leixing] = float(obj.default_quota) if obj else 20.0
|
||||
|
||||
# 3. 每日总限额(提现类型1~6 → 配置表4~9)
|
||||
total_limit_map = {}
|
||||
for withdraw_leixing, quota_leixing in [(1, 4), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9)]:
|
||||
obj = TixianQuotaDefault.query.filter(UserType=quota_leixing).first()
|
||||
total_limit_map[withdraw_leixing] = float(obj.default_quota) if obj else 0.0
|
||||
|
||||
# 4. 当日已提现总额(按提现类型 leixing 1~6)
|
||||
today = date.today()
|
||||
today_totals = {i: 0.0 for i in range(1, 7)}
|
||||
records = WithdrawalDailyStats.query.filter(Date=today)
|
||||
for rec in records:
|
||||
if rec.WithdrawalType in today_totals:
|
||||
today_totals[rec.WithdrawalType] = float(rec.total_amount)
|
||||
|
||||
# 🆕 获取提现模式(自动1 / 手动2),默认2
|
||||
config = WithdrawConfig.query.filter(id=1).first()
|
||||
withdraw_mode = config.mode if config else 2
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'withdraw_mode': withdraw_mode,
|
||||
'rates': rate_map,
|
||||
'order_rates': order_rate_map,
|
||||
'quotas': quota_map,
|
||||
'total_limits': total_limit_map,
|
||||
'today_totals': today_totals,
|
||||
}
|
||||
})
|
||||
from jituan.services.withdraw_config import build_withdraw_settings_payload
|
||||
return Response({'code': 0, 'data': build_withdraw_settings_payload(request)})
|
||||
|
||||
|
||||
class UpdateWithdrawSettingsView(APIView):
|
||||
@@ -3566,124 +3568,8 @@ class UpdateWithdrawSettingsView(APIView):
|
||||
|
||||
# 权限映射:要修改的角色需要对应的权限
|
||||
# 前端传来 rates, quotas, total_limits 三个对象,每个包含 1,2,3
|
||||
rates = request.data.get('rates', {})
|
||||
order_rates = request.data.get('order_rates', request.data.get('commission_rates', {}))
|
||||
quotas = request.data.get('quotas', {})
|
||||
total_limits = request.data.get('total_limits', {})
|
||||
|
||||
# 角色类型映射
|
||||
role_perms = {1: '5500a', 2: '5500b', 3: '5500c'}
|
||||
# 利率代码映射(1-3 有水缸限额;4审核官/5打手押金/6商家余额仅费率)
|
||||
rate_code_map = {1: '5', 2: '6', 3: '8', 4: '9', 5: '11', 6: '10'}
|
||||
# 订单/押金分红(1平台订单/3商家订单/12押金管事/13商家订单管事分红)
|
||||
order_rate_code_map = {1: '1', 3: '3', 12: '12', 13: '13'}
|
||||
# 总限额:提现类型 → TixianQuotaDefault.leixing(4~9)
|
||||
total_code_map = {1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9}
|
||||
|
||||
def _rate_key_present(data, role):
|
||||
return (str(role) in data and data[str(role)] is not None) or \
|
||||
(role in data and data[role] is not None)
|
||||
|
||||
with transaction.atomic():
|
||||
# 遍历三个角色(限额相关)
|
||||
for role in [1, 2, 3]:
|
||||
perm_needed = role_perms[role]
|
||||
if perm_needed not in permissions:
|
||||
if _rate_key_present(rates, role) or \
|
||||
(str(role) in quotas and quotas[str(role)] is not None) or \
|
||||
(role in quotas and quotas.get(role) is not None) or \
|
||||
(str(role) in total_limits and total_limits[str(role)] is not None) or \
|
||||
(role in total_limits and total_limits.get(role) is not None):
|
||||
return Response({'code': 403, 'msg': f'无权限修改{["","打手","管事","组长"][role]}相关设置(需要{perm_needed})'})
|
||||
|
||||
# 其他提现手续费(审核官/打手押金/商家余额):需 5500a/b/c 任一
|
||||
extra_role_names = {4: '考核官', 5: '打手押金', 6: '商家余额'}
|
||||
for role in [4, 5, 6]:
|
||||
if _rate_key_present(rates, role) and not any(p in permissions for p in ('5500a', '5500b', '5500c')):
|
||||
return Response({'code': 403, 'msg': f'无权限修改{extra_role_names[role]}提现手续费率'})
|
||||
if (str(role) in total_limits and total_limits[str(role)] is not None) or \
|
||||
(role in total_limits and total_limits.get(role) is not None):
|
||||
if not any(p in permissions for p in ('5500a', '5500b', '5500c')):
|
||||
return Response({'code': 403, 'msg': f'无权限修改{extra_role_names[role]}总限额'})
|
||||
|
||||
# 订单/押金分红费率:需 5500a/b/c 任一
|
||||
for role in [1, 3, 12, 13]:
|
||||
if _rate_key_present(order_rates, role) and not any(p in permissions for p in ('5500a', '5500b', '5500c')):
|
||||
order_names = {
|
||||
1: '平台订单打手分红', 3: '商家订单打手分红',
|
||||
12: '押金管事分红', 13: '管事订单分红',
|
||||
}
|
||||
return Response({'code': 403, 'msg': f'无权限修改{order_names[role]}费率'})
|
||||
|
||||
# 1. 修改手续费利率
|
||||
for role in [1, 2, 3, 4, 5, 6]:
|
||||
val = rates.get(str(role), rates.get(role))
|
||||
if val is not None:
|
||||
rate = Decimal(str(val))
|
||||
code = rate_code_map[role]
|
||||
obj, created = CommissionRate.objects.select_for_update().get_or_create(
|
||||
Platform=code,
|
||||
defaults={'Rate': rate}
|
||||
)
|
||||
if not created:
|
||||
obj.Rate = rate
|
||||
obj.save()
|
||||
|
||||
# 1b. 修改订单/押金分红费率
|
||||
for role in [1, 3, 12, 13]:
|
||||
val = order_rates.get(str(role), order_rates.get(role))
|
||||
if val is not None:
|
||||
rate = Decimal(str(val))
|
||||
code = order_rate_code_map[role]
|
||||
obj, created = CommissionRate.objects.select_for_update().get_or_create(
|
||||
Platform=code,
|
||||
defaults={'Rate': rate}
|
||||
)
|
||||
if not created:
|
||||
obj.Rate = rate
|
||||
obj.save()
|
||||
|
||||
# 2. 修改个人每日限额
|
||||
for role in [1, 2, 3]:
|
||||
if str(role) in quotas:
|
||||
val = quotas[str(role)]
|
||||
if val is not None:
|
||||
quota = Decimal(str(val))
|
||||
obj, created = TixianQuotaDefault.objects.select_for_update().get_or_create(
|
||||
UserType=role,
|
||||
defaults={'default_quota': quota}
|
||||
)
|
||||
if not created:
|
||||
obj.default_quota = quota
|
||||
obj.save()
|
||||
|
||||
# 3. 修改每日总限额(1打手/2管事/3组长/4考核官/5押金/6商家)
|
||||
for role in [1, 2, 3, 4, 5, 6]:
|
||||
val = total_limits.get(str(role), total_limits.get(role))
|
||||
if val is not None:
|
||||
limit = Decimal(str(val))
|
||||
code = total_code_map[role]
|
||||
obj, created = TixianQuotaDefault.objects.select_for_update().get_or_create(
|
||||
UserType=code,
|
||||
defaults={'default_quota': limit}
|
||||
)
|
||||
if not created:
|
||||
obj.default_quota = limit
|
||||
obj.save()
|
||||
|
||||
# 🆕 修改提现模式(有5500a/b/c任一即可)
|
||||
withdraw_mode = request.data.get('withdraw_mode')
|
||||
if withdraw_mode is not None:
|
||||
if not any(p in permissions for p in ('5500a', '5500b', '5500c')):
|
||||
return Response({'code': 403, 'msg': '无权限修改提现模式'})
|
||||
# 更新或创建 id=1 的配置
|
||||
WithdrawConfig.query.update_or_create(
|
||||
id=1,
|
||||
defaults={'mode': int(withdraw_mode)}
|
||||
)
|
||||
|
||||
# 注意:WithdrawalDailyStats 表由提现流程自动更新,此处不直接修改
|
||||
return Response({'code': 0, 'msg': '设置修改成功'})
|
||||
from jituan.services.withdraw_config import apply_withdraw_settings_update
|
||||
return apply_withdraw_settings_update(request, permissions)
|
||||
|
||||
|
||||
|
||||
@@ -3738,7 +3624,10 @@ class GetZuzhangListView(APIView):
|
||||
commission_value = request.data.get('commission_value')
|
||||
|
||||
# 5. 构建基础 QuerySet(预加载关联表)
|
||||
queryset = UserZuzhang.query.select_related('user', 'user__BossProfile').all()
|
||||
queryset = filter_user_related_by_club(
|
||||
UserZuzhang.query.select_related('user', 'user__BossProfile').all(),
|
||||
request,
|
||||
)
|
||||
|
||||
# 6. 应用筛选条件(使用 ORM 安全过滤)
|
||||
if keyword:
|
||||
@@ -3808,6 +3697,7 @@ class GetZuzhangListView(APIView):
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'success',
|
||||
**list_response_meta(request),
|
||||
'data': {
|
||||
'list': data_list,
|
||||
'total': total,
|
||||
@@ -3869,6 +3759,10 @@ class GetZuzhangDetailView(APIView):
|
||||
except UserZuzhang.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '用户不是组长'})
|
||||
|
||||
denied = forbid_if_user_out_of_scope(request, user)
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
# 基础信息
|
||||
base_data = {
|
||||
'yonghuid': user.UserUID,
|
||||
@@ -4134,7 +4028,11 @@ class UpdateZuzhangView(APIView):
|
||||
|
||||
# 4.2 首次定制分红(cishu=1)
|
||||
if custom_first is not None and isinstance(custom_first, dict):
|
||||
existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1)
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id
|
||||
zuzhang_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
|
||||
existing_first = DuociFenhong.query.filter(
|
||||
club_id=zuzhang_club, yonghuid=yonghuid, cishu=1,
|
||||
)
|
||||
for huiyuan_id, amount in custom_first.items():
|
||||
try:
|
||||
amount = Decimal(str(amount))
|
||||
@@ -4142,9 +4040,12 @@ class UpdateZuzhangView(APIView):
|
||||
continue
|
||||
if amount <= 0:
|
||||
# 删除定制(恢复默认)
|
||||
DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete()
|
||||
DuociFenhong.query.filter(
|
||||
club_id=zuzhang_club, yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1,
|
||||
).delete()
|
||||
else:
|
||||
DuociFenhong.query.update_or_create(
|
||||
club_id=zuzhang_club,
|
||||
yonghuid=yonghuid,
|
||||
huiyuan=huiyuan_id,
|
||||
cishu=1,
|
||||
@@ -4160,6 +4061,8 @@ class UpdateZuzhangView(APIView):
|
||||
|
||||
# 4.3 额外次数分红(cishu >= 2)
|
||||
if extra_map is not None and isinstance(extra_map, dict):
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id
|
||||
zuzhang_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
|
||||
keep_set = set()
|
||||
for times_str, members in extra_map.items():
|
||||
try:
|
||||
@@ -4182,6 +4085,7 @@ class UpdateZuzhangView(APIView):
|
||||
continue
|
||||
keep_set.add((cishu, huiyuan_id))
|
||||
DuociFenhong.query.update_or_create(
|
||||
club_id=zuzhang_club,
|
||||
yonghuid=yonghuid,
|
||||
huiyuan=huiyuan_id,
|
||||
cishu=cishu,
|
||||
@@ -4191,7 +4095,9 @@ class UpdateZuzhangView(APIView):
|
||||
}
|
||||
)
|
||||
# 删除不在 keep_set 中的额外次数记录
|
||||
existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2)
|
||||
existing_extra = DuociFenhong.query.filter(
|
||||
club_id=zuzhang_club, yonghuid=yonghuid, cishu__gte=2,
|
||||
)
|
||||
for record in existing_extra:
|
||||
if (record.cishu, record.huiyuan) not in keep_set:
|
||||
record.delete()
|
||||
@@ -4367,6 +4273,8 @@ class GetOperationLogListView(APIView):
|
||||
page_size = 20
|
||||
|
||||
qs = Xiugaijilu.query.all().order_by('-CreateTime')
|
||||
from jituan.services.admin_audit import filter_xiugaijilu_by_request
|
||||
qs = filter_xiugaijilu_by_request(qs, request)
|
||||
if yonghuid:
|
||||
qs = qs.filter(yonghuid=yonghuid)
|
||||
if xiugaiid:
|
||||
@@ -4412,6 +4320,7 @@ class GetOperationLogListView(APIView):
|
||||
'create_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
|
||||
})
|
||||
|
||||
from jituan.services.club_user_access import list_response_meta
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
@@ -4419,6 +4328,7 @@ class GetOperationLogListView(APIView):
|
||||
'total': total,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
**list_response_meta(request),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -4995,11 +4905,19 @@ class PopupNoticeListAPIView(APIView):
|
||||
return Response({'code': 403, 'msg': '您没有权限访问弹窗管理功能'})
|
||||
|
||||
# 4. 查询所有页面,并预加载关联的弹窗和图片(避免N+1查询)
|
||||
pages = PopupPage.query.all().prefetch_related('popups__images').order_by('id')
|
||||
from jituan.services.display_config import filter_popup_page_by_request, list_response_meta
|
||||
|
||||
pages = filter_popup_page_by_request(
|
||||
PopupPage.query.all().prefetch_related('popups__images'),
|
||||
request,
|
||||
).order_by('id')
|
||||
|
||||
# 5. 序列化输出
|
||||
serializer = PopupPageSerializer(pages, many=True)
|
||||
return Response({'code': 0, 'data': {'pages': serializer.data}})
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {'pages': serializer.data, **list_response_meta(request)},
|
||||
})
|
||||
|
||||
|
||||
class PopupNoticeModifyAPIView(APIView):
|
||||
@@ -5020,6 +4938,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
if REQUIRED_PERMISSION not in permissions:
|
||||
return Response({'code': 403, 'msg': '您没有权限操作弹窗管理'})
|
||||
|
||||
from jituan.services.display_config import forbid_display_write_in_all_scope
|
||||
deny = forbid_display_write_in_all_scope(request)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# ---------- 2. 获取 action 并分发 ----------
|
||||
action = request.data.get('action')
|
||||
if not action:
|
||||
@@ -5055,15 +4978,24 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
|
||||
def add_page(self, request):
|
||||
"""添加新页面"""
|
||||
from jituan.services.club_context import resolve_club_id_from_request
|
||||
from jituan.services.display_config import forbid_display_write_in_all_scope
|
||||
|
||||
deny = forbid_display_write_in_all_scope(request)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
data = request.data
|
||||
# 必填字段校验
|
||||
if not data.get('page_key') or not data.get('name'):
|
||||
return Response({'code': 400, 'msg': '缺少 page_key 或 name'})
|
||||
# 唯一性校验
|
||||
if PopupPage.query.filter(page_key=data['page_key']).exists():
|
||||
club_id = resolve_club_id_from_request(request)
|
||||
# 唯一性校验(同俱乐部内)
|
||||
if PopupPage.query.filter(club_id=club_id, page_key=data['page_key']).exists():
|
||||
return Response({'code': 400, 'msg': '页面标识已存在'})
|
||||
|
||||
page = PopupPage.query.create(
|
||||
club_id=club_id,
|
||||
page_key=data['page_key'],
|
||||
name=data['name'],
|
||||
description=data.get('description', ''),
|
||||
@@ -5082,6 +5014,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupPage.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '页面不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# 更新允许修改的字段
|
||||
page.page_key = request.data.get('page_key', page.page_key)
|
||||
page.name = request.data.get('name', page.name)
|
||||
@@ -5102,6 +5039,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupPage.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '页面不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope, forbid_display_write_in_all_scope
|
||||
deny = forbid_display_write_in_all_scope(request) or forbid_popup_page_out_of_scope(request, page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
if cascade:
|
||||
# 级联删除:使用事务保证原子性
|
||||
with transaction.atomic():
|
||||
@@ -5135,6 +5077,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupPage.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '页面不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# 同一页面下 popup_id 必须唯一
|
||||
if PopupConfig.query.filter(page=page, popup_id=popup_id).exists():
|
||||
return Response({'code': 400, 'msg': '该页面下已存在相同的弹窗ID'})
|
||||
@@ -5166,6 +5113,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupConfig.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '弹窗不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, popup.page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# 更新弹窗字段
|
||||
popup.popup_id = request.data.get('popup_id', popup.popup_id)
|
||||
popup.title = request.data.get('title', popup.title)
|
||||
@@ -5192,6 +5144,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupConfig.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '弹窗不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, popup.page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
with transaction.atomic():
|
||||
for img in popup.images.all():
|
||||
if img.image_url:
|
||||
@@ -5237,6 +5194,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupConfig.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '弹窗不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, popup.page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# 获取上传的文件
|
||||
file_obj = request.FILES.get('file')
|
||||
if not file_obj:
|
||||
@@ -5267,6 +5229,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupImage.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '图片不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, image.popup_config.page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
# 更新文字和排序
|
||||
image.text = request.data.get('text', image.text)
|
||||
image.sort_order = request.data.get('sort_order', image.sort_order)
|
||||
@@ -5297,6 +5264,11 @@ class PopupNoticeModifyAPIView(APIView):
|
||||
except PopupImage.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '图片不存在'})
|
||||
|
||||
from jituan.services.display_config import forbid_popup_page_out_of_scope
|
||||
deny = forbid_popup_page_out_of_scope(request, image.popup_config.page)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
if image.image_url:
|
||||
delete_from_oss(image.image_url)
|
||||
image.delete()
|
||||
@@ -6191,7 +6163,7 @@ class FaKuanTongJiView(APIView):
|
||||
if not has_fadan_view_permission(permissions, username):
|
||||
return Response({'code': 403, 'msg': '无权限查看罚款统计'})
|
||||
|
||||
stats = Penalty.query.aggregate(
|
||||
stats = filter_penalty_qs(Penalty.query.all(), request).aggregate(
|
||||
total=Count('id'),
|
||||
daijiaona=Count('id', filter=Q(Status=1)),
|
||||
shensuzhong=Count('id', filter=Q(Status=3)),
|
||||
@@ -6199,7 +6171,8 @@ class FaKuanTongJiView(APIView):
|
||||
yibohui=Count('id', filter=Q(Status=4)),
|
||||
)
|
||||
data = {k: v or 0 for k, v in stats.items()}
|
||||
return Response({'code': 0, 'msg': '成功', 'data': data})
|
||||
from jituan.services.club_user_access import list_response_meta
|
||||
return Response({'code': 0, 'msg': '成功', 'data': {**data, **list_response_meta(request)}})
|
||||
except Exception as e:
|
||||
logger.error(f"罚款统计异常: {traceback.format_exc()}")
|
||||
return Response({'code': 500, 'msg': '系统繁忙'})
|
||||
@@ -6230,7 +6203,7 @@ class FaKuanLieBiaoView(APIView):
|
||||
if page_size > 100:
|
||||
page_size = 100
|
||||
|
||||
qs = Penalty.query.all()
|
||||
qs = filter_penalty_qs(Penalty.query.all(), request)
|
||||
|
||||
# 状态筛选
|
||||
zhuangtai = request.data.get('zhuangtai')
|
||||
@@ -6309,6 +6282,7 @@ class FaKuanLieBiaoView(APIView):
|
||||
'UpdateTime': r.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if r.UpdateTime else '',
|
||||
})
|
||||
|
||||
from jituan.services.club_user_access import list_response_meta
|
||||
return Response({
|
||||
'code': 0, 'msg': '成功',
|
||||
'data': {
|
||||
@@ -6316,6 +6290,7 @@ class FaKuanLieBiaoView(APIView):
|
||||
'total': paginator.count,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
**list_response_meta(request),
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
@@ -6351,6 +6326,10 @@ class FaKuanChuLiView(APIView):
|
||||
except Penalty.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '罚单不存在'})
|
||||
|
||||
deny = forbid_penalty_out_of_scope(request, penalty)
|
||||
if deny:
|
||||
return deny
|
||||
|
||||
if penalty.Status != 3:
|
||||
return Response({'code': 400, 'msg': '当前状态不可处理'})
|
||||
|
||||
@@ -6479,6 +6458,9 @@ class FaKuanChuangJianView(APIView):
|
||||
FineAmount=FineAmount,
|
||||
AffectsGrabbing=AffectsGrabbing,
|
||||
Status=1, # 待缴纳
|
||||
ClubID=resolve_penalty_club_id(
|
||||
penalized_user_id=PenalizedUserID, request=request,
|
||||
),
|
||||
)
|
||||
for relative_url in uploaded_urls:
|
||||
PenaltyAppealImage.query.create(
|
||||
@@ -6580,6 +6562,7 @@ class FineApplyView(APIView):
|
||||
Status=1, # 待缴纳
|
||||
AffectsGrabbing=AffectsGrabbing,
|
||||
ApplicantIdentity=1, # 申请人身份:1 客服
|
||||
ClubID=resolve_penalty_club_id(order=order, request=request),
|
||||
)
|
||||
for relative_url in uploaded_urls:
|
||||
PenaltyAppealImage.query.create(
|
||||
@@ -6658,6 +6641,7 @@ class PunishDashouView(APIView):
|
||||
ApplyStatus=0,
|
||||
DeductedPoints=jifen,
|
||||
OrderID=OrderID,
|
||||
ClubID=resolve_penalty_record_club_id(order_id=OrderID, player_id=dashou_id),
|
||||
)
|
||||
# 扣除打手积分
|
||||
dashou.jifen = F('jifen') - jifen
|
||||
@@ -7158,7 +7142,9 @@ class HybkjtsjView(APIView):
|
||||
}
|
||||
|
||||
# 充值分组查询
|
||||
chongzhi_qs = Czjilu.query.filter(**chongzhi_filter) \
|
||||
chongzhi_qs = filter_queryset_by_club(
|
||||
Czjilu.query.filter(**chongzhi_filter), request,
|
||||
) \
|
||||
.annotate(period=trunc_func) \
|
||||
.values('period') \
|
||||
.annotate(
|
||||
@@ -7174,7 +7160,9 @@ class HybkjtsjView(APIView):
|
||||
fenhong_agg['guanshi_amount'] = Sum('fenhong')
|
||||
if include_zuzhang:
|
||||
fenhong_agg['zuzhang_amount'] = Sum('zuzhang_fenhong')
|
||||
fenhong_qs = Gsfenhong.query.filter(**fenhong_filter) \
|
||||
fenhong_qs = filter_gsfenhong_qs(
|
||||
Gsfenhong.query.filter(**fenhong_filter), request,
|
||||
) \
|
||||
.annotate(period=trunc_func) \
|
||||
.values('period') \
|
||||
.annotate(**fenhong_agg) \
|
||||
@@ -7347,13 +7335,16 @@ class SzxxView(APIView):
|
||||
return Response({'code': 1, 'msg': '无效的颗粒度'}, status=400)
|
||||
|
||||
# ---------- 收入分组查询 ----------
|
||||
income_qs = DailyIncomeStat.query.filter(**income_filter) \
|
||||
.values(group_field) \
|
||||
income_qs = filter_queryset_by_club(
|
||||
DailyIncomeStat.query.filter(**income_filter), request,
|
||||
).values(group_field) \
|
||||
.annotate(total_income=Sum('total_amount'), total_count=Sum('total_count')) \
|
||||
.order_by(group_field)
|
||||
|
||||
# ---------- 支出分组查询 ----------
|
||||
payout_qs = DailyPayoutStat.query.filter(**payout_filter) \
|
||||
payout_qs = filter_queryset_by_club(
|
||||
DailyPayoutStat.query.filter(**payout_filter), request,
|
||||
).values(group_field) \
|
||||
.values(group_field) \
|
||||
.annotate(total_payout=Sum('total_amount'), total_count=Sum('total_count')) \
|
||||
.order_by(group_field)
|
||||
@@ -7395,10 +7386,14 @@ class SzxxView(APIView):
|
||||
time_series.sort(key=lambda x: x['date'])
|
||||
|
||||
# ---------- 汇总数据 ----------
|
||||
income_summary = DailyIncomeStat.query.filter(**summary_filter).aggregate(
|
||||
income_summary = filter_queryset_by_club(
|
||||
DailyIncomeStat.query.filter(**summary_filter), request,
|
||||
).aggregate(
|
||||
total_income=Sum('total_amount'), total_count=Sum('total_count')
|
||||
)
|
||||
payout_summary = DailyPayoutStat.query.filter(**summary_filter).aggregate(
|
||||
payout_summary = filter_queryset_by_club(
|
||||
DailyPayoutStat.query.filter(**summary_filter), request,
|
||||
).aggregate(
|
||||
total_payout=Sum('total_amount'), total_count=Sum('total_count')
|
||||
)
|
||||
total_income = float(income_summary['total_income'] or 0)
|
||||
@@ -7542,7 +7537,10 @@ class CwhqjtddsjView(APIView):
|
||||
filters['Platform'] = order_source
|
||||
|
||||
# ---------- 时间序列分组查询 ----------
|
||||
qs = Order.query.filter(**filters) \
|
||||
order_base = filter_queryset_by_club(
|
||||
Order.query.filter(**filters), request, club_field='ClubID',
|
||||
)
|
||||
qs = order_base \
|
||||
.annotate(period=trunc_func) \
|
||||
.values('period') \
|
||||
.annotate(
|
||||
@@ -7595,7 +7593,9 @@ class CwhqjtddsjView(APIView):
|
||||
})
|
||||
|
||||
# ---------- 汇总数据 ----------
|
||||
summary_qs = Order.query.filter(**filters)
|
||||
summary_qs = filter_queryset_by_club(
|
||||
Order.query.filter(**filters), request, club_field='ClubID',
|
||||
)
|
||||
total_order_count = summary_qs.count()
|
||||
total_order_amount = summary_qs.aggregate(s=Sum('Amount'))['s'] or 0
|
||||
total_success_count = summary_qs.filter(Status=3).count()
|
||||
@@ -7728,11 +7728,14 @@ class CwqtczhqView(APIView):
|
||||
# 1. 处理充值记录(Czjilu)—— 完全不变
|
||||
cz_types = [t for t in types if t in [2, 3, 4, 5]]
|
||||
if cz_types:
|
||||
cz_qs = Czjilu.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
leixing__in=cz_types,
|
||||
zhuangtai=3 # 只统计支付成功的
|
||||
cz_qs = filter_queryset_by_club(
|
||||
Czjilu.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
leixing__in=cz_types,
|
||||
zhuangtai=3,
|
||||
),
|
||||
request,
|
||||
).annotate(
|
||||
period=trunc_func
|
||||
).values('period', 'leixing').annotate(
|
||||
@@ -7762,10 +7765,13 @@ class CwqtczhqView(APIView):
|
||||
# 2. 处理罚款(Penalty)—— 修改:直接从 Penalty 表获取分红总额和分红笔数
|
||||
if 6 in types:
|
||||
# 使用一次聚合查询,同时获取罚款笔数、罚款金额、分红总额、分红笔数
|
||||
penalty_qs = Penalty.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
Status=2 # 已缴纳
|
||||
penalty_qs = filter_penalty_qs(
|
||||
Penalty.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
Status=2,
|
||||
),
|
||||
request,
|
||||
).annotate(
|
||||
period=trunc_func
|
||||
).values('period').annotate(
|
||||
@@ -7816,7 +7822,9 @@ class CwqtczhqView(APIView):
|
||||
filter_kwargs['CreateTime__month'] = summary_q.month
|
||||
else:
|
||||
filter_kwargs['CreateTime__year'] = summary_q.year
|
||||
agg = Czjilu.query.filter(**filter_kwargs).aggregate(count=Count('id'), amount=Sum('jine'))
|
||||
agg = filter_queryset_by_club(
|
||||
Czjilu.query.filter(**filter_kwargs), request,
|
||||
).aggregate(count=Count('id'), amount=Sum('jine'))
|
||||
count = agg['count'] or 0
|
||||
amount = float(agg['amount'] or 0)
|
||||
profit = amount if lx == 3 else 0.0
|
||||
@@ -7845,7 +7853,9 @@ class CwqtczhqView(APIView):
|
||||
penalty_filter['CreateTime__year'] = summary_q.year
|
||||
|
||||
# 一次聚合:罚款笔数、金额、分红总额、分红笔数
|
||||
agg = Penalty.query.filter(**penalty_filter).aggregate(
|
||||
agg = filter_penalty_qs(
|
||||
Penalty.query.filter(**penalty_filter), request,
|
||||
).aggregate(
|
||||
count=Count('id'),
|
||||
amount=Sum('FineAmount'),
|
||||
fenhong_amount=Sum('ApplicantBonusAmount'),
|
||||
@@ -8073,7 +8083,9 @@ class CwqtczhqView(APIView):
|
||||
filter_kwargs['CreateTime__month'] = summary_q.month
|
||||
else:
|
||||
filter_kwargs['CreateTime__year'] = summary_q.year
|
||||
agg = Czjilu.query.filter(**filter_kwargs).aggregate(count=Count('id'), amount=Sum('jine'))
|
||||
agg = filter_queryset_by_club(
|
||||
Czjilu.query.filter(**filter_kwargs), request,
|
||||
).aggregate(count=Count('id'), amount=Sum('jine'))
|
||||
count = agg['count'] or 0
|
||||
amount = float(agg['amount'] or 0)
|
||||
profit = amount if lx == 3 else 0.0
|
||||
@@ -8422,7 +8434,10 @@ class KhgglView(APIView):
|
||||
filter_bankuai_name = request.data.get('bankuai_name', '').strip()
|
||||
|
||||
# 基础查询:所有审核官,预加载用户及打手扩展表
|
||||
queryset = UserShenheguan.query.select_related('user__DashouProfile')
|
||||
queryset = filter_user_related_by_club(
|
||||
UserShenheguan.query.select_related('user__DashouProfile'),
|
||||
request,
|
||||
)
|
||||
|
||||
if filter_yonghuid:
|
||||
queryset = queryset.filter(user__UserUID=filter_yonghuid)
|
||||
@@ -8446,14 +8461,19 @@ class KhgglView(APIView):
|
||||
end = start + page_size
|
||||
shenheguan_list = queryset.order_by('-CreateTime')[start:end]
|
||||
|
||||
from jituan.services.shenhe_club import yonghu_chenghao_qs_for_request
|
||||
|
||||
# ---------- 预计算每个板块的打手数量 ----------
|
||||
bankuai_dashou_count_map = {}
|
||||
all_banquai = Bankuai.query.all()
|
||||
for bk in all_banquai:
|
||||
tag_ids = Chenghao.query.filter(bankuai=bk, leixing='dashou').values_list('id', flat=True)
|
||||
count = YonghuChenghao.query.filter(
|
||||
chenghao_id__in=tag_ids,
|
||||
yonghu__DashouProfile__isnull=False
|
||||
count = yonghu_chenghao_qs_for_request(
|
||||
YonghuChenghao.query.filter(
|
||||
chenghao_id__in=tag_ids,
|
||||
yonghu__DashouProfile__isnull=False,
|
||||
),
|
||||
request,
|
||||
).values('yonghu').distinct().count()
|
||||
bankuai_dashou_count_map[bk.bankuai_id] = count
|
||||
|
||||
@@ -8463,7 +8483,10 @@ class KhgglView(APIView):
|
||||
tags = Chenghao.query.filter(bankuai=bk, leixing='dashou')
|
||||
tag_list = []
|
||||
for tag in tags:
|
||||
user_count = YonghuChenghao.query.filter(chenghao=tag).values('yonghu').distinct().count()
|
||||
user_count = yonghu_chenghao_qs_for_request(
|
||||
YonghuChenghao.query.filter(chenghao=tag),
|
||||
request,
|
||||
).values('yonghu').distinct().count()
|
||||
tag_list.append({
|
||||
'id': tag.id,
|
||||
'name': tag.mingcheng,
|
||||
@@ -8772,6 +8795,7 @@ class ZxkfghdsView(APIView):
|
||||
Remark=old_order.Remark,
|
||||
User1ID=old_order.User1ID, # 商家标识
|
||||
ImageURL=old_order.ImageURL,
|
||||
ClubID=getattr(old_order, 'ClubID', None) or 'xq',
|
||||
# 注意:不继承 AssignedID、PlayerID
|
||||
)
|
||||
|
||||
@@ -9022,13 +9046,24 @@ class KhjlglView(APIView):
|
||||
if page_size > 100:
|
||||
page_size = 100
|
||||
|
||||
from jituan.services.shenhe_club import filter_shenhe_jilu_by_request
|
||||
|
||||
filter_data = request.data
|
||||
qs = _build_shenhe_jilu_filters(filter_data)
|
||||
qs = filter_shenhe_jilu_by_request(
|
||||
_build_shenhe_jilu_filters(filter_data),
|
||||
request,
|
||||
)
|
||||
|
||||
# FluentQuery.filter() 会原地修改同一对象;统计与列表必须各自独立查询
|
||||
stats_base = _build_shenhe_jilu_filters(filter_data)
|
||||
stats_base = filter_shenhe_jilu_by_request(
|
||||
_build_shenhe_jilu_filters(filter_data),
|
||||
request,
|
||||
)
|
||||
agg = stats_base.aggregate(total_fee=Sum('jiaofei_jine'))
|
||||
tag_rows = _build_shenhe_jilu_filters(filter_data).values(
|
||||
tag_rows = filter_shenhe_jilu_by_request(
|
||||
_build_shenhe_jilu_filters(filter_data),
|
||||
request,
|
||||
).values(
|
||||
'chenghao_id', 'chenghao__mingcheng'
|
||||
).annotate(
|
||||
total=Count('jilu_id'),
|
||||
@@ -9040,10 +9075,10 @@ class KhjlglView(APIView):
|
||||
|
||||
stats = {
|
||||
'total': stats_base.count(),
|
||||
'passed': _build_shenhe_jilu_filters(filter_data).filter(zhuangtai=1).count(),
|
||||
'failed': _build_shenhe_jilu_filters(filter_data).filter(zhuangtai=2).count(),
|
||||
'in_progress': _build_shenhe_jilu_filters(filter_data).filter(zhuangtai=0).count(),
|
||||
'pending': _build_shenhe_jilu_filters(filter_data).filter(zhuangtai=3).count(),
|
||||
'passed': stats_base.filter(zhuangtai=1).count(),
|
||||
'failed': stats_base.filter(zhuangtai=2).count(),
|
||||
'in_progress': stats_base.filter(zhuangtai=0).count(),
|
||||
'pending': stats_base.filter(zhuangtai=3).count(),
|
||||
'total_fee': float(agg['total_fee'] or 0),
|
||||
'tag_stats': [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user