From e2729587d4a8b9c2e3e2c4dd50a25adedb337e98 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 14 八月 2026 15:58:15 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business

---
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java |    4 +
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java                    |    4 +
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java         |   31 ++++++++--
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java   |   39 +++++++++++-
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java           |    4 +
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java |   22 +++++++
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/vo/CrmSaleQuotationRespVO.java    |   12 +++
 docs/projectSql/ruoyi-vue-pro.sql                                                                                       |    2 
 docs/contract_generate_order_frontend.md                                                                                |    3 +
 9 files changed, 105 insertions(+), 16 deletions(-)

diff --git a/docs/contract_generate_order_frontend.md b/docs/contract_generate_order_frontend.md
index cab4848..5ad5506 100644
--- a/docs/contract_generate_order_frontend.md
+++ b/docs/contract_generate_order_frontend.md
@@ -228,6 +228,9 @@
 ALTER TABLE `erp_sale_order`
 ADD COLUMN `contract_id` bigint DEFAULT NULL COMMENT '鍏宠仈 CRM 鍚堝悓缂栧彿' AFTER `customer_id`,
 ADD COLUMN `contract_no` varchar(32) DEFAULT NULL COMMENT 'CRM 鍚堝悓鍗曞彿' AFTER `contract_id`;
+
+ALTER TABLE `erp_sale_order`
+MODIFY COLUMN `deposit_price` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�';
 ```
 
 ---
diff --git a/docs/projectSql/ruoyi-vue-pro.sql b/docs/projectSql/ruoyi-vue-pro.sql
index 82f8c7a..baaafbc 100644
--- a/docs/projectSql/ruoyi-vue-pro.sql
+++ b/docs/projectSql/ruoyi-vue-pro.sql
@@ -3449,7 +3449,7 @@
   `total_tax_price` decimal(24, 6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
   `discount_percent` decimal(24, 6) NOT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
   `discount_price` decimal(24, 6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
-  `deposit_price` decimal(24, 6) NOT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
+  `deposit_price` decimal(24, 6) NOT NULL DEFAULT 0 COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
   `file_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '闄勪欢鍦板潃',
   `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '澶囨敞',
   `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
index 7e8f217..0c51c0e 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
@@ -36,9 +36,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Stream;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
@@ -123,18 +121,39 @@
         List<CrmBusinessProductDO> businessProducts = businessService.getBusinessProductListByBusinessId(businessVO.getId());
         Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
                 convertSet(businessProducts, CrmBusinessProductDO::getItemId));
-        Map<Long, MdmUnitMeasureRespDTO> unitMap = mdmUnitMeasureApi.getUnitMeasureMap(
-                convertSet(businessProducts, CrmBusinessProductDO::getItemUnitId));
+        // 鏀堕泦鎵�鏈夐渶瑕佹煡璇㈢殑鍗曚綅ID锛堜富鍗曚綅 + 杈呭崟浣�1 + 杈呭崟浣�2锛�
+        Set<Long> unitIds = new HashSet<>();
+        unitIds.addAll(convertSet(businessProducts, CrmBusinessProductDO::getItemUnitId));
+        itemMap.values().forEach(item -> {
+            if (item.getUnitMeasureId2() != null) {
+                unitIds.add(item.getUnitMeasureId2());
+            }
+            if (item.getUnitMeasureId3() != null) {
+                unitIds.add(item.getUnitMeasureId3());
+            }
+        });
+        Map<Long, MdmUnitMeasureRespDTO> unitMap = mdmUnitMeasureApi.getUnitMeasureMap(unitIds);
         businessVO.setProducts(BeanUtils.toBean(businessProducts, CrmBusinessRespVO.Product.class, businessProductVO ->
                 MapUtils.findAndThen(itemMap, businessProductVO.getItemId(),
                         item -> businessProductVO.setItemName(item.getName())
                                 .setItemCode(item.getCode())
                                 .setBarCode(item.getBarCode())
                                 .setItemSpecification(item.getSpecification()))));
-        // 濉厖鍗曚綅鍚嶇О
+        // 濉厖鍗曚綅鍚嶇О锛堜富鍗曚綅 + 杈呭崟浣�1 + 杈呭崟浣�2锛�
         businessVO.getProducts().forEach(product -> {
             MapUtils.findAndThen(unitMap, product.getItemUnitId(),
                     unit -> product.setItemUnitName(unit.getName()));
+            // 濉厖杈呭崟浣嶅悕绉�
+            MapUtils.findAndThen(itemMap, product.getItemId(), item -> {
+                if (item.getUnitMeasureId2() != null) {
+                    MapUtils.findAndThen(unitMap, item.getUnitMeasureId2(),
+                            unit -> product.setItemUnitName2(unit.getName()));
+                }
+                if (item.getUnitMeasureId3() != null) {
+                    MapUtils.findAndThen(unitMap, item.getUnitMeasureId3(),
+                            unit -> product.setItemUnitName3(unit.getName()));
+                }
+            });
         });
         return businessVO;
     }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
