From 41ab7abd0b0ec0fefb03b60bbaf42c02fbda666b Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 23 四月 2026 15:53:16 +0800
Subject: [PATCH] feat(production): 添加生产订单与销售台账关联功能

---
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java |  128 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 122 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
index 978c76d..e48509e 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -5,6 +5,13 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.dto.StorageBlobVO;
+import com.ruoyi.basic.mapper.StorageAttachmentMapper;
+import com.ruoyi.basic.mapper.StorageBlobMapper;
+import com.ruoyi.basic.pojo.StorageAttachment;
+import com.ruoyi.basic.pojo.StorageBlob;
+import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.common.constant.StorageAttachmentConstants;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.production.bean.dto.ProductionOrderDto;
 import com.ruoyi.production.bean.vo.ProductionOrderVo;
@@ -31,6 +38,10 @@
 import com.ruoyi.production.pojo.ProductionPlan;
 import com.ruoyi.production.pojo.ProductionProductMain;
 import com.ruoyi.production.enums.ProductOrderStatusEnum;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.pojo.SalesLedger;
+import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.production.service.ProductionOrderService;
 import com.ruoyi.technology.mapper.TechnologyBomMapper;
 import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
@@ -75,27 +86,39 @@
     private final ProductionOrderPickMapper productionOrderPickMapper;
     private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper;
     private final ProductionPlanMapper productionPlanMapper;
+    private final StorageAttachmentMapper storageAttachmentMapper;
+    private final StorageBlobMapper storageBlobMapper;
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final SalesLedgerProductMapper salesLedgerProductMapper;
     private final TechnologyRoutingMapper technologyRoutingMapper;
     private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
     private final TechnologyRoutingOperationParamMapper technologyRoutingOperationParamMapper;
     private final TechnologyBomMapper technologyBomMapper;
     private final TechnologyBomStructureMapper technologyBomStructureMapper;
+    private final FileUtil fileUtil;
 
     @Override
     public com.baomidou.mybatisplus.core.metadata.IPage<ProductionOrderVo> pageProductionOrder(Page<ProductionOrderDto> page, ProductionOrderDto dto) {
-        Page<ProductionOrder> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
-        return this.page(entityPage, buildQueryWrapper(dto)).convert(item -> BeanUtil.copyProperties(item, ProductionOrderVo.class));
+        Page<ProductionOrderVo> result = (Page<ProductionOrderVo>) baseMapper.pageProductionOrder(page, dto);
+        fillProductImages(result.getRecords());
+        return result;
     }
 
     @Override
     public List<ProductionOrderVo> listProductionOrder(ProductionOrderDto dto) {
-        return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOrderVo.class);
+        List<ProductionOrderVo> records = baseMapper.listProductionOrder(dto);
+        fillProductImages(records);
+        return records;
     }
 
     @Override
     public ProductionOrderVo getProductionOrderInfo(Long id) {
-        ProductionOrder item = this.getById(id);
-        return item == null ? null : BeanUtil.copyProperties(item, ProductionOrderVo.class);
+        ProductionOrderVo item = baseMapper.getProductionOrderInfo(id);
+        if (item == null) {
+            return null;
+        }
+        fillProductImages(java.util.Collections.singletonList(item));
+        return item;
     }
 
     @Override
@@ -312,6 +335,7 @@
         ProductionOrder query = dto == null ? new ProductionOrder() : dto;
         return Wrappers.<ProductionOrder>lambdaQuery()
                 .eq(query.getId() != null, ProductionOrder::getId, query.getId())
+                .eq(query.getSalesLedgerId() != null, ProductionOrder::getSalesLedgerId, query.getSalesLedgerId())
                 .eq(query.getProductModelId() != null, ProductionOrder::getProductModelId, query.getProductModelId())
                 .eq(query.getTechnologyRoutingId() != null, ProductionOrder::getTechnologyRoutingId, query.getTechnologyRoutingId())
                 .like(query.getNpsNo() != null && !query.getNpsNo().trim().isEmpty(), ProductionOrder::getNpsNo, query.getNpsNo())
@@ -363,9 +387,10 @@
         if (productionOrder == null) {
             throw new ServiceException("Production order is required");
         }
