Commit 0a97ff03c6492e8b00528a8049c4f1cb953d817f

Authored by puhui999
2 parents c6b133d9 d604e76d

Merge remote-tracking branch 'yudao/develop' into develop

# Conflicts:
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
Showing 21 changed files with 318 additions and 437 deletions
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
@@ -95,7 +95,6 @@ public interface LogRecordConstants { @@ -95,7 +95,6 @@ public interface LogRecordConstants {
95 String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】"; 95 String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】";
96 String CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE = "更新商机状态"; 96 String CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE = "更新商机状态";
97 String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "更新了商机【{{#businessName}}】的状态从【{{#oldStatusName}}】变更为了【{{#newStatusName}}】"; 97 String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "更新了商机【{{#businessName}}】的状态从【{{#oldStatusName}}】变更为了【{{#newStatusName}}】";
98 -// String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "阿巴阿巴";  
99 98
100 // ======================= CRM_CONTRACT 合同 ======================= 99 // ======================= CRM_CONTRACT 合同 =======================
101 100
@@ -110,6 +109,8 @@ public interface LogRecordConstants { @@ -110,6 +109,8 @@ public interface LogRecordConstants {
110 String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; 109 String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
111 String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批"; 110 String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批";
112 String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功"; 111 String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功";
  112 + String CRM_CONTRACT_FOLLOW_UP_SUB_TYPE = "合同跟进";
  113 + String CRM_CONTRACT_FOLLOW_UP_SUCCESS = "合同跟进【{{#contractName}}】";
113 114
114 // ======================= CRM_PRODUCT 产品 ======================= 115 // ======================= CRM_PRODUCT 产品 =======================
115 116
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
@@ -135,7 +135,6 @@ public class CrmBusinessController { @@ -135,7 +135,6 @@ public class CrmBusinessController {
135 return success(BeanUtils.toBean(businessService.getBusinessList(ids, getLoginUserId()), CrmBusinessRespVO.class)); 135 return success(BeanUtils.toBean(businessService.getBusinessList(ids, getLoginUserId()), CrmBusinessRespVO.class));
136 } 136 }
137 137
138 - // TODO 芋艿:处理下  
139 @GetMapping("/simple-all-list") 138 @GetMapping("/simple-all-list")
140 @Operation(summary = "获得联系人的精简列表") 139 @Operation(summary = "获得联系人的精简列表")
141 @PreAuthorize("@ss.hasPermission('crm:contact:query')") 140 @PreAuthorize("@ss.hasPermission('crm:contact:query')")
@@ -144,7 +143,8 @@ public class CrmBusinessController { @@ -144,7 +143,8 @@ public class CrmBusinessController {
144 reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 143 reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页
145 PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); 144 PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(reqVO, getLoginUserId());
146 return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 145 return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段
147 - new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()))); 146 + new CrmBusinessRespVO().setId(business.getId()).setName(business.getName())
  147 + .setCustomerId(business.getCustomerId())));
148 } 148 }
149 149
150 @GetMapping("/page") 150 @GetMapping("/page")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
@@ -130,7 +130,7 @@ public class CrmBusinessRespVO { @@ -130,7 +130,7 @@ public class CrmBusinessRespVO {
130 @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") 130 @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
131 private BigDecimal productPrice; 131 private BigDecimal productPrice;
132 132
133 - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") 133 + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
134 private BigDecimal businessPrice; 134 private BigDecimal businessPrice;
135 135
136 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") 136 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
@@ -53,7 +53,7 @@ public class CrmBusinessSaveReqVO { @@ -53,7 +53,7 @@ public class CrmBusinessSaveReqVO {
53 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 53 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
54 private LocalDateTime dealTime; 54 private LocalDateTime dealTime;
55 55
56 - @Schema(description = "整单折扣") 56 + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00")
57 @DiffLogField(name = "整单折扣") 57 @DiffLogField(name = "整单折扣")
58 @NotNull(message = "整单折扣不能为空") 58 @NotNull(message = "整单折扣不能为空")
59 private BigDecimal discountPercent; 59 private BigDecimal discountPercent;
@@ -82,8 +82,8 @@ public class CrmBusinessSaveReqVO { @@ -82,8 +82,8 @@ public class CrmBusinessSaveReqVO {
82 @NotNull(message = "产品单价不能为空") 82 @NotNull(message = "产品单价不能为空")
83 private BigDecimal productPrice; 83 private BigDecimal productPrice;
84 84
85 - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")  
86 - @NotNull(message = "合同价格不能为空") 85 + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  86 + @NotNull(message = "商机价格不能为空")
87 private BigDecimal businessPrice; 87 private BigDecimal businessPrice;
88 88
89 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") 89 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
@@ -120,7 +120,8 @@ public class CrmContactController { @@ -120,7 +120,8 @@ public class CrmContactController {
120 public CommonResult<List<CrmContactRespVO>> getSimpleContactList() { 120 public CommonResult<List<CrmContactRespVO>> getSimpleContactList() {
121 List<CrmContactDO> list = contactService.getContactList(getLoginUserId()); 121 List<CrmContactDO> list = contactService.getContactList(getLoginUserId());
122 return success(convertList(list, contact -> // 只返回 id、name 字段 122 return success(convertList(list, contact -> // 只返回 id、name 字段
123 - new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()))); 123 + new CrmContactRespVO().setId(contact.getId()).setName(contact.getName())
  124 + .setCustomerId(contact.getCustomerId())));
124 } 125 }
125 126
126 @GetMapping("/page") 127 @GetMapping("/page")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 10 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
@@ -12,7 +13,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR @@ -12,7 +13,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR
12 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO; 13 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
13 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; 14 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
14 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; 15 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
15 -import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;  
16 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 16 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
17 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; 17 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
@@ -24,6 +24,8 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; @@ -24,6 +24,8 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
24 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; 24 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
25 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; 25 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
26 import cn.iocoder.yudao.module.crm.service.product.CrmProductService; 26 import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
  27 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  28 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
27 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 29 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
28 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 30 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
29 import io.swagger.v3.oas.annotations.Operation; 31 import io.swagger.v3.oas.annotations.Operation;
@@ -44,6 +46,7 @@ import java.util.stream.Stream; @@ -44,6 +46,7 @@ import java.util.stream.Stream;
44 46
45 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 47 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
46 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 48 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  49 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
47 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; 50 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
48 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 51 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
49 import static java.util.Collections.singletonList; 52 import static java.util.Collections.singletonList;
@@ -64,8 +67,11 @@ public class CrmContractController { @@ -64,8 +67,11 @@ public class CrmContractController {
64 private CrmBusinessService businessService; 67 private CrmBusinessService businessService;
65 @Resource 68 @Resource
66 private CrmProductService productService; 69 private CrmProductService productService;
  70 +
67 @Resource 71 @Resource
68 private AdminUserApi adminUserApi; 72 private AdminUserApi adminUserApi;
  73 + @Resource
  74 + private DeptApi deptApi;
69 75
70 @PostMapping("/create") 76 @PostMapping("/create")
71 @Operation(summary = "创建合同") 77 @Operation(summary = "创建合同")
@@ -96,15 +102,24 @@ public class CrmContractController { @@ -96,15 +102,24 @@ public class CrmContractController {
96 @Parameter(name = "id", description = "编号", required = true, example = "1024") 102 @Parameter(name = "id", description = "编号", required = true, example = "1024")
97 @PreAuthorize("@ss.hasPermission('crm:contract:query')") 103 @PreAuthorize("@ss.hasPermission('crm:contract:query')")
98 public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) { 104 public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) {
99 - // 1. 查询合同  
100 CrmContractDO contract = contractService.getContract(id); 105 CrmContractDO contract = contractService.getContract(id);
  106 + return success(buildContractDetail(contract));
  107 + }
  108 +
  109 + private CrmContractRespVO buildContractDetail(CrmContractDO contract) {
101 if (contract == null) { 110 if (contract == null) {
102 - return success(null); 111 + return null;
103 } 112 }
104 -  
105 - // 2. 拼接合同信息  
106 - List<CrmContractRespVO> respVOList = buildContractDetailList(singletonList(contract));  
107 - return success(respVOList.get(0)); 113 + CrmContractRespVO contractVO = buildContractDetailList(singletonList(contract)).get(0);
  114 + // 拼接产品项
  115 + List<CrmContractProductDO> businessProducts = contractService.getContractProductListByContractId(contractVO.getId());
  116 + Map<Long, CrmProductDO> productMap = productService.getProductMap(
  117 + convertSet(businessProducts, CrmContractProductDO::getProductId));
  118 + contractVO.setProducts(BeanUtils.toBean(businessProducts, CrmContractRespVO.Product.class, businessProductVO ->
  119 + MapUtils.findAndThen(productMap, businessProductVO.getProductId(),
  120 + product -> businessProductVO.setProductName(product.getName())
  121 + .setProductNo(product.getNo()).setProductUnit(product.getUnit()))));
  122 + return contractVO;
108 } 123 }
109 124
110 @GetMapping("/page") 125 @GetMapping("/page")
@@ -161,27 +176,35 @@ public class CrmContractController { @@ -161,27 +176,35 @@ public class CrmContractController {
161 if (CollUtil.isEmpty(contractList)) { 176 if (CollUtil.isEmpty(contractList)) {
162 return Collections.emptyList(); 177 return Collections.emptyList();
163 } 178 }
164 - // 1. 获取客户列表  
165 - List<CrmCustomerDO> customerList = customerService.getCustomerList( 179 + // 1.1 获取客户列表
  180 + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
166 convertSet(contractList, CrmContractDO::getCustomerId)); 181 convertSet(contractList, CrmContractDO::getCustomerId));
167 - // 2. 获取创建人、负责人列表 182 + // 1.2 获取创建人、负责人列表
168 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList, 183 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList,
169 contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); 184 contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
170 - // 3. 获取联系人 185 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  186 + // 1.3 获取联系人
171 Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactList(convertSet(contractList, 187 Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactList(convertSet(contractList,
172 - CrmContractDO::getContactId)), CrmContactDO::getId);  
173 - // 4. 获取商机 188 + CrmContractDO::getSignContactId)), CrmContactDO::getId);
  189 + // 1.4 获取商机
174 Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList, 190 Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList,
175 CrmContractDO::getBusinessId)), CrmBusinessDO::getId); 191 CrmContractDO::getBusinessId)), CrmBusinessDO::getId);
176 - // 5. 获取合同关联的商品  
177 - Map<Long, CrmContractProductDO> contractProductMap = null;  
178 - List<CrmProductDO> productList = null;  
179 - if (contractList.size() == 1) {  
180 - List<CrmContractProductDO> contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId());  
181 - contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId);  
182 - productList = productService.getProductList(convertSet(contractProductList, CrmContractProductDO::getProductId));  
183 - }  
184 - return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap, contractProductMap, productList); 192 + // 2. 拼接数据
  193 + return BeanUtils.toBean(contractList, CrmContractRespVO.class, contractVO -> {
  194 + // 2.1 设置客户信息
  195 + findAndThen(customerMap, contractVO.getCustomerId(), customer -> contractVO.setCustomerName(customer.getName()));
  196 + // 2.2 设置用户信息
  197 + findAndThen(userMap, Long.parseLong(contractVO.getCreator()), user -> contractVO.setCreatorName(user.getNickname()));
  198 + MapUtils.findAndThen(userMap, contractVO.getOwnerUserId(), user -> {
  199 + contractVO.setOwnerUserName(user.getNickname());
  200 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contractVO.setOwnerUserDeptName(dept.getName()));
  201 + });
  202 + findAndThen(userMap, contractVO.getSignUserId(), user -> contractVO.setSignUserName(user.getNickname()));
  203 + // 2.3 设置联系人信息
  204 + findAndThen(contactMap, contractVO.getSignContactId(), contact -> contractVO.setSignContactName(contact.getName()));
  205 + // 2.4 设置商机信息
  206 + findAndThen(businessMap, contractVO.getBusinessId(), business -> contractVO.setBusinessName(business.getName()));
  207 + });
