|
|
@@ -579,6 +579,10 @@ vo.setIsSelf(viewerMember != null && viewerMember.getId().equals(fm.getId()));
|
|
|
if (targetUserId != null) {
|
|
|
User targetUser = userMapper.selectById(targetUserId);
|
|
|
if (targetUser != null && oldFamilyId.equals(targetUser.getFamilyId())) {
|
|
|
+ // FIX S-cfc-179:被踢用户离开原家庭前,先按个人维度重算家庭派生会员缓存
|
|
|
+ // (仅清除 FAMILY/BASIC/PREMIUM 家庭派生等级,保留 LIFETIME/PROVIDER 独立身份),
|
|
|
+ // 与下方唯一的 userMapper.updateById 一并持久化,保证主流程只产生一次用户更新
|
|
|
+ resetStaleFamilyDerivedMemberCache(targetUser);
|
|
|
boolean isWechatUser = isWechatUser(targetUser);
|
|
|
if (isWechatUser) {
|
|
|
// 微信用户:迁移资产到初始家庭,CF 带走
|
|
|
@@ -681,6 +685,10 @@ vo.setIsSelf(viewerMember != null && viewerMember.getId().equals(fm.getId()));
|
|
|
member.setStatus("active");
|
|
|
familyMemberMapper.updateById(member);
|
|
|
|
|
|
+ // FIX S-cfc-179:退出用户离开原家庭前,先按个人维度重算家庭派生会员缓存
|
|
|
+ // (仅清除 FAMILY/BASIC/PREMIUM 家庭派生等级,保留 LIFETIME/PROVIDER 独立身份),
|
|
|
+ // 与下方唯一的 userMapper.updateById 一并持久化,保证主流程只产生一次用户更新
|
|
|
+ resetStaleFamilyDerivedMemberCache(user);
|
|
|
user.setFamilyId(ownFamilyId);
|
|
|
user.setUpdatedAt(new Date());
|
|
|
userMapper.updateById(user);
|
|
|
@@ -710,6 +718,36 @@ vo.setIsSelf(viewerMember != null && viewerMember.getId().equals(fm.getId()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * FIX S-cfc-179:被移出家庭的用户按「个人维度」重算会员缓存(纯内存变更,不落库)。
|
|
|
+ *
|
|
|
+ * <p>仅清除源自家庭会员的缓存(等级 + 到期时间)——家庭可授予等级(FAMILY/BASIC/PREMIUM,
|
|
|
+ * 由 {@code syncMembershipToFamilyMembers} 同步给全家、只升不降)在被移出家庭后若无独立更高等级
|
|
|
+ * 应恢复 FREE;更高等级独立个人会员(LIFETIME)与独立角色(PROVIDER)保留,不被误清。</p>
|
|
|
+ *
|
|
|
+ * <p>注意:此方法<b>不</b>调用 {@code userMapper.updateById}——调用方在既有的一次 {@code updateById}
|
|
|
+ * 中一并持久化(保证 kick/leave 主流程只产生一次用户更新,契约单测以 {@code verify(times(1))} 锁定)。</p>
|
|
|
+ *
|
|
|
+ * <p>不依赖 {@code MembershipService}(避免 mock 场景下默认值干扰),直接按等级代码判定,
|
|
|
+ * 与 {@code MembershipService.getMemberLevel} 的语义一致(结果契约由契约单测锁定)。</p>
|
|
|
+ *
|
|
|
+ * @param targetUser 被移出家庭的用户(调用方随后会 updateById 持久化)
|
|
|
+ */
|
|
|
+ private void resetStaleFamilyDerivedMemberCache(User targetUser) {
|
|
|
+ if (targetUser == null || targetUser.getMemberLevel() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String level = targetUser.getMemberLevel();
|
|
|
+ // 家庭可授予等级(家庭会员同步来源):被移出后无独立更高等级 → 恢复 FREE,并清空到期时间
|
|
|
+ // LIFETIME(个人终身权益)/ PROVIDER(独立服务商角色)为独立身份,保留不清
|
|
|
+ if ("FAMILY".equals(level) || "BASIC".equals(level) || "PREMIUM".equals(level)) {
|
|
|
+ targetUser.setMemberLevel("FREE");
|
|
|
+ targetUser.setMemberExpireTime(null);
|
|
|
+ targetUser.setUpdatedAt(new Date());
|
|
|
+ log.info("被移出家庭成员会员缓存已重置为 FREE: userId={}, fromLevel={}", targetUser.getId(), level);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 从回收箱回收成员(管理员操作):将回收箱中的非微信用户重新加入指定家庭
|
|
|
*/
|