CRM-CONTRACT: 完善 TODO

This commit is contained in:
puhui999 2024-02-03 12:29:28 +08:00
parent 1a96fb2ffc
commit 59e6f23788
16 changed files with 171 additions and 71 deletions

View File

@ -35,6 +35,22 @@ public class MoneyUtils {
return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue(); return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue();
} }
/**
* 计算百分比金额
*
* @param price 金额单位分
* @param count 数量
* @param percent 折扣单位分列如 60.2%则传入 6020
* @return 商品总价
*/
public static Integer calculator(Integer price, Integer count, Integer percent) {
price = price * count;
if (percent == null) {
return price;
}
return MoneyUtils.calculateRatePriceFloor(price, (double) (percent / 100));
}
/** /**
* 计算百分比金额 * 计算百分比金额
* *

View File

@ -43,7 +43,7 @@ public class BpmModelController {
return success(model); return success(model);
} }
// TODO @puhui999这个接口的目的是啥呀 // TODO @puhui999这个接口的目的是啥呀业务表单预览流程🤣
@GetMapping("/get-by-key") @GetMapping("/get-by-key")
@Operation(summary = "获得模型") @Operation(summary = "获得模型")
@Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave") @Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave")

View File

@ -12,6 +12,7 @@ public interface ErrorCodeConstants {
// ========== 合同管理 1-020-000-000 ========== // ========== 合同管理 1-020-000-000 ==========
ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑"); ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑");
ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态");
// ========== 线索管理 1-020-001-000 ========== // ========== 线索管理 1-020-001-000 ==========
ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");

View File

@ -39,6 +39,8 @@ public interface LogRecordConstants {
String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海"; String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海";
String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}"; String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}";
String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}";
String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}";
String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}";
// ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 =======================

View File

@ -132,21 +132,19 @@ public class CrmContractController {
return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList); return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList);
} }
// TODO @puhui999transferContract @PutMapping("/transfer-contract")
@PutMapping("/transfer")
@Operation(summary = "合同转移") @Operation(summary = "合同转移")
@PreAuthorize("@ss.hasPermission('crm:contract:update')") @PreAuthorize("@ss.hasPermission('crm:contract:update')")
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmContractTransferReqVO reqVO) { public CommonResult<Boolean> transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
contractService.transferContract(reqVO, getLoginUserId()); contractService.transferContract(reqVO, getLoginUserId());
return success(true); return success(true);
} }
// TODO @puhui999方法名不对哈要不改成 submit提交审核的意思 @PutMapping("/submit")
@PutMapping("/approve") @Operation(summary = "提交合同审批")
@Operation(summary = "发起合同审批流程")
@PreAuthorize("@ss.hasPermission('crm:contract:update')") @PreAuthorize("@ss.hasPermission('crm:contract:update')")
public CommonResult<Boolean> transfer(@RequestParam("id") Long id) { public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
contractService.handleApprove(id, getLoginUserId()); contractService.submitContract(id, getLoginUserId());
return success(true); return success(true);
} }

View File

@ -89,9 +89,6 @@ public class CrmContractSaveReqVO {
@DiffLogField(name = "备注") @DiffLogField(name = "备注")
private String remark; private String remark;
// TODO @puhui999这个字段按道理不用传递
@Schema(description = "审批状态", example = "1")
private Integer auditStatus;
@Schema(description = "产品列表") @Schema(description = "产品列表")
private List<CrmContractProductItem> productItems; private List<CrmContractProductItem> productItems;

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.business; package cn.iocoder.yudao.module.crm.dal.dataobject.business;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
@ -40,6 +41,12 @@ public class CrmBusinessProductDO extends BaseDO {
* 关联 {@link CrmProductDO#getId()} * 关联 {@link CrmProductDO#getId()}
*/ */
private Long productId; private Long productId;
/**
* 合同编号
*
* 关联 {@link CrmContractDO#getId()}
*/
private Long contractId;
/** /**
* 产品单价 * 产品单价

View File

@ -45,7 +45,7 @@ public class CrmProductDO extends BaseDO {
/** /**
* 价格单位 * 价格单位
*/ */
private Long price; private Integer price;
/** /**
* 状态 * 状态
* *

View File

@ -101,10 +101,9 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
} }
default List<CrmCustomerDO> selectListByLockAndDealStatusAndNotPool(Boolean lockStatus, Boolean dealStatus) { default List<CrmCustomerDO> selectListByLockAndNotPool(Boolean lockStatus) {
return selectList(new LambdaQueryWrapper<CrmCustomerDO>() return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getLockStatus, lockStatus) .eq(CrmCustomerDO::getLockStatus, lockStatus)
.eq(CrmCustomerDO::getDealStatus, dealStatus)
.gt(CrmCustomerDO::getOwnerUserId, 0)); .gt(CrmCustomerDO::getOwnerUserId, 0));
} }

View File

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

View File

@ -47,4 +47,9 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
businessProductMapper.deleteByBusinessId(businessId); businessProductMapper.deleteByBusinessId(businessId);
} }
@Override
public List<CrmBusinessProductDO> selectListByContractId(Long contractId) {
return businessProductMapper.selectList(CrmBusinessProductDO::getContractId, contractId);
}
} }

View File

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

View File

@ -64,7 +64,7 @@ public interface CrmContractService {
* @param id 合同编号 * @param id 合同编号
* @param userId 用户编号 * @param userId 用户编号
*/ */
void handleApprove(Long id, Long userId); void submitContract(Long id, Long userId);
/** /**
* 更新合同流程审批结果 * 更新合同流程审批结果
@ -125,13 +125,12 @@ public interface CrmContractService {
*/ */
Long getContractCountByCustomerId(Long customerId); Long getContractCountByCustomerId(Long customerId);
// TODO @puhui999要不改成 getContractCountByBusinessId
/** /**
* 根据商机ID获取关联客户的合同数量 * 根据商机ID获取关联客户的合同数量
* *
* @param businessId 商机编号 * @param businessId 商机编号
* @return 数量 * @return 数量
*/ */
Long selectCountByBusinessId(Long businessId); Long getContractCountByBusinessId(Long businessId);
} }

