From f350465db70d6f9db9494483ee0cec7793a9007b Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 19 八月 2026 17:47:57 +0800
Subject: [PATCH] feat(approve): 实现审批流程或签会签功能并优化数据库配置

---
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java |  422 +++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 319 insertions(+), 103 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 62a13ef..3f8c05f 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -2,7 +2,6 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.extra.spring.SpringUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -16,7 +15,6 @@
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.common.enums.AuditEnum;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -33,13 +31,11 @@
 import com.ruoyi.quality.mapper.*;
 import com.ruoyi.quality.pojo.*;
 import com.ruoyi.quality.service.IQualityInspectService;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import lombok.AllArgsConstructor;
 import org.springframework.aop.framework.AopContext;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
 
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
@@ -49,11 +45,15 @@
 import java.util.*;
 import java.util.stream.Collectors;
 
+import static cn.hutool.core.date.LocalDateTimeUtil.between;
+
 @Service
 @AllArgsConstructor
 @Transactional(rollbackFor = Exception.class)
 public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService {
 
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final ProductionMachineRecordMapper productionMachineRecordMapper;
     private IQualityInspectService qualityInspectService;
     private ProductionProductMainMapper productionProductMainMapper;
 
@@ -90,6 +90,8 @@
 
     private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
 
+    private ProductionReportPersonMapper productionReportPersonMapper;
+
     private StockUtils stockUtils;
 
 
@@ -101,7 +103,9 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean addProductMain(ProductionProductMainDto dto) {
-        SysUser user = userMapper.selectUserById(dto.getUserId());
+        LocalDateTime now = LocalDateTime.now();
+        ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
+
         ProductionProductMain productionProductMain = new ProductionProductMain();
         //褰撳墠宸ヨ壓璺嚎瀵瑰簲鐨勫伐搴忚鎯�
         ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(dto.getProductProcessRouteItemId());
@@ -113,7 +117,7 @@
         //宸ヨ壓璺嚎涓綋鍓嶅伐搴忓搴旂殑浜у嚭瑙勬牸鍨嬪彿
         ProductModel productModel = productModelMapper.selectById(productProcessRouteItem.getProductModelId());
         //鏌ヨ璇ョ敓浜ц鍗曞搴旂殑bom
-        ProductProcessRoute productProcessRoute = productProcessRouteMapper.selectById(productProcessRouteItem.getProductRouteId());
+        ProductProcessRoute productProcessRoute = Optional.ofNullable(productProcessRouteMapper.selectById(productProcessRouteItem.getProductRouteId())).orElse(new ProductProcessRoute());
         /*鏂板鎶ュ伐涓昏〃*/
         //鏌ヨ鏈�澶ф姤宸ョ紪鍙�
         String datePrefix = "BG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
@@ -144,28 +148,58 @@
         productionProductMain.setProductNo(productNo);
 
         // 淇敼鐝粍淇℃伅 浠ョ涓�浜轰綔涓哄師鍏坰etUserId setUserName
-        Assert.isTrue(CollUtil.isNotEmpty(dto.getTeamList()),"鐝粍淇℃伅涓嶈兘涓虹┖");
+        Assert.isTrue(CollUtil.isNotEmpty(dto.getTeamList()), "鐝粍淇℃伅涓嶈兘涓虹┖");
 
         productionProductMain.setTeamIds(dto.getTeamList().stream().map(ProductionProductMainDto.Team::getUserId).map(String::valueOf).collect(Collectors.joining(",")));
         productionProductMain.setTeamNames(dto.getTeamList().stream().map(ProductionProductMainDto.Team::getUserName).collect(Collectors.joining(",")));
 
-        productionProductMain.setUserId(dto.getTeamList().get(0).getUserId());
-        productionProductMain.setUserName(dto.getTeamList().get(0).getUserName());
-
+        //鎶ュ伐浜� 鏄� 璋佹姤宸ュ氨鏄槸璋�
+        productionProductMain.setUserId(SecurityUtils.getUserId());
+        productionProductMain.setUserName(SecurityUtils.getLoginUser().getNickName());
 
 
         productionProductMain.setProductProcessRouteItemId(dto.getProductProcessRouteItemId());
         productionProductMain.setWorkOrderId(dto.getWorkOrderId());
-        productionProductMain.setAuditUserId(dto.getAuditUserId());
-        productionProductMain.setAuditUserName(dto.getAuditUserName());
+//        productionProductMain.setAuditUserId(dto.getAuditUserId());
+//        productionProductMain.setAuditUserName(dto.getAuditUserName());
         productionProductMain.setStatus(0);
-        productionProductMain.setStartTime(dto.getStartTime());
-        productionProductMain.setEndTime(dto.getEndTime());
-        productionProductMain.setDeviceId(productProcess.getDeviceId());
-        productionProductMain.setDeviceName(productProcess.getDeviceName());
+        if (ObjectUtils.isNotEmpty(dto.getStartTime()) && ObjectUtils.isNotEmpty(dto.getEndTime())) {
+            productionProductMain.setStartTime(dto.getStartTime());
+            productionProductMain.setEndTime(dto.getEndTime());
+        } else {
+            productionProductMain.setStartTime(productWorkOrder.getStartProductTime());
+            productionProductMain.setEndTime(now);
+        }
+        productionProductMain.setDeviceId(dto.getDeviceId());
+        productionProductMain.setDeviceName(dto.getDeviceName());
+
+        // 瀹℃壒浜轰负鑷繁 鐩存帴閫氳繃瀹℃壒
+        productionProductMain.setAuditUserName(SecurityUtils.getUsername());
+        productionProductMain.setAuditUserId(SecurityUtils.getUserId());
+
         productionProductMainMapper.insert(productionProductMain);
+        /*淇濆瓨鎶ュ伐鐝粍浜哄憳浜ч噺鏃堕暱鏄庣粏*/
+        List<ProductionProductMainDto.Person> personList = dto.getPersonList();
+        BigDecimal personSum = BigDecimal.ZERO;
+        if (CollUtil.isNotEmpty(personList)) {
+            for (ProductionProductMainDto.Person person : personList) {
+                BigDecimal personQty = person.getQuantity() == null ? BigDecimal.ZERO : person.getQuantity();
+                personSum = personSum.add(personQty);
+                ProductionReportPerson reportPerson = new ProductionReportPerson();
+                reportPerson.setProductMainId(productionProductMain.getId());
+                reportPerson.setUserId(person.getUserId());
+                reportPerson.setUserName(person.getUserName());
+                reportPerson.setQuantity(personQty);
+                reportPerson.setWorkHour(person.getWorkHour() != null ? person.getWorkHour() : 0);
+                productionReportPersonMapper.insert(reportPerson);
+            }
+        }
+        BigDecimal totalQuantity = dto.getQuantity() == null ? BigDecimal.ZERO : dto.getQuantity();
+        if (CollUtil.isNotEmpty(personList) && personSum.compareTo(totalQuantity) != 0) {
+            throw new ServiceException("鍚勭彮缁勪骇閲忎箣鍜屽繀椤荤瓑浜庢姤宸ユ�讳骇閲�");
+        }
         /*鏂板鎶ュ伐鎶曞叆琛�*/
-        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(productProcessRoute.getBomId(), productProcess.getId());
+        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(Optional.ofNullable(productProcessRoute.getBomId()).orElse(0), productProcess.getId());
         if (productStructureDtos.isEmpty()) {
             //濡傛灉璇ュ伐搴忔病鏈変骇鍝佺粨鏋勭殑鎶曞叆鍝�,閭h繖涓姇鍏ュ搧鍜屼骇鍑哄搧鏄悓涓�涓�
             ProductStructureDto productStructureDto = new ProductStructureDto();
@@ -174,14 +208,12 @@
             productStructureDtos.add(productStructureDto);
         }
         for (ProductStructureDto productStructureDto : productStructureDtos) {
-
             ProductionProductInput productionProductInput = new ProductionProductInput();
             productionProductInput.setProductModelId(productStructureDto.getProductModelId());
             productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity()));
             productionProductInput.setProductMainId(productionProductMain.getId());
             productionProductInputMapper.insert(productionProductInput);
-            stockUtils.substractStock(productStructureDto.getProductModelId(), productionProductInput.getQuantity(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId());
-
+//            stockUtils.substractStock(productStructureDto.getProductModelId(), productionProductInput.getQuantity(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId());
         }
         /*鏂板鎶ュ伐浜у嚭琛�*/
         ProductionProductOutput productionProductOutput = new ProductionProductOutput();
@@ -190,38 +222,58 @@
         productionProductOutput.setQuantity(dto.getQuantity() != null ? dto.getQuantity() : BigDecimal.ZERO);
         productionProductOutput.setScrapQty(dto.getScrapQty() != null ? dto.getScrapQty() : BigDecimal.ZERO);
         productionProductOutput.setReplenishQty(dto.getReplenishQty());
+        productionProductOutput.setAddQty(dto.getAddQty() != null ? dto.getAddQty() : BigDecimal.ZERO);
         productionProductOutputMapper.insert(productionProductOutput);
-        //鍚堟牸鏁伴噺=鎶ュ伐鏁伴噺-鎶ュ簾鏁伴噺
-        BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty());
-        //鍙湁鍚堟牸鏁伴噺>0鎵嶈兘澧炲姞鐩稿簲鏁版嵁
+        //宸ュ簭娴佽浆鏁伴噺=浜у嚭鏁伴噺+鍔犳斁鏁帮紙鎶ュ簾浠呭仛鏁版嵁璁板綍锛屼笉鎵e噺宸ュ簭娴佽浆鍩烘暟锛屽悇宸ュ簭鎬讳骇閲忎繚鎸佽繛璐級
+        BigDecimal addQty = productionProductOutput.getAddQty() == null ? BigDecimal.ZERO : productionProductOutput.getAddQty();
+        BigDecimal productQty = productionProductOutput.getQuantity().add(addQty);
+        //鍙湁宸ュ簭娴佽浆鏁伴噺>0鎵嶈兘澧炲姞鐩稿簲鏁版嵁
         if (productQty.compareTo(BigDecimal.ZERO) > 0) {
             List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
             /*鏇存柊宸ュ崟鍜岀敓浜ц鍗�*/
-            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
             productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().add(productQty));
