Browse Source

CRM: 客户自动掉入公海

puhui999 1 year ago
parent
commit
ed92bf45ce

+ 4 - 0
yudao-module-crm/yudao-module-crm-biz/pom.xml

@@ -70,5 +70,9 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-test</artifactId>
         </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 7 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java

@@ -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.enums.common.CrmBizTypeEnum;
 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 org.apache.ibatis.annotations.Mapper;
 import org.springframework.lang.Nullable;
@@ -99,4 +100,10 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
         return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
     }
 
+    default List<CrmCustomerDO> selectListByLockStatusAndOwnerUserIdNotNull(Boolean lockStatus) {
+        return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
+                .eq(CrmCustomerDO::getLockStatus, lockStatus)
+                .isNotNull(CrmCustomerDO::getOwnerUserId));
+    }
+
 }

+ 27 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/customer/CrmCustomerAutoPutPoolJob.java

@@ -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);
+    }
+
+}

+ 1 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.crm.job;

+ 7 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java

@@ -126,4 +126,11 @@ public interface CrmCustomerService {
      */
     void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
 
+    /**
+     * 【系统】客户自动掉入公海
+     *
+     * @return 掉入公海数量
+     */
+    int customerAutoPutPoolBySystem();
+
 }

+ 53 - 11
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java

@@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.crm.service.customer;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 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.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO;
 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.dal.dataobject.customer.CrmCustomerDO;
 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.enums.common.CrmBizTypeEnum;
 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.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -55,6 +59,7 @@ import static java.util.Collections.singletonList;
  * @author Wanwan
  */
 @Service
+@Slf4j
 @Validated
 public class CrmCustomerServiceImpl implements CrmCustomerService {
 
@@ -67,6 +72,9 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     private CrmCustomerLimitConfigService customerLimitConfigService;
     @Resource
     @Lazy
+    private CrmCustomerPoolConfigService customerPoolConfigService;
+    @Resource
+    @Lazy
     private CrmContactService contactService;
     @Resource
     @Lazy
@@ -245,17 +253,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
         // 1.3. 校验客户是否锁定
         validateCustomerIsLocked(customer, true);
 
-        // 2.1 设置负责人为 NULL
-        int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null);
-        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);
+        // 2. 客户放入公海
+        putCustomerPool(customer);
 
         // 记录操作日志上下文
         LogRecordContext.putVariable("customerName", customer.getName());
@@ -313,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}}",
             success = CRM_CUSTOMER_RECEIVE_SUCCESS)
     public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) {