185 } 208 }
186 209
187 @GetMapping("/check-contract-count") 210 @GetMapping("/check-contract-count")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractRespVO.java
@@ -6,13 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema; @@ -6,13 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
6 import lombok.AllArgsConstructor; 6 import lombok.AllArgsConstructor;
7 import lombok.Data; 7 import lombok.Data;
8 import lombok.NoArgsConstructor; 8 import lombok.NoArgsConstructor;
9 -import org.springframework.format.annotation.DateTimeFormat;  
10 9
  10 +import java.math.BigDecimal;
11 import java.time.LocalDateTime; 11 import java.time.LocalDateTime;
12 import java.util.List; 12 import java.util.List;
13 13
14 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;  
15 -  
16 @Schema(description = "管理后台 - CRM 合同 Response VO") 14 @Schema(description = "管理后台 - CRM 合同 Response VO")
17 @Data 15 @Data
18 @ExcelIgnoreUnannotated 16 @ExcelIgnoreUnannotated
@@ -26,6 +24,10 @@ public class CrmContractRespVO { @@ -26,6 +24,10 @@ public class CrmContractRespVO {
26 @ExcelProperty("合同名称") 24 @ExcelProperty("合同名称")
27 private String name; 25 private String name;
28 26
  27 + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")
  28 + @ExcelProperty("合同编号")
  29 + private String no;
  30 +
29 @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") 31 @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
30 @ExcelProperty("客户编号") 32 @ExcelProperty("客户编号")
31 private Long customerId; 33 private Long customerId;
@@ -40,72 +42,70 @@ public class CrmContractRespVO { @@ -40,72 +42,70 @@ public class CrmContractRespVO {
40 @ExcelProperty("商机名称") 42 @ExcelProperty("商机名称")
41 private String businessName; 43 private String businessName;
42 44
  45 + @Schema(description = "最后跟进时间")
  46 + @ExcelProperty("最后跟进时间")
  47 + private LocalDateTime contactLastTime;
  48 +
  49 + @Schema(description = "负责人的用户编号", example = "25682")
  50 + @ExcelProperty("负责人的用户编号")
  51 + private Long ownerUserId;
  52 + @Schema(description = "负责人名字", example = "25682")
  53 + @ExcelProperty("负责人名字")
  54 + private String ownerUserName;
  55 + @Schema(description = "负责人部门")
  56 + @ExcelProperty("负责人部门")
  57 + private String ownerUserDeptName;
  58 +
43 @Schema(description = "工作流编号", example = "1043") 59 @Schema(description = "工作流编号", example = "1043")
44 @ExcelProperty("工作流编号") 60 @ExcelProperty("工作流编号")
45 private Long processInstanceId; 61 private Long processInstanceId;
46 62
  63 + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  64 + @ExcelProperty("审批状态")
  65 + private Integer auditStatus;
  66 +
47 @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) 67 @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
48 @ExcelProperty("下单日期") 68 @ExcelProperty("下单日期")
49 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
50 private LocalDateTime orderDate; 69 private LocalDateTime orderDate;
51 70
52 - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144")  
53 - @ExcelProperty("负责人的用户编号")  
54 - private Long ownerUserId;  
55 -  
56 - // TODO @芋艿:未来应该支持自动生成;  
57 - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")  
58 - @ExcelProperty("合同编号")  
59 - private String no;  
60 -  
61 @Schema(description = "开始时间") 71 @Schema(description = "开始时间")
62 @ExcelProperty("开始时间") 72 @ExcelProperty("开始时间")
63 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
64 private LocalDateTime startTime; 73 private LocalDateTime startTime;
65 74
66 @Schema(description = "结束时间") 75 @Schema(description = "结束时间")
67 @ExcelProperty("结束时间") 76 @ExcelProperty("结束时间")
68 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
69 private LocalDateTime endTime; 77 private LocalDateTime endTime;
70 78
71 - @Schema(description = "合同金额", example = "5617")  
72 - @ExcelProperty("合同金额")  
73 - private Integer price; 79 + @Schema(description = "产品总金额", example = "19510")
  80 + @ExcelProperty("产品总金额")
  81 + private BigDecimal totalProductPrice;
74 82
75 @Schema(description = "整单折扣") 83 @Schema(description = "整单折扣")
76 @ExcelProperty("整单折扣") 84 @ExcelProperty("整单折扣")
77 - private Integer discountPercent; 85 + private BigDecimal discountPercent;
78 86
79 - @Schema(description = "产品总金额", example = "19510")  
80 - @ExcelProperty("产品总金额")  
81 - private Integer productPrice; 87 + @Schema(description = "合同金额", example = "5617")
  88 + @ExcelProperty("合同金额")
  89 + private BigDecimal totalPrice;
82 90
83 - @Schema(description = "联系人编号", example = "18546")  
84 - @ExcelProperty("联系人编号")  
85 - private Long contactId;  
86 - @Schema(description = "联系人编号", example = "18546")  
87 - @ExcelProperty("联系人编号")  
88 - private String contactName; 91 + @Schema(description = "客户签约人编号", example = "18546")
  92 + private Long signContactId;
  93 + @Schema(description = "客户签约人", example = "小豆")
  94 + @ExcelProperty("客户签约人")
  95 + private String signContactName;
89 96
90 @Schema(description = "公司签约人", example = "14036") 97 @Schema(description = "公司签约人", example = "14036")
91 - @ExcelProperty("公司签约人")  
92 private Long signUserId; 98 private Long signUserId;
93 - @Schema(description = "公司签约人", example = "14036") 99 + @Schema(description = "公司签约人", example = "小明")
94 @ExcelProperty("公司签约人") 100 @ExcelProperty("公司签约人")
95 private String signUserName; 101 private String signUserName;
96 102
97 - @Schema(description = "最后跟进时间")  
98 - @ExcelProperty("最后跟进时间")  
99 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
100 - private LocalDateTime contactLastTime;  
101 -  
102 @Schema(description = "备注", example = "你猜") 103 @Schema(description = "备注", example = "你猜")
103 @ExcelProperty("备注") 104 @ExcelProperty("备注")
104 private String remark; 105 private String remark;
105 106
106 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 107 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
107 @ExcelProperty("创建时间") 108 @ExcelProperty("创建时间")
108 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
109 private LocalDateTime createTime; 109 private LocalDateTime createTime;
110 110
111 @Schema(description = "创建人", example = "25682") 111 @Schema(description = "创建人", example = "25682")
@@ -118,46 +118,40 @@ public class CrmContractRespVO { @@ -118,46 +118,40 @@ public class CrmContractRespVO {
118 118
119 @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) 119 @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
120 @ExcelProperty("更新时间") 120 @ExcelProperty("更新时间")
121 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
122 private LocalDateTime updateTime; 121 private LocalDateTime updateTime;
123 122
124 - @Schema(description = "负责人", example = "test")  
125 - @ExcelProperty("负责人")  
126 - private String ownerUserName;  
127 -  
128 - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")  
129 - @ExcelProperty("审批状态")  
130 - private Integer auditStatus;  
131 -  
132 @Schema(description = "产品列表") 123 @Schema(description = "产品列表")
133 - private List<Item> items; 124 + private List<Product> products;
134 125
135 @Schema(description = "产品列表") 126 @Schema(description = "产品列表")
136 @Data 127 @Data
137 @NoArgsConstructor 128 @NoArgsConstructor
138 @AllArgsConstructor 129 @AllArgsConstructor
139 - public static class Item { 130 + public static class Product {
140 131
141 - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") 132 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
142 private Long id; 133 private Long id;
143 134
144 - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是产品")  
145 - private String name;  
146 -  
147 - @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "N881")  
148 - private String no; 135 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
  136 + private Long productId;
  137 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  138 + private String productName;
  139 + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
  140 + private String productNo;
  141 + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  142 + private Integer productUnit;
149 143
150 - @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")  
151 - private Integer unit; 144 + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  145 + private BigDecimal productPrice;
152 146
153 - @Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")  
154 - private Integer price; 147 + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  148 + private BigDecimal contractPrice;
155 149
156 - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")  
157 - private Integer count; 150 + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
  151 + private BigDecimal count;
158 152
159 - @Schema(description = "产品折扣", example = "99")  
160 - private Integer discountPercent; 153 + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  154 + private BigDecimal totalPrice;
161 155
162 } 156 }
163 157
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java
@@ -12,6 +12,7 @@ import lombok.Data; @@ -12,6 +12,7 @@ import lombok.Data;
12 import lombok.NoArgsConstructor; 12 import lombok.NoArgsConstructor;
13 import org.springframework.format.annotation.DateTimeFormat; 13 import org.springframework.format.annotation.DateTimeFormat;
14 14
  15 +import java.math.BigDecimal;
15 import java.time.LocalDateTime; 16 import java.time.LocalDateTime;
16 import java.util.List; 17 import java.util.List;
17 18
@@ -38,22 +39,16 @@ public class CrmContractSaveReqVO { @@ -38,22 +39,16 @@ public class CrmContractSaveReqVO {
38 @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME) 39 @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME)
39 private Long businessId; 40 private Long businessId;
40 41
41 - @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)  
42 - @DiffLogField(name = "下单日期")  
43 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
44 - @NotNull(message = "下单日期不能为空")  
45 - private LocalDateTime orderDate;  
46 -  
47 @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") 42 @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144")
48 @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) 43 @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME)
49 @NotNull(message = "负责人不能为空") 44 @NotNull(message = "负责人不能为空")
50 private Long ownerUserId; 45 private Long ownerUserId;
51 46
52 - // TODO @芋艿:未来应该支持自动生成;  
53 - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")  
54 - @DiffLogField(name = "合同编号")  
55 - @NotNull(message = "合同编号不能为空")  
56 - private String no; 47 + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
  48 + @DiffLogField(name = "下单日期")
  49 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  50 + @NotNull(message = "下单日期不能为空")
  51 + private LocalDateTime orderDate;
