📖 CRM:code review 合同的代码实现

This commit is contained in:
YunaiV 2024-02-04 09:41:50 +08:00
parent bb9173f7f0
commit 3347d3320d
17 changed files with 88 additions and 55 deletions

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.api.listener;
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
// TODO @芋艿后续改成支持 RPC
/**
* 业务流程实例的结果发生变化的监听器 Api
*

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.api.listener.dto;
import lombok.Data;
// TODO @芋艿后续改成支持 RPC
/**
* 业务流程实例的结果 Response DTO
*

View File

@ -43,7 +43,8 @@ public class BpmModelController {
return success(model);
}
// TODO @puhui999这个接口的目的是啥呀业务表单预览流程🤣
// TODO @puhui999这个接口的目的是啥呀业务表单预览流程🤣
// TODO @puhui999捉摸是不是搞成前端跳转过去不另外做 bpmn 组件哈
@GetMapping("/get-by-key")
@Operation(summary = "获得模型")
@Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave")

View File

@ -11,6 +11,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
// TODO @芋艿后续改成支持 RPC
/**
* 业务流程结果监听器实现类
*

View File

@ -50,4 +50,5 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
protected void processCompleted(FlowableEngineEntityEvent event) {
processInstanceService.updateProcessInstanceExtComplete((ProcessInstance)event.getEntity());
}
}

View File

@ -99,9 +99,17 @@ public class CrmContractController {
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('crm:contract:query')")
public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) {
// 1. 查询合同
CrmContractDO contract = contractService.getContract(id);
List<CrmContractRespVO> respVOList = buildContractDetail(Collections.singletonList(contract));
CrmContractRespVO respVO = respVOList.getFirst();
if (contract == null) {
return success(null);
}
// 2.1 拼接合同信息
List<CrmContractRespVO> respVOList = buildContractDetailList(Collections.singletonList(contract));
// 2.2 拼接产品信息
// TODO @puhui999下面这块也可以搞到 convert 里哈可以在 ContractDetailList 加个开关是不是查询商品信息psjdk21 的方法不太能去用因为 jdk8 项目要兼容
CrmContractRespVO respVO = respVOList.get(0);
List<CrmBusinessProductDO> businessProductList = businessProductService.getBusinessProductListByContractId(id);
Map<Long, CrmBusinessProductDO> businessProductMap = convertMap(businessProductList, CrmBusinessProductDO::getProductId);
List<CrmProductDO> productList = productService.getProductListByIds(convertSet(businessProductList, CrmBusinessProductDO::getProductId));
@ -120,7 +128,7 @@ public class CrmContractController {
@PreAuthorize("@ss.hasPermission('crm:contract:query')")
public CommonResult<PageResult<CrmContractRespVO>> getContractPage(@Valid CrmContractPageReqVO pageVO) {
PageResult<CrmContractDO> pageResult = contractService.getContractPage(pageVO, getLoginUserId());
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetail(pageResult.getList())));
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList())));
}
@GetMapping("/page-by-customer")
@ -128,7 +136,7 @@ public class CrmContractController {
public CommonResult<PageResult<CrmContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) {
Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空");
PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageVO);
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetail(pageResult.getList())));
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList())));
}
@GetMapping("/export-excel")
@ -149,7 +157,7 @@ public class CrmContractController {
* @param contractList 原始合同信息
* @return 细的合同结果
*/
private List<CrmContractRespVO> buildContractDetail(List<CrmContractDO> contractList) {
private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) {
if (CollUtil.isEmpty(contractList)) {
return Collections.emptyList();
}

View File

@ -133,25 +133,25 @@ public class CrmContractRespVO {
@AllArgsConstructor
public static class CrmContractProductItemRespVO {
@Schema(description = "产品编号", example = "20529")
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
private Long id;
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是产品")
private String name;
@Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
@Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "N881")
private String no;
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer unit;
@Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
@Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private Integer price;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer count;
@Schema(description = "产品折扣")
@Schema(description = "产品折扣", example = "99")
private Integer discountPercent;
}

View File

@ -188,6 +188,7 @@ public class CrmCustomerController {
new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName())));
}
// TODO @puhui999公海的导出前端可以接下
@GetMapping("/export-excel")
@Operation(summary = "导出客户 Excel")
@PreAuthorize("@ss.hasPermission('crm:customer:export')")

