Commit 59e6f23788af5cd79888eaeada5519b5f952a2ed

Authored by puhui999
1 parent 1a96fb2f

CRM-CONTRACT: 完善 TODO

Showing 16 changed files with 171 additions and 71 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java
... ... @@ -38,6 +38,22 @@ public class MoneyUtils {
38 38 /**
39 39 * 计算百分比金额
40 40 *
  41 + * @param price 金额(单位分)
  42 + * @param count 数量
  43 + * @param percent 折扣(单位分),列如 60.2%,则传入 6020
  44 + * @return 商品总价
  45 + */
  46 + public static Integer calculator(Integer price, Integer count, Integer percent) {
  47 + price = price * count;
  48 + if (percent == null) {
  49 + return price;
  50 + }
  51 + return MoneyUtils.calculateRatePriceFloor(price, (double) (percent / 100));
  52 + }
  53 +
  54 + /**
  55 + * 计算百分比金额
  56 + *
41 57 * @param price 金额
42 58 * @param rate 百分比,例如说 56.77% 则传入 56.77
43 59 * @param scale 保留小数位数
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
... ... @@ -43,7 +43,7 @@ public class BpmModelController {
43 43 return success(model);
44 44 }
45 45  
46   - // TODO @puhui999:这个接口的目的是啥呀?
  46 + // TODO @puhui999:这个接口的目的是啥呀?业务表单预览流程🤣
47 47 @GetMapping("/get-by-key")
48 48 @Operation(summary = "获得模型")
49 49 @Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave")
... ...
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
... ... @@ -12,6 +12,7 @@ public interface ErrorCodeConstants {
12 12 // ========== 合同管理 1-020-000-000 ==========
13 13 ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
14 14 ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑");
  15 + ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态");
15 16  
16 17 // ========== 线索管理 1-020-001-000 ==========
17 18 ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
... ...
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
... ... @@ -39,6 +39,8 @@ public interface LogRecordConstants {
39 39 String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海";
40 40 String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}";
41 41 String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}";
  42 + String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}";
  43 + String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}";
42 44  
43 45 // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 =======================
44 46  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
... ... @@ -132,21 +132,19 @@ public class CrmContractController {
132 132 return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList);
133 133 }
134 134  
135   - // TODO @puhui999:transferContract
136   - @PutMapping("/transfer")
  135 + @PutMapping("/transfer-contract")
137 136 @Operation(summary = "合同转移")
138 137 @PreAuthorize("@ss.hasPermission('crm:contract:update')")
139   - public CommonResult<Boolean> transfer(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
  138 + public CommonResult<Boolean> transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
140 139 contractService.transferContract(reqVO, getLoginUserId());
141 140 return success(true);
142 141 }
143 142  
144   - // TODO @puhui999:方法名不对哈;要不改成 submit?提交审核的意思
145   - @PutMapping("/approve")
146   - @Operation(summary = "发起合同审批流程")
  143 + @PutMapping("/submit")
  144 + @Operation(summary = "提交合同审批")
147 145 @PreAuthorize("@ss.hasPermission('crm:contract:update')")
148   - public CommonResult<Boolean> transfer(@RequestParam("id") Long id) {
149   - contractService.handleApprove(id, getLoginUserId());
  146 + public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
  147 + contractService.submitContract(id, getLoginUserId());
150 148 return success(true);
151 149 }
152 150  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java
... ... @@ -89,9 +89,6 @@ public class CrmContractSaveReqVO {
89 89 @DiffLogField(name = "备注")
90 90 private String remark;
91 91  
92   - // TODO @puhui999:这个字段,按道理不用传递?
93   - @Schema(description = "审批状态", example = "1")
94   - private Integer auditStatus;
95 92  
96 93 @Schema(description = "产品列表")
97 94 private List<CrmContractProductItem> productItems;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java
1 1 package cn.iocoder.yudao.module.crm.dal.dataobject.business;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
4 5 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
5 6 import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
6 7 import com.baomidou.mybatisplus.annotation.KeySequence;
... ... @@ -40,6 +41,12 @@ public class CrmBusinessProductDO extends BaseDO {
40 41 * 关联 {@link CrmProductDO#getId()}
41 42 */
42 43 private Long productId;
  44 + /**
  45 + * 合同编号
  46 + *
  47 + * 关联 {@link CrmContractDO#getId()}
  48 + */
  49 + private Long contractId;
43 50  
44 51 /**
45 52 * 产品单价
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java
... ... @@ -45,7 +45,7 @@ public class CrmProductDO extends BaseDO {
45 45 /**
46 46 * 价格,单位:分
47 47 */
48   - private Long price;
  48 + private Integer price;
49 49 /**
50 50 * 状态
51 51 *
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
... ... @@ -101,10 +101,9 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
101 101 return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
102 102 }
103 103  
104   - default List<CrmCustomerDO> selectListByLockAndDealStatusAndNotPool(Boolean lockStatus, Boolean dealStatus) {
  104 + default List<CrmCustomerDO> selectListByLockAndNotPool(Boolean lockStatus) {
105 105 return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
106 106 .eq(CrmCustomerDO::getLockStatus, lockStatus)
107   - .eq(CrmCustomerDO::getDealStatus, dealStatus)
108 107 .gt(CrmCustomerDO::getOwnerUserId, 0));
109 108 }
110 109  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessProductService.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
5 5 import java.util.List;
6 6  
7 7 // TODO @lzxhqs:方法名上,带下 BusinessProduct;主要考虑不精简的原因,是因为一个逻辑,可能会出现一些超越它自身方法,省略不容易懂;
  8 +
8 9 /**
9 10 * 商机产品关联表 Service 接口
10 11 *
... ... @@ -14,31 +15,45 @@ public interface CrmBusinessProductService {
14 15  
15 16 /**
16 17 * 批量新增商机产品关联数据
  18 + *
17 19 * @param list 商机产品集合
18 20 */
19 21 void insertBatch(List<CrmBusinessProductDO> list);
20 22  
21 23 /**
22 24 * 根据商机id获取商机产品关联数据集合
  25 + *
23 26 * @param businessId 商机id
24 27 */
25 28 List<CrmBusinessProductDO> selectListByBusinessId(Long businessId);
26 29  
27 30 /**
28 31 * 批量更新商机产品表
  32 + *
29 33 * @param list 商机产品数据集合
30 34 */
31 35 void updateBatch(List<CrmBusinessProductDO> list);
32 36  
33 37 /**
34 38 * 批量删除
  39 + *
35 40 * @param list 需要删除的商机产品集合
36 41 */
37 42 void deleteBatch(List<CrmBusinessProductDO> list);
38 43  
39 44 /**
40   - *根据商机id删除商机产品关联数据
  45 + * 根据商机id删除商机产品关联数据
  46 + *
41 47 * @param businessId 商机id
42 48 */
43 49 void deleteByBusinessId(Long businessId);
  50 +
  51 + /**
  52 + * 获得合同关联的商品列表
  53 + *
  54 + * @param contractId 合同编号
  55 + * @return 关联的商品列表
  56 + */
  57 + List<CrmBusinessProductDO> selectListByContractId(Long contractId);
  58 +
44 59 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessProductServiceImpl.java
... ... @@ -28,7 +28,7 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
28 28  
29 29 @Override
30 30 public List<CrmBusinessProductDO> selectListByBusinessId(Long businessId) {
31   - return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId,businessId);
  31 + return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId, businessId);
