From fd5ff7ce41f402720c79546617842bbf679e576e Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期三, 21 十月 2026 16:32:55 +0800
Subject: [PATCH] fix(销售台账/产品维护): 图号与销售合同号长度校验、导入提示优化

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java |  187 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 161 insertions(+), 26 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 7610fa8..c2f95c1 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -12,16 +12,19 @@
 import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
 import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
 import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.basic.dto.StorageAttachmentDTO;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.mapper.CustomerMapper;
 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;
 import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.AmountUtils;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.EnumUtil;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -150,7 +153,7 @@
             // 鏌ヨ閫�璐т俊鎭�
             List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList());
             List<SimpleReturnOrderGroupDto> groupListByProductIds = new ArrayList<>();
-            if(CollectionUtils.isNotEmpty(productIds)){
+            if (CollectionUtils.isNotEmpty(productIds)) {
                 groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds);
             }
             Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, SimpleReturnOrderGroupDto::getSumReturnQuantity));
@@ -176,6 +179,7 @@
         productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId());
         productWrapper.eq(SalesLedgerProduct::getType, 1);
         List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
+        AmountUtils.normalizeSalesLedgerProducts(products);
         for (SalesLedgerProduct product : products) {
             product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
             product.setRegisterDate(LocalDateTime.now());
@@ -185,7 +189,11 @@
                     .orderByDesc(ShippingInfo::getCreateTime)
                     .last("limit 1"));
             if (shippingInfo != null) {
+                product.setShippingCarNumber(shippingInfo.getShippingCarNumber());
+                product.setShippingDate(shippingInfo.getShippingDate());
                 product.setShippingStatus(shippingInfo.getStatus());
+                product.setExpressCompany(shippingInfo.getExpressCompany());
+                product.setExpressNumber(shippingInfo.getExpressNumber());
             }
         }
 
@@ -198,11 +206,18 @@
         // 4. 杞崲 DTO
         SalesLedgerDto resultDto = new SalesLedgerDto();
         BeanUtils.copyProperties(salesLedger, resultDto);
+        AmountUtils.normalizeContractAmount(resultDto);
         if (!products.isEmpty()) {
             resultDto.setHasChildren(true);
             resultDto.setProductData(products);
             resultDto.setSalesLedgerFiles(salesLedgerFiles);
         }
+
+        StorageAttachmentDTO attachmentQuery = new StorageAttachmentDTO();
+        attachmentQuery.setApplication(ApplicationTypeEnum.FILE.getType());
+        attachmentQuery.setRecordType(RecordTypeEnum.SALES_LEDGER.getType());
+        attachmentQuery.setRecordId(salesLedger.getId());
+        resultDto.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(attachmentQuery));
         return resultDto;
     }
 
@@ -297,7 +312,7 @@
             dto.setReceiptAmount(totalIncome);
             //寮�绁ㄩ噾棰�
             List<AccountInvoiceApplication> accountInvoiceApplications = accountInvoiceApplicationMapper.selectList(new LambdaQueryWrapper<AccountInvoiceApplication>()
-                            .eq(AccountInvoiceApplication::getStatus,1)
+                    .eq(AccountInvoiceApplication::getStatus, 1)
                     .between(AccountInvoiceApplication::getApplyDate, startTime, endTime));
             BigDecimal totalInvoiceAmount = Optional.of(
                     accountInvoiceApplications.stream()
@@ -313,7 +328,11 @@
 
     @Override
     public IPage<SalesLedgerVo> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) {
-        return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
+        IPage<SalesLedgerVo> result = salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
+        if (!CollectionUtils.isEmpty(result.getRecords())) {
+            result.getRecords().forEach(AmountUtils::normalizeContractAmount);
+        }
+        return result;
     }
 
     @Override
