fix: 体验会员抢单池与正式同等展示,修复总会员子类型与club_id
clumber 传递 club_id 展开总会员子类型;充值单路径同步;不暴露 is_trial。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -79,6 +79,29 @@ def get_bundle_included_ids(club_id, bundle_huiyuan_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_user_club_id(yonghu_id, club_id=None):
|
||||||
|
"""解析用户所属俱乐部(体验/正式同一套;总会员子类型依赖此值)。"""
|
||||||
|
from jituan.constants import CLUB_ID_DEFAULT
|
||||||
|
from jituan.services.club_user import get_user_club_id
|
||||||
|
|
||||||
|
cid = (club_id or '').strip()
|
||||||
|
if cid:
|
||||||
|
return cid
|
||||||
|
try:
|
||||||
|
from users.business_models import User
|
||||||
|
user = User.query.filter(UserUID=yonghu_id).first()
|
||||||
|
return get_user_club_id(user) or CLUB_ID_DEFAULT
|
||||||
|
except Exception:
|
||||||
|
return CLUB_ID_DEFAULT
|
||||||
|
|
||||||
|
|
||||||
|
def _record_club_id(record, club_id=None):
|
||||||
|
cid = (getattr(record, 'club_id', None) or '').strip()
|
||||||
|
if cid:
|
||||||
|
return cid
|
||||||
|
return _resolve_user_club_id(getattr(record, 'yonghu_id', ''), club_id=club_id)
|
||||||
|
|
||||||
|
|
||||||
def is_bundle_huiyuan(huiyuan_id):
|
def is_bundle_huiyuan(huiyuan_id):
|
||||||
try:
|
try:
|
||||||
return bool(Huiyuan.query.get(huiyuan_id=huiyuan_id).is_bundle)
|
return bool(Huiyuan.query.get(huiyuan_id=huiyuan_id).is_bundle)
|
||||||
@@ -118,10 +141,11 @@ def user_has_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
|||||||
)
|
)
|
||||||
if bundle_ids:
|
if bundle_ids:
|
||||||
req_set = {req, req.lstrip('0') or '0'}
|
req_set = {req, req.lstrip('0') or '0'}
|
||||||
|
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||||||
for rec in Huiyuangoumai.query.filter(yonghu_id=yonghu_id, huiyuan_id__in=bundle_ids):
|
for rec in Huiyuangoumai.query.filter(yonghu_id=yonghu_id, huiyuan_id__in=bundle_ids):
|
||||||
if not _record_valid(rec):
|
if not _record_valid(rec):
|
||||||
continue
|
continue
|
||||||
cid = club_id or rec.club_id or ''
|
cid = _record_club_id(rec, club_id) or effective_club
|
||||||
included = get_bundle_included_ids(cid, rec.huiyuan_id)
|
included = get_bundle_included_ids(cid, rec.huiyuan_id)
|
||||||
included_set = set()
|
included_set = set()
|
||||||
for x in included:
|
for x in included:
|
||||||
@@ -138,21 +162,21 @@ def user_has_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
|||||||
|
|
||||||
|
|
||||||
def _czjilu_grants_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
def _czjilu_grants_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
||||||
"""已支付会员充值单(含体验)在有效期内,视同已开通。"""
|
"""已支付会员充值单(含体验)在有效期内,视同已开通;总会员含子类型。"""
|
||||||
from jituan.constants import CLUB_ID_DEFAULT
|
from jituan.constants import CLUB_ID_DEFAULT
|
||||||
from jituan.services.member_recharge import (
|
from jituan.services.member_recharge import (
|
||||||
MEMBER_LEIXING,
|
MEMBER_LEIXING,
|
||||||
MEMBER_PAID_STATUS,
|
MEMBER_PAID_STATUS,
|
||||||
_order_is_trial_like,
|
|
||||||
_czjilu_entitlement_revoked,
|
_czjilu_entitlement_revoked,
|
||||||
club_huiyuan_sellable,
|
czjilu_entitlement_active,
|
||||||
)
|
)
|
||||||
from products.models import Czjilu
|
from products.models import Czjilu
|
||||||
|
|
||||||
req = normalize_huiyuan_id(required_huiyuan_id)
|
req = normalize_huiyuan_id(required_huiyuan_id)
|
||||||
if not req:
|
if not req:
|
||||||
return False
|
return False
|
||||||
now = _normalize_datetime_for_compare(timezone.now())
|
req_set = {req, req.lstrip('0') or '0'}
|
||||||
|
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||||||
for order in Czjilu.query.filter(
|
for order in Czjilu.query.filter(
|
||||||
yonghuid=yonghu_id,
|
yonghuid=yonghu_id,
|
||||||
leixing=MEMBER_LEIXING,
|
leixing=MEMBER_LEIXING,
|
||||||
@@ -160,17 +184,24 @@ def _czjilu_grants_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
|
|||||||
).order_by('-CreateTime')[:30]:
|
).order_by('-CreateTime')[:30]:
|
||||||
if _czjilu_entitlement_revoked(order):
|
if _czjilu_entitlement_revoked(order):
|
||||||
continue
|
continue
|
||||||
if not huiyuan_ids_match(order.huiyuan_id, req):
|
cid = getattr(order, 'club_id', None) or club_id or effective_club or CLUB_ID_DEFAULT
|
||||||
|
if not czjilu_entitlement_active(order, cid):
|
||||||
continue
|
continue
|
||||||
cid = getattr(order, 'club_id', None) or club_id or CLUB_ID_DEFAULT
|
hid = normalize_huiyuan_id(order.huiyuan_id)
|
||||||
is_trial = _order_is_trial_like(order, cid)
|
if not hid:
|
||||||
days = int(getattr(order, 'purchase_days', None) or 0)
|
continue
|
||||||
if days <= 0:
|
if huiyuan_ids_match(hid, req):
|
||||||
_, _, days = club_huiyuan_sellable(cid, order.huiyuan_id, is_trial=is_trial)
|
|
||||||
days = max(int(days or 0), 1)
|
|
||||||
start = _normalize_datetime_for_compare(order.CreateTime or now)
|
|
||||||
if start + timedelta(days=days) > now:
|
|
||||||
return True
|
return True
|
||||||
|
if is_bundle_huiyuan(hid):
|
||||||
|
included = get_bundle_included_ids(cid, hid)
|
||||||
|
included_set = set()
|
||||||
|
for x in included:
|
||||||
|
sx = normalize_huiyuan_id(x)
|
||||||
|
if sx:
|
||||||
|
included_set.add(sx)
|
||||||
|
included_set.add(sx.lstrip('0') or '0')
|
||||||
|
if req_set & included_set:
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -248,9 +279,10 @@ def resolve_grab_pool_member_display(order_dict, yonghu_id, club_id=None, user_c
|
|||||||
return 1, membership_id or '', has_valid
|
return 1, membership_id or '', has_valid
|
||||||
|
|
||||||
|
|
||||||
def enrich_clumber_item(record):
|
def enrich_clumber_item(record, club_id=None):
|
||||||
"""老端 clumber:有效期内体验会员与正式会员返回格式完全一致。"""
|
"""老端 clumber:体验会员与正式会员返回格式完全一致(不暴露 is_trial)。"""
|
||||||
daoqi_str = format_legacy_daoqi(record.daoqi_time)
|
daoqi_str = format_legacy_daoqi(record.daoqi_time)
|
||||||
|
cid = _record_club_id(record, club_id)
|
||||||
item = {
|
item = {
|
||||||
'huiyuanid': record.huiyuan_id,
|
'huiyuanid': record.huiyuan_id,
|
||||||
'huiyuan_id': record.huiyuan_id,
|
'huiyuan_id': record.huiyuan_id,
|
||||||
@@ -261,9 +293,8 @@ def enrich_clumber_item(record):
|
|||||||
}
|
}
|
||||||
if is_bundle_huiyuan(record.huiyuan_id):
|
if is_bundle_huiyuan(record.huiyuan_id):
|
||||||
item['is_bundle'] = True
|
item['is_bundle'] = True
|
||||||
item['included_huiyuan_ids'] = get_bundle_included_ids(
|
item['bundle_huiyuan_id'] = record.huiyuan_id
|
||||||
record.club_id or '', record.huiyuan_id,
|
item['included_huiyuan_ids'] = get_bundle_included_ids(cid, record.huiyuan_id)
|
||||||
)
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
@@ -280,11 +311,16 @@ def _append_clumber_id_variants(items, seen, base_item, huiyuan_id):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _append_bundle_sub_clumber(items, seen, record, base_item):
|
def _append_bundle_sub_clumber(items, seen, base_item):
|
||||||
"""总会员有效时,为抢单页展开子会员虚拟条目。"""
|
"""总会员有效时,为抢单页展开子会员虚拟条目(体验=正式)。"""
|
||||||
if not base_item.get('is_bundle'):
|
if not base_item.get('is_bundle'):
|
||||||
return
|
return
|
||||||
bundle_hid = str(record.huiyuan_id)
|
bundle_hid = str(
|
||||||
|
base_item.get('bundle_huiyuan_id')
|
||||||
|
or base_item.get('huiyuanid')
|
||||||
|
or base_item.get('huiyuan_id')
|
||||||
|
or '',
|
||||||
|
)
|
||||||
for sub_id in base_item.get('included_huiyuan_ids') or []:
|
for sub_id in base_item.get('included_huiyuan_ids') or []:
|
||||||
sid = str(sub_id).strip()
|
sid = str(sub_id).strip()
|
||||||
if not sid:
|
if not sid:
|
||||||
@@ -299,15 +335,17 @@ def _append_bundle_sub_clumber(items, seen, record, base_item):
|
|||||||
_append_clumber_id_variants(items, seen, sub_base, sid)
|
_append_clumber_id_variants(items, seen, sub_base, sid)
|
||||||
|
|
||||||
|
|
||||||
def _build_user_clumber_core(yonghu_id):
|
def _build_user_clumber_core(yonghu_id, club_id=None):
|
||||||
|
"""huiyuangoumai 未过期会员 → clumber(体验与正式完全同等,不读 is_trial)。"""
|
||||||
items = []
|
items = []
|
||||||
seen = set()
|
seen = set()
|
||||||
|
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||||||
for record in Huiyuangoumai.query.filter(yonghu_id=yonghu_id):
|
for record in Huiyuangoumai.query.filter(yonghu_id=yonghu_id):
|
||||||
if not _membership_record_active(record):
|
if not _membership_record_active(record):
|
||||||
continue
|
continue
|
||||||
base = enrich_clumber_item(record)
|
base = enrich_clumber_item(record, club_id=effective_club)
|
||||||
_append_clumber_id_variants(items, seen, base, record.huiyuan_id)
|
_append_clumber_id_variants(items, seen, base, record.huiyuan_id)
|
||||||
_append_bundle_sub_clumber(items, seen, record, base)
|
_append_bundle_sub_clumber(items, seen, base)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
@@ -332,17 +370,20 @@ def _merge_clumber_extra_items(items, extra):
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def _build_clumber_from_paid_czjilu(yonghu_id):
|
def _build_clumber_from_paid_czjilu(yonghu_id, club_id=None):
|
||||||
"""只读:huiyuangoumai 缺失时,用已支付会员充值单合成 clumber(体验=正式,不写库)。"""
|
"""只读:有效期内充值单合成 clumber(体验=正式,不写库);总会员展开子类型。"""
|
||||||
|
from jituan.constants import CLUB_ID_DEFAULT
|
||||||
from jituan.services.member_recharge import (
|
from jituan.services.member_recharge import (
|
||||||
MEMBER_LEIXING,
|
MEMBER_LEIXING,
|
||||||
MEMBER_PAID_STATUS,
|
MEMBER_PAID_STATUS,
|
||||||
czjilu_entitlement_active,
|
czjilu_entitlement_active,
|
||||||
|
_czjilu_entitlement_end,
|
||||||
)
|
)
|
||||||
from products.models import Czjilu, Huiyuan
|
from products.models import Czjilu, Huiyuan
|
||||||
|
|
||||||
items = []
|
items = []
|
||||||
seen = set()
|
seen = set()
|
||||||
|
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||||||
for order in Czjilu.query.filter(
|
for order in Czjilu.query.filter(
|
||||||
yonghuid=yonghu_id,
|
yonghuid=yonghu_id,
|
||||||
leixing=MEMBER_LEIXING,
|
leixing=MEMBER_LEIXING,
|
||||||
@@ -351,7 +392,7 @@ def _build_clumber_from_paid_czjilu(yonghu_id):
|
|||||||
hid = normalize_huiyuan_id(order.huiyuan_id)
|
hid = normalize_huiyuan_id(order.huiyuan_id)
|
||||||
if not hid:
|
if not hid:
|
||||||
continue
|
continue
|
||||||
cid = getattr(order, 'club_id', None) or ''
|
cid = getattr(order, 'club_id', None) or effective_club or CLUB_ID_DEFAULT
|
||||||
if not czjilu_entitlement_active(order, cid):
|
if not czjilu_entitlement_active(order, cid):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
@@ -359,7 +400,6 @@ def _build_clumber_from_paid_czjilu(yonghu_id):
|
|||||||
ming = hy.jieshao or f'会员{hid}'
|
ming = hy.jieshao or f'会员{hid}'
|
||||||
except Huiyuan.DoesNotExist:
|
except Huiyuan.DoesNotExist:
|
||||||
ming = f'会员{hid}'
|
ming = f'会员{hid}'
|
||||||
from jituan.services.member_recharge import _czjilu_entitlement_end
|
|
||||||
daoqi = _czjilu_entitlement_end(order, cid)
|
daoqi = _czjilu_entitlement_end(order, cid)
|
||||||
base = {
|
base = {
|
||||||
'huiyuanming': ming,
|
'huiyuanming': ming,
|
||||||
@@ -367,10 +407,25 @@ def _build_clumber_from_paid_czjilu(yonghu_id):
|
|||||||
'huiyuan_zhuangtai': 1,
|
'huiyuan_zhuangtai': 1,
|
||||||
'shifou_daoqi': False,
|
'shifou_daoqi': False,
|
||||||
}
|
}
|
||||||
|
if is_bundle_huiyuan(hid):
|
||||||
|
base['is_bundle'] = True
|
||||||
|
base['bundle_huiyuan_id'] = hid
|
||||||
|
base['included_huiyuan_ids'] = get_bundle_included_ids(cid, hid)
|
||||||
_append_clumber_id_variants(items, seen, base, hid)
|
_append_clumber_id_variants(items, seen, base, hid)
|
||||||
|
_append_bundle_sub_clumber(items, seen, base)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def _finalize_clumber_for_legacy_client(items):
|
||||||
|
"""老端只认 huiyuanid;去掉 is_trial 等内部字段。"""
|
||||||
|
cleaned = []
|
||||||
|
for it in items or []:
|
||||||
|
row = dict(it)
|
||||||
|
row.pop('is_trial', None)
|
||||||
|
cleaned.append(row)
|
||||||
|
return cleaned
|
||||||
|
|
||||||
|
|
||||||
def ensure_grab_pool_clumber(yonghu_id, club_id=None):
|
def ensure_grab_pool_clumber(yonghu_id, club_id=None):
|
||||||
"""
|
"""
|
||||||
dddhq / dashouxinxi:只读 huiyuangoumai + 有效期内充值单 生成 clumber(体验=正式)。
|
dddhq / dashouxinxi:只读 huiyuangoumai + 有效期内充值单 生成 clumber(体验=正式)。
|
||||||
@@ -378,11 +433,16 @@ def ensure_grab_pool_clumber(yonghu_id, club_id=None):
|
|||||||
"""
|
"""
|
||||||
from jituan.services.member_recharge import repair_recent_paid_entitlements_if_missing
|
from jituan.services.member_recharge import repair_recent_paid_entitlements_if_missing
|
||||||
|
|
||||||
items = _build_user_clumber_core(yonghu_id)
|
effective_club = _resolve_user_club_id(yonghu_id, club_id)
|
||||||
|
items = _build_user_clumber_core(yonghu_id, club_id=effective_club)
|
||||||
if not items:
|
if not items:
|
||||||
repair_recent_paid_entitlements_if_missing(yonghu_id, limit=3)
|
repair_recent_paid_entitlements_if_missing(yonghu_id, limit=3)
|
||||||
items = _build_user_clumber_core(yonghu_id)
|
items = _build_user_clumber_core(yonghu_id, club_id=effective_club)
|
||||||
items = _merge_clumber_extra_items(items, _build_clumber_from_paid_czjilu(yonghu_id))
|
items = _merge_clumber_extra_items(
|
||||||
|
items,
|
||||||
|
_build_clumber_from_paid_czjilu(yonghu_id, club_id=effective_club),
|
||||||
|
)
|
||||||
|
items = _finalize_clumber_for_legacy_client(items)
|
||||||
return bool(items), items
|
return bool(items), items
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user