+        fillFromSalesLedgerProduct(productionOrder);
         fillFromProductionPlans(productionOrder);
         if (productionOrder.getProductModelId() == null) {
-            throw new ServiceException("productModelId is required when manually creating a production order");
+            throw new ServiceException("productModelId is required");
         }
         if (defaultDecimal(productionOrder.getQuantity()).compareTo(BigDecimal.ZERO) <= 0) {
             throw new ServiceException("quantity must be greater than 0");
@@ -388,6 +413,36 @@
                     || !Objects.equals(oldOrder.getTechnologyRoutingId(), productionOrder.getTechnologyRoutingId())
                     || compareDecimal(oldOrder.getQuantity(), productionOrder.getQuantity()) != 0) {
                 throw new ServiceException("Started production orders cannot modify product, routing or quantity");
+            }
+        }
+    }
+
+    private void fillFromSalesLedgerProduct(ProductionOrder productionOrder) {
+        if (productionOrder.getSaleLedgerProductId() == null) {
+            return;
+        }
+        // 閿�鍞槑缁嗘槸璁㈠崟鏉ユ簮鏃讹紝浠ラ攢鍞槑缁嗕负鍑嗗洖濉攢鍞彴璐︺�佷骇鍝佽鏍煎拰榛樿鏁伴噺銆�
+        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productionOrder.getSaleLedgerProductId().longValue());
+        if (salesLedgerProduct == null) {
+            throw new ServiceException("Sales ledger product not found");
+        }
+        if (productionOrder.getSalesLedgerId() == null) {
+            productionOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
+        } else if (!Objects.equals(productionOrder.getSalesLedgerId(), salesLedgerProduct.getSalesLedgerId())) {
+            throw new ServiceException("salesLedgerId does not match the sales ledger product");
+        }
+        if (productionOrder.getProductModelId() == null) {
+            productionOrder.setProductModelId(salesLedgerProduct.getProductModelId());
+        } else if (!Objects.equals(productionOrder.getProductModelId(), salesLedgerProduct.getProductModelId())) {
+            throw new ServiceException("productModelId does not match the sales ledger product");
+        }
+        if (productionOrder.getQuantity() == null || productionOrder.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+            productionOrder.setQuantity(salesLedgerProduct.getQuantity());
+        }
+        if (productionOrder.getPlanCompleteTime() == null && productionOrder.getSalesLedgerId() != null) {
+            SalesLedger salesLedger = salesLedgerMapper.selectById(productionOrder.getSalesLedgerId());
+            if (salesLedger != null && salesLedger.getDeliveryDate() != null) {
+                productionOrder.setPlanCompleteTime(salesLedger.getDeliveryDate());
             }
         }
     }
@@ -547,4 +602,65 @@
     private int compareDecimal(BigDecimal left, BigDecimal right) {
         return defaultDecimal(left).compareTo(defaultDecimal(right));
     }
+
+    private void fillProductImages(List<ProductionOrderVo> records) {
+        if (records == null || records.isEmpty()) {
+            return;
+        }
+        List<Long> productModelIds = records.stream()
+                .map(ProductionOrderVo::getProductModelId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (productModelIds.isEmpty()) {
+            return;
+        }
+
+        List<StorageAttachment> attachments = storageAttachmentMapper.selectList(
+                Wrappers.<StorageAttachment>lambdaQuery()
+                        .in(StorageAttachment::getRecordId, productModelIds)
+                        .eq(StorageAttachment::getApplication, StorageAttachmentConstants.StorageAttachmentImage)
+                        .eq(StorageAttachment::getDeleted, 0L)
+                        .orderByAsc(StorageAttachment::getId));
+        if (attachments == null || attachments.isEmpty()) {
+            return;
+        }
+
+        Map<Long, List<StorageAttachment>> attachmentMap = attachments.stream()
+                .collect(Collectors.groupingBy(StorageAttachment::getRecordId, java.util.LinkedHashMap::new, Collectors.toList()));
+        List<Long> blobIds = attachments.stream()
+                .map(StorageAttachment::getStorageBlobId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (blobIds.isEmpty()) {
+            return;
+        }
+
+        Map<Long, StorageBlob> blobMap = storageBlobMapper.selectBatchIds(blobIds).stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.toMap(StorageBlob::getId, item -> item));
+        for (ProductionOrderVo record : records) {
+            List<StorageAttachment> modelAttachments = attachmentMap.get(record.getProductModelId());
+            if (modelAttachments == null || modelAttachments.isEmpty()) {
+                continue;
+            }
+            List<StorageBlobVO> images = modelAttachments.stream()
+                    .map(StorageAttachment::getStorageBlobId)
+                    .map(blobMap::get)
+                    .filter(Objects::nonNull)
+                    .map(this::toStorageBlobVO)
+                    .collect(Collectors.toList());
+            if (!images.isEmpty()) {
+                record.setProductImages(images);
+            }
+        }
+    }
+
+    private StorageBlobVO toStorageBlobVO(StorageBlob blob) {
+        StorageBlobVO vo = BeanUtil.copyProperties(blob, StorageBlobVO.class);
+        vo.setPreviewURL(fileUtil.buildSignedPreviewUrl(vo));
+        vo.setDownloadURL(fileUtil.buildSignedDownloadUrl(vo));
+        return vo;
+    }
 }

--
Gitblit v1.9.3