Merge remote-tracking branch 'yudao/develop' into develop
# Conflicts: # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
This commit is contained in:
commit
1a96fb2ffc
|
@ -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")
|
||||
|
|
|
@ -132,6 +132,7 @@ public class CrmContractController {
|
|||
return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList);
|
||||
}
|
||||
|
||||
// TODO @puhui999:transferContract
|
||||
@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')")
|
||||
|
|
|
@ -89,6 +89,7 @@ public class CrmContractSaveReqVO {
|
|||
@DiffLogField(name = "备注")
|
||||
private String remark;
|
||||
|
||||
// TODO @puhui999:这个字段,按道理不用传递?
|
||||
@Schema(description = "审批状态", example = "1")
|
||||
private Integer auditStatus;
|
||||
|
||||
|
|
|
@ -217,6 +217,8 @@ public class CrmCustomerController {
|
|||
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
|
||||
}
|
||||
|
||||
// TODO @puhui999:updateSupport 要不改成前端必须传递;哈哈哈,代码排版看着有点乱;
|
||||
// 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')")
|
||||
|
|
|
@ -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 @puhui999:industryId、level、source 字段,可以研究下怎么搞下拉框
|
||||
@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;
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ public interface CrmContractService {
|
|||
*/
|
||||
Long getContractCountByCustomerId(Long customerId);
|
||||
|
||||
// TODO @puhui999:要不改成 getContractCountByBusinessId
|
||||
/**
|
||||
* 根据商机ID获取关联客户的合同数量
|
||||
*
|
||||
|
|
|
@ -6,7 +6,6 @@ import cn.hutool.core.util.ObjUtil;
|
|||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||
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.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
||||
|
@ -23,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;
|
||||
|
@ -34,7 +32,6 @@ import com.mzt.logapi.context.LogRecordContext;
|
|||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -71,17 +68,14 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
@Resource
|
||||
private CrmProductService productService;
|
||||
@Resource
|
||||
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||
@Resource
|
||||
private CrmCustomerService customerService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private CrmContactService contactService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private CrmBusinessService businessService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
@Resource
|
||||
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -89,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();
|
||||
}
|
||||
|
@ -125,6 +119,7 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
contractMapper.updateById(updateObj);
|
||||
|
||||
// TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理?
|
||||
// TODO @puhui999:和商品 spu、sku 编辑一样;新增的插入;修改的更新;删除的删除
|
||||
//List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
|
||||
//businessProductService.selectListByBusinessId()
|
||||
//diffList()
|
||||
|
@ -145,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));
|
||||
|
@ -158,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) {
|
||||
|
@ -180,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);
|
||||
}
|
||||
|
@ -239,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)));
|
||||
|
@ -248,12 +247,6 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
|
||||
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey())).setAuditStatus(event.getResult()));
|
||||
}
|
||||
|
||||
//======================= 查询相关 =======================
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue