Commit f5f827b59fa08f2e2bab5c76c978df5f409e8e42
1 parent
acb8d3f2
📖 CRM:code review 合同流程
Showing
10 changed files
with
39 additions
and
28 deletions
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
| ... | ... | @@ -43,6 +43,7 @@ public class BpmModelController { |
| 43 | 43 | return success(model); |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | + // TODO @puhui999:这个接口的目的是啥呀? | |
| 46 | 47 | @GetMapping("/get-by-key") |
| 47 | 48 | @Operation(summary = "获得模型") |
| 48 | 49 | @Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave") | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
| ... | ... | @@ -132,6 +132,7 @@ public class CrmContractController { |
| 132 | 132 | return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList); |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | + // TODO @puhui999:transferContract | |
| 135 | 136 | @PutMapping("/transfer") |
| 136 | 137 | @Operation(summary = "合同转移") |
| 137 | 138 | @PreAuthorize("@ss.hasPermission('crm:contract:update')") |
| ... | ... | @@ -140,6 +141,7 @@ public class CrmContractController { |
| 140 | 141 | return success(true); |
| 141 | 142 | } |
| 142 | 143 | |
| 144 | + // TODO @puhui999:方法名不对哈;要不改成 submit?提交审核的意思 | |
| 143 | 145 | @PutMapping("/approve") |
| 144 | 146 | @Operation(summary = "发起合同审批流程") |
| 145 | 147 | @PreAuthorize("@ss.hasPermission('crm:contract:update')") | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
| ... | ... | @@ -217,6 +217,8 @@ public class CrmCustomerController { |
| 217 | 217 | ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list); |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | + // TODO @puhui999:updateSupport 要不改成前端必须传递;哈哈哈,代码排版看着有点乱; | |
| 221 | + // TODO @puhui999:加一个选择负责人;允许空,空就进入公海; | |
| 220 | 222 | @PostMapping("/import") |
| 221 | 223 | @Operation(summary = "导入客户") |
| 222 | 224 | @Parameters({ |
| ... | ... | @@ -224,13 +226,12 @@ public class CrmCustomerController { |
| 224 | 226 | @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") |
| 225 | 227 | }) |
| 226 | 228 | @PreAuthorize("@ss.hasPermission('system:customer:import')") |
| 227 | - public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file, | |
| 228 | - @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { | |
| 229 | + public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) | |
| 230 | + throws Exception { | |
| 229 | 231 | List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class); |
| 230 | 232 | return success(customerService.importCustomerList(list, updateSupport, getLoginUserId())); |
| 231 | 233 | } |
| 232 | 234 | |
| 233 | - | |
| 234 | 235 | @PutMapping("/transfer") |
| 235 | 236 | @Operation(summary = "转移客户") |
| 236 | 237 | @PreAuthorize("@ss.hasPermission('crm:customer:update')") | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerImportExcelVO.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | 5 | import com.alibaba.excel.annotation.ExcelProperty; |
| 6 | -import jakarta.validation.constraints.Size; | |
| 7 | 6 | import lombok.AllArgsConstructor; |
| 8 | 7 | import lombok.Builder; |
| 9 | 8 | import lombok.Data; |
| ... | ... | @@ -25,6 +24,7 @@ public class CrmCustomerImportExcelVO { |
| 25 | 24 | @ExcelProperty("客户名称") |
| 26 | 25 | private String name; |
| 27 | 26 | |
| 27 | + // TODO @puhui999:industryId、level、source 字段,可以研究下怎么搞下拉框 | |
| 28 | 28 | @ExcelProperty(value = "所属行业", converter = DictConvert.class) |
| 29 | 29 | @DictFormat(CRM_CUSTOMER_INDUSTRY) |
| 30 | 30 | private Integer industryId; |
| ... | ... | @@ -46,25 +46,22 @@ public class CrmCustomerImportExcelVO { |
| 46 | 46 | @ExcelProperty("网址") |
| 47 | 47 | private String website; |
| 48 | 48 | |
| 49 | - @Size(max = 20, message = "QQ长度不能超过 20 个字符") | |
| 50 | 49 | @ExcelProperty("QQ") |
| 51 | 50 | private String qq; |
| 52 | 51 | |
| 53 | - @Size(max = 255, message = "微信长度不能超过 255 个字符") | |
| 54 | 52 | @ExcelProperty("微信") |
| 55 | 53 | private String wechat; |
| 56 | 54 | |
| 57 | - @Size(max = 255, message = "邮箱长度不能超过 255 个字符") | |
| 58 | 55 | @ExcelProperty("邮箱") |
| 59 | 56 | private String email; |
| 60 | 57 | |
| 61 | - @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") | |
| 62 | 58 | @ExcelProperty("客户描述") |
| 63 | 59 | private String description; |
| 64 | 60 | |
| 65 | 61 | @ExcelProperty("备注") |
| 66 | 62 | private String remark; |
| 67 | 63 | |
| 64 | + // TODO @puhui999:需要选择省市区,需要研究下,怎么搞合理点; | |
| 68 | 65 | @ExcelProperty("地区编号") |
| 69 | 66 | private Integer areaId; |
| 70 | 67 | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
| ... | ... | @@ -22,7 +22,6 @@ import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| 22 | 22 | import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; |
| 23 | 23 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService; |
| 24 | 24 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; |
| 25 | -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; | |
| 26 | 25 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 27 | 26 | import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; |
| 28 | 27 | import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; |
| ... | ... | @@ -69,15 +68,14 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 69 | 68 | @Resource |
| 70 | 69 | private CrmProductService productService; |
| 71 | 70 | @Resource |
| 72 | - private BpmProcessInstanceApi bpmProcessInstanceApi; | |
| 73 | - @Resource | |
| 74 | 71 | private CrmCustomerService customerService; |
| 75 | 72 | @Resource |
| 76 | - private CrmContactService contactService; | |
| 77 | - @Resource | |
| 78 | 73 | private CrmBusinessService businessService; |
| 74 | + | |
| 79 | 75 | @Resource |
| 80 | 76 | private AdminUserApi adminUserApi; |
| 77 | + @Resource | |
| 78 | + private BpmProcessInstanceApi bpmProcessInstanceApi; | |
| 81 | 79 | |
| 82 | 80 | @Override |
| 83 | 81 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -85,19 +83,19 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 85 | 83 | success = CRM_CONTRACT_CREATE_SUCCESS) |
| 86 | 84 | public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) { |
| 87 | 85 | validateRelationDataExists(createReqVO); |
| 88 | - // 插入合同 | |
| 86 | + // 1.1 插入合同 | |
| 89 | 87 | CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null); |
| 90 | 88 | contractMapper.insert(contract); |
| 89 | + // 1.2 插入商机关联商品 | |
| 90 | + List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO); | |
| 91 | + businessProductService.insertBatch(businessProduct); | |
| 91 | 92 | |
| 92 | - // 创建数据权限 | |
| 93 | + // 2. 创建数据权限 | |
| 93 | 94 | crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) |
| 94 | 95 | .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) |
| 95 | 96 | .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); |
| 96 | 97 | |
| 97 | - // 插入商机关联商品 | |
| 98 | - List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO); | |
| 99 | - businessProductService.insertBatch(businessProduct); | |
| 100 | - // 4. 记录操作日志上下文 | |
| 98 | + // 3. 记录操作日志上下文 | |
| 101 | 99 | LogRecordContext.putVariable("contract", contract); |
| 102 | 100 | return contract.getId(); |
| 103 | 101 | } |
| ... | ... | @@ -121,6 +119,7 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 121 | 119 | contractMapper.updateById(updateObj); |
| 122 | 120 | |
| 123 | 121 | // TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理? |
| 122 | + // TODO @puhui999:和商品 spu、sku 编辑一样;新增的插入;修改的更新;删除的删除 | |
| 124 | 123 | //List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO); |
| 125 | 124 | //businessProductService.selectListByBusinessId() |
| 126 | 125 | //diffList() |
| ... | ... | @@ -141,6 +140,7 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 141 | 140 | } |
| 142 | 141 | Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId); |
| 143 | 142 | return convertList(reqVO.getProductItems(), productItem -> { |
| 143 | + // TODO @puhui999:这里可以改成直接 return,不用弄一个 businessProduct 变量哈; | |
| 144 | 144 | CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class); |
| 145 | 145 | businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()) |
| 146 | 146 | .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct)); |
| ... | ... | @@ -154,6 +154,7 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 154 | 154 | * @param businessProduct 关联商品 |
| 155 | 155 | * @return 商品总价 |
| 156 | 156 | */ |
| 157 | + // TODO @puhui999:这个逻辑的计算,是不是可以封装到 calculateRatePriceFloor 里; | |
| 157 | 158 | private Integer calculator(CrmBusinessProductDO businessProduct) { |
| 158 | 159 | int price = businessProduct.getPrice() * businessProduct.getCount(); |
| 159 | 160 | if (businessProduct.getDiscountPercent() == null) { |
| ... | ... | @@ -176,7 +177,7 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 176 | 177 | if (reqVO.getOwnerUserId() != null && adminUserApi.getUser(reqVO.getOwnerUserId()) == null) { |
| 177 | 178 | throw exception(USER_NOT_EXISTS); |
| 178 | 179 | } |
| 179 | - // 4. 如果有关联商机,则需要校验存在 | |
| 180 | + // 3. 如果有关联商机,则需要校验存在 | |
| 180 | 181 | if (reqVO.getBusinessId() != null && businessService.getBusiness(reqVO.getBusinessId()) == null) { |
| 181 | 182 | throw exception(BUSINESS_NOT_EXISTS); |
| 182 | 183 | } |
| ... | ... | @@ -235,6 +236,8 @@ public class CrmContractServiceImpl implements CrmContractService { |
| 235 | 236 | @Override |
| 236 | 237 | @Transactional(rollbackFor = Exception.class) |
| 237 | 238 | public void handleApprove(Long id, Long userId) { |
| 239 | + // TODO @puhui999:需要做状态检查 | |
| 240 | + | |
| 238 | 241 | // 创建合同审批流程实例 |
| 239 | 242 | String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() |
| 240 | 243 | .setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id))); | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
| ... | ... | @@ -232,8 +232,10 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 232 | 232 | return customer.getId(); |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | + // TODO @puhui999:操作日志 | |
| 235 | 236 | @Override |
| 236 | - public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId) { | |
| 237 | + public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, | |
| 238 | + Boolean isUpdateSupport, Long userId) { | |
| 237 | 239 | if (CollUtil.isEmpty(importCustomers)) { |
| 238 | 240 | throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY); |
| 239 | 241 | } |
| ... | ... | @@ -241,6 +243,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 241 | 243 | .updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build(); |
| 242 | 244 | importCustomers.forEach(importCustomer -> { |
| 243 | 245 | // 校验,判断是否有不符合的原因 |
| 246 | + // TODO @puhui999:可以用 ValidationUtils 做参数校验;可能要封装一个方法,返回 message;这样的话,就可以在 CrmCustomerImportExcelVO 写需要校验的参数啦; | |
| 244 | 247 | try { |
| 245 | 248 | validateCustomerForCreate(importCustomer); |
| 246 | 249 | } catch (ServiceException ex) { |
| ... | ... | @@ -250,6 +253,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 250 | 253 | // 判断如果不存在,在进行插入 |
| 251 | 254 | CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName()); |
| 252 | 255 | if (existCustomer == null) { |
| 256 | + // TODO @puhui999:可以搞个 initCustomer 方法;这样可以把 create 和导入复用下这个方法; | |
| 253 | 257 | CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId) |
| 254 | 258 | .setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now()); |
| 255 | 259 | customerMapper.insert(customer); |
| ... | ... | @@ -366,6 +370,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 366 | 370 | // 1.1 获取没有锁定的不在公海的客户且没有成交的 |
| 367 | 371 | List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE); |
| 368 | 372 | // 1.2 获取没有锁定的不在公海的客户且成交的 |
| 373 | + // TODO @puhui999:下面也搞到 sql 里去哈;写 or 查询,问题不大的; | |
| 369 | 374 | List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE); |
| 370 | 375 | List<CrmCustomerDO> poolCustomerList = new ArrayList<>(); |
| 371 | 376 | poolCustomerList.addAll(filterList(notDealCustomerList, customer -> |
| ... | ... | @@ -382,7 +387,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 382 | 387 | getSelf().putCustomerPool(customer); |
| 383 | 388 | count++; |
| 384 | 389 | } catch (Throwable e) { |
| 385 | - log.error("[customerAutoPutPoolBySystem][Customer 客户({}) 放入公海异常]", customer.getId(), e); | |
| 390 | + log.error("[autoPutCustomerPool][Customer 客户({}) 放入公海异常]", customer.getId(), e); | |
| 386 | 391 | } |
| 387 | 392 | } |
| 388 | 393 | return count; | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java
| ... | ... | @@ -109,14 +109,14 @@ public interface CrmPermissionService { |
| 109 | 109 | List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId); |
| 110 | 110 | |
| 111 | 111 | /** |
| 112 | - * 校验权限 | |
| 112 | + * 校验是否有指定数据的操作权限 | |
| 113 | 113 | * |
| 114 | 114 | * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} |
| 115 | 115 | * @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() |
| 116 | 116 | * @param userId 用户编号 |
| 117 | - * @param levelEnum 权限级别 | |
| 118 | - * @return boolean | |
| 117 | + * @param level 权限级别 | |
| 118 | + * @return 是否有权限 | |
| 119 | 119 | */ |
| 120 | - boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum); | |
| 120 | + boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level); | |
| 121 | 121 | |
| 122 | 122 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
| ... | ... | @@ -213,10 +213,10 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { |
| 213 | 213 | } |
| 214 | 214 | |
| 215 | 215 | @Override |
| 216 | - public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum) { | |
| 216 | + public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level) { | |
| 217 | 217 | List<CrmPermissionDO> permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId); |
| 218 | 218 | return anyMatch(permissionList, permission -> |
| 219 | - ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), levelEnum.getLevel())); | |
| 219 | + ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), level.getLevel())); | |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | } | ... | ... |