📖 CRM:code review 合同流程

This commit is contained in:
YunaiV 2024-02-01 09:46:32 +08:00
parent acb8d3f23b
commit f5f827b59f
10 changed files with 39 additions and 28 deletions

View File

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

View File

@ -132,6 +132,7 @@ public class CrmContractController {
return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList);
}
// TODO @puhui999transferContract
@PutMapping("/transfer")
@Operation(summary = "合同转移")
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
@ -140,6 +141,7 @@ public class CrmContractController {
return success(true);
}
// TODO @puhui999方法名不对哈要不改成 submit提交审核的意思
@PutMapping("/approve")
@Operation(summary = "发起合同审批流程")
@PreAuthorize("@ss.hasPermission('crm:contract:update')")

View File

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

View File

@ -217,6 +217,8 @@ public class CrmCustomerController {
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
}
// TODO @puhui999updateSupport 要不改成前端必须传递哈哈哈代码排版看着有点乱
// TODO @puhui999加一个选择负责人允许空空就进入公海
@PostMapping("/import")
@Operation(summary = "导入客户")
@Parameters({
@ -224,13 +226,12 @@ public class CrmCustomerController {
@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
})
@PreAuthorize("@ss.hasPermission('system:customer:import')")
public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
@RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport)
throws Exception {
List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class);
return success(customerService.importCustomerList(list, updateSupport, getLoginUserId()));
}
@PutMapping("/transfer")
@Operation(summary = "转移客户")
@PreAuthorize("@ss.hasPermission('crm:customer:update')")

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelProperty;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -25,6 +24,7 @@ public class CrmCustomerImportExcelVO {
@ExcelProperty("客户名称")
private String name;
// TODO @puhui999industryIdlevelsource 字段可以研究下怎么搞下拉框
@ExcelProperty(value = "所属行业", converter = DictConvert.class)
@DictFormat(CRM_CUSTOMER_INDUSTRY)
private Integer industryId;
@ -46,25 +46,22 @@ public class CrmCustomerImportExcelVO {
@ExcelProperty("网址")
private String website;
@Size(max = 20, message = "QQ长度不能超过 20 个字符")
@ExcelProperty("QQ")
private String qq;
@Size(max = 255, message = "微信长度不能超过 255 个字符")
@ExcelProperty("微信")
private String wechat;
@Size(max = 255, message = "邮箱长度不能超过 255 个字符")
@ExcelProperty("邮箱")
private String email;
@Size(max = 4096, message = "客户描述长度不能超过 4096 个字符")
@ExcelProperty("客户描述")
private String description;
@ExcelProperty("备注")
private String remark;
// TODO @puhui999需要选择省市区需要研究下怎么搞合理点
@ExcelProperty("地区编号")
private Integer areaId;

View File

@ -118,6 +118,7 @@ public interface CrmContractService {
*/
Long getContractCountByCustomerId(Long customerId);
// TODO @puhui999要不改成 getContractCountByBusinessId
/**
* 根据商机ID获取关联客户的合同数量
*

View File

@ -22,7 +22,6 @@ import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService;
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
@ -69,15 +68,14 @@ public class CrmContractServiceImpl implements CrmContractService {
@Resource
private CrmProductService productService;
@Resource
private BpmProcessInstanceApi bpmProcessInstanceApi;
@Resource
private CrmCustomerService customerService;
@Resource
private CrmContactService contactService;
@Resource
private CrmBusinessService businessService;
@Resource
private AdminUserApi adminUserApi;
@Resource
private BpmProcessInstanceApi bpmProcessInstanceApi;
@Override
@Transactional(rollbackFor = Exception.class)
@ -85,19 +83,19 @@ public class CrmContractServiceImpl implements CrmContractService {
success = CRM_CONTRACT_CREATE_SUCCESS)
public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) {
validateRelationDataExists(createReqVO);
// 插入合同
// 1.1 插入合同
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
contractMapper.insert(contract);
// 1.2 插入商机关联商品
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
businessProductService.insertBatch(businessProduct);
// 创建数据权限
// 2. 创建数据权限
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
.setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId())
.setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
// 插入商机关联商品
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
businessProductService.insertBatch(businessProduct);
// 4. 记录操作日志上下文
// 3. 记录操作日志上下文
LogRecordContext.putVariable("contract", contract);
return contract.getId();
}
@ -121,6 +119,7 @@ public class CrmContractServiceImpl implements CrmContractService {
contractMapper.updateById(updateObj);
// TODO puhui999: @芋艿合同变更关联的商机后商品怎么处理
// TODO @puhui999和商品 spusku 编辑一样新增的插入修改的更新删除的删除
//List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
//businessProductService.selectListByBusinessId()
//diffList()
@ -141,6 +140,7 @@ public class CrmContractServiceImpl implements CrmContractService {
}
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
return convertList(reqVO.getProductItems(), productItem -> {
// TODO @puhui999这里可以改成直接 return不用弄一个 businessProduct 变量哈
CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class);
businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId())
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct));
@ -154,6 +154,7 @@ public class CrmContractServiceImpl implements CrmContractService {
* @param businessProduct 关联商品
* @return 商品总价
*/
// TODO @puhui999这个逻辑的计算是不是可以封装到 calculateRatePriceFloor
private Integer calculator(CrmBusinessProductDO businessProduct) {
int price = businessProduct.getPrice() * businessProduct.getCount();
if (businessProduct.getDiscountPercent() == null) {
@ -176,7 +177,7 @@ public class CrmContractServiceImpl implements CrmContractService {
if (reqVO.getOwnerUserId() != null && adminUserApi.getUser(reqVO.getOwnerUserId()) == null) {
throw exception(USER_NOT_EXISTS);
}
// 4. 如果有关联商机则需要校验存在
// 3. 如果有关联商机则需要校验存在
if (reqVO.getBusinessId() != null && businessService.getBusiness(reqVO.getBusinessId()) == null) {
throw exception(BUSINESS_NOT_EXISTS);
}
@ -235,6 +236,8 @@ public class CrmContractServiceImpl implements CrmContractService {
@Override
@Transactional(rollbackFor = Exception.class)
public void handleApprove(Long id, Long userId) {
// TODO @puhui999需要做状态检查
// 创建合同审批流程实例
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
.setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));

View File

@ -232,8 +232,10 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
return customer.getId();
}
// TODO @puhui999操作日志
@Override
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId) {
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
Boolean isUpdateSupport, Long userId) {
if (CollUtil.isEmpty(importCustomers)) {
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
}
@ -241,6 +243,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
.updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build();
importCustomers.forEach(importCustomer -> {
// 校验判断是否有不符合的原因
// TODO @puhui999可以用 ValidationUtils 做参数校验可能要封装一个方法返回 message这样的话就可以在 CrmCustomerImportExcelVO 写需要校验的参数啦
try {
validateCustomerForCreate(importCustomer);
} catch (ServiceException ex) {
@ -250,6 +253,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
// 判断如果不存在在进行插入
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
if (existCustomer == null) {
// TODO @puhui999可以搞个 initCustomer 方法这样可以把 create 和导入复用下这个方法
CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId)
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
customerMapper.insert(customer);
@ -366,6 +370,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
// 1.1 获取没有锁定的不在公海的客户且没有成交的
List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE);
// 1.2 获取没有锁定的不在公海的客户且成交的
// TODO @puhui999下面也搞到 sql 里去哈 or 查询问题不大的
List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE);
List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
poolCustomerList.addAll(filterList(notDealCustomerList, customer ->
@ -382,7 +387,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
getSelf().putCustomerPool(customer);
count++;
} catch (Throwable e) {
log.error("[customerAutoPutPoolBySystem][Customer 客户({}) 放入公海异常]", customer.getId(), e);
log.error("[autoPutCustomerPool][Customer 客户({}) 放入公海异常]", customer.getId(), e);
}
}
return count;

View File

@ -109,14 +109,14 @@ public interface CrmPermissionService {
List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId);
/**
* 校验权限
* 校验是否有指定数据的操作权限
*
* @param bizType 数据类型关联 {@link CrmBizTypeEnum}
* @param bizId 数据编号关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
* @param userId 用户编号
* @param levelEnum 权限级别
* @return boolean
* @param level 权限级别
* @return 是否有权限
*/
boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum);
boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level);
}

View File

@ -213,10 +213,10 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
}
@Override
public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum) {
public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level) {
List<CrmPermissionDO> permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId);
return anyMatch(permissionList, permission ->
ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), levelEnum.getLevel()));
ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), level.getLevel()));
}
}