252 lines
9.1 KiB
Python
252 lines
9.1 KiB
Python
"""后台赠送会员(免费接单):与购买会员 Huiyuangoumai 分离。"""
|
||
from datetime import datetime, time
|
||
|
||
from django.db import transaction
|
||
from django.utils import timezone
|
||
from django.utils.dateparse import parse_datetime, parse_date
|
||
|
||
from products.models import Huiyuan
|
||
from users.models import DashouZengsongHuiyuan, UserDashou
|
||
|
||
GIFT_HUIYUAN_PERMS = frozenset({
|
||
'000001', '001aa', '001bb', '001cc', '001dd', '001ee',
|
||
})
|
||
TARGET_JIFEN_ON_GIFT = 10
|
||
|
||
|
||
def has_gift_huiyuan_permission(permissions):
|
||
return any(p in (permissions or []) for p in GIFT_HUIYUAN_PERMS)
|
||
|
||
|
||
def _gift_record_active(record, now=None):
|
||
if not record or not record.daoqi_time:
|
||
return False
|
||
from jituan.services.huiyuan_bundle import _normalize_datetime_for_compare
|
||
now = _normalize_datetime_for_compare(now or timezone.now())
|
||
daoqi = _normalize_datetime_for_compare(record.daoqi_time)
|
||
return daoqi > now
|
||
|
||
|
||
def user_has_any_active_gift_huiyuan(yonghu_id):
|
||
"""是否持有任意一条未过期的赠送会员(提现/收款资格用)。"""
|
||
if not yonghu_id:
|
||
return False
|
||
now = timezone.now()
|
||
for rec in DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id):
|
||
if _gift_record_active(rec, now=now):
|
||
return True
|
||
return False
|
||
|
||
|
||
def parse_gift_daoqi_time(raw):
|
||
"""
|
||
解析到期时间。
|
||
支持:'YYYY-MM-DD HH:MM:SS' / ISO / 'YYYY-MM-DD'(当天 23:59:59)。
|
||
"""
|
||
if raw is None or str(raw).strip() == '':
|
||
return None, '请填写到期时间'
|
||
text = str(raw).strip()
|
||
dt = parse_datetime(text.replace('/', '-'))
|
||
if dt is None:
|
||
d = parse_date(text.replace('/', '-'))
|
||
if d is None:
|
||
try:
|
||
dt = datetime.strptime(text, '%Y-%m-%d %H:%M:%S')
|
||
except ValueError:
|
||
try:
|
||
d = datetime.strptime(text, '%Y-%m-%d').date()
|
||
except ValueError:
|
||
return None, '到期时间格式错误,请用 YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS'
|
||
dt = datetime.combine(d, time(23, 59, 59))
|
||
else:
|
||
dt = datetime.combine(d, time(23, 59, 59))
|
||
if timezone.is_naive(dt) and timezone.is_aware(timezone.now()):
|
||
dt = timezone.make_aware(dt, timezone.get_current_timezone())
|
||
elif (not timezone.is_naive(dt)) and (not timezone.is_aware(timezone.now())):
|
||
dt = timezone.make_naive(dt, timezone.get_current_timezone())
|
||
if dt <= timezone.now():
|
||
return None, '到期时间必须晚于当前时间'
|
||
return dt, None
|
||
|
||
|
||
def list_gift_huiyuan_for_admin(yonghu_id):
|
||
"""后台详情:全部赠送记录(含已过期),附会员名。"""
|
||
records = list(
|
||
DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id).order_by('-daoqi_time')
|
||
)
|
||
if not records:
|
||
return []
|
||
name_map = {
|
||
h.huiyuan_id: h.jieshao
|
||
for h in Huiyuan.query.filter(
|
||
huiyuan_id__in=[r.huiyuan_id for r in records]
|
||
).only('huiyuan_id', 'jieshao')
|
||
}
|
||
now = timezone.now()
|
||
out = []
|
||
for r in records:
|
||
active = _gift_record_active(r, now=now)
|
||
out.append({
|
||
'id': r.id,
|
||
'huiyuan_id': r.huiyuan_id,
|
||
'huiyuan_name': name_map.get(r.huiyuan_id, f'会员{r.huiyuan_id}'),
|
||
'daoqi_time': r.daoqi_time.strftime('%Y-%m-%d %H:%M:%S') if r.daoqi_time else '',
|
||
'song_ren': r.song_ren or '',
|
||
'song_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
|
||
'is_active': active,
|
||
})
|
||
return out
|
||
|
||
|
||
def user_has_gift_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
||
"""抢单资格:赠送会员是否覆盖所需会员类型(支持总会员展开)。"""
|
||
from jituan.services.huiyuan_bundle import (
|
||
huiyuan_ids_match,
|
||
is_bundle_huiyuan,
|
||
normalize_huiyuan_id,
|
||
resolve_bundle_included_ids,
|
||
_included_huiyuan_id_set,
|
||
)
|
||
|
||
req = normalize_huiyuan_id(required_huiyuan_id)
|
||
if not req:
|
||
return True
|
||
req_set = {req, req.lstrip('0') or '0'}
|
||
now = timezone.now()
|
||
for rec in DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id):
|
||
if not _gift_record_active(rec, now=now):
|
||
continue
|
||
if huiyuan_ids_match(rec.huiyuan_id, req):
|
||
return True
|
||
if is_bundle_huiyuan(rec.huiyuan_id):
|
||
included = resolve_bundle_included_ids(
|
||
rec.huiyuan_id,
|
||
club_id=club_id,
|
||
yonghu_id=yonghu_id,
|
||
)
|
||
if req_set & _included_huiyuan_id_set(included):
|
||
return True
|
||
return False
|
||
|
||
|
||
def build_gift_clumber_items(yonghu_id, club_id=None):
|
||
"""抢单池 clumber:未过期赠送会员条目。"""
|
||
from jituan.services.huiyuan_bundle import (
|
||
_append_bundle_sub_clumber,
|
||
_append_clumber_id_variants,
|
||
format_legacy_daoqi,
|
||
is_bundle_huiyuan,
|
||
resolve_bundle_included_ids,
|
||
_resolve_user_club_id,
|
||
)
|
||
|
||
items = []
|
||
seen = set()
|
||
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||
now = timezone.now()
|
||
for rec in DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id):
|
||
if not _gift_record_active(rec, now=now):
|
||
continue
|
||
try:
|
||
hy = Huiyuan.query.get(huiyuan_id=rec.huiyuan_id)
|
||
ming = hy.jieshao or f'会员{rec.huiyuan_id}'
|
||
except Huiyuan.DoesNotExist:
|
||
ming = f'会员{rec.huiyuan_id}'
|
||
base = {
|
||
'huiyuanming': ming,
|
||
'daoqi': format_legacy_daoqi(rec.daoqi_time),
|
||
'huiyuan_zhuangtai': 1,
|
||
'shifou_daoqi': False,
|
||
'is_gift': True,
|
||
}
|
||
if is_bundle_huiyuan(rec.huiyuan_id):
|
||
base['is_bundle'] = True
|
||
base['bundle_huiyuan_id'] = rec.huiyuan_id
|
||
base['included_huiyuan_ids'] = resolve_bundle_included_ids(
|
||
rec.huiyuan_id,
|
||
club_id=effective_club,
|
||
yonghu_id=yonghu_id,
|
||
)
|
||
_append_clumber_id_variants(items, seen, base, rec.huiyuan_id)
|
||
_append_bundle_sub_clumber(items, seen, base)
|
||
return items
|
||
|
||
|
||
def upsert_gift_huiyuan(*, yonghu_id, huiyuan_id, daoqi_time, song_ren):
|
||
"""
|
||
赠送或改期。同一打手同一会员类型仅一条记录。
|
||
返回 (record, created, jifen_changed_info_or_None, error_msg)
|
||
jifen_changed_info = {'before': x, 'after': 10} 若调整了积分
|
||
"""
|
||
huiyuan_id = str(huiyuan_id or '').strip()
|
||
if not huiyuan_id:
|
||
return None, False, None, '缺少会员ID'
|
||
if not Huiyuan.query.filter(huiyuan_id=huiyuan_id).exists():
|
||
return None, False, None, '会员类型不存在'
|
||
|
||
jifen_info = None
|
||
with transaction.atomic():
|
||
try:
|
||
dashou = UserDashou.objects.select_for_update().select_related('user').get(
|
||
user__UserUID=yonghu_id
|
||
)
|
||
except UserDashou.DoesNotExist:
|
||
return None, False, None, '打手不存在'
|
||
|
||
before_jifen = int(dashou.jifen or 0)
|
||
if before_jifen != TARGET_JIFEN_ON_GIFT:
|
||
dashou.jifen = TARGET_JIFEN_ON_GIFT
|
||
dashou.save(update_fields=['jifen'])
|
||
jifen_info = {'before': before_jifen, 'after': TARGET_JIFEN_ON_GIFT}
|
||
|
||
locked_qs = DashouZengsongHuiyuan.objects.select_for_update().filter(
|
||
yonghu_id=yonghu_id, huiyuan_id=huiyuan_id
|
||
)
|
||
existing = locked_qs.first()
|
||
if existing:
|
||
existing.daoqi_time = daoqi_time
|
||
existing.song_ren = song_ren
|
||
existing.save(update_fields=['daoqi_time', 'song_ren', 'UpdateTime'])
|
||
return existing, False, jifen_info, None
|
||
|
||
record = DashouZengsongHuiyuan.query.create(
|
||
yonghu_id=yonghu_id,
|
||
huiyuan_id=huiyuan_id,
|
||
daoqi_time=daoqi_time,
|
||
song_ren=song_ren,
|
||
)
|
||
return record, True, jifen_info, None
|
||
|
||
|
||
def update_gift_huiyuan_daoqi(*, record_id, yonghu_id, daoqi_time, song_ren):
|
||
"""按记录 ID 改期。"""
|
||
try:
|
||
rec = DashouZengsongHuiyuan.query.get(id=record_id)
|
||
except DashouZengsongHuiyuan.DoesNotExist:
|
||
return None, '赠送会员记录不存在'
|
||
if str(rec.yonghu_id) != str(yonghu_id):
|
||
return None, '记录与打手不匹配'
|
||
rec.daoqi_time = daoqi_time
|
||
if song_ren:
|
||
rec.song_ren = song_ren
|
||
rec.save(update_fields=['daoqi_time', 'song_ren', 'UpdateTime'])
|
||
return rec, None
|
||
|
||
|
||
def remove_gift_huiyuan(*, record_id=None, yonghu_id=None, huiyuan_id=None):
|
||
"""按记录 ID,或 (yonghu_id, huiyuan_id) 移除。"""
|
||
qs = DashouZengsongHuiyuan.query
|
||
if record_id:
|
||
deleted, _ = qs.filter(id=record_id).delete()
|
||
if not deleted:
|
||
return False, '赠送会员记录不存在'
|
||
return True, None
|
||
yonghu_id = str(yonghu_id or '').strip()
|
||
huiyuan_id = str(huiyuan_id or '').strip()
|
||
if not yonghu_id or not huiyuan_id:
|
||
return False, '缺少记录ID或会员ID'
|
||
deleted, _ = qs.filter(yonghu_id=yonghu_id, huiyuan_id=huiyuan_id).delete()
|
||
if not deleted:
|
||
return False, '赠送会员记录不存在'
|
||
return True, None
|