@@ -343,13 +362,37 @@
             // 褰曞叆浜烘暟鎹�
             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 (contractNo.length() > 50) {
+                    return AjaxResult.error("閿�鍞崟鍙枫��" + contractNo + "銆戦暱搴︿笉鑳借秴杩�50涓瓧绗�");
+                }
+                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()));
@@ -371,7 +414,7 @@
                         .map(SysUser::getUserId)
                         .orElse(null);
                 if (aLong == null)
-                    throw new RuntimeException("褰曞叆浜�:" + salesLedger.getEntryPerson() + ",鏃犲搴旂敤鎴凤紒");
+                    throw new RuntimeException("褰曞叆浜�:" + salesLedger.getEntryPerson() + ",鏃犲搴旂敤鎴凤紒璇峰~鍐欑郴缁熺敤鎴风殑鏄电О锛堜笉鏄櫥褰曡处鍙凤級");
                 salesLedger.setEntryPerson(aLong.toString());
                 // 閿�鍞骇鍝佹暟鎹粦瀹氾紝閫氳繃閿�鍞崟鍙疯幏鍙栧搴旈攢鍞骇鍝佹暟鎹�
                 List<SalesLedgerProductImportDto> salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream()
@@ -390,14 +433,29 @@
                     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(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
+                    salesLedgerProduct.setTaxExclusiveTotalPrice(
+                            AmountUtils.calcTaxExclusiveTotalPrice(
+                                    salesLedgerProduct.getTaxInclusiveTotalPrice(),
+                                    salesLedgerProduct.getTaxRate()
+                            )
+                    );
                     list.stream()
                             .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                             .findFirst()
                             .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()))
@@ -412,7 +470,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);
@@ -445,17 +503,19 @@
             productWrapper.eq(SalesLedgerProduct::getType, 1);
             List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
             for (SalesLedgerProduct product : products) {
-               product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
+                product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
                 product.setRegisterDate(LocalDateTime.now());
                 // 鍙戣揣淇℃伅
                 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
                         .eq(ShippingInfo::getSalesLedgerProductId, product.getId())
                         .orderByDesc(ShippingInfo::getCreateTime)
                         .last("limit 1"));
-                product.setShippingCarNumber(shippingInfo.getShippingCarNumber());
-                product.setShippingDate(shippingInfo.getShippingDate());
                 if (shippingInfo != null) {
+                    product.setShippingCarNumber(shippingInfo.getShippingCarNumber());
+                    product.setShippingDate(shippingInfo.getShippingDate());
                     product.setShippingStatus(shippingInfo.getStatus());
+                    product.setExpressCompany(shippingInfo.getExpressCompany());
+                    product.setExpressNumber(shippingInfo.getExpressNumber());
                 }
             }
             // 杩囨护鍙繚鐣欏彂璐ц褰�
@@ -504,6 +564,7 @@
         // 鍒犻櫎閿�鍞鐞嗘暟鎹�
         LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList)
+                .eq(SalesLedgerProduct::getType, 1)
                 .select(SalesLedgerProduct::getId);
 
         List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(queryWrapper);
@@ -552,11 +613,20 @@
 
         // 2. DTO杞珽ntity
         SalesLedger salesLedger = convertToEntity(salesLedgerDto);
+        AmountUtils.normalizeContractAmount(salesLedger);
         salesLedger.setCustomerName(customer.getCustomerName());
         salesLedger.setTenantId(customer.getTenantId());
-        // 3. 鏂板鎴栨洿鏂颁富琛�
+        // 3. 閿�鍞悎鍚屽彿鍞竴鏍¢獙锛堟敮鎸佸瓧姣嶃�佹暟瀛楀強鐗规畩瀛楃锛屼笉鍋氬瓧绗﹂泦闄愬埗锛�
+        String contractNo = StringUtils.trim(salesLedger.getSalesContractNo());
+        if (StringUtils.isNotEmpty(contractNo)) {
+            if (contractNo.length() > 50) {
+                throw new BaseException("閿�鍞悎鍚屽彿闀垮害涓嶈兘瓒呰繃50涓瓧绗�");
+            }
+            checkSalesContractNoUnique(contractNo, salesLedger.getId());
+            salesLedger.setSalesContractNo(contractNo);
+        }
+        // 4. 鏂板鎴栨洿鏂颁富琛�
         if (salesLedger.getId() == null) {
-            String contractNo = salesLedger.getSalesContractNo();
             if (StringUtils.isEmpty(contractNo)) {
                 contractNo = generateSalesContractNo();
             }
@@ -567,9 +637,10 @@
         }
 
 