-            if (ObjectUtils.isNull(productWorkOrder.getActualStartTime())) {
-                productWorkOrder.setActualStartTime(LocalDate.now());//瀹為檯寮�濮嬫椂闂�
+            // 鏌ヨ璇ュ伐鍗曞搴旂殑鏈�鏃╀笂鏈烘椂闂达紙鎸変笂鏈烘椂闂村崌搴忥紝鍙栫涓�鏉★級
+            List<ProductionMachineRecord> machineRecords = productionMachineRecordMapper.selectList(
+                    Wrappers.<ProductionMachineRecord>lambdaQuery()
+                            .eq(ProductionMachineRecord::getWorkOrderId, productWorkOrder.getId())
+                            .isNotNull(ProductionMachineRecord::getMachineStartTime)
+                            .orderByAsc(ProductionMachineRecord::getMachineStartTime)
+            );
+            if (!machineRecords.isEmpty()) {
+                productWorkOrder.setActualStartTime(machineRecords.get(0).getMachineStartTime());
             }
-            if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) == 0) {
-                productWorkOrder.setActualEndTime(LocalDate.now());//瀹為檯缁撴潫鏃堕棿
+            // 浠呭畬鎴愭暟閲忚揪鍒拌鍒掓暟閲忔椂鎵嶅~鍏呭疄闄呯粨鏉熸椂闂达紝鏈畬鎴愬垯娓呯┖宸插~鐨勭粨鏉熸椂闂达紙鍏佽缁х画鍒嗘壒鎶ュ伐锛�
+            if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) >= 0) {
+                productWorkOrder.setActualEndTime(now);
+                productWorkOrder.setEndProductTime(now);
+                productWorkOrderMapper.updateById(productWorkOrder);
+            } else {
+                // updateById 榛樿蹇界暐 null 瀛楁锛岄渶鐢� UpdateWrapper 鏄惧紡娓呯┖锛堣嚜鎰堝巻鍙茶剰鏁版嵁锛�
+                productWorkOrderMapper.update(null, Wrappers.<ProductWorkOrder>lambdaUpdate()
+                        .eq(ProductWorkOrder::getId, productWorkOrder.getId())
+                        .set(ProductWorkOrder::getActualEndTime, null)
+                        .set(ProductWorkOrder::getEndProductTime, null));
             }