View File

@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.crm.service.contract;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
@ -87,8 +89,10 @@ public class CrmContractServiceImpl implements CrmContractService {
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null); CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
contractMapper.insert(contract); contractMapper.insert(contract);
// 1.2 插入商机关联商品 // 1.2 插入商机关联商品
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO); if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO, contract.getId());
businessProductService.insertBatch(businessProduct); businessProductService.insertBatch(businessProduct);
}
// 2. 创建数据权限 // 2. 创建数据权限
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
@ -106,9 +110,11 @@ public class CrmContractServiceImpl implements CrmContractService {
success = CRM_CONTRACT_UPDATE_SUCCESS) success = CRM_CONTRACT_UPDATE_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateContract(CrmContractSaveReqVO updateReqVO) { public void updateContract(CrmContractSaveReqVO updateReqVO) {
// TODO @合同待定只有草稿审批中可以编辑 Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
if (ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) || CrmContractDO contract = validateContractExists(updateReqVO.getId());
ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { // 只有草稿审批中可以编辑
if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED); throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
} }
validateRelationDataExists(updateReqVO); validateRelationDataExists(updateReqVO);
@ -117,21 +123,41 @@ public class CrmContractServiceImpl implements CrmContractService {
// 更新合同 // 更新合同
CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class); CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
contractMapper.updateById(updateObj); contractMapper.updateById(updateObj);
// 更新合同关联商品
// TODO puhui999: @芋艿合同变更关联的商机后商品怎么处理 updateContractProduct(updateReqVO, updateObj.getId());
// TODO @puhui999和商品 spusku 编辑一样新增的插入修改的更新删除的删除
//List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
//businessProductService.selectListByBusinessId()
//diffList()
// 3. 记录操作日志上下文 // 3. 记录操作日志上下文
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class)); LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
LogRecordContext.putVariable("contractName", oldContract.getName()); LogRecordContext.putVariable("contractName", oldContract.getName());
} }
private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {
if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
return;
}
List<CrmBusinessProductDO> newProductList = convertBusinessProductList(updateReqVO, contractId);
List<CrmBusinessProductDO> oldProductList = businessProductService.selectListByContractId(contractId);
List<List<CrmBusinessProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {
if (ObjUtil.notEqual(oldObj.getProductId(), newObj.getProductId())) {
return false;
}
newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用
return true;
});
if (CollUtil.isNotEmpty(diffList.getFirst())) {
businessProductService.insertBatch(diffList.getFirst());
}
if (CollUtil.isNotEmpty(diffList.get(1))) {
businessProductService.updateBatch(diffList.get(1));
}
if (CollUtil.isNotEmpty(diffList.get(2))) {
businessProductService.deleteBatch(diffList.get(2));
}
}
// TODO @合同待定缺一个取消合同的接口只有草稿审批中可以取消CrmAuditStatusEnum // TODO @合同待定缺一个取消合同的接口只有草稿审批中可以取消CrmAuditStatusEnum
private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO) { private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO, Long contractId) {
// 校验商品存在 // 校验商品存在
Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId); Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
List<CrmProductDO> productList = productService.getProductList(productIds); List<CrmProductDO> productList = productService.getProductList(productIds);
@ -140,29 +166,14 @@ public class CrmContractServiceImpl implements CrmContractService {
} }
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId); Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
return convertList(reqVO.getProductItems(), productItem -> { return convertList(reqVO.getProductItems(), productItem -> {
// TODO @puhui999这里可以改成直接 return不用弄一个 businessProduct 变量哈 CrmProductDO product = productMap.get(productItem.getId());
CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class); return BeanUtils.toBean(product, CrmBusinessProductDO.class)
businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()) .setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()).setContractId(contractId)
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct)); .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
return businessProduct; .setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
}); });
} }
/**
* 计算商品总价
*
* @param businessProduct 关联商品
* @return 商品总价
*/
// TODO @puhui999这个逻辑的计算是不是可以封装到 calculateRatePriceFloor
private Integer calculator(CrmBusinessProductDO businessProduct) {
int price = businessProduct.getPrice() * businessProduct.getCount();
if (businessProduct.getDiscountPercent() == null) {
return price;
}
return MoneyUtils.calculateRatePriceFloor(price, (double) (businessProduct.getDiscountPercent() / 100));
}
/** /**
* 校验关联数据是否存在 * 校验关联数据是否存在
* *
@ -235,9 +246,12 @@ public class CrmContractServiceImpl implements CrmContractService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void handleApprove(Long id, Long userId) { public void submitContract(Long id, Long userId) {
// TODO @puhui999需要做状态检查 // 1. 校验合同是否在审批
CrmContractDO contract = validateContractExists(id);
if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) {
throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);
}
// 创建合同审批流程实例 // 创建合同审批流程实例
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
.setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id))); .setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));
@ -247,6 +261,12 @@ public class CrmContractServiceImpl implements CrmContractService {
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
} }
@Override
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
.setAuditStatus(event.getResult()));
}
//======================= 查询相关 ======================= //======================= 查询相关 =======================
@Override @Override
@ -285,7 +305,7 @@ public class CrmContractServiceImpl implements CrmContractService {
} }
@Override @Override
public Long selectCountByBusinessId(Long businessId) { public Long getContractCountByBusinessId(Long businessId) {
return contractMapper.selectCountByBusinessId(businessId); return contractMapper.selectCountByBusinessId(businessId);
} }
// TODO @合同待定需要新增一个 ContractConfigDO 合同配置重点是到期提醒 // TODO @合同待定需要新增一个 ContractConfigDO 合同配置重点是到期提醒

View File

@ -1,7 +1,11 @@
package cn.iocoder.yudao.module.crm.service.contract.listener; package cn.iocoder.yudao.module.crm.service.contract.listener;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi; import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi;
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl; import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -25,7 +29,31 @@ public class CrmContractResultListener implements BpmResultListenerApi {
@Override @Override
public void onEvent(BpmResultListenerRespDTO event) { public void onEvent(BpmResultListenerRespDTO event) {
boolean currentTaskFinish = isEndResult(event.getResult());
if (!currentTaskFinish) {
return;
}
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) {
event.setResult(CrmAuditStatusEnum.APPROVE.getStatus());
}
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) {
event.setResult(CrmAuditStatusEnum.REJECT.getStatus());
}
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) {
event.setResult(CrmAuditStatusEnum.CANCEL.getStatus());
}
contractService.updateContractAuditStatus(event); contractService.updateContractAuditStatus(event);
} }
/**
* 判断该结果是否处于 End 最终结果
*
* @param result 结果
* @return 是否
*/
public static boolean isEndResult(Integer result) {
return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
}
} }

