From 38e410cae079fcdfdea8bcca3fd7330528db568a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 19 Feb 2024 20:41:10 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=96=20CRM=EF=BC=9A=E7=BA=BF=E7=B4=A2?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 5 +-- .../admin/clue/CrmClueController.java | 23 ++++++---- .../admin/clue/vo/CrmCluePageReqVO.java | 3 ++ .../admin/clue/vo/CrmClueSaveReqVO.java | 2 + .../admin/clue/vo/CrmClueTranslateReqVO.java | 17 -------- .../crm/dal/mysql/clue/CrmClueMapper.java | 1 + .../crm/service/clue/CrmClueService.java | 8 ++-- .../crm/service/clue/CrmClueServiceImpl.java | 42 ++++++++----------- 8 files changed, 45 insertions(+), 56 deletions(-) delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTranslateReqVO.java diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index d536d8a40..aa09b2032 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -16,8 +16,8 @@ public interface ErrorCodeConstants { // ========== 线索管理 1-020-001-000 ========== ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); - ErrorCode CLUE_ANY_CLUE_NOT_EXISTS = new ErrorCode(1_020_001_001, "线索【{}】不存在"); - ErrorCode CLUE_ANY_CLUE_ALREADY_TRANSLATED = new ErrorCode(1_020_001_002, "线索【{}】已经转化过了,请勿重复转化"); + ErrorCode CLUE_NOT_EXISTS_ANY = new ErrorCode(1_020_001_001, "线索【{}】不存在"); + ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_002, "线索【{}】已经转化过了,请勿重复转化"); // ========== 商机管理 1-020-002-000 ========== ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); @@ -25,7 +25,6 @@ public interface ErrorCodeConstants { // TODO @lilleo:商机状态、商机类型,都单独错误码段 - // ========== 联系人管理 1-020-003-000 ========== ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在"); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java index f1087c4ec..726afc549 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*; import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; @@ -35,8 +36,7 @@ import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -60,7 +60,7 @@ public class CrmClueController { @Operation(summary = "创建线索") @PreAuthorize("@ss.hasPermission('crm:clue:create')") public CommonResult createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { - return success(clueService.createClue(createReqVO, getLoginUserId())); + return success(clueService.createClue(createReqVO)); } @PutMapping("/update") @@ -86,7 +86,14 @@ public class CrmClueController { @PreAuthorize("@ss.hasPermission('crm:clue:query')") public CommonResult getClue(@RequestParam("id") Long id) { CrmClueDO clue = clueService.getClue(id); - return success(BeanUtils.toBean(clue, CrmClueRespVO.class)); + return success(buildClueDetail(clue)); + } + + public CrmClueRespVO buildClueDetail(CrmClueDO clue) { + if (clue == null) { + return null; + } + return buildClueDetailList(Collections.singletonList(clue)).get(0); } @GetMapping("/page") @@ -121,6 +128,7 @@ public class CrmClueController { Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 2. 转换成 VO return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> { + clueVO.setAreaName(AreaUtils.format(clueVO.getAreaId())); // 2.1 设置客户名称 MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName())); // 2.2 设置创建人、负责人名称 @@ -141,11 +149,12 @@ public class CrmClueController { return success(true); } - @PostMapping("/transform") + @PutMapping("/transform") @Operation(summary = "线索转化为客户") + @Parameter(name = "ids", description = "线索编号数组", required = true) @PreAuthorize("@ss.hasPermission('crm:clue:update')") - public CommonResult translateCustomer(@Valid @RequestBody CrmClueTranslateReqVO reqVO) { - clueService.translateCustomer(reqVO, getLoginUserId()); + public CommonResult transformClue(@RequestParam("ids") List ids) { + clueService.transformClue(ids, getLoginUserId()); return success(Boolean.TRUE); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java index be8d30dbe..a63d946e9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java @@ -17,6 +17,9 @@ public class CrmCluePageReqVO extends PageParam { @Schema(description = "线索名称", example = "线索xxx") private String name; + @Schema(description = "转化状态", example = "2048") + private Boolean transformStatus; + @Schema(description = "电话", example = "18000000000") private String telephone; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java index ca45d5ee1..a27de7059 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java @@ -13,6 +13,7 @@ import com.mzt.logapi.starter.annotation.DiffLogField; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -45,6 +46,7 @@ public class CrmClueSaveReqVO { private LocalDateTime contactNextTime; @Schema(description = "负责人编号", example = "2048") + @NotNull(message = "负责人编号不能为空") private Long ownerUserId; @Schema(description = "手机号", example = "18000000000") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTranslateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTranslateReqVO.java deleted file mode 100644 index 03a4d78f1..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTranslateReqVO.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import java.util.Set; - -@Schema(description = "管理后台 - 线索转化为客户 Request VO") -@Data -public class CrmClueTranslateReqVO { - - @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024, 1025]") - @NotEmpty(message = "线索编号不能为空") - private Set ids; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java index 4c5206472..4bef3112a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java @@ -36,6 +36,7 @@ public interface CrmClueMapper extends BaseMapperX { // 拼接自身的查询条件 query.selectAll(CrmClueDO.class) .likeIfPresent(CrmClueDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmClueDO::getTransformStatus, pageReqVO.getTransformStatus()) .likeIfPresent(CrmClueDO::getTelephone, pageReqVO.getTelephone()) .likeIfPresent(CrmClueDO::getMobile, pageReqVO.getMobile()) .eqIfPresent(CrmClueDO::getIndustryId, pageReqVO.getIndustryId()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java index 6c37305c7..26245bc9c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTranslateReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; import jakarta.validation.Valid; @@ -23,10 +22,9 @@ public interface CrmClueService { * 创建线索 * * @param createReqVO 创建信息 - * @param userId 用户编号 * @return 编号 */ - Long createClue(@Valid CrmClueSaveReqVO createReqVO, Long userId); + Long createClue(@Valid CrmClueSaveReqVO createReqVO); /** * 更新线索 @@ -85,10 +83,10 @@ public interface CrmClueService { /** * 线索转化为客户 * - * @param reqVO 线索编号 + * @param ids 线索编号数组 * @param userId 用户编号 */ - void translateCustomer(CrmClueTranslateReqVO reqVO, Long userId); + void transformClue(List ids, Long userId); /** * 获得分配给我的线索数量 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index 56f760795..1b7ba634a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -10,7 +10,6 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTranslateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; @@ -36,14 +35,16 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; -import static java.util.Collections.singletonList; /** * 线索 Service 实现类 @@ -71,17 +72,13 @@ public class CrmClueServiceImpl implements CrmClueService { @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_CREATE_SUB_TYPE, bizNo = "{{#clue.id}}", success = CRM_LEADS_CREATE_SUCCESS) - public Long createClue(CrmClueSaveReqVO createReqVO, Long userId) { + public Long createClue(CrmClueSaveReqVO createReqVO) { // 1.1 校验关联数据 validateRelationDataExists(createReqVO); // 1.2 校验负责人是否存在 - if (createReqVO.getOwnerUserId() != null) { - adminUserApi.validateUserList(singletonList(createReqVO.getOwnerUserId())); - } else { - createReqVO.setOwnerUserId(userId); // 如果没有设置负责人那么默认操作人为负责人 - } + adminUserApi.validateUser(createReqVO.getOwnerUserId()); - // 2. 插入 + // 2. 插入线索 CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class) .setContactLastTime(LocalDateTime.now()); clueMapper.insert(clue); @@ -103,12 +100,12 @@ public class CrmClueServiceImpl implements CrmClueService { @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER) public void updateClue(CrmClueSaveReqVO updateReq) { Assert.notNull(updateReq.getId(), "线索编号不能为空"); - // 1. 校验线索是否存在 + // 1.1 校验线索是否存在 CrmClueDO oldClue = validateClueExists(updateReq.getId()); - // 2. 校验关联数据 + // 1.2 校验关联数据 validateRelationDataExists(updateReq); - // 3. 更新 + // 2. 更新线索 CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class); clueMapper.updateById(updateObj); @@ -130,7 +127,6 @@ public class CrmClueServiceImpl implements CrmClueService { // 3. 记录操作日志上下文 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmUpdateFollowUpReqBO.class)); LogRecordContext.putVariable("clueName", oldClue.getName()); - } @Override @@ -155,12 +151,11 @@ public class CrmClueServiceImpl implements CrmClueService { LogRecordContext.putVariable("clueName", clue.getName()); } - @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", success = CRM_LEADS_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { // 1 校验线索是否存在 CrmClueDO clue = validateClueExists(reqVO.getId()); @@ -176,20 +171,19 @@ public class CrmClueServiceImpl implements CrmClueService { @Override @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void translateCustomer(CrmClueTranslateReqVO reqVO, Long userId) { + @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#ids", level = CrmPermissionLevelEnum.OWNER) + public void transformClue(List ids, Long userId) { // 1.1 校验线索都存在 - Set clueIds = reqVO.getIds(); - List clues = getClueList(clueIds, userId); - if (CollUtil.isEmpty(clues) || ObjectUtil.notEqual(clues.size(), clueIds.size())) { - clueIds.removeAll(convertSet(clues, CrmClueDO::getId)); - throw exception(CLUE_ANY_CLUE_NOT_EXISTS, clueIds); + List clues = getClueList(ids, userId); + if (CollUtil.isEmpty(clues) || ObjectUtil.notEqual(clues.size(), ids.size())) { + ids.removeAll(convertSet(clues, CrmClueDO::getId)); + throw exception(CLUE_NOT_EXISTS_ANY, ids); } // 1.2 存在已经转化的,直接提示哈。避免操作的用户,以为都转化成功了 List translatedClues = filterList(clues, clue -> ObjectUtil.equal(Boolean.TRUE, clue.getTransformStatus())); if (CollUtil.isNotEmpty(translatedClues)) { - throw exception(CLUE_ANY_CLUE_ALREADY_TRANSLATED, convertSet(translatedClues, CrmClueDO::getId)); + throw exception(CLUE_TRANSFORM_FAIL_ALREADY, convertSet(translatedClues, CrmClueDO::getId)); } // 2.1 遍历线索(未转化的线索),创建对应的客户