|
|
@@ -0,0 +1,292 @@
|
|
|
+package shop.alien.store.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+import shop.alien.entity.store.*;
|
|
|
+import shop.alien.entity.store.dto.AccountLogoutCompleteRequestDTO;
|
|
|
+import shop.alien.entity.store.vo.AccountLogoutCompleteResultVo;
|
|
|
+import shop.alien.mapper.*;
|
|
|
+import shop.alien.store.service.AccountLogoutCompleteService;
|
|
|
+import shop.alien.store.service.NearMeService;
|
|
|
+import shop.alien.store.service.StoreLogoutSyncService;
|
|
|
+import shop.alien.util.common.AccountLogoutUtil;
|
|
|
+import shop.alien.util.common.constant.CouponStatusEnum;
|
|
|
+import shop.alien.util.common.constant.DiscountCouponEnum;
|
|
|
+
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class AccountLogoutCompleteServiceImpl implements AccountLogoutCompleteService {
|
|
|
+
|
|
|
+ private static final String LOGOUT_DISPLAY_NAME = "已注销";
|
|
|
+
|
|
|
+ private final StoreUserMapper storeUserMapper;
|
|
|
+ private final StoreInfoMapper storeInfoMapper;
|
|
|
+ private final LifeUserMapper lifeUserMapper;
|
|
|
+ private final LawyerUserMapper lawyerUserMapper;
|
|
|
+ private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
|
|
|
+ private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
|
|
|
+ private final LifeCouponMapper lifeCouponMapper;
|
|
|
+ private final NearMeService nearMeService;
|
|
|
+ private final StoreLogoutSyncService storeLogoutSyncService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public AccountLogoutCompleteResultVo completeCoolingPeriod(boolean force) {
|
|
|
+ AccountLogoutCompleteRequestDTO request = new AccountLogoutCompleteRequestDTO();
|
|
|
+ request.setAccountType("ALL");
|
|
|
+ request.setForce(force);
|
|
|
+ return completeCoolingPeriod(request);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public AccountLogoutCompleteResultVo completeCoolingPeriod(AccountLogoutCompleteRequestDTO request) {
|
|
|
+ boolean force = request == null || request.getForce() == null || Boolean.TRUE.equals(request.getForce());
|
|
|
+ String accountType = normalizeAccountType(request != null ? request.getAccountType() : null);
|
|
|
+ Integer id = request != null ? request.getId() : null;
|
|
|
+ String phone = request != null ? request.getPhone() : null;
|
|
|
+
|
|
|
+ AccountLogoutCompleteResultVo result = new AccountLogoutCompleteResultVo();
|
|
|
+ if ("ALL".equals(accountType) || "STORE_USER".equals(accountType)) {
|
|
|
+ completeStoreUsers(force, id, phone, result);
|
|
|
+ }
|
|
|
+ // 仅兼容历史独立店铺注销数据;新流程随商家用户一并注销
|
|
|
+ if ("STORE".equals(accountType)) {
|
|
|
+ completeLegacyStores(force, id, result);
|
|
|
+ }
|
|
|
+ if ("ALL".equals(accountType) || "LIFE_USER".equals(accountType)) {
|
|
|
+ completeLifeUsers(force, id, phone, result);
|
|
|
+ }
|
|
|
+ if ("ALL".equals(accountType) || "LAWYER".equals(accountType)) {
|
|
|
+ completeLawyerUsers(force, id, phone, result);
|
|
|
+ }
|
|
|
+ log.info("注销冷静期完成处理: force={}, type={}, success={}, fail={}, skipped={}",
|
|
|
+ force, accountType, result.getSuccessCount(), result.getFailCount(), result.getSkippedCount());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void completeStoreUsers(boolean force, Integer id, String phone, AccountLogoutCompleteResultVo result) {
|
|
|
+ LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<StoreUser>()
|
|
|
+ .and(w -> w.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_COOLING)
|
|
|
+ .or(o -> o.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE)
|
|
|
+ .eq(StoreUser::getStatus, -1)));
|
|
|
+ if (id != null) {
|
|
|
+ wrapper.eq(StoreUser::getId, id);
|
|
|
+ }
|
|
|
+ if (StringUtils.hasText(phone)) {
|
|
|
+ wrapper.eq(StoreUser::getPhone, phone);
|
|
|
+ }
|
|
|
+ for (StoreUser storeUser : storeUserMapper.selectList(wrapper)) {
|
|
|
+ try {
|
|
|
+ if (storeUser.getLogoutTime() == null) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("STORE_USER#" + storeUser.getId() + " 跳过:无 logoutTime");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!force && !AccountLogoutUtil.isLogoutCoolingExpired(storeUser.getLogoutTime())) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("STORE_USER#" + storeUser.getId() + " 跳过:未满7天冷静期");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ storeUser.setLogoutFlag(StoreUser.LOGOUT_FLAG_DONE);
|
|
|
+ storeUser.setName(LOGOUT_DISPLAY_NAME);
|
|
|
+ storeUser.setNickName(LOGOUT_DISPLAY_NAME);
|
|
|
+ storeUser.setHeadImg(null);
|
|
|
+ if (Integer.valueOf(-1).equals(storeUser.getStatus())) {
|
|
|
+ storeUser.setStatus(0);
|
|
|
+ }
|
|
|
+ storeUserMapper.updateById(storeUser);
|
|
|
+ storeLogoutSyncService.completeLogoutForStoreUser(storeUser, result);
|
|
|
+ result.setSuccessCount(result.getSuccessCount() + 1);
|
|
|
+ result.addDetail("STORE_USER#" + storeUser.getId() + " 已注销");
|
|
|
+ } catch (Exception e) {
|
|
|
+ result.setFailCount(result.getFailCount() + 1);
|
|
|
+ result.addDetail("STORE_USER#" + storeUser.getId() + " 失败:" + e.getMessage());
|
|
|
+ log.error("商家账号注销完成失败 userId={}", storeUser.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 处理历史独立店铺注销数据(新流程已合并至商家用户注销) */
|
|
|
+ private void completeLegacyStores(boolean force, Integer storeId, AccountLogoutCompleteResultVo result) {
|
|
|
+ LambdaQueryWrapper<StoreInfo> wrapper = new LambdaQueryWrapper<StoreInfo>()
|
|
|
+ .and(w -> w.eq(StoreInfo::getLogoutFlag, StoreInfo.LOGOUT_FLAG_COOLING)
|
|
|
+ .or(o -> o.eq(StoreInfo::getLogoutFlag, StoreInfo.LOGOUT_FLAG_DONE)
|
|
|
+ .eq(StoreInfo::getStoreStatus, -1)));
|
|
|
+ if (storeId != null) {
|
|
|
+ wrapper.eq(StoreInfo::getId, storeId);
|
|
|
+ }
|
|
|
+ for (StoreInfo storeInfo : storeInfoMapper.selectList(wrapper)) {
|
|
|
+ try {
|
|
|
+ if (storeInfo.getLogoutTime() == null) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("STORE#" + storeInfo.getId() + " 跳过:无 logoutTime");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!force && !AccountLogoutUtil.isLogoutCoolingExpired(storeInfo.getLogoutTime())) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("STORE#" + storeInfo.getId() + " 跳过:未满7天冷静期");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (StoreInfo.LOGOUT_FLAG_DONE == storeInfo.getLogoutFlag()
|
|
|
+ && StoreInfo.BUSINESS_STATUS_PERMANENT_CLOSE == storeInfo.getBusinessStatus()) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("STORE#" + storeInfo.getId() + " 跳过:已是已注销状态");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ invalidateStoreCoupons(storeInfo.getId());
|
|
|
+ try {
|
|
|
+ nearMeService.removeGeolocation(Boolean.TRUE, storeInfo.getId().toString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("清理Redis地理位置失败 storeId={}", storeInfo.getId(), e);
|
|
|
+ }
|
|
|
+ storeInfoMapper.update(null, new LambdaUpdateWrapper<StoreInfo>()
|
|
|
+ .eq(StoreInfo::getId, storeInfo.getId())
|
|
|
+ .set(StoreInfo::getLogoutFlag, StoreInfo.LOGOUT_FLAG_DONE)
|
|
|
+ .set(StoreInfo::getStoreStatus, 2)
|
|
|
+ .set(StoreInfo::getBusinessStatus, StoreInfo.BUSINESS_STATUS_PERMANENT_CLOSE)
|
|
|
+ .set(StoreInfo::getStoreName, LOGOUT_DISPLAY_NAME));
|
|
|
+ result.setSuccessCount(result.getSuccessCount() + 1);
|
|
|
+ result.addDetail("STORE#" + storeInfo.getId() + " 已注销");
|
|
|
+ } catch (Exception e) {
|
|
|
+ result.setFailCount(result.getFailCount() + 1);
|
|
|
+ result.addDetail("STORE#" + storeInfo.getId() + " 失败:" + e.getMessage());
|
|
|
+ log.error("店铺注销完成失败 storeId={}", storeInfo.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void completeLifeUsers(boolean force, Integer id, String phone, AccountLogoutCompleteResultVo result) {
|
|
|
+ LambdaQueryWrapper<LifeUser> wrapper = new LambdaQueryWrapper<LifeUser>()
|
|
|
+ .eq(LifeUser::getLogoutFlag, LifeUser.LOGOUT_FLAG_COOLING);
|
|
|
+ if (id != null) {
|
|
|
+ wrapper.eq(LifeUser::getId, id);
|
|
|
+ }
|
|
|
+ if (StringUtils.hasText(phone)) {
|
|
|
+ wrapper.eq(LifeUser::getUserPhone, phone);
|
|
|
+ }
|
|
|
+ for (LifeUser lifeUser : lifeUserMapper.selectList(wrapper)) {
|
|
|
+ try {
|
|
|
+ if (lifeUser.getLogoutTime() == null) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("LIFE_USER#" + lifeUser.getId() + " 跳过:无 logoutTime");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!force && !AccountLogoutUtil.isLogoutCoolingExpired(lifeUser.getLogoutTime())) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("LIFE_USER#" + lifeUser.getId() + " 跳过:未满7天冷静期");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lifeUserMapper.update(null, new LambdaUpdateWrapper<LifeUser>()
|
|
|
+ .eq(LifeUser::getId, lifeUser.getId())
|
|
|
+ .set(LifeUser::getLogoutFlag, LifeUser.LOGOUT_FLAG_DONE)
|
|
|
+ .set(LifeUser::getUserName, LOGOUT_DISPLAY_NAME)
|
|
|
+ .set(LifeUser::getUserImage, null));
|
|
|
+ result.setSuccessCount(result.getSuccessCount() + 1);
|
|
|
+ result.addDetail("LIFE_USER#" + lifeUser.getId() + " 已注销");
|
|
|
+ } catch (Exception e) {
|
|
|
+ result.setFailCount(result.getFailCount() + 1);
|
|
|
+ result.addDetail("LIFE_USER#" + lifeUser.getId() + " 失败:" + e.getMessage());
|
|
|
+ log.error("C端用户注销完成失败 userId={}", lifeUser.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void completeLawyerUsers(boolean force, Integer id, String phone, AccountLogoutCompleteResultVo result) {
|
|
|
+ LambdaQueryWrapper<LawyerUser> wrapper = new LambdaQueryWrapper<LawyerUser>()
|
|
|
+ .eq(LawyerUser::getLogoutFlag, LawyerUser.LOGOUT_FLAG_COOLING)
|
|
|
+ .eq(LawyerUser::getDeleteFlag, 0);
|
|
|
+ if (id != null) {
|
|
|
+ wrapper.eq(LawyerUser::getId, id);
|
|
|
+ }
|
|
|
+ if (StringUtils.hasText(phone)) {
|
|
|
+ wrapper.eq(LawyerUser::getPhone, phone);
|
|
|
+ }
|
|
|
+ for (LawyerUser lawyerUser : lawyerUserMapper.selectList(wrapper)) {
|
|
|
+ try {
|
|
|
+ if (lawyerUser.getLogoutTime() == null) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("LAWYER#" + lawyerUser.getId() + " 跳过:无 logoutTime");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!force && !AccountLogoutUtil.isLogoutCoolingExpired(lawyerUser.getLogoutTime())) {
|
|
|
+ result.setSkippedCount(result.getSkippedCount() + 1);
|
|
|
+ result.addDetail("LAWYER#" + lawyerUser.getId() + " 跳过:未满7天冷静期");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ lawyerUserMapper.update(null, new LambdaUpdateWrapper<LawyerUser>()
|
|
|
+ .eq(LawyerUser::getId, lawyerUser.getId())
|
|
|
+ .set(LawyerUser::getLogoutFlag, LawyerUser.LOGOUT_FLAG_DONE)
|
|
|
+ .set(LawyerUser::getName, LOGOUT_DISPLAY_NAME)
|
|
|
+ .set(LawyerUser::getNickName, LOGOUT_DISPLAY_NAME)
|
|
|
+ .set(LawyerUser::getHeadImg, null)
|
|
|
+ .set(LawyerUser::getOrderReceivingStatus, 0)
|
|
|
+ .set(LawyerUser::getIsOnline, 0)
|
|
|
+ .set(LawyerUser::getIsRecommended, 0)
|
|
|
+ .set(LawyerUser::getLastOnlineTime, new Date()));
|
|
|
+ result.setSuccessCount(result.getSuccessCount() + 1);
|
|
|
+ result.addDetail("LAWYER#" + lawyerUser.getId() + " 已注销");
|
|
|
+ } catch (Exception e) {
|
|
|
+ result.setFailCount(result.getFailCount() + 1);
|
|
|
+ result.addDetail("LAWYER#" + lawyerUser.getId() + " 失败:" + e.getMessage());
|
|
|
+ log.error("律师注销完成失败 lawyerId={}", lawyerUser.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void invalidateStoreCoupons(Integer storeId) {
|
|
|
+ if (storeId == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String storeIdStr = String.valueOf(storeId);
|
|
|
+ int voidedUserCouponStatus = Integer.parseInt(DiscountCouponEnum.HAVE_BEEN_VOIDED.getValue());
|
|
|
+
|
|
|
+ lifeDiscountCouponMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCoupon>()
|
|
|
+ .eq(LifeDiscountCoupon::getStoreId, storeIdStr)
|
|
|
+ .set(LifeDiscountCoupon::getCouponStatus, LifeDiscountCoupon.COUPON_STATUS_INVALID)
|
|
|
+ .set(LifeDiscountCoupon::getGetStatus, 0));
|
|
|
+
|
|
|
+ List<LifeDiscountCoupon> storeCoupons = lifeDiscountCouponMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<LifeDiscountCoupon>().eq(LifeDiscountCoupon::getStoreId, storeIdStr));
|
|
|
+ if (!storeCoupons.isEmpty()) {
|
|
|
+ List<Integer> couponIds = storeCoupons.stream().map(LifeDiscountCoupon::getId).collect(Collectors.toList());
|
|
|
+ lifeDiscountCouponUserMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCouponUser>()
|
|
|
+ .in(LifeDiscountCouponUser::getCouponId, couponIds)
|
|
|
+ .eq(LifeDiscountCouponUser::getStatus, Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()))
|
|
|
+ .set(LifeDiscountCouponUser::getStatus, voidedUserCouponStatus));
|
|
|
+ }
|
|
|
+
|
|
|
+ lifeCouponMapper.update(null, new LambdaUpdateWrapper<LifeCoupon>()
|
|
|
+ .eq(LifeCoupon::getStoreId, storeIdStr)
|
|
|
+ .notIn(LifeCoupon::getStatus, CouponStatusEnum.ENDED.getCode(), CouponStatusEnum.INVALID.getCode())
|
|
|
+ .set(LifeCoupon::getStatus, CouponStatusEnum.INVALID.getCode()));
|
|
|
+
|
|
|
+ List<LifeCoupon> storeVouchers = lifeCouponMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<LifeCoupon>().eq(LifeCoupon::getStoreId, storeIdStr));
|
|
|
+ if (!storeVouchers.isEmpty()) {
|
|
|
+ List<String> voucherIds = storeVouchers.stream().map(LifeCoupon::getId).collect(Collectors.toList());
|
|
|
+ lifeDiscountCouponUserMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCouponUser>()
|
|
|
+ .in(LifeDiscountCouponUser::getVoucherId, voucherIds)
|
|
|
+ .eq(LifeDiscountCouponUser::getStatus, Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()))
|
|
|
+ .set(LifeDiscountCouponUser::getStatus, voidedUserCouponStatus));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String normalizeAccountType(String accountType) {
|
|
|
+ if (!StringUtils.hasText(accountType)) {
|
|
|
+ return "ALL";
|
|
|
+ }
|
|
|
+ return accountType.trim().toUpperCase(Locale.ROOT);
|
|
|
+ }
|
|
|
+}
|