feat: 资金冻结 P2 客服后台 API(配置/明细/风险/手动解冻)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -330,6 +330,9 @@ class KefuGetDashouDetailView(APIView):
|
||||
'tuikuanliang': dashou.tuikuanliang,
|
||||
'jinrijiedan': dashou.jinrijiedan,
|
||||
'yue': float(dashou.yue) if dashou.yue else 0.00,
|
||||
'dongjie_yue': float(getattr(dashou, 'dongjie_yue', 0) or 0),
|
||||
'risk_fine_rate': float(getattr(dashou, 'risk_fine_rate', 0) or 0),
|
||||
'risk_complaint_rate': float(getattr(dashou, 'risk_complaint_rate', 0) or 0),
|
||||
'zonge': float(dashou.zonge) if dashou.zonge else 0.00,
|
||||
'jifen': dashou.jifen,
|
||||
'yajin': float(dashou.yajin) if dashou.yajin else 0.00,
|
||||
|
||||
384
jituan/services/fund_freeze_admin.py
Normal file
384
jituan/services/fund_freeze_admin.py
Normal file
@@ -0,0 +1,384 @@
|
||||
"""客服后台:资金冻结配置 / 明细 / 风险指标。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from decimal import Decimal
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import ClubFundFreezeConfig, FundFreezeLedger, FundUnfreezeEvent
|
||||
from jituan.services.club_context import filter_user_related_by_club, resolve_club_id_from_request
|
||||
from jituan.services.fund_freeze import (
|
||||
ROLE_DASHOU,
|
||||
ROLE_GUANSHI,
|
||||
ROLE_SHENHEGUAN,
|
||||
ROLE_ZUZHANG,
|
||||
apply_unfreeze_step,
|
||||
invalidate_freeze_config_cache,
|
||||
split_preview,
|
||||
)
|
||||
|
||||
ROLES = (
|
||||
(ROLE_DASHOU, '打手'),
|
||||
(ROLE_GUANSHI, '管事'),
|
||||
(ROLE_ZUZHANG, '组长'),
|
||||
(ROLE_SHENHEGUAN, '考核官'),
|
||||
)
|
||||
|
||||
DEFAULT_INSTALLMENT = {
|
||||
'steps': [
|
||||
{'seq': 1, 'after_days': 7, 'type': 'ratio', 'value': 0.3, 'need_condition': False},
|
||||
{'seq': 2, 'after_days': 14, 'type': 'ratio', 'value': 0.3, 'need_condition': True},
|
||||
{'seq': 3, 'after_days': 30, 'type': 'remain', 'value': 1, 'need_condition': True},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _club(request) -> str:
|
||||
return (resolve_club_id_from_request(request) or CLUB_ID_DEFAULT).strip() or CLUB_ID_DEFAULT
|
||||
|
||||
|
||||
def _dec(v, default='0') -> str:
|
||||
try:
|
||||
return str(Decimal(str(v if v is not None else default)))
|
||||
except Exception:
|
||||
return str(default)
|
||||
|
||||
|
||||
def _cfg_to_dict(row: Optional[ClubFundFreezeConfig], club_id: str, role: str) -> Dict[str, Any]:
|
||||
if not row:
|
||||
return {
|
||||
'club_id': club_id,
|
||||
'role': role,
|
||||
'enabled': False,
|
||||
'freeze_mode': 1,
|
||||
'freeze_rate': '0',
|
||||
'freeze_fixed': '0',
|
||||
'freeze_cap': '0',
|
||||
'min_credit_to_freeze': '0',
|
||||
'source_scope': ['order_settle'],
|
||||
'unfreeze_trigger': 'time_only',
|
||||
'schedule_mode': 'all_at_once',
|
||||
'installment_json': {'steps': [{'seq': 1, 'after_days': 15, 'type': 'remain', 'value': 1, 'need_condition': False}]},
|
||||
'condition_json': {
|
||||
'min_completed_orders': 0,
|
||||
'max_fine_rate': 1,
|
||||
'fine_rate_window_days': 30,
|
||||
'max_complaint_rate': 1,
|
||||
'complaint_rate_window_days': 30,
|
||||
'min_valid_invites': 0,
|
||||
},
|
||||
'freeze_min_days': 0,
|
||||
'remark': '',
|
||||
'exists': False,
|
||||
}
|
||||
return {
|
||||
'club_id': row.club_id,
|
||||
'role': row.role,
|
||||
'enabled': bool(row.enabled),
|
||||
'freeze_mode': int(row.freeze_mode or 1),
|
||||
'freeze_rate': _dec(row.freeze_rate),
|
||||
'freeze_fixed': _dec(row.freeze_fixed),
|
||||
'freeze_cap': _dec(row.freeze_cap),
|
||||
'min_credit_to_freeze': _dec(row.min_credit_to_freeze),
|
||||
'source_scope': row.source_scope or [],
|
||||
'unfreeze_trigger': row.unfreeze_trigger or 'time_only',
|
||||
'schedule_mode': row.schedule_mode or 'all_at_once',
|
||||
'installment_json': row.installment_json or {},
|
||||
'condition_json': row.condition_json or {},
|
||||
'freeze_min_days': int(row.freeze_min_days or 0),
|
||||
'remark': row.remark or '',
|
||||
'updated_by': row.updated_by or '',
|
||||
'exists': True,
|
||||
}
|
||||
|
||||
|
||||
def build_config_payload(request) -> Dict[str, Any]:
|
||||
club_id = _club(request)
|
||||
rows = {
|
||||
r.role: r
|
||||
for r in ClubFundFreezeConfig.query.filter(club_id=club_id)
|
||||
}
|
||||
items = []
|
||||
for role, name in ROLES:
|
||||
d = _cfg_to_dict(rows.get(role), club_id, role)
|
||||
d['role_name'] = name
|
||||
avail, frozen = split_preview(club_id, role, Decimal('100'), 'order_settle')
|
||||
d['preview_100'] = {'available': str(avail), 'frozen': str(frozen)}
|
||||
items.append(d)
|
||||
return {'club_id': club_id, 'roles': items}
|
||||
|
||||
|
||||
def save_config(request, data: dict, operator: str = '') -> Tuple[Optional[dict], Optional[str]]:
|
||||
club_id = _club(request)
|
||||
role = (data.get('role') or '').strip().lower()
|
||||
if role not in {r[0] for r in ROLES}:
|
||||
return None, '无效角色'
|
||||
|
||||
enabled = bool(data.get('enabled'))
|
||||
freeze_mode = int(data.get('freeze_mode') or 1)
|
||||
if freeze_mode not in (1, 2, 3):
|
||||
return None, 'freeze_mode 无效'
|
||||
|
||||
try:
|
||||
freeze_rate = Decimal(str(data.get('freeze_rate') or 0))
|
||||
freeze_fixed = Decimal(str(data.get('freeze_fixed') or 0))
|
||||
freeze_cap = Decimal(str(data.get('freeze_cap') or 0))
|
||||
min_credit = Decimal(str(data.get('min_credit_to_freeze') or 0))
|
||||
except Exception:
|
||||
return None, '金额/比例格式错误'
|
||||
|
||||
if freeze_rate < 0 or freeze_rate > 1:
|
||||
return None, '冻结比例须在 0~1 之间(如 0.2=20%)'
|
||||
|
||||
source_scope = data.get('source_scope')
|
||||
if source_scope is None:
|
||||
source_scope = ['order_settle']
|
||||
if isinstance(source_scope, str):
|
||||
try:
|
||||
source_scope = json.loads(source_scope)
|
||||
except Exception:
|
||||
source_scope = [source_scope]
|
||||
|
||||
unfreeze_trigger = (data.get('unfreeze_trigger') or 'time_only').strip()
|
||||
if unfreeze_trigger not in (
|
||||
'time_only', 'condition_only', 'time_and_condition', 'time_or_condition', 'manual_only',
|
||||
):
|
||||
return None, '解冻触发模式无效'
|
||||
|
||||
schedule_mode = (data.get('schedule_mode') or 'all_at_once').strip()
|
||||
if schedule_mode not in ('all_at_once', 'installment'):
|
||||
return None, '分期模式无效'
|
||||
|
||||
installment_json = data.get('installment_json') or {}
|
||||
if isinstance(installment_json, str):
|
||||
try:
|
||||
installment_json = json.loads(installment_json)
|
||||
except Exception:
|
||||
return None, 'installment_json 不是合法 JSON'
|
||||
if schedule_mode == 'installment' and not (installment_json.get('steps') or []):
|
||||
installment_json = DEFAULT_INSTALLMENT
|
||||
|
||||
condition_json = data.get('condition_json') or {}
|
||||
if isinstance(condition_json, str):
|
||||
try:
|
||||
condition_json = json.loads(condition_json)
|
||||
except Exception:
|
||||
return None, 'condition_json 不是合法 JSON'
|
||||
|
||||
freeze_min_days = int(data.get('freeze_min_days') or 0)
|
||||
if freeze_min_days < 0:
|
||||
return None, '最短冻结天数不能为负'
|
||||
|
||||
row = ClubFundFreezeConfig.query.filter(club_id=club_id, role=role).first()
|
||||
if not row:
|
||||
row = ClubFundFreezeConfig(
|
||||
club_id=club_id,
|
||||
role=role,
|
||||
)
|
||||
row.enabled = enabled
|
||||
row.freeze_mode = freeze_mode
|
||||
row.freeze_rate = freeze_rate
|
||||
row.freeze_fixed = freeze_fixed
|
||||
row.freeze_cap = freeze_cap
|
||||
row.min_credit_to_freeze = min_credit
|
||||
row.source_scope = source_scope
|
||||
row.unfreeze_trigger = unfreeze_trigger
|
||||
row.schedule_mode = schedule_mode
|
||||
row.installment_json = installment_json
|
||||
row.condition_json = condition_json
|
||||
row.freeze_min_days = freeze_min_days
|
||||
row.remark = (data.get('remark') or '')[:255]
|
||||
row.updated_by = (operator or '')[:32]
|
||||
row.save()
|
||||
invalidate_freeze_config_cache(club_id, role)
|
||||
out = _cfg_to_dict(row, club_id, role)
|
||||
out['role_name'] = dict(ROLES).get(role, role)
|
||||
return out, None
|
||||
|
||||
|
||||
STATUS_LABEL = {
|
||||
FundFreezeLedger.STATUS_FROZEN: '冻结中',
|
||||
FundFreezeLedger.STATUS_PARTIAL: '部分解冻',
|
||||
FundFreezeLedger.STATUS_DONE: '已解冻',
|
||||
FundFreezeLedger.STATUS_VOID: '已作废',
|
||||
}
|
||||
|
||||
|
||||
def list_ledgers(request, data: dict) -> Dict[str, Any]:
|
||||
club_id = _club(request)
|
||||
page = max(1, int(data.get('page') or 1))
|
||||
page_size = min(100, max(1, int(data.get('page_size') or 20)))
|
||||
role = (data.get('role') or '').strip().lower()
|
||||
status = data.get('status')
|
||||
user_id = (data.get('user_id') or data.get('yonghuid') or '').strip()
|
||||
order_id = (data.get('order_id') or '').strip()
|
||||
kw = (data.get('keyword') or '').strip()
|
||||
|
||||
qs = FundFreezeLedger.query.filter(club_id=club_id)
|
||||
if role:
|
||||
qs = qs.filter(role=role)
|
||||
if status not in (None, ''):
|
||||
try:
|
||||
qs = qs.filter(status=int(status))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if user_id:
|
||||
qs = qs.filter(user_id=user_id)
|
||||
if order_id:
|
||||
qs = qs.filter(order_id=order_id)
|
||||
if kw:
|
||||
qs = qs.filter(Q(user_id__icontains=kw) | Q(order_id__icontains=kw) | Q(biz_id__icontains=kw))
|
||||
|
||||
total = qs.count()
|
||||
rows = qs.order_by('-id')[(page - 1) * page_size: page * page_size]
|
||||
items = []
|
||||
for r in rows:
|
||||
remain = Decimal(str(r.amount_total or 0)) - Decimal(str(r.amount_unfrozen or 0))
|
||||
items.append({
|
||||
'id': r.id,
|
||||
'club_id': r.club_id,
|
||||
'user_id': r.user_id,
|
||||
'role': r.role,
|
||||
'role_name': dict(ROLES).get(r.role, r.role),
|
||||
'amount_total': _dec(r.amount_total),
|
||||
'amount_unfrozen': _dec(r.amount_unfrozen),
|
||||
'amount_remain': _dec(remain),
|
||||
'status': r.status,
|
||||
'status_label': STATUS_LABEL.get(r.status, str(r.status)),
|
||||
'frozen_at': r.frozen_at.isoformat() if r.frozen_at else '',
|
||||
'next_eligible_at': r.next_eligible_at.isoformat() if r.next_eligible_at else '',
|
||||
'source_type': r.source_type,
|
||||
'order_id': r.order_id,
|
||||
'czjilu_id': r.czjilu_id,
|
||||
'biz_id': r.biz_id,
|
||||
'freeze_reason': r.freeze_reason,
|
||||
'current_step': r.current_step,
|
||||
})
|
||||
return {
|
||||
'club_id': club_id,
|
||||
'list': items,
|
||||
'total': total,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
}
|
||||
|
||||
|
||||
def list_unfreeze_events(ledger_id: int, club_id: str) -> List[dict]:
|
||||
qs = FundUnfreezeEvent.query.filter(ledger_id=ledger_id, club_id=club_id).order_by('-id')[:50]
|
||||
return [{
|
||||
'id': e.id,
|
||||
'step_seq': e.step_seq,
|
||||
'amount': _dec(e.amount),
|
||||
'unfrozen_at': e.unfrozen_at.isoformat() if e.unfrozen_at else '',
|
||||
'trigger': e.trigger,
|
||||
'reason': e.reason,
|
||||
'operator_id': e.operator_id,
|
||||
} for e in qs]
|
||||
|
||||
|
||||
def manual_unfreeze(request, data: dict, operator: str = '') -> Tuple[Optional[dict], Optional[str]]:
|
||||
club_id = _club(request)
|
||||
try:
|
||||
ledger_id = int(data.get('ledger_id') or data.get('id') or 0)
|
||||
except (TypeError, ValueError):
|
||||
return None, 'ledger_id 无效'
|
||||
if ledger_id <= 0:
|
||||
return None, '缺少 ledger_id'
|
||||
|
||||
ledger = FundFreezeLedger.query.filter(id=ledger_id, club_id=club_id).first()
|
||||
if not ledger:
|
||||
return None, '冻结单不存在或不属于当前俱乐部'
|
||||
|
||||
mode = (data.get('mode') or 'step').strip() # step | all
|
||||
if mode == 'all':
|
||||
# 循环解完(最多 20 步防死循环)
|
||||
last = None
|
||||
for _ in range(20):
|
||||
last = apply_unfreeze_step(
|
||||
ledger_id,
|
||||
trigger='manual',
|
||||
operator_id=operator,
|
||||
reason=(data.get('reason') or '后台手动全部解冻')[:255],
|
||||
force=True,
|
||||
)
|
||||
if not last.get('ok'):
|
||||
return None, last.get('msg') or '解冻失败'
|
||||
if last.get('done'):
|
||||
break
|
||||
return last, None
|
||||
|
||||
result = apply_unfreeze_step(
|
||||
ledger_id,
|
||||
trigger='manual',
|
||||
operator_id=operator,
|
||||
reason=(data.get('reason') or '后台手动解冻一步')[:255],
|
||||
force=True,
|
||||
)
|
||||
if not result.get('ok'):
|
||||
return None, result.get('msg') or '解冻失败'
|
||||
return result, None
|
||||
|
||||
|
||||
def list_risk_users(request, data: dict) -> Dict[str, Any]:
|
||||
"""从角色扩展表读风险快照 + 冻结池(按俱乐部用户过滤)。"""
|
||||
from users.models import UserDashou, UserGuanshi, UserZuzhang, UserShenheguan
|
||||
from jituan.services.club_context import filter_user_related_by_club
|
||||
|
||||
club_id = _club(request)
|
||||
role = (data.get('role') or ROLE_DASHOU).strip().lower()
|
||||
page = max(1, int(data.get('page') or 1))
|
||||
page_size = min(100, max(1, int(data.get('page_size') or 20)))
|
||||
keyword = (data.get('keyword') or '').strip()
|
||||
only_frozen = bool(data.get('only_frozen'))
|
||||
|
||||
mapping = {
|
||||
ROLE_DASHOU: UserDashou,
|
||||
ROLE_GUANSHI: UserGuanshi,
|
||||
ROLE_ZUZHANG: UserZuzhang,
|
||||
ROLE_SHENHEGUAN: UserShenheguan,
|
||||
}
|
||||
model = mapping.get(role)
|
||||
if not model:
|
||||
return {'club_id': club_id, 'list': [], 'total': 0, 'page': page, 'page_size': page_size}
|
||||
|
||||
qs = model.query.select_related('user').all()
|
||||
qs = filter_user_related_by_club(qs, request, user_club_path='user__ClubID')
|
||||
|
||||
if keyword:
|
||||
qs = qs.filter(user__UserUID__icontains=keyword)
|
||||
if only_frozen:
|
||||
qs = qs.filter(dongjie_yue__gt=0)
|
||||
|
||||
total = qs.count()
|
||||
rows = qs.order_by('-dongjie_yue', '-id')[(page - 1) * page_size: page * page_size]
|
||||
items = []
|
||||
for p in rows:
|
||||
uid = getattr(p.user, 'UserUID', '') if p.user_id else ''
|
||||
if role == ROLE_ZUZHANG:
|
||||
available = _dec(getattr(p, 'ketixian_jine', 0))
|
||||
else:
|
||||
available = _dec(getattr(p, 'yue', 0))
|
||||
items.append({
|
||||
'user_id': uid,
|
||||
'role': role,
|
||||
'role_name': dict(ROLES).get(role, role),
|
||||
'available': available,
|
||||
'dongjie_yue': _dec(getattr(p, 'dongjie_yue', 0)),
|
||||
'risk_fine_rate': _dec(getattr(p, 'risk_fine_rate', 0)),
|
||||
'risk_complaint_rate': _dec(getattr(p, 'risk_complaint_rate', 0)),
|
||||
'risk_completed_orders': int(getattr(p, 'risk_completed_orders', 0) or 0),
|
||||
'risk_valid_invites': int(getattr(p, 'risk_valid_invites', 0) or 0),
|
||||
'risk_stat_at': p.risk_stat_at.isoformat() if getattr(p, 'risk_stat_at', None) else '',
|
||||
'nicheng': getattr(p, 'nicheng', '') or '',
|
||||
})
|
||||
return {
|
||||
'club_id': club_id,
|
||||
'role': role,
|
||||
'list': items,
|
||||
'total': total,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
}
|
||||
@@ -101,6 +101,11 @@ from jituan.views_recharge_page_copy import (
|
||||
RechargePageCopyView,
|
||||
)
|
||||
from jituan.views_order_grab_share import ClubOrderGrabLinkManageView
|
||||
from jituan.views_fund_freeze import (
|
||||
FundFreezeConfigView,
|
||||
FundFreezeLedgerView,
|
||||
FundFreezeRiskView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path('auth/wechat-login', ClubWechatLoginView.as_view(), name='jituan_wechat_login'),
|
||||
@@ -112,6 +117,9 @@ urlpatterns = [
|
||||
path('auth/dashou-register', ClubDashouRegisterView.as_view(), name='jituan_dashou_register'),
|
||||
path('houtai/club-manage', ClubManageView.as_view(), name='jituan_club_manage'),
|
||||
path('houtai/order-grab-link', ClubOrderGrabLinkManageView.as_view(), name='jituan_order_grab_link'),
|
||||
path('houtai/fund-freeze-config', FundFreezeConfigView.as_view(), name='jituan_fund_freeze_config'),
|
||||
path('houtai/fund-freeze-ledger', FundFreezeLedgerView.as_view(), name='jituan_fund_freeze_ledger'),
|
||||
path('houtai/fund-freeze-risk', FundFreezeRiskView.as_view(), name='jituan_fund_freeze_risk'),
|
||||
path('houtai/payment-channel-manage', ClubPaymentChannelManageView.as_view(), name='jituan_payment_channel_manage'),
|
||||
path('houtai/club-cert-upload', ClubCertUploadView.as_view(), name='jituan_club_cert_upload'),
|
||||
path('houtai/admin-assignments', ClubAdminAssignmentListView.as_view(), name='jituan_admin_assignments'),
|
||||
|
||||
105
jituan/views_fund_freeze.py
Normal file
105
jituan/views_fund_freeze.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""客服后台资金冻结 API。"""
|
||||
from rest_framework.parsers import JSONParser
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from backend.utils import verify_kefu_permission
|
||||
from jituan.services import fund_freeze_admin as admin_svc
|
||||
|
||||
PERM_CFG = 'djcfg001'
|
||||
PERM_LED = 'djled001'
|
||||
PERM_RISK = 'djrisk001'
|
||||
|
||||
|
||||
def _auth(request, perm_code: str):
|
||||
username = (request.data.get('username') or request.data.get('phone') or '').strip()
|
||||
if not username:
|
||||
return None, None, Response({'code': 400, 'msg': '缺少username'})
|
||||
kefu, permissions = verify_kefu_permission(request, username)
|
||||
if kefu is None:
|
||||
return None, None, permissions
|
||||
codes = set(permissions or [])
|
||||
user = getattr(request, 'user', None)
|
||||
if getattr(user, 'IsSuperuser', False) or '000001' in codes:
|
||||
return kefu, permissions, None
|
||||
if perm_code not in codes:
|
||||
return None, None, Response({'code': 403, 'msg': f'无权限(需要 {perm_code})'})
|
||||
return kefu, permissions, None
|
||||
|
||||
|
||||
class FundFreezeConfigView(APIView):
|
||||
"""
|
||||
POST /jituan/houtai/fund-freeze-config
|
||||
action: get | save
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
kefu, permissions, err = _auth(request, PERM_CFG)
|
||||
if err:
|
||||
return err
|
||||
action = (request.data.get('action') or 'get').strip().lower()
|
||||
if action == 'get':
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': admin_svc.build_config_payload(request)})
|
||||
if action == 'save':
|
||||
operator = getattr(getattr(request, 'user', None), 'UserUID', '') or ''
|
||||
data, msg = admin_svc.save_config(request, request.data, operator=operator)
|
||||
if msg:
|
||||
return Response({'code': 400, 'msg': msg})
|
||||
return Response({'code': 0, 'msg': '已保存', 'data': data})
|
||||
return Response({'code': 400, 'msg': '无效 action'})
|
||||
|
||||
|
||||
class FundFreezeLedgerView(APIView):
|
||||
"""
|
||||
POST /jituan/houtai/fund-freeze-ledger
|
||||
action: list | events | unfreeze
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
kefu, permissions, err = _auth(request, PERM_LED)
|
||||
if err:
|
||||
return err
|
||||
action = (request.data.get('action') or 'list').strip().lower()
|
||||
if action == 'list':
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': admin_svc.list_ledgers(request, request.data)})
|
||||
if action == 'events':
|
||||
from jituan.services.fund_freeze_admin import _club
|
||||
try:
|
||||
lid = int(request.data.get('ledger_id') or 0)
|
||||
except (TypeError, ValueError):
|
||||
return Response({'code': 400, 'msg': 'ledger_id 无效'})
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'ok',
|
||||
'data': {'list': admin_svc.list_unfreeze_events(lid, _club(request))},
|
||||
})
|
||||
if action == 'unfreeze':
|
||||
operator = getattr(getattr(request, 'user', None), 'UserUID', '') or ''
|
||||
data, msg = admin_svc.manual_unfreeze(request, request.data, operator=operator)
|
||||
if msg:
|
||||
return Response({'code': 400, 'msg': msg})
|
||||
return Response({'code': 0, 'msg': '解冻成功', 'data': data})
|
||||
return Response({'code': 400, 'msg': '无效 action'})
|
||||
|
||||
|
||||
class FundFreezeRiskView(APIView):
|
||||
"""
|
||||
POST /jituan/houtai/fund-freeze-risk
|
||||
action: list
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
kefu, permissions, err = _auth(request, PERM_RISK)
|
||||
if err:
|
||||
return err
|
||||
action = (request.data.get('action') or 'list').strip().lower()
|
||||
if action == 'list':
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': admin_svc.list_risk_users(request, request.data)})
|
||||
return Response({'code': 400, 'msg': '无效 action'})
|
||||
Reference in New Issue
Block a user