32 32 }
33 33  
34 34 @Override
... ... @@ -47,4 +47,9 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
47 47 businessProductMapper.deleteByBusinessId(businessId);
48 48 }
49 49  
  50 + @Override
  51 + public List<CrmBusinessProductDO> selectListByContractId(Long contractId) {
  52 + return businessProductMapper.selectList(CrmBusinessProductDO::getContractId, contractId);
  53 + }
  54 +
50 55 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -196,7 +196,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
196 196 */
197 197 private void validateContractExists(Long businessId) {
198 198 // TODO @lzxhqs:保持风格的统一,selectCountByBusinessId 改成 getContractCountByBusinessId;另外,可以不用声明 count,因为就一次性使用,直接把 197 和 198 合并成一行;
199   - Long count = contractService.selectCountByBusinessId(businessId);
  199 + Long count = contractService.getContractCountByBusinessId(businessId);
200 200 if (count > 0) {
201 201 throw exception(BUSINESS_CONTRACT_EXISTS);
202 202 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
... ... @@ -64,7 +64,7 @@ public interface CrmContractService {
64 64 * @param id 合同编号
65 65 * @param userId 用户编号
66 66 */
67   - void handleApprove(Long id, Long userId);
  67 + void submitContract(Long id, Long userId);
68 68  
69 69 /**
70 70 * 更新合同流程审批结果
... ... @@ -125,13 +125,12 @@ public interface CrmContractService {
125 125 */
126 126 Long getContractCountByCustomerId(Long customerId);
127 127  
128   - // TODO @puhui999:要不改成 getContractCountByBusinessId
129 128 /**
130 129 * 根据商机ID获取关联客户的合同数量
131 130 *
132 131 * @param businessId 商机编号
133 132 * @return 数量
134 133 */
135   - Long selectCountByBusinessId(Long businessId);
  134 + Long getContractCountByBusinessId(Long businessId);
136 135  
137 136 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
... ... @@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.crm.service.contract;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.ListUtil;
  5 +import cn.hutool.core.lang.Assert;
5 6 import cn.hutool.core.util.ObjUtil;
6 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 8 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
8 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  10 +import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
9 11 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
10 12 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
11 13 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
... ... @@ -87,8 +89,10 @@ public class CrmContractServiceImpl implements CrmContractService {
87 89 CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
88 90 contractMapper.insert(contract);
89 91 // 1.2 插入商机关联商品
90   - List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
91   - businessProductService.insertBatch(businessProduct);
  92 + if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
  93 + List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO, contract.getId());
  94 + businessProductService.insertBatch(businessProduct);
  95 + }
92 96  
93 97 // 2. 创建数据权限
94 98 crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
... ... @@ -106,9 +110,11 @@ public class CrmContractServiceImpl implements CrmContractService {
106 110 success = CRM_CONTRACT_UPDATE_SUCCESS)
107 111 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
108 112 public void updateContract(CrmContractSaveReqVO updateReqVO) {
109   - // TODO @合同待定:只有草稿、审批中,可以编辑;
110   - if (ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
111   - ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
  113 + Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
  114 + CrmContractDO contract = validateContractExists(updateReqVO.getId());
  115 + // 只有草稿、审批中,可以编辑;
  116 + if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
  117 + ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
112 118 throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
113 119 }
114 120 validateRelationDataExists(updateReqVO);
... ... @@ -117,21 +123,41 @@ public class CrmContractServiceImpl implements CrmContractService {
117 123 // 更新合同
118 124 CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
119 125 contractMapper.updateById(updateObj);
120   -
121   - // TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理?
122   - // TODO @puhui999:和商品 spu、sku 编辑一样;新增的插入;修改的更新;删除的删除
123   - //List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
124   - //businessProductService.selectListByBusinessId()
125   - //diffList()
  126 + // 更新合同关联商品
  127 + updateContractProduct(updateReqVO, updateObj.getId());
126 128  
127 129 // 3. 记录操作日志上下文
128 130 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
129 131 LogRecordContext.putVariable("contractName", oldContract.getName());
130 132 }
131 133  
  134 + private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {
  135 + if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
  136 + return;
  137 + }
  138 + List<CrmBusinessProductDO> newProductList = convertBusinessProductList(updateReqVO, contractId);
  139 + List<CrmBusinessProductDO> oldProductList = businessProductService.selectListByContractId(contractId);
  140 + List<List<CrmBusinessProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {
  141 + if (ObjUtil.notEqual(oldObj.getProductId(), newObj.getProductId())) {
  142 + return false;
  143 + }
  144 + newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用
  145 + return true;
  146 + });
  147 + if (CollUtil.isNotEmpty(diffList.getFirst())) {
  148 + businessProductService.insertBatch(diffList.getFirst());
  149 + }
  150 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  151 + businessProductService.updateBatch(diffList.get(1));
  152 + }
  153 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  154 + businessProductService.deleteBatch(diffList.get(2));
  155 + }
  156 + }
  157 +
