From c7e7ed6d05cd1586b37396bcabc9f3f7e6ec589f Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期三, 21 十月 2026 16:08:51 +0800
Subject: [PATCH] feat(销售台账/产品维护): 图号必填唯一、合同号唯一、明细产品编码与导入物料编码

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java |  100 +++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 91 insertions(+), 9 deletions(-)

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 50975fd..86ed7cf 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -19,6 +19,7 @@
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.Customer;
+import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.enums.SaleEnum;
@@ -361,13 +362,34 @@
             // 褰曞叆浜烘暟鎹�
             List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
                     salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
-            for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
-                SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
-                        .eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo())
-                        .last("LIMIT 1"));
-                if (salesLedger1 != null) {
+            // 閿�鍞崟鍙烽噸澶嶆牎楠岋細鏂囦欢鍐呴噸澶嶆垨搴撳唴宸插瓨鍦ㄧ殑锛岀洿鎺ュけ璐ュ苟鍥炴樉鍘熸湁閿�鍞崟鍙�
+            List<String> duplicateContractNos = new ArrayList<>();
+            Set<String> importContractNos = new HashSet<>();
+            for (SalesLedgerImportDto item : salesLedgerImportDtoList) {
+                String contractNo = StringUtils.trim(item.getSalesContractNo());
+                if (StringUtils.isEmpty(contractNo)) {
                     continue;
                 }
+                if (!importContractNos.add(contractNo)) {
+                    duplicateContractNos.add(contractNo);
+                }
+            }
+            if (CollectionUtils.isNotEmpty(duplicateContractNos)) {
+                return AjaxResult.error("瀵煎叆鏂囦欢涓瓨鍦ㄩ噸澶嶇殑閿�鍞崟鍙凤細" + String.join("銆�", duplicateContractNos));
+            }
+            if (CollectionUtils.isNotEmpty(importContractNos)) {
+                List<SalesLedger> existLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
+                        .in(SalesLedger::getSalesContractNo, importContractNos)
+                        .select(SalesLedger::getId, SalesLedger::getSalesContractNo));
+                if (CollectionUtils.isNotEmpty(existLedgers)) {
+                    String existNos = existLedgers.stream()
+                            .map(SalesLedger::getSalesContractNo)
+                            .distinct()
+                            .collect(Collectors.joining("銆�"));
+                    return AjaxResult.error("浠ヤ笅閿�鍞崟鍙峰凡瀛樺湪锛屼笉鑳介噸澶嶆柊澧烇細" + existNos);
+                }
+            }
+            for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
                 SalesLedger salesLedger = new SalesLedger();
                 BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
                 salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate()));
@@ -408,6 +430,11 @@
                     BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct);
                     salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                     salesLedgerProduct.setType(1);