57 52
58 @Schema(description = "开始时间") 53 @Schema(description = "开始时间")
59 @DiffLogField(name = "开始时间") 54 @DiffLogField(name = "开始时间")
@@ -65,21 +60,18 @@ public class CrmContractSaveReqVO { @@ -65,21 +60,18 @@ public class CrmContractSaveReqVO {
65 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 60 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
66 private LocalDateTime endTime; 61 private LocalDateTime endTime;
67 62
68 - @Schema(description = "合同金额", example = "5617")  
69 - @DiffLogField(name = "合同金额")  
70 - private Integer price;  
71 -  
72 - @Schema(description = "整单折扣") 63 + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00")
73 @DiffLogField(name = "整单折扣") 64 @DiffLogField(name = "整单折扣")
74 - private Integer discountPercent; 65 + @NotNull(message = "整单折扣不能为空")
  66 + private BigDecimal discountPercent;
75 67
76 - @Schema(description = "产品总金额", example = "19510")  
77 - @DiffLogField(name = "产品总金额")  
78 - private Integer productPrice; 68 + @Schema(description = "合同金额", example = "5617")
  69 + @DiffLogField(name = "合同金额")
  70 + private BigDecimal totalPrice;
79 71
80 - @Schema(description = "联系人编号", example = "18546")  
81 - @DiffLogField(name = "联系人", function = CrmContactParseFunction.NAME)  
82 - private Long contactId; 72 + @Schema(description = "客户签约人编号", example = "18546")
  73 + @DiffLogField(name = "客户签约人", function = CrmContactParseFunction.NAME)
  74 + private Long signContactId;
83 75
84 @Schema(description = "公司签约人", example = "14036") 76 @Schema(description = "公司签约人", example = "14036")
85 @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME) 77 @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME)
@@ -89,27 +81,31 @@ public class CrmContractSaveReqVO { @@ -89,27 +81,31 @@ public class CrmContractSaveReqVO {
89 @DiffLogField(name = "备注") 81 @DiffLogField(name = "备注")
90 private String remark; 82 private String remark;
91 83
92 -  
93 @Schema(description = "产品列表") 84 @Schema(description = "产品列表")
94 - private List<CrmContractProductItem> productItems; 85 + private List<Product> products;
95 86
96 @Schema(description = "产品列表") 87 @Schema(description = "产品列表")
97 @Data 88 @Data
98 @NoArgsConstructor 89 @NoArgsConstructor
99 @AllArgsConstructor 90 @AllArgsConstructor
100 - public static class CrmContractProductItem { 91 + public static class Product {
101 92
102 - @Schema(description = "产品编号", example = "20529") 93 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
103 @NotNull(message = "产品编号不能为空") 94 @NotNull(message = "产品编号不能为空")
104 - private Long id; 95 + private Long productId;
  96 +
  97 + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  98 + @NotNull(message = "产品单价不能为空")
  99 + private BigDecimal productPrice;
  100 +
  101 + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  102 + @NotNull(message = "合同价格不能为空")
  103 + private BigDecimal contractPrice;
105 104
106 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") 105 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
107 @NotNull(message = "产品数量不能为空") 106 @NotNull(message = "产品数量不能为空")
108 private Integer count; 107 private Integer count;
109 108
110 - @Schema(description = "产品折扣")  
111 - private Integer discountPercent;  
112 -  
113 } 109 }
114 110
115 } 111 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java deleted
1 -package cn.iocoder.yudao.module.crm.convert.contract;  
2 -  
3 -import cn.hutool.core.collection.CollUtil;  
4 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
5 -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;  
6 -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;  
7 -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;  
8 -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;  
9 -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;  
10 -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;  
11 -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;  
12 -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;  
13 -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;  
14 -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;  
15 -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;  
16 -import org.mapstruct.Mapper;  
17 -import org.mapstruct.Mapping;  
18 -import org.mapstruct.factory.Mappers;  
19 -  
20 -import java.util.List;  
21 -import java.util.Map;  
22 -  
23 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;  
24 -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;  
25 -  
26 -/**  
27 - * 合同 Convert  
28 - *  
29 - * @author dhb52  
30 - */  
31 -@Mapper  
32 -public interface CrmContractConvert {  
33 -  
34 - CrmContractConvert INSTANCE = Mappers.getMapper(CrmContractConvert.class);  
35 -  
36 - @Mapping(target = "bizId", source = "reqVO.id")  
37 - CrmPermissionTransferReqBO convert(CrmContractTransferReqVO reqVO, Long userId);  
38 -  
39 - default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,  
40 - List<CrmCustomerDO> customerList, Map<Long, CrmContactDO> contactMap,  
41 - Map<Long, CrmBusinessDO> businessMap, Map<Long, CrmContractProductDO> contractProductMap,  
42 - List<CrmProductDO> productList) {  
43 - List<CrmContractRespVO> respVOList = BeanUtils.toBean(contractList, CrmContractRespVO.class);  
44 - // 拼接关联字段  
45 - Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);  
46 - respVOList.forEach(contract -> {  
47 - findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname()));  
48 - findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname()));  
49 - findAndThen(userMap, contract.getSignUserId(), user -> contract.setSignUserName(user.getNickname()));  
50 - findAndThen(customerMap, contract.getCustomerId(), customer -> contract.setCustomerName(customer.getName()));  
51 - findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.getName()));  
52 - findAndThen(businessMap, contract.getBusinessId(), business -> contract.setBusinessName(business.getName()));  
53 - });  
54 - if (CollUtil.isNotEmpty(respVOList) && respVOList.size() == 1) {  
55 - setContractRespVOProductItems(respVOList.get(0), contractProductMap, productList);  
56 - }  
57 - return respVOList;  
58 - }  
59 -  
60 - default void setContractRespVOProductItems(CrmContractRespVO respVO, Map<Long, CrmContractProductDO> contractProductMap,  
61 - List<CrmProductDO> productList) {  
62 - respVO.setItems(CollectionUtils.convertList(productList, product -> {  
63 - CrmContractRespVO.Item productItemRespVO = BeanUtils.toBean(product, CrmContractRespVO.Item.class);  
64 - findAndThen(contractProductMap, product.getId(), contractProduct ->  
65 - productItemRespVO.setCount(contractProduct.getCount()).setDiscountPercent(contractProduct.getDiscountPercent()));  
66 - return productItemRespVO;  
67 - }));  
68 - }  
69 -  
70 -}  
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java
@@ -50,7 +50,7 @@ public class CrmBusinessProductDO extends BaseDO { @@ -50,7 +50,7 @@ public class CrmBusinessProductDO extends BaseDO {
50 */ 50 */
51 private BigDecimal productPrice; 51 private BigDecimal productPrice;
52 /** 52 /**
53 - * 合同价格, 单位:元 53 + * 商机价格, 单位:元
54 */ 54 */
55 private BigDecimal businessPrice; 55 private BigDecimal businessPrice;
56 /** 56 /**
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java
@@ -10,9 +10,9 @@ import com.baomidou.mybatisplus.annotation.TableId; @@ -10,9 +10,9 @@ import com.baomidou.mybatisplus.annotation.TableId;
10 import com.baomidou.mybatisplus.annotation.TableName; 10 import com.baomidou.mybatisplus.annotation.TableName;
11 import lombok.*; 11 import lombok.*;
12 12
  13 +import java.math.BigDecimal;
13 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
14 15
15 -// TODO 芋艿:实体的梳理  
16 /** 16 /**
17 * CRM 合同 DO 17 * CRM 合同 DO
18 * 18 *
@@ -34,25 +34,38 @@ public class CrmContractDO extends BaseDO { @@ -34,25 +34,38 @@ public class CrmContractDO extends BaseDO {
34 @TableId 34 @TableId
35 private Long id; 35 private Long id;
36 /** 36 /**
37 - * 合同编号  
38 - */  
39 - private String no;  
40 - /**  
41 * 合同名称 37 * 合同名称
42 */ 38 */
43 private String name; 39 private String name;
44 /** 40 /**
  41 + * 合同编号
  42 + */
  43 + private String no;
  44 + /**
45 * 客户编号 45 * 客户编号
46 * 46 *
47 * 关联 {@link CrmCustomerDO#getId()} 47 * 关联 {@link CrmCustomerDO#getId()}
48 */ 48 */
49 private Long customerId; 49 private Long customerId;
50 /** 50 /**
51 - * 商机编号 51 + * 商机编号,非必须
52 * 52 *
53 * 关联 {@link CrmBusinessDO#getId()} 53 * 关联 {@link CrmBusinessDO#getId()}
54 */ 54 */
55 private Long businessId; 55 private Long businessId;
  56 +
  57 + /**
  58 + * 最后跟进时间
  59 + */
  60 + private LocalDateTime contactLastTime;
  61 +
  62 + /**
  63 + * 负责人的用户编号
  64 + *
  65 + * 关联 AdminUserDO 的 id 字段
  66 + */
  67 + private Long ownerUserId;
  68 +
56 /** 69 /**
57 * 工作流编号 70 * 工作流编号
58 * 71 *
@@ -60,6 +73,13 @@ public class CrmContractDO extends BaseDO { @@ -60,6 +73,13 @@ public class CrmContractDO extends BaseDO {
60 */ 73 */
61 private String processInstanceId; 74 private String processInstanceId;
62 /** 75 /**
  76 + * 审批状态
  77 + *
  78 + * 枚举 {@link CrmAuditStatusEnum}
  79 + */
  80 + private Integer auditStatus;
  81 +
  82 + /**
63 * 下单日期 83 * 下单日期
64 */ 84 */
65 private LocalDateTime orderDate; 85 private LocalDateTime orderDate;
@@ -72,50 +92,32 @@ public class CrmContractDO extends BaseDO { @@ -72,50 +92,32 @@ public class CrmContractDO extends BaseDO {
72 */ 92 */
73 private LocalDateTime endTime; 93 private LocalDateTime endTime;
74 /** 94 /**
75 - * 合同金额,单位:分 95 + * 产品总金额,单位:元
76 */ 96 */
77 - private Integer price; 97 + private BigDecimal totalProductPrice;
78 /** 98 /**
79 * 整单折扣 99 * 整单折扣
80 */ 100 */
81 - private Integer discountPercent; 101 + private BigDecimal discountPercent;
82 /** 102 /**
83 - * 产品总金额,单位:分 103 + * 合同总金额,单位:分
84 */ 104 */
85 - private Integer productPrice; 105 + private BigDecimal totalPrice;
86 /** 106 /**
87 - * 客户签约人 107 + * 客户签约人,非必须
88 * 108 *
89 * 关联 {@link CrmContactDO#getId()} 109 * 关联 {@link CrmContactDO#getId()}
90 */ 110 */
91 - private Long contactId; 111 + private Long signContactId;
92 /** 112 /**
93 - * 公司签约人 113 + * 公司签约人,非必须
94 * 114 *
95 * 关联 AdminUserDO 的 id 字段 115 * 关联 AdminUserDO 的 id 字段
96 */ 116 */
97 private Long signUserId; 117 private Long signUserId;
98 /** 118 /**
99 - * 最后跟进时间  
100 - */  
101 - private LocalDateTime contactLastTime;  
102 - /**  
103 * 备注 119 * 备注
104 */ 120 */
105 private String remark; 121 private String remark;
106 122
107 - /**  
108 - * 负责人的用户编号  
109 - *  
110 - * 关联 AdminUserDO 的 id 字段  
111 - */  
112 - private Long ownerUserId;  
113 -  
114 - /**  
115 - * 审批状态  
116 - *  
117 - * 枚举 {@link CrmAuditStatusEnum}  
118 - */  
119 - private Integer auditStatus;  
120 -  
121 } 123 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java
@@ -7,8 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableId; @@ -7,8 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
8 import lombok.*; 8 import lombok.*;
9 9
  10 +import java.math.BigDecimal;
  11 +
10 /** 12 /**
11 - * 合同产品关联表 DO 13 + * CRM 合同产品关联表 DO
12 * 14 *
13 * @author HUIHUI 15 * @author HUIHUI
14 */ 16 */
@@ -28,39 +30,34 @@ public class CrmContractProductDO extends BaseDO { @@ -28,39 +30,34 @@ public class CrmContractProductDO extends BaseDO {
28 @TableId 30 @TableId
29 private Long id; 31 private Long id;
30 /** 32 /**
31 - * 产品编号  
32 - *  
33 - * 关联 {@link CrmProductDO#getId()}  
34 - */  
35 - private Long productId;  
36 - /**  
37 * 合同编号 33 * 合同编号
38 * 34 *
39 * 关联 {@link CrmContractDO#getId()} 35 * 关联 {@link CrmContractDO#getId()}
40 */ 36 */
41 private Long contractId; 37 private Long contractId;
42 /** 38 /**
43 - * 产品单价 39 + * 产品编号
  40 + *
  41 + * 关联 {@link CrmProductDO#getId()}
44 */ 42 */
45 - private Integer price; 43 + private Long productId;
46 /** 44 /**
47 - * 销售价格, 单位:分 45 + * 产品单价,单位:元
48 */ 46 */
49 - private Integer salesPrice; 47 + private BigDecimal productPrice;
50 /** 48 /**
51 - * 数量 49 + * 合同价格, 单位:分
52 */ 50 */
53 - private Integer count; 51 + private BigDecimal contractPrice;
54 /** 52 /**
55 - * 折扣 53 + * 数量
56 */ 54 */
57 - private Integer discountPercent; 55 + private BigDecimal count;
58 /** 56 /**
59 - * 总计价格(折扣后价格)  
60 - * = {@link #price}  
61 - * * {@link #count}  
62 - * * ({@link #discountPercent / 100}) 57 + * 总计价格,单位:元
  58 + *
  59 + * totalPrice = businessPrice * count
63 */ 60 */
64 - private Integer totalPrice; 61 + private BigDecimal totalPrice;
65 62
66 } 63 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
@@ -81,7 +81,7 @@ public interface CrmContractMapper extends BaseMapperX&lt;CrmContractDO&gt; { @@ -81,7 +81,7 @@ public interface CrmContractMapper extends BaseMapperX&lt;CrmContractDO&gt; {
81 } 81 }
82 82
83 default Long selectCountByContactId(Long contactId) { 83 default Long selectCountByContactId(Long contactId) {
84 - return selectCount(CrmContractDO::getContactId, contactId); 84 + return selectCount(CrmContractDO::getSignContactId, contactId);
85 } 85 }
86 86
87 default Long selectCountByBusinessId(Long businessId) { 87 default Long selectCountByBusinessId(Long businessId) {
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
@@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
11 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; 11 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
12 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; 12 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
13 import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; 13 import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum;
14 -import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;  
15 import jakarta.validation.Valid; 14 import jakarta.validation.Valid;
16 15
17 import java.time.LocalDateTime; 16 import java.time.LocalDateTime;
@@ -81,19 +80,20 @@ public interface CrmBusinessService { @@ -81,19 +80,20 @@ public interface CrmBusinessService {
81 void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId); 80 void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId);
82 81
83 /** 82 /**
84 - * 更新商机关联商品 83 + * 获得商机
85 * 84 *
86 - * @param updateProductReqBO 请求 85 + * @param id 编号
  86 + * @return 商机
87 */ 87 */
88 - void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO); 88 + CrmBusinessDO getBusiness(Long id);
89 89
90 /** 90 /**
91 - * 获得商机 91 + * 校验商机是否有效
92 * 92 *
93 * @param id 编号 93 * @param id 编号
94 * @return 商机 94 * @return 商机
95 */ 95 */
96 - CrmBusinessDO getBusiness(Long id); 96 + CrmBusinessDO validateBusiness(Long id);
97 97
98 /** 98 /**
99 * 获得商机列表 99 * 获得商机列表
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper; @@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper;
19 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 19 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
20 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 20 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
21 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; 21 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
22 -import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;  
23 import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; 22 import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
24 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; 23 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
25 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; 24 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
@@ -91,10 +90,10 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -91,10 +90,10 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
91 // 1.1 校验产品项的有效性 90 // 1.1 校验产品项的有效性
92 List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(createReqVO.getProducts()); 91 List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(createReqVO.getProducts());
93 // 1.2 校验关联字段 92 // 1.2 校验关联字段
94 - validateBusinessForCreate(createReqVO); 93 + validateRelationDataExists(createReqVO);
95 94
96 // 2.1 插入商机 95 // 2.1 插入商机
97 - CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class).setOwnerUserId(userId); 96 + CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class);
98 business.setStatusId(businessStatusService.getBusinessStatusListByTypeId(createReqVO.getStatusTypeId()).get(0).getId()); // 默认状态 97 business.setStatusId(businessStatusService.getBusinessStatusListByTypeId(createReqVO.getStatusTypeId()).get(0).getId()); // 默认状态
99 calculateTotalPrice(business, businessProducts); 98 calculateTotalPrice(business, businessProducts);
100 businessMapper.insert(business); 99 businessMapper.insert(business);
@@ -105,9 +104,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -105,9 +104,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
105 } 104 }
106 105
107 // 3. 创建数据权限 106 // 3. 创建数据权限
108 - // 设置当前操作的人为负责人  
109 - permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())  
110 - .setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); 107 + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(business.getOwnerUserId())
  108 + .setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()).setBizId(business.getId())
  109 + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
111 110
112 // 4. 在联系人的详情页,如果直接【新建商机】,则需要关联下 111 // 4. 在联系人的详情页,如果直接【新建商机】,则需要关联下
113 if (createReqVO.getContactId() != null) { 112 if (createReqVO.getContactId() != null) {
@@ -132,7 +131,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -132,7 +131,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
132 // 1.2 校验产品项的有效性 131 // 1.2 校验产品项的有效性
133 List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts()); 132 List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts());
134 // 1.3 校验关联字段 133 // 1.3 校验关联字段
135 - validateBusinessForCreate(updateReqVO); 134 + validateRelationDataExists(updateReqVO);
136 135
137 // 2.1 更新商机 136 // 2.1 更新商机
138 CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class); 137 CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class);
@@ -141,7 +140,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -141,7 +140,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
141 // 2.2 更新商机关联商品 140 // 2.2 更新商机关联商品
142 updateBusinessProduct(updateObj.getId(), businessProducts); 141 updateBusinessProduct(updateObj.getId(), businessProducts);
143 142
144 - // TODO @商机待定:如果状态发生变化,插入商机状态变更记录表  
145 // 3. 记录操作日志上下文 143 // 3. 记录操作日志上下文
146 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class)); 144 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class));
147 LogRecordContext.putVariable("businessName", oldBusiness.getName()); 145 LogRecordContext.putVariable("businessName", oldBusiness.getName());
@@ -185,7 +183,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -185,7 +183,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
185 } 183 }
186 } 184 }
187 185
188 - private void validateBusinessForCreate(CrmBusinessSaveReqVO saveReqVO) { 186 + private void validateRelationDataExists(CrmBusinessSaveReqVO saveReqVO) {
189 // 校验商机状态 187 // 校验商机状态
190 if (saveReqVO.getStatusTypeId() != null) { 188 if (saveReqVO.getStatusTypeId() != null) {
191 businessStatusService.validateBusinessStatusType(saveReqVO.getStatusTypeId()); 189 businessStatusService.validateBusinessStatusType(saveReqVO.getStatusTypeId());
@@ -208,9 +206,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -208,9 +206,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
208 // 1. 校验产品存在 206 // 1. 校验产品存在
209 productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); 207 productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId));
210 // 2. 转化为 CrmBusinessProductDO 列表 208 // 2. 转化为 CrmBusinessProductDO 列表
211 - return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> {  
212 - item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount()));  
213 - })); 209 + return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class,
  210 + item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount()))));
214 } 211 }
215 212
216 private void calculateTotalPrice(CrmBusinessDO business, List<CrmBusinessProductDO> businessProducts) { 213 private void calculateTotalPrice(CrmBusinessDO business, List<CrmBusinessProductDO> businessProducts) {
@@ -219,7 +216,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -219,7 +216,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
219 business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); 216 business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice));
220 } 217 }
221 218
222 -  
223 @Override 219 @Override
224 @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE, bizNo = "{{#reqVO.id}}", 220 @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE, bizNo = "{{#reqVO.id}}",
225 success = CRM_BUSINESS_UPDATE_STATUS_SUCCESS) 221 success = CRM_BUSINESS_UPDATE_STATUS_SUCCESS)
@@ -264,7 +260,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -264,7 +260,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
264 // 1.2 校验是否关联合同 260 // 1.2 校验是否关联合同
265 validateContractExists(id); 261 validateContractExists(id);
266 262
267 - // 删除 263 + // 删除商机
268 businessMapper.deleteById(id); 264 businessMapper.deleteById(id);
269 // 删除数据权限 265 // 删除数据权限
270 permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id); 266 permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id);
@@ -313,14 +309,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -313,14 +309,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
313 LogRecordContext.putVariable("business", business); 309 LogRecordContext.putVariable("business", business);
314 } 310 }
315 311
316 - @Override  
317 - public void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO) {  
318 - // 更新商机关联商品 TODO yunai  
319 -// List<CrmBusinessProductDO> productList = buildBusinessProductList(  
320 -// BeanUtils.toBean(updateProductReqBO.getProductItems(), CrmBusinessSaveReqVO.Product.class), updateProductReqBO.getId());  
321 -// updateBusinessProduct(productList, updateProductReqBO.getId());  
322 - }  
323 -  
324 //======================= 查询相关 ======================= 312 //======================= 查询相关 =======================
325 313
326 @Override 314 @Override
@@ -330,6 +318,11 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -330,6 +318,11 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
330 } 318 }
331 319
332 @Override 320 @Override
  321 + public CrmBusinessDO validateBusiness(Long id) {
  322 + return validateBusinessExists(id);
  323 + }
  324 +
  325 + @Override
333 public List<CrmBusinessDO> getBusinessList(Collection<Long> ids, Long userId) { 326 public List<CrmBusinessDO> getBusinessList(Collection<Long> ids, Long userId) {
334 if (CollUtil.isEmpty(ids)) { 327 if (CollUtil.isEmpty(ids)) {
335 return ListUtil.empty(); 328 return ListUtil.empty();
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/bo/CrmBusinessUpdateProductReqBO.java deleted
1 -package cn.iocoder.yudao.module.crm.service.business.bo;  
2 -  
3 -import io.swagger.v3.oas.annotations.media.Schema;  
4 -import jakarta.validation.constraints.NotEmpty;  
5 -import jakarta.validation.constraints.NotNull;  
6 -import lombok.AllArgsConstructor;  
7 -import lombok.Data;  
8 -import lombok.NoArgsConstructor;  
9 -  
10 -import java.util.List;  
11 -  
12 -/**  
13 - * 更新商机商品 Update Req BO  
14 - *  
15 - * @author HUIHUI  
16 - */  
17 -@Data  
18 -public class CrmBusinessUpdateProductReqBO {  
19 -  
20 - /**  
21 - * 商机编号  
22 - */  
23 - @NotNull(message = "商机编号不能为空")  
24 - private Long id;  
25 -  
26 - // TODO @芋艿:再想想  
27 - @NotEmpty(message = "产品列表不能为空")  
28 - private List<Item> items;  
29 -  
30 - @Schema(description = "产品列表")  
31 - @Data  
32 - @NoArgsConstructor  
33 - @AllArgsConstructor  
34 - public static class Item {  
35 -  
36 - @Schema(description = "产品编号", example = "20529")  
37 - @NotNull(message = "产品编号不能为空")  
38 - private Long id;  
39 -  
40 - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")  
41 - @NotNull(message = "产品数量不能为空")  
42 - private Integer count;  
43 -  
44 - @Schema(description = "产品折扣")  
45 - private Integer discountPercent;  
46 -  
47 - }  
48 -  
49 -}  
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java
@@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; @@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
19 import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; 19 import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
20 import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; 20 import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService;
21 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; 21 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO;
22 -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;  
23 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 22 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
24 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; 23 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
25 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; 24 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
@@ -133,7 +132,6 @@ public class CrmClueServiceImpl implements CrmClueService { @@ -133,7 +132,6 @@ public class CrmClueServiceImpl implements CrmClueService {
133 .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); 132 .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent));
134 133
135 // 3. 记录操作日志上下文 134 // 3. 记录操作日志上下文
136 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmUpdateFollowUpReqBO.class));  
137 LogRecordContext.putVariable("clueName", oldClue.getName()); 135 LogRecordContext.putVariable("clueName", oldClue.getName());
138 } 136 }
139 137
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
@@ -8,9 +8,9 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTrans @@ -8,9 +8,9 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTrans
8 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 8 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; 9 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
10 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; 10 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
11 -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;  
12 import jakarta.validation.Valid; 11 import jakarta.validation.Valid;
13 12
  13 +import java.time.LocalDateTime;