132 158 // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
133 159  
134   - private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO) {
  160 + private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO, Long contractId) {
135 161 // 校验商品存在
136 162 Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
137 163 List<CrmProductDO> productList = productService.getProductList(productIds);
... ... @@ -140,30 +166,15 @@ public class CrmContractServiceImpl implements CrmContractService {
140 166 }
141 167 Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
142 168 return convertList(reqVO.getProductItems(), productItem -> {
143   - // TODO @puhui999:这里可以改成直接 return,不用弄一个 businessProduct 变量哈;
144   - CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class);
145   - businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId())
146   - .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct));
147   - return businessProduct;
  169 + CrmProductDO product = productMap.get(productItem.getId());
  170 + return BeanUtils.toBean(product, CrmBusinessProductDO.class)
  171 + .setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()).setContractId(contractId)
  172 + .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
  173 + .setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
148 174 });
149 175 }
150 176  
151 177 /**
152   - * 计算商品总价
153   - *
154   - * @param businessProduct 关联商品
155   - * @return 商品总价
156   - */
157   - // TODO @puhui999:这个逻辑的计算,是不是可以封装到 calculateRatePriceFloor 里;
158   - private Integer calculator(CrmBusinessProductDO businessProduct) {
159   - int price = businessProduct.getPrice() * businessProduct.getCount();
160   - if (businessProduct.getDiscountPercent() == null) {
161   - return price;
162   - }
163   - return MoneyUtils.calculateRatePriceFloor(price, (double) (businessProduct.getDiscountPercent() / 100));
164   - }
165   -
166   - /**
167 178 * 校验关联数据是否存在
168 179 *
169 180 * @param reqVO 请求
... ... @@ -235,9 +246,12 @@ public class CrmContractServiceImpl implements CrmContractService {
235 246  
236 247 @Override
237 248 @Transactional(rollbackFor = Exception.class)
238   - public void handleApprove(Long id, Long userId) {
239   - // TODO @puhui999:需要做状态检查
240   -
  249 + public void submitContract(Long id, Long userId) {
  250 + // 1. 校验合同是否在审批
  251 + CrmContractDO contract = validateContractExists(id);
  252 + if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) {
  253 + throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);
  254 + }
241 255 // 创建合同审批流程实例
242 256 String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
243 257 .setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));
... ... @@ -247,6 +261,12 @@ public class CrmContractServiceImpl implements CrmContractService {
247 261 .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
248 262 }
249 263  
  264 + @Override
  265 + public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
  266 + contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
  267 + .setAuditStatus(event.getResult()));
  268 + }
  269 +
250 270 //======================= 查询相关 =======================
251 271  
252 272 @Override
... ... @@ -285,7 +305,7 @@ public class CrmContractServiceImpl implements CrmContractService {
285 305 }
286 306  
287 307 @Override
288   - public Long selectCountByBusinessId(Long businessId) {
  308 + public Long getContractCountByBusinessId(Long businessId) {
289 309 return contractMapper.selectCountByBusinessId(businessId);
290 310 }
291 311 // TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java
1 1 package cn.iocoder.yudao.module.crm.service.contract.listener;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
3 5 import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi;
4 6 import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
  7 +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
  8 +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
5 9 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
6 10 import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
7 11 import jakarta.annotation.Resource;
... ... @@ -25,7 +29,31 @@ public class CrmContractResultListener implements BpmResultListenerApi {
25 29  
26 30 @Override
27 31 public void onEvent(BpmResultListenerRespDTO event) {
  32 + boolean currentTaskFinish = isEndResult(event.getResult());
  33 + if (!currentTaskFinish) {
  34 + return;
  35 + }
  36 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) {
  37 + event.setResult(CrmAuditStatusEnum.APPROVE.getStatus());
  38 + }
  39 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) {
  40 + event.setResult(CrmAuditStatusEnum.REJECT.getStatus());
  41 + }
  42 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) {
  43 + event.setResult(CrmAuditStatusEnum.CANCEL.getStatus());
  44 + }
28 45 contractService.updateContractAuditStatus(event);
29 46 }
30 47  
  48 + /**
  49 + * 判断该结果是否处于 End 最终结果
  50 + *
  51 + * @param result 结果
  52 + * @return 是否
  53 + */
  54 + public static boolean isEndResult(Integer result) {
  55 + return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
  56 + BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
  57 + }
  58 +
