Files
Django/orders/services/fake_order_pool.py
2026-06-28 18:22:57 +08:00

167 lines
5.4 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.
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
import random
from datetime import timedelta
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.utils import timezone
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 orders.models import FakeGrabOrder, FakeGrabOrderShuffleState
DEFAULT_DISPATCHER_AVATAR = 'beijing/morentouxiang.jpg'
SHUFFLE_STATE_PK = 1
def dashou_should_use_fake_pool(user):
"""
打手是否只能看假单:
- 账号封禁zhanghaozhuangtai != 1
- 或未开通有效会员 且 押金不大于 5
"""
try:
dashou = user.DashouProfile
except ObjectDoesNotExist:
return True
if dashou.zhanghaozhuangtai != 1:
return True
yajin = Decimal(str(dashou.yajin or 0))
if yajin > Decimal('5'):
return False
if user_has_active_member(user.UserUID):
return False
return True
def _random_display_time_str():
"""返回给前端的创建时间:当前请求时刻 2~5 分钟前的随机时间。"""
seconds_ago = random.randint(120, 300)
dt = timezone.now() - timedelta(seconds=seconds_ago)
return fmt_datetime(dt)
def _resolve_shuffle_epoch():
"""
全用户共用一条打乱状态id=1
- 距上次打乱 >= IntervalSeconds更新 LastShuffleTime进入新打乱窗口
- 否则:沿用上次打乱时刻,本窗口内顺序不变
返回用于固定顺序的 epoch 时间戳;若应使用库表顺序则返回 None。
"""
now = timezone.now()
with transaction.atomic():
state, created = FakeGrabOrderShuffleState.objects.select_for_update().get_or_create(
pk=SHUFFLE_STATE_PK,
defaults={
'LastShuffleTime': now - timedelta(days=1),
'IntervalSeconds': 120,
},
)
interval = max(1, int(state.IntervalSeconds or 120))
elapsed = (now - state.LastShuffleTime).total_seconds()
if created or elapsed >= interval:
state.LastShuffleTime = now
state.save(update_fields=['LastShuffleTime', 'UpdateTime'])
return int(state.LastShuffleTime.timestamp())
return None
def _order_fake_rows(rows, shuffle_epoch):
"""shuffle_epoch 有值:按全局 epoch 固定打乱None按库表 SortOrder/CreateTime。"""
items = list(rows)
if shuffle_epoch is None:
items.sort(
key=lambda r: (
-(r.SortOrder or 0),
r.CreateTime or timezone.datetime.min.replace(tzinfo=timezone.utc),
r.id or 0,
),
)
return items
base = sorted(items, key=lambda r: (r.id or 0, r.OrderID or ''))
rng = random.Random(shuffle_epoch)
rng.shuffle(base)
return base
def _format_fake_row(row, display_time=None):
"""字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
# 平台单用 tupian、商家单用 tupian + sj_avatar统一默认头像
avatar = DEFAULT_DISPATCHER_AVATAR
platform = int(row.Platform or 1)
oid = row.OrderID
price = float(row.Amount or 0)
ct = display_time or _random_display_time_str()
zid = (row.DispatcherUserID or '').strip()
sj_name = (getattr(row, 'MerchantNickname', None) or '').strip()
return {
'dingdan_id': oid,
'zhuangtai': 1,
'pingtai': platform,
'dashou_fencheng': price,
'leixing_id': row.ProductTypeID or 0,
'tupian': avatar,
'yaoqiuleixing': 0,
'huiyuan_id': '',
'yajin': 0.0,
'jieshao': row.Description or '',
'beizhu': row.Remark or '',
'creat_time': ct,
'create_time': ct,
'sjnicheng': sj_name if platform == 2 else '',
'sj_avatar': avatar if platform == 2 else '',
'zhiding_uid': zid,
'zhiding_avatar': avatar,
'zhiding_nicheng': '',
'xuqiu_biaoqian': [],
'dashou_biaoqian': [],
'shangjia_biaoqian': [],
'shangjia_identity_biaoqian': [],
'zhiding_identity_biaoqian': [],
'shangjia_youzhi': bool(row.IsPremiumMerchant) if platform == 2 else False,
}
def build_fake_order_pool_response(request):
data = request.data
leixing_id = pick_leixing_id(data)
page = max(1, int(data.get('page', 1)))
page_size = max(1, min(int(data.get('page_size', 10)), 50))
club_id = resolve_effective_club_id(request, getattr(request, 'user', None))
qs = FakeGrabOrder.query.filter(ClubID=club_id)
if leixing_id is not None:
qs = qs.filter(ProductTypeID=leixing_id)
shuffle_epoch = _resolve_shuffle_epoch()
rows = _order_fake_rows(qs, shuffle_epoch)
total = len(rows)
offset = (page - 1) * page_size
page_rows = rows[offset:offset + page_size]
formatted_list = [_format_fake_row(r) for r in page_rows]
has_more = (page * page_size) < total
return Response({
'code': 200,
'msg': '获取成功',
'data': {
'list': formatted_list,
'has_more': has_more,
'total': total,
'current_page': page,
'page_size': page_size,
'total_pages': (total + page_size - 1) // page_size if page_size else 0,
},
})