inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -17,19 +17,27 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.dto.InventoryDetailDTO;
import com.ruoyi.basic.dto.StandardTreeTemplateBindingVo;
import com.ruoyi.basic.dto.TemplateInspectionItemDto;
import com.ruoyi.basic.mapper.IfsInventoryQuantityMapper;
import com.ruoyi.basic.mapper.StandardProductListMapper;
import com.ruoyi.basic.mapper.StructureItemParameterMapper;
import com.ruoyi.basic.pojo.IfsInventoryQuantity;
import com.ruoyi.basic.pojo.StandardProductList;
import com.ruoyi.basic.pojo.StandardMethod;
import com.ruoyi.basic.pojo.StructureItemParameter;
import com.ruoyi.basic.pojo.StructureTestObject;
import com.ruoyi.basic.pojo.StandardTree;
import com.ruoyi.basic.pojo.StandardTemplate;
import com.ruoyi.basic.service.StandardTemplateService;
import com.ruoyi.basic.service.StandardMethodService;
import com.ruoyi.basic.service.StandardTreeService;
import com.ruoyi.basic.utils.StandardTreePathParser;
import com.ruoyi.common.constant.InsOrderTypeConstants;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.enums.OrderType;
import com.ruoyi.common.numgen.NumberGenerator;
import com.ruoyi.common.utils.LimsDateUtil;
import com.ruoyi.common.utils.QueryWrappers;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.api.IfsApiUtils;
@@ -43,6 +51,8 @@
import com.ruoyi.inspect.service.InsSampleService;
import com.ruoyi.inspect.vo.IfsOrderVO;
import com.ruoyi.inspect.vo.InsOrderPrintingVo;
import com.ruoyi.inspect.vo.OrderTemplateSummaryVo;
import com.ruoyi.inspect.vo.TemplateConditionVo;
import com.ruoyi.system.mapper.UserMapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
@@ -90,6 +100,11 @@
    private SpotCheckQuarterItemMapper spotCheckQuarterItemMapper;
    private StandardProductListMapper standardProductListMapper;
    private StructureItemParameterMapper structureItemParameterMapper;
    private StandardTreeService standardTreeService;
    private StandardMethodService standardMethodService;
    private StandardTemplateService standardTemplateService;
    private InsOrderStandardTemplateMapper insOrderStandardTemplateMapper;
    private InsOrderTemplateDeviceMapper insOrderTemplateDeviceMapper;
