From 5a90ac8955f198f21954a3dca0443d1c5892bf0b Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期二, 03 十一月 2026 18:08:29 +0800
Subject: [PATCH] 成品下单批量下单接口与检验委托单批次合并(batch_no),含数据库加列脚本

---
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java |  233 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 182 insertions(+), 51 deletions(-)

diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
index f4b1b84..891bdac 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -55,6 +55,7 @@
 import com.ruoyi.inspect.vo.TemplateConditionVo;
 import com.ruoyi.system.mapper.UserMapper;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.context.ApplicationEventPublisher;
@@ -80,6 +81,7 @@
  * @description 閽堝琛ㄣ�恑ns_order(妫�楠屼笅鍗�)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
  * @createDate 2024-03-12 16:17:55
  */
+@Slf4j
 @Service
 @AllArgsConstructor
 public class InsOrderServiceImpl extends ServiceImpl<InsOrderMapper, InsOrder>
@@ -300,6 +302,9 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int addInsOrder(List<SampleProductDto> list, InsOrder insOrder) {
+        if (insOrder == null || insOrder.getSampleDate() == null) {
+            throw new ErrorException("閫佹牱鏃ユ湡涓嶈兘涓虹┖");
+        }
         // todo: 涓嬪崟鍒ゆ柇鎶芥牱璁″垝鐨勫敮涓�鎬�
         if (insOrder.getQuarterItemId() != null) {
             Long quarterItemCount = insOrderMapper.selectCount(Wrappers.<InsOrder>lambdaQuery()
@@ -502,6 +507,64 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int addNewJuInsOrder(InsPlaceOrderDto dto) {
+        return createNewJuOrder(dto, null, false);
+    }
+
+    /**
+     * 鎵归噺涓嬪崟锛氬叕鍏卞鎵樹俊鎭彧濉竴娆★紝鍚庡彴鎸夋牱鍝侀�愭潯鎷嗘垚鐙珛濮旀墭鍗曞苟鍏变韩鎵规鍙枫��
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int addBatchNewJuInsOrder(InsBatchPlaceOrderDto dto) {
+        if (dto == null || dto.getInsOrder() == null) {
+            throw new ErrorException("涓嬪崟淇℃伅涓嶈兘涓虹┖");
+        }
+        List<InsBatchSampleDto> rows = dto.getSampleList();
+        if (CollectionUtils.isEmpty(rows)) {
+            throw new ErrorException("璇疯嚦灏戞坊鍔犱竴涓牱鍝�");
+        }
+        // 鍙湁涓�涓牱鍝佹椂鎸夋櫘閫氬崟鏍峰搧涓嬪崟澶勭悊锛屼笉浜х敓鎵规
+        if (rows.size() == 1) {
+            return createNewJuOrder(buildBatchRowOrder(dto.getInsOrder(), rows.get(0)), null, false);
+        }
+        String batchNo = "PC" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS");
+        int firstOrderId = 0;
+        for (InsBatchSampleDto row : rows) {
+            int orderId = createNewJuOrder(buildBatchRowOrder(dto.getInsOrder(), row), batchNo, true);
+            if (firstOrderId == 0) {
+                firstOrderId = orderId;
+            }
+        }
+        return firstOrderId;
+    }
+
+    private InsPlaceOrderDto buildBatchRowOrder(InsOrder common, InsBatchSampleDto row) {
+        if (common == null || row == null) {
+            throw new ErrorException("涓嬪崟淇℃伅涓嶈兘涓虹┖");
+        }
+        if (row.getStandardTreeId() == null) {
+            throw new ErrorException("璇蜂负姣忎釜鏍峰搧閫夋嫨妫�娴嬩緷鎹�");
+        }
+        if (StringUtils.isBlank(row.getSampleCode()) || row.getSampleCode().trim().length() < 2) {
+            throw new ErrorException("鏍峰搧缂栧彿涓嶈兘涓虹┖涓斾笉鑳藉皯浜�2浣�");
+        }
+        InsOrder order = new InsOrder();
+        BeanUtils.copyProperties(common, order);
+        order.setId(null);
+        order.setEntrustCode(null);
+        order.setBatchNo(null);
+        order.setSampleView(row.getSampleView());
+        order.setTestQuantity(row.getTestQuantity());
+        order.setSampleStatus(row.getSampleStatus());
+        InsPlaceOrderDto single = new InsPlaceOrderDto();
+        single.setInsOrder(order);
+        single.setStandardTreeId(row.getStandardTreeId());
+        single.setSampleCode(row.getSampleCode());
+        single.setTemplateList(row.getTemplateList());
+        return single;
+    }
+
+    private int createNewJuOrder(InsPlaceOrderDto dto, String batchNo, boolean batchEntrustFallback) {
         if (dto == null || dto.getInsOrder() == null || dto.getStandardTreeId() == null) {
             throw new ErrorException("涓嬪崟淇℃伅鎴栨爣鍑嗕笉鑳戒负绌�");
         }
@@ -593,6 +656,7 @@
 
         InsOrder order = dto.getInsOrder();
         order.setId(null);
+        order.setBatchNo(StringUtils.isBlank(batchNo) ? null : batchNo);
         // 鏂拌仛涓嬪崟鍏嶅鏍革細鐩存帴鍙楃悊锛屼笅鍗曞嵆娴佽浆鍒版牱鍝佹帴鏀�
         order.setState(1);
         order.setExamineTime(LocalDateTime.now());
@@ -653,6 +717,10 @@
 
         // 涓嬪崟鏃剁敓鎴愬鎵樼紪鍙峰苟鏍¢獙鍞竴鎬э紝閲嶅鍒欐彁绀猴紝閬垮厤鐣欏埌瀹℃牳鎵嶆姤閿欍��
         String entrustCode = buildEntrustCode(order, Collections.singletonList(sample));
+        if (batchEntrustFallback && isEntrustCodeUsed(entrustCode)) {
+            // 鎵归噺涓嬪崟鏃朵笉鍚屾牱鍝佺紪鍙锋湯涓や綅鍙兘鐩稿悓锛屾敼鐢ㄥ綋澶╅『寤剁紪鍙峰厹搴�
+            entrustCode = buildNextAvailableEntrustCode(order);
+        }
         assertEntrustCodeUnique(entrustCode, order.getId());
         insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate()
                 .eq(InsOrder::getId, order.getId())
@@ -844,6 +912,7 @@
             snapshot.setTemplateId(template.getId());
             snapshot.setName(template.getName());
             snapshot.setNumber(template.getNumber());
+            snapshot.setStandardRequirement(template.getStandardRequirement());
             snapshot.setRemark(template.getRemark());
             snapshot.setThing(template.getThing());
             snapshot.setSort(selection.getSort());
@@ -1044,6 +1113,23 @@
         }
     }
 
+    private boolean isEntrustCodeUsed(String entrustCode) {
+        return StringUtils.isNotBlank(entrustCode) && insOrderMapper.selectCount(Wrappers.<InsOrder>lambdaQuery()
+                .eq(InsOrder::getEntrustCode, entrustCode)) > 0;
+    }
+
+    private String buildNextAvailableEntrustCode(InsOrder order) {
+        LocalDate entrustDate = order.getSampleDate() == null ? LocalDate.now() : order.getSampleDate();
+        String prefix = "LMSY-" + entrustDate.format(DateTimeFormatter.BASIC_ISO_DATE) + "-";
+        for (int seq = 1; seq <= 99; seq++) {
+            String candidate = prefix + String.format("%02d", seq);
+            if (!isEntrustCodeUsed(candidate)) {
+                return candidate;
+            }
+        }
+        throw new ErrorException("褰撳ぉ濮旀墭缂栧彿宸茬敤灏斤紝璇疯皟鏁存牱鍝佺紪鍙�");
+    }
+
     /**
      * 鐢熸垚濮旀墭缂栧彿锛氭柊鑱氱洿缁戞ā鏉胯鍗曟湯涓や綅鍙栨牱鍝佺紪鍙锋湯涓や綅锛屽叾浣欐寜閫佹牱鏃ユ湡鐢熸垚搴忓彿銆�
      */
@@ -1067,7 +1153,11 @@
     @Transactional(rollbackFor = Exception.class)
     public Map<String, Object> getInsOrderAndSample(Integer id, String laboratory) {
         Map<String, Object> map = new HashMap<>();
-        initializeTemplateDevicesOnFirstOpen(id);
+        try {
+            initializeTemplateDevicesOnFirstOpen(id, laboratory);
+        } catch (RuntimeException e) {
+            log.warn("妫�楠屼换鍔¢粯璁よ澶囧悓姝ュけ璐ワ紝orderId={}", id, e);
+        }
 //        InsOrder insOrder = insOrderMapper.selectById(id);
         IfsOrderVO ifsOrderVO = insOrderMapper.selectOrderInfoById(id);
         Map<Integer, List<Integer>> templateDeviceIds = insOrderTemplateDeviceMapper.selectList(
@@ -1085,6 +1175,7 @@
                                 .select(InsOrderStandardTemplate::getTemplateId,
                                         InsOrderStandardTemplate::getTemperature,
                                         InsOrderStandardTemplate::getDetectionTime,
+                                        InsOrderStandardTemplate::getDetectionEndTime,
                                         InsOrderStandardTemplate::getDetectionPlace,
                                         InsOrderStandardTemplate::getInsResult)
                                 .orderByAsc(InsOrderStandardTemplate::getSort,
@@ -1094,6 +1185,8 @@
                     condition.setTemplateId(snapshot.getTemplateId());
                     condition.setTemperature(snapshot.getTemperature());
                     condition.setDetectionTime(snapshot.getDetectionTime());
+                    condition.setDetectionEndTime(snapshot.getDetectionEndTime() == null
+                            ? snapshot.getDetectionTime() : snapshot.getDetectionEndTime());
                     condition.setDetectionPlace(snapshot.getDetectionPlace());
                     condition.setInsResult(snapshot.getInsResult());
                     condition.setDeviceIds(templateDeviceIds.getOrDefault(
@@ -1110,18 +1203,34 @@
         return map;
     }
 
-    /** 棣栨鎵撳紑妫�楠屼换鍔℃椂锛屽皢浠嶄负绌虹殑妯℃澘璁惧浠庡搴旀爣鍑嗚ˉ鍏ヨ鍗曘�� */
-    private void initializeTemplateDevicesOnFirstOpen(Integer orderId) {
+    /**
+     * 鎵撳紑妫�楠屼换鍔℃椂锛屾妸灏氭湭琚汉宸ユ敼鍔ㄨ繃鐨勬ā鏉胯澶囧悓姝ヤ负鏍囧噯搴撳綋鍓嶇粦瀹氱殑璁惧锛�
+     * 妫�楠屽憳鎵嬪姩澧炲垹杩囩殑妯℃澘浠ヤ汉宸ヤ负鍑嗭紝涓嶅啀鑷姩濉厖銆�
+     */
+    private void initializeTemplateDevicesOnFirstOpen(Integer orderId, String laboratory) {
         InsOrder order = insOrderMapper.selectById(orderId);
-        if (order == null || !DIRECT_TEMPLATE_LABORATORY.equals(order.getLaboratory())
-                || !Objects.equals(order.getTypeSource(), -1)
+        if (order == null || !Objects.equals(order.getTypeSource(), -1)
                 || !Objects.equals(order.getState(), 1)
                 || "QUALITY_MONITOR".equals(order.getTaskSource())) {
             return;
         }
+        if (StringUtils.isNotBlank(laboratory)) {
+            InsOrderState orderState = insOrderStateService.getOne(Wrappers.<InsOrderState>lambdaQuery()
+                    .eq(InsOrderState::getInsOrderId, orderId)
+                    .eq(InsOrderState::getLaboratory, laboratory)
+                    .last("limit 1"));
+            // 浠呭緟妫�銆佸湪妫�闃舵鍚屾锛涜繘鍏ュ鏍哥瓑鍚庣画鐘舵�佸悗浠ヤ繚瀛樹笅鏉ョ殑璁惧涓哄噯銆�
+            if (orderState != null && orderState.getInsState() != null
+                    && orderState.getInsState() != 0 && orderState.getInsState() != 1) {
+                return;
+            }
+        }
         List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateMapper.selectList(
                 Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                         .eq(InsOrderStandardTemplate::getInsOrderId, orderId)
+                        .select(InsOrderStandardTemplate::getId,
+                                InsOrderStandardTemplate::getTemplateId,
+                                InsOrderStandardTemplate::getDeviceDefaultsInitialized)
                         .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)
                         .last("FOR UPDATE"));
         if (snapshots.isEmpty() || snapshots.stream().allMatch(
@@ -1129,41 +1238,57 @@
             return;
         }
 
-        Set<Integer> existingTemplateIds = insOrderTemplateDeviceMapper.selectList(
-                Wrappers.<InsOrderTemplateDevice>lambdaQuery()
-                        .eq(InsOrderTemplateDevice::getInsOrderId, orderId))
-                .stream().map(InsOrderTemplateDevice::getTemplateId)
-                .filter(Objects::nonNull).collect(Collectors.toSet());
-        boolean inspectionStarted = order.getFirstInspectDate() != null
-                || (order.getInsState() != null && order.getInsState() > 0)
-                || snapshots.stream().anyMatch(snapshot -> StringUtils.isNotBlank(snapshot.getRecordValues())
-                        || snapshot.getDetectionTime() != null || snapshot.getTemperature() != null
-                        || snapshot.getDetectionPlace() != null);
-        Map<Integer, List<Integer>> defaults = inspectionStarted ? Collections.emptyMap()
-                : findStandardDeviceDefaults(order, snapshots);
+        Map<Integer, List<InsOrderTemplateDevice>> existingDevices = insOrderTemplateDeviceMapper.selectList(
+                        Wrappers.<InsOrderTemplateDevice>lambdaQuery()
+                                .eq(InsOrderTemplateDevice::getInsOrderId, orderId)
+                                .orderByAsc(InsOrderTemplateDevice::getSort, InsOrderTemplateDevice::getId))
+                .stream().filter(relation -> relation.getTemplateId() != null)
+                .collect(Collectors.groupingBy(InsOrderTemplateDevice::getTemplateId));
+        Map<Integer, List<Integer>> defaults = findStandardDeviceDefaults(order, snapshots);
 
         for (InsOrderStandardTemplate snapshot : snapshots) {
+            // 妫�楠屽憳鎵嬪姩閫夋嫨鎴栨竻绌鸿繃鐨勬ā鏉夸互浜哄伐涓哄噯锛屼笉鍐嶅鐢ㄦ爣鍑嗗簱榛樿鍊笺��
             if (Objects.equals(snapshot.getDeviceDefaultsInitialized(), 1)) {
                 continue;
             }
             Integer templateId = snapshot.getTemplateId();
-            if (!inspectionStarted && !existingTemplateIds.contains(templateId)
-                    && defaults.containsKey(templateId)) {
-                List<Integer> deviceIds = defaults.get(templateId);
-                for (int index = 0; index < deviceIds.size(); index++) {
-                    InsOrderTemplateDevice relation = new InsOrderTemplateDevice();
-                    relation.setInsOrderId(orderId);
-                    relation.setTemplateId(templateId);
-                    relation.setDeviceId(deviceIds.get(index));
-                    relation.setSort(index);
-                    insOrderTemplateDeviceMapper.insert(relation);
-                }
+            if (templateId == null) {
+                continue;
             }
-            // 鏃犳硶鍞竴纭畾鏉ユ簮鏃朵篃鍙皾璇曡繖涓�娆★紝閬垮厤浠ュ悗鏍囧噯搴撹皟鏁存椂鎰忓鏀瑰姩璁㈠崟銆�
-            insOrderStandardTemplateMapper.update(null,
-                    Wrappers.<InsOrderStandardTemplate>lambdaUpdate()
-                            .eq(InsOrderStandardTemplate::getId, snapshot.getId())
-                            .set(InsOrderStandardTemplate::getDeviceDefaultsInitialized, 1));
+            List<InsOrderTemplateDevice> currentDevices = existingDevices.getOrDefault(
+                    templateId, Collections.emptyList());
+            // 鏃ф暟鎹病鏈夊垵濮嬪寲鏍囪锛屽凡鏈夎澶囪涓轰汉宸ラ�夋嫨锛屾爣璁板悗涓嶅啀鑷姩瑕嗙洊銆�
+            if (snapshot.getDeviceDefaultsInitialized() == null && !currentDevices.isEmpty()) {
+                insOrderStandardTemplateMapper.update(null,
+                        Wrappers.<InsOrderStandardTemplate>lambdaUpdate()
+                                .eq(InsOrderStandardTemplate::getId, snapshot.getId())
+                                .set(InsOrderStandardTemplate::getDeviceDefaultsInitialized, 1));
+                continue;
+            }
+            if (!defaults.containsKey(templateId)) {
+                continue;
+            }
+            List<Integer> standardDeviceIds = defaults.get(templateId).stream()
+                    .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+            List<Integer> currentDeviceIds = currentDevices.stream()
+                    .map(InsOrderTemplateDevice::getDeviceId)
+                    .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+            if (currentDeviceIds.equals(standardDeviceIds)) {
+                continue;
+            }
+            // 鏈垵濮嬪寲杩囩殑妯℃澘瀹屽叏瀵归綈鏍囧噯搴撶粦瀹氾細缁戝畾鍑犱釜灏辨樉绀哄嚑涓��
+            insOrderTemplateDeviceMapper.delete(
+                    Wrappers.<InsOrderTemplateDevice>lambdaQuery()
+                            .eq(InsOrderTemplateDevice::getInsOrderId, orderId)
+                            .eq(InsOrderTemplateDevice::getTemplateId, templateId));
+            for (int index = 0; index < standardDeviceIds.size(); index++) {
+                InsOrderTemplateDevice relation = new InsOrderTemplateDevice();
+                relation.setInsOrderId(orderId);
+                relation.setTemplateId(templateId);
+                relation.setDeviceId(standardDeviceIds.get(index));
+                relation.setSort(index);
+                insOrderTemplateDeviceMapper.insert(relation);
+            }
         }
     }
 
@@ -1184,23 +1309,29 @@
                         .isNotNull(StandardTree::getSample)
                         .isNull(StandardTree::getSampleType)
                         .isNull(StandardTree::getModel));
-                List<StandardTree> matches = candidates.stream()
-                        .filter(tree -> StringUtils.isNotBlank(tree.getSample()))
-                        .filter(tree -> {
-                            Set<Integer> boundIds = standardTreeService.selectTemplateBindings(tree.getId()).stream()
-                                    .map(StandardTreeTemplateBindingVo::getTemplateId).collect(Collectors.toSet());
-                            return boundIds.containsAll(templateIds);
-                        }).collect(Collectors.toList());
-                if (matches.size() == 1) {
-                    standardTreeId = matches.get(0).getId();
-                } else {
-                    List<StandardTree> exact = matches.stream().filter(tree ->
-                            standardTreeService.selectTemplateBindings(tree.getId()).stream()
-                                    .map(StandardTreeTemplateBindingVo::getTemplateId)
-                                    .collect(Collectors.toSet()).equals(templateIds))
-                            .collect(Collectors.toList());
-                    if (exact.size() == 1) {
-                        standardTreeId = exact.get(0).getId();
+                if (candidates.size() == 1) {
+                    // 鍚屼竴鏍囧噯缂栧彿銆佸悓涓�瀹為獙瀹ゅ彧鏈変竴涓簩绾ц妭鐐规椂鐩存帴璁ゅ畾锛�
+                    // 閬垮厤鏍囧噯搴撹皟鏁磋繃妯℃澘鍚庢棫璁㈠崟鍖归厤涓嶄笂銆�
+                    standardTreeId = candidates.get(0).getId();
+                } else if (!candidates.isEmpty()) {
+                    List<StandardTree> matches = candidates.stream()
+                            .filter(tree -> StringUtils.isNotBlank(tree.getSample()))
+                            .filter(tree -> {
+                                Set<Integer> boundIds = standardTreeService.selectTemplateBindings(tree.getId()).stream()
+                                        .map(StandardTreeTemplateBindingVo::getTemplateId).collect(Collectors.toSet());
+                                return boundIds.containsAll(templateIds);
+                            }).collect(Collectors.toList());
+                    if (matches.size() == 1) {
+                        standardTreeId = matches.get(0).getId();
+                    } else if (!matches.isEmpty()) {
+                        List<StandardTree> exact = matches.stream().filter(tree ->
+                                standardTreeService.selectTemplateBindings(tree.getId()).stream()
+                                        .map(StandardTreeTemplateBindingVo::getTemplateId)
+                                        .collect(Collectors.toSet()).equals(templateIds))
+                                .collect(Collectors.toList());
+                        if (exact.size() == 1) {
+                            standardTreeId = exact.get(0).getId();
+                        }
                     }
                 }
             }
@@ -1755,7 +1886,7 @@
                 List<String> unqualifiedList = insProductMapper.selectUnqualifiedList(orderDto.getId());
                 orderDto.setUnqualifiedItem(CollUtil.join(unqualifiedList, ","));
             }
-            orderDto.setCreateTimeString(orderDto.getCreateTime() == null ? "" : orderDto.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            orderDto.setSampleDateString(orderDto.getSampleDate() == null ? "" : orderDto.getSampleDate().toString());
 
         }
 

--
Gitblit v1.9.3