index f6cd8db..b910cf0 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
@@ -134,6 +134,10 @@
         private Long itemUnitId;
         @Schema(description = "璁¢噺鍗曚綅鍚嶇О", example = "涓�")
         private String itemUnitName;
+        @Schema(description = "杈呭崟浣�1鍚嶇О")
+        private String itemUnitName2;
+        @Schema(description = "杈呭崟浣�2鍚嶇О")
+        private String itemUnitName3;
 
         @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
         private String barCode;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java
index 4550df6..edb91c0 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java
@@ -44,5 +44,25 @@
     private List<Long> contactIds;
 
     @Schema(description = "鍥剧墖 URL 鍒楄〃")
-    private List<String> picUrls;
+    private Object picUrls; // 鎺ュ彈瀛楃涓叉垨鏁扮粍
+
+    /**
+     * 鑾峰彇鍥剧墖 URL 鍒楄〃
+     */
+    public List<String> getPicUrlList() {
+        if (picUrls == null) {
+            return null;
+        }
+        if (picUrls instanceof List) {
+            return (List<String>) picUrls;
+        }
+        if (picUrls instanceof String) {
+            String str = (String) picUrls;
+            if (str.isEmpty()) {
+                return null;
+            }
+            return java.util.Arrays.asList(str.split(","));
+        }
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
index 58b5dba..fda9a92 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
@@ -161,9 +161,14 @@
         // 1. 鏋勫缓鐗╂枡鏄庣粏
         if (CollUtil.isNotEmpty(productList)) {
             Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(convertSet(productList, CrmSaleQuotationProductDO::getItemId));
+            java.util.Set<Long> unitIds = new java.util.HashSet<>(convertSet(productList, CrmSaleQuotationProductDO::getItemUnitId));
+            itemMap.values().forEach(item -> {
+                if (item.getUnitMeasureId2() != null) {
+                    unitIds.add(item.getUnitMeasureId2());
+                }
+            });
             Map<Long, MdmUnitMeasureRespDTO> unitMap = convertMap(
-                    mdmUnitMeasureApi.getUnitMeasureList(
-                            convertSet(productList, CrmSaleQuotationProductDO::getItemUnitId)).getCheckedData(),
+                    mdmUnitMeasureApi.getUnitMeasureList(unitIds).getCheckedData(),
                     MdmUnitMeasureRespDTO::getId);
             respVO.setItems(BeanUtils.toBean(productList, CrmSaleQuotationRespVO.Item.class, item -> {
                 MdmItemRespDTO mdmItem = itemMap.get(item.getItemId());
@@ -171,8 +176,13 @@
                     item.setItemCode(mdmItem.getCode());
                     item.setItemName(mdmItem.getName());
                     item.setItemBarCode(mdmItem.getBarCode());
+                    item.setItemSpecification(mdmItem.getSpecification());
+                    item.setItemUnitId2(mdmItem.getUnitMeasureId2());
+                    item.setItemUnitId3(mdmItem.getUnitMeasureId3());
                 }
                 MapUtils.findAndThen(unitMap, item.getItemUnitId(), unit -> item.setItemUnitName(unit.getName()));
+                MapUtils.findAndThen(unitMap, item.getItemUnitId2(), unit -> item.setItemUnitName2(unit.getName()));
+                MapUtils.findAndThen(unitMap, item.getItemUnitId3(), unit -> item.setItemUnitName3(unit.getName()));
             }));
         }
         // 2. 濉厖瀹㈡埛鍚嶇О
@@ -206,6 +216,15 @@
         Map<Long, List<CrmSaleQuotationProductDO>> productMap = convertMultiMap(productList, CrmSaleQuotationProductDO::getQuotationId);
         // 1.2 鐗╂枡淇℃伅
         Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(convertSet(productList, CrmSaleQuotationProductDO::getItemId));
+        java.util.Set<Long> unitIds = new java.util.HashSet<>(convertSet(productList, CrmSaleQuotationProductDO::getItemUnitId));
+        itemMap.values().forEach(item -> {
+            if (item.getUnitMeasureId2() != null) {
+                unitIds.add(item.getUnitMeasureId2());
+            }
+        });
+        Map<Long, MdmUnitMeasureRespDTO> unitMap = convertMap(
+                mdmUnitMeasureApi.getUnitMeasureList(unitIds).getCheckedData(),
+                MdmUnitMeasureRespDTO::getId);
         // 1.3 瀹㈡埛淇℃伅
         Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
                 convertSet(pageResult.getList(), CrmSaleQuotationDO::getCustomerId));
