From 901e3c96c76f168ddbeaa10562a4d2d6f4d3ba8c Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 25 五月 2026 15:07:09 +0800
Subject: [PATCH] refactor(approve): 重构审批业务状态同步逻辑

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java |   21 ++++++++++
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                  |    5 +-
 doc/20260525_sales_销售产品总数字段.sql                                               |    6 +++
 src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java                    |    6 +++
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java        |   16 ++++++++
 doc/20260525_sales_总数字段前端联调文档.md                                              |   59 +++++++++++++++++++++++++++++
 6 files changed, 110 insertions(+), 3 deletions(-)

diff --git "a/doc/20260525_sales_\346\200\273\346\225\260\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260525_sales_\346\200\273\346\225\260\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..4a2670d
--- /dev/null
+++ "b/doc/20260525_sales_\346\200\273\346\225\260\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,59 @@
+# Sales 妯″潡銆屾�绘暟銆嶅墠绔仈璋冩枃妗�
+
+## 1. 鍙樻洿鐩爣
+
+- 閿�鍞彴璐︿骇鍝佹柊澧炲瓧娈� `totalQuantity`锛堟�绘暟锛夈��
+- 褰撲骇鍝� `isProduction = true` 鏃讹紝杩涘叆鐢熶骇涓昏鍒掞紙`production_plan`锛夌殑 `qtyRequired` 浣跨敤 `totalQuantity`銆�
+
+## 2. 鏁版嵁搴撳彉鏇�
+
+- 鏂板鍒楋細`sales_ledger_product.total_quantity`锛坄DECIMAL(18,4)`锛屽彲绌猴級銆�
+- SQL 鏂囦欢锛歚doc/20260525_sales_閿�鍞骇鍝佹�绘暟瀛楁.sql`銆�
+
+## 3. 瀛楁瀹氫箟
+
+- 瀛楁鍚嶏細`totalQuantity`
+- 鍚箟锛氫骇鍝佹�绘暟锛堢敤浜庡彂璐у緟鍙戣揣鏁伴噺灞曠ず涓庣敓浜т富璁″垝闇�姹傛暟閲忥級
+- 绫诲瀷锛歚number`锛堝悗绔� `BigDecimal`锛�
+- 鍚庣鍏滃簳瑙勫垯锛�
+  - 鑻ユ湭浼犳垨 `<= 0`锛屽悗绔寜 `quantity * singleQuantity` 鑷姩琛ラ綈锛�
+  - `singleQuantity` 涓虹┖鎴� `<= 0` 鏃舵寜 `1` 澶勭悊銆�
+
+## 4. 鎺ュ彛鑱旇皟璇存槑
+
+1. `POST /sales/ledger/addOrUpdateSalesLedger`
+   - 鍏ュ弬 `productData[]` 鏀寔 `totalQuantity`銆�
+2. `POST /sales/product/addOrUpdateSalesLedgerProduct`
+   - 鍏ュ弬鏀寔 `totalQuantity`銆�
+3. `GET /sales/product/list`
+   - 杩斿洖鏂板瀛楁 `totalQuantity`锛�
+   - `noQuantity`锛堝緟鍙戣揣鏁伴噺锛夋寜 `totalQuantity - shippedQuantity` 璁$畻锛堣嫢 `totalQuantity` 涓虹┖锛屽悗绔嚜鍔ㄥ洖閫�涓� `quantity * singleQuantity`锛夈��
+
+## 5. 鐢熶骇涓昏鍒掕仈鍔�
+
+- 瑙﹀彂鏉′欢锛氶攢鍞骇鍝� `isProduction = true`銆�
+- 涓昏鍒掕惤搴撹鍒欙細
+  - `production_plan.qty_required = totalQuantity`锛堜紭鍏堬級锛�
+  - 鑻� `totalQuantity` 鏃犳晥鍒欏洖閫� `quantity * singleQuantity`銆�
+
+## 6. 鍓嶇瀹炵幇寤鸿
+
+1. 鍦ㄩ攢鍞骇鍝佸脊绐楁柊澧炲睍绀哄瓧娈� `totalQuantity`锛堝缓璁彧璇伙級銆�
+2. 鍓嶇鍦� `quantity`銆乣singleQuantity` 鍙樺寲鏃跺疄鏃惰绠楋細`totalQuantity = quantity * singleQuantity`銆�
+3. 鎻愪氦鏃跺皢 `totalQuantity` 涓�骞朵紶缁欏悗绔紝閬垮厤鍓嶅悗绔睍绀哄樊寮傘��
+
+## 7. 鍏ュ弬绀轰緥
+
+```json
+{
+  "productData": [
+    {
+      "productModelId": 101,
+      "quantity": 10,
+      "singleQuantity": 12,
+      "totalQuantity": 120,
+      "isProduction": true
+    }
+  ]
+}
+```
diff --git "a/doc/20260525_sales_\351\224\200\345\224\256\344\272\247\345\223\201\346\200\273\346\225\260\345\255\227\346\256\265.sql" "b/doc/20260525_sales_\351\224\200\345\224\256\344\272\247\345\223\201\346\200\273\346\225\260\345\255\227\346\256\265.sql"
new file mode 100644
index 0000000..aee226e
--- /dev/null
+++ "b/doc/20260525_sales_\351\224\200\345\224\256\344\272\247\345\223\201\346\200\273\346\225\260\345\255\227\346\256\265.sql"
@@ -0,0 +1,6 @@
+ALTER TABLE sales_ledger_product
+    ADD COLUMN total_quantity DECIMAL(18, 4) NULL COMMENT '鎬绘暟' AFTER single_quantity;
+
+UPDATE sales_ledger_product
+SET total_quantity = IFNULL(quantity, 0) * IFNULL(NULLIF(single_quantity, 0), 1)
+WHERE total_quantity IS NULL;
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
index 63f5c50..4e922d1 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -66,9 +66,15 @@
      */
     @Excel(name = "鏁伴噺")
     private BigDecimal quantity;
