From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsSxtJihuaServiceImpl.java |  501 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 501 insertions(+), 0 deletions(-)

diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsSxtJihuaServiceImpl.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsSxtJihuaServiceImpl.java
new file mode 100644
index 0000000..5e2c6e7
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsSxtJihuaServiceImpl.java
@@ -0,0 +1,501 @@
+package jnpf.limsService.impl;
+
+import jnpf.audit.sdk.annotation.AuditLog;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import jnpf.base.UserInfo;
+import jnpf.exception.DataException;
+import jnpf.limsEntity.BizStatus;
+import jnpf.limsEntity.LimsQingyandanEntity;
+import jnpf.limsEntity.LimsSxtQuyangJihuaEntity;
+import jnpf.limsEntity.LimsSxtQuyangJihuaZhongzhiEntity;
+import jnpf.limsEntity.LimsSxtQuyangZhongzhiShenqingEntity;
+import jnpf.limsEntity.LimsSxtQuyangZhongzhiShenqingZixiangEntity;
+import jnpf.limsMapper.LimsSxtQuyangJihuaMapper;
+import jnpf.limsMapper.LimsSxtQuyangJihuaZhongzhiMapper;
+import jnpf.limsMapper.LimsSxtQuyangZhongzhiShenqingMapper;
+import jnpf.limsMapper.LimsSxtQuyangZhongzhiShenqingZixiangMapper;
+import jnpf.limsMapper.LimsQingyandanMapper;
+import jnpf.limsService.LimsQingyandanService;
+import jnpf.limsService.LimsSxtJihuaService;
+import jnpf.limsService.LimsSxtQuyangJihuaRenwuService;
+import jnpf.limsService.event.LimsSxtPlanApprovedEvent;
+import jnpf.limsService.support.LimsSxtFlowStatusResolver;
+import jnpf.limsService.support.LimsSxtPlanStatusResolver;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 姘寸郴缁熷彇鏍疯鍒掑畾鏃朵换鍔★紝缁撴瀯鐓ф惉 LimsJianceTaskRemindServiceImpl銆�
+ *
+ * <p>娉ㄦ剰锛欯Scheduled 鏄繘绋嬪唴瀹氭椂鍣紝澶氬疄渚嬮儴缃蹭細姣忎釜瀹炰緥鍚勮Е鍙戜竴娆★紙閲嶅鍙戯級銆�
+ * 褰撳墠鎸夊崟瀹炰緥閮ㄧ讲锛屾棤姝ら棶棰橈紱鑻ュ皢鏉ユí鍚戞墿瀹癸紝闇�鍦� cronTrigger 鍏ュ彛鍔犲垎甯冨紡閿�
+ * 锛堝 Redis SETNX 褰撳ぉ key锛変繚璇佸崟鐐规墽琛屻��
+ */
+@Slf4j
+@Service
+public class LimsSxtJihuaServiceImpl implements LimsSxtJihuaService {
+
+    private static final Integer FLOW_STATE_APPROVED = 2;
+
+    private final ApplicationEventPublisher eventPublisher;
+
+    @Autowired
+    public LimsSxtJihuaServiceImpl(ApplicationEventPublisher eventPublisher) {
+        this.eventPublisher = eventPublisher;
+    }
+
+    @Autowired
+    private LimsSxtQuyangJihuaMapper jihuaMapper;
+    @Autowired
+    private LimsSxtQuyangJihuaZhongzhiMapper zhongzhiMapper;
+    @Autowired
+    private LimsSxtQuyangZhongzhiShenqingMapper quyangZhongzhiShenqingMapper;
+    @Autowired
+    private LimsSxtQuyangZhongzhiShenqingZixiangMapper quyangZhongzhiShenqingZixiangMapper;
+    @Autowired
+    private LimsQingyandanMapper qingyandanMapper;
+    @Autowired
+    private LimsQingyandanService qingyandanService;
+    @Autowired
+    private LimsSxtRenwuQingyandanZhuangtaiTongbuService renwuQingyandanZhuangtaiTongbuService;
+    @Autowired
+    private LimsSxtQuyangJihuaRenwuService renwuService;
+
+    @Override
+    public void runTodayJihua(boolean dryRun) {
+        shengchengDangriQingyandan(LocalDate.now(), dryRun);
+    }
+
+    @Override
+    @AuditLog(action = "PLAN_RUN", label = "鎵ц姘寸郴缁熷綋澶╄鍒�", bizType = "SXT",
+            bizCodeExpr = "#dryRun ? '' : 'SXT_PLAN_RUN'", targetTable = "lims_sxt_quyang_jihua_renwu")
+    public void runDailyJihua(LocalDate date, boolean dryRun) {
+        shengchengDangriQingyandan(date, dryRun);
+    }
+
+    @Override
+    @AuditLog(action = "PLAN_RUN", label = "鎵ц鎸囧畾姘寸郴缁熻鍒�", bizType = "SXT",
+            bizCodeExpr = "#jihuaId", bizCodeRequired = false, targetTable = "lims_sxt_quyang_jihua")
+    public void runJihua(String jihuaId) {
+        UserInfo user = UserProvider.getUser();
+        String tenantId = user == null || !StringUtils.hasText(user.getTenantId()) ? "0" : user.getTenantId();
+        int generated = renwuService.shengchengDaishengchengQingyandanByJihua(jihuaId, tenantId, LocalDate.now());
+        log.info("姘寸郴缁燂細鎵嬪姩鎵ц璁″垝 {}锛岀敓鎴� {} 寮犺楠屽崟", jihuaId, generated);
+    }
+
+    private void shengchengDangriQingyandan(LocalDate date, boolean dryRun) {
+        if (dryRun) {
+            log.info("姘寸郴缁燂細dry run 璺宠繃 {} 鐨勫緟鍔炰换鍔$敓鎴�", date);
+            return;
+        }
+        int generated = renwuService.shengchengDaishengchengQingyandan(date);
+        log.info("姘寸郴缁燂細鎵ц {} 鐨勫緟鍔炰换鍔★紝鐢熸垚 {} 寮犺楠屽崟锛宒ryRun={}", date, generated, dryRun);
+    }
+
+    @Override
+    public void createJihuaQuyangDan(LimsQingyandanEntity qingyandan) {
+        qingyandanService.sxtAutoSubmit(qingyandan);
+    }
+
+    @Override
+    public List<LimsQingyandanEntity> chaxunDaiquyangQingyandan(String jianyanLiushuihao, String quyangDidian) {
+        UserInfo user = UserProvider.getUser();
+        String tenantId = user == null || !StringUtils.hasText(user.getTenantId()) ? "0" : user.getTenantId();
+
+        LambdaQueryWrapper<LimsQingyandanEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsQingyandanEntity::getTenantId, tenantId)
+                .eq(LimsQingyandanEntity::getBizType, "SXT")
+                .eq(LimsQingyandanEntity::getQuyangStatus, BizStatus.PENDING_FETCH.getCode())
+                .and(item -> item.isNull(LimsQingyandanEntity::getDeleteMark)
+                        .or().ne(LimsQingyandanEntity::getDeleteMark, 1));
+        if (StringUtils.hasText(jianyanLiushuihao)) {
+            wrapper.like(LimsQingyandanEntity::getJianyanLiushuihao, jianyanLiushuihao.trim());
+        }
+        if (StringUtils.hasText(quyangDidian)) {
+            wrapper.like(LimsQingyandanEntity::getQuyangDidian, quyangDidian.trim());
+        }
+        wrapper.orderByAsc(LimsQingyandanEntity::getCreatorTime)
+                .orderByAsc(LimsQingyandanEntity::getId);
+        return qingyandanMapper.selectList(wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @AuditLog(action = "FLOW_START", label = "姘寸郴缁熻鍒掓祦绋嬪彂璧�", bizType = "SXT",
+            bizCodeExpr = "#flowId", bizCodeRequired = false, targetTable = "lims_sxt_quyang_jihua")
+    public void syncFlowStarted(String flowId, String taskId) {
+        validateFlowKey(flowId, taskId);
+        LimsSxtQuyangJihuaEntity jihua = findJihuaByFlow(flowId, taskId);
+        LimsSxtQuyangJihuaZhongzhiEntity zhongzhi = findZhongzhiByFlow(flowId, taskId);
+        LimsSxtQuyangZhongzhiShenqingEntity quyangZhongzhiShenqing = findQuyangZhongzhiShenqingByFlow(flowId, taskId);
+        ensureSingleBusiness(jihua, zhongzhi, quyangZhongzhiShenqing, flowId, taskId);
+
+        if (jihua != null) {
+            syncJihuaStarted(jihua, flowId, taskId);
+        } else if (zhongzhi != null) {
+            syncZhongzhiStarted(zhongzhi, flowId, taskId);
+        } else {
+            syncQuyangZhongzhiShenqingStarted(quyangZhongzhiShenqing);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @AuditLog(action = "FLOW_END", label = "姘寸郴缁熻鍒掓祦绋嬬粨鏉�", bizType = "SXT",
+            bizCodeExpr = "#flowId", bizCodeRequired = false, targetTable = "lims_sxt_quyang_jihua")
+    public void syncFlowEnded(String flowId, String taskId, Integer flowState) {
+        syncFlowEndedStatus(flowId, taskId, flowState);
+    }
+
+    private void syncFlowEndedStatus(String flowId, String taskId, Integer flowState) {
+        validateFlowKey(flowId, taskId);
+        String targetStatus = LimsSxtFlowStatusResolver.resolveBizStatus(flowState)
+                .orElseThrow(() -> new DataException("鏈煡鐨勫伐浣滄祦鐘舵�侊細" + flowState));
+        if (!LimsSxtFlowStatusResolver.COMPLETED.equals(targetStatus)) {
+            throw new DataException("娴佺▼灏氭湭缁撴潫锛屽綋鍓嶇姸鎬侊細" + flowState);
+        }
+
+        LimsSxtQuyangJihuaEntity jihua = findJihuaByFlow(flowId, taskId);
+        LimsSxtQuyangJihuaZhongzhiEntity zhongzhi = findZhongzhiByFlow(flowId, taskId);
+        LimsSxtQuyangZhongzhiShenqingEntity quyangZhongzhiShenqing = findQuyangZhongzhiShenqingByFlow(flowId, taskId);
+        ensureSingleBusiness(jihua, zhongzhi, quyangZhongzhiShenqing, flowId, taskId);
+
+        if (jihua != null) {
+            syncJihuaEnded(jihua, flowId, taskId, flowState, targetStatus);
+        } else if (zhongzhi != null) {
+            syncZhongzhiEnded(zhongzhi, flowId, taskId, flowState, targetStatus);
+        } else {
+            syncQuyangZhongzhiShenqingEnded(quyangZhongzhiShenqing, flowState, targetStatus);
+        }
+    }
+
+    private void syncJihuaStarted(LimsSxtQuyangJihuaEntity jihua, String flowId, String taskId) {
+        if (LimsSxtFlowStatusResolver.COMPLETED.equals(jihua.getBizStatus())) {
+            return;
+        }
+        boolean changed = !Objects.equals(jihua.getBizStatus(), LimsSxtFlowStatusResolver.PROCESSING)
+                || !Objects.equals(jihua.getPlanStatus(), LimsSxtPlanStatusResolver.DISABLED);
+        if (!changed) {
+            return;
+        }
+        if (!markJihuaStarted(jihua.getId())) {
+            return;
+        }
+    }
+
+    private void syncZhongzhiStarted(LimsSxtQuyangJihuaZhongzhiEntity zhongzhi, String flowId, String taskId) {
+        if (LimsSxtFlowStatusResolver.COMPLETED.equals(zhongzhi.getBizStatus())) {
+            return;
+        }
+        if (!Objects.equals(zhongzhi.getBizStatus(), LimsSxtFlowStatusResolver.PROCESSING)) {
+            if (!markZhongzhiStarted(zhongzhi.getId())) {
+                return;
+            }
+        }
+        markApprovedJihuaTerminating(zhongzhi, flowId, taskId);
+    }
+
+    private void syncJihuaEnded(LimsSxtQuyangJihuaEntity jihua, String flowId, String taskId,
+                                Integer flowState, String targetStatus) {
+        boolean passed = LimsSxtFlowStatusResolver.isApproved(flowState);
+        String targetPlanStatus = passed
+                ? LimsSxtPlanStatusResolver.AVAILABLE : LimsSxtPlanStatusResolver.DISABLED;
+        boolean changed = !Objects.equals(jihua.getBizStatus(), targetStatus)
+                || !Objects.equals(jihua.getPlanStatus(), targetPlanStatus);
+        if (changed) {
+            updateJihua(jihua.getId(), targetStatus, targetPlanStatus);
+        }
+        if (passed) {
+            eventPublisher.publishEvent(new LimsSxtPlanApprovedEvent(jihua.getId(), jihua.getFTenantId()));
+        }
+    }
+
+    private void syncZhongzhiEnded(LimsSxtQuyangJihuaZhongzhiEntity zhongzhi, String flowId, String taskId,
+                                   Integer flowState, String targetStatus) {
+        if (!Objects.equals(zhongzhi.getBizStatus(), targetStatus)) {
+            updateZhongzhi(zhongzhi.getId(), targetStatus);
+        }
+        syncApprovedJihuaTerminationStatus(zhongzhi, flowId, taskId, flowState);
+    }
+
+    private void syncQuyangZhongzhiShenqingStarted(LimsSxtQuyangZhongzhiShenqingEntity shenqing) {
+        if (LimsSxtFlowStatusResolver.COMPLETED.equals(shenqing.getBizStatus())
+                || Objects.equals(shenqing.getBizStatus(), LimsSxtFlowStatusResolver.PROCESSING)) {
+            return;
+        }
+        if (!markQuyangZhongzhiShenqingStarted(shenqing)) {
+            return;
+        }
+    }
+
+    private void syncQuyangZhongzhiShenqingEnded(LimsSxtQuyangZhongzhiShenqingEntity shenqing,
+                                                  Integer flowState, String targetStatus) {
+        if (!Objects.equals(shenqing.getBizStatus(), targetStatus)) {
+            updateQuyangZhongzhiShenqing(shenqing, targetStatus);
+        }
+        if (LimsSxtFlowStatusResolver.isApproved(flowState)) {
+            syncApprovedQuyangTerminationStatus(shenqing);
+        }
+    }
+
+    private void syncApprovedQuyangTerminationStatus(LimsSxtQuyangZhongzhiShenqingEntity shenqing) {
+        List<LimsSxtQuyangZhongzhiShenqingZixiangEntity> children = listActiveQuyangZhongzhiChildren(
+                shenqing.getId(), shenqing.getFTenantId());
+        int updated = 0;
+        for (LimsSxtQuyangZhongzhiShenqingZixiangEntity child : children) {
+            if (!StringUtils.hasText(child.getQingyandanId())) {
+                log.warn("鍙栨牱缁堟鐢宠瀛愯〃鏈叧鑱旇楠屽崟锛宑hildId={}", child.getId());
+                continue;
+            }
+            if (terminatePendingQingyandan(child)) {
+                updated++;
+            }
+        }
+        log.info("鍙栨牱缁堟鐢宠瀹℃壒閫氳繃锛屽悓姝ョ粓姝� {} 寮犲緟鍙栨牱璇烽獙鍗曪紝terminationId={}", updated, shenqing.getId());
+    }
+
+    private void markApprovedJihuaTerminating(LimsSxtQuyangJihuaZhongzhiEntity zhongzhi, String flowId,
+                                              String taskId) {
+        if (!StringUtils.hasText(zhongzhi.getJihuaMingcheng())) {
+            log.warn("璁″垝缁堟鐢宠宸插彂璧蜂絾鏈叧鑱斿師鍙栨牱璁″垝锛宼erminationId={}", zhongzhi.getId());
+            return;
+        }
+        LimsSxtQuyangJihuaEntity jihua = findApprovedJihua(zhongzhi.getJihuaMingcheng(), zhongzhi.getFTenantId());
+        if (jihua == null) {
+            log.warn("璁″垝缁堟鐢宠宸插彂璧凤紝浣嗗師鍙栨牱璁″垝涓嶆槸宸插鎵归�氳繃鐘舵�侊紝terminationId={}, jihuaId={}",
+                    zhongzhi.getId(), zhongzhi.getJihuaMingcheng());
+            return;
+        }
+        if (!Objects.equals(jihua.getPlanStatus(), LimsSxtPlanStatusResolver.AVAILABLE)) {
+            return;
+        }
+        if (!updateJihuaPlanStatus(jihua.getId(), jihua.getPlanStatus(), LimsSxtPlanStatusResolver.TERMINATING)) {
+            return;
+        }
+    }
+
+    private void syncApprovedJihuaTerminationStatus(LimsSxtQuyangJihuaZhongzhiEntity zhongzhi, String flowId,
+                                                    String taskId, Integer flowState) {
+        if (!StringUtils.hasText(zhongzhi.getJihuaMingcheng())) {
+            log.warn("璁″垝缁堟鐢宠宸插姙缁撲絾鏈叧鑱斿師鍙栨牱璁″垝锛宼erminationId={}", zhongzhi.getId());
+            return;
+        }
+        LimsSxtQuyangJihuaEntity jihua = findApprovedJihua(zhongzhi.getJihuaMingcheng(), zhongzhi.getFTenantId());
+        if (jihua == null) {
+            log.warn("璁″垝缁堟鐢宠宸插姙缁擄紝浣嗗師鍙栨牱璁″垝涓嶆槸宸插鎵归�氳繃鐘舵�侊紝terminationId={}, jihuaId={}",
+                    zhongzhi.getId(), zhongzhi.getJihuaMingcheng());
+            return;
+        }
+        String targetPlanStatus = LimsSxtPlanStatusResolver.resolveTerminationStatus(jihua.getPlanStatus(), flowState);
+        if (Objects.equals(jihua.getPlanStatus(), targetPlanStatus)) {
+            return;
+        }
+        if (!updateJihuaPlanStatus(jihua.getId(), jihua.getPlanStatus(), targetPlanStatus)) {
+            return;
+        }
+        boolean passed = LimsSxtFlowStatusResolver.isApproved(flowState);
+        if (passed && LimsSxtPlanStatusResolver.TERMINATED.equals(targetPlanStatus)) {
+            renwuService.quxiaoWeishengchengRenwuByJihua(
+                    jihua.getId(), jihua.getFTenantId(), "plan_terminated");
+        }
+    }
+
+    private void updateJihua(String id, String bizStatus, String planStatus) {
+        LambdaUpdateWrapper<LimsSxtQuyangJihuaEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaEntity::getId, id)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getFDeleteMark, 1))
+                .set(LimsSxtQuyangJihuaEntity::getBizStatus, bizStatus)
+                .set(LimsSxtQuyangJihuaEntity::getPlanStatus, planStatus);
+        if (jihuaMapper.update(null, wrapper) != 1) {
+            throw new DataException("鏇存柊鍙栨牱璁″垝鐘舵�佸け璐�");
+        }
+    }
+
+    private boolean updateJihuaPlanStatus(String id, String currentPlanStatus, String targetPlanStatus) {
+        LambdaUpdateWrapper<LimsSxtQuyangJihuaEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaEntity::getId, id)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getFDeleteMark, 1))
+                .eq(LimsSxtQuyangJihuaEntity::getPlanStatus, currentPlanStatus)
+                .set(LimsSxtQuyangJihuaEntity::getPlanStatus, targetPlanStatus);
+        return jihuaMapper.update(null, wrapper) == 1;
+    }
+
+    /**
+     * 璧峰浜嬩欢鍙兘鎶婃湭鍔炵粨璁板綍鎺ㄨ繘鍒板湪鍔烇紝閬垮厤寤惰繜/閲嶆斁浜嬩欢瑕嗙洊缁撴潫浜嬩欢鐨勬渶缁堢粨鏋溿��
+     */
+    private boolean markJihuaStarted(String id) {
+        LambdaUpdateWrapper<LimsSxtQuyangJihuaEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaEntity::getId, id)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getFDeleteMark, 1))
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getBizStatus)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getBizStatus, LimsSxtFlowStatusResolver.COMPLETED))
+                .set(LimsSxtQuyangJihuaEntity::getBizStatus, LimsSxtFlowStatusResolver.PROCESSING)
+                .set(LimsSxtQuyangJihuaEntity::getPlanStatus, LimsSxtPlanStatusResolver.DISABLED);
+        return jihuaMapper.update(null, wrapper) > 0;
+    }
+
+    private void updateZhongzhi(String id, String bizStatus) {
+        LambdaUpdateWrapper<LimsSxtQuyangJihuaZhongzhiEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaZhongzhiEntity::getId, id)
+                .set(LimsSxtQuyangJihuaZhongzhiEntity::getBizStatus, bizStatus);
+        if (zhongzhiMapper.update(null, wrapper) != 1) {
+            throw new DataException("鏇存柊璁″垝缁堟鐢宠鐘舵�佸け璐�");
+        }
+    }
+
+    private boolean markZhongzhiStarted(String id) {
+        LambdaUpdateWrapper<LimsSxtQuyangJihuaZhongzhiEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaZhongzhiEntity::getId, id)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaZhongzhiEntity::getBizStatus)
+                        .or().ne(LimsSxtQuyangJihuaZhongzhiEntity::getBizStatus, LimsSxtFlowStatusResolver.COMPLETED))
+                .set(LimsSxtQuyangJihuaZhongzhiEntity::getBizStatus, LimsSxtFlowStatusResolver.PROCESSING);
+        return zhongzhiMapper.update(null, wrapper) > 0;
+    }
+
+    private void updateQuyangZhongzhiShenqing(LimsSxtQuyangZhongzhiShenqingEntity shenqing, String bizStatus) {
+        LambdaUpdateWrapper<LimsSxtQuyangZhongzhiShenqingEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangZhongzhiShenqingEntity::getId, shenqing.getId())
+                .eq(LimsSxtQuyangZhongzhiShenqingEntity::getFTenantId, shenqing.getFTenantId())
+                .and(item -> item.isNull(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark, 1))
+                .set(LimsSxtQuyangZhongzhiShenqingEntity::getBizStatus, bizStatus);
+        if (quyangZhongzhiShenqingMapper.update(null, wrapper) != 1) {
+            throw new DataException("鏇存柊鍙栨牱缁堟鐢宠鐘舵�佸け璐�");
+        }
+    }
+
+    private boolean markQuyangZhongzhiShenqingStarted(LimsSxtQuyangZhongzhiShenqingEntity shenqing) {
+        LambdaUpdateWrapper<LimsSxtQuyangZhongzhiShenqingEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsSxtQuyangZhongzhiShenqingEntity::getId, shenqing.getId())
+                .eq(LimsSxtQuyangZhongzhiShenqingEntity::getFTenantId, shenqing.getFTenantId())
+                .and(item -> item.isNull(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark, 1))
+                .and(item -> item.isNull(LimsSxtQuyangZhongzhiShenqingEntity::getBizStatus)
+                        .or().ne(LimsSxtQuyangZhongzhiShenqingEntity::getBizStatus, LimsSxtFlowStatusResolver.COMPLETED))
+                .set(LimsSxtQuyangZhongzhiShenqingEntity::getBizStatus, LimsSxtFlowStatusResolver.PROCESSING);
+        return quyangZhongzhiShenqingMapper.update(null, wrapper) > 0;
+    }
+
+    private List<LimsSxtQuyangZhongzhiShenqingZixiangEntity> listActiveQuyangZhongzhiChildren(String shenqingId,
+                                                                                                  String tenantId) {
+        LambdaQueryWrapper<LimsSxtQuyangZhongzhiShenqingZixiangEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsSxtQuyangZhongzhiShenqingZixiangEntity::getFForeignId, shenqingId)
+                .eq(LimsSxtQuyangZhongzhiShenqingZixiangEntity::getFTenantId, tenantId)
+                .and(item -> item.isNull(LimsSxtQuyangZhongzhiShenqingZixiangEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangZhongzhiShenqingZixiangEntity::getFDeleteMark, 1));
+        return quyangZhongzhiShenqingZixiangMapper.selectList(wrapper);
+    }
+
+    private boolean terminatePendingQingyandan(LimsSxtQuyangZhongzhiShenqingZixiangEntity child) {
+        LimsQingyandanEntity qingyandan = qingyandanMapper.selectById(child.getQingyandanId());
+        if (qingyandan == null) {
+            return false;
+        }
+        LambdaUpdateWrapper<LimsQingyandanEntity> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(LimsQingyandanEntity::getId, child.getQingyandanId())
+                .eq(LimsQingyandanEntity::getTenantId, child.getFTenantId())
+                .eq(LimsQingyandanEntity::getBizType, "SXT")
+                .eq(LimsQingyandanEntity::getQuyangStatus, BizStatus.PENDING_FETCH.getCode())
+                .and(item -> item.isNull(LimsQingyandanEntity::getDeleteMark)
+                        .or().ne(LimsQingyandanEntity::getDeleteMark, 1))
+                .set(LimsQingyandanEntity::getQuyangStatus, BizStatus.DELETED.getCode());
+        if (qingyandanMapper.update(null, wrapper) != 1) {
+            return false;
+        }
+        qingyandan.setQuyangStatus(BizStatus.DELETED.getCode());
+        renwuQingyandanZhuangtaiTongbuService.tongbu(qingyandan, "quyang_zhongzhi_tongguo");
+        return true;
+    }
+
+    private LimsSxtQuyangJihuaEntity findJihuaByFlow(String flowId, String taskId) {
+        LambdaQueryWrapper<LimsSxtQuyangJihuaEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaEntity::getFFlowId, flowId)
+                .eq(LimsSxtQuyangJihuaEntity::getFFlowTaskId, taskId)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getFDeleteMark, 1));
+        List<LimsSxtQuyangJihuaEntity> list = jihuaMapper.selectList(wrapper);
+        if (list.size() > 1) {
+            throw new DataException("澶氫釜鍙栨牱璁″垝鍏宠仈鍚屼竴娴佺▼浠诲姟锛歵ask_id=" + taskId);
+        }
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    private LimsSxtQuyangJihuaZhongzhiEntity findZhongzhiByFlow(String flowId, String taskId) {
+        LambdaQueryWrapper<LimsSxtQuyangJihuaZhongzhiEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaZhongzhiEntity::getFFlowId, flowId)
+                .eq(LimsSxtQuyangJihuaZhongzhiEntity::getFFlowTaskId, taskId);
+        List<LimsSxtQuyangJihuaZhongzhiEntity> list = zhongzhiMapper.selectList(wrapper);
+        if (list.size() > 1) {
+            throw new DataException("澶氫釜璁″垝缁堟鐢宠鍏宠仈鍚屼竴娴佺▼浠诲姟锛歵ask_id=" + taskId);
+        }
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    private LimsSxtQuyangZhongzhiShenqingEntity findQuyangZhongzhiShenqingByFlow(String flowId, String taskId) {
+        LambdaQueryWrapper<LimsSxtQuyangZhongzhiShenqingEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsSxtQuyangZhongzhiShenqingEntity::getFFlowId, flowId)
+                .eq(LimsSxtQuyangZhongzhiShenqingEntity::getFFlowTaskId, taskId)
+                .and(item -> item.isNull(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangZhongzhiShenqingEntity::getFDeleteMark, 1));
+        List<LimsSxtQuyangZhongzhiShenqingEntity> list = quyangZhongzhiShenqingMapper.selectList(wrapper);
+        if (list.size() > 1) {
+            throw new DataException("澶氫釜鍙栨牱缁堟鐢宠鍏宠仈鍚屼竴娴佺▼浠诲姟锛歵ask_id=" + taskId);
+        }
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    private LimsSxtQuyangJihuaEntity findApprovedJihua(String jihuaId, String tenantId) {
+        LambdaQueryWrapper<LimsSxtQuyangJihuaEntity> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LimsSxtQuyangJihuaEntity::getId, jihuaId)
+                .eq(LimsSxtQuyangJihuaEntity::getFFlowState, FLOW_STATE_APPROVED)
+                .and(item -> item.isNull(LimsSxtQuyangJihuaEntity::getFDeleteMark)
+                        .or().ne(LimsSxtQuyangJihuaEntity::getFDeleteMark, 1));
+        if (StringUtils.hasText(tenantId)) {
+            wrapper.eq(LimsSxtQuyangJihuaEntity::getFTenantId, tenantId);
+        }
+        List<LimsSxtQuyangJihuaEntity> list = jihuaMapper.selectList(wrapper);
+        if (list.size() > 1) {
+            throw new DataException("澶氫釜宸插鎵瑰彇鏍疯鍒掍娇鐢ㄧ浉鍚屼富閿細jihuaId=" + jihuaId);
+        }
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    private void ensureSingleBusiness(LimsSxtQuyangJihuaEntity jihua,
+                                      LimsSxtQuyangJihuaZhongzhiEntity zhongzhi,
+                                      LimsSxtQuyangZhongzhiShenqingEntity quyangZhongzhiShenqing,
+                                      String flowId, String taskId) {
+        int businessCount = (jihua == null ? 0 : 1)
+                + (zhongzhi == null ? 0 : 1)
+                + (quyangZhongzhiShenqing == null ? 0 : 1);
+        if (businessCount == 0) {
+            throw new DataException("鏈壘鍒版祦绋嬪叧鑱旂殑鍙栨牱璁″垝銆佽鍒掔粓姝㈢敵璇锋垨鍙栨牱缁堟鐢宠锛歠low_id=" + flowId + ", task_id=" + taskId);
+        }
+        if (businessCount > 1) {
+            throw new DataException("娴佺▼浠诲姟鍏宠仈浜嗗涓按绯荤粺涓氬姟璁板綍锛歵ask_id=" + taskId);
+        }
+    }
+
+    private void validateFlowKey(String flowId, String taskId) {
+        if (!StringUtils.hasText(flowId)) {
+            throw new DataException("娴佺▼id(flow_id)涓嶈兘涓虹┖");
+        }
+        if (!StringUtils.hasText(taskId)) {
+            throw new DataException("娴佺▼浠诲姟id(task_id)涓嶈兘涓虹┖");
+        }
+    }
+
+}

--
Gitblit v1.8.0