@@ -407,6 +422,142 @@
    }
    /**
     * 新聚标准库直绑模板的下单流程:一个订单、一个样品,检验记录完全由模板标记生成。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addNewJuInsOrder(InsPlaceOrderDto dto) {
        if (dto == null || dto.getInsOrder() == null || dto.getStandardTreeId() == null) {
            throw new ErrorException("下单信息或标准不能为空");
        }
        StandardTree standard = standardTreeService.getById(dto.getStandardTreeId());
        if (standard == null || StringUtils.isBlank(standard.getSample())
                || standard.getSampleType() != null || standard.getModel() != null) {
            throw new ErrorException("请选择标准库二级标准");
        }
        List<StandardTreeTemplateBindingVo> bindings = standardTreeService.selectTemplateBindings(dto.getStandardTreeId());
        if (bindings.isEmpty()) {
            throw new ErrorException("该标准尚未绑定可用的原始记录模板");
        }
        Map<Integer, StandardTreeTemplateBindingVo> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StandardTreeTemplateBindingVo::getTemplateId,
                        binding -> binding, (first, ignored) -> first));
        List<OrderTemplateSelectionDto> selections = dto.getTemplateList();
        if (selections == null) {
            selections = bindings.stream().map(binding -> {
                OrderTemplateSelectionDto selection = new OrderTemplateSelectionDto();
                selection.setTemplateId(binding.getTemplateId());
                selection.setSort(binding.getSort());
                return selection;
            }).collect(Collectors.toList());
        }
        if (selections.isEmpty()) {
            throw new ErrorException("请至少保留一个原始记录模板");
        }
        Set<Integer> selectedTemplateIds = new HashSet<>();
        for (int index = 0; index < selections.size(); index++) {
            OrderTemplateSelectionDto selection = selections.get(index);
            if (selection == null || selection.getTemplateId() == null
                    || !bindingMap.containsKey(selection.getTemplateId())) {
                throw new ErrorException("所选原始记录模板不属于当前标准");
            }
            if (!selectedTemplateIds.add(selection.getTemplateId())) {
                throw new ErrorException("原始记录模板不能重复选择");
            }
            if (selection.getSort() == null) {
                selection.setSort(index);
            }
        }
        selections.sort(Comparator.comparing(OrderTemplateSelectionDto::getSort)
                .thenComparing(OrderTemplateSelectionDto::getTemplateId));
        Map<Integer, Integer> templateSortMap = selections.stream()
                .collect(Collectors.toMap(OrderTemplateSelectionDto::getTemplateId,
                        OrderTemplateSelectionDto::getSort));
        List<TemplateInspectionItemDto> templateItems = standardTreeService
                .selectTemplateInspectionItems(dto.getStandardTreeId()).stream()
                .filter(item -> selectedTemplateIds.contains(item.getTemplateId()))
                .sorted(Comparator
                        .comparing((TemplateInspectionItemDto item) -> templateSortMap.get(item.getTemplateId()))
                        .thenComparing(item -> item.getTemplateRowIndex() == null
                                ? Integer.MAX_VALUE : item.getTemplateRowIndex()))
                .collect(Collectors.toList());
        StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId());
        if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) {
            throw new ErrorException("标准编号不存在");
        }
        String standardCode = standardMethod.getCode().trim();
        InsOrder order = dto.getInsOrder();
        order.setId(null);
        order.setState(0);
        order.setIsExemption(0);
        order.setFactory(null);
        order.setLaboratory(standard.getLaboratory());
        order.setSampleType(null);
        order.setSample(standardCode);
        order.setPrepareUserEn(null);
        order.setPrepareCode(null);
        order.setRemarkEn(null);
        // 新聚订单的环境条件由检验任务填写,避免下单模板或浏览器缓存带入旧值。
        order.setTemperature(null);
        order.setHumidity(null);
        insOrderMapper.insert(order);
        InsSample sample = new InsSample();
        sample.setInsOrderId(order.getId());
        sample.setSampleCode(dto.getSampleCode());
        sample.setFactory(null);
        sample.setLaboratory(standard.getLaboratory());
        sample.setSampleType(null);
        sample.setSample(standardCode);
        sample.setModel(null);
        sample.setQuantity(1);
        sample.setStandardMethodListId(null);
        insSampleMapper.insert(sample);
        int productSort = 0;
        for (TemplateInspectionItemDto item : templateItems) {
            InsProduct product = new InsProduct();
            product.setInsSampleId(sample.getId());
            product.setInspectionItem(item.getInspectionItem());
            product.setInspectionItemClass("");
            product.setInspectionItemSubclass("");
            product.setFactory(null);
            product.setLaboratory(standard.getLaboratory());
            product.setSampleType(null);
            product.setSample(standardCode);
            product.setModel(null);
            product.setTemplateId(item.getTemplateId());
            product.setTemplateRowIndex(item.getTemplateRowIndex());
            product.setSonLaboratory("新聚");
            product.setState(1);
            product.setSort(productSort++);
            insProductMapper.insert(product);
        }
        saveTemplateSnapshots(order.getId(), selections);
        return order.getId();
    }
    private void saveTemplateSnapshots(Integer orderId, List<OrderTemplateSelectionDto> selections) {
        for (OrderTemplateSelectionDto selection : selections) {
            StandardTemplate template = standardTemplateService.getById(selection.getTemplateId());
            if (template == null) {
                throw new ErrorException("原始记录模板不存在");
            }
            InsOrderStandardTemplate snapshot = new InsOrderStandardTemplate();
            snapshot.setInsOrderId(orderId);
            snapshot.setTemplateId(template.getId());
            snapshot.setName(template.getName());
            snapshot.setNumber(template.getNumber());
            snapshot.setRemark(template.getRemark());
            snapshot.setThing(template.getThing());
            snapshot.setSort(selection.getSort());
            insOrderStandardTemplateMapper.insert(snapshot);
        }
    }
    /**
     * 添加检验项
     * @param sampleId
     * @param productList
@@ -447,9 +598,33 @@
            list = insSampleMapper.selectSampleProductListByOrderId2(id);
        }
        Map<String, Object> map1 = insSampleMapper.selectInsOrder(id);
        List<InsSample> orderSamples = insSampleMapper.selectList(
                Wrappers.<InsSample>lambdaQuery()
                        .eq(InsSample::getInsOrderId, id)
                        .select(InsSample::getSampleCode)
                        .orderByAsc(InsSample::getId));
        List<OrderTemplateSummaryVo> templateList = insOrderStandardTemplateMapper.selectList(
                        Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                                .eq(InsOrderStandardTemplate::getInsOrderId, id)
                                .orderByAsc(InsOrderStandardTemplate::getSort,
                                        InsOrderStandardTemplate::getId))
                .stream()
                .map(template -> {
                    OrderTemplateSummaryVo summary = new OrderTemplateSummaryVo();
                    summary.setTemplateId(template.getTemplateId());
                    summary.setName(template.getName());
                    summary.setNumber(template.getNumber());
                    summary.setRemark(template.getRemark());
                    summary.setSort(template.getSort());
                    return summary;
                })
                .collect(Collectors.toList());
        map.put("insOrder", insOrder);
        map.put("sampleProduct", list);
        // 样品编号直接从样品表读取,不依赖检验项目关联查询是否有结果。
        map.put("sampleCode", orderSamples.isEmpty() ? null : orderSamples.get(0).getSampleCode());
        map.put("insOrderTemplate", map1);
        map.put("templateList", templateList);
        return map;
    }
@@ -463,24 +638,15 @@
        insOrder.setExamineTime(LocalDateTime.now());
        if (insOrder.getState() == 1) {
            //审核通过才会生成委托编号
            // todo: 检验类型编号
            InsOrder order = this.getById(insOrder.getId());
            String code = "";
            switch (order.getOrderType()) {
                case InsOrderTypeConstants.SPOT_CHECK:
                    code = "C";
                    break;
                case InsOrderTypeConstants.CUSTOMER_ORDERED:
                    code = "W";
                    break;
                case InsOrderTypeConstants.ENTER_THE_FACTORY:
                case InsOrderTypeConstants.QUARTERLY_TEST:
                    code = "Y";
                    break;
            }
            // 生成编号
            String no = numberGenerator.generateNumberWithPrefix(3,
                    "JCZX/ZB-" + code + LimsDateUtil.resetDate(LocalDateTime.now()),
            // 委托编号按送样日期独立流水,例如:LMSY-20260909-01。
            // 历史/外部订单未填写送样日期时回退到当天,避免影响原有流程。
            LocalDate entrustDate = order.getSampleDate() == null ? LocalDate.now() : order.getSampleDate();
            String entrustCodePrefix = "LMSY-"
                    + entrustDate.format(DateTimeFormatter.BASIC_ISO_DATE)
                    + "-";
            String no = numberGenerator.generateNumberWithPrefix(2,
                    entrustCodePrefix,
                    InsOrder::getEntrustCode);
            // 判断是否是季度检验, 是季度检验取消原材料季度检验下单
            if (InsOrderTypeConstants.QUARTERLY_TEST.equals(order.getOrderType())) {
@@ -525,6 +691,39 @@
        Map<String, Object> map = new HashMap<>();
//        InsOrder insOrder = insOrderMapper.selectById(id);
        IfsOrderVO ifsOrderVO = insOrderMapper.selectOrderInfoById(id);
        Map<Integer, List<Integer>> templateDeviceIds = insOrderTemplateDeviceMapper.selectList(
                        Wrappers.<InsOrderTemplateDevice>lambdaQuery()
                                .eq(InsOrderTemplateDevice::getInsOrderId, id)
                                .orderByAsc(InsOrderTemplateDevice::getSort,
                                        InsOrderTemplateDevice::getId))
                .stream().collect(Collectors.groupingBy(
                        InsOrderTemplateDevice::getTemplateId,
                        LinkedHashMap::new,
                        Collectors.mapping(InsOrderTemplateDevice::getDeviceId, Collectors.toList())));
        List<TemplateConditionVo> templateConditions = insOrderStandardTemplateMapper.selectList(
                        Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                                .eq(InsOrderStandardTemplate::getInsOrderId, id)
                                .select(InsOrderStandardTemplate::getTemplateId,
                                        InsOrderStandardTemplate::getTemperature,
                                        InsOrderStandardTemplate::getHumidity,
                                        InsOrderStandardTemplate::getDetectionTime,
                                        InsOrderStandardTemplate::getDetectionPlace,
                                        InsOrderStandardTemplate::getInsResult)
                                .orderByAsc(InsOrderStandardTemplate::getSort,
                                        InsOrderStandardTemplate::getId))
                .stream().map(snapshot -> {
                    TemplateConditionVo condition = new TemplateConditionVo();
                    condition.setTemplateId(snapshot.getTemplateId());
                    condition.setTemperature(snapshot.getTemperature());
                    condition.setHumidity(snapshot.getHumidity());
                    condition.setDetectionTime(snapshot.getDetectionTime());
                    condition.setDetectionPlace(snapshot.getDetectionPlace());
                    condition.setInsResult(snapshot.getInsResult());
                    condition.setDeviceIds(templateDeviceIds.getOrDefault(
                            snapshot.getTemplateId(), Collections.emptyList()));
                    return condition;
                }).collect(Collectors.toList());
        ifsOrderVO.setTemplateConditions(templateConditions);
        List<SampleProductDto> list = insSampleMapper.getInsOrderAndSample(id, laboratory);
        map.put("insOrder", ifsOrderVO);
        map.put("sampleProduct", list);
@@ -648,13 +847,6 @@
                if(isSplitOrder){
                    ifsInventoryQuantity.setIsSplitOrder(1);
                }
                //todo:不清楚用途,暂时屏蔽掉
                // 查询产业链检测数据
//                String industryChainAttrFields = IndustryChainUtils.getIndustryChainAttrFields(ifsInventoryQuantity.getOrderNo(),
//                        ifsInventoryQuantity.getLineNo(),
//                        ifsInventoryQuantity.getReleaseNo());
//                ifsInventoryQuantity.setIndustryChain(industryChainAttrFields);
                ifsInventoryQuantityMapper.insert(ifsInventoryQuantity);
            }
        }
@@ -881,6 +1073,19 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateInsOrder(InsOrderUpdateDto insOrderUpdateDto) {
        InsOrder currentOrder = insOrderMapper.selectById(insOrderUpdateDto.getInsOrder().getId());
        if (currentOrder == null || !Objects.equals(currentOrder.getState(), 2)) {
            throw new ErrorException("只有退回的检验单可以修改");
        }
        boolean hasSelectedProduct = CollectionUtils.isNotEmpty(insOrderUpdateDto.getSampleProduct())
                && insOrderUpdateDto.getSampleProduct().stream()
                .filter(sample -> CollectionUtils.isNotEmpty(sample.getInsProduct()))
                .flatMap(sample -> sample.getInsProduct().stream())
                .anyMatch(product -> Objects.equals(product.getState(), 1));
        if (!hasSelectedProduct) {
            throw new ErrorException("请至少选择一个检验项");
        }
        // 修改订单
        insOrderUpdateDto.getInsOrder().setState(0);
        insOrderUpdateDto.getInsOrder().setTell("");
@@ -888,11 +1093,50 @@
        // 修改检验项
        for (SampleProductDto sampleProductDto : insOrderUpdateDto.getSampleProduct()) {
            Long sampleCount = insSampleMapper.selectCount(Wrappers.<InsSample>lambdaQuery()
                    .eq(InsSample::getId, sampleProductDto.getId())
                    .eq(InsSample::getInsOrderId, insOrderUpdateDto.getInsOrder().getId()));
            if (sampleCount == 0) {
                throw new ErrorException("检验样品数据异常");
            }
            insSampleService.update(Wrappers.<InsSample>lambdaUpdate()
                    .eq(InsSample::getId, sampleProductDto.getId())
                    .set(InsSample::getSpecialStandardMethod, sampleProductDto.getSpecialStandardMethod()));
            insProductService.updateBatchById(sampleProductDto.getInsProduct());
            List<InsProduct> products = sampleProductDto.getInsProduct();
            if (CollectionUtils.isEmpty(products)) {
                continue;
            }
            Set<Integer> productIds = insProductMapper.selectList(Wrappers.<InsProduct>lambdaQuery()
                            .eq(InsProduct::getInsSampleId, sampleProductDto.getId()))
                    .stream()
                    .map(InsProduct::getId)
                    .collect(Collectors.toSet());
            if (products.stream().anyMatch(product -> product.getId() != null && !productIds.contains(product.getId()))) {
                throw new ErrorException("检验项数据异常");
            }
            List<Integer> removedIds = products.stream()
                    .filter(product -> product.getId() != null && !Objects.equals(product.getState(), 1))
                    .map(InsProduct::getId)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(removedIds)) {
                insProductService.removeByIds(removedIds);
            }
            List<InsProduct> existingProducts = products.stream()
                    .filter(product -> product.getId() != null && Objects.equals(product.getState(), 1))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(existingProducts)) {
                insProductService.updateBatchById(existingProducts);
            }
            List<InsProduct> newProducts = products.stream()
                    .filter(product -> product.getId() == null && Objects.equals(product.getState(), 1))
                    .collect(Collectors.toList());
            addInsProductMethod(sampleProductDto.getId(), newProducts);
        }
        return true;
@@ -924,11 +1168,18 @@
        InsProduct insProduct = insProductMapper.selectOne(Wrappers.<InsProduct>lambdaQuery()
                .eq(InsProduct::getInsSampleId, insSampleId)
                .last("limit 1"));
        String tree = insProduct.getFactory() + " - " +
                insProduct.getLaboratory() + " - " +
                insProduct.getSampleType() + " - " +
                insProduct.getSample() + " - " +
                insProduct.getModel();
        String tree;
        if (insProduct.getSampleType() == null && insProduct.getModel() == null
                && StringUtils.isNotBlank(insProduct.getLaboratory())
                && StringUtils.isNotBlank(insProduct.getSample())) {
            tree = StandardTreePathParser.canonical(insProduct.getLaboratory(), insProduct.getSample());
        } else {
            tree = insProduct.getFactory() + " - " +
                    insProduct.getLaboratory() + " - " +
                    insProduct.getSampleType() + " - " +
                    insProduct.getSample() + " - " +
                    insProduct.getModel();
        }
        // 查询标准树
        List<StandardProductList> standardProductLists = standardProductListMapper.selectList(Wrappers.<StandardProductList>lambdaQuery()
                .eq(StandardProductList::getStandardMethodListId, insProduct.getStandardMethodListId())