+                    // 鐗╂枡缂栫爜 -> 浜у搧缂栫爜
+                    String materialCode = StringUtils.trim(salesLedgerProductImportDto.getMaterialCode());
+                    if (StringUtils.isNotEmpty(materialCode)) {
+                        salesLedgerProduct.setProductCode(materialCode);
+                    }
                     AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
                     // 璁$畻涓嶅惈绋庢�讳环
                     salesLedgerProduct.setTaxExclusiveTotalPrice(
@@ -422,6 +449,10 @@
                             .ifPresent(map -> {
                                 salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
                                 salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
+                                // 鏈~鐗╂枡缂栫爜鏃讹紝鎸変骇鍝佸瀷鍙峰洖濉骇鍝佺紪鐮�
+                                if (StringUtils.isEmpty(salesLedgerProduct.getProductCode()) && map.get("productCode") != null) {
+                                    salesLedgerProduct.setProductCode(map.get("productCode").toString());
+                                }
                             });
 //                    salesLedgerProduct.setProductId(productList.stream()
 //                            .filter(product -> product.getProductName().equals(salesLedgerProduct.getProductCategory()))
@@ -436,7 +467,7 @@
                     salesLedgerProduct.setRegister(loginUser.getNickName());
                     salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                     salesLedgerProduct.setApproveStatus(0);
-                    salesLedgerProduct.setIsProduction(salesLedgerProductImportDto.getIsProduction() == 1);
+                    salesLedgerProduct.setIsProduction(parseProductionFlag(salesLedgerProductImportDto.getIsProduction()));
                     salesLedgerProductMapper.insert(salesLedgerProduct);
                     // 娣诲姞鐢熶骇鏁版嵁
                     salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
@@ -582,9 +613,14 @@
         AmountUtils.normalizeContractAmount(salesLedger);
         salesLedger.setCustomerName(customer.getCustomerName());
         salesLedger.setTenantId(customer.getTenantId());
-        // 3. 鏂板鎴栨洿鏂颁富琛�
+        // 3. 閿�鍞悎鍚屽彿鍞竴鏍¢獙锛堟敮鎸佸瓧姣嶃�佹暟瀛楀強鐗规畩瀛楃锛屼笉鍋氬瓧绗﹂泦闄愬埗锛�
+        String contractNo = StringUtils.trim(salesLedger.getSalesContractNo());
+        if (StringUtils.isNotEmpty(contractNo)) {
+            checkSalesContractNoUnique(contractNo, salesLedger.getId());
+            salesLedger.setSalesContractNo(contractNo);
+        }
+        // 4. 鏂板鎴栨洿鏂颁富琛�
         if (salesLedger.getId() == null) {
-            String contractNo = salesLedger.getSalesContractNo();
             if (StringUtils.isEmpty(contractNo)) {
                 contractNo = generateSalesContractNo();
             }
@@ -595,7 +631,7 @@
         }
 
 
-        // 4. 澶勭悊瀛愯〃鏁版嵁
+        // 5. 澶勭悊瀛愯〃鏁版嵁
         List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
         if (productList != null && !productList.isEmpty()) {
             AmountUtils.normalizeSalesLedgerProducts(productList);
@@ -615,8 +651,31 @@
         return 1;
     }
 
+    /**
+     * 閿�鍞悎鍚屽彿鍞竴鏍¢獙锛堢紪杈戞椂鎺掗櫎鑷韩锛�
+     */
+    private void checkSalesContractNoUnique(String salesContractNo, Long currentId) {
+        LambdaQueryWrapper<SalesLedger> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SalesLedger::getSalesContractNo, salesContractNo)
+                .ne(currentId != null, SalesLedger::getId, currentId)
+                .last("limit 1");
+        SalesLedger duplicate = salesLedgerMapper.selectOne(queryWrapper);
+        if (duplicate != null) {
+            throw new BaseException("閿�鍞悎鍚屽彿" + salesContractNo + "宸插瓨鍦紙閿�鍞崟鍙凤細" + duplicate.getSalesContractNo() + "锛夛紝璇烽噸鏂板~鍐�");
+        }
+    }
+
     @Override
     public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) {
+        // 浜у搧缂栫爜鍏滃簳锛氬墠绔湭浼犳椂鎸変骇鍝佸瀷鍙峰洖濉�
+        products.forEach(p -> {
+            if (StringUtils.isEmpty(p.getProductCode()) && p.getProductModelId() != null) {
+                ProductModel productModel = productModelMapper.selectById(p.getProductModelId());
+                if (productModel != null) {
+                    p.setProductCode(productModel.getProductCode());
+                }
+            }
+        });
         // 鎸塈D鍒嗙粍锛屽尯鍒嗘柊澧炲拰鏇存柊鐨勮褰�
         Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
                 .peek(p -> p.setSalesLedgerId(salesLedgerId))
@@ -643,6 +702,17 @@
                 salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
             }
         }
+    }
+
+    /**
+     * 瑙f瀽瀵煎叆鐨勨�滄槸鍚︾敓浜р�濆垪锛氭敮鎸� 1/0銆佹槸/鍚�
+     */
+    private static boolean parseProductionFlag(String value) {
+        if (StringUtils.isEmpty(value)) {
+            return false;
+        }
+        String v = value.trim();
+        return "1".equals(v) || "鏄�".equals(v) || "true".equalsIgnoreCase(v) || "yes".equalsIgnoreCase(v);
     }
 
     private SalesLedger convertToEntity(SalesLedgerDto dto) {
@@ -800,4 +870,16 @@
         result.put("ledger", ledger);
         return result;
     }
+
+    @Override
+    public Map<Long, SalesLedgerEditFlagDto> getEditFlags(List<Long> ids) {
+        if (CollectionUtils.isEmpty(ids)) {
+            return new HashMap<>();
+        }
+        List<SalesLedgerEditFlagDto> flags = salesLedgerMapper.selectEditFlags(ids);
+        return flags.stream().collect(Collectors.toMap(
+                SalesLedgerEditFlagDto::getSalesLedgerId,
+                Function.identity(),
+                (existing, replacement) -> existing));
+    }
 }

--
Gitblit v1.9.3