From 1e123568c2f561013f5636e45dc0db30b17a3517 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 10 九月 2026 16:39:26 +0800
Subject: [PATCH] feat(basic): 添加产品条码功能并完善生产统计报表

---
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java |   83 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index 20f4bfc..7154c0e 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -15,17 +15,24 @@
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.bean.BeanUtils;
+import com.ruoyi.device.mapper.DeviceLedgerMapper;
+import com.ruoyi.device.pojo.DeviceLedger;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.production.bean.dto.ProductStructureDto;
 import com.ruoyi.production.bean.dto.ProductionProductMainDto;
+import com.ruoyi.production.bean.vo.DeviceOutputStatVo;
+import com.ruoyi.production.bean.vo.PieceWageSummaryVo;
 import com.ruoyi.production.enums.ProductOrderStatusEnum;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
+import com.ruoyi.production.service.PieceRateConfigService;
 import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.quality.mapper.*;
 import com.ruoyi.quality.pojo.*;
+import com.ruoyi.stock.pojo.StockInRecord;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.service.StockInventoryService;
 import com.ruoyi.technology.mapper.TechnologyOperationMapper;
@@ -41,6 +48,7 @@
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -77,7 +85,10 @@
     private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
     private final TechnologyOperationMapper technologyOperationMapper;
     private final StockUtils stockUtils;
+    private final StockInRecordService stockInRecordService;
     private final StockInventoryService stockInventoryService;
+    private final DeviceLedgerMapper deviceLedgerMapper;
+    private final PieceRateConfigService pieceRateConfigService;
 
     @Override
     public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) {
@@ -272,6 +283,14 @@
         productionProductMain.setProductNo(generateProductNo());
         productionProductMain.setUserId(user == null ? dto.getUserId() : user.getUserId());
         productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName());
+        if (dto.getDeviceId() != null) {
+            DeviceLedger device = deviceLedgerMapper.selectById(dto.getDeviceId());
+            if (device == null) {
+                throw new ServiceException("璁惧涓嶅瓨鍦紝ID=" + dto.getDeviceId());
+            }
+            productionProductMain.setDeviceId(device.getId());
+            productionProductMain.setDeviceName(device.getDeviceName());
+        }
         productionProductMain.setProductionOperationTaskId(taskId);
         productionProductMain.setStatus(0);
         productionProductMain.setWorkHour(dto.getWorkHour());
@@ -291,7 +310,6 @@
             // 褰撳墠瀹炵幇鎸夊伐搴忔垚鍝佺洿鎺ヤ綔涓烘姇鍏ワ紝鍚庣画鑻ユ帴鍏ラ鏂欒褰曞彲鍦ㄨ繖閲屾浛鎹㈡潵婧愩��
             ProductionProductInput productionProductInput = new ProductionProductInput();
             productionProductInput.setProductionProductMainId(productionProductMain.getId());
-            productionProductInput.setProductMainId(productionProductMain.getId());
             productionProductInput.setProductModelId(item.getProductModelId());
             productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity())));
             productionProductInput.setQuantity(productionProductInput.getInputQuantity());
@@ -300,13 +318,14 @@
 
         ProductionProductOutput productionProductOutput = new ProductionProductOutput();
         productionProductOutput.setProductionProductMainId(productionProductMain.getId());
-        productionProductOutput.setProductMainId(productionProductMain.getId());
         productionProductOutput.setProductModelId(productModel.getId());
         productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity()));
         productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
         productionProductOutputMapper.insert(productionProductOutput);
         BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity());
+        BigDecimal scrapQty = defaultDecimal(productionProductOutput.getScrapQty());
         BigDecimal productQty = reportQty;
+        String qualifiedBatchNo = null;
 
         List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
@@ -345,13 +364,19 @@
                                 qualityInspectParamMapper.insert(param);
                             });
                 }
-            } else {
+            } else if(isLastOperation){
+                //(鏈�鍚庝竴閬撳伐搴忔墠鍏ュ簱)
                 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);
