统一 clumber 返回 huiyuanid 并展开总会员子类型;抢单池接口对已具备会员权限的用户将 yaoqiuleixing 置 0,使小程序无需发版即可正常显示分佣并抢单。 Co-authored-by: Cursor <cursoragent@cursor.com>
185 lines
6.2 KiB
Python
185 lines
6.2 KiB
Python
"""总会员(包含式会员):购买一个会员,可接多个子会员类型订单。"""
|
||
from products.models import Huiyuan, Huiyuangoumai
|
||
|
||
|
||
def get_bundle_included_ids(club_id, bundle_huiyuan_id):
|
||
from jituan.models import ClubHuiyuanBundleInclude
|
||
|
||
if not club_id or not bundle_huiyuan_id:
|
||
return []
|
||
return list(
|
||
ClubHuiyuanBundleInclude.query.filter(
|
||
club_id=club_id,
|
||
bundle_huiyuan_id=bundle_huiyuan_id,
|
||
).values_list('included_huiyuan_id', flat=True)
|
||
)
|
||
|
||
|
||
def is_bundle_huiyuan(huiyuan_id):
|
||
try:
|
||
return bool(Huiyuan.query.get(huiyuan_id=huiyuan_id).is_bundle)
|
||
except Huiyuan.DoesNotExist:
|
||
return False
|
||
|
||
|
||
def user_has_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
||
"""用户是否可接要求 required_huiyuan_id 的会员单(含总会员覆盖)。"""
|
||
if not required_huiyuan_id:
|
||
return True
|
||
|
||
req = str(required_huiyuan_id).strip()
|
||
|
||
def _record_valid(rec):
|
||
return (
|
||
rec
|
||
and not rec.jiance_shifou_daoqi()
|
||
and rec.huiyuan_zhuangtai == 1
|
||
)
|
||
|
||
try:
|
||
direct = Huiyuangoumai.query.get(yonghu_id=yonghu_id, huiyuan_id=req)
|
||
if _record_valid(direct):
|
||
return True
|
||
except Huiyuangoumai.DoesNotExist:
|
||
pass
|
||
|
||
bundle_ids = set(
|
||
Huiyuan.query.filter(is_bundle=True).values_list('huiyuan_id', flat=True)
|
||
)
|
||
if not bundle_ids:
|
||
return False
|
||
|
||
for rec in Huiyuangoumai.query.filter(yonghu_id=yonghu_id, huiyuan_id__in=bundle_ids):
|
||
if not _record_valid(rec):
|
||
continue
|
||
cid = club_id or rec.club_id or ''
|
||
included = get_bundle_included_ids(cid, rec.huiyuan_id)
|
||
if req in {str(x) for x in included}:
|
||
return True
|
||
return False
|
||
|
||
|
||
def enrich_clumber_item(record):
|
||
"""为 clumber 条目附加总会员覆盖的子会员 ID 列表(旧端忽略该字段)。"""
|
||
item = {
|
||
'huiyuanid': record.huiyuan_id,
|
||
'huiyuan_id': record.huiyuan_id,
|
||
'huiyuanming': record.jieshao or f'会员{record.huiyuan_id}',
|
||
'daoqi': record.daoqi_time,
|
||
'is_trial': bool(getattr(record, 'is_trial', False)),
|
||
}
|
||
if is_bundle_huiyuan(record.huiyuan_id):
|
||
item['is_bundle'] = True
|
||
item['included_huiyuan_ids'] = get_bundle_included_ids(
|
||
record.club_id or '', record.huiyuan_id,
|
||
)
|
||
return item
|
||
|
||
|
||
def _append_bundle_sub_clumber(items, seen, record, base_item):
|
||
"""总会员有效时,为抢单页展开子会员虚拟条目。"""
|
||
if not base_item.get('is_bundle'):
|
||
return
|
||
bundle_hid = str(record.huiyuan_id)
|
||
for sub_id in base_item.get('included_huiyuan_ids') or []:
|
||
sid = str(sub_id).strip()
|
||
if not sid or sid in seen:
|
||
continue
|
||
seen.add(sid)
|
||
items.append({
|
||
'huiyuanid': sid,
|
||
'huiyuan_id': sid,
|
||
'huiyuanming': base_item.get('huiyuanming', ''),
|
||
'daoqi': base_item.get('daoqi'),
|
||
'from_bundle': bundle_hid,
|
||
'is_trial': bool(getattr(record, 'is_trial', False)),
|
||
})
|
||
|
||
|
||
def build_user_clumber(yonghu_id):
|
||
"""
|
||
构建抢单页可用的 clumber 列表。
|
||
- 仅包含未过期且状态有效的会员(含体验会员)
|
||
- 总会员自动展开所覆盖的子会员 ID
|
||
- 同时返回 huiyuanid / huiyuan_id,兼容小程序各页面字段名
|
||
"""
|
||
items = []
|
||
seen = set()
|
||
for record in Huiyuangoumai.query.filter(yonghu_id=yonghu_id):
|
||
if record.jiance_shifou_daoqi():
|
||
continue
|
||
if record.huiyuan_zhuangtai != 1:
|
||
continue
|
||
base = enrich_clumber_item(record)
|
||
hid = str(record.huiyuan_id)
|
||
if hid not in seen:
|
||
seen.add(hid)
|
||
items.append(base)
|
||
_append_bundle_sub_clumber(items, seen, record, base)
|
||
return items
|
||
|
||
|
||
def build_auth_clumber(yonghu_id):
|
||
"""登录/注册返回的 clumber:保留状态字段,并补齐抢单页所需的 huiyuanid。"""
|
||
items = []
|
||
seen = set()
|
||
for record in Huiyuangoumai.query.filter(yonghu_id=yonghu_id):
|
||
shifou_daoqi = record.jiance_shifou_daoqi()
|
||
base = enrich_clumber_item(record)
|
||
base.update({
|
||
'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
|
||
'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
|
||
'shifou_daoqi': shifou_daoqi,
|
||
'jieshao': record.jieshao,
|
||
})
|
||
hid = str(record.huiyuan_id)
|
||
if hid not in seen:
|
||
seen.add(hid)
|
||
items.append(base)
|
||
if not shifou_daoqi and record.huiyuan_zhuangtai == 1:
|
||
_append_bundle_sub_clumber(items, seen, record, base)
|
||
return items
|
||
|
||
|
||
def save_bundle_includes(club_id, bundle_huiyuan_id, included_ids):
|
||
"""保存俱乐部总会员包含的子会员(须为本俱乐部已上架的普通会员)。"""
|
||
from jituan.models import ClubHuiyuanBundleInclude, ClubHuiyuanPrice
|
||
|
||
if not is_bundle_huiyuan(bundle_huiyuan_id):
|
||
return None, '该会员不是总会员类型'
|
||
|
||
enabled = set(
|
||
ClubHuiyuanPrice.query.filter(club_id=club_id, is_enabled=True).values_list(
|
||
'huiyuan_id', flat=True,
|
||
)
|
||
)
|
||
bundle_ids = set(
|
||
Huiyuan.query.filter(is_bundle=True).values_list('huiyuan_id', flat=True)
|
||
)
|
||
cleaned = []
|
||
for hid in included_ids or []:
|
||
hid = str(hid).strip()
|
||
if not hid or hid == bundle_huiyuan_id:
|
||
continue
|
||
if hid not in enabled:
|
||
return None, f'子会员 {hid} 未在本俱乐部上架'
|
||
if hid in bundle_ids:
|
||
return None, '总会员不能包含另一个总会员'
|
||
if not Huiyuan.query.filter(huiyuan_id=hid).exists():
|
||
return None, f'子会员 {hid} 不存在'
|
||
cleaned.append(hid)
|
||
|
||
if not cleaned:
|
||
return None, '请至少选择一个包含的子会员'
|
||
|
||
ClubHuiyuanBundleInclude.query.filter(
|
||
club_id=club_id, bundle_huiyuan_id=bundle_huiyuan_id,
|
||
).delete()
|
||
for hid in cleaned:
|
||
ClubHuiyuanBundleInclude.query.create(
|
||
club_id=club_id,
|
||
bundle_huiyuan_id=bundle_huiyuan_id,
|
||
included_huiyuan_id=hid,
|
||
)
|
||
return {'included_huiyuan_ids': cleaned}, None
|