View File

@ -41,6 +41,7 @@ public class CrmBusinessProductDO extends BaseDO {
* 关联 {@link CrmProductDO#getId()}
*/
private Long productId;
// TODO 芋艿需要在看下 CRM
/**
* 合同编号
*

View File

@ -38,6 +38,7 @@ public interface CrmProductMapper extends BaseMapperX<CrmProductDO> {
return selectOne(CrmProductDO::getNo, no);
}
// TODO @puhui999selectBatchIds
default List<CrmProductDO> selectListByIds(Collection<Long> ids) {
return selectList(new LambdaQueryWrapperX<CrmProductDO>().in(CrmProductDO::getId, ids));
}

View File

@ -4,8 +4,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
import java.util.List;
// TODO @lzxhqs方法名上带下 BusinessProduct主要考虑不精简的原因是因为一个逻辑可能会出现一些超越它自身方法省略不容易懂
/**
* 商机产品关联表 Service 接口
*
@ -20,13 +18,6 @@ public interface CrmBusinessProductService {
*/
void createBusinessProductBatch(List<CrmBusinessProductDO> list);
/**
* 根据商机id获取商机产品关联数据集合
*
* @param businessId 商机id
*/
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
/**
* 批量更新商机产品表
*
@ -42,14 +33,21 @@ public interface CrmBusinessProductService {
void deleteBusinessProductBatch(List<CrmBusinessProductDO> list);
/**
* 根据商机id删除商机产品关联数据
* 根据商机编号删除商机产品关联数据
*
* @param businessId 商机id
*/
void deleteBusinessProductByBusinessId(Long businessId);
/**
* 获得合同关联的商品列表
* 根据商机编号获取商机产品关联数据集合
*
* @param businessId 商机编号
*/
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
/**
* 根据合同编号获得合同关联的商品列表
*
* @param contractId 合同编号
* @return 关联的商品列表

View File

@ -26,17 +26,12 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
businessProductMapper.insertBatch(list);
}
@Override
public List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId) {
return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId, businessId);
}
@Override
public void updateBusinessProductBatch(List<CrmBusinessProductDO> list) {
businessProductMapper.updateBatch(list);
}
// TODO @lzxhqs这个方法可以直接调用 deleteList 方法然后传递 ids 就好了
// TODO @puhui999这个方法可以直接调用 deleteList 方法然后传递 ids 就好了
@Override
public void deleteBusinessProductBatch(List<CrmBusinessProductDO> list) {
businessProductMapper.deleteBatchIds(CollectionUtils.convertList(list, CrmBusinessProductDO::getId));
@ -52,4 +47,9 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
return businessProductMapper.selectList(CrmBusinessProductDO::getContractId, contractId);
}
@Override
public List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId) {
return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId, businessId);
}
}

View File

@ -195,9 +195,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
* @author lzxhqs
*/
private void validateContractExists(Long businessId) {
// TODO @lzxhqs保持风格的统一selectCountByBusinessId 改成 getContractCountByBusinessId另外可以不用声明 count因为就一次性使用直接把 197 198 合并成一行
Long count = contractService.getContractCountByBusinessId(businessId);
if (count > 0) {
if (contractService.getContractCountByBusinessId(businessId) > 0) {
throw exception(BUSINESS_CONTRACT_EXISTS);
}
}

View File

@ -72,6 +72,7 @@ public interface CrmContractService {
* @param event 审批结果
*/
void updateContractAuditStatus(BpmResultListenerRespDTO event);
/**
* 获得合同
*

View File

@ -113,24 +113,24 @@ public class CrmContractServiceImpl implements CrmContractService {
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateContract(CrmContractSaveReqVO updateReqVO) {
Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
// 1.1 校验存在
CrmContractDO contract = validateContractExists(updateReqVO.getId());
// 只有草稿审批中可以编辑
// 1.2 只有草稿审批中可以编辑
if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
CrmAuditStatusEnum.PROCESS.getStatus())) {
throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
}
validateRelationDataExists(updateReqVO);
// 校验存在
CrmContractDO oldContract = validateContractExists(updateReqVO.getId());
// 更新合同
// 2.1 更新合同
CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
contractMapper.updateById(updateObj);
// 更新合同关联商品
// 2.2 更新合同关联商品
updateContractProduct(updateReqVO, updateObj.getId());
// 3. 记录操作日志上下文
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
LogRecordContext.putVariable("contractName", oldContract.getName());
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class));
LogRecordContext.putVariable("contractName", contract.getName());
}
private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {
@ -248,23 +248,26 @@ public class CrmContractServiceImpl implements CrmContractService {
@Override
@Transactional(rollbackFor = Exception.class)
// TODO @puhui999操作日志
public void submitContract(Long id, Long userId) {
// 1. 校验合同是否在审批
CrmContractDO contract = validateContractExists(id);
if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) {
throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);
}
// 创建合同审批流程实例
// 2. 创建合同审批流程实例
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
.setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));
// 更新合同工作流编号
// 3. 更新合同工作流编号
contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId)
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
}
@Override
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
// TODO @puhui999可能要判断下状态是否符合预期
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
.setAuditStatus(event.getResult()));
}

View File

@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
// TODO @芋艿后续改成支持 RPC
/**
* 合同审批的结果的监听器实现类
*

View File

@ -105,6 +105,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
return customer.getId();
}
/**
* 初始化客户的通用字段
*
* @param customer 客户信息
* @param ownerUserId 负责人编号
* @return 客户信息 DO
*/
private static CrmCustomerDO initCustomer(Object customer, Long ownerUserId) {
return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(ownerUserId)
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
@ -248,44 +260,47 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
respVO.getFailureCustomerNames().put(importCustomer.getName(), ex.getMessage());
return;
}
// 判断如果不存在在进行插入
// 情况一判断如果不存在在进行插入
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
if (existCustomer == null) {
// 1.1 插入客户信息
CrmCustomerDO customer = initCustomer(importCustomer, userId);
customerMapper.insert(customer);
respVO.getCreateCustomerNames().add(importCustomer.getName());
// 创建数据权限
// 1.2 创建数据权限
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
// 记录操作日志
// 1.3 记录操作日志
getSelf().importCustomerLog(customer, false);
return;
}
// 如果存在判断是否允许更新
// 情况二如果存在判断是否允许更新
if (!isUpdateSupport) {
respVO.getFailureCustomerNames().put(importCustomer.getName(),
StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName()));
return;
}
CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class);
updateCustomer.setId(existCustomer.getId());
// 2.1 更新客户信息
CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class)
.setId(existCustomer.getId());
customerMapper.updateById(updateCustomer);
respVO.getUpdateCustomerNames().add(importCustomer.getName());
// 记录操作日志
// 2.2 记录操作日志
getSelf().importCustomerLog(updateCustomer, true);
});
return respVO;
}
private static CrmCustomerDO initCustomer(Object customer, Long userId) {
return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(userId)
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
}
/**
* 记录导入客户时的操作日志
*
* @param customer 客户信息
* @param isUpdate 是否更新true - 更新false - 新增
*/
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_IMPORT_SUB_TYPE, bizNo = "{{#customer.id}}",
success = CRM_CUSTOMER_IMPORT_SUCCESS)
public void importCustomerLog(CrmCustomerDO customer, boolean isUpdate) {
// 记录操作日志上下文
LogRecordContext.putVariable("customer", customer);
LogRecordContext.putVariable("isUpdate", isUpdate);
}
@ -382,6 +397,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
}
// 1.1 获取没有锁定的不在公海的客户
List<CrmCustomerDO> customerList = customerMapper.selectListByLockAndNotPool(Boolean.FALSE);
// TODO @puhui999下面也搞到 sql 里去哈 or 查询问题不大的 393 402原因是避免无用的太多数据查询到 java 进程里
List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
poolCustomerList.addAll(filterList(customerList, customer ->
!customer.getDealStatus() && (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));