CustomerPoolLogic.php 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. <?php
  2. /**
  3. * 客户公海逻辑类
  4. *
  5. * @author fanqi
  6. * @since 2021-04-13
  7. */
  8. namespace app\crm\logic;
  9. use app\admin\model\ActionRecord;
  10. use app\admin\model\Common;
  11. use app\admin\model\Field;
  12. use app\admin\model\File;
  13. use app\admin\model\Record;
  14. use app\crm\model\CustomerConfig;
  15. use PDOStatement;
  16. use think\Collection;
  17. use think\Db;
  18. use think\Model;
  19. class CustomerPoolLogic extends Common
  20. {
  21. /**
  22. * 公海列表
  23. *
  24. * @param $param
  25. * @author fanqi
  26. * @since 2021-04-14
  27. * @return array
  28. */
  29. public function getPoolList($param)
  30. {
  31. $result = ['dataCount' => 0, 'list' => []];
  32. $fieldModel = new Field();
  33. $poolId = $param['pool_id'];
  34. $orderField = $param['order_field'];
  35. $orderType = $param['order_type'];
  36. # 基础条件
  37. $where['relation.pool_id'] = $poolId;
  38. # 普通搜索
  39. $searchMap = [];
  40. if ($param['search'] == '0' || !empty($param['search'])) {
  41. $search = $param['search'];
  42. $searchMap = function($query) use ($search) {
  43. $query->where('customer.name',array('like','%'.$search.'%'))
  44. ->whereOr('customer.mobile',array('like','%'.$search.'%'))
  45. ->whereOr('customer.telephone',array('like','%'.$search.'%'));
  46. };
  47. }
  48. # 处理排序参数
  49. if (!empty($orderField)) {
  50. if ($orderField == 'create_user_id_name') $orderField = 'create_user_id';
  51. if ($orderField == 'before_owner_user_name') $orderField = 'before_owner_user_id';
  52. }
  53. # 公海条件
  54. if ($param['is_excel'] == 1 && !empty($param['customer_id'])) {
  55. $authMap['customer.customer_id'] = ['in', trim(arrayToString($param['customer_id']),',')];
  56. }
  57. # 排序
  58. if (!empty($orderField) && !empty($orderType)) {
  59. $order = $fieldModel->getOrderByFormtype('crm_customer','customer', $orderField, $orderType);
  60. } else {
  61. $order = 'customer.update_time desc';
  62. }
  63. # 删除参数
  64. unset($param['pool_id']);
  65. unset($param['search']);
  66. unset($param['order_field']);
  67. unset($param['order_type']);
  68. unset($param['is_excel']);
  69. unset($param['customer_id']);
  70. # 格式化参数
  71. $request = $this->fmtRequest( $param );
  72. $requestMap = !empty($request['map']) ? $request['map'] : [];
  73. # 高级搜索
  74. $map = where_arr($requestMap, 'crm', 'customer', 'index');
  75. # 公海字段
  76. $customerFieldString = $this->getPoolQueryField($poolId);
  77. # 公海数据
  78. $customerPoolCount = db('crm_customer_pool_relation')->alias('relation')
  79. ->join('__CRM_CUSTOMER__ customer', 'customer.customer_id = relation.customer_id', 'LEFT')
  80. ->where($where)->where($searchMap)->where($map)->where($authMap)->count();
  81. if (empty($customerPoolCount)) return $result;
  82. $customerPoolList = db('crm_customer_pool_relation')->alias('relation')->field($customerFieldString)
  83. ->join('__CRM_CUSTOMER__ customer', 'customer.customer_id = relation.customer_id', 'LEFT')
  84. ->limit($request['offset'], $request['length'])->where($where)->where($searchMap)->where($map)->where($authMap)->orderRaw($order)->select();
  85. # 员工列表
  86. $userData = $this->getUserList();
  87. # 部门列表
  88. $structureData = $this->getStructureList();
  89. # 特殊字段
  90. $userField = $fieldModel->getFieldByFormType('crm_customer', 'user'); # 人员类型
  91. $structureField = $fieldModel->getFieldByFormType('crm_customer', 'structure'); # 部门类型
  92. $datetimeField = $fieldModel->getFieldByFormType('crm_customer', 'datetime'); # 日期时间类型
  93. # 整理公海数据
  94. foreach ($customerPoolList AS $key => $value) {
  95. $customerPoolList[$key]['create_user_name'] = !empty($userData[$value['create_user_id']]) ? $userData[$value['create_user_id']] : '';
  96. $customerPoolList[$key]['before_owner_user_name'] = !empty($userData[$value['before_owner_user_id']]) ? $userData[$value['before_owner_user_id']] : '';
  97. $customerPoolList[$key]['next_time'] = !empty($value['next_time']) ? date('Y-m-d H:i:s', $value['next_time']) : null;
  98. $customerPoolList[$key]['update_time'] = !empty($value['update_time']) ? date('Y-m-d H:i:s', $value['update_time']) : null;
  99. $customerPoolList[$key]['create_time'] = !empty($value['create_time']) ? date('Y-m-d H:i:s', $value['create_time']) : null;
  100. $customerPoolList[$key]['last_time'] = !empty($value['last_time']) ? date('Y-m-d H:i:s', $value['last_time']) : null;
  101. $customerPoolList[$key]['into_pool_time'] = !empty($value['into_pool_time']) ? date('Y-m-d H:i:s', $value['into_pool_time']) : null;
  102. # 处理日期时间类型的自定义字段
  103. foreach ($datetimeField AS $k => $v) {
  104. if (isset($datetimeField[$key][$v])) {
  105. $datetimeField[$key][$v] = !empty($value[$v]) ? date('Y-m-d H:i:s', $value[$v]) : null;
  106. }
  107. }
  108. # 处理人员类型的自定义字段
  109. foreach ($userField AS $k => $v) {
  110. if (isset($datetimeField[$key][$v]) && !empty($value[$v])) {
  111. $datetimeField[$key][$v] = $this->fieldTransformToText($value[$v], $userData);
  112. }
  113. }
  114. # 处理部门类型的自定义字段
  115. foreach ($structureField AS $k => $v) {
  116. if (isset($datetimeField[$key][$v]) && !empty($value[$v])) {
  117. $datetimeField[$key][$v] = $this->fieldTransformToText($value[$v], $structureData);
  118. }
  119. }
  120. }
  121. $result['dataCount'] = $customerPoolCount;
  122. $result['list'] = $customerPoolList;
  123. return $result;
  124. }
  125. /**
  126. * 公海详情
  127. *
  128. * @param array $param pool_id 公海ID,customer_id 客户ID
  129. * @author fanqi
  130. * @since 2021-04-14
  131. * @return array|bool|PDOStatement|string|Model|null
  132. */
  133. public function getPoolData($param)
  134. {
  135. # 更新用户自定义字段样式
  136. $this->updateFieldStyle($param);
  137. # 公海字段
  138. $fields = $this->getPoolQueryField($param['pool_id']);
  139. $data = db('crm_customer')->alias('customer')->field($fields)->where('customer_id', $param['customer_id'])->find();
  140. $fieldModel = new Field();
  141. # 员工列表
  142. $userData = $this->getUserList();
  143. # 部门列表
  144. $structureData = $this->getStructureList();
  145. # 特殊字段
  146. $userField = $fieldModel->getFieldByFormType('crm_customer', 'user'); # 人员类型
  147. $structureField = $fieldModel->getFieldByFormType('crm_customer', 'structure'); # 部门类型
  148. $datetimeField = $fieldModel->getFieldByFormType('crm_customer', 'datetime'); # 日期时间类型
  149. # 整理公海数据
  150. $data['create_user_name'] = !empty($userData[$data['create_user_id']]) ? $userData[$data['create_user_id']] : '';
  151. $data['before_owner_user_name'] = !empty($userData[$data['before_owner_user_id']]) ? $userData[$data['before_owner_user_id']] : '';
  152. $data['next_time'] = !empty($data['next_time']) ? date('Y-m-d H:i:s', $data['next_time']) : null;
  153. $data['update_time'] = !empty($data['update_time']) ? date('Y-m-d H:i:s', $data['update_time']) : null;
  154. $data['create_time'] = !empty($data['create_time']) ? date('Y-m-d H:i:s', $data['create_time']) : null;
  155. $data['last_time'] = !empty($data['last_time']) ? date('Y-m-d H:i:s', $data['last_time']) : null;
  156. $data['into_pool_time'] = !empty($data['into_pool_time']) ? date('Y-m-d H:i:s', $data['into_pool_time']) : null;
  157. # 处理日期时间类型的自定义字段
  158. foreach ($datetimeField AS $k => $v) {
  159. if (isset($data[$v])) {
  160. $data[$v] = !empty($data[$v]) ? date('Y-m-d H:i:s', $data[$v]) : null;
  161. }
  162. }
  163. # 处理人员类型的自定义字段
  164. foreach ($userField AS $k => $v) {
  165. if (isset($data[$v]) && !empty($data[$v])) {
  166. $data[$v] = $this->fieldTransformToText($data[$v], $userData);
  167. }
  168. }
  169. # 处理部门类型的自定义字段
  170. foreach ($structureField AS $k => $v) {
  171. if (isset($data[$v]) && !empty($data[$v])) {
  172. $data[$v] = $this->fieldTransformToText($data[$v], $structureData);
  173. }
  174. }
  175. return $data;
  176. }
  177. /**
  178. * @param array $param
  179. * @return array
  180. */
  181. public function deletePoolCustomer($param)
  182. {
  183. if (empty($param['user_id'])) return ['缺少用户ID!'];
  184. # 消息数据
  185. $message = [];
  186. $customerId = $param['id'];
  187. # 查询客户列表数据
  188. $customerData = $this->getCustomerList($customerId);
  189. # 验证是否是公海数据
  190. foreach ($customerId AS $key => $value) {
  191. if (empty($customerData[$value])) {
  192. $message[] = '删除 《' . $customerData[$value]['name'] . '》 失败,原因:公海客户不存在!';
  193. unset($customerId[(int)$key]);
  194. }
  195. if (!empty($customerData[$value]['owner_user_id'])) {
  196. $message[] = '删除 《' . $customerData[$value]['name'] . '》 失败,原因:不是公海客户!';
  197. unset($customerId[(int)$key]);
  198. }
  199. }
  200. # 验证是否还有需要删除的客户
  201. if (empty($customerId)) return $message;
  202. # 查询与客户有关的数据
  203. $customerContactsData = db('crm_contacts')->whereIn('customer_id', $customerId)->column('customer_id');
  204. $customerBusinessData = db('crm_business')->whereIn('customer_id', $customerId)->column('customer_id');
  205. $customerContractData = db('crm_contract')->whereIn('customer_id', $customerId)->column('customer_id');
  206. # 验证客户下是否存在联系人、商机、合同
  207. foreach ($customerId AS $key => $value) {
  208. if (in_array($value, $customerContactsData)) {
  209. $message[] = '删除 《' . $customerData[$value]['name'] . '》 失败,原因:客户下存在联系人!';
  210. unset($customerId[(int)$key]);
  211. }
  212. if (in_array($value, $customerBusinessData)) {
  213. $message[] = '删除 《' . $customerData[$value]['name'] . '》 失败,原因:客户下存在商机!';
  214. unset($customerId[(int)$key]);
  215. }
  216. if (in_array($value, $customerContractData)) {
  217. $message[] = '删除 《' . $customerData[$value]['name'] . '》 失败,原因:客户下存在合同!';
  218. unset($customerId[(int)$key]);
  219. }
  220. }
  221. # 删除客户
  222. if (!empty($customerId)) {
  223. if (db('crm_customer')->whereIn('customer_id', $customerId)->delete()) {
  224. # 删除公海关联数据
  225. db('crm_customer_pool_relation')->whereIn('customer_id', $customerId)->delete();
  226. # 删除跟进记录
  227. (new Record())->delDataByTypes(2, $customerId);
  228. # 删除关联附件
  229. (new File())->delRFileByModule('crm_customer', $customerId);
  230. # 删除关联操作记录
  231. (new ActionRecord())->delDataById(['types' => 'crm_customer', 'action_id' => $customerId]);
  232. # 记录到数据操作日志
  233. $ip = request()->ip();
  234. $addOperationLogData = [];
  235. foreach ($customerId AS $key => $value) {
  236. $addOperationLogData[] = [
  237. 'user_id' => $param['user_id'],
  238. 'client_ip' => $ip,
  239. 'module' => 'crm_customer',
  240. 'action_id' => $value,
  241. 'content' => '删除了客户:' . $customerData[$value]['name'],
  242. 'create_time' => time(),
  243. 'action_name' => 'delete',
  244. 'target_name' => $customerData[$value]['name']
  245. ];
  246. }
  247. db('admin_operation_log')->insertAll($addOperationLogData);
  248. } else {
  249. $message[] = '删除客户失败,请刷新后重试!';
  250. }
  251. }
  252. return $message;
  253. }
  254. /**
  255. * 获取公海池列表
  256. *
  257. * @param array $param 查询参数:user_id 用户id,structure_id 部门id
  258. * @author fanqi
  259. * @since 2021-04-21
  260. * @return bool|PDOStatement|string|Collection
  261. */
  262. public function getPondList($param)
  263. {
  264. return db('crm_customer_pool')->field(['pool_id', 'pool_name'])
  265. ->where('status', 1)
  266. ->where(function ($query) use ($param) {
  267. $query->where('admin_user_ids', 'like', '%,' . $param['user_id'] . ',%');
  268. $query->whereOr('user_ids', 'like', '%,' . $param['user_id'] . ',%');
  269. $query->whereOr('department_ids', '%,' . $param['structure_id'] . ',%');
  270. })->select();
  271. }
  272. /**
  273. * 获取公海字段
  274. *
  275. * @param array $param pool_id 公海ID,action 操作类型,action_id 数据id
  276. * @author fanqi
  277. * @since 2021-04-13
  278. * @return array
  279. */
  280. public function getFieldList($param)
  281. {
  282. $data = [];
  283. # 自定义字段
  284. $list = db('crm_customer_pool_field_setting')->where('pool_id', $param['pool_id'])->where('is_hidden', 0)->select();
  285. # 处理公海字段
  286. foreach ($list AS $key => $value) {
  287. $list[$key]['field'] = $value['field_name'];
  288. # 处理别名
  289. switch ($value['field_name']) {
  290. case 'create_user_id' :
  291. $list[$key]['fieldName'] = 'create_user_name';
  292. break;
  293. case 'before_owner_user_id' :
  294. $list[$key]['fieldName'] = 'before_owner_user_name';
  295. break;
  296. default :
  297. $list[$key]['fieldName'] = $value['field_name'];
  298. }
  299. if (in_array($value['form_type'], ['user', 'structure']) && !in_array($value['field_name'], ['create_user_id', 'owner_user_id', 'before_owner_user_id'])) {
  300. $list[$key]['fieldName'] = $value['field_name'] . '_name';
  301. }
  302. if (in_array($value['field_name'], ['last_record', 'create_user_id', 'create_time', 'update_time', 'last_time', 'deal_status'])) {
  303. $list[$key]['system'] = 1;
  304. } else {
  305. $list[$key]['system'] = 0;
  306. }
  307. $data[$list[$key]['field']] = [
  308. 'field' => $list[$key]['field'],
  309. 'fieldName' => $list[$key]['fieldName'],
  310. 'name' => $list[$key]['name'],
  311. 'width' => '',
  312. 'is_hidden' => 1,
  313. 'system' => $list[$key]['system'],
  314. 'form_type' => $list[$key]['form_type']
  315. ];
  316. }
  317. # 公海字段样式
  318. $list = $this->setFieldStyle($param, $data);
  319. return array_values((array)$list);
  320. }
  321. /**
  322. * 高级筛选字段列表
  323. *
  324. * @author fanqi
  325. * @since 2021-04-14
  326. * @return array
  327. */
  328. public function getAdvancedFilterFieldList()
  329. {
  330. # 基础字段
  331. $base = [
  332. ['field' => 'address', 'name' => '省、市、区/县', 'form_type' => 'address', 'setting' => ''],
  333. ['field' => 'detail_address', 'name' => '详细地址', 'form_type' => 'text', 'setting' => ''],
  334. ['field' => 'last_record', 'name' => '最后跟进记录', 'form_type' => 'text', 'setting' => ''],
  335. ['field' => 'last_time', 'name' => '最后跟进时间', 'form_type' => 'datetime', 'setting' => ''],
  336. ['field' => 'create_time', 'name' => '创建时间', 'form_type' => 'datetime', 'setting' => ''],
  337. ['field' => 'update_time', 'name' => '更新时间', 'form_type' => 'datetime', 'setting' => ''],
  338. ['field' => 'create_user_id', 'name' => '创建人', 'form_type' => 'user', 'setting' => ''],
  339. ['field' => 'before_owner_user_id', 'name' => '前负责人', 'form_type' => 'user', 'setting' => ''],
  340. ['field' => 'into_pool_time', 'name' => '进入公海时间', 'form_type' => 'datetime', 'setting' => ''],
  341. ];
  342. # 自定义字段
  343. $list = db('admin_field')->field(['field', 'name', 'form_type', 'setting'])->where('types', 'crm_customer')->select();
  344. $list = array_merge($list, $base);
  345. # 整理数据
  346. foreach ($list AS $key => $value) {
  347. if (!empty($value['setting'])) $list[$key]['setting'] = explode(chr(10), $value['setting']);
  348. }
  349. return $list;
  350. }
  351. /**
  352. * 领取公海客户
  353. *
  354. * @param array $param user_id 领取人ID,customer_id 要领取的客户ID
  355. * @author fanqi
  356. * @since 2021-04-15
  357. * @return array
  358. */
  359. public function receiveCustomers($param)
  360. {
  361. if (empty($param['user_id'])) return ['缺少员工ID'];
  362. # 查询参数
  363. $userId = $param['user_id'];
  364. $customerId = $param['customer_id'];
  365. # 消息数据
  366. $message = [];
  367. # 查询客户列表数据
  368. $customerData = $this->getCustomerList($customerId);
  369. # 剔除非公海客户
  370. foreach ($customerId AS $key => $value) {
  371. if (!empty($customerData[$value]['owner_user_id'])) {
  372. $message[] = '客户《' . $customerData[$value]['name'] . '》领取失败,失败原因:不是公海客户!';
  373. unset($customerId[(int)$key]);
  374. continue;
  375. }
  376. }
  377. # 检查是否还有要领取的客户
  378. if (empty($customerId)) return $message;
  379. # 获取超出持有客户数的数量
  380. $customerConfigModel = new CustomerConfig();
  381. $exceedCount = $customerConfigModel->checkData($userId, 1, 0, count($customerId));
  382. # 记录添加失败的客户
  383. $failCustomer = [];
  384. if (!is_bool($exceedCount) && !empty($exceedCount) && $exceedCount > 0) {
  385. $failCustomer = array_slice($customerId, count($customerId) - $exceedCount);
  386. foreach ($failCustomer AS $key => $value) {
  387. $message[] = '客户《' . $customerData[$value]['name'] . '》领取失败,失败原因:持有客户数达到上限!';
  388. }
  389. }
  390. # 可以领取的客户ID,取差集
  391. $addCustomerId = count($customerId) == 1 ? $customerId : array_diff($customerId, $failCustomer);
  392. # 检查是否还有要领取的客户
  393. if (empty($addCustomerId)) return $message;
  394. # 公海配置
  395. $poolConfig = db('crm_customer_pool')->field(['before_owner_conf', 'before_owner_day', 'receive_conf', 'receive_count'])->where('pool_id', $param['pool_id'])->find();
  396. # 前负责人N天内不能领取客户
  397. if (!empty($poolConfig['before_owner_conf'])) {
  398. foreach ($addCustomerId AS $key => $value) {
  399. # 是前负责人,检查前负责人是否能够领取。
  400. if ($userId == $customerData[$value]['before_owner_user_id']) {
  401. $restrictDay = $customerData[$value]['into_pool_time'] + 86400 * $poolConfig['before_owner_day'];
  402. if (time() < $restrictDay) {
  403. $message[] = '客户《' . $customerData[$value]['name'] . '》领取失败,失败原因:进入公海后,'.$poolConfig['before_owner_day'].'天内不能领取!';
  404. unset($addCustomerId[(int)$key]);
  405. }
  406. }
  407. }
  408. }
  409. # 检查是否还有要领取的客户
  410. if (empty($addCustomerId)) return $message;
  411. # 检查每天领取的个数限制
  412. $countWhere['type'] = 1;
  413. $countWhere['pool_id'] = $param['pool_id'];
  414. $countWhere['user_id'] = $userId;
  415. $countWhere['create_time'] = ['between', [strtotime(date('Y-m-d 00:00:00')), strtotime(date('Y-m-d 23:59:59'))]];
  416. $receiveCount = db('crm_customer_pool_record')->where($countWhere)->count();
  417. if (!empty($poolConfig['receive_conf']) && $receiveCount + count($addCustomerId) > $poolConfig['receive_count']) {
  418. $overQuantity = ($receiveCount + count($addCustomerId)) - $poolConfig['receive_count'];
  419. $message[] = '领取客户失败,失败原因:超出当日可领取数量,超出'.$overQuantity.'个!';
  420. return $message;
  421. }
  422. # 整理客户更新数据
  423. $addCustomerData = [
  424. 'owner_user_id' => $userId,
  425. 'before_owner_user_id' => 0,
  426. 'into_pool_time' => 0,
  427. 'obtain_time' => time()
  428. ];
  429. # 整理字段操作记录和数据日志的数据
  430. $ip = request()->ip();
  431. $addActionRecordData = [];
  432. $addOperationLogData = [];
  433. $addReceiveData = [];
  434. foreach ($addCustomerId AS $key => $value) {
  435. $addActionRecordData[] = [
  436. 'user_id' => $userId,
  437. 'types' => 'crm_customer',
  438. 'action_id' => $value,
  439. 'content' => '领取了客户',
  440. 'create_time' => time()
  441. ];
  442. $addOperationLogData[] = [
  443. 'user_id' => $userId,
  444. 'client_ip' => $ip,
  445. 'module' => 'crm_customer',
  446. 'action_id' => $value,
  447. 'content' => '领取了客户',
  448. 'create_time' => time(),
  449. 'action_name' => 'update',
  450. 'target_name' => $customerData[$value]['name']
  451. ];
  452. $addReceiveData[] = [
  453. 'customer_id' => $value,
  454. 'user_id' => $userId,
  455. 'pool_id' => $param['pool_id'],
  456. 'type' => 1,
  457. 'create_time' => time()
  458. ];
  459. }
  460. Db::startTrans();
  461. try {
  462. # 领取客户
  463. Db::name('crm_customer')->whereIn('customer_id', $addCustomerId)->update($addCustomerData);
  464. # 设置客户的联系人数据
  465. Db::name('crm_contacts')->whereIn('customer_id', $addCustomerId)->update(['owner_user_id' => $userId]);
  466. # 删除公海与客户关联数据
  467. Db::name('crm_customer_pool_relation')->whereIn('customer_id', $addCustomerId)->delete();
  468. # 字段操作日志
  469. Db::name('admin_action_record')->insertAll($addActionRecordData);
  470. # 数据操作日志
  471. Db::name('admin_operation_log')->insertAll($addOperationLogData);
  472. # 记录领取的客户
  473. Db::name('crm_customer_pool_record')->insertAll($addReceiveData);
  474. Db::commit();
  475. } catch (\Exception $e) {
  476. Db::rollback();
  477. $message = ['领取失败,刷新后重试!'];
  478. }
  479. return $message;
  480. }
  481. /**
  482. * 分配客户
  483. *
  484. * @param array $param user_id 员工ID,customer_id 客户ID
  485. * @author fanqi
  486. * @since 2021-04-15
  487. * @return array
  488. */
  489. public function distributeCustomer($param)
  490. {
  491. # 查询参数
  492. $userId = $param['user_id'];
  493. $customerId = $param['customer_id'];
  494. $username = db('admin_user')->where('id', $userId)->value('realname');
  495. # 消息数据
  496. $message = [];
  497. # 查询客户列表数据
  498. $customerData = $this->getCustomerList($customerId);
  499. # 剔除非公海客户
  500. foreach ($customerId AS $key => $value) {
  501. if (!empty($customerData[$value]['owner_user_id'])) {
  502. $message[] = '将客户《' . $customerData[$value]['name'] . '》分配给员工' . $username . '失败,失败原因:不是公海客户!';
  503. unset($customerId[(int)$key]);
  504. continue;
  505. }
  506. }
  507. # 检查是否还有要领取的客户
  508. if (empty($customerId)) return $message;
  509. # 获取超出持有客户数的数量
  510. $customerConfigModel = new CustomerConfig();
  511. $exceedCount = $customerConfigModel->checkData($userId, 1, 0, count($customerId));
  512. # 记录添加失败的客户
  513. $failCustomer = [];
  514. if (!is_bool($exceedCount) && !empty($exceedCount) && $exceedCount > 0) {
  515. $failCustomer = array_slice($customerId, count($customerId) - $exceedCount);
  516. foreach ($failCustomer AS $key => $value) {
  517. $message[] = '将客户《' . $customerData[$value]['name'] . '》分配给员工' . $username . '失败,失败原因:持有客户数达到上限!';
  518. }
  519. }
  520. # 可以领取的客户ID,取差集
  521. $addCustomerId = count($customerId) == 1 ? $customerId : array_diff($customerId, $failCustomer);
  522. # 检查是否还有要领取的客户
  523. if (empty($addCustomerId)) return $message;
  524. # 整理客户更新数据
  525. $addCustomerData = [
  526. 'owner_user_id' => $userId,
  527. 'before_owner_user_id' => 0,
  528. 'into_pool_time' => 0,
  529. 'obtain_time' => time(),
  530. 'is_dealt' => 0,
  531. 'is_allocation' => 1,
  532. 'follow' => '待跟进'
  533. ];
  534. # 整理字段操作记录和数据日志的数据
  535. $ip = request()->ip();
  536. $addActionRecordData = [];
  537. $addOperationLogData = [];
  538. $addReceiveData = [];
  539. foreach ($addCustomerId AS $key => $value) {
  540. $addActionRecordData[] = [
  541. 'user_id' => $userId,
  542. 'types' => 'crm_customer',
  543. 'action_id' => $value,
  544. 'content' => '将客户 ' . $customerData[$value]['name'] . ' 分配给员工 ' . $username,
  545. 'create_time' => time()
  546. ];
  547. $addOperationLogData[] = [
  548. 'user_id' => $userId,
  549. 'client_ip' => $ip,
  550. 'module' => 'crm_customer',
  551. 'action_id' => $value,
  552. 'content' => '将客户 ' . $customerData[$value]['name'] . ' 分配给员工 ' . $username,
  553. 'create_time' => time(),
  554. 'action_name' => 'update',
  555. 'target_name' => $customerData[$value]['name']
  556. ];
  557. $addReceiveData[] = [
  558. 'customer_id' => $value,
  559. 'user_id' => $userId,
  560. 'pool_id' => $param['pool_id'],
  561. 'type' => 3,
  562. 'create_time' => time()
  563. ];
  564. }
  565. Db::startTrans();
  566. try {
  567. # 领取客户
  568. Db::name('crm_customer')->whereIn('customer_id', $addCustomerId)->update($addCustomerData);
  569. # 设置客户的联系人数据
  570. Db::name('crm_contacts')->whereIn('customer_id', $addCustomerId)->update(['owner_user_id' => $userId]);
  571. # 删除公海与客户关联数据
  572. Db::name('crm_customer_pool_relation')->whereIn('customer_id', $addCustomerId)->delete();
  573. # 字段操作日志
  574. Db::name('admin_action_record')->insertAll($addActionRecordData);
  575. # 数据操作日志
  576. Db::name('admin_operation_log')->insertAll($addOperationLogData);
  577. # 记录领取的客户
  578. Db::name('crm_customer_pool_record')->insertAll($addReceiveData);
  579. Db::commit();
  580. } catch (\Exception $e) {
  581. Db::rollback();
  582. $message = ['分配失败,刷新后重试!'];
  583. }
  584. return $message;
  585. }
  586. /**
  587. * 公海权限
  588. *
  589. * @param $param
  590. * @author fanqi
  591. * @since 2021-04-14
  592. * @return array
  593. */
  594. public function getAuthorityData($param)
  595. {
  596. # 权限
  597. $authority = [
  598. 'index' => false, # 列表
  599. 'receive' => false, # 领取
  600. 'distribute' => false, # 分配
  601. 'excelexport' => false, # 导出
  602. 'excelimport' => false, # 导入
  603. 'delete' => false, # 删除
  604. ];
  605. if (empty($param['pool_id']) || empty($param['user_id']) || empty($param['structure_id'])) return $authority;
  606. $poolId = $param['pool_id'];
  607. $userId = $param['user_id'];
  608. $structureId = $param['structure_id'];
  609. # 是否是超级管理员
  610. $userLevel = isSuperAdministrators($param['user_id']);
  611. # 公海成员数据
  612. $data = db('crm_customer_pool')->field(['admin_user_ids', 'user_ids', 'department_ids'])->where('pool_id', $poolId)->find();
  613. # 管理员、成员、部门
  614. $adminUserIds = !empty($data['admin_user_ids']) ? explode(',', trim($data['admin_user_ids'], ',')) : [];
  615. $userIds = !empty($data['user_ids']) ? explode(',', trim($data['user_ids'], ',')) : [];
  616. $structureIds = !empty($data['department_ids']) ? explode(',', trim($data['department_ids'], ',')) : [];
  617. # 权限判断
  618. $authority['index'] = ($userLevel || in_array($userId, $adminUserIds)) || (in_array($userId, $userIds) || in_array($structureId, $structureIds));
  619. $authority['receive'] = ($userLevel || in_array($userId, $adminUserIds)) || (in_array($userId, $userIds) || in_array($structureId, $structureIds));
  620. $authority['distribute'] = $userLevel || in_array($userId, $adminUserIds);
  621. $authority['excelexport'] = $userLevel || in_array($userId, $adminUserIds);
  622. $authority['excelimport'] = $userLevel || in_array($userId, $adminUserIds);
  623. $authority['delete'] = $userLevel || in_array($userId, $adminUserIds);
  624. return $authority;
  625. }
  626. /**
  627. * 获取用户公海字段样式
  628. *
  629. * @param array $param pool 公海ID,user_is 用户ID
  630. * @author fanqi
  631. * @since 2021-04-22
  632. * @return array[]
  633. */
  634. public function getFieldConfigIndex($param)
  635. {
  636. $showList = [];
  637. $hideList = [];
  638. # 公海字段-用户配置数据
  639. $data = db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->value('content');
  640. $data = !empty($data) ? json_decode($data, true) :[];
  641. if (!empty($data)) {
  642. foreach ($data AS $key => $value) {
  643. if (!empty($value['is_hidden'])) {
  644. $hideList[] = $value;
  645. } else {
  646. $showList[] = $value;
  647. }
  648. }
  649. } else {
  650. # 公海字段-后台配置数据
  651. $poolField = db('crm_customer_pool_field_setting')->where('pool_id', $param['pool_id'])->select();
  652. foreach ($poolField AS $key => $value) {
  653. if (empty($value['is_hidden'])) {
  654. $showList[] = [
  655. 'field' => $value['field_name'],
  656. 'name' => $value['name'],
  657. 'form_type' => $value['form_type'],
  658. 'is_hidden' => $value['is_hidden'],
  659. 'width' => ''
  660. ];
  661. }
  662. }
  663. }
  664. return ['value_list' => $showList, 'hide_list' => $hideList];
  665. }
  666. /**
  667. * 设置公海字段列宽
  668. *
  669. * @param array $param pool_id 公海ID,field 字段名,width 宽度
  670. * @author fanqi
  671. * @since 2021-04-22
  672. */
  673. public function setFieldWidth($param)
  674. {
  675. $data = db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->value('content');
  676. $data = !empty($data) ? json_decode($data, true) :[];
  677. if (!empty($data)) {
  678. foreach ($data AS $key => $value) {
  679. if ($param['field'] == $value['field']) {
  680. $data[$key]['width'] = $param['width'];
  681. }
  682. }
  683. db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->update([
  684. 'content' => json_encode($data),
  685. 'update_time' => time()
  686. ]);
  687. } else {
  688. $result = [];
  689. $poolField = db('crm_customer_pool_field_setting')->where('pool_id', $param['pool_id'])->select();
  690. foreach ($poolField AS $key => $value) {
  691. if ($param['field'] == $value['field_name']) {
  692. $value['width'] = $param['width'];
  693. }
  694. $result[] = [
  695. 'field' => $value['field_name'],
  696. 'name' => $value['name'],
  697. 'width' => $value['width'],
  698. 'is_hidden' => $value['hidden']
  699. ];
  700. }
  701. if (!empty($result)) {
  702. db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->insert([
  703. 'user_id' => $param['user_id'],
  704. 'pool_id' => $param['pool_id'],
  705. 'content' => json_encode($result),
  706. 'create_time' => time(),
  707. 'update_time' => time()
  708. ]);
  709. }
  710. }
  711. }
  712. /**
  713. * 设置公海字段样式
  714. *
  715. * @param array $param pool_id 公海ID,value 要显示的字段数组,hide_value 要隐藏的字段数组
  716. * @author fanqi
  717. * @since 2021-04-22
  718. */
  719. public function setFieldConfig($param)
  720. {
  721. $data = [];
  722. $showList = $param['value'];
  723. $hideList = $param['hide_value'];
  724. foreach ($showList AS $key => $value) {
  725. $data[] = [
  726. 'field' => $value['field'],
  727. 'name' => $value['name'],
  728. 'is_hidden' => 0,
  729. 'width' => $value['width']
  730. ];
  731. }
  732. foreach ($hideList AS $key => $value) {
  733. $data[] = [
  734. 'field' => $value['field'],
  735. 'name' => $value['name'],
  736. 'is_hidden' => 1,
  737. 'width' => $value['width']
  738. ];
  739. }
  740. if (db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->value('id')) {
  741. db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->update([
  742. 'content' => json_encode($data),
  743. 'update_time' => time()
  744. ]);
  745. } else {
  746. db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->insert([
  747. 'user_id' => $param['user_id'],
  748. 'pool_id' => $param['pool_id'],
  749. 'content' => json_encode($data),
  750. 'create_time' => time(),
  751. 'update_time' => time()
  752. ]);
  753. }
  754. }
  755. /**
  756. * 数据的ID字符串转文字
  757. *
  758. * @param string $source 源ids
  759. * @param array $target 目标数组
  760. * @author fanqi
  761. * @since 2021-04-14
  762. * @return string
  763. */
  764. private function fieldTransformToText($source, $target)
  765. {
  766. $result = [];
  767. $array = explode(',', trim($source, ','));
  768. foreach ($array AS $kk => $vv) {
  769. if (!empty($target[$vv])) $result[] = $target[$vv];
  770. }
  771. return implode(',', $result);
  772. }
  773. /**
  774. * 查询表字段
  775. *
  776. * @param int $poolId 公海ID
  777. * @author fanqi
  778. * @since 2021-04-14
  779. * @return string
  780. */
  781. private function getPoolQueryField($poolId)
  782. {
  783. # 自定义字段
  784. $customerFields = db('crm_customer_pool_field_setting')->where('pool_id', $poolId)->column('field_name');
  785. $customerFields[] = 'customer_id';
  786. # 自定增加表别名
  787. $result = array_reduce($customerFields, function ($result, $value) {
  788. return $result . 'customer.' . $value . ',';
  789. });
  790. return trim($result, ',');
  791. }
  792. /**
  793. * 获取员工列表
  794. *
  795. * @author fanqi
  796. * @since 2021-04-14
  797. * @return array
  798. */
  799. private function getUserList()
  800. {
  801. $result = [];
  802. $list = db('admin_user')->field(['id', 'realname'])->select();
  803. foreach ($list AS $key => $value) {
  804. $result[$value['id']] = $value['realname'];
  805. }
  806. return $result;
  807. }
  808. /**
  809. * 获取部门列表
  810. *
  811. * @author fanqi
  812. * @since 2021-04-14
  813. * @return array
  814. */
  815. private function getStructureList()
  816. {
  817. $result = [];
  818. $list = db('admin_structure')->field(['id', 'name'])->select();
  819. foreach ($list AS $key => $value) {
  820. $result[$value['id']] = $value['name'];
  821. }
  822. return $result;
  823. }
  824. /**
  825. * 获取客户列表
  826. *
  827. * @param array $customerId 客户ID
  828. * @author fanqi
  829. * @since 2021-04-15
  830. * @return array
  831. */
  832. private function getCustomerList($customerId)
  833. {
  834. $result = [];
  835. # 获取客户数据
  836. $customerList = db('crm_customer')->field(['customer_id', 'owner_user_id', 'name', 'into_pool_time', 'before_owner_user_id'])->whereIn('customer_id', $customerId)->select();
  837. # 整理客户数据
  838. foreach ($customerList AS $key => $value) {
  839. $result[$value['customer_id']] = $value;
  840. }
  841. return $result;
  842. }
  843. /**
  844. * 设置公海字段样式
  845. *
  846. * @param array $param user_id 用户id,pool_id 公海id
  847. * @param array $data 公海字段数据
  848. * @return array
  849. */
  850. private function setFieldStyle($param, $data)
  851. {
  852. $result = [];
  853. # 更新字段样式
  854. $this->updateFieldStyle($param);
  855. # 查询自定义字段样式列表
  856. $list = db('crm_customer_pool_field_style')->where(['user_id' => $param['user_id'], 'pool_id' => $param['pool_id']])->value('content');
  857. # 如果用户没有自定义数据返回原数据
  858. if (empty($list)) return $data;
  859. $list = json_decode($list, true);
  860. foreach ($list AS $key => $value) {
  861. if (!empty($value['is_hidden']) || empty($data[$value['field']])) continue;
  862. $result[] = [
  863. 'field' => $value['field'],
  864. 'fieldName' => $data[$value['field']]['fieldName'],
  865. 'name' => $value['name'],
  866. 'width' => $value['width'],
  867. 'is_hidden' => 0,
  868. 'system' => $data[$value['field']]['system'],
  869. 'form_type' => $data[$value['field']]['form_type'],
  870. ];
  871. }
  872. return $result;
  873. }
  874. /**
  875. * 更新用户设置的字段样式
  876. *
  877. * @param $param
  878. * @author fanqi
  879. * @since 2021-05-06
  880. */
  881. private function updateFieldStyle($param)
  882. {
  883. if (!empty($param['user_id']) && !empty($param['pool_id'])) {
  884. # 公海字段-用户配置数据
  885. $fieldStyleContent = db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->value('content');
  886. if (!empty($fieldStyleContent)) {
  887. $fieldStyleList = json_decode($fieldStyleContent, true);
  888. # 公海字段-后台配置数据
  889. $poolField = db('crm_customer_pool_field_setting')->where('pool_id', $param['pool_id'])->select();
  890. $poolData = [];
  891. foreach ($poolField AS $key => $value) {
  892. $poolData[$value['field_name']] = $value;
  893. }
  894. # 去掉隐藏的字段 + 去掉已经存在的字段 = 剩下的就是新增(隐藏后又开启)的字段
  895. foreach ($fieldStyleList AS $key => $value) {
  896. # 去掉隐藏的字段
  897. if (empty($poolData[$value['field']]) || (!empty($poolData[$value['field']]) && !empty($poolData[$value['field']]['is_hidden']))) {
  898. unset($fieldStyleList[$key]);
  899. unset($poolData[$value['field']]);
  900. continue;
  901. }
  902. # 后台可能更新了字段名称
  903. $fieldStyleList[$key]['name'] = $poolData[$value['field']]['name'];
  904. # 去掉已经存在的字段
  905. unset($poolData[$value['field']]);
  906. }
  907. # 新增(隐藏后又开启)字段
  908. if (!empty($poolData)) {
  909. foreach ($poolData AS $key => $value) {
  910. if (empty($value['is_hidden'])) {
  911. $fieldStyleList[] = [
  912. 'field' => $value['field_name'],
  913. 'name' => $value['name'],
  914. 'is_hidden' => 0,
  915. 'width' => ''
  916. ];
  917. }
  918. }
  919. }
  920. # 公海字段-更新用户配置
  921. db('crm_customer_pool_field_style')->where(['pool_id' => $param['pool_id'], 'user_id' => $param['user_id']])->update([
  922. 'content' => json_encode(array_values($fieldStyleList))
  923. ]);
  924. }
  925. }
  926. }
  927. }