# 注销店铺流程完整性分析报告

## 一、流程概览

```
1. 商家提交注销申请 (logoutStore)
   ↓
2. 设置店铺状态为注销中 (storeStatus=-1, logoutFlag=1)
   ↓
3. 发送通知（7天冷静期）
   ↓
4. 7天内可撤回 (cancelLogoutStore)
   ↓
5. 超过7天后，定时任务自动删除店铺数据 (cancellationOfBusinessJob)
```

## 二、当前实现分析

### 1. 注销申请接口 ✅

**文件：** `StoreInfoServiceImpl.java:2691-2726`

**实现逻辑：**
- ✅ 设置 `storeStatus = -1`（注销中）
- ✅ 设置 `logoutFlag = 1`（注销标记）
- ✅ 记录 `logoutTime`（注销申请时间）
- ✅ 记录 `logoutReason`（注销原因）
- ✅ 记录 `logoutCode`（注销code）
- ✅ 发送WebSocket通知

**问题：**
- ⚠️ 通知内容说"7天冷静期"，但定时任务判断是"8天后"删除（不一致）

### 2. 取消注销接口 ✅

**文件：** `StoreInfoServiceImpl.java:2743-2773`

**实现逻辑：**
- ✅ 恢复 `logoutFlag = 0`
- ✅ 恢复 `storeStatus = 1`（可用）
- ✅ 清空注销相关字段
- ✅ 发送撤回通知

**问题：**
- ❌ **缺少状态检查**：没有检查是否还在冷静期内（理论上超过7天就不应该允许撤回）
- ❌ **缺少时间验证**：没有验证 `logoutTime` 是否超过7天

### 3. 定时任务删除 ⚠️

**文件：** `StoreMembershipCardJob.java:122-198`

**实现逻辑：**
- ✅ 查询 `logoutFlag = 1` 的店铺
- ✅ 判断 `logoutTime` 是否超过8天
- ✅ 删除店铺记录
- ✅ 清空 `StoreUser.storeId`
- ✅ 删除粉丝关系
- ✅ 删除Redis token

**问题：**
- ❌ **时间不一致**：通知说7天冷静期，但判断是8天后删除（应该改为7天）
- ❌ **数据清理不完整**：只清理了基础数据，缺少以下关联数据：
  - 订单数据（`life_user_order`）
  - 订单-优惠券中间表（`order_coupon_middle`）
  - 优惠券（`life_discount_coupon`）
  - 代金券（`life_coupon`）
  - 用户领取的优惠券（`life_discount_coupon_user`）
  - 团购券（`life_group_buy_main`）
  - 评论（`store_comment`、`life_comment`）
  - 通知消息（`life_notice`）
  - 店铺图片（`store_img`）
  - 店铺标签关系（`tag_store_relation`）
  - 其他关联数据
- ❌ **缺少事务保护**：没有 `@Transactional`，可能导致部分数据删除失败
- ❌ **缺少异常处理**：没有 try-catch，一个店铺删除失败会影响其他店铺
- ❌ **缺少详细日志**：删除操作缺少详细的日志记录
- ❌ **缺少状态检查**：删除前没有再次检查 `logoutFlag` 是否为1（可能已被撤回）

## 三、发现的问题汇总

### 🔴 严重问题

1. **数据清理不完整**
   - 定时任务只清理了基础数据（StoreInfo、StoreUser、LifeFans、Redis）
   - 缺少订单、优惠券、商品、评论等大量关联数据的清理
   - 参考 `MerchantUserServiceImpl.resetToInitialStatus` 应该清理更多数据

2. **时间逻辑不一致**
   - 通知说"7天冷静期"
   - 定时任务判断"8天后"删除
   - 应该统一为7天

3. **缺少事务保护**
   - 定时任务没有事务，可能导致部分数据删除失败，造成数据不一致

### 🟡 中等问题

4. **缺少状态检查**
   - 取消注销时没有检查是否还在冷静期内
   - 定时任务删除前没有再次检查 `logoutFlag` 是否为1

5. **缺少异常处理**
   - 定时任务没有 try-catch，一个店铺删除失败会影响其他店铺
   - 应该每个店铺单独处理，失败不影响其他

6. **缺少详细日志**
   - 删除操作缺少详细的日志记录
   - 无法追踪删除过程和失败原因

### 🟢 轻微问题

7. **代码可读性**
   - 定时任务中变量命名 `sevenDay` 实际是8天后的时间，容易误导

## 四、建议修复方案

### 1. 修复时间逻辑

```java
// 当前代码（错误）
calendar.add(Calendar.DAY_OF_YEAR, 8);  // 8天后删除

// 应该改为
calendar.add(Calendar.DAY_OF_YEAR, 7);  // 7天后删除
```

### 2. 完善数据清理

参考 `MerchantUserServiceImpl.resetToInitialStatus`，添加以下清理逻辑：

