Files
Django/jituan/services/group_finance_gate.py
XingQue 96f1a80395 feat: 俱乐部超级管理可加本店余额,不再强制集团高管
持有000001且处于当前俱乐部视图时可加余额/押金/可提现;强制目标用户同俱乐部,并在修改记录中写入俱乐部ID。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 07:53:33 +08:00

137 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""集团/俱乐部资金处置权限。
加余额(及同类增加资金):
- 系统超管 / 集团高管GROUP_OWNER、GROUP_SUPER_ADMIN可按数据范围操作
- 当前俱乐部超级管理 000001仅限 SINGLE_CLUB 本店,且目标用户必须属于当前俱乐部
不再强制「仅集团高管才能加余额」。
提现审核:权限码 005bb + 按俱乐部隔离——
- 子公司视图:持有 005bb 且任职含当前俱乐部 → 可审本俱乐部
- 集团汇总视图 / 跨俱乐部:须集团资金处置权
"""
from django.db.models import Q
from jituan.constants import DATA_SCOPE_ALL
from jituan.models import AdminAssignment
from jituan.services.admin_context import (
GROUP_MANAGE_ROLES,
build_admin_club_context,
get_allowed_club_ids,
is_system_super_admin,
)
MSG_GROUP_FINANCE_REQUIRED = '该操作仅集团高管可执行(需在数据范围配置中为集团级任职)'
MSG_BALANCE_ADD_DENIED = (
'无权加余额需当前俱乐部超级管理权限000001或集团高管任职'
'且仅能操作当前俱乐部用户'
)
MSG_BALANCE_ADD_CROSS_CLUB = '跨俱乐部加余额仅集团高管可执行,请切换到具体俱乐部后再操作'
MSG_BALANCE_ADD_CLUB_DENIED = '无权在该俱乐部加余额'
MSG_WITHDRAW_CROSS_CLUB = '跨俱乐部提现审核仅集团高管可执行,请切换到具体俱乐部后再操作'
MSG_WITHDRAW_CLUB_DENIED = '无权审核该俱乐部提现'
def has_group_finance_exec(user, request=None):
"""系统超管 / 集团任职GROUP_OWNER、GROUP_SUPER_ADMIN"""
if is_system_super_admin(user):
return True
ctx = build_admin_club_context(user)
if ctx.get('is_group_admin') and ctx.get('role_code') in GROUP_MANAGE_ROLES:
return True
uid = getattr(user, 'UserUID', None)
if not uid:
return False
return AdminAssignment.query.filter(
yonghuid=uid,
status=1,
role_code__in=GROUP_MANAGE_ROLES,
).filter(
Q(club_id__isnull=True) | Q(data_scope=DATA_SCOPE_ALL),
).exists()
def deny_group_finance_exec(user, request=None):
"""仅集团高管(旧闸门,保留给非加余额场景如需)。"""
from rest_framework.response import Response
if has_group_finance_exec(user, request):
return None
return Response({'code': 403, 'msg': MSG_GROUP_FINANCE_REQUIRED})
def deny_balance_add_exec(request, *, permissions=None, target_user=None):
"""
加余额 / 加押金 / 增加可提现等「资金增加」闸门。
放行条件(满足其一):
1) 系统超管或集团高管
2) 当前请求权限含俱乐部超级管理 000001且为 SINGLE_CLUB
当前俱乐部在任职范围内
无论哪种身份:若传入 target_user必须属于当前请求俱乐部数据范围
(集团 ALL_CLUBS 视图下目标校验放行,见 forbid_if_user_out_of_scope
"""
from rest_framework.response import Response
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
from jituan.services.club_user_access import forbid_if_user_out_of_scope
user = getattr(request, 'user', None)
perms = permissions or []
if has_group_finance_exec(user, request):
if target_user is not None:
denied = forbid_if_user_out_of_scope(request, target_user)
if denied:
return denied
return None
if '000001' not in perms:
return Response({'code': 403, 'msg': MSG_BALANCE_ADD_DENIED})
scope = resolve_club_scope(request)
if scope == DATA_SCOPE_ALL:
return Response({'code': 403, 'msg': MSG_BALANCE_ADD_CROSS_CLUB})
club_id = resolve_club_id_from_request(request)
allowed = get_allowed_club_ids(user)
if not club_id or club_id not in allowed:
return Response({'code': 403, 'msg': MSG_BALANCE_ADD_CLUB_DENIED})
if target_user is not None:
denied = forbid_if_user_out_of_scope(request, target_user)
if denied:
return denied
return None
def require_withdraw_audit_access(request, phone):
"""
提现审核访问:
1) 须权限码 005bb
2) 集团高管:可在 ALL_CLUBS 或任意子公司视图操作
3) 俱乐部管理员:仅 SINGLE_CLUB 且当前 club 在其任职范围内
"""
from backend.utils import verify_kefu_permission
from rest_framework.response import Response
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
kefu, permissions = verify_kefu_permission(request, phone)
if kefu is None:
return None, permissions
if '005bb' not in permissions:
return None, Response({'code': 403, 'msg': '您无权操作提现审核'})
if has_group_finance_exec(request.user, request):
return kefu, None
scope = resolve_club_scope(request)
if scope == DATA_SCOPE_ALL:
return None, Response({'code': 403, 'msg': MSG_WITHDRAW_CROSS_CLUB})
club_id = resolve_club_id_from_request(request)
allowed = get_allowed_club_ids(request.user)
if not club_id or club_id not in allowed:
return None, Response({'code': 403, 'msg': MSG_WITHDRAW_CLUB_DENIED})
return kefu, None