+                qualifiedBatchNo = resolveLatestStockInBatchNo(
+                        productionProductMain.getId(),
+                        StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
+                        productModel.getId(),
+                        "0");
             }
 
             productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
@@ -370,8 +395,10 @@
             if (ObjectUtils.isNull(productionOrder.getStartTime())) {
                 productionOrder.setStartTime(LocalDateTime.now());
             }
-            // 璁㈠崟鐘舵�佺敱鏈�鍚庝竴閬撳伐搴忕殑鍚堟牸浜у嚭鎺ㄥ姩锛岄伩鍏嶄腑闂村伐搴忔彁鍓嶅畬宸ャ��
-            productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
+            // 浠呭緟寮�濮嬬姸鎬佹墠鎺ㄨ繘鍒拌繘琛屼腑锛岄伩鍏嶉潪鏈亾宸ュ簭鎶ュ伐鏃惰鐩栧凡瀹屾垚鐘舵�併��
+            if (ProductOrderStatusEnum.WAIT.getCode().equals(productionOrder.getStatus())) {
+                productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
+            }
             if (isLastOperation) {
                 productionOrder.setCompleteQuantity(defaultDecimal(productionOrder.getCompleteQuantity()).add(productQty));
                 if (productionOrder.getQuantity() != null
@@ -393,12 +420,42 @@
             productionAccount.setSchedulingUserId(user == null ? null : user.getUserId());
             productionAccount.setSchedulingUserName(user == null ? dto.getUserName() : user.getNickName());
             productionAccount.setFinishedNum(productQty);
-            productionAccount.setWorkHours(workHours);
+            productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
             productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
             productionAccount.setSchedulingDate(LocalDateTime.now());
             productionAccountMapper.insert(productionAccount);
         }
+        if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
+            stockUtils.addUnStockWithBatchNo(
+                    productModel.getId(),
+                    scrapQty,
+                    StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(),
+                    productionProductMain.getId(),
+                    qualifiedBatchNo);
+        }
         return true;
+    }
+
+    private String resolveLatestStockInBatchNo(Long recordId,
+                                               String recordType,
+                                               Long productModelId,
+                                               String stockType) {
+        if (recordId == null || productModelId == null) {
+            return null;
+        }
+        StockInRecord stockInRecord = stockInRecordService.getOne(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .eq(StockInRecord::getRecordId, recordId)
+                        .eq(StockInRecord::getRecordType, recordType)
+                        .eq(StockInRecord::getProductModelId, productModelId)
+                        .eq(StockInRecord::getType, stockType)
+                        .orderByDesc(StockInRecord::getId)
+                        .last("limit 1"),
+                false);
+        if (stockInRecord == null) {
+            throw new ServiceException("鏈壘鍒板搴旂殑鍏ュ簱鐢宠璁板綍");
+        }
+        return stockInRecord.getBatchNo();
     }
 
     private void syncOperationParamInputValue(ProductionProductMainDto dto,
@@ -646,4 +703,18 @@
         // 鏌ヨ涓昏〃ID闆嗗悎
         return productionProductMainMapper.listMain(idList);
     }
+
+    @Override
+    public List<PieceWageSummaryVo> wageSummary(LocalDate startDate, LocalDate endDate, String userName) {
+        return productionProductMainMapper.wageSummary(startDate, endDate, userName);
+    }
+
+    @Override
+    public List<DeviceOutputStatVo> outputStat(String dimension, LocalDate startDate, LocalDate endDate, Long deviceId) {
+        String dim = dimension == null || dimension.isEmpty() ? "device" : dimension;
+        if (!Arrays.asList("device", "operation", "product").contains(dim)) {
+            throw new ServiceException("缁熻缁村害涓嶅悎娉曪紝浠呮敮鎸� device/operation/product");
+        }
+        return productionProductMainMapper.outputStat(dim, startDate, endDate, deviceId);
+    }
 }

--
Gitblit v1.9.3