```java
// 1. 查询订单ID列表
List<LifeUserOrder> orders = lifeUserOrderMapper.selectList(
    new LambdaQueryWrapper<LifeUserOrder>().eq(LifeUserOrder::getStoreId, storeId)
);
List<String> orderIds = orders.stream().map(o -> o.getId().toString()).collect(Collectors.toList());

// 2. 删除订单-优惠券中间表
if (!orderIds.isEmpty()) {
    orderCouponMiddleMapper.delete(
        new LambdaQueryWrapper<OrderCouponMiddle>().in(OrderCouponMiddle::getOrderId, orderIds)
    );
}

// 3. 删除订单
lifeUserOrderMapper.delete(
    new LambdaQueryWrapper<LifeUserOrder>().eq(LifeUserOrder::getStoreId, storeId)
);

// 4. 删除优惠券
lifeDiscountCouponMapper.delete(
    new LambdaQueryWrapper<LifeDiscountCoupon>().eq(LifeDiscountCoupon::getStoreId, storeId)
);

// 5. 删除代金券
lifeCouponMapper.delete(
    new LambdaQueryWrapper<LifeCoupon>().eq(LifeCoupon::getStoreId, storeId)
);

// 6. 删除团购券
lifeGroupBuyMainMapper.delete(
    new LambdaQueryWrapper<LifeGroupBuyMain>().eq(LifeGroupBuyMain::getStoreId, storeId)
);

// 7. 删除通知消息
lifeNoticeMapper.delete(
    new LambdaQueryWrapper<LifeNotice>().eq(LifeNotice::getReceiverId, "store_" + storeUser.getPhone())
);

// 8. 删除店铺图片
storeImgMapper.delete(
    new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId)
);

// 9. 删除标签关系
tagStoreRelationMapper.delete(
    new LambdaQueryWrapper<TagStoreRelation>().eq(TagStoreRelation::getStoreId, storeId)
);

// 10. 删除评论（根据实际表结构调整）
// storeCommentMapper.delete(...)
// lifeCommentMapper.delete(...)
```

### 3. 添加事务保护

```java
@XxlJob("cancellationOfBusinessJob")
@Transactional(rollbackFor = Exception.class)
public void cancellationOfBusinessJob() {
    // ... 删除逻辑
}
```

### 4. 添加异常处理

```java
for (StoreInfo storeInfo : storeInfos) {
    try {
        // 再次检查状态
        if (storeInfo.getLogoutFlag() != 1) {
            log.warn("店铺 {} 的注销状态已变更，跳过删除", storeInfo.getId());
            continue;
        }
        
        // 检查时间
        if (storeInfo.getLogoutTime() == null) {
            log.warn("店铺 {} 的注销时间为空，跳过删除", storeInfo.getId());
            continue;
        }
        
        // 计算7天后的时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(storeInfo.getLogoutTime());
        calendar.add(Calendar.DAY_OF_YEAR, 7);  // 改为7天
        Date sevenDayLater = calendar.getTime();
        
        if (new Date().compareTo(sevenDayLater) >= 0) {
            // 执行删除逻辑
            deleteStoreData(storeInfo);
            log.info("成功删除店铺 {} 及其关联数据", storeInfo.getId());
        }
    } catch (Exception e) {
        log.error("删除店铺 {} 失败: {}", storeInfo.getId(), e.getMessage(), e);
        // 继续处理下一个店铺，不中断整个任务
    }
}
```

### 5. 添加取消注销时的状态检查

```java
public void cancelLogoutStore(StoreInfoVo storeInfo) {
    StoreInfo storeIn = storeInfoMapper.selectOne(
        new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, storeInfo.getId())
    );
    
    if (storeIn == null) {
        throw new IllegalArgumentException("店铺不存在");
    }
    
    // 检查是否还在冷静期内
    if (storeIn.getLogoutTime() != null) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(storeIn.getLogoutTime());
        calendar.add(Calendar.DAY_OF_YEAR, 7);
        Date sevenDayLater = calendar.getTime();
        
        if (new Date().compareTo(sevenDayLater) >= 0) {
            throw new IllegalStateException("已超过7天冷静期，无法撤回注销申请");
        }
    }
    
    // 检查当前状态
    if (storeIn.getLogoutFlag() != 1) {
        throw new IllegalStateException("店铺未处于注销状态，无法撤回");
    }
    
    // ... 后续恢复逻辑
}
```

## 五、修复优先级

1. **P0（必须修复）**
   - 修复时间逻辑（7天 vs 8天）
   - 完善数据清理逻辑
   - 添加异常处理

2. **P1（重要）**
   - 添加事务保护
   - 添加状态检查
   - 添加详细日志

3. **P2（优化）**
   - 代码可读性优化
   - 性能优化（批量删除）

## 六、测试建议

1. **单元测试**
   - 测试注销申请后状态是否正确
   - 测试7天内取消注销是否成功
   - 测试7天后取消注销是否失败
   - 测试定时任务是否正确删除数据

2. **集成测试**
   - 测试完整注销流程
   - 测试数据清理是否完整
   - 测试异常情况处理

3. **数据验证**
   - 验证删除后数据库中是否还有残留数据
   - 验证关联数据是否全部清理
