7 天以前 2f80b7085c4eabce06d3491306b75eecc275275f
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -27,6 +27,8 @@
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.quality.mapper.*;
import com.ruoyi.quality.pojo.*;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
import com.ruoyi.technology.pojo.TechnologyOperation;
@@ -40,10 +42,14 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@@ -72,10 +78,13 @@
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
    private final StockUtils stockUtils;
    private final StockInventoryService stockInventoryService;
    @Override
    public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) {
        return productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto);
        IPage<ProductionProductMainDto> result = productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto);
        fillOperationParamList(result.getRecords());
        return result;
    }
    @Override
@@ -85,9 +94,119 @@
    @Override
    public ProductionProductMainDto getProductionProductMainInfo(Long id) {
        return productionProductMainMapper.listPageProductionProductMainDto(new Page<>(1, 1), new ProductionProductMainDto() {{
        return listPageProductionProductMainDto(new Page<>(1, 1), new ProductionProductMainDto() {{
            setId(id);
        }}).getRecords().stream().findFirst().orElse(null);
    }
    private void fillOperationParamList(List<ProductionProductMainDto> recordList) {
        if (recordList == null || recordList.isEmpty()) {
            return;
        }
        Set<Long> mainIdSet = recordList.stream()
                .map(ProductionProductMainDto::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (mainIdSet.isEmpty()) {
            recordList.forEach(item -> item.setProductionOperationParamList(Collections.emptyList()));
            return;
        }
        List<ProductionOrderRoutingOperationParam> paramList = productionOrderRoutingOperationParamMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .in(ProductionOrderRoutingOperationParam::getProductionProductMainId, mainIdSet)
                        .orderByAsc(ProductionOrderRoutingOperationParam::getId));
        Map<Long, List<ProductionOrderRoutingOperationParam>> paramGroupMap = new HashMap<>();
        for (ProductionOrderRoutingOperationParam param : paramList) {
            if (param == null || param.getProductionProductMainId() == null) {
                continue;
            }
            paramGroupMap.computeIfAbsent(param.getProductionProductMainId(), key -> new ArrayList<>()).add(param);
        }
        Set<Long> missingMainIdSet = new LinkedHashSet<>();
        for (ProductionProductMainDto item : recordList) {
            Long mainId = item.getId();
            if (mainId == null) {
                item.setProductionOperationParamList(Collections.emptyList());
                continue;
            }
            List<ProductionOrderRoutingOperationParam> params = paramGroupMap.get(mainId);
            if (params != null && !params.isEmpty()) {
                item.setProductionOperationParamList(params);
                continue;
            }
            missingMainIdSet.add(mainId);
        }
        if (missingMainIdSet.isEmpty()) {
            return;
        }
        // 兼容历史数据:旧报工记录没有按报工ID落参数快照时,回退展示工序模板参数。
        List<ProductionProductMain> mainList = productionProductMainMapper.selectBatchIds(missingMainIdSet);
        Map<Long, Long> mainIdToTaskIdMap = mainList.stream()
                .filter(Objects::nonNull)
                .filter(item -> item.getId() != null)
                .collect(Collectors.toMap(ProductionProductMain::getId,
                        ProductionProductMain::getProductionOperationTaskId, (left, right) -> left));
        Set<Long> taskIdSet = mainIdToTaskIdMap.values().stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (taskIdSet.isEmpty()) {
            for (ProductionProductMainDto item : recordList) {
                if (item.getId() != null && missingMainIdSet.contains(item.getId())) {
                    item.setProductionOperationParamList(Collections.emptyList());
                }
            }
            return;
        }
        List<ProductionOperationTask> taskList = productionOperationTaskMapper.selectList(
                Wrappers.<ProductionOperationTask>lambdaQuery()
                        .in(ProductionOperationTask::getId, taskIdSet));
        Map<Long, Long> taskIdToRoutingOperationIdMap = taskList.stream()
                .filter(Objects::nonNull)
                .filter(item -> item.getId() != null)
                .collect(Collectors.toMap(ProductionOperationTask::getId,
                        ProductionOperationTask::getProductionOrderRoutingOperationId, (left, right) -> left));
        Set<Long> routingOperationIdSet = taskIdToRoutingOperationIdMap.values().stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (routingOperationIdSet.isEmpty()) {
            for (ProductionProductMainDto item : recordList) {
                if (item.getId() != null && missingMainIdSet.contains(item.getId())) {
                    item.setProductionOperationParamList(Collections.emptyList());
                }
            }
            return;
        }
        List<ProductionOrderRoutingOperationParam> fallbackParamList = productionOrderRoutingOperationParamMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .in(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, routingOperationIdSet)
                        .isNull(ProductionOrderRoutingOperationParam::getProductionProductMainId)
                        .orderByAsc(ProductionOrderRoutingOperationParam::getId));
        Map<Long, List<ProductionOrderRoutingOperationParam>> fallbackGroupMap = new HashMap<>();
        for (ProductionOrderRoutingOperationParam param : fallbackParamList) {
            if (param == null || param.getProductionOrderRoutingOperationId() == null) {
                continue;
            }
            fallbackGroupMap.computeIfAbsent(param.getProductionOrderRoutingOperationId(), key -> new ArrayList<>()).add(param);
        }
        for (ProductionProductMainDto item : recordList) {
            Long mainId = item.getId();
            if (mainId == null || !missingMainIdSet.contains(mainId)) {
                continue;
            }
            Long taskId = mainIdToTaskIdMap.get(mainId);
            Long routingOperationId = taskId == null ? null : taskIdToRoutingOperationIdMap.get(taskId);
            if (routingOperationId == null) {
                item.setProductionOperationParamList(Collections.emptyList());
                continue;
            }
            item.setProductionOperationParamList(fallbackGroupMap.getOrDefault(routingOperationId, Collections.emptyList()));
        }
    }
    @Override
@@ -132,7 +251,6 @@
        if (productionOrder == null) {
            throw new ServiceException("生产订单不存在");
        }
        syncOperationParamInputValue(dto, routingOperation.getId());
        TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
        TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
@@ -149,11 +267,16 @@
        productionProductMain.setProductionOperationTaskId(taskId);
        productionProductMain.setStatus(0);
        productionProductMainMapper.insert(productionProductMain);
        syncOperationParamInputValue(dto, routingOperation.getId(), productionProductMain.getId());
        List<ProductStructureDto> productStructureDtos = resolveInputStructures(
                productionOrder.getId(), routingOperation, productModel.getId());
       // 如果没有bom子节点了,那么投入就是他本身
        if (productStructureDtos.isEmpty()) {
            throw new ServiceException("未找到当前工序对应的BOM投入节点");
            ProductStructureDto fallbackInput = new ProductStructureDto();
            fallbackInput.setProductModelId(productModel.getId());
            fallbackInput.setUnitQuantity(BigDecimal.ONE);
            productStructureDtos.add(fallbackInput);
        }
        for (ProductStructureDto item : productStructureDtos) {
            // 当前实现按工序成品直接作为投入,后续若接入领料记录可在这里替换来源。
@@ -173,7 +296,8 @@
        productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity()));
        productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
        productionProductOutputMapper.insert(productionProductOutput);
        BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty());
        BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity());
        BigDecimal productQty = reportQty;
        List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
