fix: 迁移子会员时长按总会员有效覆盖累加,避免少加天数
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -593,8 +593,74 @@ def _find_user_huiyuangoumai(uid: str, huiyuan_id: str, *, for_update: bool = Fa
|
|||||||
return qs.first()
|
return qs.first()
|
||||||
|
|
||||||
|
|
||||||
|
def _latest_effective_cover_until(uid: str, huiyuan_id: str, club_id: str, *, goumai_row=None):
|
||||||
|
"""
|
||||||
|
目标店对该会员类型的有效覆盖到期:
|
||||||
|
- 自己开通的该子会员/总会员未到期
|
||||||
|
- 或任意未到期总会员包含该子会员
|
||||||
|
用于迁移累加:总会员覆盖剩 10 天 + 迁入同子会员 10 天 → 子会员落到 20 天。
|
||||||
|
"""
|
||||||
|
from jituan.services.huiyuan_bundle import (
|
||||||
|
_included_huiyuan_id_set,
|
||||||
|
_membership_record_active,
|
||||||
|
expand_huiyuan_id_variants,
|
||||||
|
huiyuan_ids_match,
|
||||||
|
is_bundle_huiyuan,
|
||||||
|
normalize_huiyuan_id,
|
||||||
|
resolve_bundle_included_ids,
|
||||||
|
)
|
||||||
|
from products.models import Huiyuangoumai
|
||||||
|
|
||||||
|
now = _now_aware()
|
||||||
|
hid = normalize_huiyuan_id(huiyuan_id)
|
||||||
|
if not hid:
|
||||||
|
return None
|
||||||
|
req_set = {hid, hid.lstrip('0') or '0'}
|
||||||
|
for vid in expand_huiyuan_id_variants(hid):
|
||||||
|
req_set.add(vid)
|
||||||
|
req_set.add(vid.lstrip('0') or '0')
|
||||||
|
|
||||||
|
latest = None
|
||||||
|
|
||||||
|
def bump(dt):
|
||||||
|
nonlocal latest
|
||||||
|
exp = _aware(dt)
|
||||||
|
if not exp or exp <= now:
|
||||||
|
return
|
||||||
|
if latest is None or exp > latest:
|
||||||
|
latest = exp
|
||||||
|
|
||||||
|
row = goumai_row
|
||||||
|
if row is None:
|
||||||
|
row = _find_user_huiyuangoumai(uid, hid)
|
||||||
|
if row is not None and int(row.huiyuan_zhuangtai or 0) == 1:
|
||||||
|
bump(row.daoqi_time)
|
||||||
|
|
||||||
|
for rec in Huiyuangoumai.query.filter(yonghu_id=str(uid)):
|
||||||
|
if not _membership_record_active(rec):
|
||||||
|
continue
|
||||||
|
if huiyuan_ids_match(rec.huiyuan_id, hid):
|
||||||
|
bump(rec.daoqi_time)
|
||||||
|
continue
|
||||||
|
if not is_bundle_huiyuan(rec.huiyuan_id):
|
||||||
|
continue
|
||||||
|
included = resolve_bundle_included_ids(
|
||||||
|
rec.huiyuan_id,
|
||||||
|
club_id=club_id,
|
||||||
|
yonghu_id=uid,
|
||||||
|
record_club_id=getattr(rec, 'club_id', None),
|
||||||
|
)
|
||||||
|
if req_set & _included_huiyuan_id_set(included):
|
||||||
|
bump(rec.daoqi_time)
|
||||||
|
return latest
|
||||||
|
|
||||||
|
|
||||||
def _add_huiyuan_duration(*, to_uid: str, to_club: str, huiyuan_id: str, remain, jieshao: str, is_trial: bool, has_used_trial: bool):
|
def _add_huiyuan_duration(*, to_uid: str, to_club: str, huiyuan_id: str, remain, jieshao: str, is_trial: bool, has_used_trial: bool):
|
||||||
"""给目标用户对应会员加时长(已有则累加剩余,否则从现在起算)。"""
|
"""给目标用户对应会员加时长。
|
||||||
|
|
||||||
|
累加基数 = max(现在, 该会员自身到期, 覆盖它的总会员到期)。
|
||||||
|
避免:目标已有总会员覆盖子会员 10 天,迁入同子会员 10 天却只得到约 10 天(应为 20)。
|
||||||
|
"""
|
||||||
from products.models import Huiyuangoumai
|
from products.models import Huiyuangoumai
|
||||||
|
|
||||||
now = _now_aware()
|
now = _now_aware()
|
||||||
@@ -611,9 +677,12 @@ def _add_huiyuan_duration(*, to_uid: str, to_club: str, huiyuan_id: str, remain,
|
|||||||
'zhuangtai': dst.huiyuan_zhuangtai,
|
'zhuangtai': dst.huiyuan_zhuangtai,
|
||||||
'club_id': dst.club_id,
|
'club_id': dst.club_id,
|
||||||
}
|
}
|
||||||
dst_exp = _aware(dst.daoqi_time)
|
|
||||||
base = dst_exp if (dst_exp and dst_exp > now and int(dst.huiyuan_zhuangtai or 0) == 1) else now
|
cover = _latest_effective_cover_until(to_uid, hid, to_club, goumai_row=dst)
|
||||||
exp = base + remain
|
base = cover if (cover and cover > now) else now
|
||||||
|
exp = base + remain
|
||||||
|
|
||||||
|
if dst:
|
||||||
dst.daoqi_time = exp
|
dst.daoqi_time = exp
|
||||||
dst.huiyuan_zhuangtai = 1
|
dst.huiyuan_zhuangtai = 1
|
||||||
dst.club_id = to_club
|
dst.club_id = to_club
|
||||||
@@ -622,7 +691,6 @@ def _add_huiyuan_duration(*, to_uid: str, to_club: str, huiyuan_id: str, remain,
|
|||||||
dst.save(update_fields=['daoqi_time', 'huiyuan_zhuangtai', 'club_id', 'jieshao', 'UpdateTime'])
|
dst.save(update_fields=['daoqi_time', 'huiyuan_zhuangtai', 'club_id', 'jieshao', 'UpdateTime'])
|
||||||
return exp, before_dst
|
return exp, before_dst
|
||||||
|
|
||||||
exp = now + remain
|
|
||||||
try:
|
try:
|
||||||
Huiyuangoumai.query.create(
|
Huiyuangoumai.query.create(
|
||||||
huiyuan_id=hid,
|
huiyuan_id=hid,
|
||||||
@@ -644,9 +712,9 @@ def _add_huiyuan_duration(*, to_uid: str, to_club: str, huiyuan_id: str, remain,
|
|||||||
'zhuangtai': dst2.huiyuan_zhuangtai,
|
'zhuangtai': dst2.huiyuan_zhuangtai,
|
||||||
'club_id': dst2.club_id,
|
'club_id': dst2.club_id,
|
||||||
}
|
}
|
||||||
dst_exp = _aware(dst2.daoqi_time)
|
cover2 = _latest_effective_cover_until(to_uid, hid, to_club, goumai_row=dst2)
|
||||||
base = dst_exp if (dst_exp and dst_exp > now and int(dst2.huiyuan_zhuangtai or 0) == 1) else now
|
base2 = cover2 if (cover2 and cover2 > now) else now
|
||||||
exp = base + remain
|
exp = base2 + remain
|
||||||
dst2.daoqi_time = exp
|
dst2.daoqi_time = exp
|
||||||
dst2.huiyuan_zhuangtai = 1
|
dst2.huiyuan_zhuangtai = 1
|
||||||
dst2.club_id = to_club
|
dst2.club_id = to_club
|
||||||
|
|||||||
Reference in New Issue
Block a user