gaoluyang
2026-11-03 a829dd34332bbc10c6b42ef86635ed48e34c6207
src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -34,7 +34,9 @@
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.stock.mapper.StockInRecordMapper;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.technology.mapper.*;
import com.ruoyi.technology.pojo.*;
@@ -70,6 +72,7 @@
    private final QualityInspectFileMapper qualityInspectFileMapper;
    private final ProductionPlanMapper productionPlanMapper;
    private final StockInventoryMapper stockInventoryMapper;
    private final StockInRecordMapper stockInRecordMapper;
    private final StorageAttachmentMapper storageAttachmentMapper;
    private final StorageBlobMapper storageBlobMapper;
    private final SalesLedgerMapper salesLedgerMapper;
@@ -1144,12 +1147,41 @@
            List<StockInventory> stockList = stockInventoryMapper.selectList(
                    Wrappers.<StockInventory>lambdaQuery()
                            .in(StockInventory::getProductModelId, productModelIds));
            // 各批次首次入库时间,用于先进先出排序(历史数据导入时库存行的 create_time 可能相同)
            Map<Long, Map<String, LocalDateTime>> firstInTimeMap = new HashMap<>();
            List<StockInRecord> stockInRecords = stockInRecordMapper.selectList(
                    Wrappers.<StockInRecord>lambdaQuery()
                            .in(StockInRecord::getProductModelId, productModelIds)
                            .isNotNull(StockInRecord::getBatchNo));
            for (StockInRecord stockInRecord : stockInRecords) {
                if (stockInRecord == null || stockInRecord.getProductModelId() == null
                        || stockInRecord.getBatchNo() == null || stockInRecord.getCreateTime() == null) {
                    continue;
                }
                firstInTimeMap.computeIfAbsent(stockInRecord.getProductModelId(), key -> new HashMap<>())
                        .merge(stockInRecord.getBatchNo(), stockInRecord.getCreateTime(),
                                (a, b) -> a.isBefore(b) ? a : b);
            }
            // 库存行按所属批次的首次入库时间升序,保证领料下拉框是先进先出顺序
            stockList.sort(Comparator
                    .comparing((StockInventory stockItem) -> {
                        Map<String, LocalDateTime> modelBatchTimeMap = firstInTimeMap.get(stockItem.getProductModelId());
                        return modelBatchTimeMap == null ? null : modelBatchTimeMap.get(stockItem.getBatchNo());
                    }, Comparator.nullsLast(Comparator.naturalOrder()))
                    .thenComparing(StockInventory::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
                    .thenComparing(stockItem -> stockItem.getId() == null ? Long.MAX_VALUE : stockItem.getId()));
            for (StockInventory stockItem : stockList) {
                if (stockItem == null || stockItem.getProductModelId() == null) {
                    continue;
                }
                Long productModelId = stockItem.getProductModelId();
                stockQuantityMap.merge(productModelId, defaultDecimal(stockItem.getQualitity()), BigDecimal::add);
                // 已无可用库存(数量扣完或被锁定)的批次不再带到领料下拉框
                BigDecimal availableQuantity = defaultDecimal(stockItem.getQualitity())
                        .subtract(defaultDecimal(stockItem.getLockedQuantity()));
                if (availableQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }
                String batchNo = stockItem.getBatchNo();
                if (batchNo != null && !batchNo.trim().isEmpty()) {
                    stockBatchNoMap.computeIfAbsent(productModelId, key -> new LinkedHashSet<>()).add(batchNo);