14 import java.util.Collection; 14 import java.util.Collection;
15 import java.util.List; 15 import java.util.List;
16 16
@@ -55,9 +55,11 @@ public interface CrmContractService { @@ -55,9 +55,11 @@ public interface CrmContractService {
55 /** 55 /**
56 * 更新合同相关的更进信息 56 * 更新合同相关的更进信息
57 * 57 *
58 - * @param contractUpdateFollowUpReqBO 信息 58 + * @param id 合同编号
  59 + * @param contactNextTime 下次联系时间
  60 + * @param contactLastContent 最后联系内容
59 */ 61 */
60 - void updateContractFollowUp(CrmUpdateFollowUpReqBO contractUpdateFollowUpReqBO); 62 + void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent);
61 63
62 /** 64 /**
63 * 发起合同审批流程 65 * 发起合同审批流程
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
@@ -11,13 +11,12 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; @@ -11,13 +11,12 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
11 import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; 11 import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
12 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; 12 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
13 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; 13 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
  14 +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
14 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; 15 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
15 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; 16 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
16 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; 17 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
17 -import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;  
18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
19 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; 19 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
20 -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;  
21 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; 20 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
22 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper; 21 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper;
23 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; 22 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
@@ -25,11 +24,11 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; @@ -25,11 +24,11 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
25 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 24 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
26 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; 25 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
27 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; 26 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
28 -import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO; 27 +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
29 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; 28 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
30 -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;  
31 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 29 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
32 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; 30 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
  31 +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
33 import cn.iocoder.yudao.module.crm.service.product.CrmProductService; 32 import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
34 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 33 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
35 import com.mzt.logapi.context.LogRecordContext; 34 import com.mzt.logapi.context.LogRecordContext;
@@ -40,17 +39,15 @@ import org.springframework.stereotype.Service; @@ -40,17 +39,15 @@ import org.springframework.stereotype.Service;
40 import org.springframework.transaction.annotation.Transactional; 39 import org.springframework.transaction.annotation.Transactional;
41 import org.springframework.validation.annotation.Validated; 40 import org.springframework.validation.annotation.Validated;
42 41
  42 +import java.math.BigDecimal;
  43 +import java.time.LocalDateTime;
43 import java.util.Collection; 44 import java.util.Collection;
44 import java.util.List; 45 import java.util.List;
45 -import java.util.Map;  
46 -import java.util.Set;  
47 46
48 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 47 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 48 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
50 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; 49 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
51 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; 50 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
52 -import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertAuditStatus;  
53 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;  
54 51
55 /** 52 /**
56 * CRM 合同 Service 实现类 53 * CRM 合同 Service 实现类
@@ -79,6 +76,8 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -79,6 +76,8 @@ public class CrmContractServiceImpl implements CrmContractService {
79 private CrmCustomerService customerService; 76 private CrmCustomerService customerService;
80 @Resource 77 @Resource
81 private CrmBusinessService businessService; 78 private CrmBusinessService businessService;
  79 + @Resource
  80 + private CrmContactService contactService;
82 81
83 @Resource 82 @Resource
84 private AdminUserApi adminUserApi; 83 private AdminUserApi adminUserApi;
@@ -90,30 +89,29 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -90,30 +89,29 @@ public class CrmContractServiceImpl implements CrmContractService {
90 @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}", 89 @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}",
91 success = CRM_CONTRACT_CREATE_SUCCESS) 90 success = CRM_CONTRACT_CREATE_SUCCESS)
92 public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) { 91 public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) {
  92 + // 1.1 校验产品项的有效性
  93 + List<CrmContractProductDO> contractProducts = validateContractProducts(createReqVO.getProducts());
  94 + // 1.2 校验关联字段
93 validateRelationDataExists(createReqVO); 95 validateRelationDataExists(createReqVO);
94 - // 1.1 插入合同  
95 - CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null); 96 + // TODO 芋艿:生成 no
  97 +
  98 + // 2.1 插入合同
  99 + CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class);
  100 + contract.setNo(System.currentTimeMillis() + ""); // TODO
  101 + calculateTotalPrice(contract, contractProducts);
96 contractMapper.insert(contract); 102 contractMapper.insert(contract);
97 - // 1.2 插入合同关联商品  
98 - if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话  
99 - List<CrmContractProductDO> productList = convertContractProductList(createReqVO, contract.getId());  
100 - contractProductMapper.insertBatch(productList);  
101 - // 更新合同商品总金额  
102 - contractMapper.updateById(new CrmContractDO().setId(contract.getId()).setProductPrice(  
103 - getSumValue(productList, CrmContractProductDO::getTotalPrice, Integer::sum)));  
104 - // 如果存在合同关联了商机则更新商机商品关联  
105 - if (contract.getBusinessId() != null) {  
106 - businessService.updateBusinessProduct(new CrmBusinessUpdateProductReqBO().setId(contract.getBusinessId())  
107 - .setItems(BeanUtils.toBean(createReqVO.getProductItems(), CrmBusinessUpdateProductReqBO.Item.class)));  
108 - } 103 + // 2.2 插入合同关联商品
  104 + if (CollUtil.isNotEmpty(contractProducts)) {
  105 + contractProducts.forEach(item -> item.setContractId(contract.getId()));
  106 + contractProductMapper.insertBatch(contractProducts);
109 } 107 }
110 108
111 - // 2. 创建数据权限  
112 - crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) 109 + // 3. 创建数据权限
  110 + crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(contract.getOwnerUserId())
113 .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) 111 .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId())
114 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); 112 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
115 113
116 - // 3. 记录操作日志上下文 114 + // 4. 记录操作日志上下文
117 LogRecordContext.putVariable("contract", contract); 115 LogRecordContext.putVariable("contract", contract);
118 return contract.getId(); 116 return contract.getId();
119 } 117 }
@@ -125,6 +123,7 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -125,6 +123,7 @@ public class CrmContractServiceImpl implements CrmContractService {
125 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) 123 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
126 public void updateContract(CrmContractSaveReqVO updateReqVO) { 124 public void updateContract(CrmContractSaveReqVO updateReqVO) {
127 Assert.notNull(updateReqVO.getId(), "合同编号不能为空"); 125 Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
  126 + updateReqVO.setOwnerUserId(null); // 不允许更新的字段
128 // 1.1 校验存在 127 // 1.1 校验存在
129 CrmContractDO contract = validateContractExists(updateReqVO.getId()); 128 CrmContractDO contract = validateContractExists(updateReqVO.getId());
130 // 1.2 只有草稿、审批中,可以编辑; 129 // 1.2 只有草稿、审批中,可以编辑;
@@ -132,63 +131,41 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -132,63 +131,41 @@ public class CrmContractServiceImpl implements CrmContractService {
132 CrmAuditStatusEnum.PROCESS.getStatus())) { 131 CrmAuditStatusEnum.PROCESS.getStatus())) {
133 throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED); 132 throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
134 } 133 }
  134 + // 1.3 校验产品项的有效性
  135 + List<CrmContractProductDO> contractProducts = validateContractProducts(updateReqVO.getProducts());
  136 + // 1.4 校验关联字段
135 validateRelationDataExists(updateReqVO); 137 validateRelationDataExists(updateReqVO);
136 138
137 // 2.1 更新合同 139 // 2.1 更新合同
138 CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class); 140 CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
  141 + calculateTotalPrice(updateObj, contractProducts);
139 contractMapper.updateById(updateObj); 142 contractMapper.updateById(updateObj);
140 // 2.2 更新合同关联商品 143 // 2.2 更新合同关联商品
141 - updateContractProduct(updateReqVO, updateObj.getId()); 144 + updateContractProduct(updateReqVO.getId(), contractProducts);
142 145
143 // 3. 记录操作日志上下文 146 // 3. 记录操作日志上下文
144 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class)); 147 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class));
145 LogRecordContext.putVariable("contractName", contract.getName()); 148 LogRecordContext.putVariable("contractName", contract.getName());
146 } 149 }
147 150
148 - private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {  
149 - if (CollUtil.isEmpty(updateReqVO.getProductItems())) {  
150 - return;  
151 - }  
152 - List<CrmContractProductDO> newProductList = convertContractProductList(updateReqVO, contractId);  
153 - List<CrmContractProductDO> oldProductList = contractProductMapper.selectListByContractId(contractId);  
154 - List<List<CrmContractProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {  
155 - boolean match = ObjUtil.equal(oldObj.getProductId(), newObj.getProductId());  
156 - if (match) {  
157 - newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用  
158 - }  
159 - return match;  
160 - }); 151 + private void updateContractProduct(Long id, List<CrmContractProductDO> newList) {
  152 + List<CrmContractProductDO> oldList = contractProductMapper.selectListByContractId(id);
  153 + List<List<CrmContractProductDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  154 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
161 if (CollUtil.isNotEmpty(diffList.get(0))) { 155 if (CollUtil.isNotEmpty(diffList.get(0))) {
  156 + diffList.get(0).forEach(o -> o.setContractId(id));
162 contractProductMapper.insertBatch(diffList.get(0)); 157 contractProductMapper.insertBatch(diffList.get(0));
163 } 158 }
164 if (CollUtil.isNotEmpty(diffList.get(1))) { 159 if (CollUtil.isNotEmpty(diffList.get(1))) {
165 contractProductMapper.updateBatch(diffList.get(1)); 160 contractProductMapper.updateBatch(diffList.get(1));
166 } 161 }
167 if (CollUtil.isNotEmpty(diffList.get(2))) { 162 if (CollUtil.isNotEmpty(diffList.get(2))) {
168 - contractProductMapper.deleteBatchIds(convertList(diffList.get(2), CrmContractProductDO::getId)); 163 + contractProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmContractProductDO::getId));
169 } 164 }
170 } 165 }
171 166
172 // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum 167 // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
173 168
174 - private List<CrmContractProductDO> convertContractProductList(CrmContractSaveReqVO reqVO, Long contractId) {  
175 - // 校验商品存在  
176 - Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);  
177 - List<CrmProductDO> productList = productService.getProductList(productIds);  
178 - if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) {  
179 - throw exception(PRODUCT_NOT_EXISTS);  
180 - }  
181 - Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);  
182 - return convertList(reqVO.getProductItems(), productItem -> {  
183 - CrmProductDO product = productMap.get(productItem.getId());  
184 - return BeanUtils.toBean(product, CrmContractProductDO.class)  
185 - .setId(null).setProductId(productItem.getId()).setContractId(contractId)  
186 - .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())  
187 - // TODO 芋艿:这里临时注释掉  
188 - .setTotalPrice(MoneyUtils.calculator(null, productItem.getCount(), productItem.getDiscountPercent()));  
189 - });  
190 - }  
191 -  
192 /** 169 /**
193 * 校验关联数据是否存在 170 * 校验关联数据是否存在
194 * 171 *
@@ -196,17 +173,38 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -196,17 +173,38 @@ public class CrmContractServiceImpl implements CrmContractService {
196 */ 173 */
197 private void validateRelationDataExists(CrmContractSaveReqVO reqVO) { 174 private void validateRelationDataExists(CrmContractSaveReqVO reqVO) {
198 // 1. 校验客户 175 // 1. 校验客户
199 - if (reqVO.getCustomerId() != null && customerService.getCustomer(reqVO.getCustomerId()) == null) {  
200 - throw exception(CUSTOMER_NOT_EXISTS); 176 + if (reqVO.getCustomerId() != null) {
  177 + customerService.validateCustomer(reqVO.getCustomerId());
201 } 178 }
202 // 2. 校验负责人 179 // 2. 校验负责人
203 - if (reqVO.getOwnerUserId() != null && adminUserApi.getUser(reqVO.getOwnerUserId()) == null) {  
204 - throw exception(USER_NOT_EXISTS); 180 + if (reqVO.getOwnerUserId() != null) {
  181 + adminUserApi.validateUser(reqVO.getOwnerUserId());
205 } 182 }
206 // 3. 如果有关联商机,则需要校验存在 183 // 3. 如果有关联商机,则需要校验存在
207 - if (reqVO.getBusinessId() != null && businessService.getBusiness(reqVO.getBusinessId()) == null) {  
208 - throw exception(BUSINESS_NOT_EXISTS); 184 + if (reqVO.getBusinessId() != null) {
  185 + businessService.validateBusiness(reqVO.getBusinessId());
209 } 186 }
  187 + // 4. 校验签约相关字段
  188 + if (reqVO.getSignContactId() != null) {
  189 + contactService.validateContact(reqVO.getSignContactId());
  190 + }
  191 + if (reqVO.getSignUserId() != null) {
  192 + adminUserApi.validateUser(reqVO.getSignUserId());
  193 + }
  194 + }
  195 +
  196 + private List<CrmContractProductDO> validateContractProducts(List<CrmContractSaveReqVO.Product> list) {
  197 + // 1. 校验产品存在
  198 + productService.validProductList(convertSet(list, CrmContractSaveReqVO.Product::getProductId));
  199 + // 2. 转化为 CrmContractProductDO 列表
  200 + return convertList(list, o -> BeanUtils.toBean(o, CrmContractProductDO.class,
  201 + item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getContractPrice(), item.getCount()))));
  202 + }
  203 +
  204 + private void calculateTotalPrice(CrmContractDO contract, List<CrmContractProductDO> contractProducts) {
  205 + contract.setTotalProductPrice(getSumValue(contractProducts, CrmContractProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO));
  206 + BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(contract.getTotalProductPrice(), contract.getDiscountPercent());
  207 + contract.setTotalPrice(contract.getTotalProductPrice().subtract(discountPrice));
210 } 208 }
211 209
212 @Override 210 @Override
@@ -245,8 +243,8 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -245,8 +243,8 @@ public class CrmContractServiceImpl implements CrmContractService {
245 CrmContractDO contract = validateContractExists(reqVO.getId()); 243 CrmContractDO contract = validateContractExists(reqVO.getId());
246 244
247 // 2.1 数据权限转移 245 // 2.1 数据权限转移
248 - crmPermissionService.transferPermission(  
249 - CrmContractConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType())); 246 + crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(),
  247 + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel()));
