| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- <?php
- /**
- * 使用定时器将符合条件的用户回收到公海池
- *
- * @author fanqi
- * @since 2021-03-31
- */
-
- namespace app\common\command;
-
- use think\Config;
- use think\console\Command;
- use think\console\Input;
- use think\console\input\Argument;
- use think\console\input\Option;
- use think\console\Output;
- use think\Db;
- use think\response\Json;
- use Workerman\Lib\Timer;
- use Workerman\Worker;
-
- class PoolCommand extends Command
- {
- protected $timer;
- protected $interval = 10;
-
- protected function configure()
- {
- $this->setName('pool')
- ->addArgument('status', Argument::REQUIRED, 'start/stop/reload/status/connections')
- ->addOption('d', null, Option::VALUE_NONE, 'daemon(守护进程)方式启动')
- ->setDescription('公海回收定时器');
-
- // 读取数据库配置文件
- $filename = ROOT_PATH . 'config' . DS . 'database.php';
- // 重新加载数据库配置文件
- Config::load($filename, 'database');
- }
-
- /**
- * 初始化
- *
- * @param Input $input
- * @param Output $output
- */
- protected function init(Input $input, Output $output)
- {
- global $argv;
-
- $argv[1] = $input->getArgument('status') ?: 'start';
-
- if ($input->hasOption('d')) {
- $argv[2] = '-d';
- } else {
- unset($argv[2]);
- }
- }
-
- /**
- * 停止定时器
- */
- public function stop()
- {
- Timer::del($this->timer);
- }
-
- /**
- * 启动定时器
- */
- public function start()
- {
- $this->timer = Timer::add($this->interval, function () {
- # 只在凌晨12点至6点间执行
- if ((int)date('H') >= 0 && (int)date('H') < 6) {
- # 公海规则
- $ruleList = db('crm_customer_pool_rule')->alias('rule')->field('rule.*')
- ->join('__CRM_CUSTOMER_POOL__ pool', 'pool.pool_id = rule.pool_id', 'LEFT')->where('pool.status', 1)->select();
-
- if (!empty($ruleList)) {
- # 符合公海条件的客户IDS
- $customerIds = $this->getQueryCondition($ruleList);
-
- # 整理客户公海关联数据
- $poolRelationData = $this->getCustomerPoolRelationData($customerIds);
-
- # 整理修改客户数据的条件(进入公海时间,前负责人...)
- $customerWhere = $this->getCustomerQueryCondition($customerIds);
-
- Db::startTrans();
- try {
- # 将客户退回公海
- if (!empty($poolRelationData)) Db::name('crm_customer_pool_relation')->insertAll($poolRelationData);
-
- # 修改客户数据
- if (!empty($customerWhere)) {
- Db::name('crm_customer')->whereIn('customer_id', $customerWhere)->exp('before_owner_user_id', 'owner_user_id')->update([
- 'ro_user_id' => '',
- 'rw_user_id' => '',
- 'owner_user_id' => 0,
- 'into_pool_time' => time()
- ]);
- }
- $this->updateInfo($ruleList,$customerWhere);
- # 删除联系人的负责人
- Db::name('crm_contacts')->whereIn('customer_id', $customerWhere)->update(['owner_user_id' => '']);
-
- Db::commit();
- } catch (\Exception $e) {
- Db::rollback();
- }
- }
- }
- });
- }
- /**
- * 自动入公海操作记录
- * @param $ruleList
- * @param $customerWhere
- *
- * @author alvin guogaobo
- * @version 1.0 版本号
- * @since 2021/6/3 0003 10:38
- */
- // private function updateInfo($ruleList, $customerWhere)
- // {
- // foreach ($ruleList as $k => $v) {
- // $levels = json_decode($v['level'], true);
- // foreach ($levels as $k1 => $v1) {
- // if (!empty($v1['limit_day'])) {
- // $time = $v1['limit_day'];
- // } else {
- // $time = $this->getMinDay($levels);
- // }
- // }
- // foreach ($customerWhere as $val) {
- // if ($v['type'] == 1) updateActionLog(0, 'crm_customer', $val, '', '', '超过' . $time . '天无新建跟进记录自动进入公海');
- // if ($v['type'] == 2) updateActionLog(0, 'crm_customer', $val, '', '', '超过' . $time . '天无新建商机自动进入公海');
- // if ($v['type'] == 3) updateActionLog(0, 'crm_customer', $val, '', '', '超过' . $time . '天未成交自动进入公海');
- //
- // }
- // }
- // }
- //
-
-
- protected function execute(Input $input, Output $output)
- {
- # 动态修改运行时参数
- set_time_limit(0);
- ini_set('memory_limit', '512M');
-
- $this->init($input, $output);
-
- # 创建定时器任务
- $task = new Worker();
- $task->name = 'pool';
- $task->count = 1;
- $task->onWorkerStart = [$this, 'start'];
- $task->runAll();
- }
-
- /**
- * 整理修改客户数据的条件
- *
- * @param array $customerIds 客户ID
- * @return array
- * @since 2021-04-01
- * @author fanqi
- */
- private function getCustomerQueryCondition($customerIds)
- {
- $result = [];
-
- foreach ($customerIds as $k1 => $v1) {
- foreach ($v1 as $k2 => $v2) {
- $result[] = $v2;
- }
- }
-
- return array_unique($result);
- }
-
- /**
- * 客户公海关联数据
- *
- * @param array $customerIds 客户ID
- * @return array
- * @since 2021-04-01
- * @author fanqi
- */
- private function getCustomerPoolRelationData($customerIds)
- {
- $result = [];
-
- # 用于排重
- $repeat = [];
-
- foreach ($customerIds as $k1 => $v1) {
- $customerArray = array_unique($v1);
- foreach ($customerArray as $k2 => $v2) {
- if (!empty($repeat[$k1][$v2])) continue;
-
- $result[] = [
- 'pool_id' => $k1,
- 'customer_id' => $v2
- ];
-
- $repeat[$k1][$v2] = $v2;
- }
- }
-
- return $result;
- }
-
- /**
- * 获取符合公海条件的客户
- *
- * @param array $rules 公海规则数据
- * @return array
- * @since 2021-04-01
- * @author fanqi
- */
- private function getQueryCondition($rules)
- {
- $result = [];
-
- foreach ($rules as $k => $v) {
-
- if (!isset($result[$v['pool_id']])) $result[$v['pool_id']] = [];
- if ($v['type'] == 1) $result[$v['pool_id']] = array_merge($result[$v['pool_id']], $this->getFollowUpQueryResult($v['level_conf'], $v['level'], $v['deal_handle'], $v['business_handle']));
- if ($v['type'] == 2) $result[$v['pool_id']] = array_merge($result[$v['pool_id']], $this->getBusinessQueryResult($v['level_conf'], $v['level'], $v['deal_handle']));
- if ($v['type'] == 3) $result[$v['pool_id']] = array_merge($result[$v['pool_id']], $this->getDealQueryResult($v['level_conf'], $v['level'], $v['business_handle']));
- }
-
- return $result;
- }
-
- /**
- * N天内无新建跟进记录的客户
- *
- * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分
- * @param Json $levels 级别数据
- * @param int $dealStatus 是否排除成交用户:1 排除,0 不排除
- * @param int $businessStatus 是否排除有商机用户:1 排除,0 不排除
- * @return array
- * @since 2021-04-01
- * @author fanqi
- */
- private function getFollowUpQueryResult($type, $levels, $dealStatus, $businessStatus)
- {
- # 转换格式
- $levels = json_decode($levels, true);
-
- # 默认条件
- $where = "`customer`.`owner_user_id` > 0";
-
- # 所有用户,不区分级别
- if ($type == 1) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['limit_day'])) {
- $time = time() - 24 * 60 * 60 * $v1['limit_day'];
- $where .= " AND ((`customer`.`last_time` < " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`obtain_time` < " . $time . " AND ISNULL(`customer`.`last_time`)))";
- }
- }
- }
-
- # 根据用户级别设置条件
- if ($type == 2) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['level']) && !empty($v1['limit_day'])) {
- $time = (time() - 24 * 60 * 60 * $v1['limit_day']);
- if ($k1 == 0) {
- $where .= " AND ( ((`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`last_time` < " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` < " . $time . " AND ISNULL(`customer`.`last_time`)))";
- } else {
- $where .= " OR ((`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`last_time` < " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` < " . $time . " AND ISNULL(`customer`.`last_time`)))";
- }
- }
- }
-
- # 获取最小天数,对于没有设置级别的客户数据使用
- $minLimit = $this->getMinDay($levels);
- $minTime = (time() - 24 * 60 * 60 * $minLimit);
-
- $where .= " OR ((!`customer`.`level` AND `customer`.`last_time` < " . $minTime . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (!`customer`.`level` AND `customer`.`obtain_time` < " . $minTime . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (!`customer`.`level` AND `customer`.`obtain_time` < " . $minTime . " AND ISNULL(`customer`.`last_time`))) )";
- }
-
- # 选择不进入公海的客户(已成交客户)
- if (!empty($dealStatus)) $where .= " AND (`customer`.`deal_status` <> '已成交' OR ISNULL(`customer`.`deal_status`))";
-
- # 选择不进入公海的客户(有商机客户)
- if (!empty($businessStatus)) $where .= " AND ISNULL(`business`.`customer_id`)";
-
- # 锁定的客户不提醒
- $where .= " AND `customer`.`is_lock` = 0";
-
- # 查询符合条件的客户
- return db('crm_customer')
- ->alias('customer')->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT')
- ->where($where)->column('customer.customer_id');
- }
-
- /**
- * N天内无新建商机的客户
- *
- * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分
- * @param Json $levels 级别数据
- * @param int $dealStatus 是否排除成交用户:1 排除,0 不排除
- * @return array|false|string
- * @since 2021-04-01
- * @author fanqi
- */
- private function getBusinessQueryResult($type, $levels, $dealStatus)
- {
- # 转换格式
- $levels = json_decode($levels, true);
-
- # 默认条件
- $where = "`customer`.`owner_user_id` > 0";
-
- # 所有用户,不区分级别
- if ($type == 1) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['limit_day'])) {
- $time = time() - 24 * 60 * 60 * $v1['limit_day'];
- $where .= " AND ( (ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` < " . $time . ") OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `business`.`create_time`) OR (`business`.`create_time` < " . $time . " AND `business`.`create_time` > `customer`.`obtain_time`) )";
- }
- }
- }
-
- # 根据用户级别设置条件
- if ($type == 2) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['level']) && !empty($v1['limit_day'])) {
- $time = time() - 24 * 60 * 60 * $v1['limit_day'];
- if ($k1 == 0) {
- $where .= " AND ( ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` < " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `business`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`business`.`create_time` < " . $time . " AND `business`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))";
- } else {
- $where .= " OR ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` < " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `business`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`business`.`create_time` < " . $time . " AND `business`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))";
- }
- }
- }
-
- # 获取最小天数,对于没有设置级别的客户数据使用
- $minLimit = $this->getMinDay($levels);
- $minTime = (time() - 24 * 60 * 60 * $minLimit);
-
- $where .= " OR ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` < " . $minTime . " AND !`customer`.`level`) OR (`customer`.`obtain_time` < " . $minTime . " AND `customer`.`obtain_time` > `business`.`create_time` AND !`customer`.`level`) OR (`business`.`create_time` < " . $minTime . " AND `business`.`create_time` > `customer`.`obtain_time` AND !`customer`.`level`)) )";
- }
-
- # 选择不进入公海的客户(已成交客户)
- if (!empty($dealStatus)) $where .= " AND (`customer`.`deal_status` <> '已成交' OR ISNULL(`customer`.`deal_status`))";
-
- # 锁定的客户不提醒
- $where .= " AND `customer`.`is_lock` = 0";
-
- # 查询匹配条件的客户
- return db('crm_customer')->alias('customer')
- ->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT')
- ->where($where)->column('customer.customer_id');
- }
-
- /**
- * N天内没有成交的客户
- *
- * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分
- * @param Json $levels 级别数据
- * @param int $businessStatus 是否排除有商机用户:1 排除,0 不排除
- * @return array|false|string
- * @since 2021-04-01
- * @author fanqi
- */
- private function getDealQueryResult($type, $levels, $businessStatus)
- {
- # 转换格式
- $levels = json_decode($levels, true);
-
- # 默认条件
- $where = "`customer`.`owner_user_id` > 0";
-
- # 所有用户,不区分级别
- if ($type == 1) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['limit_day'])) {
- $time = time() - 24 * 60 * 60 * $v1['limit_day'];
- $where .= " AND ( (ISNULL(`contract`.`customer_id`) AND `customer`.`obtain_time` < " . $time . ") OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time`) OR (`contract`.`create_time` < " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time`) )";
- }
- }
- }
-
- # 根据用户级别设置条件
- if ($type == 2) {
- foreach ($levels as $k1 => $v1) {
- if (!empty($v1['level']) && !empty($v1['limit_day'])) {
- $time = time() - 24 * 60 * 60 * $v1['limit_day'];
- if ($k1 == 0) {
- $where .= " AND ( ((ISNULL(`contract`.`customer_id`) AND `customer`.`obtain_time` < " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`contract`.`create_time` < " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))";
- } else {
- $where .= " OR ((ISNULL(`contract`.`customer_id`) AND `customer`.`obtain_time` < " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` < " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`contract`.`create_time` < " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))";
- }
- }
- }
-
- # 获取最小天数,对于没有设置级别的客户数据使用
- $minLimit = $this->getMinDay($levels);
- $minTime = (time() - 24 * 60 * 60 * $minLimit);
-
- $where .= " OR ((ISNULL(`contract`.`customer_id`) AND `customer`.`obtain_time` < " . $minTime . " AND !`customer`.`level`) OR (`customer`.`obtain_time` < " . $minTime . " AND `customer`.`obtain_time` > `contract`.`create_time` AND !`customer`.`level`) OR (`contract`.`create_time` < " . $minTime . " AND `contract`.`create_time` > `customer`.`obtain_time` AND !`customer`.`level`)) )";
- }
-
- # 选择不进入公海的客户(有商机客户)
- if (!empty($businessStatus)) $where .= " AND ISNULL(`business`.`customer_id`)";
-
- # 锁定的客户不提醒
- $where .= " AND `customer`.`is_lock` = 0";
-
- # 查询符合条件的客户
- return db('crm_customer')->alias('customer')
- ->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT')
- ->join('__CRM_CONTRACT__ contract', 'contract.customer_id = customer.customer_id', 'LEFT')
- ->where($where)->column('customer.customer_id');
- }
-
- /**
- * 获取公海规则最小数字(最快进入公海天数)
- *
- * @param $data
- * @return int
- * @since 2021-04-19
- * @author fanqi
- */
- private function getMinDay($data)
- {
- $number = 1;
-
- foreach ($data as $k1 => $v1) {
- if (empty($number) || $v1['limit_day'] < $number) $number = $v1['limit_day'];
- }
-
- return $number;
- }
- }
|