View File

@ -93,8 +93,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1); validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
// 2. 插入客户 // 2. 插入客户
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class).setOwnerUserId(userId) CrmCustomerDO customer = initCustomer(createReqVO, userId);
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
customerMapper.insert(customer); customerMapper.insert(customer);
// 3. 创建数据权限 // 3. 创建数据权限
@ -232,7 +231,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
return customer.getId(); return customer.getId();
} }
// TODO @puhui999操作日志
@Override @Override
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
Boolean isUpdateSupport, Long userId) { Boolean isUpdateSupport, Long userId) {
@ -253,14 +251,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
// 判断如果不存在在进行插入 // 判断如果不存在在进行插入
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName()); CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
if (existCustomer == null) { if (existCustomer == null) {
// TODO @puhui999可以搞个 initCustomer 方法这样可以把 create 和导入复用下这个方法 CrmCustomerDO customer = initCustomer(importCustomer, userId);
CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId)
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
customerMapper.insert(customer); customerMapper.insert(customer);
respVO.getCreateCustomerNames().add(importCustomer.getName()); respVO.getCreateCustomerNames().add(importCustomer.getName());
// 创建数据权限 // 创建数据权限
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
// 记录操作日志
getSelf().importCustomerLog(customer, false);
return; return;
} }
// 如果存在判断是否允许更新 // 如果存在判断是否允许更新
@ -273,10 +271,25 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
updateCustomer.setId(existCustomer.getId()); updateCustomer.setId(existCustomer.getId());
customerMapper.updateById(updateCustomer); customerMapper.updateById(updateCustomer);
respVO.getUpdateCustomerNames().add(importCustomer.getName()); respVO.getUpdateCustomerNames().add(importCustomer.getName());
// 记录操作日志
getSelf().importCustomerLog(updateCustomer, true);
}); });
return respVO; 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());
}
@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);
}
private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) { private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
// 校验客户名称不能为空 // 校验客户名称不能为空
if (StrUtil.isEmptyIfStr(importCustomer.getName())) { if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
@ -367,15 +380,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
if (poolConfig == null || !poolConfig.getEnabled()) { if (poolConfig == null || !poolConfig.getEnabled()) {
return 0; return 0;
} }
// 1.1 获取没有锁定的不在公海的客户且没有成交的 // 1.1 获取没有锁定的不在公海的客户
List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE); List<CrmCustomerDO> customerList = customerMapper.selectListByLockAndNotPool(Boolean.FALSE);
// 1.2 获取没有锁定的不在公海的客户且成交的
// TODO @puhui999下面也搞到 sql 里去哈 or 查询问题不大的
List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE);
List<CrmCustomerDO> poolCustomerList = new ArrayList<>(); List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
poolCustomerList.addAll(filterList(notDealCustomerList, customer -> poolCustomerList.addAll(filterList(customerList, customer ->
(poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0)); !customer.getDealStatus() && (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
poolCustomerList.addAll(filterList(dealCustomerList, customer -> { poolCustomerList.addAll(filterList(customerList, customer -> {
if (!customer.getDealStatus()) { // 这里只处理成交的
return false;
}
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime()); LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0; return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
})); }));