From 87733eb3623593da247c051593d64b8ff9e1d3a4 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 06 十一月 2026 19:00:39 +0800
Subject: [PATCH] feat(crm,mes): 扩展客户字段与重构批次号生成逻辑

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java |   50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 49 insertions(+), 1 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java
index 7303e8d..4d712e9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java
@@ -6,6 +6,10 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
+import org.springframework.transaction.annotation.Transactional;
 import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
 import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
@@ -40,9 +44,26 @@
     private MesWmMaterialStockService materialStockService;
     @Resource
     private MesWmWarehouseAreaService warehouseAreaService;
+    @Resource
+    private MesWmMaterialStockBagMapper stockBagMapper;
+    @Resource
+    private MesWmProductSalesMapper productSalesMapper;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createProductSalesDetail(MesWmProductSalesDetailSaveReqVO createReqVO) {
+        lockPickingOrder(createReqVO.getSalesId());
+        if (createReqVO.getRemark() != null && createReqVO.getRemark().matches("绉诲姩绔棤琚嬬爜鎷h揣 #[a-f0-9-]{36}")) {
+            var existing = productSalesDetailMapper.selectListBySalesId(createReqVO.getSalesId()).stream()
+                    .filter(d -> createReqVO.getRemark().equals(d.getRemark())).findFirst().orElse(null);
+            if (existing != null) {
+                if (ObjUtil.notEqual(existing.getLineId(), createReqVO.getLineId())
+                        || ObjUtil.notEqual(existing.getMaterialStockId(), createReqVO.getMaterialStockId())
+                        || existing.getQuantity().compareTo(createReqVO.getQuantity()) != 0)
+                    throw new IllegalArgumentException("鎷h揣璇锋眰鏍囪瘑宸茬敤浜庡叾浠栨槑缁�");
+                return existing.getId();
+            }
+        }
         // 鏍¢獙鏁版嵁
         validateProductSalesDetailSaveData(createReqVO);
 
@@ -53,9 +74,13 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateProductSalesDetail(MesWmProductSalesDetailSaveReqVO updateReqVO) {
         // 鏍¢獙瀛樺湪
         MesWmProductSalesDetailDO existing = validateProductSalesDetailExists(updateReqVO.getId());
+        lockPickingOrder(existing.getSalesId());
+        if (existing.getShipmentId() != null) throw new IllegalArgumentException("宸插垎閰嶅彂璐ц褰曠殑鏄庣粏涓嶈兘淇敼");
+        if (ObjUtil.notEqual(existing.getSalesId(), updateReqVO.getSalesId())) throw exception(WM_PRODUCT_SALES_DETAIL_LINE_NOT_MATCH);
         if (existing.getBagCodeId() != null) throw new IllegalArgumentException("鎵爜琚嬬爜鏄庣粏涓嶈兘鎵嬪伐淇敼鏁伴噺鎴栧簱瀛橈紝璇峰垹闄ゅ悗閲嶆柊鎵爜閫夋嫨");
         // 鏍¢獙鏁版嵁
         validateProductSalesDetailSaveData(updateReqVO);
@@ -66,9 +91,12 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void deleteProductSalesDetail(Long id) {
         // 鏍¢獙瀛樺湪
-        validateProductSalesDetailExists(id);
+        MesWmProductSalesDetailDO detail = validateProductSalesDetailExists(id);
+        lockPickingOrder(detail.getSalesId());
+        if (detail.getShipmentId() != null) throw new IllegalArgumentException("宸插垎閰嶅彂璐ц褰曠殑鏄庣粏涓嶈兘鍒犻櫎");
         // 鍒犻櫎
         productSalesDetailMapper.deleteById(id);
     }
@@ -106,7 +134,19 @@
         return detail;
     }
 
+    private void lockPickingOrder(Long salesId) {
+        var sales = productSalesMapper.selectByIdForUpdate(salesId);
+        if (sales == null) throw exception(WM_PRODUCT_SALES_NOT_EXISTS);
+        if (!MesWmProductSalesStatusEnum.APPROVING.getStatus().equals(sales.getStatus())) {
+            throw exception(WM_PRODUCT_SALES_CANNOT_PICK);
+        }
+    }
+
     private void validateProductSalesDetailSaveData(MesWmProductSalesDetailSaveReqVO reqVO) {
+        if (reqVO.getQuantity() == null || reqVO.getQuantity().signum() <= 0) throw new IllegalArgumentException("鎷h揣鏁伴噺蹇呴』澶т簬闆�");
+        if (reqVO.getMaterialStockId() != null && stockBagMapper.selectOneActiveByMaterialStockId(reqVO.getMaterialStockId()) != null) {
+            throw new IllegalArgumentException("璇ュ簱瀛樺瓨鍦ㄨ鐮佹槑缁嗭紝璇烽�夋嫨瀹為檯鎷e嚭鐨勮鐮�");
+        }
         // 鏍¢獙鐖舵暟鎹紙琛岋級瀛樺湪
         MesWmProductSalesLineDO line = productSalesLineService.getProductSalesLine(reqVO.getLineId());
         if (line == null) {
@@ -115,11 +155,19 @@
         if (ObjUtil.notEqual(line.getSalesId(), reqVO.getSalesId())) {
             throw exception(WM_PRODUCT_SALES_DETAIL_LINE_NOT_MATCH);
         }
+        var picked = productSalesDetailMapper.selectListByLineId(line.getId()).stream()
+                .filter(d -> !java.util.Objects.equals(d.getId(), reqVO.getId()))
+                .map(MesWmProductSalesDetailDO::getQuantity).reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
+        if (line.getQuantity() == null || picked.add(reqVO.getQuantity()).compareTo(line.getQuantity()) > 0)
+            throw new IllegalArgumentException("绱鎷h揣鏁伴噺涓嶈兘瓒呰繃鍑哄簱鍗曡璁″垝鏁伴噺");
         // 鏍¢獙鐗╂枡瀛樺湪
         mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
         if (ObjUtil.notEqual(line.getItemId(), reqVO.getItemId())) {
             throw exception(WM_PRODUCT_SALES_DETAIL_ITEM_MISMATCH);
         }
+        if (line.getBatchCode() != null && !line.getBatchCode().isBlank()
+                && !java.util.Objects.equals(line.getBatchCode(), reqVO.getBatchCode()))
+            throw new IllegalArgumentException("鎵�閫夊簱瀛樻壒娆′笌鍑哄簱鍗曡鎵规涓嶄竴鑷�");
         // 鏍¢獙搴撲綅瀛樺湪
         warehouseAreaService.validateWarehouseAreaExists(
                 reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId());

--
Gitblit v1.9.3