123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Description: 商机
  4. // +----------------------------------------------------------------------
  5. // | Author: Michael_xu | gengxiaoxu@5kcrm.com
  6. // +----------------------------------------------------------------------
  7. namespace app\crm\model;
  8. use app\admin\traits\FieldVerificationTrait;
  9. use think\Db;
  10. use app\admin\model\Common;
  11. use app\crm\model\Business as CrmBusinessModel;
  12. class Business extends Common
  13. {
  14. use FieldVerificationTrait;
  15. /**
  16. * 为了数据库的整洁,同时又不影响Model和Controller的名称
  17. * 我们约定每个模块的数据表都加上相同的前缀,比如CRM模块用crm作为数据表前缀
  18. */
  19. protected $name = 'crm_business';
  20. protected $createTime = 'create_time';
  21. protected $updateTime = 'update_time';
  22. protected $autoWriteTimestamp = true;
  23. /**
  24. * [getDataList 商机list]
  25. *
  26. * @param $request
  27. * @return array
  28. * @throws \think\db\exception\DataNotFoundException
  29. * @throws \think\db\exception\ModelNotFoundException
  30. * @throws \think\exception\DbException
  31. */
  32. public function getDataList($request)
  33. {
  34. $userModel = new \app\admin\model\User();
  35. $structureModel = new \app\admin\model\Structure();
  36. $fieldModel = new \app\admin\model\Field();
  37. $search = $request['search'];
  38. $user_id = $request['user_id'];
  39. $scene_id = (int)$request['scene_id'];
  40. $contacts_id = $request['contacts_id'];
  41. $order_field = $request['order_field'];
  42. $order_type = $request['order_type'];
  43. $is_excel = $request['is_excel']; //导出
  44. $getCount = $request['getCount'];
  45. $businessTypeId = $request['typesId']; // 针对mobile
  46. $businessStatusId = $request['statusId']; // 针对mobile
  47. $overdue = $request['overdue']; // 待办事项下需联系商机(逾期)
  48. unset($request['scene_id']);
  49. unset($request['search']);
  50. unset($request['user_id']);
  51. unset($request['contacts_id']);
  52. unset($request['order_field']);
  53. unset($request['order_type']);
  54. unset($request['is_excel']);
  55. unset($request['getCount']);
  56. unset($request['typesId']);
  57. unset($request['statusId']);
  58. unset($request['overdue']);
  59. $request = $this->fmtRequest($request);
  60. $requestMap = $request['map'] ?: [];
  61. $sceneModel = new \app\admin\model\Scene();
  62. # getCount是代办事项传来的参数,代办事项不需要使用场景
  63. $sceneMap = [];
  64. if (empty($getCount)) {
  65. if ($scene_id) {
  66. //自定义场景
  67. $sceneMap = $sceneModel->getDataById($scene_id, $user_id, 'business') ?: [];
  68. } else {
  69. //默认场景
  70. $sceneMap = $sceneModel->getDefaultData('crm_business', $user_id) ?: [];
  71. }
  72. }
  73. if ($search || $search == '0') {
  74. //普通筛选
  75. $sceneMap['name'] = ['condition' => 'contains', 'value' => $search, 'form_type' => 'text', 'name' => '商机名称'];
  76. }
  77. if (isset($requestMap['type_id'])) {
  78. $requestMap['type_id']['value'] = $requestMap['type_id']['type_id'];
  79. if(in_array($requestMap['type_id']['status_id'],[1,2,3])){
  80. $requestMap['is_end']=$requestMap['type_id']['status_id'];
  81. }else{
  82. if ($requestMap['type_id']['status_id']) $requestMap['status_id']['value'] = $requestMap['type_id']['status_id'];
  83. $requestMap['is_end']=0;
  84. }
  85. }
  86. if ($sceneMap['type_id']) {
  87. $requestMap['type_id']['value'] = $sceneMap['type_id']['type_id'];
  88. if(in_array($sceneMap['type_id']['status_id'],[1,2,3])){
  89. $sceneMap['is_end']=$sceneMap['type_id']['status_id'];
  90. }else{
  91. if ($sceneMap['type_id']['status_id']) $requestMap['status_id']['value'] = $sceneMap['type_id']['status_id'];
  92. $sceneMap['is_end']=0;
  93. }
  94. unset($sceneMap['type_id']);
  95. }
  96. $partMap = [];
  97. //优先级:普通筛选>高级筛选>场景
  98. if ($requestMap['team_id']) {
  99. //相关团队查询
  100. $map = $requestMap;
  101. $partMap= advancedQueryFormatForTeam($requestMap,'crm_business','business_id');
  102. unset($map['team_id']);
  103. } else {
  104. $map = $requestMap ? array_merge($sceneMap, $requestMap) : $sceneMap;
  105. }
  106. //高级筛选
  107. $map = advancedQuery($map, 'crm', 'business', 'index');
  108. $authMap = [];
  109. if (!$partMap) {
  110. $a = 'index';
  111. if ($is_excel) $a = 'excelExport';
  112. $auth_user_ids = $userModel->getUserByPer('crm', 'business', $a);
  113. if (isset($map['business.owner_user_id']) && $map['business.owner_user_id'][0] != 'like') {
  114. if (!is_array($map['business.owner_user_id'][1])) {
  115. $map['business.owner_user_id'][1] = [$map['business.owner_user_id'][1]];
  116. }
  117. if (in_array($map['business.owner_user_id'][0], ['neq', 'notin'])) {
  118. $auth_user_ids = array_diff($auth_user_ids, $map['business.owner_user_id'][1]) ?: []; //取差集
  119. } else {
  120. $auth_user_ids = array_intersect($map['business.owner_user_id'][1], $auth_user_ids) ?: []; //取交集
  121. }
  122. unset($map['business.owner_user_id']);
  123. $auth_user_ids = array_merge(array_unique(array_filter($auth_user_ids))) ?: ['-1'];
  124. $authMap['business.owner_user_id'] = array('in', $auth_user_ids);
  125. } else {
  126. $authMapData = [];
  127. $authMapData['auth_user_ids'] = $auth_user_ids;
  128. $authMapData['user_id'] = $user_id;
  129. $authMap = function ($query) use ($authMapData) {
  130. $query->where('business.owner_user_id', array('in', $authMapData['auth_user_ids']))
  131. ->whereOr('business.ro_user_id', array('like', '%,' . $authMapData['user_id'] . ',%'))
  132. ->whereOr('business.rw_user_id', array('like', '%,' . $authMapData['user_id'] . ',%'));
  133. };
  134. }
  135. }
  136. //联系人商机
  137. if ($contacts_id) {
  138. $business_id = Db::name('crm_contacts_business')->where(['contacts_id' => $contacts_id])->column('business_id');
  139. if ($business_id) {
  140. $map['business.business_id'] = array('in', $business_id);
  141. } else {
  142. $map['business.business_id'] = array('eq', -1);
  143. }
  144. }
  145. //列表展示字段
  146. $indexField = $fieldModel->getIndexField('crm_business', $user_id, 1) ?: array('name');
  147. if (!empty($indexField)) {
  148. foreach ($indexField as $key => $value) {
  149. if ($value == 'business.customer_name') unset($indexField[(int)$key]);
  150. }
  151. }
  152. $userField = $fieldModel->getFieldByFormType('crm_business', 'user'); //人员类型
  153. $structureField = $fieldModel->getFieldByFormType('crm_business', 'structure'); //部门类型
  154. $datetimeField = $fieldModel->getFieldByFormType('crm_business', 'datetime'); //日期时间类型
  155. $booleanField = $fieldModel->getFieldByFormType('crm_business', 'boolean_value'); //布尔值
  156. $dateIntervalField = $fieldModel->getFieldByFormType('crm_business', 'date_interval'); // 日期区间类型字段
  157. $positionField = $fieldModel->getFieldByFormType('crm_business', 'position'); // 地址类型字段
  158. $handwritingField = $fieldModel->getFieldByFormType('crm_business', 'handwriting_sign'); // 手写签名类型字段
  159. $locationField = $fieldModel->getFieldByFormType('crm_business', 'location'); // 定位类型字段
  160. # 处理人员和部门类型的排序报错问题(前端传来的是包含_name的别名字段)
  161. $temporaryField = str_replace('_name', '', $order_field);
  162. if (in_array($temporaryField, $userField) || in_array($temporaryField, $structureField)) {
  163. $order_field = $temporaryField;
  164. }
  165. //排序
  166. if ($order_type && $order_field) {
  167. $order = $fieldModel->getOrderByFormtype('crm_business', 'business', $order_field, $order_type);
  168. } else {
  169. $order = 'business.update_time desc';
  170. }
  171. # 商机组和商机状态搜索
  172. if (!empty($businessTypeId)) $map['business.type_id'] = ['eq', $businessTypeId];
  173. if (!empty($businessStatusId)) {
  174. if(preg_match("/^[1-9][0-9]*$/" ,$businessStatusId)){
  175. $map['is_end']=0;
  176. $map['business.status_id'] = ['eq', $businessStatusId];
  177. }else{
  178. $map['is_end']=abs($businessStatusId);
  179. }
  180. }
  181. // 待办事项下需联系商机(逾期)
  182. $overdueWhere = '';
  183. if (!empty($overdue)) {
  184. $overdueWhere = "(FROM_UNIXTIME(`business`.`last_time`,'%Y-%m-%d') < FROM_UNIXTIME(`business`.`next_time`,'%Y-%m-%d') OR (ISNULL(`business`.`last_time`) AND `business`.`next_time` < ".time()."))";
  185. }
  186. $readAuthIds = $userModel->getUserByPer('crm', 'business', 'read');
  187. $updateAuthIds = $userModel->getUserByPer('crm', 'business', 'update');
  188. $deleteAuthIds = $userModel->getUserByPer('crm', 'business', 'delete');
  189. $dataCount = db('crm_business')
  190. ->alias('business')
  191. ->join('__CRM_CUSTOMER__ customer', 'business.customer_id = customer.customer_id', 'LEFT')
  192. ->where($map)->where($partMap)->where($authMap)->where($overdueWhere)->count('business_id');
  193. if (!empty($getCount) && $getCount == 1) {
  194. $data['dataCount'] = !empty($dataCount) ? $dataCount : 0;
  195. # 商机总金额
  196. $sumMoney = Db::name('crm_business')->alias('business')
  197. ->whereIn('is_end', [0, 1])->where($map)->where($partMap)->where($authMap)->sum('money');
  198. $data['extraData']['money'] = ['businessSumMoney' => !empty($sumMoney) ? sprintf("%.2f", $sumMoney) : 0.00];
  199. return $data;
  200. }
  201. $list = db('crm_business')
  202. ->alias('business')
  203. ->join('__CRM_CUSTOMER__ customer', 'business.customer_id = customer.customer_id', 'LEFT')
  204. ->where($map)
  205. ->where($partMap)
  206. ->where($authMap)
  207. ->where($overdueWhere)
  208. ->limit($request['offset'], $request['length'])
  209. ->field('business.*,customer.name as customer_name')
  210. ->orderRaw($order)
  211. ->select();
  212. $endStatus = ['1' => '赢单', '2' => '输单', '3' => '无效'];
  213. # 扩展数据
  214. $extraData = [];
  215. $business_id_list = !empty($list) ? array_column($list, 'business_id') : [];
  216. $extraList = db('crm_business_data')->whereIn('business_id', $business_id_list)->select();
  217. foreach ($extraList AS $key => $value) {
  218. $extraData[$value['business_id']][$value['field']] = $value['content'];
  219. }
  220. foreach ($list as $k => $v) {
  221. $list[$k]['customer_id_info']['customer_id'] = $v['customer_id'];
  222. $list[$k]['customer_id_info']['name'] = $v['customer_name'];
  223. $list[$k]['create_user_id_info'] = isset($v['create_user_id']) ? $userModel->getUserById($v['create_user_id']) : [];
  224. $list[$k]['owner_user_id_info'] = isset($v['owner_user_id']) ? $userModel->getUserById($v['owner_user_id']) : [];
  225. $list[$k]['create_user_name'] = !empty($list[$k]['create_user_id_info']['realname']) ? $list[$k]['create_user_id_info']['realname'] : '';
  226. $list[$k]['owner_user_name'] = !empty($list[$k]['owner_user_id_info']['realname']) ? $list[$k]['owner_user_id_info']['realname'] : '';
  227. foreach ($userField as $key => $val) {
  228. $usernameField = !empty($v[$val]) ? db('admin_user')->whereIn('id', stringToArray($v[$val]))->column('realname') : [];
  229. $list[$k][$val] = implode($usernameField, ',');
  230. }
  231. foreach ($structureField as $key => $val) {
  232. $structureNameField = !empty($v[$val]) ? db('admin_structure')->whereIn('id', stringToArray($v[$val]))->column('name') : [];
  233. $list[$k][$val] = implode($structureNameField, ',');
  234. }
  235. foreach ($datetimeField as $key => $val) {
  236. $list[$k][$val] = !empty($v[$val]) ? date('Y-m-d H:i:s', $v[$val]) : null;
  237. }
  238. foreach ($booleanField as $key => $val) {
  239. $list[$k][$val] = !empty($v[$val]) ? (string)$v[$val] : '0';
  240. }
  241. // 处理日期区间类型字段的格式
  242. foreach ($dateIntervalField AS $key => $val) {
  243. $list[$k][$val] = !empty($extraData[$v['business_id']][$val]) ? json_decode($extraData[$v['business_id']][$val], true) : null;
  244. }
  245. // 处理地址类型字段的格式
  246. foreach ($positionField AS $key => $val) {
  247. $list[$k][$val] = !empty($extraData[$v['business_id']][$val]) ? json_decode($extraData[$v['business_id']][$val], true) : null;
  248. }
  249. // 手写签名类型字段
  250. foreach ($handwritingField AS $key => $val) {
  251. $handwritingData = !empty($v[$val]) ? db('admin_file')->where('file_id', $v[$val])->value('file_path') : null;
  252. $list[$k][$val] = ['url' => !empty($handwritingData) ? getFullPath($handwritingData) : null];
  253. }
  254. // 定位类型字段
  255. foreach ($locationField AS $key => $val) {
  256. $list[$k][$val] = !empty($extraData[$v['business_id']][$val]) ? json_decode($extraData[$v['business_id']][$val], true) : null;
  257. }
  258. $statusInfo = [];
  259. $status_count = 0;
  260. if (!$v['is_end']) {
  261. $statusInfo = db('crm_business_status')->where('status_id', $v['status_id'])->find();
  262. if ($statusInfo['order_id'] < 99) {
  263. $status_count = db('crm_business_status')->where('type_id', ['eq', $v['type_id']])->count();
  264. }
  265. //进度
  266. $list[$k]['status_progress'] = [$statusInfo['order_id'], $status_count + 1];
  267. } else {
  268. $statusInfo['name'] = $endStatus[$v['is_end']];
  269. }
  270. $list[$k]['status_id_info'] = $statusInfo['name'];//销售阶段
  271. $list[$k]['type_id_info'] = db('crm_business_type')->where('type_id', $v['type_id'])->value('name');//商机状态组
  272. //权限
  273. $roPre = $userModel->rwPre($user_id, $v['ro_user_id'], $v['rw_user_id'], 'read');
  274. $rwPre = $userModel->rwPre($user_id, $v['ro_user_id'], $v['rw_user_id'], 'update');
  275. $permission = [];
  276. $is_read = 0;
  277. $is_update = 0;
  278. $is_delete = 0;
  279. if (in_array($v['owner_user_id'], $readAuthIds) || $roPre || $rwPre) $is_read = 1;
  280. if (in_array($v['owner_user_id'], $updateAuthIds) || $rwPre) $is_update = 1;
  281. if (in_array($v['owner_user_id'], $deleteAuthIds)) $is_delete = 1;
  282. $permission['is_read'] = $is_read;
  283. $permission['is_update'] = $is_update;
  284. $permission['is_delete'] = $is_delete;
  285. $list[$k]['permission'] = $permission;
  286. # 下次联系时间
  287. $list[$k]['next_time'] = !empty($v['next_time']) ? date('Y-m-d H:i:s', $v['next_time']) : null;
  288. # 关注
  289. $starWhere = ['user_id' => $user_id, 'target_id' => $v['business_id'], 'type' => 'crm_business'];
  290. $star = Db::name('crm_star')->where($starWhere)->value('star_id');
  291. $list[$k]['star'] = !empty($star) ? 1 : 0;
  292. # 日期
  293. $list[$k]['create_time'] = !empty($v['create_time']) ? date('Y-m-d H:i:s', $v['create_time']) : null;
  294. $list[$k]['update_time'] = !empty($v['update_time']) ? date('Y-m-d H:i:s', $v['update_time']) : null;
  295. $list[$k]['last_time'] = !empty($v['last_time']) ? date('Y-m-d H:i:s', $v['last_time']) : null;
  296. }
  297. $data = [];
  298. $data['list'] = $list ?: [];
  299. $data['dataCount'] = $dataCount ?: 0;
  300. # 商机总金额
  301. $sumMoney = Db::name('crm_business')->alias('business')
  302. ->join('__CRM_CUSTOMER__ customer', 'business.customer_id = customer.customer_id', 'LEFT')
  303. ->whereIn('is_end', [0, 1])->where($map)->where($partMap)->where($authMap)->sum('money');
  304. $data['extraData']['money'] = ['businessSumMoney' => !empty($sumMoney) ? sprintf("%.2f", $sumMoney) : 0.00];
  305. return $data;
  306. }
  307. /**
  308. * 创建商机主表信息
  309. * @param
  310. * @return
  311. * @author Michael_xu
  312. */
  313. public function createData($param)
  314. {
  315. // 商机扩展表数据
  316. $businessData = [];
  317. $fieldModel = new \app\admin\model\Field();
  318. $productModel = new \app\crm\model\Product();
  319. // 数据验证
  320. $validateResult = $this->fieldDataValidate($param, $this->name, $param['create_user_id']);
  321. if (!empty($validateResult)) {
  322. $this->error = $validateResult;
  323. return false;
  324. }
  325. if (!$param['customer_id']) {
  326. $this->error = '请选择相关客户';
  327. return false;
  328. }
  329. // 处理部门、员工、附件、多选类型字段
  330. $arrFieldAtt = $fieldModel->getArrayField('crm_business');
  331. foreach ($arrFieldAtt as $k => $v) {
  332. $param[$v] = arrayToString($param[$v]);
  333. }
  334. // 处理日期(date)类型
  335. $dateField = $fieldModel->getFieldByFormType('crm_business', 'date');
  336. if (!empty($dateField)) {
  337. foreach ($param AS $key => $value) {
  338. if (in_array($key, $dateField) && empty($value)) $param[$key] = null;
  339. }
  340. }
  341. // 处理手写签名类型
  342. $handwritingField = $fieldModel->getFieldByFormType('crm_business', 'handwriting_sign');
  343. if (!empty($handwritingField)) {
  344. foreach ($param AS $key => $value) {
  345. if (in_array($key, $handwritingField)) {
  346. $param[$key] = !empty($value['file_id']) ? $value['file_id'] : '';
  347. }
  348. }
  349. }
  350. // 处理地址、定位、日期区间、明细表格类型字段
  351. $positionField = $fieldModel->getFieldByFormType($this->name, 'position');
  352. $locationField = $fieldModel->getFieldByFormType($this->name, 'location');
  353. $dateIntervalField = $fieldModel->getFieldByFormType($this->name, 'date_interval');
  354. $detailTableField = $fieldModel->getFieldByFormType($this->name, 'detail_table');
  355. foreach ($param AS $key => $value) {
  356. // 处理地址类型字段数据
  357. if (in_array($key, $positionField)) {
  358. if (!empty($value)) {
  359. $businessData[] = [
  360. 'field' => $key,
  361. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  362. 'create_time' => time()
  363. ];
  364. $positionNames = array_column($value, 'name');
  365. $param[$key] = implode(',', $positionNames);
  366. } else {
  367. $param[$key] = '';
  368. }
  369. }
  370. // 处理定位类型字段数据
  371. if (in_array($key, $locationField)) {
  372. if (!empty($value)) {
  373. $businessData[] = [
  374. 'field' => $key,
  375. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  376. 'create_time' => time()
  377. ];
  378. $param[$key] = $value['address'];
  379. } else {
  380. $param[$key] = '';
  381. }
  382. }
  383. // 处理日期区间类型字段数据
  384. if (in_array($key, $dateIntervalField)) {
  385. if (!empty($value)) {
  386. $businessData[] = [
  387. 'field' => $key,
  388. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  389. 'create_time' => time()
  390. ];
  391. $param[$key] = implode('_', $value);
  392. } else {
  393. $param[$key] = '';
  394. }
  395. }
  396. // 处理明细表格类型字段数据
  397. if (in_array($key, $detailTableField)) {
  398. if (!empty($value)) {
  399. $businessData[] = [
  400. 'field' => $key,
  401. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  402. 'create_time' => time()
  403. ];
  404. $param[$key] = $key;
  405. } else {
  406. $param[$key] = '';
  407. }
  408. }
  409. }
  410. # 设置今日需联系商机
  411. if (!empty($param['next_time']) && $param['next_time'] >= strtotime(date('Y-m-d 00:00:00'))) $param['is_dealt'] = 0;
  412. $param['money'] = $param['money'] ?: '0.00';
  413. $param['discount_rate'] = $param['discount_rate'] ?: '0.00';
  414. if ($this->data($param)->allowField(true)->save()) {
  415. updateActionLog($param['create_user_id'], 'crm_business', $this->business_id, '', '', '创建了商机');
  416. RecordActionLog($param['create_user_id'],'crm_business','save',$param['name'],'','','新增了商机'.$param['name']);
  417. $business_id = $this->business_id;
  418. $data['business_id'] = $business_id;
  419. if ($param['product']) {
  420. //产品数据处理
  421. $resProduct = $productModel->createObject('crm_business', $param, $business_id);
  422. if ($resProduct == false) {
  423. $this->error = '产品添加失败';
  424. return false;
  425. }
  426. }
  427. //添加商机日志
  428. $data_log['business_id'] = $business_id;
  429. $data_log['is_end'] = 0;
  430. $data_log['status_id'] = $param['status_id'];
  431. $data_log['create_time'] = time();
  432. $data_log['owner_user_id'] = $param['owner_user_id'];
  433. $data_log['remark'] = '新建商机';
  434. Db::name('CrmBusinessLog')->insert($data_log);
  435. # 添加活动记录
  436. Db::name('crm_activity')->insert([
  437. 'type' => 2,
  438. 'activity_type' => 5,
  439. 'activity_type_id' => $data['business_id'],
  440. 'content' => $param['name'],
  441. 'create_user_id' => $param['create_user_id'],
  442. 'update_time' => time(),
  443. 'create_time' => time(),
  444. 'customer_ids' => ',' . $param['customer_id'] . ','
  445. ]);
  446. // 添加商机扩展数据
  447. array_walk($businessData, function (&$val) use ($data) {
  448. $val['business_id'] = $data['business_id'];
  449. });
  450. db('crm_business_data')->insertAll($businessData);
  451. return $data;
  452. } else {
  453. $this->error = '添加失败';
  454. return false;
  455. }
  456. }
  457. /**
  458. * 编辑商机主表信息
  459. * @param
  460. * @return
  461. * @author Michael_xu
  462. */
  463. public function updateDataById($param, $business_id = '')
  464. {
  465. // 商机扩展表数据
  466. $businessData = [];
  467. $productModel = new \app\crm\model\Product();
  468. $dataInfo = $this->getDataById($business_id);
  469. if (!$dataInfo) {
  470. $this->error = '数据不存在或已删除';
  471. return false;
  472. }
  473. $param['business_id'] = $business_id;
  474. //过滤不能修改的字段
  475. $unUpdateField = ['create_user_id', 'is_deleted', 'delete_time'];
  476. foreach ($unUpdateField as $v) {
  477. unset($param[$v]);
  478. }
  479. $fieldModel = new \app\admin\model\Field();
  480. // 数据验证
  481. $validateResult = $this->fieldDataValidate($param, $this->name, $param['user_id'], $param['business_id']);
  482. if (!empty($validateResult)) {
  483. $this->error = $validateResult;
  484. return false;
  485. }
  486. # 商机金额小数处理
  487. if (!empty($param['money']) && is_numeric($param['money']) && strpos($param['money'], ".") === false) {
  488. $param['money'] .= '.00';
  489. }
  490. // 处理部门、员工、附件、多选类型字段
  491. $arrFieldAtt = $fieldModel->getArrayField('crm_business');
  492. foreach ($arrFieldAtt as $k => $v) {
  493. if (isset($param[$v])) $param[$v] = arrayToString($param[$v]);
  494. }
  495. // 处理日期(date)类型
  496. $dateField = $fieldModel->getFieldByFormType('crm_business', 'date');
  497. if (!empty($dateField)) {
  498. foreach ($param AS $key => $value) {
  499. if (in_array($key, $dateField) && empty($value)) $param[$key] = null;
  500. }
  501. }
  502. // 处理手写签名类型
  503. $handwritingField = $fieldModel->getFieldByFormType('crm_business', 'handwriting_sign');
  504. if (!empty($handwritingField)) {
  505. foreach ($param AS $key => $value) {
  506. if (in_array($key, $handwritingField)) {
  507. $param[$key] = !empty($value['file_id']) ? $value['file_id'] : '';
  508. }
  509. }
  510. }
  511. // 处理地址、定位、日期区间、明细表格类型字段
  512. $positionField = $fieldModel->getFieldByFormType($this->name, 'position');
  513. $locationField = $fieldModel->getFieldByFormType($this->name, 'location');
  514. $dateIntervalField = $fieldModel->getFieldByFormType($this->name, 'date_interval');
  515. $detailTableField = $fieldModel->getFieldByFormType($this->name, 'detail_table');
  516. foreach ($param AS $key => $value) {
  517. // 处理地址类型字段数据
  518. if (in_array($key, $positionField)) {
  519. if (!empty($value)) {
  520. $businessData[] = [
  521. 'field' => $key,
  522. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  523. 'create_time' => time()
  524. ];
  525. $positionNames = array_column($value, 'name');
  526. $param[$key] = implode(',', $positionNames);
  527. } else {
  528. $param[$key] = '';
  529. }
  530. }
  531. // 处理定位类型字段数据
  532. if (in_array($key, $locationField)) {
  533. if (!empty($value)) {
  534. $businessData[] = [
  535. 'field' => $key,
  536. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  537. 'create_time' => time()
  538. ];
  539. $param[$key] = $value['address'];
  540. } else {
  541. $param[$key] = '';
  542. }
  543. }
  544. // 处理日期区间类型字段数据
  545. if (in_array($key, $dateIntervalField)) {
  546. if (!empty($value)) {
  547. $businessData[] = [
  548. 'field' => $key,
  549. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  550. 'create_time' => time()
  551. ];
  552. $param[$key] = implode('_', $value);
  553. } else {
  554. $param[$key] = '';
  555. }
  556. }
  557. // 处理明细表格类型字段数据
  558. if (in_array($key, $detailTableField)) {
  559. if (!empty($value)) {
  560. $businessData[] = [
  561. 'field' => $key,
  562. 'content' => json_encode($value, JSON_NUMERIC_CHECK),
  563. 'create_time' => time()
  564. ];
  565. $param[$key] = $key;
  566. } else {
  567. $param[$key] = '';
  568. }
  569. }
  570. }
  571. # 设置今日需联系商机
  572. if (!empty($param['next_time']) && $param['next_time'] >= strtotime(date('Y-m-d 00:00:00'))) $param['is_dealt'] = 0;
  573. $param['money'] = $param['money'] ?: '0.00';
  574. $param['discount_rate'] = $param['discount_rate'] ?: '0.00';
  575. //商机状态改变
  576. $statusInfo = db('crm_business_status')->where(['status_id' => $param['status_id']])->find();
  577. if ($statusInfo['type_id']) {
  578. $param['is_end'] = 0;
  579. } else {
  580. $param['is_end'] = $param['status_id'];
  581. }
  582. if ($this->update($param, ['business_id' => $business_id], true)) {
  583. $data['business_id'] = $business_id;
  584. //产品数据处理
  585. $resProduct = $productModel->createObject('crm_business', $param, $business_id);
  586. //修改记录
  587. updateActionLog($param['user_id'], 'crm_business', $business_id, $dataInfo, $param);
  588. RecordActionLog($param['user_id'], 'crm_business', 'update',$dataInfo['name'], $dataInfo, $param);
  589. // 添加商机扩展数据
  590. db('crm_business_data')->where('business_id', $business_id)->delete();
  591. array_walk($businessData, function (&$val) use ($business_id) {
  592. $val['business_id'] = $business_id;
  593. });
  594. db('crm_business_data')->insertAll($businessData);
  595. return $data;
  596. } else {
  597. $this->rollback();
  598. $this->error = '编辑失败';
  599. return false;
  600. }
  601. }
  602. /**
  603. * 商机数据
  604. *
  605. * @param string $id
  606. * @param int $userId
  607. * @return Common|array|bool|\PDOStatement|string|\think\Model|null
  608. * @throws \think\db\exception\DataNotFoundException
  609. * @throws \think\db\exception\ModelNotFoundException
  610. * @throws \think\exception\DbException
  611. */
  612. public function getDataById($id = '', $userId = 0)
  613. {
  614. $dataInfo = db('crm_business')->where('business_id', $id)->find();
  615. if (!$dataInfo) {
  616. $this->error = '暂无此数据';
  617. return false;
  618. }
  619. $userModel = new \app\admin\model\User();
  620. $dataInfo['create_user_id_info'] = isset($dataInfo['create_user_id']) ? $userModel->getUserById($dataInfo['create_user_id']) : [];
  621. $dataInfo['owner_user_id_info'] = isset($dataInfo['owner_user_id']) ? $userModel->getUserById($dataInfo['owner_user_id']) : [];
  622. $dataInfo['create_user_name'] = !empty($dataInfo['create_user_id_info']['realname']) ? $dataInfo['create_user_id_info']['realname'] : '';
  623. $dataInfo['owner_user_name'] = !empty($dataInfo['owner_user_id_info']['realname']) ? $dataInfo['owner_user_id_info']['realname'] : '';
  624. $dataInfo['type_id_info'] = db('crm_business_type')->where(['type_id' => $dataInfo['type_id']])->value('name');
  625. $dataInfo['status_id_info'] = db('crm_business_status')->where(['status_id' => $dataInfo['status_id']])->value('name');
  626. $dataInfo['customer_id_info'] = db('crm_customer')->where(['customer_id' => $dataInfo['customer_id']])->field('customer_id,name')->find();
  627. $dataInfo['customer_name'] = !empty($dataInfo['customer_id_info']['name']) ? $dataInfo['customer_id_info']['name'] : '';
  628. # 关注
  629. $starId = empty($userId) ? 0 : Db::name('crm_star')->where(['user_id' => $userId, 'target_id' => $id, 'type' => 'crm_business'])->value('star_id');
  630. $dataInfo['star'] = !empty($starId) ? 1 : 0;
  631. # 首要联系人
  632. $primaryId = Db::name('crm_contacts')->where(['contacts_id' => $dataInfo['contacts_id']])->value('contacts_id');
  633. $dataInfo['contacts_id'] = !empty($primaryId) && $this->getContactsAuth($primaryId) ? $primaryId : 0;
  634. # 处理日期格式
  635. $fieldModel = new \app\admin\model\Field();
  636. $datetimeField = $fieldModel->getFieldByFormType('crm_business', 'datetime'); //日期时间类型
  637. foreach ($datetimeField as $key => $val) {
  638. $dataInfo[$val] = !empty($dataInfo[$val]) ? date('Y-m-d H:i:s', $dataInfo[$val]) : null;
  639. }
  640. if($dataInfo['is_end']!=1){
  641. $dataInfo['statusRemark']=db('crm_business_log')->where(['business_id'=>$id,'is_end'=>$dataInfo['is_end']])->value('remark');
  642. }
  643. $dataInfo['next_time'] = !empty($dataInfo['next_time']) ? date('Y-m-d H:i:s', $dataInfo['next_time']) : null;
  644. $dataInfo['create_time'] = !empty($dataInfo['create_time']) ? date('Y-m-d H:i:s', $dataInfo['create_time']) : null;
  645. $dataInfo['update_time'] = !empty($dataInfo['update_time']) ? date('Y-m-d H:i:s', $dataInfo['update_time']) : null;
  646. $dataInfo['last_time'] = !empty($dataInfo['last_time']) ? date('Y-m-d H:i:s', $dataInfo['last_time']) : null;
  647. // 字段授权
  648. if (!empty($userId)) {
  649. $grantData = getFieldGrantData($userId);
  650. $userLevel = isSuperAdministrators($userId);
  651. foreach ($dataInfo AS $key => $value) {
  652. if (!$userLevel && !empty($grantData['crm_business'])) {
  653. $status = getFieldGrantStatus($key, $grantData['crm_business']);
  654. # 查看权限
  655. if ($status['read'] == 0) unset($dataInfo[$key]);
  656. }
  657. }
  658. }
  659. return $dataInfo;
  660. }
  661. //根据IDs获取数组
  662. public function getDataByStr($idstr)
  663. {
  664. $idArr = stringToArray($idstr);
  665. if (!$idArr) {
  666. return [];
  667. }
  668. $list = Db::name('CrmBusiness')->where(['business_id' => ['in', $idArr]])->select();
  669. return $list;
  670. }
  671. /**
  672. * [商机漏斗]
  673. * @param
  674. * @return
  675. * @author Michael_xu
  676. */
  677. public function getFunnel($request)
  678. {
  679. $merge = $request['merge'] ?: 0;
  680. $perUserIds = $request['perUserIds'] ?: [];
  681. $adminModel = new \app\admin\model\Admin();
  682. $whereArr = $adminModel->getWhere($request, $merge, $perUserIds); //统计查询
  683. $userIds = $whereArr['userIds'];
  684. $between_time = $whereArr['between_time'];
  685. $where['owner_user_id'] = array('in', $userIds);
  686. $where['create_time'] = array('between', $between_time);
  687. //商机状态组
  688. $default_type_id = db('crm_business_type')->order('type_id asc')->value('type_id');
  689. $type_id = $request['type_id'] ? $request['type_id'] : $default_type_id;
  690. $statusList = db('crm_business_status')->where(['type_id' => $type_id])->select();
  691. $map = [];
  692. $map['create_time'] = $where['create_time'];
  693. $map['owner_user_id'] = ['in', $userIds];
  694. $map['type_id'] = $type_id;
  695. $sql_a = CrmBusinessModel::field([
  696. 'SUM(CASE WHEN is_end = 1 THEN money ELSE 0 END) AS sum_ying',
  697. 'SUM(CASE WHEN is_end = 2 THEN money ELSE 0 END) AS sum_shu',
  698. 'type_id'
  699. ])
  700. ->where($map)
  701. ->fetchSql()
  702. ->find();
  703. $res_a = queryCache($sql_a, 200);
  704. $sql = CrmBusinessModel::field([
  705. "status_id",
  706. 'COUNT(*)' => 'count',
  707. 'SUM(`money`)' => 'sum',
  708. 'type_id'
  709. ])
  710. ->where($where)
  711. ->whereNotIn('is_end', '1,2,3')
  712. ->group('status_id')
  713. ->fetchSql()
  714. ->select();
  715. $res = queryCache($sql, 200);
  716. $res = array_column($res, null, 'status_id');
  717. $sum_money = 0;
  718. $count = 0; # 商机数总和
  719. $moneyCount = 0; # 金额总和
  720. foreach ($statusList as $k => $v) {
  721. $v['count'] = $res[$v['status_id']]['count'] ?: 0;
  722. $v['money'] = $res[$v['status_id']]['sum'] ?: 0;
  723. $v['status_name'] = $v['name'];
  724. $statusList[$k] = $v;
  725. $sum_money += $v['money'];
  726. $moneyCount += $v['money'];
  727. $count += $v['count'];
  728. }
  729. $data['list'] = $statusList;
  730. $data['sum_ying'] = $res_a[0]['sum_ying'] ?: 0;
  731. $data['sum_shu'] = $res_a[0]['sum_shu'] ?: 0;
  732. $data['sum_money'] = $sum_money ?: 0;
  733. $data['total'] = ['name' => '合计', 'money_count' => $moneyCount, 'count' => $count];
  734. return $data ?: [];
  735. }
  736. /**
  737. * [商机转移]
  738. * @param ids 商机ID数组
  739. * @param owner_user_id 变更负责人
  740. * @param is_remove 1移出,2转为团队成员
  741. * @return
  742. * @author Michael_xu
  743. */
  744. public function transferDataById($ids, $owner_user_id, $type = 1, $is_remove)
  745. {
  746. $settingModel = new \app\crm\model\Setting();
  747. $errorMessage = [];
  748. foreach ($ids as $id) {
  749. $businessInfo = db('crm_business')->where(['business_id' => $id])->find();
  750. //团队成员
  751. $teamData = [];
  752. $teamData['type'] = $type; //权限 1只读2读写
  753. $teamData['user_id'] = [$businessInfo['owner_user_id']]; //协作人
  754. $teamData['types'] = 'crm_business'; //类型
  755. $teamData['types_id'] = $id; //类型ID
  756. $teamData['is_del'] = ($is_remove == 1) ? 1 : '';
  757. $res = $settingModel->createTeamData($teamData);
  758. $data = [];
  759. $data['owner_user_id'] = $owner_user_id;
  760. $data['update_time'] = time();
  761. if (!db('crm_business')->where(['business_id' => $id])->update($data)) {
  762. $errorMessage[] = '商机:' . $businessInfo['name'] . '"转移失败,错误原因:数据出错;';
  763. continue;
  764. } else {
  765. $businessArray = [];
  766. $teamBusiness = db('crm_business')->field(['owner_user_id', 'ro_user_id', 'rw_user_id'])->where('business_id', $id)->find();
  767. if (!empty($teamBusiness['ro_user_id'])) {
  768. $businessRo = arrayToString(array_diff(stringToArray($teamBusiness['ro_user_id']), [$teamBusiness['owner_user_id']]));
  769. $businessArray['ro_user_id'] = $businessRo;
  770. }
  771. if (!empty($teamBusiness['rw_user_id'])) {
  772. $businessRo = arrayToString(array_diff(stringToArray($teamBusiness['rw_user_id']), [$teamBusiness['owner_user_id']]));
  773. $businessArray['rw_user_id'] = $businessRo;
  774. }
  775. db('crm_business')->where('business_id', $id)->update($businessArray);
  776. }
  777. }
  778. if ($errorMessage) {
  779. return $errorMessage;
  780. } else {
  781. return true;
  782. }
  783. }
  784. /**
  785. * [商机统计]
  786. * @param
  787. * @return
  788. */
  789. public function getTrendql($map)
  790. {
  791. $prefix = config('database.prefix');
  792. $sql = "SELECT
  793. '{$map['type']}' AS type,
  794. '{$map['start_time']}' AS start_time,
  795. '{$map['end_time']}' AS end_time,
  796. IFNULL(
  797. (
  798. SELECT
  799. sum(money)
  800. FROM
  801. {$prefix}crm_business
  802. WHERE
  803. create_time BETWEEN {$map['start_time']} AND {$map['end_time']}
  804. AND owner_user_id IN ({$map['owner_user_id']})
  805. ),
  806. 0
  807. ) AS business_money,
  808. IFNULL(
  809. count(business_id),
  810. 0
  811. ) AS business_num
  812. FROM
  813. {$prefix}crm_business
  814. WHERE
  815. create_time BETWEEN {$map['start_time']} AND {$map['end_time']}
  816. AND owner_user_id IN ({$map['owner_user_id']})";
  817. return $sql;
  818. }
  819. /**
  820. * [赢单机会转化率趋势分析]
  821. * @param
  822. * @return
  823. */
  824. public function getWinSql($map)
  825. {
  826. $prefix = config('database.prefix');
  827. $sql = "SELECT
  828. '{$map['type']}' AS type,
  829. '{$map['start_time']}' AS start_time,
  830. '{$map['end_time']}' AS end_time,
  831. IFNULL(
  832. (
  833. SELECT
  834. count(business_id)
  835. FROM
  836. {$prefix}crm_business
  837. WHERE
  838. create_time BETWEEN {$map['start_time']} AND {$map['end_time']}
  839. AND owner_user_id IN ({$map['owner_user_id']})
  840. AND is_end = 1
  841. ),
  842. 0
  843. ) AS business_end,
  844. IFNULL(
  845. count(business_id),
  846. 0
  847. ) AS business_num
  848. FROM
  849. {$prefix}crm_business
  850. WHERE
  851. create_time BETWEEN {$map['start_time']} AND {$map['end_time']}
  852. AND owner_user_id IN ({$map['owner_user_id']})";
  853. return $sql;
  854. }
  855. /**
  856. * 获取系统信息
  857. *
  858. * @param $id
  859. * @return array
  860. * @throws \think\db\exception\DataNotFoundException
  861. * @throws \think\db\exception\ModelNotFoundException
  862. * @throws \think\exception\DbException
  863. */
  864. public function getSystemInfo($id)
  865. {
  866. # 商机
  867. $business = Db::name('crm_business')->field(['create_user_id', 'create_time', 'update_time', 'last_time'])->where('business_id', $id)->find();
  868. # 创建人
  869. $realname = Db::name('admin_user')->where('id', $business['create_user_id'])->value('realname');
  870. return [
  871. 'create_user_id' => $realname,
  872. 'create_time' => date('Y-m-d H:i:s', $business['create_time']),
  873. 'update_time' => date('Y-m-d H:i:s', $business['update_time']),
  874. 'last_time' => !empty($business['last_time']) ? date('Y-m-d H:i:s', $business['last_time']) : ''
  875. ];
  876. }
  877. /**
  878. * 判断联系人详情权限 todo 客户模块也在用,以后抽成一个公共的方法
  879. *
  880. * @param $contactsId
  881. * @return bool
  882. */
  883. private function getContactsAuth($contactsId)
  884. {
  885. $ownerUserId = db('crm_contacts')->where('contacts_id', $contactsId)->value('owner_user_id');
  886. $authUserIds = (new \app\admin\model\User())->getUserByPer('crm', 'contacts', 'read');
  887. return in_array($ownerUserId, $authUserIds);
  888. }
  889. }