Commit 4418a7bebce6497e63c19d1626f4b772f4025e7a
1 parent
ea6752f1
CRM-合同:完善新增合同插入关联的商品
Showing
4 changed files
with
94 additions
and
6 deletions
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