-            productWorkOrderMapper.updateById(productWorkOrder);
             //鐢熶骇璁㈠崟
             ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
             if (ObjectUtils.isNull(productOrder.getStartTime())) {
-                productOrder.setStartTime(LocalDateTime.now());//寮�濮嬫椂闂�
+                productOrder.setStartTime(now);//寮�濮嬫椂闂�
             }
-            if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
+            if (productProcessRouteItem.getDragSort() >= productProcessRouteItems.size() -1 ) {
                 //濡傛灉鏄渶鍚庝竴閬撳伐搴忔姤宸ヤ箣鍚庣敓浜ц鍗曞畬鎴愭暟閲�+
                 productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().add(productQty));
-                if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) == 0) {
-                    productOrder.setEndTime(LocalDateTime.now());//缁撴潫鏃堕棿
+                if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) >= 0) {
+                    productOrder.setEndTime(now);//缁撴潫鏃堕棿
                 }
             }
             productOrderMapper.updateById(productOrder);
         }
-
-        //nextAddProductMain(productionProductOutput) // 鐢变簬闇�瑕佸鏍革紝鎵�浠ラ渶瑕佹媶灏佷笅鏉�
+        ProductAuditVo productAuditVo = new ProductAuditVo();
+        productAuditVo.setId(productionProductMain.getId());
+        productAuditVo.setAuditStatus(AuditEnum.AUDIT_SUCCESS);
+        productAuditVo.setAuditOpinion("");
+        ((ProductionProductMainService) AopContext.currentProxy()).auditProductMain(productAuditVo);
+//        nextAddProductMain(productionProductOutput) // 鐢变簬闇�瑕佸鏍革紝鎵�浠ラ渶瑕佹媶灏佷笅鏉�
         return true;
     }
 
