12 changed files with 599 additions and 614 deletions
@ -0,0 +1,95 @@ |
|||||
|
package com.zdxt.rest.test.cp; |
||||
|
|
||||
|
import com.zdxt.enforcementcode.domain.EfcodeCpReserve; |
||||
|
import com.zdxt.enforcementcode.service.IEfcodeCpPlanService; |
||||
|
import org.dromara.ZdxtAdminApplication; |
||||
|
import org.junit.jupiter.api.*; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
import org.springframework.test.context.ActiveProfiles; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 计划自动匹配预约测试 |
||||
|
* <p> |
||||
|
* 强制调用系统匹配方法,验证待预约计划的自动联合匹配逻辑。 |
||||
|
* 匹配条件:同一企业 + 一周内 + 不同执法单位 ≥ 2 个单位的待预约计划 |
||||
|
* </p> |
||||
|
*/ |
||||
|
@SpringBootTest(classes = ZdxtAdminApplication.class) |
||||
|
@ActiveProfiles({"dev", "dev-cust-zrb"}) |
||||
|
@DisplayName("计划自动匹配预约测试") |
||||
|
public class AppEnfCpAutoReserveTest { |
||||
|
|
||||
|
@Autowired |
||||
|
private IEfcodeCpPlanService cpPlanService; |
||||
|
|
||||
|
/** |
||||
|
* 强制执行系统自动匹配(干跑模式:不更新计划、不插入预约记录) |
||||
|
* <p>只计算匹配结果,不修改数据库,用于验证匹配逻辑是否正确</p> |
||||
|
*/ |
||||
|
@DisplayName("干跑模式 - 强制系统匹配(不落库)") |
||||
|
@Test |
||||
|
@Order(1) |
||||
|
public void testAutoMatch_dryRun() { |
||||
|
System.out.println("========== 开始执行自动匹配预约(干跑模式) =========="); |
||||
|
|
||||
|
// forceMatch=true: 跳过日期校验
|
||||
|
// updatePlan=false: 不更新计划状态
|
||||
|
// insertReserve=false: 不插入预约记录
|
||||
|
Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV2(true, false, false); |
||||
|
|
||||
|
System.out.println("匹配结果组数: " + result.size()); |
||||
|
for (Map.Entry<String, List<EfcodeCpReserve>> entry : result.entrySet()) { |
||||
|
String planGroupId = entry.getKey(); |
||||
|
List<EfcodeCpReserve> reserves = entry.getValue(); |
||||
|
System.out.println(" planGroupId=" + planGroupId + ", 联合计划数=" + reserves.size()); |
||||
|
for (EfcodeCpReserve r : reserves) { |
||||
|
System.out.println(" - planId=" + r.getPlanId() |
||||
|
+ ", receiverId=" + r.getReceiverId() |
||||
|
+ ", opStatus=" + r.getOpStatus()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("========== 干跑模式执行完毕 =========="); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 强制执行系统自动匹配(实际执行:更新计划 + 插入预约记录) |
||||
|
* <p>将匹配结果落库,计划状态变为“预约中(2)”,生成预约记录</p> |
||||
|
*/ |
||||
|
@DisplayName("实际执行 - 强制系统匹配(落库)") |
||||
|
@Test |
||||
|
@Order(2) |
||||
|
public void testAutoMatch_execute() { |
||||
|
System.out.println("========== 开始执行自动匹配预约(实际落库) =========="); |
||||
|
|
||||
|
// forceMatch=true: 跳过日期校验
|
||||
|
// updatePlan=true: 更新计划状态(system_reserved=1, reserve_status=2)
|
||||
|
// insertReserve=true: 插入预约记录到数据库
|
||||
|
Map<String, List<EfcodeCpReserve>> result = cpPlanService.autoMatchReserveV2(true, true, true); |
||||
|
|
||||
|
System.out.println("匹配结果组数: " + result.size()); |
||||
|
int totalReserves = 0; |
||||
|
for (Map.Entry<String, List<EfcodeCpReserve>> entry : result.entrySet()) { |
||||
|
String planGroupId = entry.getKey(); |
||||
|
List<EfcodeCpReserve> reserves = entry.getValue(); |
||||
|
totalReserves += reserves.size(); |
||||
|
System.out.println(" planGroupId=" + planGroupId + ", 联合计划数=" + reserves.size()); |
||||
|
for (EfcodeCpReserve r : reserves) { |
||||
|
System.out.println(" - planId=" + r.getPlanId() |
||||
|
+ ", receiverId=" + r.getReceiverId() |
||||
|
+ ", opStatus=" + r.getOpStatus() |
||||
|
+ ", opSetDate=" + r.getOpSetDate()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("总计生成预约记录数: " + totalReserves); |
||||
|
System.out.println("========== 实际落库执行完毕 =========="); |
||||
|
|
||||
|
// 验证:如果之前有多个账号创建了同一企业的计划,应能匹配到
|
||||
|
Assertions.assertFalse(result.isEmpty(), "应至少匹配到一组联合预约"); |
||||
|
} |
||||
|
} |
||||
@ -1,220 +0,0 @@ |
|||||
package com.zdxt.rest.test.cp; |
|
||||
|
|
||||
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; |
|
||||
import cn.dev33.satoken.stp.StpUtil; |
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
||||
import com.zdxt.enforcementcode.domain.EfcodeCpPlan; |
|
||||
import com.zdxt.enforcementcode.domain.EfcodeCpReserve; |
|
||||
import com.zdxt.enforcementcode.mapper.EfcodeCpPlanMapper; |
|
||||
import com.zdxt.enforcementcode.mapper.EfcodeCpReserveMapper; |
|
||||
import org.dromara.ZdxtAdminApplication; |
|
||||
import org.junit.jupiter.api.*; |
|
||||
import org.junit.jupiter.api.Tag; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
|
||||
import org.springframework.boot.test.context.SpringBootTest; |
|
||||
import org.springframework.mock.web.MockHttpServletRequest; |
|
||||
import org.springframework.test.context.ActiveProfiles; |
|
||||
import org.springframework.web.context.request.RequestContextHolder; |
|
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
|
||||
|
|
||||
import java.util.*; |
|
||||
import java.util.stream.Collectors; |
|
||||
|
|
||||
/** |
|
||||
* 预约记录批量生成测试 |
|
||||
* <p> |
|
||||
* 基于已创建的计划数据,为多个用户交替创建 efcode_cp_reserve 预约记录。 |
|
||||
* 模拟场景:用户A的计划被用户B预约,用户B的计划被用户C预约...循环交替。 |
|
||||
* 预约状态交替:待确认(3)、已同意(1)、已拒绝(2) |
|
||||
* 预约来源交替:手动预约(0)、系统匹配(1) |
|
||||
* </p> |
|
||||
*/ |
|
||||
@SpringBootTest(classes = ZdxtAdminApplication.class) |
|
||||
@AutoConfigureMockMvc |
|
||||
@ActiveProfiles({"dev", "dev-cust-zrb"}) |
|
||||
@DisplayName("AppEnfCpReserve 批量生成预约记录测试") |
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
|
||||
@Tag("dev") |
|
||||
public class AppEnfCpReserveTest { |
|
||||
|
|
||||
@Autowired |
|
||||
private EfcodeCpPlanMapper cpPlanMapper; |
|
||||
|
|
||||
@Autowired |
|
||||
private EfcodeCpReserveMapper cpReserveMapper; |
|
||||
|
|
||||
/** |
|
||||
* 测试账号对应的 userId(需从数据库匹配) |
|
||||
* 这里通过查询 plan 表的 create_by 字段获取对应用户ID |
|
||||
*/ |
|
||||
private static final String[] TEST_ACCOUNTS = {"liuqianlin", "baining", "caizifan", "chenchong4"}; |
|
||||
|
|
||||
/** 每个用户最多取多少条计划来生成预约 */ |
|
||||
private static final int MAX_PLANS_PER_USER = 50; |
|
||||
|
|
||||
/** 预约留言模板 */ |
|
||||
private static final String[] MESSAGES = { |
|
||||
"希望联合执法,请确认时间", |
|
||||
"我单位有相关检查需求,申请联合", |
|
||||
"建议合并检查,减轻企业负担", |
|
||||
"时间安排一致,申请联合执法", |
|
||||
"", // 部分无留言
|
|
||||
"请尽快确认预约", |
|
||||
"", |
|
||||
"我方已做好准备,等待确认" |
|
||||
}; |
|
||||
|
|
||||
@BeforeEach |
|
||||
public void setUp() { |
|
||||
SaTokenContextMockUtil.setMockContext(); |
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest(); |
|
||||
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); |
|
||||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); |
|
||||
} |
|
||||
|
|
||||
@AfterEach |
|
||||
public void tearDown() { |
|
||||
try { |
|
||||
StpUtil.logout(); |
|
||||
} catch (Exception ignored) { |
|
||||
} |
|
||||
RequestContextHolder.resetRequestAttributes(); |
|
||||
SaTokenContextMockUtil.clearContext(); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("基于已有计划批量生成交替预约记录") |
|
||||
@Test |
|
||||
@Order(1) |
|
||||
public void testBatchCreateReserves() { |
|
||||
// 1. 收集每个用户的计划(通过 enforce_user_names LIKE 账号中文名识别)
|
|
||||
// 实际通过 create_by 字段分组获取不同用户的计划
|
|
||||
Map<Long, List<EfcodeCpPlan>> userPlansMap = loadUserPlansMap(); |
|
||||
|
|
||||
List<Long> userIds = new ArrayList<>(userPlansMap.keySet()); |
|
||||
Assertions.assertTrue(userIds.size() >= 2, "至少需要2个用户的计划数据才能交叉预约"); |
|
||||
|
|
||||
System.out.println("========== 检测到 " + userIds.size() + " 个用户的计划数据 =========="); |
|
||||
for (Long uid : userIds) { |
|
||||
System.out.println(" userId=" + uid + ", 计划数=" + userPlansMap.get(uid).size()); |
|
||||
} |
|
||||
|
|
||||
Random random = new Random(42); // 固定种子,可重复
|
|
||||
int totalCreated = 0; |
|
||||
int reserveIndex = 0; |
|
||||
|
|
||||
// 2. 交替为每个用户的计划创建来自其他用户的预约
|
|
||||
for (int ownerIdx = 0; ownerIdx < userIds.size(); ownerIdx++) { |
|
||||
Long ownerUserId = userIds.get(ownerIdx); |
|
||||
List<EfcodeCpPlan> ownerPlans = userPlansMap.get(ownerUserId); |
|
||||
|
|
||||
// 限制数量
|
|
||||
int planCount = Math.min(ownerPlans.size(), MAX_PLANS_PER_USER); |
|
||||
|
|
||||
for (int planIdx = 0; planIdx < planCount; planIdx++) { |
|
||||
EfcodeCpPlan targetPlan = ownerPlans.get(planIdx); |
|
||||
|
|
||||
// 选择预约发起者:循环选取其他用户
|
|
||||
int reserverIdx = (ownerIdx + 1 + planIdx) % userIds.size(); |
|
||||
if (reserverIdx == ownerIdx) { |
|
||||
reserverIdx = (reserverIdx + 1) % userIds.size(); |
|
||||
} |
|
||||
Long reserverUserId = userIds.get(reserverIdx); |
|
||||
List<EfcodeCpPlan> reserverPlans = userPlansMap.get(reserverUserId); |
|
||||
|
|
||||
// 找预约者匹配的计划(同日期+同时段+同企业),如果没有就用预约者的任意一条计划
|
|
||||
EfcodeCpPlan reserverPlan = findMatchingPlan(reserverPlans, targetPlan); |
|
||||
if (reserverPlan == null && !reserverPlans.isEmpty()) { |
|
||||
reserverPlan = reserverPlans.get(planIdx % reserverPlans.size()); |
|
||||
} |
|
||||
if (reserverPlan == null) continue; |
|
||||
|
|
||||
// 3. 确定 planGroupId
|
|
||||
String planGroupId = targetPlan.getId(); |
|
||||
|
|
||||
// 4. 交替 opStatus: 3(待确认), 1(已同意), 2(已拒绝), 3, 1, 2...
|
|
||||
long opStatus = getAlternatingStatus(reserveIndex); |
|
||||
// 5. 交替 resFrom: 0(手动), 1(系统)
|
|
||||
long resFrom = reserveIndex % 2; |
|
||||
// 6. 留言
|
|
||||
String message = MESSAGES[reserveIndex % MESSAGES.length]; |
|
||||
|
|
||||
// 插入目标计划方的记录(计划拥有者)
|
|
||||
insertReserve(targetPlan.getId(), planGroupId, "", targetPlan.getPlanDate(), |
|
||||
targetPlan.getPlanTime(), resFrom, opStatus); |
|
||||
|
|
||||
// 插入预约发起方的记录
|
|
||||
insertReserve(reserverPlan.getId(), planGroupId, message, targetPlan.getPlanDate(), |
|
||||
targetPlan.getPlanTime(), resFrom, 3L); // 发起方始终待确认
|
|
||||
|
|
||||
totalCreated += 2; |
|
||||
reserveIndex++; |
|
||||
} |
|
||||
|
|
||||
System.out.println("[userId=" + ownerUserId + "] 已为其 " + planCount + " 条计划生成预约记录"); |
|
||||
} |
|
||||
|
|
||||
System.out.println("========== 预约记录生成完成 =========="); |
|
||||
System.out.println("总计插入: " + totalCreated + " 条预约记录"); |
|
||||
Assertions.assertTrue(totalCreated > 0, "应至少生成1条预约记录"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 从数据库加载各用户的计划,按 create_by 分组 |
|
||||
* 只取未删除、reserve_status=1(待预约)的计划 |
|
||||
*/ |
|
||||
private Map<Long, List<EfcodeCpPlan>> loadUserPlansMap() { |
|
||||
LambdaQueryWrapper<EfcodeCpPlan> lqw = Wrappers.lambdaQuery(); |
|
||||
lqw.eq(EfcodeCpPlan::getIsDelete, 0L); |
|
||||
lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); // 待预约状态
|
|
||||
lqw.like(EfcodeCpPlan::getEnforceContent, "批量测试执法事项"); // 只取测试数据
|
|
||||
lqw.orderByAsc(EfcodeCpPlan::getPlanDate); |
|
||||
List<EfcodeCpPlan> allPlans = cpPlanMapper.selectList(lqw); |
|
||||
|
|
||||
return allPlans.stream() |
|
||||
.filter(p -> p.getCreateBy() != null) |
|
||||
.collect(Collectors.groupingBy(EfcodeCpPlan::getCreateBy)); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 在预约者的计划列表中查找与目标计划匹配的计划(同日期+同时段+同企业) |
|
||||
*/ |
|
||||
private EfcodeCpPlan findMatchingPlan(List<EfcodeCpPlan> plans, EfcodeCpPlan target) { |
|
||||
if (plans == null || plans.isEmpty()) return null; |
|
||||
for (EfcodeCpPlan p : plans) { |
|
||||
if (p.getPlanDate() != null && p.getPlanDate().equals(target.getPlanDate()) |
|
||||
&& Objects.equals(p.getPlanTime(), target.getPlanTime()) |
|
||||
&& Objects.equals(p.getEnterpriseId(), target.getEnterpriseId())) { |
|
||||
return p; |
|
||||
} |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 交替状态: 3, 1, 2, 3, 1, 2... |
|
||||
*/ |
|
||||
private long getAlternatingStatus(int index) { |
|
||||
int mod = index % 3; |
|
||||
return mod == 0 ? 3L : (mod == 1 ? 1L : 2L); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 插入一条预约记录 |
|
||||
*/ |
|
||||
private void insertReserve(String planId, String planGroupId, String opMessage, |
|
||||
Date opSetDate, Long opSetTime, Long resFrom, Long opStatus) { |
|
||||
EfcodeCpReserve record = new EfcodeCpReserve(); |
|
||||
record.setPlanId(planId); |
|
||||
record.setPlanGroupId(planGroupId); |
|
||||
record.setReserveTime(new Date()); |
|
||||
record.setOpStatus(opStatus); |
|
||||
record.setOpOrder(0L); |
|
||||
record.setOpMessage(opMessage); |
|
||||
record.setOpSetDate(opSetDate); |
|
||||
record.setOpSetTime(opSetTime); |
|
||||
record.setResFrom(resFrom); |
|
||||
cpReserveMapper.insert(record); |
|
||||
} |
|
||||
} |
|
||||
@ -1,354 +0,0 @@ |
|||||
package com.zdxt.rest.test.cp; |
|
||||
|
|
||||
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; |
|
||||
import cn.dev33.satoken.stp.StpUtil; |
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
||||
import com.zdxt.enforcementcode.domain.EfcodeCpPlan; |
|
||||
import com.zdxt.enforcementcode.domain.EfcodeCpReserve; |
|
||||
import com.zdxt.enforcementcode.mapper.EfcodeCpPlanMapper; |
|
||||
import com.zdxt.enforcementcode.mapper.EfcodeCpReserveMapper; |
|
||||
import com.zdxt.enforcementcode.service.IEfcodeCpPlanService; |
|
||||
import org.dromara.ZdxtAdminApplication; |
|
||||
import org.junit.jupiter.api.*; |
|
||||
import org.junit.jupiter.api.Tag; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
|
||||
import org.springframework.boot.test.context.SpringBootTest; |
|
||||
import org.springframework.mock.web.MockHttpServletRequest; |
|
||||
import org.springframework.test.context.ActiveProfiles; |
|
||||
import org.springframework.web.context.request.RequestContextHolder; |
|
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
|
||||
|
|
||||
import java.time.LocalDate; |
|
||||
import java.time.ZoneId; |
|
||||
import java.util.*; |
|
||||
import java.util.stream.Collectors; |
|
||||
|
|
||||
/** |
|
||||
* 计划自动匹配预约 autoMatchReserve 方法测试 |
|
||||
* <p> |
|
||||
* 测试场景: |
|
||||
* 1. 强制模式下执行自动匹配(绕过日期校验) |
|
||||
* 2. 验证匹配结果:同企业不同单位的计划被联合 |
|
||||
* 3. 验证计划状态更新:system_reserved=1, reserve_status=2 |
|
||||
* 4. 验证预约记录生成:相同 plan_group_id 关联多条记录 |
|
||||
* </p> |
|
||||
*/ |
|
||||
@SpringBootTest(classes = ZdxtAdminApplication.class) |
|
||||
@AutoConfigureMockMvc |
|
||||
@ActiveProfiles({"dev", "dev-cust-zrb"}) |
|
||||
@DisplayName("autoMatchReserve 自动匹配预约测试") |
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
|
||||
@Tag("dev") |
|
||||
public class AutoMatchReserveTest { |
|
||||
|
|
||||
@Autowired |
|
||||
private IEfcodeCpPlanService cpPlanService; |
|
||||
|
|
||||
@Autowired |
|
||||
private EfcodeCpPlanMapper cpPlanMapper; |
|
||||
|
|
||||
@Autowired |
|
||||
private EfcodeCpReserveMapper cpReserveMapper; |
|
||||
|
|
||||
@BeforeEach |
|
||||
public void setUp() { |
|
||||
SaTokenContextMockUtil.setMockContext(); |
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest(); |
|
||||
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); |
|
||||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); |
|
||||
} |
|
||||
|
|
||||
@AfterEach |
|
||||
public void tearDown() { |
|
||||
try { |
|
||||
StpUtil.logout(); |
|
||||
} catch (Exception ignored) { |
|
||||
} |
|
||||
RequestContextHolder.resetRequestAttributes(); |
|
||||
SaTokenContextMockUtil.clearContext(); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("0. 插入1000条适合匹配的计划数据") |
|
||||
@Test |
|
||||
@Order(0) |
|
||||
public void testInsert1000MatchablePlans() { |
|
||||
// 模拟登录(避免自动填充 createBy 报空)
|
|
||||
StpUtil.login(1); |
|
||||
|
|
||||
// 准备数据:200个企业 × 每企业5个不同执法单位 = 1000条计划
|
|
||||
int enterpriseCount = 200; |
|
||||
int unitsPerEnterprise = 5; |
|
||||
Random random = new Random(); |
|
||||
|
|
||||
// 模拟执法单位ID池(确保不同单位)
|
|
||||
String[] bureauDeptIds = { |
|
||||
"BUREAU_TEST_A", "BUREAU_TEST_B", "BUREAU_TEST_C", |
|
||||
"BUREAU_TEST_D", "BUREAU_TEST_E", "BUREAU_TEST_F", |
|
||||
"BUREAU_TEST_G", "BUREAU_TEST_H" |
|
||||
}; |
|
||||
String[] bureauDeptNames = { |
|
||||
"测试执法局A", "测试执法局B", "测试执法局C", |
|
||||
"测试执法局D", "测试执法局E", "测试执法局F", |
|
||||
"测试执法局G", "测试执法局H" |
|
||||
}; |
|
||||
|
|
||||
// 基准日期:从明天开始
|
|
||||
LocalDate baseDate = LocalDate.now().plusDays(1); |
|
||||
int insertedCount = 0; |
|
||||
|
|
||||
for (int e = 0; e < enterpriseCount; e++) { |
|
||||
String enterpriseNumber = String.format("91440300TEST%06d", e); |
|
||||
String enterpriseName = "测试企业" + e + "号"; |
|
||||
String enterpriseId = "ENT_TEST_" + e; |
|
||||
|
|
||||
// 同一企业的计划日期在基准日期附3天内(确保一周内可匹配)
|
|
||||
Date planDate = Date.from( |
|
||||
baseDate.plusDays(random.nextInt(3)) |
|
||||
.atStartOfDay(ZoneId.systemDefault()).toInstant() |
|
||||
); |
|
||||
|
|
||||
for (int u = 0; u < unitsPerEnterprise; u++) { |
|
||||
int bureauIdx = (e + u) % bureauDeptIds.length; |
|
||||
|
|
||||
EfcodeCpPlan plan = new EfcodeCpPlan(); |
|
||||
plan.setId(UUID.randomUUID().toString().replace("-", "")); |
|
||||
plan.setPlanType(random.nextBoolean() ? 1L : 2L); |
|
||||
plan.setPlanDate(planDate); |
|
||||
plan.setPlanTime((long) (random.nextInt(3) + 1)); // 1=上午,2=下午,3=其他
|
|
||||
plan.setPlanActualDate(plan.getPlanDate()); |
|
||||
plan.setPlanActualTime(plan.getPlanTime()); // 1=上午,2=下午,3=其他
|
|
||||
plan.setEnforceContent("自动匹配测试-执法事项" + e + "-" + u); |
|
||||
plan.setEnterpriseName(enterpriseName); |
|
||||
plan.setEnterpriseNumber(enterpriseNumber); |
|
||||
plan.setEnterpriseId(enterpriseId); |
|
||||
plan.setEnforceUserNames("测试人员" + u); |
|
||||
plan.setEnforceUserIds(String.valueOf(1000 + u)); |
|
||||
plan.setEnforceUserCodes("CODE" + u); |
|
||||
plan.setEnforceUserTels("1380000" + String.format("%04d", u)); |
|
||||
plan.setIsPublic(1L); |
|
||||
plan.setIsUnion(1L); |
|
||||
plan.setReserveStatus(1L); // 待预约
|
|
||||
plan.setSystemReserved(0L); // 未经系统匹配
|
|
||||
plan.setManualReserved(0L); |
|
||||
plan.setBureauDeptId(bureauDeptIds[bureauIdx]); |
|
||||
plan.setBureauDeptName(bureauDeptNames[bureauIdx]); |
|
||||
plan.setOrganId(plan.getBureauDeptId()); |
|
||||
plan.setOrganName(plan.getBureauDeptName()); |
|
||||
plan.setDeptId(plan.getBureauDeptId()); |
|
||||
plan.setDeptName(plan.getBureauDeptName()); |
|
||||
plan.setIsDelete(0L); |
|
||||
plan.setCreateBy(1L); |
|
||||
plan.setCreateTime(new Date()); |
|
||||
plan.setUpdateBy(1L); |
|
||||
plan.setUpdateTime(new Date()); |
|
||||
|
|
||||
cpPlanMapper.insert(plan); |
|
||||
insertedCount++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
System.out.println("========== 插入匹配测试数据完成 =========="); |
|
||||
System.out.println("共插入计划数: " + insertedCount); |
|
||||
System.out.println("涉及企业数: " + enterpriseCount); |
|
||||
System.out.println("每企业不同单位数: " + unitsPerEnterprise); |
|
||||
System.out.println("预期可匹配企业组数: " + enterpriseCount + " (每企业都有>=2个单位)"); |
|
||||
System.out.println("==========================================="); |
|
||||
|
|
||||
Assertions.assertEquals(1000, insertedCount, "应插入恰好1000条计划"); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("1. 查看当前待匹配计划数据概况") |
|
||||
@Test |
|
||||
@Order(1) |
|
||||
public void testCheckPendingPlans() { |
|
||||
// 查询符合自动匹配条件的计划
|
|
||||
LambdaQueryWrapper<EfcodeCpPlan> lqw = Wrappers.lambdaQuery(); |
|
||||
lqw.gt(EfcodeCpPlan::getPlanDate, new Date()); |
|
||||
lqw.eq(EfcodeCpPlan::getSystemReserved, 0L); |
|
||||
lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); |
|
||||
lqw.eq(EfcodeCpPlan::getIsPublic, 1L); |
|
||||
lqw.eq(EfcodeCpPlan::getIsUnion, 1L); |
|
||||
lqw.eq(EfcodeCpPlan::getIsDelete, 0L); |
|
||||
List<EfcodeCpPlan> pendingPlans = cpPlanMapper.selectList(lqw); |
|
||||
|
|
||||
System.out.println("========== 待匹配计划数据概况 =========="); |
|
||||
System.out.println("符合条件的计划总数: " + pendingPlans.size()); |
|
||||
|
|
||||
// 按企业信用代码分组统计
|
|
||||
Map<String, List<EfcodeCpPlan>> groupByEnterprise = pendingPlans.stream() |
|
||||
.filter(p -> p.getEnterpriseNumber() != null) |
|
||||
.collect(Collectors.groupingBy(EfcodeCpPlan::getEnterpriseNumber)); |
|
||||
|
|
||||
int potentialMatchCount = 0; |
|
||||
for (Map.Entry<String, List<EfcodeCpPlan>> entry : groupByEnterprise.entrySet()) { |
|
||||
// 统计不同执法单位数量
|
|
||||
long distinctUnits = entry.getValue().stream() |
|
||||
.map(EfcodeCpPlan::getBureauDeptId) |
|
||||
.distinct() |
|
||||
.count(); |
|
||||
if (distinctUnits >= 2) { |
|
||||
potentialMatchCount++; |
|
||||
System.out.println(" 企业[" + entry.getKey() + "] - 有" + distinctUnits + "个不同单位的计划,可匹配"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
System.out.println("潜在可匹配的企业数: " + potentialMatchCount); |
|
||||
System.out.println("======================================="); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("2. 强制执行 autoMatchReserve 并验证结果") |
|
||||
@Test |
|
||||
@Order(2) |
|
||||
public void testAutoMatchReserveForceMode() { |
|
||||
// 执行前:统计当前系统匹配预约记录数
|
|
||||
long beforeReserveCount = cpReserveMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpReserve>lambdaQuery().eq(EfcodeCpReserve::getResFrom, 1L) |
|
||||
); |
|
||||
System.out.println("执行前系统匹配预约记录数: " + beforeReserveCount); |
|
||||
|
|
||||
// 执行前:统计已被系统预约的计划数
|
|
||||
long beforeMatchedPlanCount = cpPlanMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpPlan>lambdaQuery() |
|
||||
.eq(EfcodeCpPlan::getSystemReserved, 1L) |
|
||||
.eq(EfcodeCpPlan::getIsDelete, 0L) |
|
||||
); |
|
||||
System.out.println("执行前已系统匹配计划数: " + beforeMatchedPlanCount); |
|
||||
|
|
||||
// 执行自动匹配(强制模式,忽略日期校验)
|
|
||||
System.out.println("\n========== 开始执行 autoMatchReserve(true) =========="); |
|
||||
cpPlanService.autoMatchReserve(true, true, true); |
|
||||
System.out.println("========== 执行完毕 ==========\n"); |
|
||||
|
|
||||
// 执行后:统计系统匹配预约记录数
|
|
||||
long afterReserveCount = cpReserveMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpReserve>lambdaQuery().eq(EfcodeCpReserve::getResFrom, 1L) |
|
||||
); |
|
||||
System.out.println("执行后系统匹配预约记录数: " + afterReserveCount); |
|
||||
System.out.println("本次新增预约记录数: " + (afterReserveCount - beforeReserveCount)); |
|
||||
|
|
||||
// 执行后:统计已被系统预约的计划数
|
|
||||
long afterMatchedPlanCount = cpPlanMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpPlan>lambdaQuery() |
|
||||
.eq(EfcodeCpPlan::getSystemReserved, 1L) |
|
||||
.eq(EfcodeCpPlan::getIsDelete, 0L) |
|
||||
); |
|
||||
System.out.println("执行后已系统匹配计划数: " + afterMatchedPlanCount); |
|
||||
System.out.println("本次新增匹配计划数: " + (afterMatchedPlanCount - beforeMatchedPlanCount)); |
|
||||
|
|
||||
// 验证:如果有符合条件的数据,则应产生匹配结果
|
|
||||
if (afterReserveCount > beforeReserveCount) { |
|
||||
System.out.println("\n[验证通过] 自动匹配产生了新的预约记录"); |
|
||||
} else { |
|
||||
System.out.println("\n[提示] 未产生新预约记录(可能没有符合条件的跨单位同企业计划)"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@DisplayName("3. 验证匹配后的 plan_group_id 分组一致性") |
|
||||
@Test |
|
||||
@Order(3) |
|
||||
public void testVerifyPlanGroupConsistency() { |
|
||||
// 查询所有系统匹配生成的预约记录
|
|
||||
LambdaQueryWrapper<EfcodeCpReserve> lqw = Wrappers.lambdaQuery(); |
|
||||
lqw.eq(EfcodeCpReserve::getResFrom, 1L); |
|
||||
lqw.eq(EfcodeCpReserve::getOpStatus, 3L); // 待确认
|
|
||||
lqw.orderByDesc(EfcodeCpReserve::getCreateTime); |
|
||||
List<EfcodeCpReserve> reserves = cpReserveMapper.selectList(lqw); |
|
||||
|
|
||||
if (reserves.isEmpty()) { |
|
||||
System.out.println("[跳过] 无系统匹配的预约记录,无法验证分组一致性"); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// 按 plan_group_id 分组
|
|
||||
Map<String, List<EfcodeCpReserve>> groupMap = reserves.stream() |
|
||||
.collect(Collectors.groupingBy(EfcodeCpReserve::getPlanGroupId)); |
|
||||
|
|
||||
System.out.println("========== plan_group_id 分组验证 =========="); |
|
||||
System.out.println("共有 " + groupMap.size() + " 组联合预约"); |
|
||||
|
|
||||
int validGroups = 0; |
|
||||
for (Map.Entry<String, List<EfcodeCpReserve>> entry : groupMap.entrySet()) { |
|
||||
List<EfcodeCpReserve> group = entry.getValue(); |
|
||||
// 每组至少2条记录(2个不同单位)
|
|
||||
if (group.size() >= 2) { |
|
||||
validGroups++; |
|
||||
|
|
||||
// 验证同组内关联的计划属于不同执法单位
|
|
||||
Set<String> planIds = group.stream() |
|
||||
.map(EfcodeCpReserve::getPlanId) |
|
||||
.collect(Collectors.toSet()); |
|
||||
List<EfcodeCpPlan> plans = cpPlanMapper.selectByIds(planIds); |
|
||||
Set<String> bureauDeptIds = plans.stream() |
|
||||
.map(EfcodeCpPlan::getBureauDeptId) |
|
||||
.collect(Collectors.toSet()); |
|
||||
|
|
||||
System.out.println(" groupId=" + entry.getKey() |
|
||||
+ " | 记录数=" + group.size() |
|
||||
+ " | 涉及单位数=" + bureauDeptIds.size()); |
|
||||
|
|
||||
// 断言:同组关联的计划应来自不同单位
|
|
||||
Assertions.assertTrue(bureauDeptIds.size() >= 2, |
|
||||
"同一planGroupId下应关联至少2个不同执法单位的计划"); |
|
||||
} |
|
||||
} |
|
||||
System.out.println("有效分组数(>=2条记录): " + validGroups); |
|
||||
System.out.println("============================================="); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("4. 验证匹配后计划状态已更新") |
|
||||
@Test |
|
||||
@Order(4) |
|
||||
public void testVerifyPlanStatusUpdated() { |
|
||||
// 查询已被系统匹配的计划
|
|
||||
LambdaQueryWrapper<EfcodeCpPlan> lqw = Wrappers.lambdaQuery(); |
|
||||
lqw.eq(EfcodeCpPlan::getSystemReserved, 1L); |
|
||||
lqw.eq(EfcodeCpPlan::getReserveStatus, 2L); // 预约中
|
|
||||
lqw.eq(EfcodeCpPlan::getIsDelete, 0L); |
|
||||
List<EfcodeCpPlan> matchedPlans = cpPlanMapper.selectList(lqw); |
|
||||
|
|
||||
System.out.println("========== 计划状态验证 =========="); |
|
||||
System.out.println("system_reserved=1 且 reserve_status=2 的计划数: " + matchedPlans.size()); |
|
||||
|
|
||||
if (!matchedPlans.isEmpty()) { |
|
||||
// 验证每条计划都满足状态要求
|
|
||||
for (EfcodeCpPlan plan : matchedPlans) { |
|
||||
Assertions.assertEquals(1L, plan.getSystemReserved(), |
|
||||
"计划[" + plan.getId() + "]的system_reserved应为1"); |
|
||||
Assertions.assertEquals(2L, plan.getReserveStatus(), |
|
||||
"计划[" + plan.getId() + "]的reserve_status应为2(预约中)"); |
|
||||
} |
|
||||
System.out.println("[验证通过] 所有已匹配计划状态正确"); |
|
||||
} else { |
|
||||
System.out.println("[提示] 无已匹配计划数据"); |
|
||||
} |
|
||||
System.out.println("=================================="); |
|
||||
} |
|
||||
|
|
||||
@DisplayName("5. 再次执行 autoMatchReserve 验证幂等性(不重复匹配)") |
|
||||
@Test |
|
||||
@Order(5) |
|
||||
public void testAutoMatchReserveIdempotent() { |
|
||||
// 先统计当前预约记录数
|
|
||||
long beforeCount = cpReserveMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpReserve>lambdaQuery().eq(EfcodeCpReserve::getResFrom, 1L) |
|
||||
); |
|
||||
|
|
||||
// 再次执行
|
|
||||
System.out.println("========== 二次执行 autoMatchReserve(true) 验证幂等性 =========="); |
|
||||
cpPlanService.autoMatchReserve(true, true, true); |
|
||||
|
|
||||
long afterCount = cpReserveMapper.selectCount( |
|
||||
Wrappers.<EfcodeCpReserve>lambdaQuery().eq(EfcodeCpReserve::getResFrom, 1L) |
|
||||
); |
|
||||
|
|
||||
long newRecords = afterCount - beforeCount; |
|
||||
System.out.println("二次执行新增预约记录数: " + newRecords); |
|
||||
|
|
||||
// 已匹配过的计划不应再次匹配(system_reserved已设为1)
|
|
||||
// 但如果有新的符合条件的数据也可能产生新记录
|
|
||||
System.out.println("[说明] 已匹配的计划(system_reserved=1)不会被重复匹配"); |
|
||||
System.out.println("================================================================"); |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue