From 6c95c2f6a3602fe6f92898dd322c20bbe955e69d Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期二, 21 四月 2026 18:03:20 +0800
Subject: [PATCH] feat: 成品入库增加审批环节,原材质检后提交入库时增加一个审批环节

---
 src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java  |    3 
 src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java  |  113 ++++++++++++
 src/main/java/com/ruoyi/sales/dto/SalesScanInboundDto.java                   |    3 
 src/main/resources/mapper/device/DeviceMaintenanceMapper.xml                 |    5 
 src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java                     |    5 
 src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java                 |    3 
 src/main/java/com/ruoyi/quality/service/IQualityInspectService.java          |    6 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java |   11 +
 src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java               |    7 
 src/main/resources/mapper/stock/StockInRecordMapper.xml                      |   32 ++-
 src/main/java/com/ruoyi/quality/pojo/QualityInspect.java                     |    6 
 doc/河南鹤壁天沐钢化玻璃厂.sql                                                          |   11 +
 src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java                     |    3 
 src/main/resources/mapper/quality/QualityInspectMapper.xml                   |   12 +
 src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java     |  108 ++++++++++++
 src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java  |    3 
 src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java                  |    3 
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java       |  198 +++++++++++++++++++++
 src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java                    |    3 
 src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java                   |    3 
 20 files changed, 508 insertions(+), 30 deletions(-)

diff --git "a/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql" "b/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
index a1325ec..e18f1d9 100644
--- "a/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
+++ "b/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
@@ -159,5 +159,12 @@
 ALTER TABLE `product-inventory-management-hbtmblc`.`device_ledger`
     ADD COLUMN `product_process_id` bigint NULL COMMENT '宸ュ簭ID' AFTER `type`;
 