250 // 2.2 设置负责人 248 // 2.2 设置负责人
251 contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); 249 contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
252 250
@@ -255,8 +253,18 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -255,8 +253,18 @@ public class CrmContractServiceImpl implements CrmContractService {
255 } 253 }
256 254
257 @Override 255 @Override
258 - public void updateContractFollowUp(CrmUpdateFollowUpReqBO contractUpdateFollowUpReqBO) {  
259 - contractMapper.updateById(BeanUtils.toBean(contractUpdateFollowUpReqBO, CrmContractDO.class).setId(contractUpdateFollowUpReqBO.getBizId())); 256 + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}",
  257 + success = CRM_CONTRACT_FOLLOW_UP_SUCCESS)
  258 + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
  259 + public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {
  260 + // 1. 校验存在
  261 + CrmContractDO contract = validateContractExists(id);
  262 +
  263 + // 2. 更新联系人的跟进信息
  264 + contractMapper.updateById(new CrmContractDO().setId(id).setContactLastTime(LocalDateTime.now()));
  265 +
  266 + // 3. 记录操作日志上下文
  267 + LogRecordContext.putVariable("contractName", contract.getName());
260 } 268 }
261 269
262 @Override 270 @Override
@@ -284,12 +292,36 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -284,12 +292,36 @@ public class CrmContractServiceImpl implements CrmContractService {
284 292
285 @Override 293 @Override
286 public void updateContractAuditStatus(BpmResultListenerRespDTO event) { 294 public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
287 - convertAuditStatus(event); 295 + // 判断下状态是否符合预期
  296 + if (!isEndResult(event.getResult())) {
  297 + return;
  298 + }
  299 + // 状态转换
  300 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) {
  301 + event.setResult(CrmAuditStatusEnum.APPROVE.getStatus());
  302 + }
  303 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) {
  304 + event.setResult(CrmAuditStatusEnum.REJECT.getStatus());
  305 + }
  306 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) {
  307 + event.setResult(CrmAuditStatusEnum.CANCEL.getStatus());
  308 + }
