修复结训:阻止未报到与请假学员被错误归档

This commit is contained in:
wangzhibiao committed 2026-09-21 21:43:52 +08:00
1 parent 1c395b7827
commit 8900dcb101
3 files changed
+86

No files matched your search

@@ -38,10 +38,82 @@ public class EnrollmentPlanCompletionAdapter implements PlanEnrollmentCompletion
@Autowired(required = false)
private AccessAuthorizationOrchestrator accessAuthorizationOrchestrator;
@Override
public void precheckCompletion(String planId)
{
List<java.util.Map<String, Object>> stats = trainEnrollmentService.selectEnrollmentCompletionStatsByPlanId(planId);
int status0Waiting = 0;
int status1Reported = 0;
int status2Leave = 0;
int status3Abandoned = 0;
int status4Completed = 0;
int integrityErrorCount = 0;
if (stats != null)
{
for (java.util.Map<String, Object> map : stats)
{
Object stObj = map.get("enrollmentStatus") != null ? map.get("enrollmentStatus") : map.get("enrollment_status");
int st = stObj instanceof Number ? ((Number) stObj).intValue() : 0;
Object repObj = map.get("hasReport") != null ? map.get("hasReport") : map.get("has_report");
int hasRep = repObj instanceof Number ? ((Number) repObj).intValue() : 0;
if (st == 0)
{
status0Waiting++;
}
else if (st == 1)
{
status1Reported++;
if (hasRep == 0)
{
integrityErrorCount++;
}
}
else if (st == 2)
{
status2Leave++;
}
else if (st == 3)
{
status3Abandoned++;
}
else if (st == 4)
{
status4Completed++;
}
}
}
if (status0Waiting > 0 || status2Leave > 0 || integrityErrorCount > 0)
{
StringBuilder msg = new StringBuilder("计划暂不能结训:");
List<String> reasons = new java.util.ArrayList<>();
if (status0Waiting > 0)
{
reasons.add("待报到 " + status0Waiting + " 人 (WAITING_REPORT_ENROLLMENTS_EXIST)");
}
if (status2Leave > 0)
{
reasons.add("请假 " + status2Leave + " 人 (LEAVE_ENROLLMENTS_REQUIRE_RESOLUTION)");
}
if (integrityErrorCount > 0)
{
reasons.add("已报到缺失报到单异常 " + integrityErrorCount + " 人 (REPORTED_WITHOUT_REPORT_INTEGRITY_ERROR)");
}
msg.append(String.join(",", reasons)).append("。请先处理后再结训。");
log.warn("计划结训预检拦截: planId={}, 原因={}", planId, msg.toString());
throw new com.ruoyi.common.exception.ServiceException(msg.toString());
}
}
@Override
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
public void completeEnrollments(String planId, String operator, Date completeTime)
{
// 结训预检 (All-or-Nothing 守卫)
precheckCompletion(planId);
log.info("执行计划结训学员状态联动归档: planId={}, operator={}, completeTime={}", planId, operator, completeTime);
int updatedRows = trainEnrollmentService.completeActiveEnrollmentsByPlanId(planId, operator, completeTime);
log.info("计划结训学员归档完成: planId={}, 更新记录数={}", planId, updatedRows);
@@ -158,6 +158,12 @@ public class PlanAppServiceImpl implements PlanAppService
throw error(PlanErrorCode.PLAN_STATUS_LOCKED_MESSAGE, PlanErrorCode.PLAN_STATUS_LOCKED);
}
// 结训预检 (All-or-Nothing 守卫:存在待报到、请假或报到数据异常学员时阻止结训)
for (PlanEnrollmentCompletionPort port : completionPorts)
{
port.precheckCompletion(planId);
}
Date completeTime = DateUtils.getNowDate();
TrainClassPlan statusUpdate = new TrainClassPlan();
statusUpdate.setPlanId(planId);
@@ -8,5 +8,13 @@ import java.util.Date;
*/
public interface PlanEnrollmentCompletionPort
{
/**
* 结训前预检参训人员状态完整性 (All-or-Nothing Precheck)。
* 若存在 0:待报到、2:请假、或 1:已报到但无报到记录异常,抛出异常阻止结训。
*
* @param planId 培训班ID
*/
default void precheckCompletion(String planId) {}
void completeEnrollments(String planId, String operator, Date completeTime);
}