Customer.php 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Description: 客户
  4. // +----------------------------------------------------------------------
  5. // | Author: Michael_xu | gengxiaoxu@5kcrm.com
  6. // +----------------------------------------------------------------------
  7. namespace app\bi\model;
  8. use think\Db;
  9. use app\admin\model\Common;
  10. use think\Request;
  11. use think\Validate;
  12. class Customer extends Common
  13. {
  14. /**
  15. * 为了数据库的整洁,同时又不影响Model和Controller的名称
  16. * 我们约定每个模块的数据表都加上相同的前缀,比如CRM模块用crm作为数据表前缀
  17. */
  18. protected $name = 'crm_customer';
  19. /**
  20. * 获取转化客户信息
  21. *
  22. * @param $where
  23. * @param string $sortField
  24. * @param string $sortValue
  25. * @return array
  26. * @throws \think\Exception
  27. * @throws \think\db\exception\DataNotFoundException
  28. * @throws \think\db\exception\ModelNotFoundException
  29. * @throws \think\exception\DbException
  30. */
  31. function getWhereByList($where, $sortField = '', $sortValue = '')
  32. {
  33. if (!empty($sortField) && $sortField == 'name') $sortField = 'a.customer_id';
  34. if (!empty($sortField) && $sortField == 'contract_name') $sortField = 'b.name';
  35. if (!empty($sortField) && $sortField == 'r_money') $sortField = 'r_money';
  36. if (!empty($sortField) && $sortField == 'owner_realname') $sortField = 'a.owner_user_id';
  37. if (!empty($sortField) && $sortField == 'create_time') $sortField = 'b.create_time';
  38. if (!empty($sortField) && $sortField == 'order_time') $sortField = 'b.order_date';
  39. if (empty($sortField)) $sortField = 'r_money';
  40. if (empty($sortValue)) $sortValue = 'desc';
  41. $userModel = new \app\admin\model\User();
  42. $prefix = config('database.prefix');
  43. $count = $this->alias('a')->join(
  44. "(
  45. SELECT
  46. `contract_id`,
  47. `customer_id`,
  48. `name`,
  49. `money`,
  50. `create_time`,
  51. `order_date`
  52. FROM
  53. {$prefix}crm_contract
  54. WHERE
  55. `contract_id` IN (
  56. SELECT
  57. MIN(`contract_id`) as `contract_id`
  58. FROM
  59. `{$prefix}crm_contract`
  60. WHERE
  61. `create_time` > 1572537600
  62. AND `check_status` = 2
  63. GROUP BY
  64. `customer_id`
  65. )
  66. ) b",
  67. 'b.customer_id = a.customer_id',
  68. 'LEFT'
  69. )->join(
  70. "(
  71. SELECT
  72. `contract_id`,
  73. SUM(`money`) AS `r_money`
  74. FROM
  75. `{$prefix}crm_receivables`
  76. GROUP BY
  77. `contract_id`
  78. ) c",
  79. 'c.contract_id = b.contract_id',
  80. 'LEFT'
  81. )->where([
  82. 'a.create_time' => $where['create_time'],
  83. 'a.owner_user_id' => $where['owner_user_id'],
  84. 'a.deal_status' => $where['deal_status'],
  85. 'b.money' => ['gt', 0]
  86. ])->count();
  87. $sql = $this->alias('a')
  88. ->field([
  89. 'a.customer_id',
  90. 'a.name',
  91. 'a.owner_user_id',
  92. 'a.create_user_id',
  93. 'a.industry',
  94. 'a.source',
  95. 'a.create_time',
  96. 'b.name' => 'contract_name',
  97. 'b.money' => 'contract_money',
  98. 'b.order_date' => 'order_time',
  99. 'b.contract_id' => 'contract_id',
  100. 'c.r_money'
  101. ])
  102. ->join(
  103. "(
  104. SELECT
  105. `contract_id`,
  106. `customer_id`,
  107. `name`,
  108. `money`,
  109. `create_time`,
  110. `order_date`
  111. FROM
  112. {$prefix}crm_contract
  113. WHERE
  114. `contract_id` IN (
  115. SELECT
  116. MIN(`contract_id`) as `contract_id`
  117. FROM
  118. `{$prefix}crm_contract`
  119. WHERE
  120. `create_time` > 1572537600
  121. AND `check_status` = 2
  122. GROUP BY
  123. `customer_id`
  124. )
  125. ) b",
  126. 'b.customer_id = a.customer_id',
  127. 'LEFT'
  128. )
  129. ->join(
  130. "(
  131. SELECT
  132. `contract_id`,
  133. SUM(`money`) AS `r_money`
  134. FROM
  135. `{$prefix}crm_receivables`
  136. GROUP BY
  137. `contract_id`
  138. ) c",
  139. 'c.contract_id = b.contract_id',
  140. 'LEFT'
  141. )
  142. ->where([
  143. 'a.create_time' => $where['create_time'],
  144. 'a.owner_user_id' => $where['owner_user_id'],
  145. 'a.deal_status' => $where['deal_status'],
  146. 'b.money' => ['gt', 0]
  147. ])
  148. ->fetchSql()
  149. ->order($sortField, $sortValue)
  150. ->limit(15)
  151. ->select();
  152. $list = queryCache($sql);
  153. foreach ($list as &$val) {
  154. $val['create_time'] = date('Y-m-d',$val['create_time']);
  155. $owner_user = $userModel->getUserById($val['owner_user_id']);
  156. $val['owner_realname'] = $owner_user['realname'];
  157. $create_user = $userModel->getUserById($val['create_user_id']);
  158. $val['create_realname'] = $create_user['realname'];
  159. }
  160. return ['dataCount' => $count, 'list' => $list];
  161. }
  162. /**
  163. * 根据条件获取开始、结束时间
  164. * @author zhi
  165. * @param $type
  166. * @param $year
  167. * @param $i
  168. * @return
  169. */
  170. function getStartAndEnd($param,$year,$i)
  171. {
  172. $timeArr = array();
  173. switch($param['type']) {
  174. case 'year'://本年度
  175. case 'lastYear'://上年度
  176. $type = $year.'-'.$i;
  177. $whereTime = $this->getMonthArray(strtotime($type.'-01'));
  178. break;
  179. case 'quarter'://本季度
  180. $timeType = getTimeByType($param['type']);
  181. $month = date('m',$timeType[0]);
  182. if ($month+$i <= 13) {
  183. $type = $year.'-'.($month+$i-1);
  184. } else {
  185. $type = ($year+1).'-'.'01';
  186. }
  187. $whereTime = $this->getMonthArray(strtotime($type.'-01'));
  188. break;
  189. case 'lastQuarter'://上季度
  190. $timeType = getTimeByType($param['type']);
  191. $month = date('m',$timeType[0]);
  192. $type = $year.'-'.($month+$i-1);
  193. $whereTime = $this->getMonthArray(strtotime($type.'-01'));
  194. break;
  195. case 'month'://本月
  196. $type = $year.'-'.date('m').'-'.$i;
  197. $dateArr = getDateRange(strtotime($type));
  198. $whereTime = [$dateArr['sdate'],$dateArr['edate']];
  199. break;
  200. case 'lastMonth'://上月
  201. $timeType = getTimeByType($param['type']);
  202. $type = date('Y-m',$timeType['0']).'-'.$i;
  203. $dateArr = getDateRange(strtotime($type));
  204. $whereTime = [$dateArr['sdate'],$dateArr['edate']];
  205. break;
  206. case 'week'://本周
  207. case 'lastWeek'://上周
  208. $timeType = getTimeByType($param['type']);
  209. $type = date('Y-m-d',$timeType['0']+($i-1)*86400);
  210. $dateArr = getDateRange(strtotime($type));
  211. $whereTime = [$dateArr['sdate'],$dateArr['edate']];
  212. break;
  213. case 'today'://今天
  214. case 'yesterday'://昨天
  215. $whereTime = getTimeByType($param['type']);
  216. $type = date('Y-m-d',$whereTime[0]);
  217. break;
  218. default ://自定义时间
  219. $subDay = ceil(($param['end_time']-$param['start_time'])/86400);
  220. if ($subDay > 31) {
  221. $param['type'] = 'year';
  222. $res = $this->getStartAndEnd($param,$year,$i);
  223. $whereTime[0] = $res['start_time'];
  224. $whereTime[1] = $res['end_time'];
  225. $type = $res['type'];
  226. } else {
  227. $type = date('Y-m-d',$param['start_time']+($i-1)*86400);
  228. $dateArr = getDateRange(strtotime($type));
  229. $whereTime = [$dateArr['sdate'],$dateArr['edate']];
  230. }
  231. break;
  232. }
  233. $timeArr['start_time'] = $whereTime[0];
  234. $timeArr['end_time'] = $whereTime[1];
  235. $timeArr['type'] = $type;
  236. return $timeArr;
  237. }
  238. /**
  239. * 根据条件获取单位
  240. * @author zhi
  241. * @param
  242. * @return
  243. */
  244. function getParamByCompany($param)
  245. {
  246. $company['year'] = date('Y');
  247. $company['month'] = date('m');
  248. switch($param['type']) {
  249. case 'year'://本年度
  250. $company['j'] = 12;
  251. break;
  252. case 'lastYear'://上年度
  253. $company['j'] = 12;
  254. $company['year'] = date('Y')-1;
  255. break;
  256. case 'quarter'://本季度
  257. $company['j'] = 3;
  258. break;
  259. case 'lastQuarter'://上季度
  260. $company['j'] = 3;
  261. break;
  262. case 'month'://本月
  263. $company['j'] = date("t");
  264. break;
  265. case 'lastMonth'://上月
  266. if (date('m') == 1) {
  267. $m = 12;
  268. } else {
  269. $m = date('m')-1;
  270. }
  271. $days = date('t', strtotime(date('Y').'-'.$m.'-1'));
  272. $company['j'] = $days;
  273. break;
  274. case 'week'://本周
  275. $company['j'] = 7;
  276. break;
  277. case 'lastWeek'://上周
  278. $company['j'] = 7;
  279. break;
  280. case 'today'://今天
  281. $company['j'] = 1;
  282. break;
  283. case 'yesterday'://昨天
  284. $company['j'] = 1;
  285. break;
  286. default ://自定义时间
  287. $whereTime[0] = $param['start_time'];
  288. $whereTime[1] = $param['end_time'];
  289. $subDay = ceil(($param['end_time']-$param['start_time'])/86400);
  290. if ($subDay > 31) {
  291. $company['j'] = 12;
  292. } else {
  293. $company['j'] = $subDay;
  294. }
  295. break;
  296. }
  297. return $company;
  298. }
  299. function getMonthNum($start_m, $end_m){
  300. $date1 = explode('-',$start_m);
  301. $date2 = explode('-',$end_m);
  302. if ($date1[1] < $date2[1]) { //判断月份大小,进行相应加或减
  303. $month_number= abs($date1[0] - $date2[0]) * 12 + abs($date1[1] - $date2[1]);
  304. } else {
  305. $month_number= abs($date1[0] - $date2[0]) * 12 - abs($date1[1] - $date2[1]);
  306. }
  307. return $month_number;
  308. }
  309. /**
  310. * 根据数据获取查询条件
  311. * @author zhi
  312. * @param
  313. * @return
  314. */
  315. function getParamByWhere($param,$type='')
  316. {
  317. $userModel = new \app\admin\model\User();
  318. $whereArr = array();
  319. if (empty($param['type']) && empty($param['start_time'])) {
  320. $param['type'] = 'month';
  321. }
  322. //时间戳:客户跟进分析 、客户转化率分析
  323. if (!empty($param['start_time'])) {
  324. $whereArr['create_time'] = array('between',array($param['start_time'],$param['end_time']));
  325. } else {
  326. $create_time = getTimeByType($param['type']);
  327. if ($create_time) {
  328. $whereArr['create_time'] = array('between',array($create_time[0],$create_time[1]));
  329. }
  330. }
  331. $map_user_ids = [];
  332. if ($param['user_id']) {
  333. $map_user_ids = array($param['user_id']);
  334. } else {
  335. if ($param['structure_id']) {
  336. $map_user_ids = $userModel->getSubUserByStr($param['structure_id'], 2);
  337. }
  338. }
  339. $perUserIds = $userModel->getUserByPer('bi', 'customer', 'read'); //权限范围内userIds
  340. $userIds = $map_user_ids ? array_intersect($map_user_ids, $perUserIds) : $perUserIds; //数组交集
  341. if ($type && $type == 'record') {
  342. $whereArr['create_user_id'] = array('in',$userIds);
  343. } else {
  344. $whereArr['owner_user_id'] = array('in',$userIds);
  345. }
  346. return $whereArr;
  347. }
  348. /**
  349. * 根据自定义字段获取 下拉框数据
  350. * @author zhi
  351. * @param
  352. * @return
  353. */
  354. function getOptionByField($whereArr)
  355. {
  356. $setting = db('admin_field')->where($whereArr)->field('setting')->find();
  357. return explode(chr(10),$setting['setting']);
  358. }
  359. /**
  360. * 根据新增客户数排序
  361. * @author zhi
  362. * @param
  363. * @return
  364. */
  365. function getSortByCount($whereArr)
  366. {
  367. $count = db('crm_customer')->group('owner_user_id')->field('owner_user_id,count(customer_id) as count')->order('count desc')->where($whereArr)->select();
  368. return $count;
  369. }
  370. /**
  371. * 获取成交周期
  372. * @author zhi
  373. * @param
  374. * @return
  375. */
  376. function getWhereByCycle($whereArr)
  377. {
  378. $customerList = db('crm_customer')->field('customer_id,create_time,deal_time')->where($whereArr)->select();
  379. //首次成交
  380. if (!empty($customerList)) {
  381. $cycle_num = 0;
  382. $customer_num = 0;
  383. foreach ($customerList as $key => $value) {
  384. $cycle_time = 0;
  385. $where = array();
  386. $where['customer_id'] = $value['customer_id'];
  387. $create_time = $value['create_time'];
  388. $where['check_status'] = 2;
  389. $contractInfo = db('crm_contract')->where($where)->field('order_date,create_time')->order('order_date asc')->find();
  390. if ($contractInfo['order_date']) {
  391. $cycle_time = ceil((strtotime($order_date)-$create_time)/86400);
  392. } else {
  393. $cycle_time = ceil(($value['deal_time']-$create_time)/86400);
  394. }
  395. if ($cycle_time > 0) {
  396. $cycle_num += $cycle_time;
  397. $customer_num ++;
  398. }
  399. }
  400. if ($cycle_num == 0 || $customer_num == 0) {
  401. $cycle = 0;
  402. } else {
  403. $cycle = ceil($cycle_num/$customer_num);
  404. }
  405. }
  406. return $cycle;
  407. }
  408. /**
  409. * 根据时间获取该时间所在月份开始结束时间
  410. * @author zhi
  411. * @param
  412. * @return
  413. */
  414. public function getMonthArray($time)
  415. {
  416. $start_time = strtotime(date('Y-m-01',$time));
  417. $monthDay = getmonthdays($time);
  418. $end_time = strtotime(date('Y-m-'.$monthDay,$time))+86399;
  419. return array($start_time,$end_time);
  420. }
  421. }