31 59 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
... ... @@ -93,8 +93,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
93 93 validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
94 94  
95 95 // 2. 插入客户
96   - CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class).setOwnerUserId(userId)
97   - .setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
  96 + CrmCustomerDO customer = initCustomer(createReqVO, userId);
98 97 customerMapper.insert(customer);
99 98  
100 99 // 3. 创建数据权限
... ... @@ -232,7 +231,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
232 231 return customer.getId();
233 232 }
234 233  
235   - // TODO @puhui999:操作日志
236 234 @Override
237 235 public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
238 236 Boolean isUpdateSupport, Long userId) {
... ... @@ -253,14 +251,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
253 251 // 判断如果不存在,在进行插入
254 252 CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
255 253 if (existCustomer == null) {
256   - // TODO @puhui999:可以搞个 initCustomer 方法;这样可以把 create 和导入复用下这个方法;
257   - CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId)
258   - .setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
  254 + CrmCustomerDO customer = initCustomer(importCustomer, userId);
259 255 customerMapper.insert(customer);
260 256 respVO.getCreateCustomerNames().add(importCustomer.getName());
261 257 // 创建数据权限
262 258 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
263 259 .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
  260 + // 记录操作日志
  261 + getSelf().importCustomerLog(customer, false);
264 262 return;
265 263 }
266 264 // 如果存在,判断是否允许更新
... ... @@ -273,10 +271,25 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
273 271 updateCustomer.setId(existCustomer.getId());
274 272 customerMapper.updateById(updateCustomer);
275 273 respVO.getUpdateCustomerNames().add(importCustomer.getName());
  274 + // 记录操作日志
  275 + getSelf().importCustomerLog(updateCustomer, true);