@@ -231,7 +283,7 @@
         ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productAuditVo.getId());
 
         // 褰撳墠瀹℃壒浜� 瑕佷笌褰撳墠鐧诲綍浜轰负鍚屼竴浜�
-        if(productionProductMain.getAuditUserId() != -1){
+        if (productionProductMain.getAuditUserId() != -1) {
             Assert.isTrue(SecurityUtils.getUserId().equals(productionProductMain.getAuditUserId()), "褰撳墠鐧诲綍鐢ㄦ埛涓嶆槸褰撳墠瀹℃壒浜�");
         }
 
@@ -260,10 +312,13 @@
                 // 鍑忓皯 鏇存柊宸ュ崟鍜岀敓浜ц鍗�
                 ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId());
                 ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
+                //宸ュ簭娴佽浆鏁伴噺=浜у嚭鏁伴噺+鍔犳斁鏁帮紙涓庢姤宸ョ疮鍔犲彛寰勪竴鑷达紝鎶ュ簾涓嶆墸鍑忔祦杞熀鏁帮級
+                BigDecimal processQty = productionProductOutput.getQuantity().add(
+                        productionProductOutput.getAddQty() == null ? BigDecimal.ZERO : productionProductOutput.getAddQty());
 
                 productWorkOrder.setCompleteQuantity(
                         productWorkOrder.getCompleteQuantity()
-                                .subtract(productionProductOutput.getQuantity())
+                                .subtract(processQty)
                                 .max(BigDecimal.ZERO)
                 );
                 List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
@@ -273,16 +328,16 @@
                     //濡傛灉鏄渶鍚庝竴閬撳伐搴忔姤宸ヤ箣鍚庣敓浜ц鍗� 闇�瑕佹墸闄�
                     productOrder.setCompleteQuantity(
                             productOrder.getCompleteQuantity()
-                                    .subtract(productionProductOutput.getQuantity())
+                                    .subtract(processQty)
                                     .max(BigDecimal.ZERO)
                     );
-                    if (productOrder.getCompleteQuantity().compareTo(productionProductOutput.getQuantity()) > 0) {
+                    if (productOrder.getCompleteQuantity().compareTo(processQty) > 0) {
                         productOrder.setEndTime(null);
                     }
                     productOrderMapper.updateById(productOrder);
                 }
 
-                if (productWorkOrder.getCompleteQuantity().compareTo(productionProductOutput.getQuantity()) > 0) {
+                if (productWorkOrder.getCompleteQuantity().compareTo(processQty) > 0) {
                     productWorkOrder.setActualEndTime(null);
                 }
 
@@ -304,10 +359,11 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void nextAddProductMain(@NotNull ProductionProductOutput productionProductOutput){
-        //鍚堟牸鏁伴噺=鎶ュ伐鏁伴噺-鎶ュ簾鏁伴噺
+    public void nextAddProductMain(@NotNull ProductionProductOutput productionProductOutput) {
+        //瀹為檯鍏ュ簱鏁伴噺=浜у嚭鏁伴噺+鍔犳斁鏁�-鎶ュ簾鏁伴噺
         ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productionProductOutput.getProductMainId());
-        BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty());
+        BigDecimal addQty = productionProductOutput.getAddQty() == null ? BigDecimal.ZERO : productionProductOutput.getAddQty();
+        BigDecimal productQty = productionProductOutput.getQuantity().add(addQty).subtract(productionProductOutput.getScrapQty());
         ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(productionProductMain.getProductProcessRouteItemId());
         ProductProcess productProcess = productProcessMapper.selectById(productProcessRouteItem.getProcessId());
         //宸ヨ壓璺嚎涓綋鍓嶅伐搴忓搴旂殑浜у嚭瑙勬牸鍨嬪彿
@@ -322,75 +378,232 @@
                 //瀵瑰簲鐨勮繃绋嬫鎴栬�呭嚭鍘傛
                 int inspectType = 1;
                 String process = productProcess.getName();//宸ュ簭
-                if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
+                if (productProcessRouteItem.getDragSort() == (productProcessRouteItems.size()-1)) {
                     //鏈�鍚庝竴閬撳伐搴忕敓鎴愬嚭鍘傛
                     inspectType = 2;
                     process = null;
                 }
-                Product product = productMapper.selectById(productModel.getProductId());
-                QualityInspect qualityInspect = new QualityInspect();
-                qualityInspect.setProductId(product.getId());
-                qualityInspect.setProductName(product.getProductName());
-                qualityInspect.setModel(productModel.getModel());
-                qualityInspect.setUnit(productModel.getUnit());
-                qualityInspect.setQuantity(productQty);
-                qualityInspect.setProcess(process);
-                qualityInspect.setInspectState(0);
-                qualityInspect.setInspectType(inspectType);
-                qualityInspect.setProductMainId(productionProductMain.getId());
-                qualityInspect.setProductModelId(productModel.getId());
-                qualityInspectMapper.insert(qualityInspect);
-                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
-                if (!qualityTestStandard.isEmpty()) {
-                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
-                    qualityInspectMapper.updateById(qualityInspect);
-                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
-                                    .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))//榛樿鑾峰彇鏈�鏂扮殑
-                            .forEach(qualityTestStandardParam -> {
-                                QualityInspectParam param = new QualityInspectParam();
-                                BeanUtils.copyProperties(qualityTestStandardParam, param);
-                                param.setId(null);
-                                param.setInspectId(qualityInspect.getId());
-                                qualityInspectParamMapper.insert(param);
-                            });
+                // 鎺掍骇涓嬭揪鏃跺凡涓鸿宸ュ崟棰勭敓鎴愯川妫�鍗曪紙product_main_id IS NULL锛夛紝鎶ュ伐瀹℃牳鏃惰棰嗗苟鏇存柊涓哄疄闄呮暟閲�
+                QualityInspect preInspect = qualityInspectMapper.selectOne(
+                        Wrappers.<QualityInspect>lambdaQuery()
+                                .eq(QualityInspect::getWorkOrderId, productionProductMain.getWorkOrderId())
+                                .isNull(QualityInspect::getProductMainId)
+                                .last("limit 1"));
+                if (preInspect != null) {
+                    preInspect.setProductMainId(productionProductMain.getId());
+                    preInspect.setQuantity(productQty);
+                    if (preInspect.getInspectState() != null && preInspect.getInspectState() == 1
+                            && preInspect.getInspectType() != null && preInspect.getInspectType() == 2) {
+                        // 宸叉彁浜や笖涓哄嚭鍘傛锛氬垹闄ゆ寜璁″垝鏁伴噺鍏ュ簱鐨勮褰曪紝鎸夊疄闄呮暟閲忛噸鏂板叆搴�
+                        stockUtils.deleteStockInRecord(preInspect.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
+                        stockUtils.addStock(productModel.getId(), productQty, StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), preInspect.getId(), "-", "-", "-");
+                    }
+                    qualityInspectMapper.updateById(preInspect);
+                } else {
+                    insertQualityInspect(productProcessRouteItem, inspectType, process, productionProductMain.getId(), productionProductMain.getWorkOrderId(), productQty);
                 }
