Commit d9b0c9b4cf1f1620c1d5e08075a6b6ddd83c3597

Authored by YunaiV
1 parent df2441de

✨ CRM:完善商机的跟进记录

yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
... ... @@ -20,7 +20,7 @@ public interface ErrorCodeConstants {
20 20  
21 21 // ========== 商机管理 1-020-002-000 ==========
22 22 ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在");
23   - ErrorCode BUSINESS_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除");
  23 + ErrorCode BUSINESS_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除");
24 24  
25 25 // ========== 联系人管理 1-020-003-000 ==========
26 26 ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在");
... ...
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
... ... @@ -91,6 +91,8 @@ public interface LogRecordConstants {
91 91 String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】";
92 92 String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机";
93 93 String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
  94 + String CRM_BUSINESS_FOLLOW_UP_SUB_TYPE = "商机跟进";
  95 + String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】";
94 96  
95 97 // ======================= CRM_CONTRACT 合同 =======================
96 98  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
... ... @@ -65,7 +65,7 @@ public class CrmBusinessRespVO {
65 65 private String statusName;
66 66  
67 67 @Schema
68   - @ExcelProperty("1赢单2输单3无效")
  68 + @ExcelProperty("结束状态")
69 69 private Integer endStatus;
70 70  
71 71 @ExcelProperty("结束时的备注")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java
1 1 package cn.iocoder.yudao.module.crm.convert.business;
2 2  
3   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 3 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
5   -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
6   -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
7 4 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
8 5 import org.mapstruct.Mapper;
9 6 import org.mapstruct.Mapping;
10 7 import org.mapstruct.factory.Mappers;
11 8  
12   -import java.util.List;
13   -
14 9 /**
15 10 * 商机 Convert
16 11 *
... ... @@ -24,11 +19,4 @@ public interface CrmBusinessConvert {
24 19 @Mapping(target = "bizId", source = "reqVO.id")
25 20 CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
26 21  
27   - @Mapping(target = "id", source = "reqBO.bizId")
28   - CrmBusinessDO convert(CrmUpdateFollowUpReqBO reqBO);
29   -
30   - default List<CrmBusinessDO> convertList(List<CrmUpdateFollowUpReqBO> list) {
31   - return CollectionUtils.convertList(list, INSTANCE::convert);
32   - }
33   -
34 22 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
... ... @@ -9,9 +9,9 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
9 9 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
10 10 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
11 11 import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;
12   -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
13 12 import jakarta.validation.Valid;
14 13  
  14 +import java.time.LocalDateTime;
15 15 import java.util.Collection;
16 16 import java.util.List;
17 17  
... ... @@ -41,9 +41,19 @@ public interface CrmBusinessService {
41 41 /**
42 42 * 更新商机相关跟进信息
43 43 *
44   - * @param updateFollowUpReqBOList 跟进信息
  44 + * @param id 编号
  45 + * @param contactNextTime 下次联系时间
  46 + * @param contactLastContent 最后联系内容
  47 + */
  48 + void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent);
  49 +
  50 + /**
  51 + * 更新商机的下次联系时间
  52 + *
  53 + * @param ids 编号数组
  54 + * @param contactNextTime 下次联系时间
45 55 */
46   - void updateBusinessFollowUpBatch(List<CrmUpdateFollowUpReqBO> updateFollowUpReqBOList);
  56 + void updateBusinessContactNextTime(Collection<Long> ids, LocalDateTime contactNextTime);
47 57  
48 58 /**
49 59 * 删除商机
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -22,7 +22,6 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
22 22 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
23 23 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
24 24 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
25   -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
26 25 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
27 26 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
28 27 import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
... ... @@ -37,12 +36,13 @@ import org.springframework.transaction.annotation.Transactional;
37 36 import org.springframework.validation.annotation.Validated;
38 37  
39 38 import java.math.BigDecimal;
  39 +import java.time.LocalDateTime;
40 40 import java.util.Collection;
41 41 import java.util.List;
42 42  
43 43 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
44 44 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
45   -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_CONTRACT_EXISTS;
  45 +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_DELETE_FAIL_CONTRACT_EXISTS;
46 46 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS;
47 47 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
48 48  
... ... @@ -139,6 +139,28 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
139 139 LogRecordContext.putVariable("businessName", oldBusiness.getName());
140 140 }
141 141  
  142 + @Override
  143 + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}",
  144 + success = CRM_BUSINESS_FOLLOW_UP_SUCCESS)
  145 + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
  146 + public void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {
  147 + // 1. 校验存在
  148 + CrmBusinessDO business = validateBusinessExists(id);
  149 +
  150 + // 2. 更新联系人的跟进信息
  151 + businessMapper.updateById(new CrmBusinessDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime)
  152 + .setContactLastTime(LocalDateTime.now()));
  153 +
  154 + // 3. 记录操作日志上下文
  155 + LogRecordContext.putVariable("businessName", business.getName());
  156 + }
  157 +
  158 + @Override
  159 + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE)
  160 + public void updateBusinessContactNextTime(Collection<Long> ids, LocalDateTime contactNextTime) {
  161 + businessMapper.updateBatch(convertList(ids, id -> new CrmBusinessDO().setId(id).setContactNextTime(contactNextTime)));
  162 + }
  163 +
142 164 private void updateBusinessProduct(Long id, List<CrmBusinessProductDO> newList) {
143 165 List<CrmBusinessProductDO> oldList = businessProductMapper.selectListByBusinessId(id);
144 166 List<List<CrmBusinessProductDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
... ... @@ -190,19 +212,14 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
190 212 }
191 213  
192 214 @Override
193   - public void updateBusinessFollowUpBatch(List<CrmUpdateFollowUpReqBO> updateFollowUpReqBOList) {
194   - businessMapper.updateBatch(CrmBusinessConvert.INSTANCE.convertList(updateFollowUpReqBOList));
195   - }
196   -
197   - @Override
198 215 @Transactional(rollbackFor = Exception.class)
199 216 @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_DELETE_SUB_TYPE, bizNo = "{{#id}}",
200 217 success = CRM_BUSINESS_DELETE_SUCCESS)
201 218 @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
202 219 public void deleteBusiness(Long id) {
203   - // 校验存在
  220 + // 1.1 校验存在
204 221 CrmBusinessDO business = validateBusinessExists(id);
205   - // TODO @商机待定:需要校验有没关联合同。CrmContractDO 的 businessId 字段
  222 + // 1.2 校验是否关联合同
206 223 validateContractExists(id);
207 224  
208 225 // 删除
... ... @@ -222,7 +239,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
222 239 */
223 240 private void validateContractExists(Long businessId) {
224 241 if (contractService.getContractCountByBusinessId(businessId) > 0) {
225   - throw exception(BUSINESS_CONTRACT_EXISTS);
  242 + throw exception(BUSINESS_DELETE_FAIL_CONTRACT_EXISTS);
226 243 }
227 244 }
228 245  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java
... ... @@ -72,13 +72,12 @@ public interface CrmContactService {
72 72 void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent);
73 73  
74 74 /**
75   - * 更新联系人相关跟进信息
  75 + * 更新联系人的下次联系时间
76 76 *
77 77 * @param ids 编号数组
78 78 * @param contactNextTime 下次联系时间
79   - * @param contactLastContent 最后联系内容
80 79 */
81   - void updateContactFollowUpBatch(Collection<Long> ids, LocalDateTime contactNextTime, String contactLastContent);
  80 + void updateContactContactNextTime(Collection<Long> ids, LocalDateTime contactNextTime);
82 81  
83 82 /**
84 83 * 获得联系人
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
... ... @@ -225,7 +225,7 @@ public class CrmContactServiceImpl implements CrmContactService {
225 225 success = CRM_CONTACT_FOLLOW_UP_SUCCESS)
226 226 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
227 227 public void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {
228   - // 1.1 校验存在
  228 + // 1. 校验存在
229 229 CrmContactDO contact = validateContactExists(id);
230 230  
231 231 // 2. 更新联系人的跟进信息
... ... @@ -238,9 +238,8 @@ public class CrmContactServiceImpl implements CrmContactService {
238 238  
239 239 @Override
240 240 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE)
241   - public void updateContactFollowUpBatch(Collection<Long> ids, LocalDateTime contactNextTime, String contactLastContent) {
242   - contactMapper.updateBatch(convertList(ids, id -> new CrmContactDO().setId(id).setContactLastTime(LocalDateTime.now())
243   - .setContactNextTime(contactNextTime).setContactLastContent(contactLastContent)));
  241 + public void updateContactContactNextTime(Collection<Long> ids, LocalDateTime contactNextTime) {
  242 + contactMapper.updateBatch(convertList(ids, id -> new CrmContactDO().setId(id).setContactNextTime(contactNextTime)));
244 243 }
245 244  
246 245 //======================= 查询相关 =======================
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java
... ... @@ -26,11 +26,9 @@ import org.springframework.validation.annotation.Validated;
26 26  
27 27 import java.time.LocalDateTime;
28 28 import java.util.Collection;
29   -import java.util.Collections;
30 29 import java.util.List;
31 30  
32 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
33   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
34 32 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED;
35 33 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS;
36 34  
... ... @@ -77,7 +75,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
77 75 .setContactLastTime(LocalDateTime.now())
78 76 .setContactNextTime(record.getNextTime()).setContactLastContent(record.getContent());
79 77 if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), record.getBizType())) { // 更新商机跟进信息
80   - businessService.updateBusinessFollowUpBatch(Collections.singletonList(updateFollowUpReqBO));
  78 + businessService.updateBusinessFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
81 79 }
82 80 if (ObjUtil.equal(CrmBizTypeEnum.CRM_CLUE.getType(), record.getBizType())) { // 更新线索跟进信息
83 81 clueService.updateClueFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
... ... @@ -92,14 +90,13 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
92 90 customerService.updateCustomerFollowUp(record.getBizId(), record.getNextTime(), record.getContent());
93 91 }
94 92  
95   - // 3.1 更新 contactIds 对应的记录,不更新 lastTime 和 lastContent
  93 + // 3.1 更新 contactIds 对应的记录,只更新 nextTime
96 94 if (CollUtil.isNotEmpty(createReqVO.getContactIds())) {
97   - contactService.updateContactFollowUpBatch(createReqVO.getContactIds(), null, null);
  95 + contactService.updateContactContactNextTime(createReqVO.getContactIds(), createReqVO.getNextTime());
98 96 }
99   - // 3.2 需要更新 businessIds 对应的记录,不更新 lastTime 和 lastContent
  97 + // 3.2 需要更新 businessIds 对应的记录,只更新 nextTime
100 98 if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) {
101   - businessService.updateBusinessFollowUpBatch(convertList(createReqVO.getBusinessIds(),
102   - businessId -> updateFollowUpReqBO.setBizId(businessId).setContactLastTime(null).setContactLastContent(null)));
  99 + businessService.updateBusinessContactNextTime(createReqVO.getBusinessIds(), createReqVO.getNextTime());
103 100 }
104 101 return record.getId();
105 102 }
... ...