Commit 4418a7bebce6497e63c19d1626f4b772f4025e7a

Authored by puhui999
1 parent ea6752f1

CRM-合同:完善新增合同插入关联的商品

yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -11,6 +11,7 @@ public interface ErrorCodeConstants { @@ -11,6 +11,7 @@ public interface ErrorCodeConstants {
11 11
12 // ========== 合同管理 1-020-000-000 ========== 12 // ========== 合同管理 1-020-000-000 ==========
13 ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); 13 ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
  14 + ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑");
14 15
15 // ========== 线索管理 1-020-001-000 ========== 16 // ========== 线索管理 1-020-001-000 ==========
16 ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); 17 ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java
@@ -89,6 +89,9 @@ public class CrmContractSaveReqVO { @@ -89,6 +89,9 @@ public class CrmContractSaveReqVO {
89 @DiffLogField(name = "备注") 89 @DiffLogField(name = "备注")
90 private String remark; 90 private String remark;
91 91
  92 + @Schema(description = "审批状态", example = "1")
  93 + private Integer auditStatus;
  94 +
92 @Schema(description = "产品列表") 95 @Schema(description = "产品列表")
93 private List<CrmContractProductItem> productItems; 96 private List<CrmContractProductItem> productItems;
94 97
@@ -104,7 +107,7 @@ public class CrmContractSaveReqVO { @@ -104,7 +107,7 @@ public class CrmContractSaveReqVO {
104 107
105 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") 108 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
106 @NotNull(message = "产品数量不能为空") 109 @NotNull(message = "产品数量不能为空")
107 - private Long count; 110 + private Integer count;
108 111
109 @Schema(description = "产品折扣") 112 @Schema(description = "产品折扣")
110 private Integer discountPercent; 113 private Integer discountPercent;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
@@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.crm.service.contract; @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.crm.service.contract;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.ListUtil; 4 import cn.hutool.core.collection.ListUtil;
  5 +import cn.hutool.core.util.ObjUtil;
5 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.number.MoneyUtils;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; 9 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
8 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; 10 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
@@ -10,16 +12,23 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR @@ -10,16 +12,23 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR
10 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; 12 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
11 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; 13 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
12 import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert; 14 import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
  15 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
13 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 16 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
  17 +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
14 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; 18 import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
15 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; 19 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
16 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 20 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
17 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 21 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
18 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; 22 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
19 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService; 23 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService;
  24 +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
  25 +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
  26 +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
20 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; 27 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
21 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 28 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
22 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; 29 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
  30 +import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
  31 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
23 import com.mzt.logapi.context.LogRecordContext; 32 import com.mzt.logapi.context.LogRecordContext;
24 import com.mzt.logapi.service.impl.DiffParseFunction; 33 import com.mzt.logapi.service.impl.DiffParseFunction;
25 import com.mzt.logapi.starter.annotation.LogRecord; 34 import com.mzt.logapi.starter.annotation.LogRecord;
@@ -30,10 +39,14 @@ import org.springframework.validation.annotation.Validated; @@ -30,10 +39,14 @@ import org.springframework.validation.annotation.Validated;
30 39
31 import java.util.Collection; 40 import java.util.Collection;
32 import java.util.List; 41 import java.util.List;
  42 +import java.util.Map;
  43 +import java.util.Set;
33 44
34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 45 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35 -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTRACT_NOT_EXISTS; 46 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  47 +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
36 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; 48 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
  49 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;
37 50
38 /** 51 /**
39 * CRM 合同 Service 实现类 52 * CRM 合同 Service 实现类
@@ -53,16 +66,25 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -53,16 +66,25 @@ public class CrmContractServiceImpl implements CrmContractService {
53 private CrmPermissionService crmPermissionService; 66 private CrmPermissionService crmPermissionService;
54 @Resource 67 @Resource
55 private CrmBusinessProductService businessProductService; 68 private CrmBusinessProductService businessProductService;
56 - 69 + @Resource
  70 + private CrmProductService productService;
57 @Resource 71 @Resource
58 private BpmProcessInstanceApi bpmProcessInstanceApi; 72 private BpmProcessInstanceApi bpmProcessInstanceApi;
  73 + @Resource
  74 + private CrmCustomerService customerService;
  75 + @Resource
  76 + private CrmContactService contactService;
  77 + @Resource
  78 + private CrmBusinessService businessService;
  79 + @Resource
  80 + private AdminUserApi adminUserApi;
59 81
60 @Override 82 @Override
61 @Transactional(rollbackFor = Exception.class) 83 @Transactional(rollbackFor = Exception.class)
62 @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}", 84 @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}",
63 success = CRM_CONTRACT_CREATE_SUCCESS) 85 success = CRM_CONTRACT_CREATE_SUCCESS)
64 public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) { 86 public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) {
65 - // TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO 87 + validateRelationDataExists(createReqVO);
66 // 插入合同 88 // 插入合同
67 CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null); 89 CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
68 contractMapper.insert(contract); 90 contractMapper.insert(contract);
@@ -71,6 +93,10 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -71,6 +93,10 @@ public class CrmContractServiceImpl implements CrmContractService {
71 crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) 93 crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
72 .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) 94 .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId())
73 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); 95 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
  96 +
  97 + // 插入商机关联商品
  98 + List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
  99 + businessProductService.insertBatch(businessProduct);
74 // 4. 记录操作日志上下文 100 // 4. 记录操作日志上下文
75 LogRecordContext.putVariable("contract", contract); 101 LogRecordContext.putVariable("contract", contract);
76 return contract.getId(); 102 return contract.getId();
@@ -83,12 +109,21 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -83,12 +109,21 @@ public class CrmContractServiceImpl implements CrmContractService {
83 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) 109 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
84 public void updateContract(CrmContractSaveReqVO updateReqVO) { 110 public void updateContract(CrmContractSaveReqVO updateReqVO) {
85 // TODO @合同待定:只有草稿、审批中,可以编辑; 111 // TODO @合同待定:只有草稿、审批中,可以编辑;
  112 + if (ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
  113 + ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
  114 + throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
  115 + }
  116 + validateRelationDataExists(updateReqVO);
86 // 校验存在 117 // 校验存在
87 CrmContractDO oldContract = validateContractExists(updateReqVO.getId()); 118 CrmContractDO oldContract = validateContractExists(updateReqVO.getId());
88 // 更新合同 119 // 更新合同
89 CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class); 120 CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
90 contractMapper.updateById(updateObj); 121 contractMapper.updateById(updateObj);
91 - // TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO 122 +
  123 + // TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理?
  124 + //List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
  125 + //businessProductService.selectListByBusinessId()
  126 + //diffList()
92 127
93 // 3. 记录操作日志上下文 128 // 3. 记录操作日志上下文
94 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class)); 129 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
@@ -97,8 +132,55 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -97,8 +132,55 @@ public class CrmContractServiceImpl implements CrmContractService {
97 132
98 // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum 133 // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
99 134
100 - // TODO @合同待定:缺一个发起审批的接口;只有草稿可以发起审批;CrmAuditStatusEnum 135 + private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO) {
  136 + // 校验商品存在
  137 + Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
  138 + List<CrmProductDO> productList = productService.getProductList(productIds);
  139 + if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) {
  140 + throw exception(PRODUCT_NOT_EXISTS);
  141 + }
  142 + Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
  143 + return convertList(reqVO.getProductItems(), productItem -> {
  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;
  148 + });
  149 + }
101 150
  151 + /**
  152 + * 计算商品总价
  153 + *
  154 + * @param businessProduct 关联商品
  155 + * @return 商品总价
  156 + */
  157 + private Integer calculator(CrmBusinessProductDO businessProduct) {
  158 + int price = businessProduct.getPrice() * businessProduct.getCount();
  159 + if (businessProduct.getDiscountPercent() == null) {
  160 + return price;
  161 + }
  162 + return MoneyUtils.calculateRatePriceFloor(price, (double) (businessProduct.getDiscountPercent() / 100));
  163 + }
  164 +
  165 + /**
  166 + * 校验关联数据是否存在
  167 + *
  168 + * @param reqVO 请求
  169 + */
  170 + private void validateRelationDataExists(CrmContractSaveReqVO reqVO) {
  171 + // 1. 校验客户
  172 + if (reqVO.getCustomerId() != null && customerService.getCustomer(reqVO.getCustomerId()) == null) {
  173 + throw exception(CUSTOMER_NOT_EXISTS);
  174 + }
  175 + // 2. 校验负责人
  176 + if (reqVO.getOwnerUserId() != null && adminUserApi.getUser(reqVO.getOwnerUserId()) == null) {
  177 + throw exception(USER_NOT_EXISTS);
  178 + }
  179 + // 4. 如果有关联商机,则需要校验存在
  180 + if (reqVO.getBusinessId() != null && businessService.getBusiness(reqVO.getBusinessId()) == null) {
  181 + throw exception(BUSINESS_NOT_EXISTS);
  182 + }
  183 + }
102 184
103 @Override 185 @Override
104 @Transactional(rollbackFor = Exception.class) 186 @Transactional(rollbackFor = Exception.class)
@@ -151,6 +233,7 @@ public class CrmContractServiceImpl implements CrmContractService { @@ -151,6 +233,7 @@ public class CrmContractServiceImpl implements CrmContractService {
151 } 233 }
152 234
153 @Override 235 @Override
  236 + @Transactional(rollbackFor = Exception.class)
154 public void handleApprove(Long id, Long userId) { 237 public void handleApprove(Long id, Long userId) {
155 // 创建合同审批流程实例 238 // 创建合同审批流程实例
156 String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() 239 String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java
1 package cn.iocoder.yudao.module.crm.service.contract.listener; 1 package cn.iocoder.yudao.module.crm.service.contract.listener;
2 2
3 public class CrmContractResultListener { 3 public class CrmContractResultListener {
  4 + // TODO puhui999: @芋艿: 艿艿写一下这个,没研究明白哈哈
4 } 5 }