mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 02:08:43 +08:00 
			
		
		
		
	| @@ -70,5 +70,9 @@ | |||||||
|             <groupId>cn.iocoder.boot</groupId> |             <groupId>cn.iocoder.boot</groupId> | ||||||
|             <artifactId>yudao-spring-boot-starter-test</artifactId> |             <artifactId>yudao-spring-boot-starter-test</artifactId> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>cn.iocoder.boot</groupId> | ||||||
|  |             <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> | ||||||
|  |         </dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
| </project> | </project> | ||||||
|   | |||||||
| @@ -2,14 +2,14 @@ package cn.iocoder.yudao.module.crm.controller.admin.operatelog; | |||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; | ||||||
|  | import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogV2RespVO; | ||||||
| import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; | import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; | ||||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
| import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; | import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; | ||||||
| import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; | import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; | ||||||
| import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO; |  | ||||||
| import io.swagger.v3.oas.annotations.Operation; | import io.swagger.v3.oas.annotations.Operation; | ||||||
| import io.swagger.v3.oas.annotations.Parameter; |  | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | import io.swagger.v3.oas.annotations.tags.Tag; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
| @@ -51,16 +51,14 @@ public class CrmOperateLogController { | |||||||
|         BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), CRM_RECEIVABLE_PLAN_TYPE); |         BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), CRM_RECEIVABLE_PLAN_TYPE); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @puhui999:还是搞个 VO 出来哈 |  | ||||||
|     @GetMapping("/page") |     @GetMapping("/page") | ||||||
|     @Operation(summary = "获得操作日志") |     @Operation(summary = "获得操作日志") | ||||||
|     @Parameter(name = "id", description = "客户编号", required = true) |     @PreAuthorize("@ss.hasPermission('crm:operate-log:query')") | ||||||
|     @PreAuthorize("@ss.hasPermission('crm:customer:query')") |     public CommonResult<PageResult<CrmOperateLogV2RespVO>> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { | ||||||
|     public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { |  | ||||||
|         OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); |         OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); | ||||||
|         reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 |         reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 | ||||||
|         reqDTO.setBizType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); |         reqDTO.setBizType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); | ||||||
|         return success(operateLogApi.getOperateLogPage(reqDTO)); |         return success(BeanUtils.toBean(operateLogApi.getOperateLogPage(reqDTO), CrmOperateLogV2RespVO.class)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,89 @@ | |||||||
|  | package cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo; | ||||||
|  |  | ||||||
|  | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - CRM 跟进 Response VO") | ||||||
|  | @Data | ||||||
|  | @ExcelIgnoreUnannotated | ||||||
|  | public class CrmOperateLogV2RespVO { | ||||||
|  |  | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private Long id; | ||||||
|  |     /** | ||||||
|  |      * 链路追踪编号 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String traceId; | ||||||
|  |     /** | ||||||
|  |      * 用户编号 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||||||
|  |     private Long userId; | ||||||
|  |     /** | ||||||
|  |      * 用户名称 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") | ||||||
|  |     private String userName; | ||||||
|  |     /** | ||||||
|  |      * 用户类型 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||||
|  |     private Integer userType; | ||||||
|  |     /** | ||||||
|  |      * 操作模块类型 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String type; | ||||||
|  |     /** | ||||||
|  |      * 操作名 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "修改客户") | ||||||
|  |     private String subType; | ||||||
|  |     /** | ||||||
|  |      * 操作模块业务编号 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private Long bizId; | ||||||
|  |     /** | ||||||
|  |      * 操作内容 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "将什么从什么改为了什么") | ||||||
|  |     private String action; | ||||||
|  |     /** | ||||||
|  |      * 拓展字段 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", example = "{orderId: 1}") | ||||||
|  |     private String extra; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 请求方法名 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String requestMethod; | ||||||
|  |     /** | ||||||
|  |      * 请求地址 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String requestUrl; | ||||||
|  |     /** | ||||||
|  |      * 用户 IP | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String userIp; | ||||||
|  |     /** | ||||||
|  |      * 浏览器 UA | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||||||
|  |     private String userAgent; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建时间 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-01") | ||||||
|  |     private LocalDateTime createTime; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.convert.permission; | |||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; | ||||||
| @@ -29,13 +30,10 @@ public interface CrmPermissionConvert { | |||||||
|  |  | ||||||
|     CrmPermissionConvert INSTANCE = Mappers.getMapper(CrmPermissionConvert.class); |     CrmPermissionConvert INSTANCE = Mappers.getMapper(CrmPermissionConvert.class); | ||||||
|  |  | ||||||
|     // TODO @puhui999:这个要不也搞到 copy 里 |     default List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permissions, List<AdminUserRespDTO> userList, | ||||||
|     List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permission); |  | ||||||
|  |  | ||||||
|     default List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permission, List<AdminUserRespDTO> userList, |  | ||||||
|                                               Map<Long, DeptRespDTO> deptMap, Map<Long, PostRespDTO> postMap) { |                                               Map<Long, DeptRespDTO> deptMap, Map<Long, PostRespDTO> postMap) { | ||||||
|         Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(userList, AdminUserRespDTO::getId); |         Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(userList, AdminUserRespDTO::getId); | ||||||
|         return CollectionUtils.convertList(convert(permission), item -> { |         return CollectionUtils.convertList(BeanUtils.toBean(permissions, CrmPermissionRespVO.class), item -> { | ||||||
|             findAndThen(userMap, item.getUserId(), user -> { |             findAndThen(userMap, item.getUserId(), user -> { | ||||||
|                 item.setNickname(user.getNickname()); |                 item.setNickname(user.getNickname()); | ||||||
|                 findAndThen(deptMap, user.getDeptId(), deptRespDTO -> item.setDeptName(deptRespDTO.getName())); |                 findAndThen(deptMap, user.getDeptId(), deptRespDTO -> item.setDeptName(deptRespDTO.getName())); | ||||||
|   | |||||||
| @@ -114,10 +114,15 @@ public class CrmCustomerDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private String detailAddress; |     private String detailAddress; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 最后接收时间 | ||||||
|  |      */ | ||||||
|  |     private LocalDateTime receiveTime; | ||||||
|     /** |     /** | ||||||
|      * 最后跟进时间 |      * 最后跟进时间 | ||||||
|      */ |      */ | ||||||
|     private LocalDateTime contactLastTime; |     private LocalDateTime contactLastTime; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 最后跟进内容 |      * 最后跟进内容 | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageR | |||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | ||||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
| import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; | ||||||
|  | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
| import org.springframework.lang.Nullable; | import org.springframework.lang.Nullable; | ||||||
| @@ -99,4 +100,10 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> { | |||||||
|         return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); |         return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default List<CrmCustomerDO> selectListByLockStatusAndOwnerUserIdNotNull(Boolean lockStatus) { | ||||||
|  |         return selectList(new LambdaQueryWrapper<CrmCustomerDO>() | ||||||
|  |                 .eq(CrmCustomerDO::getLockStatus, lockStatus) | ||||||
|  |                 .isNotNull(CrmCustomerDO::getOwnerUserId)); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,9 +1,17 @@ | |||||||
| package cn.iocoder.yudao.module.crm.framework.permission.core.util; | package cn.iocoder.yudao.module.crm.framework.permission.core.util; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.util.ObjUtil; | ||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
|  | import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; | ||||||
|  | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionRoleCodeEnum; | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionRoleCodeEnum; | ||||||
|  | import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; | ||||||
| import cn.iocoder.yudao.module.system.api.permission.PermissionApi; | import cn.iocoder.yudao.module.system.api.permission.PermissionApi; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; | ||||||
| import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -22,6 +30,21 @@ public class CrmPermissionUtils { | |||||||
|         return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode()); |         return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 校验权限 | ||||||
|  |      * | ||||||
|  |      * @param bizType   数据类型,关联 {@link CrmBizTypeEnum} | ||||||
|  |      * @param bizId     数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() | ||||||
|  |      * @param userId    用户编号 | ||||||
|  |      * @param levelEnum 权限级别 | ||||||
|  |      * @return boolean | ||||||
|  |      */ | ||||||
|  |     public static boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum) { | ||||||
|  |         List<CrmPermissionDO> permissionList = SingletonManager.getCrmPermissionService().getPermissionListByBiz(bizType, bizId); | ||||||
|  |         return anyMatch(permissionList, permission -> | ||||||
|  |                 ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), levelEnum.getLevel())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 静态内部类实现单例获取 |      * 静态内部类实现单例获取 | ||||||
|      * |      * | ||||||
| @@ -30,11 +53,16 @@ public class CrmPermissionUtils { | |||||||
|     private static class SingletonManager { |     private static class SingletonManager { | ||||||
|  |  | ||||||
|         private static final PermissionApi PERMISSION_API = SpringUtil.getBean(PermissionApi.class); |         private static final PermissionApi PERMISSION_API = SpringUtil.getBean(PermissionApi.class); | ||||||
|  |         private static final CrmPermissionService CRM_PERMISSION_SERVICE = SpringUtil.getBean(CrmPermissionService.class); | ||||||
|  |  | ||||||
|         public static PermissionApi getPermissionApi() { |         public static PermissionApi getPermissionApi() { | ||||||
|             return PERMISSION_API; |             return PERMISSION_API; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public static CrmPermissionService getCrmPermissionService() { | ||||||
|  |             return CRM_PERMISSION_SERVICE; | ||||||
|  |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | package cn.iocoder.yudao.module.crm.job.customer; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||||||
|  | import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; | ||||||
|  | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 客户自动掉入公海 Job | ||||||
|  |  * | ||||||
|  |  * @author 芋道源码 | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | public class CrmCustomerAutoPutPoolJob implements JobHandler { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private CrmCustomerService customerService; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @TenantJob | ||||||
|  |     public String execute(String param) { | ||||||
|  |         int count = customerService.customerAutoPutPoolBySystem(); | ||||||
|  |         return String.format("掉入公海客户 %s 个", count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1 @@ | |||||||
|  | package cn.iocoder.yudao.module.crm.job; | ||||||
| @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.service.clue; | |||||||
| 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.lang.Assert; | ||||||
| import cn.hutool.core.util.ObjUtil; |  | ||||||
| import cn.hutool.core.util.ObjectUtil; | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| @@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransformReqV | |||||||
| import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; | 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.convert.clue.CrmClueConvert; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |  | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; | import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; | ||||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
| @@ -193,46 +191,39 @@ public class CrmClueServiceImpl implements CrmClueService { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2. 遍历线索(未转化的线索),创建对应的客户 |         // 2. 遍历线索(未转化的线索),创建对应的客户 | ||||||
|         // TODO @puhui999:这里不用过滤了; |         clues.forEach(clue -> { | ||||||
|         List<CrmClueDO> translateClues = filterList(clues, clue -> ObjUtil.equal(Boolean.FALSE, clue.getTransformStatus())); |             Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); | ||||||
|         List<CrmCustomerDO> customers = customerService.createCustomerBatch(convertList(translateClues, clue -> |             clue.setCustomerId(customerId); | ||||||
|                 BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class)), userId); |         }); | ||||||
|  |  | ||||||
|         // TODO @puhui999:这里不用搞一个 clueCustomerIdMap 出来;可以考虑逐个创建,然后把 customerId 设置回 CrmClueDO;避免 name 匹配,极端会有问题哈; |  | ||||||
|         // TODO 是不是就直接 foreach 处理好了;因为本身量不大,for 处理性能 ok,可阅读性好 |  | ||||||
|         Map<Long, Long> clueCustomerIdMap = new HashMap<>(translateClues.size()); |  | ||||||
|         // 2.1 更新线索 |         // 2.1 更新线索 | ||||||
|         clueMapper.updateBatch(convertList(customers, customer -> { |         clueMapper.updateBatch(convertList(clues, clue -> new CrmClueDO().setId(clue.getId()).setTransformStatus(Boolean.TRUE) | ||||||
|             CrmClueDO firstClue = findFirst(translateClues, clue -> ObjUtil.equal(clue.getName(), customer.getName())); |                 .setCustomerId(clue.getCustomerId()))); | ||||||
|             clueCustomerIdMap.put(firstClue.getId(), customer.getId()); |  | ||||||
|             return new CrmClueDO().setId(firstClue.getId()).setTransformStatus(Boolean.TRUE).setCustomerId(customer.getId()); |  | ||||||
|         })); |  | ||||||
|         // 2.3 复制跟进 |         // 2.3 复制跟进 | ||||||
|         updateFollowUpRecords(clueCustomerIdMap); |         updateFollowUpRecords(clues); | ||||||
|  |  | ||||||
|         // 3. 记录操作日志 |         // 3. 记录操作日志 | ||||||
|         for (CrmClueDO clue : translateClues) { |         for (CrmClueDO clue : clues) { | ||||||
|             // TODO @puhui999:这里优化下,translate 操作日志 |             getSelf().translateCustomerLog(clue); | ||||||
|             getSelf().receiveClueLog(clue); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void updateFollowUpRecords(Map<Long, Long> clueCustomerIdMap) { |     private void updateFollowUpRecords(List<CrmClueDO> clues) { | ||||||
|         List<CrmFollowUpRecordDO> followUpRecords = followUpRecordService.getFollowUpRecordByBiz( |         List<CrmFollowUpRecordDO> followUpRecords = followUpRecordService.getFollowUpRecordByBiz( | ||||||
|                 CrmBizTypeEnum.CRM_LEADS.getType(), clueCustomerIdMap.keySet()); |                 CrmBizTypeEnum.CRM_LEADS.getType(), convertSet(clues, CrmClueDO::getId)); | ||||||
|         if (CollUtil.isEmpty(followUpRecords)) { |         if (CollUtil.isEmpty(followUpRecords)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         Map<Long, CrmClueDO> clueMap = convertMap(clues, CrmClueDO::getId); | ||||||
|         // 创建跟进 |         // 创建跟进 | ||||||
|         followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, followUpRecord -> |         followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, followUpRecord -> | ||||||
|                 BeanUtils.toBean(followUpRecord, CrmFollowUpCreateReqBO.class).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) |                 BeanUtils.toBean(followUpRecord, CrmFollowUpCreateReqBO.class).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) | ||||||
|                         .setBizId(clueCustomerIdMap.get(followUpRecord.getBizId())))); |                         .setBizId(clueMap.get(followUpRecord.getBizId()).getCustomerId()))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSLATE_SUB_TYPE, bizNo = "{{#clue.id}}", |     @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSLATE_SUB_TYPE, bizNo = "{{#clue.id}}", | ||||||
|             success = CRM_LEADS_TRANSLATE_SUCCESS) |             success = CRM_LEADS_TRANSLATE_SUCCESS) | ||||||
|     public void receiveClueLog(CrmClueDO clue) { |     public void translateCustomerLog(CrmClueDO clue) { | ||||||
|         // 记录操作日志上下文 |         // 记录操作日志上下文 | ||||||
|         LogRecordContext.putVariable("clue", clue); |         LogRecordContext.putVariable("clue", clue); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; | |||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink.CrmContactBusinessMapper; | import cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink.CrmContactBusinessMapper; | ||||||
|  | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
|  | 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.CrmBusinessService; | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| @@ -19,7 +22,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | |||||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_NOT_EXISTS; | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_NOT_EXISTS; | ||||||
|  |  | ||||||
| // TODO @puhui999:数据权限的校验;每个操作; |  | ||||||
| /** | /** | ||||||
|  * 联系人与商机的关联 Service 实现类 |  * 联系人与商机的关联 Service 实现类 | ||||||
|  * |  * | ||||||
| @@ -40,6 +42,7 @@ public class CrmContactBusinessServiceImpl implements CrmContactBusinessService | |||||||
|     private CrmContactService contactService; |     private CrmContactService contactService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#createReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) | ||||||
|     public void createContactBusinessList(CrmContactBusinessReqVO createReqVO) { |     public void createContactBusinessList(CrmContactBusinessReqVO createReqVO) { | ||||||
|         CrmContactDO contact = contactService.getContact(createReqVO.getContactId()); |         CrmContactDO contact = contactService.getContact(createReqVO.getContactId()); | ||||||
|         if (contact == null) { |         if (contact == null) { | ||||||
| @@ -65,6 +68,7 @@ public class CrmContactBusinessServiceImpl implements CrmContactBusinessService | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#deleteReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) | ||||||
|     public void deleteContactBusinessList(CrmContactBusinessReqVO deleteReqVO) { |     public void deleteContactBusinessList(CrmContactBusinessReqVO deleteReqVO) { | ||||||
|         CrmContactDO contact = contactService.getContact(deleteReqVO.getContactId()); |         CrmContactDO contact = contactService.getContact(deleteReqVO.getContactId()); | ||||||
|         if (contact == null) { |         if (contact == null) { | ||||||
| @@ -76,11 +80,13 @@ public class CrmContactBusinessServiceImpl implements CrmContactBusinessService | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.WRITE) | ||||||
|     public void deleteContactBusinessByContactId(Long contactId) { |     public void deleteContactBusinessByContactId(Long contactId) { | ||||||
|         contactBusinessMapper.delete(CrmContactBusinessDO::getContactId,contactId); |         contactBusinessMapper.delete(CrmContactBusinessDO::getContactId, contactId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.READ) | ||||||
|     public List<CrmContactBusinessDO> getContactBusinessListByContactId(Long contactId) { |     public List<CrmContactBusinessDO> getContactBusinessListByContactId(Long contactId) { | ||||||
|         return contactBusinessMapper.selectListByContactId(contactId); |         return contactBusinessMapper.selectListByContactId(contactId); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -100,13 +100,13 @@ public interface CrmCustomerService { | |||||||
|     void updateCustomerFollowUp(CrmUpdateFollowUpReqBO customerUpdateFollowUpReqBO); |     void updateCustomerFollowUp(CrmUpdateFollowUpReqBO customerUpdateFollowUpReqBO); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 批量创建客户 |      * 创建客户 | ||||||
|      * |      * | ||||||
|      * @param customerCreateReqBOs 请求 |      * @param customerCreateReq 请求信息 | ||||||
|      * @param userId            用户编号 |      * @param userId            用户编号 | ||||||
|      * @return 客户列表 |      * @return 客户列表 | ||||||
|      */ |      */ | ||||||
|     List<CrmCustomerDO> createCustomerBatch(List<CrmCustomerCreateReqBO> customerCreateReqBOs, Long userId); |     Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId); | ||||||
|  |  | ||||||
|     // ==================== 公海相关操作 ==================== |     // ==================== 公海相关操作 ==================== | ||||||
|  |  | ||||||
| @@ -126,4 +126,11 @@ public interface CrmCustomerService { | |||||||
|      */ |      */ | ||||||
|     void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive); |     void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 【系统】客户自动掉入公海 | ||||||
|  |      * | ||||||
|  |      * @return 掉入公海数量 | ||||||
|  |      */ | ||||||
|  |     int customerAutoPutPoolBySystem(); | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.crm.service.customer; | |||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.lang.Assert; | import cn.hutool.core.lang.Assert; | ||||||
|  | import cn.hutool.core.util.ObjUtil; | ||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; | ||||||
| @@ -13,6 +15,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTrans | |||||||
| import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; | import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; | ||||||
|  | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; | import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; | ||||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||||
| @@ -31,6 +34,7 @@ import com.mzt.logapi.context.LogRecordContext; | |||||||
| import com.mzt.logapi.service.impl.DiffParseFunction; | import com.mzt.logapi.service.impl.DiffParseFunction; | ||||||
| import com.mzt.logapi.starter.annotation.LogRecord; | import com.mzt.logapi.starter.annotation.LogRecord; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| @@ -43,12 +47,10 @@ import java.util.Collections; | |||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |  | ||||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; | import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT; | import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT; | import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT; | ||||||
| import static java.util.Collections.emptyList; |  | ||||||
| import static java.util.Collections.singletonList; | import static java.util.Collections.singletonList; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -57,6 +59,7 @@ import static java.util.Collections.singletonList; | |||||||
|  * @author Wanwan |  * @author Wanwan | ||||||
|  */ |  */ | ||||||
| @Service | @Service | ||||||
|  | @Slf4j | ||||||
| @Validated | @Validated | ||||||
| public class CrmCustomerServiceImpl implements CrmCustomerService { | public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||||
|  |  | ||||||
| @@ -69,6 +72,9 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | |||||||
|     private CrmCustomerLimitConfigService customerLimitConfigService; |     private CrmCustomerLimitConfigService customerLimitConfigService; | ||||||
|     @Resource |     @Resource | ||||||
|     @Lazy |     @Lazy | ||||||
|  |     private CrmCustomerPoolConfigService customerPoolConfigService; | ||||||
|  |     @Resource | ||||||
|  |     @Lazy | ||||||
|     private CrmContactService contactService; |     private CrmContactService contactService; | ||||||
|     @Resource |     @Resource | ||||||
|     @Lazy |     @Lazy | ||||||
| @@ -91,9 +97,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | |||||||
|  |  | ||||||
|         // 2. 插入客户 |         // 2. 插入客户 | ||||||
|         CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class) |         CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class) | ||||||
|                 .setLockStatus(false).setDealStatus(false) |                 .setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now()); | ||||||
|                 .setContactLastTime(LocalDateTime.now()); |  | ||||||
|         // TODO @puhui999:可能要加个 receiveTime 字段,记录最后接收时间 |  | ||||||
|         customerMapper.insert(customer); |         customerMapper.insert(customer); | ||||||
|  |  | ||||||
|         // 3. 创建数据权限 |         // 3. 创建数据权限 | ||||||
| @@ -214,24 +218,24 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public List<CrmCustomerDO> createCustomerBatch(List<CrmCustomerCreateReqBO> customerCreateReqBOs, Long userId) { |     @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", | ||||||
|         if (CollUtil.isEmpty(customerCreateReqBOs)) { |             success = CRM_CUSTOMER_CREATE_SUCCESS) | ||||||
|             return emptyList(); |     public Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId) { | ||||||
|  |         // 1. 插入客户 | ||||||
|  |         CrmCustomerDO customer = BeanUtils.toBean(customerCreateReq, CrmCustomerDO.class).setOwnerUserId(userId) | ||||||
|  |                 .setLockStatus(false).setDealStatus(false).setReceiveTime(LocalDateTime.now()); | ||||||
|  |         customerMapper.insert(customer); | ||||||
|  |  | ||||||
|  |         // 2. 创建数据权限 | ||||||
|  |         permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) | ||||||
|  |                 .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 | ||||||
|  |  | ||||||
|  |         // 3. 记录操作日志上下文 | ||||||
|  |         LogRecordContext.putVariable("customer", customer); | ||||||
|  |         return customer.getId(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         // 创建客户 | // ==================== 公海相关操作 ==================== | ||||||
|         List<CrmCustomerDO> customers = convertList(customerCreateReqBOs, customerBO -> |  | ||||||
|                 BeanUtils.toBean(customerBO, CrmCustomerDO.class).setOwnerUserId(userId)); |  | ||||||
|         customerMapper.insertBatch(customers); |  | ||||||
|  |  | ||||||
|         // 创建负责人数据权限 |  | ||||||
|         permissionService.createPermissionBatch(convertList(customers, customer -> new CrmPermissionCreateReqBO() |  | ||||||
|                 .setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()).setBizId(customer.getId()).setUserId(userId) |  | ||||||
|                 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()))); |  | ||||||
|         return customers; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // ==================== 公海相关操作 ==================== |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
| @@ -249,17 +253,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | |||||||
|         // 1.3. 校验客户是否锁定 |         // 1.3. 校验客户是否锁定 | ||||||
|         validateCustomerIsLocked(customer, true); |         validateCustomerIsLocked(customer, true); | ||||||
|  |  | ||||||
|         // 2.1 设置负责人为 NULL |         // 2. 客户放入公海 | ||||||
|         int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null); |         putCustomerPool(customer); | ||||||
|         if (updateOwnerUserIncr == 0) { |  | ||||||
|             throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL); |  | ||||||
|         } |  | ||||||
|         // 2.2 删除负责人数据权限 |  | ||||||
|         permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), |  | ||||||
|                 CrmPermissionLevelEnum.OWNER.getLevel()); |  | ||||||
|  |  | ||||||
|         // 3. 联系人的负责人,也要设置为 null。因为:因为领取后,负责人也要关联过来,这块和 receiveCustomer 是对应的 |  | ||||||
|         contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); |  | ||||||
|  |  | ||||||
|         // 记录操作日志上下文 |         // 记录操作日志上下文 | ||||||
|         LogRecordContext.putVariable("customerName", customer.getName()); |         LogRecordContext.putVariable("customerName", customer.getName()); | ||||||
| @@ -317,6 +312,49 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int customerAutoPutPoolBySystem() { | ||||||
|  |         CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); | ||||||
|  |         if (poolConfig == null || !poolConfig.getEnabled()) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         // 获取没有锁定的不在公海的客户 | ||||||
|  |         List<CrmCustomerDO> customerList = customerMapper.selectListByLockStatusAndOwnerUserIdNotNull(Boolean.FALSE); | ||||||
|  |         List<CrmCustomerDO> poolCustomerList = CollectionUtils.filterList(customerList, customer -> { | ||||||
|  |             // 1.1 未成交放入公海 | ||||||
|  |             if (!customer.getDealStatus()) { | ||||||
|  |                 return (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0; | ||||||
|  |             } | ||||||
|  |             // 1.2 未跟进放入公海 | ||||||
|  |             LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime()); | ||||||
|  |             return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0; | ||||||
|  |         }); | ||||||
|  |         int count = 0; | ||||||
|  |         for (CrmCustomerDO customer : poolCustomerList) { | ||||||
|  |             try { | ||||||
|  |                 getSelf().putCustomerPool(customer); | ||||||
|  |                 count++; | ||||||
|  |             } catch (Throwable e) { | ||||||
|  |                 log.error("[customerAutoPutPoolBySystem][Customer 客户({}) 放入公海异常]", customer.getId(), e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return count; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void putCustomerPool(CrmCustomerDO customer) { | ||||||
|  |         // 1. 设置负责人为 NULL | ||||||
|  |         int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null); | ||||||
|  |         if (updateOwnerUserIncr == 0) { | ||||||
|  |             throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL); | ||||||
|  |         } | ||||||
|  |         // 2. 删除负责人数据权限 | ||||||
|  |         permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), | ||||||
|  |                 CrmPermissionLevelEnum.OWNER.getLevel()); | ||||||
|  |  | ||||||
|  |         // 3. 联系人的负责人,也要设置为 null。因为:因为领取后,负责人也要关联过来,这块和 receiveCustomer 是对应的 | ||||||
|  |         contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_RECEIVE_SUB_TYPE, bizNo = "{{#customer.id}}", |     @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_RECEIVE_SUB_TYPE, bizNo = "{{#customer.id}}", | ||||||
|             success = CRM_CUSTOMER_RECEIVE_SUCCESS) |             success = CRM_CUSTOMER_RECEIVE_SUCCESS) | ||||||
|     public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) { |     public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) { | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |||||||
| import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; | ||||||
| import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | ||||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; |  | ||||||
| import cn.iocoder.yudao.module.crm.dal.mysql.followup.CrmFollowUpRecordMapper; | import cn.iocoder.yudao.module.crm.dal.mysql.followup.CrmFollowUpRecordMapper; | ||||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||||
| @@ -31,10 +30,10 @@ import java.util.Collections; | |||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED; | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED; | ||||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS; | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS; | ||||||
|  | import static cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils.hasPermission; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 跟进记录 Service 实现类 |  * 跟进记录 Service 实现类 | ||||||
| @@ -94,14 +93,15 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { | |||||||
|             customerService.updateCustomerFollowUp(updateFollowUpReqBO); |             customerService.updateCustomerFollowUp(updateFollowUpReqBO); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // TODO @puhui999:这两个,不更新 contactLastTime、contactLastContent,只更新 nextTime |  | ||||||
|         // 3.1 更新 contactIds 对应的记录 |         // 3.1 更新 contactIds 对应的记录 | ||||||
|         if (CollUtil.isNotEmpty(createReqVO.getContactIds())) { |         if (CollUtil.isNotEmpty(createReqVO.getContactIds())) { | ||||||
|             contactService.updateContactFollowUpBatch(convertList(createReqVO.getContactIds(), updateFollowUpReqBO::setBizId)); |             contactService.updateContactFollowUpBatch(convertList(createReqVO.getContactIds(), | ||||||
|  |                     contactId -> updateFollowUpReqBO.setBizId(contactId).setContactLastTime(null).setContactLastContent(null))); | ||||||
|         } |         } | ||||||
|         // 3.2 需要更新 businessIds、contactIds 对应的记录 |         // 3.2 需要更新 businessIds、contactIds 对应的记录 | ||||||
|         if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) { |         if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) { | ||||||
|             businessService.updateBusinessFollowUpBatch(convertList(createReqVO.getBusinessIds(), updateFollowUpReqBO::setBizId)); |             businessService.updateBusinessFollowUpBatch(convertList(createReqVO.getBusinessIds(), | ||||||
|  |                     businessId -> updateFollowUpReqBO.setBizId(businessId).setContactLastTime(null).setContactLastContent(null))); | ||||||
|         } |         } | ||||||
|         return followUpRecord.getId(); |         return followUpRecord.getId(); | ||||||
|     } |     } | ||||||
| @@ -112,8 +112,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<CrmFollowUpRecordDO> followUpRecords = BeanUtils.toBean(followUpCreateReqBOs, CrmFollowUpRecordDO.class); |         crmFollowUpRecordMapper.insertBatch(BeanUtils.toBean(followUpCreateReqBOs, CrmFollowUpRecordDO.class)); | ||||||
|         crmFollowUpRecordMapper.insertBatch(followUpRecords); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -121,12 +120,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { | |||||||
|         // 校验存在 |         // 校验存在 | ||||||
|         CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id); |         CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id); | ||||||
|         // 校验权限 |         // 校验权限 | ||||||
|         // TODO @puhui999:是不是封装一个 hasPermission,更简介一点; |         if (!hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(), userId, CrmPermissionLevelEnum.OWNER)) { | ||||||
|         List<CrmPermissionDO> permissionList = permissionService.getPermissionListByBiz( |  | ||||||
|                 followUpRecord.getBizType(), followUpRecord.getBizId()); |  | ||||||
|         boolean hasPermission = anyMatch(permissionList, permission -> |  | ||||||
|                 ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), CrmPermissionLevelEnum.OWNER.getLevel())); |  | ||||||
|         if (!hasPermission) { |  | ||||||
|             throw exception(FOLLOW_UP_RECORD_DELETE_DENIED); |             throw exception(FOLLOW_UP_RECORD_DELETE_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ public class CrmUpdateFollowUpReqBO { | |||||||
|  |  | ||||||
|     @Schema(description = "最后跟进时间") |     @Schema(description = "最后跟进时间") | ||||||
|     @DiffLogField(name = "最后跟进时间") |     @DiffLogField(name = "最后跟进时间") | ||||||
|     @NotNull(message = "最后跟进时间不能为空") |  | ||||||
|     private LocalDateTime contactLastTime; |     private LocalDateTime contactLastTime; | ||||||
|  |  | ||||||
|     @Schema(description = "下次联系时间") |     @Schema(description = "下次联系时间") | ||||||
| @@ -30,7 +29,6 @@ public class CrmUpdateFollowUpReqBO { | |||||||
|  |  | ||||||
|     @Schema(description = "最后更进内容") |     @Schema(description = "最后更进内容") | ||||||
|     @DiffLogField(name = "最后更进内容") |     @DiffLogField(name = "最后更进内容") | ||||||
|     @NotNull(message = "最后更进内容不能为空") |  | ||||||
|     private String contactLastContent; |     private String contactLastContent; | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 芋道源码
					芋道源码