feat: 假单按俱乐部开关,并按商品类型会员资格展示

This commit is contained in:
XingQue
2026-07-30 19:55:19 +08:00
parent 6f4e458871
commit bb74140150
6 changed files with 128 additions and 15 deletions

View File

@@ -371,7 +371,8 @@ CELERY_TASK_QUEUES = {
# 订单超时自动结算Celery process_expired_order / check_order_expire_task总开关False=彻底关闭
ORDER_AUTO_SETTLEMENT_ENABLED = False
# 打手抢单大厅假单展示False=仅返回真实订单(后台假单管理仍可用;改 True 可恢复假单池)
FAKE_GRAB_ORDER_POOL_ENABLED = False
# 假单功能总闸(紧急关闭用)。实际是否对打手生效由各俱乐部 config_json.fake_grab_order_enabled 控制。
FAKE_GRAB_ORDER_POOL_ENABLED = True
ORDER_EXPIRE_SECONDS = 48 * 60 * 60 # 48小时 = 172800秒开关关闭时不生效
DAILY_TASK_HOUR = 0
DAILY_TASK_MINUTE = 30

View File

@@ -113,6 +113,7 @@ def build_fake_order_list_payload(request, leixing_id=None, page=1, page_size=20
'scope': resolve_club_scope(request),
'scope_error': CLUB_READ_SCOPE_MSG,
'leixing_options': build_leixing_options(),
'fake_grab_enabled': False,
**list_response_meta(request),
}
@@ -129,6 +130,8 @@ def build_fake_order_list_payload(request, leixing_id=None, page=1, page_size=20
rows = list(qs[offset:offset + page_size])
names = _leixing_name_map()
from jituan.services.fake_grab_switch import is_club_fake_grab_enabled
return {
'list': [_row_to_dict(r, names) for r in rows],
'total': total,
@@ -137,10 +140,35 @@ def build_fake_order_list_payload(request, leixing_id=None, page=1, page_size=20
'club_id': club_id,
'scope': resolve_club_scope(request),
'leixing_options': build_leixing_options(),
'fake_grab_enabled': is_club_fake_grab_enabled(club_id),
**list_response_meta(request),
}
def set_fake_grab_enabled(request, enabled):
"""开启/关闭本俱乐部打手侧假单功能。"""
if club_write_blocked(request):
return None, CLUB_WRITE_SCOPE_MSG
from jituan.models import Club
from jituan.services.fake_grab_switch import (
is_club_fake_grab_enabled,
set_club_fake_grab_enabled,
)
club_id = club_id_for_write(request)
club = Club.query.filter(club_id=club_id).first()
if not club:
return None, '俱乐部不存在'
set_club_fake_grab_enabled(club, bool(enabled))
club.save(update_fields=['config_json'])
return {
'club_id': club_id,
'fake_grab_enabled': is_club_fake_grab_enabled(club_id),
}, None
def _parse_decimal(value, field_name='金额'):
try:
val = Decimal(str(value))

View File

@@ -0,0 +1,36 @@
"""俱乐部级假单功能开关config_json.fake_grab_order_enabled"""
import logging
logger = logging.getLogger(__name__)
CONFIG_KEY = 'fake_grab_order_enabled'
def is_club_fake_grab_enabled(club_id: str) -> bool:
"""某俱乐部是否对打手侧开启假单池。默认关闭。"""
cid = (club_id or '').strip()
if not cid:
return False
try:
from django.conf import settings
if not getattr(settings, 'FAKE_GRAB_ORDER_POOL_ENABLED', True):
return False
except Exception:
pass
try:
from jituan.models import Club
club = Club.query.filter(club_id=cid).first()
if not club:
return False
cfg = club.config_json or {}
return bool(cfg.get(CONFIG_KEY))
except Exception:
logger.exception('read fake_grab_order_enabled failed club=%s', cid)
return False
def set_club_fake_grab_enabled(club, enabled: bool) -> None:
"""写入 club.config_json调用方负责 save。"""
cfg = dict(getattr(club, 'config_json', None) or {})
cfg[CONFIG_KEY] = bool(enabled)
club.config_json = cfg

View File

@@ -59,6 +59,7 @@ class FakeGrabOrderManageView(APIView):
from jituan.services.fake_grab_order_admin import (
create_fake_order,
delete_fake_order,
set_fake_grab_enabled,
update_fake_order,
)
@@ -82,6 +83,26 @@ class FakeGrabOrderManageView(APIView):
return Response({'code': 400, 'msg': err_msg})
return Response({'code': 0, 'msg': '已删除', 'data': data})
if action in ('set_enabled', 'enable', 'disable'):
if action == 'enable':
enabled = True
elif action == 'disable':
enabled = False
else:
raw = request.data.get('enabled', request.data.get('fake_grab_enabled'))
if isinstance(raw, str):
enabled = raw.strip().lower() in ('1', 'true', 'yes', 'on')
else:
enabled = bool(raw)
data, err_msg = set_fake_grab_enabled(request, enabled)
if err_msg:
return Response({'code': 400, 'msg': err_msg})
return Response({
'code': 0,
'msg': '假单功能已开启' if data.get('fake_grab_enabled') else '假单功能已关闭',
'data': data,
})
return Response({'code': 400, 'msg': '无效的 action'})

View File

@@ -1,7 +1,6 @@
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
"""抢单大厅假单:按俱乐部开关 + 按商品类型会员资格展示假数据。"""
import random
from datetime import datetime, timedelta
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
@@ -11,19 +10,41 @@ from rest_framework.response import Response
from backend.utils import fmt_datetime, pick_leixing_id
from jituan.services.club_context import resolve_effective_club_id
from jituan.services.dashou_exam import user_has_active_member
from jituan.services.fake_grab_switch import is_club_fake_grab_enabled
from jituan.services.huiyuan_bundle import normalize_huiyuan_id, user_has_huiyuan_access
from orders.models import FakeGrabOrder, FakeGrabOrderShuffleState
DEFAULT_DISPATCHER_AVATAR = 'beijing/morentouxiang.jpg'
SHUFFLE_STATE_PK = 1
def dashou_should_use_fake_pool(user):
def _leixing_required_huiyuan_id(leixing_id):
"""商品类型绑定的会员 ID无绑定则视为不要求会员。"""
if leixing_id is None:
return ''
try:
from products.models import ShangpinLeixing
row = ShangpinLeixing.query.filter(id=int(leixing_id)).values('huiyuan_id').first()
if not row:
return ''
return normalize_huiyuan_id(row.get('huiyuan_id'))
except Exception:
return ''
def dashou_should_use_fake_pool(user, club_id=None, leixing_id=None):
"""
打手是否只能看假单:
- 账号封禁zhanghaozhuangtai != 1
- 或未开通有效会员 且 押金不大于 5
当前 Tab商品类型是否只展示假单:
- 俱乐部未开启假单功能 → 否(看真实单
- 账号封禁 → 是
- 该类型要求的会员:已充(含总会员覆盖子类型)→ 否
- 未充对应会员 → 是
不同类型互不影响;假单在独立表,抢不了。
"""
cid = (club_id or '').strip()
if not cid or not is_club_fake_grab_enabled(cid):
return False
try:
dashou = user.DashouProfile
except ObjectDoesNotExist:
@@ -32,11 +53,16 @@ def dashou_should_use_fake_pool(user):
if dashou.zhanghaozhuangtai != 1:
return True
yajin = Decimal(str(dashou.yajin or 0))
if yajin > Decimal('5'):
if leixing_id is None:
# 未指定类型时不整池切假单,走真实单列表
return False
if user_has_active_member(user.UserUID):
required = _leixing_required_huiyuan_id(leixing_id)
if not required:
# 类型未绑会员 → 不推假单
return False
if user_has_huiyuan_access(user.UserUID, required, club_id=cid):
return False
return True

View File

@@ -97,14 +97,10 @@ class DashouDingdanHuoquView(APIView):
def post(self, request):
try:
from django.conf import settings
from orders.services.fake_order_pool import (
dashou_should_use_fake_pool,
build_fake_order_pool_response,
)
if getattr(settings, 'FAKE_GRAB_ORDER_POOL_ENABLED', False):
if dashou_should_use_fake_pool(request.user):
return build_fake_order_pool_response(request)
# 1. 获取请求参数
data = request.data
@@ -119,6 +115,11 @@ class DashouDingdanHuoquView(APIView):
resolve_grab_pool_member_display,
)
club_id = resolve_effective_club_id(request, getattr(request, 'user', None))
# 假单:按俱乐部开关 + 当前商品类型是否具备对应会员(含总会员覆盖)
if dashou_should_use_fake_pool(request.user, club_id=club_id, leixing_id=leixing_id):
return build_fake_order_pool_response(request)
yonghuid = request.user.UserUID
_has_member, user_clumber = refresh_grab_pool_membership_state(
yonghuid, club_id=club_id,