修复住宿:床位重叠冲突返回标准化业务错误码
This commit is contained in:
1 parent
fb5834bb1e
commit
eb1ddfcaa8
4 files changed
+66
-4
No files matched your search
+26
@@ -2,6 +2,7 @@ package com.ruoyi.web.controller.train;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -181,5 +182,30 @@ public class AccommodationAndAuthApiControllerContractTest
|
||||
(java.util.Map<String, Object>) controller.getCapabilities().get("data");
|
||||
assertEquals(Boolean.FALSE, missing.get("manualRevokeAvailable"));
|
||||
}
|
||||
|
||||
/**
|
||||
* EX-13: 床位时间窗口冲突必须返回标准业务错误码 (AccommodationErrorCode.BED_ALREADY_OCCUPIED = 40060),
|
||||
* 严禁退化为未处理的系统 500 异常。
|
||||
*/
|
||||
@Test
|
||||
public void testEx13_BedOverlapErrorResponseContract()
|
||||
{
|
||||
com.ruoyi.framework.web.exception.GlobalExceptionHandler handler =
|
||||
new com.ruoyi.framework.web.exception.GlobalExceptionHandler();
|
||||
|
||||
com.ruoyi.common.exception.ServiceException ex = new com.ruoyi.common.exception.ServiceException(
|
||||
"BED_ALREADY_OCCUPIED: 该床位在目标培训周期内已被占用 (宿舍: DORM_101,床位: 1号床)",
|
||||
com.ruoyi.train.constant.AccommodationErrorCode.BED_ALREADY_OCCUPIED);
|
||||
|
||||
com.ruoyi.common.core.domain.AjaxResult result = handler.handleServiceException(ex, null);
|
||||
assertNotNull(result);
|
||||
assertEquals("HTTP 响应体 code 必须是标准业务错误码 40060",
|
||||
Integer.valueOf(com.ruoyi.train.constant.AccommodationErrorCode.BED_ALREADY_OCCUPIED),
|
||||
result.get(com.ruoyi.common.core.domain.AjaxResult.CODE_TAG));
|
||||
assertTrue("响应体 code 严禁为系统 500 异常",
|
||||
!Integer.valueOf(500).equals(result.get(com.ruoyi.common.core.domain.AjaxResult.CODE_TAG)));
|
||||
assertTrue("响应体消息必须包含 BED_ALREADY_OCCUPIED 提示",
|
||||
String.valueOf(result.get(com.ruoyi.common.core.domain.AjaxResult.MSG_TAG)).contains("BED_ALREADY_OCCUPIED"));
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.ruoyi.train.constant;
|
||||
|
||||
/**
|
||||
* 住宿管理业务错误码与常量规范 (API Contract V1.0.1 Module D)。
|
||||
*/
|
||||
public final class AccommodationErrorCode
|
||||
{
|
||||
/** 床位时间窗口已被占用冲突 */
|
||||
public static final int BED_ALREADY_OCCUPIED = 40060;
|
||||
public static final String BED_ALREADY_OCCUPIED_MESSAGE = "该床位在目标培训周期内已被占用";
|
||||
|
||||
/** 开班计划时间窗口不存在或无效 */
|
||||
public static final int BED_OCCUPANCY_WINDOW_INVALID = 40061;
|
||||
public static final String BED_OCCUPANCY_WINDOW_INVALID_MESSAGE = "目标开班计划时间窗口不存在或无效";
|
||||
|
||||
/** 床位存在无法解析时间窗口的预订记录 */
|
||||
public static final int BED_OCCUPANCY_WINDOW_UNRESOLVED = 40062;
|
||||
public static final String BED_OCCUPANCY_WINDOW_UNRESOLVED_MESSAGE = "目标床位存在无法解析培训时间窗口的有效预订记录";
|
||||
|
||||
/** 住宿记录不存在 */
|
||||
public static final int ACCOMMODATION_NOT_FOUND = 40460;
|
||||
public static final String ACCOMMODATION_NOT_FOUND_MESSAGE = "住宿记录不存在";
|
||||
|
||||
private AccommodationErrorCode()
|
||||
{
|
||||
}
|
||||
}
|
||||
+9
-4
@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.train.constant.AccommodationErrorCode;
|
||||
import com.ruoyi.train.domain.TrainAccommodation;
|
||||
import com.ruoyi.train.domain.TrainClassPlan;
|
||||
import com.ruoyi.train.domain.TrainDormitoryInfo;
|
||||
@@ -462,14 +463,16 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
TrainEnrollment enrollment = trainEnrollmentMapper.selectTrainEnrollmentById(enrollmentId);
|
||||
if (enrollment == null || enrollment.getPlanId() == null || enrollment.getPlanId().trim().isEmpty())
|
||||
{
|
||||
throw new ServiceException("BED_OCCUPANCY_WINDOW_INVALID: 无法解析参训档案关联的开班计划 (enrollmentId: " + enrollmentId + ")");
|
||||
throw new ServiceException("BED_OCCUPANCY_WINDOW_INVALID: 无法解析参训档案关联的开班计划 (enrollmentId: " + enrollmentId + ")",
|
||||
AccommodationErrorCode.BED_OCCUPANCY_WINDOW_INVALID);
|
||||
}
|
||||
|
||||
TrainClassPlan targetPlan = trainClassPlanMapper.selectTrainClassPlanByPlanId(enrollment.getPlanId());
|
||||
if (targetPlan == null || targetPlan.getStartTime() == null || targetPlan.getEndTime() == null
|
||||
|| !targetPlan.getEndTime().after(targetPlan.getStartTime()))
|
||||
{
|
||||
throw new ServiceException("BED_OCCUPANCY_WINDOW_INVALID: 目标开班计划时间窗口不存在或无效 (planId: " + enrollment.getPlanId() + ")");
|
||||
throw new ServiceException("BED_OCCUPANCY_WINDOW_INVALID: 目标开班计划时间窗口不存在或无效 (planId: " + enrollment.getPlanId() + ")",
|
||||
AccommodationErrorCode.BED_OCCUPANCY_WINDOW_INVALID);
|
||||
}
|
||||
|
||||
// 2. 检查同一床位是否存在无法可靠解析时间窗口的已有 active accommodation (Fail Closed)
|
||||
@@ -477,7 +480,8 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
if (unresolvedCount > 0)
|
||||
{
|
||||
throw new ServiceException("BED_OCCUPANCY_WINDOW_UNRESOLVED: 目标床位存在无法解析培训时间窗口的有效预订记录,请人工排查 (宿舍: "
|
||||
+ dormId + ",床位: " + bedNo + ")");
|
||||
+ dormId + ",床位: " + bedNo + ")",
|
||||
AccommodationErrorCode.BED_OCCUPANCY_WINDOW_UNRESOLVED);
|
||||
}
|
||||
|
||||
// 3. 检查同一床位在目标时间区间 [start_time, end_time) 内是否存在正长度交集冲突
|
||||
@@ -485,7 +489,8 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
dormId, bedNo.trim(), targetPlan.getStartTime(), targetPlan.getEndTime(), excludeAccommodationId);
|
||||
if (overlapCount > 0)
|
||||
{
|
||||
throw new ServiceException("BED_ALREADY_OCCUPIED: 该床位在目标培训周期内已被占用 (宿舍: " + dormId + ",床位: " + bedNo + ")");
|
||||
throw new ServiceException("BED_ALREADY_OCCUPIED: 该床位在目标培训周期内已被占用 (宿舍: " + dormId + ",床位: " + bedNo + ")",
|
||||
AccommodationErrorCode.BED_ALREADY_OCCUPIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -23,6 +23,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.train.constant.AccommodationErrorCode;
|
||||
import com.ruoyi.train.domain.TrainAccommodation;
|
||||
import com.ruoyi.train.domain.TrainClassPlan;
|
||||
import com.ruoyi.train.domain.TrainDormitoryInfo;
|
||||
@@ -233,6 +234,7 @@ public class BedOccupancyModelCTest
|
||||
}
|
||||
catch (ServiceException e)
|
||||
{
|
||||
assertEquals(Integer.valueOf(AccommodationErrorCode.BED_ALREADY_OCCUPIED), e.getCode());
|
||||
assertTrue(e.getMessage().contains("BED_ALREADY_OCCUPIED"));
|
||||
}
|
||||
}
|
||||
@@ -263,6 +265,7 @@ public class BedOccupancyModelCTest
|
||||
}
|
||||
catch (ServiceException e)
|
||||
{
|
||||
assertEquals(Integer.valueOf(AccommodationErrorCode.BED_ALREADY_OCCUPIED), e.getCode());
|
||||
assertTrue(e.getMessage().contains("BED_ALREADY_OCCUPIED"));
|
||||
}
|
||||
}
|
||||
@@ -564,6 +567,7 @@ public class BedOccupancyModelCTest
|
||||
}
|
||||
catch (ServiceException e)
|
||||
{
|
||||
assertEquals(Integer.valueOf(AccommodationErrorCode.BED_ALREADY_OCCUPIED), e.getCode());
|
||||
assertTrue(e.getMessage().contains("BED_ALREADY_OCCUPIED"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user