-ALTER TABLE `maintenance_task` ADD COLUMN `maintenance_location` VARCHAR ( 255 ) CHARACTER
-    SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璁惧淇濆吇浣嶇疆';
\ No newline at end of file
+ALTER TABLE `device_maintenance` ADD COLUMN `maintenance_location` VARCHAR ( 255 ) CHARACTER
+    SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璁惧淇濆吇浣嶇疆';
+
+
+
+
+ALTER TABLE `quality_inspect`
+    ADD COLUMN `approval_status` bigint DEFAULT '1' COMMENT '鍏ュ簱瀹℃壒鐘舵�侊細1-寰呭鏍革紝2-瀹℃壒涓紝3-瀹℃壒閫氳繃锛�4-瀹℃壒澶辫触' AFTER `inspect_state`,
+    ADD COLUMN `approve_user_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍏ュ簱瀹℃壒浜篿d锛岄�楀彿鍒嗛殧' AFTER `approval_status`;
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
index f9b6d0f..ee1d11d 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -31,6 +31,8 @@
 import com.ruoyi.sales.pojo.SalesQuotation;
 import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.ShippingInfoService;
+import com.ruoyi.sales.service.ISalesLedgerService;
+import com.ruoyi.quality.service.IQualityInspectService;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
@@ -91,6 +93,12 @@
     @Autowired
     @Lazy
     private ShippingInfoService shippingInfoService;
+    @Autowired
+    @Lazy
+    private ISalesLedgerService salesLedgerService;
+    @Autowired
+    @Lazy
+    private IQualityInspectService qualityInspectService;
 
 
     public ApproveProcess getApproveById(String id) {
@@ -280,6 +288,104 @@
             }
         }
 
+        // 閿�鍞鍗曟垚鍝佸叆搴撳鎵�
+        if (approveProcess.getApproveType().equals(9)) {
+            String reason = approveProcess.getApproveReason();
+            // 閿�鍞牸寮忥細鍏ュ簱瀹℃壒:鍚堝悓鍙�:salesLedgerId:productId1,productId2
+            // 璐ㄦ鏍煎紡锛氬師鏉愭枡璐ㄦ鍏ュ簱瀹℃壒:inspectId:purchaseLedgerId
+            if (org.springframework.util.StringUtils.hasText(reason)) {
+                if (reason.startsWith("鍘熸潗鏂欒川妫�鍏ュ簱瀹℃壒:")) {
+                    Integer inspectId = null;
+                    String remark = approveProcess.getApproveRemark();
+                    // 鏂伴�昏緫锛氫笟鍔″弬鏁版斁鍦� approveRemark
+                    if (org.springframework.util.StringUtils.hasText(remark) && remark.startsWith("qualityQualifiedInbound:")) {
+                        String[] split = remark.split(":");
+                        if (split.length >= 2) {
+                            inspectId = Integer.valueOf(split[1]);
+                        }
+                    }
+                    if (inspectId == null) {
+                        String[] split = reason.split(":");
+                        if (split.length >= 2) {
+                            inspectId = Integer.valueOf(split[1]);
+                        }
+                    }
+                    if (inspectId != null) {
+                        if (status.equals(2)) {
+                            qualityInspectService.executeQualifiedInboundApproval(inspectId);
+                        } else if (status.equals(3)) {
+                            qualityInspectService.markQualifiedInboundApprovalStatus(inspectId, 4);
+                        } else if (status.equals(1)) {
+                            qualityInspectService.markQualifiedInboundApprovalStatus(inspectId, 2);
+                        }
+                    }
+                    // 璐ㄦ瀹℃壒涓嶉渶瑕佺户缁蛋閿�鍞鍗曞叆搴�
+                    return;
+                }
+                if (reason.startsWith("閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:") || reason.startsWith("閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:")) {
+                    String remark = approveProcess.getApproveRemark();
+                    boolean qualified = reason.startsWith("閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:");
+                    String prefix = qualified ? "scanQualified:" : "scanUnqualified:";
+                    if (org.springframework.util.StringUtils.hasText(remark) && remark.startsWith(prefix)) {
+                        String[] split = remark.split(":");
+                        if (split.length >= 3) {
+                            Long salesLedgerId = Long.valueOf(split[1]);
+                            java.util.Map<Long, BigDecimal> inboundQtyByLineId = Arrays.stream(split[2].split(","))
+                                    .filter(org.springframework.util.StringUtils::hasText)
+                                    .map(s -> s.split("@"))
+                                    .filter(arr -> arr.length == 2)
+                                    .collect(java.util.stream.Collectors.toMap(
+                                            arr -> Long.valueOf(arr[0]),
+                                            arr -> new BigDecimal(arr[1]),
+                                            BigDecimal::add,
+                                            java.util.LinkedHashMap::new));
+                            if (status.equals(2)) {
+                                if (qualified) {
+                                    salesLedgerService.executeSalesScanInboundApproved(salesLedgerId, inboundQtyByLineId);
+                                } else {
+                                    salesLedgerService.executeSalesScanInboundUnqualifiedApproved(salesLedgerId, inboundQtyByLineId);
+                                }
+                            }
+                        }
+                    }
+                    return;
+                }
+                String[] split = reason.split(":");
+                Long salesLedgerId = null;
+                List<Long> productIds = null;
+                //  鍏ュ簱瀹℃壒鐞嗙敱鍙睍绀哄悎鍚屽彿    鍙傛暟鏀惧湪 approveRemark
+                if (reason.startsWith("鍏ュ簱瀹℃壒:")) {
+                    String remark = approveProcess.getApproveRemark();
+                    if (org.springframework.util.StringUtils.hasText(remark) && remark.startsWith("salesStock:")) {
+                        String[] r = remark.split(":");
+                        if (r.length >= 3) {
+                            salesLedgerId = Long.valueOf(r[1]);
+                            productIds = Arrays.stream(r[2].split(","))
+                                    .filter(org.springframework.util.StringUtils::hasText)
+                                    .map(Long::valueOf)
+                                    .collect(java.util.stream.Collectors.toList());
+                        }
+                    }
+                }
+                //  鍏ュ簱瀹℃壒:鍚堝悓鍙�:salesLedgerId:productId1,productId2
+                if (salesLedgerId == null && split.length >= 4) {
+                    salesLedgerId = Long.valueOf(split[2]);
+                    productIds = Arrays.stream(split[3].split(","))
+                            .filter(org.springframework.util.StringUtils::hasText)
+                            .map(Long::valueOf)
+                            .collect(java.util.stream.Collectors.toList());
+                }
+
+                if (salesLedgerId != null && productIds != null) {
+
+                    if (status.equals(2)) {
+                        // 瀹℃壒閫氳繃鎵ц鍏ュ簱
+                        salesLedgerService.executeSalesStockApproved(salesLedgerId, productIds);
+                    }
+                }
+            }
+        }
+
         // 缁戝畾闄勪欢
         if(!CollectionUtils.isEmpty(approveNode.getTempFileIds()) && approveNode.getApproveNodeStatus() == 1){
             tempFileService.migrateTempFilesToFormal(approveNode.getId(), approveNode.getTempFileIds(), FileNameType.ApproveNode.getValue());
@@ -371,6 +477,8 @@
                 return "鍙戣揣瀹℃壒";
             case 8:
                 return "鍗遍櫓浣滀笟瀹℃壒";
+            case 9:
+                return "鍏ュ簱瀹℃壒";
         }
         return null;
     }
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
index e42726f..22a6ca8 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -112,6 +112,7 @@
         approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
         approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? null : dateFormat.parse(approveProcessVO.getApproveTime()));
         approveProcess.setApproveReason(approveProcessVO.getApproveReason());
+        approveProcess.setApproveRemark(approveProcessVO.getApproveRemark());
         approveProcess.setDeviceRepairId(approveProcessVO.getDeviceRepairId());
         approveProcess.setMaintenancePrice(approveProcessVO.getMaintenancePrice());
         approveProcess.setPrice(approveProcessVO.getPrice());
@@ -455,6 +456,8 @@
                 return "鍙戣揣瀹℃壒";
             case 8:
                 return "鍗遍櫓浣滀笟瀹℃壒";
+            case 9:
+                return "鍏ュ簱瀹℃壒";
         }
         return null;
     }
diff --git a/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java b/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
index bf8edae..f2cba21 100644
--- a/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
+++ b/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
@@ -47,6 +47,11 @@
      */
     private String approveReason;
 
+    /**
+     * 瀹℃壒澶囨敞
+     */
+    private String approveRemark;
+
     @Excel(name = "寮�濮嬫椂闂�", dateFormat = "yyyy-MM-dd",width = 30)
     @JsonFormat(pattern = "yyyy-MM-dd")
     @ApiModelProperty(value = "寮�濮嬫椂闂�")
diff --git a/src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java b/src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java
index e79119d..56b09ba 100644
--- a/src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java
+++ b/src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java
@@ -22,7 +22,8 @@
     REIMBURSEMENT(4, "鎶ラ攢绠$悊"),
     PURCHASE(5, "閲囪喘瀹℃壒"),
     QUOTATION(6, "鎶ヤ环瀹℃壒"),
-    DELIVERY(7, "鍙戣揣瀹℃壒");
+    DELIVERY(7, "鍙戣揣瀹℃壒"),
+    STOCK_IN(9, "鍏ュ簱瀹℃壒");
 
     private final Integer code;
     private final String name;
diff --git a/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java b/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
index 522a324..5ad0fc7 100644
--- a/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
+++ b/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
@@ -23,6 +23,9 @@
     @ApiModelProperty("瑙勬牸鍨嬪彿")
     private String deviceModel;
 
+    @ApiModelProperty("璁惧淇濆吇浣嶇疆")
+    private String maintenanceLocation;
+
     @ApiModelProperty("璁″垝淇濆吇鏃ユ湡")
     private String maintenancePlanTimeReq;
 
diff --git a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
index a9368b0..91f8df3 100644
--- a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
+++ b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
@@ -84,4 +84,7 @@
     @ApiModelProperty("绉熸埛id")
     @TableField(fill = FieldFill.INSERT)
     private Long tenantId;
+
+    @ApiModelProperty("璁惧淇濆吇浣嶇疆")
+    private String maintenanceLocation;
 }
diff --git a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
index 512ce58..a6f4432 100644
--- a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
+++ b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -106,7 +106,4 @@
     @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
     private Long tenantId;
 
-    @ApiModelProperty("璁惧淇濆吇浣嶇疆")
-    private String maintenanceLocation;
-
 }
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
index c17d590..7bbab8e 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -47,9 +47,6 @@
             if (StringUtils.isNotEmpty(maintenanceTask.getTaskName())) {
                 queryWrapper.like(MaintenanceTask::getTaskName, maintenanceTask.getTaskName());
             }
-            if (StringUtils.isNotEmpty(maintenanceTask.getMaintenanceLocation())) {
-                queryWrapper.like(MaintenanceTask::getMaintenanceLocation, maintenanceTask.getMaintenanceLocation());
-            }
             if (StringUtils.isNotEmpty(maintenanceTask.getStatus())) {
                 queryWrapper.eq(MaintenanceTask::getStatus, maintenanceTask.getStatus());
             }
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 935cb78..337e972 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -219,6 +219,12 @@
         if (purchaseLedger.getId() == null) {
             purchaseLedgerMapper.insert(purchaseLedger);
         } else {
+            PurchaseLedger dbLedger = purchaseLedgerMapper.selectById(purchaseLedger.getId());
+            if (dbLedger != null
+                    && Objects.equals(dbLedger.getApprovalStatus(), 3)
+                    && Objects.equals(dbLedger.getStockStatus(), 2)) {
+                throw new ServiceException("璇ラ噰璐鍗曞凡瀹℃壒閫氳繃涓斿凡鍏ㄩ儴鍏ュ簱锛屼笉鑳藉啀娆″彂璧峰叆搴撳鎵癸紱濡傞渶閲嶆彁璇峰厛璧板鎵逛笉閫氳繃娴佺▼");
+            }
             // 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
             ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                     .eq(ApproveProcess::getApproveType, 5)
@@ -856,6 +862,11 @@
     }
 
     public void addApproveByPurchase(LoginUser loginUser, PurchaseLedger purchaseLedger) throws Exception {
+        if (purchaseLedger != null
+                && Objects.equals(purchaseLedger.getApprovalStatus(), 3)
+                && Objects.equals(purchaseLedger.getStockStatus(), 2)) {
+            throw new ServiceException("璇ラ噰璐鍗曞叆搴撴暟閲忓凡婊¤冻锛屼笉鑳介噸澶嶅彂璧峰鎵�");
+        }
         ApproveProcessVO approveProcessVO = new ApproveProcessVO();
         approveProcessVO.setApproveType(5);
         approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
diff --git a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
index 96454e1..1b903e7 100644
--- a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
+++ b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -151,6 +151,12 @@
     @ApiModelProperty("鍏宠仈妫�娴嬫爣鍑嗕富琛╥d")
     private Long testStandardId;
 
+    @ApiModelProperty("鍏ュ簱瀹℃壒鐘舵�侊細1-寰呭鏍革紝2-瀹℃壒涓紝3-瀹℃壒閫氳繃锛�4-瀹℃壒澶辫触")
+    private Integer approvalStatus;
+
+    @ApiModelProperty("鍏ュ簱瀹℃壒浜篿d")
+    private String approveUserIds;
+
 
     @TableField(exist = false)
     private String workOrderNo;
diff --git a/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java b/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
index 92bc88f..dbeb3b7 100644
--- a/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
+++ b/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
@@ -15,7 +15,7 @@
 
     int updateQualityInspect(QualityInspectDto qualityInspectDto);
 
-    IPage<QualityInspect> qualityInspectListPage(Page page, QualityInspect qualityInspect);
+    IPage<QualityInspect> qualityInspectListPage(Page<?> page, QualityInspect qualityInspect);
 
     void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect);
 
@@ -24,4 +24,8 @@
     int submit(QualityInspect qualityInspect);
 
     void down(HttpServletResponse response, QualityInspect qualityInspect);
+
+    void executeQualifiedInboundApproval(Integer inspectId);
+
+    void markQualifiedInboundApprovalStatus(Integer inspectId, Integer approvalStatus);
 }
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index 28a76e0..d030eac 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -11,7 +11,12 @@
 import com.deepoove.poi.config.Configure;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
+import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.approve.service.IApproveProcessService;
+import com.ruoyi.approve.vo.ApproveProcessVO;
+import com.ruoyi.common.enums.ApproveTypeEnum;
 import com.ruoyi.procurementrecord.service.ProcurementRecordService;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.quality.dto.QualityInspectDto;
@@ -27,6 +32,7 @@
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.framework.security.LoginUser;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
@@ -61,6 +67,7 @@
     private PurchaseLedgerMapper purchaseLedgerMapper;
 
     private ProcurementRecordService procurementRecordService;
+    private IApproveProcessService approveProcessService;
 
     @Override
     public int add(QualityInspectDto qualityInspectDto) {
@@ -104,15 +111,111 @@
             qualityUnqualified.setInspectId(qualityInspect.getId());
             qualityUnqualifiedMapper.insert(qualityUnqualified);
         } else {
-            //鍚堟牸鐩存帴鍏ュ簱
-            stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId());
-            // 閲囪喘鍘熸潗鏂欐楠岋細鍚堟牸鍏ュ簱鍚庡悓姝ュ埌閲囪喘浜у搧鈥滃凡鍏ュ簱鏁伴噺鈥濓紝涓庢壂鐮佸叆搴撳叡鐢ㄤ竴浠芥暟鎹彛寰�
-            syncQualifiedInboundToPurchaseProducts(qualityInspect);
+            // 鍘熸潗鏂欐楠屽悎鏍煎悗锛屽厛鍙戣捣鈥滃叆搴撳鎵光�濓紝瀹℃壒閫氳繃鍚庡啀鍏ュ簱
+            if (Objects.equals(qualityInspect.getInspectType(), 0)) {
+                submitQualifiedInboundApprove(qualityInspect);
+            } else {
+                //  鐩存帴鍏ュ簱
+                stockUtils.addStock(
+                        qualityInspect.getPurchaseLedgerId() == null ? null : qualityInspect.getPurchaseLedgerId().longValue(),
+                        null,
+                        qualityInspect.getProductModelId(),
+                        qualityInspect.getQuantity(),
+                        StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(),
+                        qualityInspect.getId()
+                );
+                syncQualifiedInboundToPurchaseProducts(qualityInspect);
+            }
         }
         qualityInspect.setInspectState(1);//宸叉彁浜�
         int updated = qualityInspectMapper.updateById(qualityInspect);
         refreshPurchaseLedgerStockStatusByInspect(qualityInspect.getPurchaseLedgerId());
         return updated;
+    }
+
+    private void submitQualifiedInboundApprove(QualityInspect qualityInspect) {
+        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(qualityInspect.getPurchaseLedgerId());
+        if (purchaseLedger == null) {
+            throw new RuntimeException("鎻愪氦澶辫触锛岄噰璐彴璐︿笉瀛樺湪");
+        }
+        String approveUserIds = ObjectUtils.isNotEmpty(qualityInspect.getApproveUserIds())
+                ? qualityInspect.getApproveUserIds()
+                : purchaseLedger.getApproveUserIds();
+        if (ObjectUtils.isEmpty(approveUserIds)) {
+            throw new RuntimeException("鎻愪氦澶辫触锛岃鍏堢淮鎶よ川妫�鍗曞鎵逛汉锛堟垨閲囪喘鍙拌处瀹℃壒浜猴級");
+        }
+
+        String approveReason = "鍘熸潗鏂欒川妫�鍏ュ簱瀹℃壒:" + purchaseLedger.getPurchaseContractNumber();
+        String approveRemark = "qualityQualifiedInbound:" + qualityInspect.getId() + ":" + purchaseLedger.getId();
+        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
+                .eq(ApproveProcess::getApproveRemark, approveRemark)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .orderByDesc(ApproveProcess::getCreateTime)
+                .last("limit 1"));
+        if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) {
+            throw new RuntimeException("鎻愪氦澶辫触锛岃璐ㄦ鍗曞凡鍙戣捣鍏ュ簱瀹℃壒锛屽鎵瑰畬鎴愬墠涓嶈兘閲嶅鎻愪氦");
+        }
+
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
+        approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode());
+        approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
+        approveProcessVO.setApproveReason(approveReason);
+        approveProcessVO.setApproveRemark(approveRemark);
+        approveProcessVO.setApproveUserIds(approveUserIds);
+        approveProcessVO.setApproveUser(loginUser.getUserId());
+        approveProcessVO.setApproveTime(java.time.LocalDate.now().toString());
+        try {
+            approveProcessService.addApprove(approveProcessVO);
+        } catch (Exception e) {
+            throw new RuntimeException("鎻愪氦澶辫触锛屽叆搴撳鎵瑰彂璧峰紓甯�:" + e.getMessage());
+        }
+        qualityInspect.setApprovalStatus(2);
+        qualityInspect.setApproveUserIds(approveUserIds);
+        qualityInspectMapper.updateById(qualityInspect);
+    }
+
+    @Override
+    public void executeQualifiedInboundApproval(Integer inspectId) {
+        if (inspectId == null) {
+            throw new RuntimeException("瀹℃壒澶辫触锛岃川妫�鍗旾D涓嶈兘涓虹┖");
+        }
+        QualityInspect qualityInspect = qualityInspectMapper.selectById(inspectId);
+        if (qualityInspect == null) {
+            throw new RuntimeException("瀹℃壒澶辫触锛岃川妫�鍗曚笉瀛樺湪");
+        }
+        if (!Objects.equals(qualityInspect.getInspectType(), 0)) {
+            throw new RuntimeException("瀹℃壒澶辫触锛屼粎鍘熸潗鏂欐楠屾敮鎸佸叆搴撳鎵�");
+        }
+        if (!Objects.equals(qualityInspect.getInspectState(), 1) || !"鍚堟牸".equals(qualityInspect.getCheckResult())) {
+            throw new RuntimeException("瀹℃壒澶辫触锛屽綋鍓嶈川妫�鍗曠姸鎬佷笉鍏佽鍏ュ簱");
+        }
+        stockUtils.addStock(
+                qualityInspect.getPurchaseLedgerId() == null ? null : qualityInspect.getPurchaseLedgerId().longValue(),
+                null,
+                qualityInspect.getProductModelId(),
+                qualityInspect.getQuantity(),
+                StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(),
+                qualityInspect.getId()
+        );
+        syncQualifiedInboundToPurchaseProducts(qualityInspect);
+        refreshPurchaseLedgerStockStatusByInspect(qualityInspect.getPurchaseLedgerId());
+        qualityInspect.setApprovalStatus(3);
+        qualityInspectMapper.updateById(qualityInspect);
+    }
+
+    @Override
+    public void markQualifiedInboundApprovalStatus(Integer inspectId, Integer approvalStatus) {
+        if (inspectId == null || approvalStatus == null) {
+            return;
+        }
+        QualityInspect qualityInspect = qualityInspectMapper.selectById(inspectId);
+        if (qualityInspect == null) {
+            return;
+        }
+        qualityInspect.setApprovalStatus(approvalStatus);
+        qualityInspectMapper.updateById(qualityInspect);
     }
 
     /*鐢熸垚妫�楠屾姤鍛�*/
@@ -182,7 +285,7 @@
     }
 
     @Override
-    public IPage<QualityInspect> qualityInspectListPage(Page page, QualityInspect qualityInspect) {
+    public IPage<QualityInspect> qualityInspectListPage(Page<?> page, QualityInspect qualityInspect) {
         return qualityInspectMapper.qualityInspectListPage(page, qualityInspect);
     }
 
diff --git a/src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java b/src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java
index 70c1d06..45c12fe 100644
--- a/src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java
@@ -25,4 +25,7 @@
     @ApiModelProperty("閿�鍞鍗曚骇鍝両d")
     private List<Long> salesLedgerProducts;
 
+    @ApiModelProperty("瀹℃壒浜篒D锛岄�楀彿鍒嗛殧")
+    private String approveUserIds;
+
 }
diff --git a/src/main/java/com/ruoyi/sales/dto/SalesScanInboundDto.java b/src/main/java/com/ruoyi/sales/dto/SalesScanInboundDto.java
index dd33b4c..013ccce 100644
--- a/src/main/java/com/ruoyi/sales/dto/SalesScanInboundDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/SalesScanInboundDto.java
@@ -20,4 +20,7 @@
     @ApiModelProperty("閿�鍞骇鍝佽鏁版嵁")
     private List<SalesLedgerProduct> salesLedgerProductList;
 
+    @ApiModelProperty("瀹℃壒浜篒D锛岄�楀彿鍒嗛殧")
+    private String approveUserIds;
+
 }
diff --git a/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java b/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
index dc93395..f0d557a 100644
--- a/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
+++ b/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -15,6 +15,7 @@
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 閿�鍞彴璐ervice鎺ュ彛
@@ -68,6 +69,12 @@
 
     void salesStock(SalesProductStockDto dto);
 
+    void executeSalesStockApproved(Long salesLedgerId, List<Long> salesLedgerProductIds);
+
+    void executeSalesScanInboundApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId);
+
+    void executeSalesScanInboundUnqualifiedApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId);
+
     List<Customer> shippedCustomers();
 
     void scanInbound(SalesScanInboundDto dto);
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index 9b21618..6af57a2 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -9,6 +9,10 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.account.service.AccountIncomeService;
+import com.ruoyi.approve.service.IApproveProcessService;
+import com.ruoyi.approve.vo.ApproveProcessVO;
+import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.common.enums.ApproveTypeEnum;
 import com.ruoyi.basic.mapper.CustomerMapper;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
@@ -103,6 +107,9 @@
     private static final String LOCK_PREFIX = "contract_no_lock:";
     private static final long LOCK_WAIT_TIMEOUT = 10; // 閿佺瓑寰呰秴鏃舵椂闂达紙绉掞級
     private static final long LOCK_EXPIRE_TIME = 30;  // 閿佽嚜鍔ㄨ繃鏈熸椂闂达紙绉掞級
+    private static final int INBOUND_BIZ_TYPE_WEB = 1;
+    private static final int INBOUND_BIZ_TYPE_SCAN_QUALIFIED = 2;
+    private static final int INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED = 3;
     private final AccountIncomeService accountIncomeService;
     private final SalesLedgerMapper salesLedgerMapper;
     private final CustomerMapper customerMapper;
@@ -144,6 +151,8 @@
     private final StockInRecordService stockInRecordService;
     private final StockOutRecordService stockOutRecordService;
     private final StockUtils stockUtils;
+    @Autowired
+    private IApproveProcessService approveProcessService;
 
     @Autowired
     private SysDeptMapper sysDeptMapper;
@@ -1857,6 +1866,9 @@
         if (ledger.getStockStatus() == null) {
             throw new ServiceException("鍏ュ簱澶辫触,閿�鍞鍗曞叆搴撶姸鎬佸紓甯�");
         }
+        if (ledger.getStockStatus() == 3) {
+            throw new ServiceException("鍏ュ簱澶辫触,璇ラ攢鍞鍗曟鍦ㄥ叆搴撳鎵逛腑,璇峰嬁閲嶅鎻愪氦");
+        }
         if (ledger.getStockStatus() == 2) {
             throw new ServiceException("鍏ュ簱澶辫触,璇ラ攢鍞鍗曞凡鍏ュ簱,璇峰嬁閲嶅鍏ュ簱");
         }
@@ -1869,6 +1881,42 @@
         if (salesLedgerProducts == null || salesLedgerProducts.isEmpty()) {
             throw new ServiceException("鍏ュ簱澶辫触,鏈煡璇㈠埌璇ラ攢鍞鍗曠殑閿�鍞骇鍝�");
         }
+        String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), ledger.getId(), INBOUND_BIZ_TYPE_WEB);
+        if (StringUtils.isEmpty(approveUserIds)) {
+            throw new ServiceException("鍏ュ簱澶辫触,璇烽�夋嫨瀹℃壒浜�");
+        }
+
+        String productIds = products.stream().map(String::valueOf).collect(Collectors.joining(","));
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
+        approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode());
+        approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
+        approveProcessVO.setApproveReason("鍏ュ簱瀹℃壒:" + ledger.getSalesContractNo());
+        approveProcessVO.setApproveRemark("salesStock:" + ledger.getId() + ":" + productIds);
+        approveProcessVO.setApproveUserIds(approveUserIds);
+        approveProcessVO.setApproveUser(loginUser.getUserId());
+        approveProcessVO.setApproveTime(LocalDate.now().toString());
+        try {
+            approveProcessService.addApprove(approveProcessVO);
+        } catch (Exception e) {
+            throw new ServiceException("鍏ュ簱瀹℃壒鍙戣捣澶辫触:" + e.getMessage());
+        }
+        // 瀹℃壒涓�
+        ledger.setStockStatus(3);
+        baseMapper.updateById(ledger);
+    }
+
+    @Override
+    public void executeSalesStockApproved(Long salesLedgerId, List<Long> products) {
+        SalesProductStockDto dto = new SalesProductStockDto();
+        dto.setSalesLedgerId(salesLedgerId);
+        dto.setSalesLedgerProducts(products);
+
+        SalesLedger ledger = baseMapper.selectById(dto.getSalesLedgerId());
+        if (ledger == null) {
+            throw new ServiceException("鍏ュ簱澶辫触,閿�鍞鍗曚笉瀛樺湪");
+        }
+        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, products));
         for (SalesLedgerProduct product : salesLedgerProducts) {
             if (!Objects.equals(product.getSalesLedgerId(), ledger.getId())) {
                 throw new ServiceException("鍏ュ簱澶辫触,瀛樺湪涓嶅睘浜庡綋鍓嶉攢鍞鍗曠殑浜у搧");
@@ -1978,11 +2026,71 @@
             }
             inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add);
         }
+        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery()
+                .in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
+        if (CollectionUtils.isEmpty(selectedProducts)) {
+            throw new ServiceException("鍏ュ簱澶辫触,鏈煡璇㈠埌鍏ュ簱浜у搧");
+        }
+        if (selectedProducts.size() != inboundQtyByLineId.size()) {
+            throw new ServiceException("鍏ュ簱澶辫触,閮ㄥ垎浜у搧涓嶅瓨鍦�");
+        }
+        for (SalesLedgerProduct selectedProduct : selectedProducts) {
+            if (!Objects.equals(selectedProduct.getSalesLedgerId(), salesLedger.getId())) {
+                throw new ServiceException("鍏ュ簱澶辫触,閿�鍞骇鍝佷笌璁㈠崟涓嶅尮閰�");
+            }
+            if (!Objects.equals(selectedProduct.getType(), SaleEnum.SALE.getCode())) {
+                throw new ServiceException("鍏ュ簱澶辫触,浠呮敮鎸侀攢鍞鍗曚骇鍝佽");
+            }
+            if (selectedProduct.getProductModelId() == null) {
+                throw new ServiceException("鍏ュ簱澶辫触,浜у搧瑙勬牸鏈淮鎶�,鏃犳硶鍏ュ簱");
+            }
+        }
+        String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_QUALIFIED);
+        if (StringUtils.isEmpty(approveUserIds)) {
+            throw new ServiceException("鍏ュ簱澶辫触,璇烽�夋嫨瀹℃壒浜�");
+        }
+        String lines = inboundQtyByLineId.entrySet().stream()
+                .map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString())
+                .collect(Collectors.joining(","));
+        String reason = "閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:" + salesLedger.getSalesContractNo();
+        String remark = "scanQualified:" + salesLedger.getId() + ":" + lines;
+        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
+                .eq(ApproveProcess::getApproveRemark, remark)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .orderByDesc(ApproveProcess::getCreateTime)
+                .last("limit 1"));
+        if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) {
+            throw new ServiceException("鍏ュ簱澶辫触,璇ョ敵璇峰凡鎻愪氦瀹℃壒");
+        }
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
+        approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode());
+        approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
+        approveProcessVO.setApproveReason(reason);
+        approveProcessVO.setApproveRemark(remark);
+        approveProcessVO.setApproveUserIds(approveUserIds);
+        approveProcessVO.setApproveUser(loginUser.getUserId());
+        approveProcessVO.setApproveTime(LocalDate.now().toString());
+        try {
+            approveProcessService.addApprove(approveProcessVO);
+        } catch (Exception e) {
+            throw new ServiceException("鍏ュ簱瀹℃壒鍙戣捣澶辫触:" + e.getMessage());
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void executeSalesScanInboundApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId) {
+        SalesLedger salesLedger = baseMapper.selectById(salesLedgerId);
+        if (salesLedger == null) {
+            throw new ServiceException("鍏ュ簱澶辫触,閿�鍞鍗曚笉瀛樺湪");
+        }
         Long ledgerId = salesLedger.getId();
         for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) {
             Long salesLedgerProductId = entry.getKey();
             BigDecimal inboundThisLine = entry.getValue();
-            if (inboundThisLine.compareTo(BigDecimal.ZERO) == 0) {
+            if (inboundThisLine == null || inboundThisLine.compareTo(BigDecimal.ZERO) <= 0) {
                 continue;
             }
             SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId);
@@ -2065,11 +2173,71 @@
             }
             inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add);
         }
+        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery()
+                .in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
+        if (CollectionUtils.isEmpty(selectedProducts)) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,鏈煡璇㈠埌鍏ュ簱浜у搧");
+        }
+        if (selectedProducts.size() != inboundQtyByLineId.size()) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,閮ㄥ垎浜у搧涓嶅瓨鍦�");
+        }
+        for (SalesLedgerProduct selectedProduct : selectedProducts) {
+            if (!Objects.equals(selectedProduct.getSalesLedgerId(), salesLedger.getId())) {
+                throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,閿�鍞骇鍝佷笌璁㈠崟涓嶅尮閰�");
+            }
+            if (!Objects.equals(selectedProduct.getType(), SaleEnum.SALE.getCode())) {
+                throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,浠呮敮鎸侀攢鍞鍗曚骇鍝佽");
+            }
+            if (selectedProduct.getProductModelId() == null) {
+                throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,浜у搧瑙勬牸鏈淮鎶�,鏃犳硶鍏ュ簱");
+            }
+        }
+        String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED);
+        if (StringUtils.isEmpty(approveUserIds)) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,璇烽�夋嫨瀹℃壒浜�");
+        }
+        String lines = inboundQtyByLineId.entrySet().stream()
+                .map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString())
+                .collect(Collectors.joining(","));
+        String reason = "閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:" + salesLedger.getSalesContractNo();
+        String remark = "scanUnqualified:" + salesLedger.getId() + ":" + lines;
+        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
+                .eq(ApproveProcess::getApproveRemark, remark)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .orderByDesc(ApproveProcess::getCreateTime)
+                .last("limit 1"));
+        if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,璇ョ敵璇峰凡鎻愪氦瀹℃壒");
+        }
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
+        approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode());
+        approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
+        approveProcessVO.setApproveReason(reason);
+        approveProcessVO.setApproveRemark(remark);
+        approveProcessVO.setApproveUserIds(approveUserIds);
+        approveProcessVO.setApproveUser(loginUser.getUserId());
+        approveProcessVO.setApproveTime(LocalDate.now().toString());
+        try {
+            approveProcessService.addApprove(approveProcessVO);
+        } catch (Exception e) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳鎵瑰彂璧峰け璐�:" + e.getMessage());
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void executeSalesScanInboundUnqualifiedApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId) {
+        SalesLedger salesLedger = baseMapper.selectById(salesLedgerId);
+        if (salesLedger == null) {
+            throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,閿�鍞鍗曚笉瀛樺湪");
+        }
         Long ledgerId = salesLedger.getId();
         for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) {
             Long salesLedgerProductId = entry.getKey();
             BigDecimal inboundThisLine = entry.getValue();
-            if (inboundThisLine.compareTo(BigDecimal.ZERO) == 0) {
+            if (inboundThisLine == null || inboundThisLine.compareTo(BigDecimal.ZERO) <= 0) {
                 continue;
             }
             SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId);
@@ -2087,7 +2255,6 @@
             }
             stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine,
                     StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId());
-
             BigDecimal oldUnStocked = dbProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedStockedQuantity();
             dbProduct.setUnqualifiedStockedQuantity(oldUnStocked.add(inboundThisLine));
             dbProduct.fillRemainingQuantity();
@@ -2095,6 +2262,31 @@
         }
     }
 
+    private String resolveApproveUserIds(String approveUserIds, Long salesLedgerId, Integer bizType) {
+        if (StringUtils.isNotEmpty(approveUserIds)) {
+            return approveUserIds;
+        }
+        LambdaQueryWrapper<ApproveProcess> wrapper = new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .orderByDesc(ApproveProcess::getCreateTime)
+                .last("limit 1");
+        if (Objects.equals(bizType, INBOUND_BIZ_TYPE_WEB)) {
+            wrapper.likeRight(ApproveProcess::getApproveReason, "鍏ュ簱瀹℃壒:")
+                    .likeRight(ApproveProcess::getApproveRemark, "salesStock:" + salesLedgerId + ":");
+        } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_QUALIFIED)) {
+            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:")
+                    .likeRight(ApproveProcess::getApproveRemark, "scanQualified:" + salesLedgerId + ":");
+        } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED)) {
+            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:")
+                    .likeRight(ApproveProcess::getApproveRemark, "scanUnqualified:" + salesLedgerId + ":");
+        } else {
+            return null;
+        }
+        ApproveProcess latest = approveProcessService.getOne(wrapper);
+        return latest == null ? null : latest.getApproveUserIds();
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void scanOutbound(SalesScanInboundDto dto) {
diff --git a/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml b/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
index 2ed16a4..0943443 100644
--- a/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
+++ b/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
@@ -18,6 +18,7 @@
         dm.update_user,
         dm.tenant_id,
         dm.maintenance_actually_name,
+        dm.maintenance_location,
         dl.device_name,
         dl.device_model,
         su.nick_name as create_user_name
@@ -37,6 +38,9 @@
             </if>
             <if test="deviceMaintenanceDto.maintenanceActuallyName != null">
                 and dm.maintenance_actually_name like concat('%',#{deviceMaintenanceDto.maintenanceActuallyName},'%')
+            </if>
+            <if test="deviceMaintenanceDto.maintenanceLocation != null and deviceMaintenanceDto.maintenanceLocation != ''">
+                and dm.maintenance_location like concat('%',#{deviceMaintenanceDto.maintenanceLocation},'%')
             </if>
             <if test="deviceMaintenanceDto.maintenancePlanTime != null">
                 and dm.maintenance_plan_time like concat('%',#{deviceMaintenanceDto.maintenancePlanTime},'%')
@@ -63,6 +67,7 @@
                dm.update_user,
                dm.tenant_id,
                dm.maintenance_actually_name,
+               dm.maintenance_location,
                dl.device_name,
                dl.device_model,
                su.user_name as create_user_name
diff --git a/src/main/resources/mapper/quality/QualityInspectMapper.xml b/src/main/resources/mapper/quality/QualityInspectMapper.xml
index 99d6df1..d4fcf5c 100644
--- a/src/main/resources/mapper/quality/QualityInspectMapper.xml
+++ b/src/main/resources/mapper/quality/QualityInspectMapper.xml
@@ -47,6 +47,12 @@
         <if test="qualityInspect.entryDateEnd != null and qualityInspect.entryDateEnd != '' ">
             AND qi.check_time &lt;= DATE_FORMAT(#{qualityInspect.entryDateEnd},'%Y-%m-%d')
         </if>
+        <if test="qualityInspect.approvalStatus != null">
+            AND qi.approval_status = #{qualityInspect.approvalStatus}
+        </if>
+        <if test="qualityInspect.approveUserIds != null and qualityInspect.approveUserIds != '' ">
+            AND qi.approve_user_ids like concat('%',#{qualityInspect.approveUserIds},'%')
+        </if>
         ORDER BY qi.id DESC
     </select>
 
@@ -68,6 +74,12 @@
         <if test="qualityInspect.productName != null and qualityInspect.productName != '' ">
             AND product_name = #{qualityInspect.productName}
         </if>
+        <if test="qualityInspect.approvalStatus != null">
+            AND approval_status = #{qualityInspect.approvalStatus}
+        </if>
+        <if test="qualityInspect.approveUserIds != null and qualityInspect.approveUserIds != '' ">
+            AND approve_user_ids like concat('%',#{qualityInspect.approveUserIds},'%')
+        </if>
     </select>
 
     <delete id="deleteByProductMainIds">
diff --git a/src/main/resources/mapper/stock/StockInRecordMapper.xml b/src/main/resources/mapper/stock/StockInRecordMapper.xml
index 4436bf3..f9c2b44 100644
--- a/src/main/resources/mapper/stock/StockInRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -11,18 +11,22 @@
         pm.thickness,
         u.nick_name as createBy,
         CASE
-            WHEN sir.record_type IN ('7', '18', '19', '20') THEN pl.purchase_contract_number
+            WHEN sir.record_type IN ('6', '7', '18', '19', '20') THEN pl.purchase_contract_number
             ELSE sl.sales_contract_no
         END as salesContractNo
         FROM stock_in_record as sir
         LEFT JOIN product_model as pm on sir.product_model_id = pm.id
         LEFT JOIN product as p on pm.product_id = p.id
         LEFT JOIN sys_user as u on sir.create_user = u.user_id
+        LEFT JOIN quality_inspect as qi on qi.id = sir.record_id and sir.record_type = '6'
         LEFT JOIN sales_ledger_product as slp_link on slp_link.id = COALESCE(sir.sales_ledger_product_id, sir.record_id)
         LEFT JOIN sales_ledger as sl on sl.id = COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
-            and sir.record_type NOT IN ('7', '18', '19', '20')
-        LEFT JOIN purchase_ledger as pl on pl.id = COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
-            and sir.record_type IN ('7', '18', '19', '20')
+            and sir.record_type NOT IN ('6', '7', '18', '19', '20')
+        LEFT JOIN purchase_ledger as pl on pl.id = CASE
+            WHEN sir.record_type = '6' THEN qi.purchase_ledger_id
+            ELSE COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
+        END
+            and sir.record_type IN ('6', '7', '18', '19', '20')
         <where>
             <if test="params.timeStr != null and params.timeStr != ''">
                 and sir.create_time like concat('%',#{params.timeStr},'%')
@@ -32,9 +36,9 @@
             </if>
             <if test="params.salesContractNo != null and params.salesContractNo != ''">
                 and (
-                    (sir.record_type IN ('7', '18', '19', '20') and pl.purchase_contract_number like concat('%',#{params.salesContractNo},'%'))
+                    (sir.record_type IN ('6', '7', '18', '19', '20') and pl.purchase_contract_number like concat('%',#{params.salesContractNo},'%'))
                     or
-                    (sir.record_type NOT IN ('7', '18', '19', '20') and sl.sales_contract_no like concat('%',#{params.salesContractNo},'%'))
+                    (sir.record_type NOT IN ('6', '7', '18', '19', '20') and sl.sales_contract_no like concat('%',#{params.salesContractNo},'%'))
                 )
             </if>
             <if test="params.type != null and params.type != ''">
@@ -54,18 +58,22 @@
         pm.unit,
         u.nick_name as createBy,
         CASE
-            WHEN sir.record_type IN ('7', '18', '19', '20') THEN pl.purchase_contract_number
+            WHEN sir.record_type IN ('6', '7', '18', '19', '20') THEN pl.purchase_contract_number
             ELSE sl.sales_contract_no
         END as salesContractNo
         FROM stock_in_record as sir
         LEFT JOIN product_model as pm on sir.product_model_id = pm.id
         LEFT JOIN product as p on pm.product_id = p.id
         LEFT JOIN sys_user as u on sir.create_user = u.user_id
+        LEFT JOIN quality_inspect as qi on qi.id = sir.record_id and sir.record_type = '6'
         LEFT JOIN sales_ledger_product as slp_link on slp_link.id = COALESCE(sir.sales_ledger_product_id, sir.record_id)
         LEFT JOIN sales_ledger as sl on sl.id = COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
-            and sir.record_type NOT IN ('7', '18', '19', '20')
-        LEFT JOIN purchase_ledger as pl on pl.id = COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
-            and sir.record_type IN ('7', '18', '19', '20')
+            and sir.record_type NOT IN ('6', '7', '18', '19', '20')
+        LEFT JOIN purchase_ledger as pl on pl.id = CASE
+            WHEN sir.record_type = '6' THEN qi.purchase_ledger_id
+            ELSE COALESCE(sir.sales_ledger_id, slp_link.sales_ledger_id, sir.record_id)
+        END
+            and sir.record_type IN ('6', '7', '18', '19', '20')
         <where>
             <if test="params.timeStr != null and params.timeStr != ''">
                 and sir.create_time like concat('%',#{params.timeStr},'%')
@@ -75,9 +83,9 @@
             </if>
             <if test="params.salesContractNo != null and params.salesContractNo != ''">
                 and (
-                    (sir.record_type IN ('7', '18', '19', '20') and pl.purchase_contract_number like concat('%',#{params.salesContractNo},'%'))
+                    (sir.record_type IN ('6', '7', '18', '19', '20') and pl.purchase_contract_number like concat('%',#{params.salesContractNo},'%'))
                     or
-                    (sir.record_type NOT IN ('7', '18', '19', '20') and sl.sales_contract_no like concat('%',#{params.salesContractNo},'%'))
+                    (sir.record_type NOT IN ('6', '7', '18', '19', '20') and sl.sales_contract_no like concat('%',#{params.salesContractNo},'%'))
                 )
             </if>
             <if test="params.type != null and params.type != ''">

--
Gitblit v1.9.3