-            }else {
+            } else {
                 //鐩存帴鍏ュ簱
-                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(),"-","-","-");
+                if (productProcessRouteItem.getDragSort() == (productProcessRouteItems.size()-1)) {
+                    //鏈�鍚庝竴閬撳伐搴忔墠浼氬叆搴�
+                    stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(), "-", "-", "-");
+                }
             }
 
             /*娣诲姞鐢熶骇鏍哥畻        鍖哄垎宸ュ簭鏄浠惰繕鏄鏃�*/
             BigDecimal workHours = productProcess.getSalaryQuota();
-
-            SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder()
-                    .productMainId(productionProductMain.getId())
-                    .schedulingUserId(user.getUserId())
-                    .schedulingUserName(user.getNickName())
-                    .finishedNum(productQty)
-                    .workHours(workHours)
-                    .process(productProcess.getName())
-                    .schedulingDate(LocalDate.now())
-                    .tenantId(productionProductOutput.getTenantId())
-                    .build();
-            salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting);
-        }
-
-        //濡傛灉鎶ュ簾鏁伴噺>0,闇�瑕佽繘鍏ユ姤搴熺殑搴撳瓨
-        if (ObjectUtils.isNotEmpty(productionProductOutput.getScrapQty())) {
-            if (productionProductOutput.getScrapQty().compareTo(BigDecimal.ZERO) > 0) {
-                stockUtils.addUnStock(productModel.getId(), productionProductOutput.getScrapQty(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId(),"-","-","-");
+            List<ProductionMachineRecord> productionMachineRecords = productionMachineRecordMapper.selectList(Wrappers.<ProductionMachineRecord>lambdaQuery().eq(ProductionMachineRecord::getWorkOrderId, productionProductMain.getWorkOrderId()));
+            // 鎶ュ伐鐝粍浜哄憳浜ч噺鏃堕暱鏄庣粏锛堟湁鏄庣粏鍒欐寜浜虹敓鎴愭牳绠楋紝鏃犳槑缁嗗垯鍥為��鏈哄彴鎿嶄綔鍛橀�昏緫锛�
+            List<ProductionReportPerson> personList = productionReportPersonMapper.selectList(Wrappers.<ProductionReportPerson>lambdaQuery().eq(ProductionReportPerson::getProductMainId, productionProductMain.getId()));
+            // 璁惧鍙栨姤宸ュ崟璁惧锛屾湭濉啓鏃跺洖閫�鍙栬宸ュ崟浠讳竴鍙版満
+            Long reportDeviceId = productionProductMain.getDeviceId() != null
+                    ? productionProductMain.getDeviceId()
+                    : productionMachineRecords.stream().map(ProductionMachineRecord::getMachineId).filter(Objects::nonNull).findFirst().orElse(null);
+            if (CollUtil.isNotEmpty(personList)) {
+                // 姣忔鎶ュ伐鐙珛鎸変汉鐢熸垚鏍哥畻锛堟敮鎸佸垎鎵规姤宸ョ洿鑷冲畬鎴愶級锛屼笉鍙椾笂鏈鸿褰曟姤宸ョ姸鎬佸奖鍝�
+                BigDecimal netQty = productQty;
+                BigDecimal rawQuantity = productionProductOutput.getQuantity() == null ? BigDecimal.ZERO : productionProductOutput.getQuantity();
+                for (ProductionReportPerson person : personList) {
+                    BigDecimal personQty = person.getQuantity() == null ? BigDecimal.ZERO : person.getQuantity();
+                    BigDecimal finishedNum;
+                    if (netQty.compareTo(rawQuantity) == 0 || rawQuantity.compareTo(BigDecimal.ZERO) == 0) {
+                        // 鏃犳姤搴燂紙鎴栨瘺浜ч噺涓�0锛夋椂鍑�鍊煎嵆姣涗骇閲忥紝鐩存帴鍙栦釜浜轰骇閲�
+                        finishedNum = personQty;
+                    } else {
+                        // 鏈夋姤搴熸椂鎸夊悇浜烘瘺浜ч噺鍗犳瘮鍒嗘憡鍑�鍊硷紝鍥涜垗浜斿叆淇濈暀2浣�
+                        finishedNum = personQty.multiply(netQty).divide(rawQuantity, 2, BigDecimal.ROUND_HALF_UP);
+                    }
+                    SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder()
+                            .productMainId(productionProductMain.getId())
+                            .schedulingUserId(person.getUserId())
+                            .schedulingUserName(person.getUserName())
+                            .finishedNum(finishedNum)
+                            .workHours(workHours)
+                            .process(productProcess.getName())
+                            .schedulingDate(LocalDate.now())
+                            .tenantId(productionProductOutput.getTenantId())
+                            .deviceId(reportDeviceId)
+                            .workHour(person.getWorkHour() == null ? 0L : person.getWorkHour().longValue())
+                            .build();
+                    salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting);
+                }
+                // 璇ュ伐鍗曚笂鏈鸿褰曟湰娆″凡鎶ュ伐
+                for (ProductionMachineRecord productionMachineRecord : productionMachineRecords) {
+                    if (!productionMachineRecord.getReportStatus()) {
+                        productionMachineRecord.setReportStatus(true);
+                        productionMachineRecordMapper.updateById(productionMachineRecord);
+                    }
+                }
+            } else if (ObjectUtils.isNotEmpty(productionMachineRecords)) {
+                // 鍏煎鏃ф暟鎹細鏈紶浜哄憳鏄庣粏鍒欏洖閫�鎸夋湭鎶ュ伐鐨勬満鍙颁笂鏈烘搷浣滃憳鐢熸垚鏍哥畻
+                for (ProductionMachineRecord productionMachineRecord : productionMachineRecords) {
+                    //璇存槑宸茬粡娣诲姞杩囦簡锛屼笉娣诲姞浜�
+                    if (productionMachineRecord.getReportStatus()) {
+                        continue;
+                    }
+                    for (String s : productionMachineRecord.getOperatorId().split(",")) {
+                        Long minutes = 0L;
+                        if (productionMachineRecord.getMachineStartTime() != null) {
+                            minutes = between(productionMachineRecord.getMachineStartTime(), LocalDateTime.now()).toMinutes();
+                        }
+                        SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder()
+                                .productMainId(productionProductMain.getId())
+                                .schedulingUserId(Long.parseLong(s))
+                                .schedulingUserName(Optional.of(userMapper.selectUserById(Long.parseLong(s))).orElse(new SysUser()).getNickName())
+                                .finishedNum(productQty)
+                                .workHours(workHours)
+                                .process(productProcess.getName())
+                                .schedulingDate(LocalDate.now())
+                                .tenantId(productionProductOutput.getTenantId())
+                                .deviceId(productionMachineRecord.getMachineId())
+                                .workHour(minutes)
+                                .build();
+                        salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting);
+                    }
+                    productionMachineRecord.setReportStatus(true);
+                    productionMachineRecordMapper.updateById(productionMachineRecord);
+                }
             }
         }