276 276 });
277 277 return respVO;
278 278 }
279 279  
  280 + private static CrmCustomerDO initCustomer(Object customer, Long userId) {
  281 + return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(userId)
  282 + .setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
  283 + }
  284 +
  285 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_IMPORT_SUB_TYPE, bizNo = "{{#customer.id}}",
  286 + success = CRM_CUSTOMER_IMPORT_SUCCESS)
  287 + public void importCustomerLog(CrmCustomerDO customer, boolean isUpdate) {
  288 + // 记录操作日志上下文
  289 + LogRecordContext.putVariable("customer", customer);
  290 + LogRecordContext.putVariable("isUpdate", isUpdate);
  291 + }
  292 +
280 293 private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
281 294 // 校验客户名称不能为空
282 295 if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
... ... @@ -367,15 +380,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
367 380 if (poolConfig == null || !poolConfig.getEnabled()) {
368 381 return 0;
369 382 }
370   - // 1.1 获取没有锁定的不在公海的客户且没有成交的
371   - List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE);
372   - // 1.2 获取没有锁定的不在公海的客户且成交的
373   - // TODO @puhui999:下面也搞到 sql 里去哈;写 or 查询,问题不大的;
374   - List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE);
  383 + // 1.1 获取没有锁定的不在公海的客户
  384 + List<CrmCustomerDO> customerList = customerMapper.selectListByLockAndNotPool(Boolean.FALSE);
375 385 List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
376   - poolCustomerList.addAll(filterList(notDealCustomerList, customer ->
377   - (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
378   - poolCustomerList.addAll(filterList(dealCustomerList, customer -> {
  386 + poolCustomerList.addAll(filterList(customerList, customer ->
  387 + !customer.getDealStatus() && (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
  388 + poolCustomerList.addAll(filterList(customerList, customer -> {
  389 + if (!customer.getDealStatus()) { // 这里只处理成交的
  390 + return false;
  391 + }
379 392 LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
380 393 return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
381 394 }));
... ...