@@ -222,8 +241,18 @@
         // 2. 寮�濮嬫嫾鎺�
         return BeanUtils.toBean(pageResult, CrmSaleQuotationRespVO.class, vo -> {
             vo.setItems(BeanUtils.toBean(productMap.get(vo.getId()), CrmSaleQuotationRespVO.Item.class,
-                    item -> MapUtils.findAndThen(itemMap, item.getItemId(), mdmItem -> item.setItemCode(mdmItem.getCode())
-                            .setItemName(mdmItem.getName()).setItemBarCode(mdmItem.getBarCode()))));
+                    item -> {
+                        MapUtils.findAndThen(itemMap, item.getItemId(), mdmItem -> item
+                                .setItemCode(mdmItem.getCode())
+                                .setItemName(mdmItem.getName())
+                                .setItemBarCode(mdmItem.getBarCode())
+                                .setItemSpecification(mdmItem.getSpecification())
+                                .setItemUnitId2(mdmItem.getUnitMeasureId2())
+                                .setItemUnitId3(mdmItem.getUnitMeasureId3()));
+                        MapUtils.findAndThen(unitMap, item.getItemUnitId(), unit -> item.setItemUnitName(unit.getName()));
+                        MapUtils.findAndThen(unitMap, item.getItemUnitId2(), unit -> item.setItemUnitName2(unit.getName()));
+                        MapUtils.findAndThen(unitMap, item.getItemUnitId3(), unit -> item.setItemUnitName3(unit.getName()));
+                    }));
             MapUtils.findAndThen(customerMap, vo.getCustomerId(), customer -> vo.setCustomerName(customer.getName()));
             MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
             MapUtils.findAndThen(deptMap, vo.getOwnerUserId(), dept -> vo.setOwnerUserDeptName(dept.getName()));
@@ -258,4 +287,4 @@
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/vo/CrmSaleQuotationRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/vo/CrmSaleQuotationRespVO.java
index ad95d47..1dc2e15 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/vo/CrmSaleQuotationRespVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/vo/CrmSaleQuotationRespVO.java
@@ -141,10 +141,20 @@
         private String itemName;
         @Schema(description = "鐗╂枡鏉$爜", example = "BAR001")
         private String itemBarCode;
+        @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
+        private String itemSpecification;
         @Schema(description = "璁¢噺鍗曚綅缂栧彿", example = "1")
         private Long itemUnitId;
         @Schema(description = "璁¢噺鍗曚綅鍚嶇О", example = "涓�")
         private String itemUnitName;
+        @Schema(description = "杈呭崟浣�1缂栧彿", example = "2")
+        private Long itemUnitId2;
+        @Schema(description = "杈呭崟浣�1鍚嶇О", example = "绠�")
+        private String itemUnitName2;
+        @Schema(description = "杈呭崟浣�2缂栧彿", example = "3")
+        private Long itemUnitId3;
+        @Schema(description = "杈呭崟浣�2鍚嶇О", example = "鎵�")
+        private String itemUnitName3;
 
         @Schema(description = "鐗╂枡鍘熶环", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
         private BigDecimal itemPrice;
@@ -169,4 +179,4 @@
 
     }
 
-}
\ No newline at end of file
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java
index 379bd62..110a803 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java
@@ -67,8 +67,10 @@
     @Override
     @CrmPermission(bizTypeValue = "#createReqVO.bizType", bizId = "#createReqVO.bizId", level = CrmPermissionLevelEnum.WRITE)
     public Long createFollowUpRecord(CrmFollowUpRecordSaveReqVO createReqVO) {
-        // 1. 鍒涘缓鏇磋繘璁板綍
+        // 1. 鍒涘缓璺熻繘璁板綍
         CrmFollowUpRecordDO record = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class);
+        // 鎵嬪姩澶勭悊 picUrls 瀛楁
+        record.setPicUrls(createReqVO.getPicUrlList());
         crmFollowUpRecordMapper.insert(record);
         storageAttachmentApi.bindAttachments("file", "crm_follow_up_record",
                 record.getId(), createReqVO.getBlobIds());
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
index b1db5b2..ae8c13c 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
@@ -101,6 +101,7 @@
         // 2.1 鎻掑叆璁㈠崟
         ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in
                 .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())
+                .setDepositPrice(ObjectUtil.defaultIfNull(createReqVO.getDepositPrice(), BigDecimal.ZERO))
                 .setOutCount(BigDecimal.ZERO).setOutStatus(ErpSaleOrderOutStatusEnum.NOT_OUT.getStatus()));
         calculateTotalPrice(saleOrder, saleOrderItems);
         saleOrderMapper.insert(saleOrder);
@@ -136,6 +137,7 @@
 
         // 2.1 鏇存柊璁㈠崟
         ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class);
+        updateObj.setDepositPrice(ObjectUtil.defaultIfNull(updateReqVO.getDepositPrice(), BigDecimal.ZERO));
         calculateTotalPrice(updateObj, saleOrderItems);
         saleOrderMapper.updateById(updateObj);
         // 2.2 鏇存柊璁㈠崟椤�
@@ -478,4 +480,4 @@
         }
     }
 
-}
\ No newline at end of file
+}

--
Gitblit v1.9.3