@@ -199,7 +323,7 @@
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
                if (qualityTestStandard.size() > 0) {
                if (!qualityTestStandard.isEmpty()) {
                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
                    qualityInspectMapper.updateById(qualityInspect);
                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
@@ -213,8 +337,12 @@
                            });
                }
            } else {
                stockUtils.addStock(productModel.getId(), productQty,
                        StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
                StockInventoryDto stockInventoryDto = new StockInventoryDto();
                stockInventoryDto.setRecordId(productionProductMain.getId());
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
                stockInventoryDto.setQualitity(productQty);
                stockInventoryDto.setProductModelId(productModel.getId());
                stockInventoryService.addStockInRecordOnly(stockInventoryDto);
            }
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
@@ -263,27 +391,40 @@
            productionAccount.setSchedulingDate(LocalDateTime.now());
            productionAccountMapper.insert(productionAccount);
        }
        if (defaultDecimal(dto.getScrapQty()).compareTo(BigDecimal.ZERO) > 0) {
            stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(),
                    StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId());
        }
//        if (defaultDecimal(dto.getScrapQty()).compareTo(BigDecimal.ZERO) > 0) {
//            stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(),
//                    StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId());
//        }
        return true;
    }
    private void syncOperationParamInputValue(ProductionProductMainDto dto, Long productionOrderRoutingOperationId) {
        if (dto == null || productionOrderRoutingOperationId == null) {
    private void syncOperationParamInputValue(ProductionProductMainDto dto,
                                              Long productionOrderRoutingOperationId,
                                              Long productionProductMainId) {
        if (dto == null || productionOrderRoutingOperationId == null || productionProductMainId == null) {
            return;
        }
        List<ProductionOrderRoutingOperationParam> paramList = dto.getProductionOperationParamList();
        if (paramList == null || paramList.isEmpty()) {
            return;
        }
        Set<Long> sourceParamIdSet = paramList.stream()
                .filter(Objects::nonNull)
                .map(ProductionOrderRoutingOperationParam::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (sourceParamIdSet.isEmpty()) {
            return;
        }
        List<ProductionOrderRoutingOperationParam> dbParamList = productionOrderRoutingOperationParamMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .in(ProductionOrderRoutingOperationParam::getId, sourceParamIdSet)
                        .eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, productionOrderRoutingOperationId));
        if (dbParamList == null || dbParamList.isEmpty()) {
            return;
        }
        Map<Long, ProductionOrderRoutingOperationParam> dbParamMap = dbParamList.stream()
                .filter(item -> item != null && item.getId() != null)
                .collect(Collectors.toMap(ProductionOrderRoutingOperationParam::getId, item -> item, (left, right) -> left));
@@ -295,14 +436,31 @@
            if (dbParam == null) {
                throw new ServiceException("工序参数不存在或不属于当前工单工序,ID=" + param.getId());
            }
            if (Objects.equals(dbParam.getInputValue(), param.getInputValue())) {
                continue;
            }
            ProductionOrderRoutingOperationParam updateParam = new ProductionOrderRoutingOperationParam();
            updateParam.setId(dbParam.getId());
            updateParam.setInputValue(param.getInputValue());
            productionOrderRoutingOperationParamMapper.updateById(updateParam);
            productionOrderRoutingOperationParamMapper.insert(buildReportParamSnapshot(dbParam, param.getInputValue(), productionProductMainId));
        }
    }
    private ProductionOrderRoutingOperationParam buildReportParamSnapshot(ProductionOrderRoutingOperationParam source,
                                                                          String inputValue,
                                                                          Long productionProductMainId) {
        ProductionOrderRoutingOperationParam target = new ProductionOrderRoutingOperationParam();
        target.setProductionOrderId(source.getProductionOrderId());
        target.setTechnologyRoutingOperationParamId(source.getTechnologyRoutingOperationParamId());
        target.setParamCode(source.getParamCode());
        target.setParamName(source.getParamName());
        target.setParamType(source.getParamType());
        target.setParamFormat(source.getParamFormat());
        target.setUnit(source.getUnit());
        target.setIsRequired(source.getIsRequired());
        target.setRemark(source.getRemark());
        target.setParamId(source.getParamId());
        target.setTechnologyOperationId(source.getTechnologyOperationId());
        target.setTechnologyOperationParamId(source.getTechnologyOperationParamId());
        target.setStandardValue(source.getStandardValue());
        target.setInputValue(inputValue);
        target.setProductionOrderRoutingOperationId(source.getProductionOrderRoutingOperationId());
        target.setProductionProductMainId(productionProductMainId);
        return target;
    }
    private List<ProductStructureDto> resolveInputStructures(Long productionOrderId,
@@ -384,8 +542,8 @@
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
        if (productionOperationTask != null && productionProductOutput != null) {
            BigDecimal validQuantity = defaultDecimal(productionProductOutput.getQuantity()).subtract(defaultDecimal(productionProductOutput.getScrapQty()));
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).subtract(validQuantity));
            BigDecimal reportQuantity = defaultDecimal(productionProductOutput.getQuantity());
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).subtract(reportQuantity));
            productionOperationTask.setActualEndTime(null);
            if (defaultDecimal(productionOperationTask.getCompleteQuantity()).compareTo(BigDecimal.ZERO) <= 0) {
                productionOperationTask.setCompleteQuantity(BigDecimal.ZERO);
@@ -406,7 +564,7 @@
                                .eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId()));
                boolean isLastOperation = routingOperation.getDragSort() != null && routingOperation.getDragSort().equals(routingOperationList.size());
                if (isLastOperation) {
                    BigDecimal newCompleteQty = defaultDecimal(productionOrder.getCompleteQuantity()).subtract(validQuantity);
                    BigDecimal newCompleteQty = defaultDecimal(productionOrder.getCompleteQuantity()).subtract(reportQuantity);
                    productionOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
                    productionOrder.setEndTime(null);
                }
@@ -431,6 +589,9 @@
                .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()));
        productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                .eq(ProductionProductInput::getProductionProductMainId, productionProductMain.getId()));
        productionOrderRoutingOperationParamMapper.delete(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .eq(ProductionOrderRoutingOperationParam::getProductionProductMainId, productionProductMain.getId()));
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());