-        // 4. 澶勭悊瀛愯〃鏁版嵁
+        // 5. 澶勭悊瀛愯〃鏁版嵁
         List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
         if (productList != null && !productList.isEmpty()) {
+            AmountUtils.normalizeSalesLedgerProducts(productList);
             handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
             updateMainContractAmount(
                     salesLedger.getId(),
@@ -586,8 +657,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))
@@ -599,6 +693,7 @@
         // 鎵ц鏇存柊鎿嶄綔
         if (!updateList.isEmpty()) {
             for (SalesLedgerProduct product : updateList) {
+                AmountUtils.normalizeSalesLedgerProduct(product);
                 product.setType(type.getCode());
                 salesLedgerProductMapper.updateById(product);
             }
@@ -606,12 +701,24 @@
         // 鎵ц鎻掑叆鎿嶄綔
         if (!insertList.isEmpty()) {
             for (SalesLedgerProduct salesLedgerProduct : insertList) {
+                AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
                 salesLedgerProduct.setType(type.getCode());
                 salesLedgerProductMapper.insert(salesLedgerProduct);
                 // 娣诲姞鐢熶骇鏁版嵁
                 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) {
@@ -650,14 +757,15 @@
             }
 
             // 2. 鏌ヨ褰撳ぉ/鍏徃宸插瓨鍦ㄧ殑搴忓垪鍙凤紙涓庡師閫昏緫涓�鑷达級
-            Long tenantId = SecurityUtils.getLoginUser().getTenantId();
-            if (null != tenantId) {
-                //鑾峰彇鍏徃缂栧彿
-                SysDept sysDept = sysDeptMapper.selectDeptById(tenantId.longValue());
-                if (!ObjectUtils.isEmpty(sysDept)) {
-                    datePart = (StringUtils.isEmpty(sysDept.getDeptNick()) ? "" : sysDept.getDeptNick()) + datePart;
-                }
-            }
+//            Long tenantId = SecurityUtils.getLoginUser().getTenantId();
+//            if (null != tenantId) {
+            //鑾峰彇鍏徃缂栧彿
+//                SysDept sysDept = sysDeptMapper.selectDeptById(tenantId.longValue());
+//                if (!ObjectUtils.isEmpty(sysDept)) {
+//                    datePart = (StringUtils.isEmpty(sysDept.getDeptNick()) ? "" : sysDept.getDeptNick()) + datePart;
+//                }
+//            }
+            datePart = "D" + datePart;
             List<Integer> existingSequences = salesLedgerMapper.selectSequencesByDate(datePart);
             int nextSequence = findFirstMissingSequence(existingSequences);
 
@@ -716,7 +824,7 @@
 
             Field amountField = mainEntityClass.getDeclaredField("contractAmount");
             amountField.setAccessible(true);
-            amountField.set(entity, totalAmount);
+            amountField.set(entity, AmountUtils.scaleAmount(totalAmount));
 
             mainMapper.updateById(entity);
         } catch (Exception e) {
@@ -753,4 +861,31 @@
             return totalAmount;
         }
     }
+
+    @Override
+    public Map<String, Object> getPrintData(Long id) {
+        SalesLedgerDto dto = new SalesLedgerDto();
+        dto.setId(id);
+        SalesLedgerDto ledger = getSalesLedgerWithProducts(dto);
+        if (ledger == null) {
+            return null;
+        }
+        SysDept dept = sysDeptMapper.selectDeptById(100L);
+        Map<String, Object> result = new HashMap<>();
+        result.put("companyName", dept != null ? dept.getDeptName() : "");
+        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