+
     @TableField(value = "single_quantity")
     @Excel(name = "姣忎欢鏁伴噺")
     private BigDecimal singleQuantity;
+
+    @TableField(value = "total_quantity")
+    @Excel(name = "鎬绘暟")
+    private BigDecimal totalQuantity;
+
     @Excel(name = "鏈�浣庡簱瀛樻暟閲�")
     private BigDecimal minStock;
     /**
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
index 6a86537..6addf3c 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -168,6 +168,11 @@
         int result;
         Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
         salesLedgerProduct.setSingleQuantity(normalizeSingleQuantity(salesLedgerProduct.getSingleQuantity()));
+        salesLedgerProduct.setTotalQuantity(normalizeTotalQuantity(
+                salesLedgerProduct.getTotalQuantity(),
+                salesLedgerProduct.getQuantity(),
+                salesLedgerProduct.getSingleQuantity()
+        ));
         if (salesLedgerProduct.getId() == null) {
             salesLedgerProduct.setRegisterDate(LocalDateTime.now());
             result = salesLedgerProductMapper.insert(salesLedgerProduct);
@@ -225,7 +230,11 @@
         productionPlan.setSalesLedgerProductId(salesLedgerProduct.getId());
         productionPlan.setMpsNo(generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
         productionPlan.setProductModelId(salesLedgerProduct.getProductModelId());
-        productionPlan.setQtyRequired(salesLedgerProduct.getQuantity());
+        productionPlan.setQtyRequired(normalizeTotalQuantity(
+                salesLedgerProduct.getTotalQuantity(),
+                salesLedgerProduct.getQuantity(),
+                salesLedgerProduct.getSingleQuantity()
+        ));
         productionPlan.setSource("閿�鍞�");
         productionPlan.setStatus(0);
         productionPlan.setRequiredDate(salesLedger.getDeliveryDate());//闇�姹傛棩鏈�=浜よ揣鏃ユ湡
@@ -344,6 +353,16 @@
         return singleQuantity;
     }
 
+    private BigDecimal normalizeTotalQuantity(BigDecimal totalQuantity, BigDecimal quantity, BigDecimal singleQuantity) {
+        if (totalQuantity != null && totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
+            return totalQuantity;
+        }
+        if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        return quantity.multiply(normalizeSingleQuantity(singleQuantity));
+    }
+
     private String generateNextPlanNo(String datePrefix) {
         QueryWrapper<ProductionPlan> queryWrapper = new QueryWrapper<>();
         queryWrapper.likeRight("mps_no", "JH" + datePrefix);
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 4775de5..47a8a6c 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -389,6 +389,11 @@
                     SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct();
                     BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct);
                     salesLedgerProduct.setSingleQuantity(normalizeSingleQuantity(salesLedgerProduct.getSingleQuantity()));
+                    salesLedgerProduct.setTotalQuantity(normalizeTotalQuantity(
+                            salesLedgerProduct.getTotalQuantity(),
+                            salesLedgerProduct.getQuantity(),
+                            salesLedgerProduct.getSingleQuantity()
+                    ));
                     salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                     salesLedgerProduct.setType(1);
                     // 璁$畻涓嶅惈绋庢�讳环
@@ -594,6 +599,7 @@
                 .peek(p -> {
                     p.setSalesLedgerId(salesLedgerId);
                     p.setSingleQuantity(normalizeSingleQuantity(p.getSingleQuantity()));
+                    p.setTotalQuantity(normalizeTotalQuantity(p.getTotalQuantity(), p.getQuantity(), p.getSingleQuantity()));
                 })
                 .collect(Collectors.partitioningBy(p -> p.getId() != null));
 
@@ -631,6 +637,16 @@
         return singleQuantity;
     }
 
+    private BigDecimal normalizeTotalQuantity(BigDecimal totalQuantity, BigDecimal quantity, BigDecimal singleQuantity) {
+        if (totalQuantity != null && totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
+            return totalQuantity;
+        }
+        if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        return quantity.multiply(normalizeSingleQuantity(singleQuantity));
+    }
+
     @Transactional(readOnly = true)
     public String generateSalesContractNo() {
         LocalDate currentDate = LocalDate.now();
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index d824291..4d8aece 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -11,6 +11,7 @@
         T1.warn_num,
         T1.quantity,
         T1.single_quantity,
+        T1.total_quantity,
         T1.min_stock,
         T1.tax_rate,
         T1.tax_inclusive_unit_price,
@@ -34,10 +35,10 @@
         WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1
         ELSE 0
         END as has_sufficient_stock,
-        (IFNULL(T1.quantity, 0) * IFNULL(NULLIF(T1.single_quantity, 0), 1) - IFNULL(t3.shipped_quantity, 0)) as no_quantity,
+        (IFNULL(NULLIF(T1.total_quantity, 0), IFNULL(T1.quantity, 0) * IFNULL(NULLIF(T1.single_quantity, 0), 1)) - IFNULL(t3.shipped_quantity, 0)) as no_quantity,
         CASE
          WHEN IFNULL(t3.shipped_quantity, 0) = 0 THEN '寰呭彂璐�'
-         WHEN (IFNULL(T1.quantity, 0) * IFNULL(NULLIF(T1.single_quantity, 0), 1) - IFNULL(t3.shipped_quantity, 0)) > 0 THEN '閮ㄥ垎鍙戣揣'
+         WHEN (IFNULL(NULLIF(T1.total_quantity, 0), IFNULL(T1.quantity, 0) * IFNULL(NULLIF(T1.single_quantity, 0), 1)) - IFNULL(t3.shipped_quantity, 0)) > 0 THEN '閮ㄥ垎鍙戣揣'
         ELSE '宸插彂璐�'
         END as shippingStatus,
         CASE

--
Gitblit v1.9.3