From 32bf2bed7dc2a14afeb50b72723570eaf295e316 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 28 五月 2026 09:53:35 +0800
Subject: [PATCH] feat(purchase): 新增采购草稿简易新增功能并完善生产订单库存数量显示

---
 src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java               |    2 
 src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java                |    2 
 doc/20260527_ProductionOrderController_pick库存数量前端联调文档.md                            |   48 ++++++
 src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java                         |   10 +
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java        |  140 ++++++++++++++++++++
 doc/20260527_采购台账简易新增_采购申请通知前端联调文档.md                                               |  133 +++++++++++++++++++
 src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java           |   11 +
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java |   29 ++++
 src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java                           |    3 
 9 files changed, 374 insertions(+), 4 deletions(-)

diff --git "a/doc/20260527_ProductionOrderController_pick\345\272\223\345\255\230\346\225\260\351\207\217\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260527_ProductionOrderController_pick\345\272\223\345\255\230\346\225\260\351\207\217\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..478ce87
--- /dev/null
+++ "b/doc/20260527_ProductionOrderController_pick\345\272\223\345\255\230\346\225\260\351\207\217\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,48 @@
+# `ProductionOrderController.pick` 鎺ュ彛鍓嶇鑱旇皟鏂囨。
+
+## 鎺ュ彛淇℃伅
+
+- 鎺ュ彛鍦板潃锛歚GET /productionOrder/pick/{productionOrderId}`
+- 浣滅敤锛氭牴鎹敓浜ц鍗旾D鏌ヨ BOM 棰嗘枡鍗曟槑缁�
+- 鏈琛ュ厖瀛楁锛歚stockQuantity`
+
+## 瀛楁璇存槑
+
+`stockQuantity` 涓轰骇鍝佸簱瀛樻�婚噺锛屽彛寰勫涓嬶細
+
+- 鎸� `productModelId` 姹囨��
+- 鍙粺璁′骇鍝佸簱瀛樿〃 `stock_inventory`
+- 涓嶅尯鍒嗘壒鍙� `batchNo`
+- 鍙栧�间负褰撳墠浜у搧瑙勬牸涓嬫墍鏈夊簱瀛樻暟閲忎箣鍜�
+
+## 杩斿洖绀轰緥
+
+```json
+[
+  {
+    "id": 1001,
+    "productionOrderId": 20001,
+    "productModelId": 30001,
+    "productName": "鍘熸潗鏂橝",
+    "model": "A-01",
+    "unit": "kg",
+    "pickQuantity": 120,
+    "stockQuantity": 860,
+    "batchNoList": ["B20260501", "B20260508"]
+  }
+]
+```
+
+## 鍓嶇鑱旇皟娉ㄦ剰鐐�
+
+- 鍒楄〃灞曠ず鏃剁洿鎺ヤ娇鐢� `stockQuantity` 鍗冲彲锛屼笉闇�瑕佸墠绔啀鎸夋壒鍙风疮鍔犮��
+- 濡傛灉 `stockQuantity` 涓� `0`锛岃〃绀鸿浜у搧瑙勬牸褰撳墠娌℃湁鍙敤搴撳瓨銆�
+- `batchNoList` 浠嶇劧淇濈暀锛岀敤浜庢壒鍙峰睍绀烘垨鍚庣画鎵瑰彿閫夋嫨锛屼笉褰卞搷 `stockQuantity` 鐨勮绠椼��
+- 璇ュ瓧娈靛睘浜庢槑缁嗚繑鍥炲瓧娈碉紝鍓嶇鍙鎷垮埌 `pick` 鎺ュ彛杩斿洖灏辫兘灞曠ず锛屾棤闇�棰濆璇锋眰搴撳瓨鎺ュ彛銆�
+
+## 楠岃瘉鏂瑰紡
+
+- 鎵撳紑鐢熶骇璁㈠崟璇︽儏椤�
+- 璋冪敤 `GET /productionOrder/pick/{productionOrderId}`
+- 纭姣忎竴鏉� BOM 棰嗘枡鏄庣粏閮借繑鍥� `stockQuantity`
+- 鏍稿搴撳瓨鏁伴噺涓庡簱瀛樻ā鍧椾腑鍚屼竴 `productModelId` 鐨勫簱瀛樻�婚噺涓�鑷�
diff --git "a/doc/20260527_\351\207\207\350\264\255\345\217\260\350\264\246\347\256\200\346\230\223\346\226\260\345\242\236_\351\207\207\350\264\255\347\224\263\350\257\267\351\200\232\347\237\245\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260527_\351\207\207\350\264\255\345\217\260\350\264\246\347\256\200\346\230\223\346\226\260\345\242\236_\351\207\207\350\264\255\347\224\263\350\257\267\351\200\232\347\237\245\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..c0b82fa
--- /dev/null
+++ "b/doc/20260527_\351\207\207\350\264\255\345\217\260\350\264\246\347\256\200\346\230\223\346\226\260\345\242\236_\351\207\207\350\264\255\347\224\263\350\257\267\351\200\232\347\237\245\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,133 @@
+# 閲囪喘鍙拌处绠�鏄撴柊澧炰笌閲囪喘鐢宠閫氱煡鍓嶇鑱旇皟鏂囨。
+
+## 1. 鐩爣
+
+鏈鏂板鐨勬槸閲囪喘鍙拌处鐨勨�滅畝鏄撴柊澧炩�濊兘鍔涳紝涓撻棬鐢ㄤ簬鐢熶骇棰嗘枡搴撳瓨涓嶈冻鍦烘櫙銆�
+
+杩欎釜鍏ュ彛鐨勮涓烘槸锛�
+
+1. 鍏堜繚瀛樹竴鏉¢噰璐崏绋匡紝涓嶈繘鍏ラ噰璐鏍搞��
+2. 鑷姩缁欐妱閫佷汉鍙戦�佷竴鏉¢噰璐敵璇锋彁閱掓秷鎭��
+3. 鍘熺敵璇蜂汉浼氳鍐欏叆閲囪喘鍙拌处澶囨敞銆�
+4. 閲囪喘鍙拌处褰曞叆浜哄浐瀹氫负鎶勯�佷汉銆�
+5. 鎶勯�佷汉琛ュ叏閲囪喘璁㈠崟淇℃伅鍚庯紝鍐嶈蛋鍘熸湁姝e紡鏂板鎺ュ彛杩涘叆閲囪喘瀹℃牳銆�
+
+## 2. 鏂板鎺ュ彛
+
+### 2.1 淇濆瓨閲囪喘鑽夌
+
+- 璇锋眰鏂瑰紡锛歚POST`
+- 鎺ュ彛璺緞锛歚/purchase/ledger/saveShortagePurchaseDraft`
+- 璇锋眰浣擄細`PurchaseLedgerDto`
+
+### 2.2 浠嶇劧淇濈暀鐨勬寮忔彁浜ゆ帴鍙�
+
+- 璇锋眰鏂瑰紡锛歚POST`
+- 鎺ュ彛璺緞锛歚/purchase/ledger/addOrEditPurchase`
+
+杩欎釜鎺ュ彛缁х画璧板師鏈夐噰璐鏍告祦绋嬨�傚墠绔湪鑽夌琛ュ叏瀹屾垚鍚庯紝浠嶇劧浣跨敤瀹冩彁浜ゆ寮忛噰璐崟銆�
+
+## 3. 璇锋眰瀛楁
+
+淇濆瓨鑽夌鏃讹紝鍓嶇鑷冲皯浼犺繖浜涘瓧娈碉細
+
+- `salesContractNo`锛氶攢鍞鍗曞彿
+- `productData`锛氶噰璐骇鍝佹槑缁嗘暟缁�
+- `ccUserId`锛氭妱閫佷汉 ID
+
+鍙�夊瓧娈垫寜 `PurchaseLedgerDto` 鍘熸湁缁撴瀯浼犲叆鍗冲彲锛屼緥濡傦細
+
+- `purchaseContractNumber`
+- `supplierId`
+- `supplierName`
+- `entryDate`
+- `remarks`
+- `storageBlobDTOS`
+- `ccUserName`
+
+璇存槑锛�
+
+- `purchaseContractNumber` 濡傛灉涓嶄紶锛屽悗绔細鑷姩鐢熸垚銆�
+- 鑽夌淇濆瓨闃舵涓嶈姹傝ˉ鍏ㄩ噰璐鏍哥浉鍏充俊鎭��
+
+## 4. 杩斿洖缁撴灉
+
+鑽夌淇濆瓨鎴愬姛鍚庯紝杩斿洖閲囪喘鍙拌处涓婚敭 `id`銆�
+
+绀轰緥锛�
+
+```json
+{
+  "code": 200,
+  "msg": "淇濆瓨鎴愬姛",
+  "data": 12345
+}
+```
+
+鍓嶇搴斾繚瀛樿繖涓� `id`锛屽悗缁ˉ鍏ㄦ椂鐩存帴甯︾潃杩欎釜 `id` 璋冪敤姝e紡鎻愪氦鎺ュ彛銆�
+
+## 5. 鍚庣琛屼负
+
+### 5.1 鑽夌淇濆瓨閫昏緫
+
+鍚庣浼氭牴鎹� `salesContractNo` 鏌ヨ閿�鍞鍗曪紝骞舵妸閿�鍞鍗曚俊鎭洖濉埌閲囪喘鑽夌閲岋紝鍖呮嫭锛�
+
+- `salesLedgerId`
+- `salesContractNo`
+- `projectName`
+
+鍚屾椂锛�
+
+- `approvalStatus` 鍥哄畾涓� `0`锛岃〃绀鸿崏绋�
+- 浜у搧鏄庣粏浼氭寜閲囪喘鍙拌处瀛愯〃淇濆瓨
+- 涓嶄細鍒涘缓閲囪喘瀹℃壒娴佺▼
+- `recorderId` 鍜� `recorderName` 浼氳缃负鎶勯�佷汉
+
+### 5.2 澶囨敞瑙勫垯
+
+鍚庣浼氭妸鍘熺敵璇蜂汉淇℃伅鍐欏叆閲囪喘鍙拌处澶囨敞锛屽娉ㄥ唴瀹圭被浼硷細
+
+- `鍘熺敵璇蜂汉锛氬紶涓夛紝鐢辨妱閫佷汉鏉庡洓琛ュ叏閲囪喘璁㈠崟淇℃伅鍚庢彁浜ゅ鏍搞�俙
+
+濡傛灉鍓嶇宸茬粡浼犱簡澶囨敞锛屽悗绔細鍦ㄥ師澶囨敞鍚庤拷鍔犺繖娈佃鏄庛��
+
+### 5.3 閲囪喘鐢宠鎻愰啋娑堟伅
+
+鑽夌鍒涘缓鍚庯紝鍚庣浼氳嚜鍔ㄥ彂閫佷竴鏉$珯鍐呮秷鎭� / APP 鎻愰啋缁欐妱閫佷汉锛�
+
+- 鏍囬锛歚閲囪喘鐢宠鎻愰啋`
+- 鍐呭锛氭彁绀鸿閿�鍞鍗曞搴旂殑閲囪喘鐢宠宸插垱寤猴紝闇�瑕佽ˉ鍏ㄩ噰璐鍗曚俊鎭悗鍐嶆彁浜ゅ鏍�
+- 璺宠浆鍦板潃锛歚/purchaseLedger/edit?id={id}`
+
+## 6. 鍓嶇鑱旇皟寤鸿
+
+### 6.1 鏂板缓鑽夌椤甸潰
+
+鍓嶇寤鸿鏂板涓�涓�滅畝鏄撻噰璐敵璇封�濆叆鍙o紝瀛楁鏈�灏戝彧鏀撅細
+
+- 閿�鍞鍗曞彿
+- 鎶勯�佷汉
+- 閲囪喘浜у搧鏄庣粏
+
+淇濆瓨鍚庤烦杞埌閲囪喘鑽夌璇︽儏鎴栫紪杈戦〉锛岀户缁ˉ鍏ㄤ緵搴斿晢銆佸綍鍏ユ棩鏈熴�佸娉ㄧ瓑淇℃伅銆�
+
+### 6.2 鑽夌缂栬緫椤�
+
+鑽夌璇︽儏椤甸渶瑕佹敮鎸侊細
+
+- 璇诲彇鑽夌璇︽儏
+- 缂栬緫閲囪喘浜у搧鏄庣粏
+- 琛ュ叏閲囪喘鍗曚富琛ㄤ俊鎭�
+- 鏈�缁堣皟鐢� `/purchase/ledger/addOrEditPurchase` 姝e紡鎻愪氦
+
+### 6.3 娑堟伅涓績
+
+濡傛灉鍓嶇鏈夋秷鎭垪琛ㄩ〉锛岀敤鎴风偣鍑昏繖鏉¢噰璐敵璇锋彁閱掑悗锛屽簲璺冲埌閲囪喘鑽夌缂栬緫椤点��
+
+## 7. 璋冭瘯鐐�
+
+1. `salesContractNo` 涓嶅瓨鍦ㄦ椂锛屽悗绔細鐩存帴鎶ラ敊銆�
+2. 鑽夌淇濆瓨鍚庝笉浼氱敓鎴愬鎵瑰崟銆�
+3. 鑽夌琛ュ叏鍚庡啀璧版寮忔彁浜ゆ帴鍙o紝鎵嶄細杩涘叆瀹℃壒娴併��
+4. 娑堟伅鎺ユ敹浜烘槸鎶勯�佷汉锛屼笉鏄師鐢宠浜恒��
+5. 鍘熺敵璇蜂汉淇℃伅鍙細鍐欏叆澶囨敞銆�
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
index d072634..0edced4 100644
--- a/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
+++ b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
@@ -15,7 +15,7 @@
     @Schema(description = "鍗曚綅")
     private String unit;
 
-    @Schema(description = "搴撳瓨鏁伴噺")
+    @Schema(description = "浜у搧搴撳瓨鎬婚噺锛堟寜 productModelId 姹囨�伙紝涓嶅尯鍒嗘壒鍙凤級")
     private BigDecimal stockQuantity;
 
     @Schema(description = "棰嗙敤鏁伴噺")
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
index 554b95e..3d9a515 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -189,6 +189,7 @@
             return Collections.emptyList();
         }
         List<ProductionOrderPickVo> detailList = baseMapper.listPickedDetailByOrderId(productionOrderId);
+        fillStockQuantity(detailList);
         fillBatchNoList(detailList);
         fillSelectableBatchNoList(detailList);
         return detailList;
@@ -1121,6 +1122,34 @@
         }
     }
 
+    private void fillStockQuantity(List<ProductionOrderPickVo> detailList) {
+        if (detailList == null || detailList.isEmpty()) {
+            return;
+        }
+        Set<Long> productModelIdSet = detailList.stream()
+                .map(ProductionOrderPickVo::getProductModelId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        if (productModelIdSet.isEmpty()) {
+            return;
+        }
+        List<StockInventory> stockList = stockInventoryMapper.selectList(
+                Wrappers.<StockInventory>lambdaQuery()
+                        .in(StockInventory::getProductModelId, productModelIdSet));
+        Map<Long, BigDecimal> stockQuantityMap = new HashMap<>();
+        for (StockInventory stockInventory : stockList) {
+            if (stockInventory == null || stockInventory.getProductModelId() == null) {
+                continue;
+            }
+            stockQuantityMap.merge(stockInventory.getProductModelId(),
+                    defaultDecimal(stockInventory.getQualitity()),
+                    BigDecimal::add);
+        }
+        for (ProductionOrderPickVo detail : detailList) {
+            detail.setStockQuantity(stockQuantityMap.getOrDefault(detail.getProductModelId(), BigDecimal.ZERO));
+        }
+    }
+
     private String buildBatchNoGroupKey(ProductionOrderPickVo detail) {
         // 鏋勫缓鎵规鑱氬悎鍒嗙粍閿��
         return detail.getProductionOrderId() + "|"
diff --git a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
index 0951d3b..b7699bc 100644
--- a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -137,6 +137,17 @@
     }
 
     /**
+     * 閲囪喘鑽夌绠�鏄撴柊澧�
+     */
+    @Log(title = "閲囪喘鍙拌处", businessType = BusinessType.INSERT)
+    @PostMapping("/saveShortagePurchaseDraft")
+    @Operation(summary = "绠�鏄撴柊澧為噰璐崏绋�")
+    public AjaxResult saveShortagePurchaseDraft(@RequestBody PurchaseLedgerDto purchaseLedgerDto) throws Exception {
+        Long id = purchaseLedgerService.saveShortagePurchaseDraft(purchaseLedgerDto);
+        return AjaxResult.success("淇濆瓨鎴愬姛", id);
+    }
+
+    /**
      * 鏌ヨ閲囪喘妯℃澘
      */
     @Operation(summary = "/鏌ヨ閲囪喘妯℃澘")
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
index 22faea3..322eabf 100644
--- a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -69,6 +69,16 @@
     private String recorderName;
 
     /**
+     * 鎶勯�佷汉ID
+     */
+    private Long ccUserId;
+
+    /**
+     * 鎶勯�佷汉濮撳悕
+     */
+    private String ccUserName;
+
+    /**
      * 閿�鍞悎鍚屽彿
      */
     @Excel(name = "閿�鍞悎鍚屽彿")
diff --git a/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java b/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
index 980c6bc..b55242c 100644
--- a/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
+++ b/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -158,7 +158,4 @@
     @TableField(fill = FieldFill.INSERT)
     private Long deptId;
 
-    @Schema(description = "妯℃澘id")
-    private Long templateId;
-
 }
diff --git a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
index a0378af..730e695 100644
--- a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
+++ b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -23,6 +23,8 @@
 
     int addOrEditPurchase(PurchaseLedgerDto purchaseLedgerDto) throws Exception;
 
+    Long saveShortagePurchaseDraft(PurchaseLedgerDto purchaseLedgerDto) throws Exception;
+
     void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct);
 
     int deletePurchaseLedgerByIds(Long[] ids);
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 09d5d20..ffc617b 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -10,6 +10,7 @@
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.common.enums.ApprovalStatusEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
@@ -30,6 +31,7 @@
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.project.system.service.ISysNoticeService;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerImportDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto;
@@ -99,6 +101,7 @@
     private final QualityInspectParamMapper qualityInspectParamMapper;
     private final ApproveProcessServiceImpl approveProcessService;
     private final ProcurementRecordMapper procurementRecordStorageMapper;
+    private final ISysNoticeService sysNoticeService;
     private final FileUtil fileUtil;
 
     @Override
@@ -174,7 +177,91 @@
         return 1;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long saveShortagePurchaseDraft(PurchaseLedgerDto purchaseLedgerDto) throws Exception {
+        if (purchaseLedgerDto == null) {
+            throw new BaseException("閲囪喘鍙拌处鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isBlank(purchaseLedgerDto.getSalesContractNo())) {
+            throw new BaseException("閿�鍞鍗曞彿涓嶈兘涓虹┖");
+        }
+        if (CollectionUtils.isEmpty(purchaseLedgerDto.getProductData())) {
+            throw new BaseException("閲囪喘浜у搧淇℃伅涓嶈兘涓虹┖");
+        }
 
+        SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
+                .eq(SalesLedger::getSalesContractNo, purchaseLedgerDto.getSalesContractNo())
+                .last("limit 1"));
+        if (salesLedger == null) {
+            throw new BaseException("閿�鍞鍗曚笉瀛樺湪");
+        }
+
+        PurchaseLedger purchaseLedger = new PurchaseLedger();
+        BeanUtils.copyProperties(purchaseLedgerDto, purchaseLedger);
+        purchaseLedger.setSalesLedgerId(salesLedger.getId());
+        purchaseLedger.setSalesContractNo(salesLedger.getSalesContractNo());
+        purchaseLedger.setProjectName(salesLedger.getProjectName());
+        if (purchaseLedger.getEntryDate() == null) {
+            purchaseLedger.setEntryDate(salesLedger.getEntryDate() != null ? salesLedger.getEntryDate() : new Date());
+        }
+        if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) {
+            purchaseLedger.setPurchaseContractNumber(getPurchaseNo());
+        }
+
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long currentUserId = loginUser != null && loginUser.getUserId() != null ? loginUser.getUserId() : null;
+        if (loginUser != null && loginUser.getTenantId() != null) {
+            purchaseLedger.setTenantId(loginUser.getTenantId());
+        }
+
+        SysUser recorderUser = resolveShortagePurchaseRecorderUser(purchaseLedgerDto, currentUserId);
+        if (ObjectUtils.isNotEmpty(recorderUser)) {
+            purchaseLedger.setRecorderId(recorderUser.getUserId());
+            purchaseLedger.setRecorderName(recorderUser.getNickName());
+            purchaseLedger.setPhoneNumber(recorderUser.getPhonenumber());
+        }
+
+//        String originalApplicantName = resolveOriginalApplicantName(salesLedger); // 婧簮閿�鍞敵璇蜂汉
+        String originalApplicantName = SecurityUtils.getLoginUser().getNickName();  // 褰撳墠鐧诲綍鐢ㄦ埛
+        purchaseLedger.setRemarks(mergeShortagePurchaseRemark(
+                purchaseLedger.getRemarks(),
+                originalApplicantName,
+                ObjectUtils.isNotEmpty(recorderUser) ? recorderUser.getNickName() : null
+        ));
+
+        purchaseLedger.setApprovalStatus(ApprovalStatusEnum.DRAFT.getCode());
+
+        boolean isNewDraft = purchaseLedger.getId() == null;
+        if (isNewDraft) {
+            purchaseLedgerMapper.insert(purchaseLedger);
+        } else {
+            PurchaseLedger dbPurchaseLedger = purchaseLedgerMapper.selectById(purchaseLedger.getId());
+            if (dbPurchaseLedger == null) {
+                throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
+            }
+            if (!ApprovalStatusEnum.DRAFT.getCode().equals(dbPurchaseLedger.getApprovalStatus())) {
+                throw new BaseException("闈炶崏绋跨姸鎬佺殑閲囪喘鍙拌处涓嶅厑璁搁�氳繃绠�鏄撴柊澧炰慨鏀�");
+            }
+            purchaseLedgerMapper.updateById(purchaseLedger);
+        }
+
+        handleSalesLedgerProducts(purchaseLedger.getId(), purchaseLedgerDto.getProductData(), purchaseLedgerDto.getType());
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId(), purchaseLedgerDto.getStorageBlobDTOS());
+
+        if (isNewDraft) {
+            Long noticeUserId = resolveShortagePurchaseCopyUserId(purchaseLedgerDto, currentUserId);
+            if (noticeUserId != null && noticeUserId > 0) {
+                sysNoticeService.simpleNoticeByUser(
+                        "閲囪喘鐢宠鎻愰啋",
+                        "閿�鍞鍗曞彿 " + salesLedger.getSalesContractNo() + " 鐨勯噰璐敵璇峰凡鍒涘缓锛岃琛ュ叏閲囪喘璁㈠崟淇℃伅鍚庢彁浜ゅ鏍搞��",
+                        Collections.singletonList(noticeUserId),
+                        "/procurementManagement/procurementLedger?purchaseContractNumber=" + purchaseLedger.getPurchaseContractNumber()
+                );
+            }
+        }
+        return purchaseLedger.getId();
+    }
     public void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
         QualityInspect qualityInspect = new QualityInspect();
         qualityInspect.setInspectType(0);
@@ -626,6 +713,59 @@
         approveProcessService.addApprove(approveProcessVO);
     }
 
+    private Long resolveShortagePurchaseCopyUserId(PurchaseLedgerDto purchaseLedgerDto, Long currentUserId) {
+        if (purchaseLedgerDto != null && purchaseLedgerDto.getCcUserId() != null) {
+            return purchaseLedgerDto.getCcUserId();
+        }
+        return currentUserId;
+    }
+
+    private SysUser resolveShortagePurchaseRecorderUser(PurchaseLedgerDto purchaseLedgerDto, Long currentUserId) {
+        if (purchaseLedgerDto != null && purchaseLedgerDto.getCcUserId() != null) {
+            SysUser ccUser = sysUserMapper.selectUserById(purchaseLedgerDto.getCcUserId());
+            if (ccUser != null) {
+                return ccUser;
+            }
+        }
+        if (purchaseLedgerDto != null && StringUtils.isNotBlank(purchaseLedgerDto.getCcUserName())) {
+            SysUser ccUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+                    .eq(SysUser::getNickName, purchaseLedgerDto.getCcUserName())
+                    .last("limit 1"));
+            if (ccUser != null) {
+                return ccUser;
+            }
+        }
+        return currentUserId == null ? null : sysUserMapper.selectUserById(currentUserId);
+    }
+
+    private String resolveOriginalApplicantName(SalesLedger salesLedger) {
+        if (salesLedger == null) {
+            return null;
+        }
+        if (salesLedger.getCreateUser() != null) {
+            SysUser applicant = sysUserMapper.selectUserById(salesLedger.getCreateUser().longValue());
+            if (applicant != null && StringUtils.hasText(applicant.getNickName())) {
+                return applicant.getNickName();
+            }
+        }
+        if (StringUtils.hasText(salesLedger.getEntryPerson())) {
+            return salesLedger.getEntryPerson();
+        }
+        return null;
+    }
+
+    private String mergeShortagePurchaseRemark(String originalRemark, String applicantName, String recorderName) {
+        String sentence = "鍘熺敵璇蜂汉锛�" + (StringUtils.hasText(applicantName) ? applicantName : "鏈瘑鍒�")
+                + "锛岀敱鎶勯�佷汉" + (StringUtils.hasText(recorderName) ? recorderName : "鏈瘑鍒�")
+                + "琛ュ叏閲囪喘璁㈠崟淇℃伅鍚庢彁浜ゅ鏍搞��";
+        if (!StringUtils.hasText(originalRemark)) {
+            return sentence;
+        }
+        if (originalRemark.contains("鍘熺敵璇蜂汉锛�")) {
+            return originalRemark;
+        }
+        return originalRemark + "\\n" + sentence;
+    }
     /**
      * 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
      */

--
Gitblit v1.9.3