CustomerPoolLogic.php 44KB

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