+    }
+
+    /**
+     * 鐢熸垚璐ㄦ鍗曞苟鍥炲~妫�娴嬫爣鍑�/妫�楠屽弬鏁�
+     */
+    private void insertQualityInspect(ProductProcessRouteItem routeItem, Integer inspectType, String process,
+                                      Long productMainId, Long workOrderId, BigDecimal quantity) {
+        ProductModel productModel = productModelMapper.selectById(routeItem.getProductModelId());
+        Product product = productMapper.selectById(productModel.getProductId());
+        QualityInspect qualityInspect = new QualityInspect();
+        qualityInspect.setProductId(product.getId());
+        qualityInspect.setProductName(product.getProductName());
+        qualityInspect.setModel(productModel.getModel());
+        qualityInspect.setUnit(productModel.getUnit());
+        qualityInspect.setQuantity(quantity);
+        qualityInspect.setProcess(process);
+        qualityInspect.setInspectState(0);
+        qualityInspect.setInspectType(inspectType);
+        qualityInspect.setProductMainId(productMainId);
+        qualityInspect.setWorkOrderId(workOrderId);
+        qualityInspect.setProductModelId(productModel.getId());
+        qualityInspectMapper.insert(qualityInspect);
+        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
+        if (!qualityTestStandard.isEmpty()) {
+            qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
+            qualityInspectMapper.updateById(qualityInspect);
+            qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
+                            .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))//榛樿鑾峰彇鏈�鏂扮殑
+                    .forEach(qualityTestStandardParam -> {
+                        QualityInspectParam param = new QualityInspectParam();
+                        BeanUtils.copyProperties(qualityTestStandardParam, param);
+                        param.setId(null);
+                        param.setInspectId(qualityInspect.getId());
+                        qualityInspectParamMapper.insert(param);
+                    });
+        }
+    }
+
+    @Override
+    public void preGenerateQualityInspectForOrder(Long productOrderId) {
+        if (productOrderId == null) {
+            return;
+        }
+        ProductProcessRoute productProcessRoute = productProcessRouteMapper.selectOne(
+                Wrappers.<ProductProcessRoute>lambdaQuery()
+                        .eq(ProductProcessRoute::getProductOrderId, productOrderId));
+        if (productProcessRoute == null) {
+            return;
+        }
+        List<ProductProcessRouteItem> items = productProcessRouteItemMapper.selectList(
+                Wrappers.<ProductProcessRouteItem>lambdaQuery()
+                        .eq(ProductProcessRouteItem::getProductRouteId, productProcessRoute.getId())
+                        .orderByAsc(ProductProcessRouteItem::getDragSort)
+                        .orderByAsc(ProductProcessRouteItem::getId));
+        if (items.isEmpty()) {
+            return;
+        }
+        // 绗竴閬撳伐搴忛渶璐ㄦ鎵嶉鐢熸垚
+        ProductProcessRouteItem first = items.get(0);
+        if (!Boolean.TRUE.equals(first.getIsQuality())) {
+            return;
+        }
+        ProductWorkOrder workOrder = productWorkOrderMapper.selectOne(
+                Wrappers.<ProductWorkOrder>lambdaQuery()
+                        .eq(ProductWorkOrder::getProductProcessRouteItemId, first.getId()));
+        if (workOrder == null) {
+            return;
+        }
+        // 璇ュ伐鍗曞凡瀛樺湪棰勭敓鎴愯川妫�鍗曞垯涓嶉噸澶嶇敓鎴�
+        Long existCount = qualityInspectMapper.selectCount(
+                Wrappers.<QualityInspect>lambdaQuery()
+                        .eq(QualityInspect::getWorkOrderId, workOrder.getId())
+                        .isNull(QualityInspect::getProductMainId));
+        if (existCount != null && existCount > 0) {
+            return;
+        }
+        boolean onlyOne = items.size() == 1;
+        int inspectType = onlyOne ? 2 : 1;
+        String process = null;
+        if (!onlyOne) {
+            ProductProcess processEntity = productProcessMapper.selectById(first.getProcessId());
+            if (processEntity != null) {
+                process = processEntity.getName();
+            }
+        }
+        insertQualityInspect(first, inspectType, process, null, workOrder.getId(), workOrder.getPlanQuantity());
+    }
+
+    @Override
+    public void cleanPreGeneratedQualityInspects(List<Long> workOrderIds) {
+        if (CollUtil.isEmpty(workOrderIds)) {
+            return;
+        }
+        List<QualityInspect> preInspects = qualityInspectMapper.selectList(
+                Wrappers.<QualityInspect>lambdaQuery()
+                        .in(QualityInspect::getWorkOrderId, workOrderIds)
+                        .isNull(QualityInspect::getProductMainId));
+        if (CollUtil.isEmpty(preInspects)) {
+            return;
+        }
+        for (QualityInspect pre : preInspects) {
+            if (pre.getInspectState() != null && pre.getInspectState() == 1) {
+                throw new ServiceException("宸叉彁浜ょ殑妫�楠屽崟涓嶈兘鍒犻櫎");
+            }
+        }
+        List<Long> inspectIds = preInspects.stream().map(QualityInspect::getId).collect(Collectors.toList());
+        qualityInspectParamMapper.delete(
+                Wrappers.<QualityInspectParam>lambdaQuery().in(QualityInspectParam::getInspectId, inspectIds));
+        qualityInspectMapper.deleteBatchIds(inspectIds);
     }
 
     @Override
     public Boolean removeProductMain(Long id) {
         //鍒ゆ柇璇ユ潯鎶ュ伐鏄惁涓嶅悎鏍煎鐞�,濡傛灉涓嶅悎鏍煎鐞嗕簡锛屽垯涓嶅厑璁稿垹闄�
         List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, id));
