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