288 // 更新合同状态 309 // 更新合同状态
289 contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey())) 310 contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
290 .setAuditStatus(event.getResult())); 311 .setAuditStatus(event.getResult()));
291 } 312 }
292 313
  314 + /**
  315 + * 判断该结果是否处于 End 最终结果
  316 + *
  317 + * @param result 结果
  318 + * @return 是否
  319 + */
  320 + public static boolean isEndResult(Integer result) {
  321 + return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
  322 + BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
  323 + }
  324 +
293 //======================= 查询相关 ======================= 325 //======================= 查询相关 =======================
294 326
295 @Override 327 @Override
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java
@@ -17,14 +17,12 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; @@ -17,14 +17,12 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
17 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; 17 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
18 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; 18 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
19 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; 19 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO;
20 -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;  
21 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 20 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
22 import jakarta.annotation.Resource; 21 import jakarta.annotation.Resource;
23 import org.springframework.context.annotation.Lazy; 22 import org.springframework.context.annotation.Lazy;
24 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
25 import org.springframework.validation.annotation.Validated; 24 import org.springframework.validation.annotation.Validated;
26 25
27 -import java.time.LocalDateTime;  
28 import java.util.Collection; 26 import java.util.Collection;
29 import java.util.List; 27 import java.util.List;
30 28
@@ -71,9 +69,6 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { @@ -71,9 +69,6 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
71 crmFollowUpRecordMapper.insert(record); 69 crmFollowUpRecordMapper.insert(record);
72 70
73 // 2. 更新 bizId 对应的记录 71 // 2. 更新 bizId 对应的记录
74 - CrmUpdateFollowUpReqBO updateFollowUpReqBO = new CrmUpdateFollowUpReqBO().setBizId(record.getBizId())  
75 - .setContactLastTime(LocalDateTime.now())  
76 - .setContactNextTime(record.getNextTime()).setContactLastContent(record.getContent());  
77 if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), record.getBizType())) { // 更新商机跟进信息 72 if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), record.getBizType())) { // 更新商机跟进信息
78 businessService.updateBusinessFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); 73 businessService.updateBusinessFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
79 } 74 }
@@ -84,7 +79,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { @@ -84,7 +79,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
84 contactService.updateContactFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); 79 contactService.updateContactFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
85 } 80 }
86 if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTRACT.getType(), record.getBizType())) { // 更新合同跟进信息 81 if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTRACT.getType(), record.getBizType())) { // 更新合同跟进信息
87 - contractService.updateContractFollowUp(updateFollowUpReqBO); 82 + contractService.updateContractFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
88 } 83 }
89 if (ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), record.getBizType())) { // 更新客户跟进信息 84 if (ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), record.getBizType())) { // 更新客户跟进信息
90 customerService.updateCustomerFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); 85 customerService.updateCustomerFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/bo/CrmUpdateFollowUpReqBO.java deleted
1 -package cn.iocoder.yudao.module.crm.service.followup.bo;  
2 -  
3 -import com.mzt.logapi.starter.annotation.DiffLogField;  
4 -import io.swagger.v3.oas.annotations.media.Schema;  
5 -import jakarta.validation.constraints.NotNull;  
6 -import lombok.Data;  
7 -  
8 -import java.time.LocalDateTime;  
9 -  
10 -/**  
11 - * 跟进信息 Update Req BO  
12 - *  
13 - * @author HUIHUI  
14 - */  
15 -@Data  
16 -public class CrmUpdateFollowUpReqBO {  
17 -  
18 - @Schema(description = "数据编号", example = "3167")  
19 - @NotNull(message = "数据编号不能为空")  
20 - private Long bizId;  
21 -  
22 - @Schema(description = "最后跟进时间")  
23 - @DiffLogField(name = "最后跟进时间")  
24 - private LocalDateTime contactLastTime;  
25 -  
26 - @Schema(description = "下次联系时间")  
27 - @DiffLogField(name = "下次联系时间")  
28 - private LocalDateTime contactNextTime;  
29 -  
30 - @Schema(description = "最后更进内容")  
31 - @DiffLogField(name = "最后更进内容")  
32 - private String contactLastContent;  
33 -  
34 -}