-        if (qualityInspects.size() > 0){
+        if (qualityInspects.size() > 0) {
             List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(Wrappers.<QualityUnqualified>lambdaQuery()
                     .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
-            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState()==1) {
+            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
                 throw new ServiceException("璇ユ潯鎶ュ伐宸茬粡涓嶅悎鏍煎鐞嗕簡锛屼笉鍏佽鍒犻櫎");
             }
         }
@@ -403,18 +616,23 @@
                 new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                         .eq(SalesLedgerProductionAccounting::getProductMainId, productionProductMain.getId())
         );
+        /*鍒犻櫎鎶ュ伐鐝粍浜哄憳浜ч噺鏃堕暱鏄庣粏*/
+        productionReportPersonMapper.delete(
+                new LambdaQueryWrapper<ProductionReportPerson>()
+                        .eq(ProductionReportPerson::getProductMainId, productionProductMain.getId())
+        );
         /*鏇存柊宸ュ崟鍜岀敓浜ц鍗�*/
         ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId());
         if (productWorkOrder != null && productionProductOutput != null) {
             BigDecimal outputQty = productionProductOutput.getQuantity() == null ? BigDecimal.ZERO : productionProductOutput.getQuantity();
-            BigDecimal scrapQty = productionProductOutput.getScrapQty() == null ? BigDecimal.ZERO : productionProductOutput.getScrapQty();
+            BigDecimal addQty = productionProductOutput.getAddQty() == null ? BigDecimal.ZERO : productionProductOutput.getAddQty();
             BigDecimal completeQty = productWorkOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productWorkOrder.getCompleteQuantity();
 
             // 蹇呴』涓哄鏍搁�氳繃鐨勬墠浼氬噺灏戞暟閲�
 
 
-            BigDecimal validQuantity = outputQty.subtract(scrapQty);
-            if(productionProductMain.getAuditStatus() != 2){
+            BigDecimal validQuantity = outputQty.add(addQty);
+            if (productionProductMain.getAuditStatus() != 2) {
                 productWorkOrder.setCompleteQuantity(completeQty.subtract(validQuantity).max(BigDecimal.ZERO));
             }
             productWorkOrder.setActualEndTime(null);
@@ -429,8 +647,8 @@
             if (productOrder != null) {
                 BigDecimal orderCompleteQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity();
                 BigDecimal totalQty = productionProductOutput.getQuantity() != null ? productionProductOutput.getQuantity() : BigDecimal.ZERO;
-                BigDecimal scrapQty = productionProductOutput.getScrapQty() != null ? productionProductOutput.getScrapQty() : BigDecimal.ZERO;
-                BigDecimal actualQualifiedQty = totalQty.subtract(scrapQty);
+                BigDecimal addQty = productionProductOutput.getAddQty() != null ? productionProductOutput.getAddQty() : BigDecimal.ZERO;
+                BigDecimal actualQualifiedQty = totalQty.add(addQty);
                 BigDecimal newCompleteQty = orderCompleteQty.subtract(actualQualifiedQty);
                 productOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
                 productOrder.setEndTime(null);
@@ -448,7 +666,7 @@
                     new LambdaQueryWrapper<QualityInspectParam>()
                             .eq(QualityInspectParam::getInspectId, q.getId()));
             qualityInspectMapper.deleteById(q.getId());
-                stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
+            stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
         });
 
         // 鍒犻櫎浜у嚭璁板綍
@@ -457,12 +675,10 @@
         //鍒犻櫎鎶曞叆璁板綍
         productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                 .eq(ProductionProductInput::getProductMainId, 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());
+//        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
         // 鍒犻櫎涓昏〃
         productionProductMainMapper.deleteById(productionProductMain.getId());
         return true;
@@ -472,4 +688,4 @@
     public ArrayList<Long> listMain(List<Long> idList) {
         return productionProductMainMapper.listMain(idList);
     }
-}
+}
\ No newline at end of file

--
Gitblit v1.9.3