From c2db2ad5831ece6b36474786a0c67f3c752e37e8 Mon Sep 17 00:00:00 2001 From: XingQue Date: Wed, 8 Jul 2026 22:13:12 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=80=BB=E4=BC=9A=E5=91=98=E5=8F=AA?= =?UTF-8?q?=E8=AF=BB=E5=B1=95=E5=BC=80=E5=AD=90=E4=BC=9A=E5=91=98=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E4=BF=AE=E5=A4=8Dclub=5Fid=E9=BB=98=E8=AE=A4?= =?UTF-8?q?xq=E6=9F=A5=E9=94=99=E9=85=8D=E7=BD=AE=EF=BC=9Bdddhq=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E5=86=99=E5=BA=93=E8=A1=A5=E4=BC=9A=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- jituan/services/huiyuan_bundle.py | 122 ++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 33 deletions(-) diff --git a/jituan/services/huiyuan_bundle.py b/jituan/services/huiyuan_bundle.py index e8aa34c..8f74eac 100644 --- a/jituan/services/huiyuan_bundle.py +++ b/jituan/services/huiyuan_bundle.py @@ -79,6 +79,57 @@ def get_bundle_included_ids(club_id, bundle_huiyuan_id): ) +def _membership_club_candidates(yonghu_id, club_id=None, record_club_id=None): + """ + 会员/总会员子类型解析用的俱乐部候选(有序)。 + Huiyuangoumai/Czjilu.club_id 历史上默认 xq,星之界用户落库为 xq 时不能盲信。 + """ + from jituan.constants import CLUB_ID_DEFAULT + + record_cid = (record_club_id or '').strip() + request_cid = (club_id or '').strip() + user_cid = _resolve_user_club_id(yonghu_id, club_id=club_id) + + candidates = [] + + def add(cid): + c = (cid or '').strip() + if c and c not in candidates: + candidates.append(c) + + if record_cid and record_cid != CLUB_ID_DEFAULT: + add(record_cid) + add(request_cid) + add(user_cid) + if record_cid: + add(record_cid) + add(CLUB_ID_DEFAULT) + return candidates + + +def resolve_bundle_included_ids(bundle_huiyuan_id, club_id=None, yonghu_id=None, record_club_id=None): + """按候选俱乐部解析总会员包含的子会员(只读,首个非空配置即返回)。""" + if not bundle_huiyuan_id: + return [] + for cid in _membership_club_candidates( + yonghu_id, club_id=club_id, record_club_id=record_club_id, + ): + ids = get_bundle_included_ids(cid, bundle_huiyuan_id) + if ids: + return list(ids) + return [] + + +def _included_huiyuan_id_set(included_ids): + included_set = set() + for x in included_ids or []: + sx = normalize_huiyuan_id(x) + if sx: + included_set.add(sx) + included_set.add(sx.lstrip('0') or '0') + return included_set + + def _resolve_user_club_id(yonghu_id, club_id=None): """解析用户所属俱乐部(体验/正式同一套;总会员子类型依赖此值)。""" from jituan.constants import CLUB_ID_DEFAULT @@ -96,10 +147,15 @@ def _resolve_user_club_id(yonghu_id, club_id=None): 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) + candidates = _membership_club_candidates( + getattr(record, 'yonghu_id', ''), + club_id=club_id, + record_club_id=getattr(record, 'club_id', None), + ) + if candidates: + return candidates[0] + from jituan.constants import CLUB_ID_DEFAULT + return CLUB_ID_DEFAULT def is_bundle_huiyuan(huiyuan_id): @@ -141,19 +197,16 @@ def user_has_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None): ) if bundle_ids: 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): if not _record_valid(rec): continue - cid = _record_club_id(rec, club_id) or effective_club - included = get_bundle_included_ids(cid, rec.huiyuan_id) - 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: + included = resolve_bundle_included_ids( + rec.huiyuan_id, + club_id=club_id, + yonghu_id=yonghu_id, + record_club_id=rec.club_id, + ) + if req_set & _included_huiyuan_id_set(included): return True if _czjilu_grants_huiyuan_access(yonghu_id, req, club_id): @@ -193,14 +246,13 @@ def _czjilu_grants_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None): if huiyuan_ids_match(hid, req): 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: + included = resolve_bundle_included_ids( + hid, + club_id=club_id, + yonghu_id=yonghu_id, + record_club_id=getattr(order, 'club_id', None), + ) + if req_set & _included_huiyuan_id_set(included): return True return False @@ -282,7 +334,6 @@ def resolve_grab_pool_member_display(order_dict, yonghu_id, club_id=None, user_c def enrich_clumber_item(record, club_id=None): """老端 clumber:体验会员与正式会员返回格式完全一致(不暴露 is_trial)。""" daoqi_str = format_legacy_daoqi(record.daoqi_time) - cid = _record_club_id(record, club_id) item = { 'huiyuanid': record.huiyuan_id, 'huiyuan_id': record.huiyuan_id, @@ -294,7 +345,12 @@ def enrich_clumber_item(record, club_id=None): if is_bundle_huiyuan(record.huiyuan_id): item['is_bundle'] = True item['bundle_huiyuan_id'] = record.huiyuan_id - item['included_huiyuan_ids'] = get_bundle_included_ids(cid, record.huiyuan_id) + item['included_huiyuan_ids'] = resolve_bundle_included_ids( + record.huiyuan_id, + club_id=club_id, + yonghu_id=record.yonghu_id, + record_club_id=record.club_id, + ) return item @@ -410,7 +466,12 @@ def _build_clumber_from_paid_czjilu(yonghu_id, club_id=None): if is_bundle_huiyuan(hid): base['is_bundle'] = True base['bundle_huiyuan_id'] = hid - base['included_huiyuan_ids'] = get_bundle_included_ids(cid, hid) + base['included_huiyuan_ids'] = resolve_bundle_included_ids( + hid, + club_id=club_id, + yonghu_id=yonghu_id, + record_club_id=getattr(order, 'club_id', None), + ) _append_clumber_id_variants(items, seen, base, hid) _append_bundle_sub_clumber(items, seen, base) return items @@ -429,15 +490,10 @@ def _finalize_clumber_for_legacy_client(items): def ensure_grab_pool_clumber(yonghu_id, club_id=None): """ dddhq / dashouxinxi:只读 huiyuangoumai + 有效期内充值单 生成 clumber(体验=正式)。 - 不写库、不全量 sync;仅在无任何会员时尝试补最近已付单(防回调丢失)。 + 总会员展开子会员虚拟条目供老端 clumber 比对;不写库、不补开通。 """ - from jituan.services.member_recharge import repair_recent_paid_entitlements_if_missing - effective_club = _resolve_user_club_id(yonghu_id, club_id) items = _build_user_clumber_core(yonghu_id, club_id=effective_club) - if not items: - repair_recent_paid_entitlements_if_missing(yonghu_id, limit=3) - items = _build_user_clumber_core(yonghu_id, club_id=effective_club) items = _merge_clumber_extra_items( items, _build_clumber_from_paid_czjilu(yonghu_id, club_id=effective_club), @@ -448,8 +504,8 @@ def ensure_grab_pool_clumber(yonghu_id, club_id=None): def refresh_grab_pool_membership_state(yonghu_id, club_id=None): """ - 抢单池/打手资料:请求入口统一刷新会员状态(同步权益 + clumber)。 - 供 /dingdan/ddhq、/yonghu/dashouxinxi、登录 clumber 调用。 + 抢单池/打手资料:只读生成 clumber(含总会员子类型展开)。 + 供 /dingdan/ddhq、/yonghu/dashouxinxi、登录 clumber 调用;禁止写库补会员。 """ return ensure_grab_pool_clumber(yonghu_id, club_id=club_id)