Brak opisu

QyCommon.php 42KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. <?php
  2. namespace App\Support\qyApi;
  3. use App\Service\AccessTokenService;
  4. use App\Service\HttpService;
  5. use App\Log;
  6. use App\RedisModel;
  7. use App\Support\EmailQueue;
  8. class QyCommon{
  9. /**
  10. * path:朋友圈接口路径 如:get_moment_comments(互动数据接口)
  11. */
  12. public static function momentCommon($path, $corpid, $params = [])
  13. {
  14. try{
  15. //记录调用日志
  16. Log::logInfo('企微朋友圈接口调用-'. $path, [
  17. 'params' => $params,
  18. 'corpid' => $corpid
  19. ], 'QyCommon/momentCommon');
  20. # 获取AccessToken
  21. $accessToken = AccessTokenService::getAccessToken($corpid, $path);
  22. if(empty($accessToken)) {
  23. return false;
  24. }
  25. $requestUri = config('qyWechat.moment_common');
  26. $url = $requestUri . $path . '?access_token=' . $accessToken;
  27. $response = HttpService::httpPost($url, json_encode($params));
  28. if(empty($response)){
  29. Log::logError('企微朋友圈接口调用失败-'.$path, [
  30. 'url' => $url,
  31. 'params' => $params,
  32. 'corpid' => $corpid,
  33. 'response' => $response
  34. ], 'QyCommon/momentCommon');
  35. return false;
  36. }
  37. $response = json_decode($response, true);
  38. if( !isset($response['errcode']) || $response['errcode'] !== 0 ){
  39. Log::logError('企微朋友圈接口调用失败-'.$path, [
  40. 'url' => $url,
  41. 'params' => $params,
  42. 'corpid' => $corpid,
  43. 'response' => $response
  44. ], 'QyCommon/momentCommon');
  45. return false;
  46. }
  47. return $response;
  48. } catch (\Exception $e){
  49. Log::logError('企微朋友圈接口调用异常-'.$path, [
  50. 'path' => $path,
  51. 'params' => $params,
  52. 'corpid' => $corpid,
  53. 'msg' => $e->getMessage(),
  54. 'line' => $e->getLine()
  55. ], 'QyCommon/momentCommon');
  56. return false;
  57. }
  58. }
  59. /**
  60. * 企业发表朋友圈获取任务创建结果
  61. * @param $corpid string 企微id
  62. * @param $jobid string 企微朋友圈发布任务id
  63. * @return bool|mixed
  64. */
  65. public static function get_moment_task_result($corpid, $jobid)
  66. {
  67. $accessToken = AccessTokenService::getAccessToken($corpid, '企业发表朋友圈获取任务创建结果');
  68. if(empty($accessToken)) {
  69. Log::logError('企业发表朋友圈获取任务创建结果', [
  70. 'params' => [
  71. 'corpid' => $corpid,
  72. 'jobid' => $jobid
  73. ],
  74. 'errmsg' => '令牌获取失败'
  75. ], 'qyWechat');
  76. return false;
  77. }
  78. $requestUri = config('qyWechat.get_moment_task_result');
  79. $requestUri .= $accessToken.'&jobid='.$jobid;
  80. $response = HttpService::httpGet($requestUri );
  81. $responseData = json_decode($response, true);
  82. Log::logInfo('企业发表朋友圈获取任务创建结果', [
  83. 'params' => [
  84. 'corpid' => $corpid,
  85. 'jobid' => $jobid
  86. ],
  87. 'response' => $responseData
  88. ], 'qyWechat');
  89. return $responseData;
  90. }
  91. /**
  92. * 获取客户朋友圈企业发表的列表
  93. * @param $corpid string 企微id
  94. * @param $moment_id string 朋友圈id
  95. * @param $retry integer 重试次数
  96. * @return array|bool
  97. */
  98. public static function get_moment_task($corpid, $moment_id, $responseDataArr = [], $cursor = '', $retry = 0)
  99. {
  100. $accessToken = AccessTokenService::getAccessToken($corpid, '获取客户朋友圈企业发表的列表');
  101. if(empty($accessToken)) {
  102. Log::logError('获取客户朋友圈企业发表的列表', [
  103. 'params' => [
  104. 'corpid' => $corpid,
  105. 'moment_id' => $moment_id
  106. ],
  107. 'errmsg' => '令牌获取失败'
  108. ], 'qyWechat');
  109. return false;
  110. }
  111. $postData = [
  112. 'moment_id' => $moment_id,
  113. 'cursor' => $cursor,
  114. 'limit' => 1000,
  115. ];
  116. $requestUri = config('qyWechat.get_moment_task');
  117. $requestUri .= $accessToken;
  118. while(true) {
  119. $response = HttpService::httpPost($requestUri, json_encode($postData));
  120. $responseData = json_decode($response, true);
  121. Log::logInfo('获取客户朋友圈企业发表的列表', [
  122. 'params' => [
  123. 'corpid' => $corpid,
  124. 'moment_id' => $moment_id,
  125. 'cursor' => $postData['cursor']
  126. ],
  127. 'response' => $responseData,
  128. ], 'qyWechat');
  129. if(isset($responseData['errcode']) && $responseData['errcode'] == 0) {
  130. // 获取下一页游标
  131. $cursor = $responseData['next_cursor'];
  132. $postData['cursor'] = $cursor;
  133. $responseDataArr = array_merge($responseDataArr, $responseData['task_list']);
  134. if(empty($cursor)) {
  135. // 没有下一页数据了,结束循环
  136. return $responseDataArr;
  137. }
  138. } else {
  139. # 检测是否为预期外的错误码需要处理
  140. // 系统繁忙 手机号码已存在
  141. if(isset($responseData['errcode']) && !in_array($responseData['errcode'], [-1])) {
  142. $content = '获取客户朋友圈企业发表的列表响应结果异常';
  143. $params = [
  144. 'params' => [
  145. 'corpid' => $corpid,
  146. 'moment_id' => $moment_id,
  147. 'cursor' => $postData['cursor']
  148. ],
  149. 'response' => $responseData
  150. ];
  151. self::getMomentTaskErrorMsgSend($content, $params);
  152. }
  153. if($retry < 3) {
  154. sleep(1);
  155. $retry++;
  156. return self::get_moment_task($corpid, $moment_id, $responseDataArr, $cursor, $retry);
  157. } else {
  158. // 返回数据异常了,退出循环并报警
  159. $content = '获取客户朋友圈企业发表的列表重试3次后失败';
  160. $params = [
  161. 'params' => [
  162. 'corpid' => $corpid,
  163. 'moment_id' => $moment_id,
  164. 'cursor' => $postData['cursor']
  165. ],
  166. 'response' => $responseData
  167. ];
  168. self::getMomentTaskErrorMsgSend($content, $params);
  169. return $responseDataArr;
  170. }
  171. }
  172. }
  173. }
  174. public static function getMomentTaskErrorMsgSend($content, $params) {
  175. Log::logError($content, $params, 'qyWechat');
  176. EmailQueue::rPush($content, json_encode($params, 256), ['song.shen@kuxuan-inc.com'], '猎羽');
  177. }
  178. /**
  179. * 修改客户备注信息
  180. * @param $corpid string 企微id
  181. * @param $userid string 企业成员userid
  182. * @param $external_userid string 外部联系人userid
  183. * @param $remark string string 此用户对外部联系人的备注,最多20个字符
  184. * @param $description string 此用户对外部联系人的描述,最多150个字符
  185. * @param $remark_company string 此用户对外部联系人备注的所属公司名称,最多20个字符
  186. * @param $remark_mobiles array 此用户对外部联系人备注的手机号
  187. * @param $remark_pic_mediaid string 备注图片的mediaid,
  188. * @return array|bool
  189. *
  190. * remark_company只在此外部联系人为微信用户时有效。
  191. * remark,description,remark_company,remark_mobiles和remark_pic_mediaid不可同时为空。
  192. * 如果填写了remark_mobiles,将会覆盖旧的备注手机号。
  193. * 如果要清除所有备注手机号,请在remark_mobiles填写一个空字符串("")。
  194. * remark_pic_mediaid可以通过素材管理接口获得。
  195. */
  196. public static function update_customer_remark($corpid, $userid, $external_userid, $remark = null, $description = null,
  197. $remark_company = null, array $remark_mobiles = null, $remark_pic_mediaid = null)
  198. {
  199. $accessToken = AccessTokenService::getAccessToken($corpid, '修改客户备注信息');
  200. if(empty($accessToken)) {
  201. Log::logError('修改客户备注信息', [
  202. 'params' => ['corpid' => $corpid],
  203. 'errmsg' => '令牌获取失败'
  204. ], 'qyWechat');
  205. return false;
  206. }
  207. $postData = [
  208. 'userid' => $userid,
  209. 'external_userid' => $external_userid,
  210. ];
  211. if(!is_null($remark)) {
  212. $postData['remark'] = $remark;
  213. }
  214. if(!is_null($description)) {
  215. $postData['description'] = $description;
  216. }
  217. if(!is_null($remark_company)) {
  218. $postData['remark_company'] = $remark_company;
  219. }
  220. if(!is_null($remark_mobiles)) {
  221. $postData['remark_mobiles'] = $remark_mobiles;
  222. }
  223. if(!is_null($remark_pic_mediaid)) {
  224. $postData['remark_pic_mediaid'] = $remark_pic_mediaid;
  225. }
  226. $requestUri = config('qyWechat.update_customer_remark');
  227. $requestUri .= $accessToken;
  228. $response = HttpService::httpPost($requestUri ,json_encode($postData));
  229. $responseData = json_decode($response, true);
  230. Log::logInfo('修改客户备注信息', [
  231. 'params' => [
  232. 'corpid' => $corpid,
  233. 'userid' => $userid,
  234. 'external_userid' => $external_userid,
  235. 'remark' => $remark,
  236. 'description' => $description,
  237. 'remark_company' => $remark_company,
  238. 'remark_mobiles' => $remark_mobiles,
  239. 'remark_pic_mediaid' => $remark_pic_mediaid,
  240. ],
  241. 'response' => $responseData
  242. ], 'qyWechat');
  243. return $responseData;
  244. }
  245. /**
  246. * 创建企业标签
  247. * @param $corpid string 企微id
  248. * @param $group_id string 标签组id
  249. * @param $group_name string 标签组名称
  250. * @param $order integer 标签组排序值
  251. * @param $tag array 标签列表
  252. * @return mixed
  253. */
  254. public static function add_corp_tag($corpid, $group_id, $group_name, $order, $tag, $retry = 0)
  255. {
  256. $accessToken = AccessTokenService::getAccessToken($corpid, '创建企业标签');
  257. if(empty($accessToken)) {
  258. Log::logError('创建企业标签', [
  259. 'params' => ['corpid' => $corpid],
  260. 'errmsg' => '令牌获取失败'
  261. ], 'qyWechat');
  262. return false;
  263. }
  264. $requestUri = config('qyWechat.add_corp_tag');
  265. $requestUri .= $accessToken;
  266. $params['tag'] = $tag; // '[{"name": "TAG_NAME_1","order": 1},{"name": "TAG_NAME_2","order": 2}]';
  267. if (!empty($group_name)) {
  268. $params['group_name'] = $group_name;
  269. }
  270. if (!empty($group_id)) {
  271. $params['group_id'] = $group_id;
  272. }
  273. if (!empty($order)) {
  274. $params['order'] = $order;
  275. }
  276. $responseData = HttpService::httpPost($requestUri, json_encode($params), true);
  277. if($responseData === false && $retry < 5) {
  278. $retry++;
  279. return self::add_corp_tag($corpid, $group_id, $group_name, $order, $tag, $retry);
  280. }
  281. $responseData = json_decode($responseData, 1);
  282. Log::logInfo('创建企业标签', [
  283. 'params' => [
  284. 'corpid' => $corpid,
  285. 'group_id' => $group_id,
  286. 'group_name' => $group_name,
  287. 'order' => $order,
  288. 'tag' => $tag,
  289. ],
  290. 'response' => $responseData
  291. ], 'qyWechat');
  292. return $responseData;
  293. }
  294. /**
  295. * 编辑客户企业标签
  296. * @param $corpid string 企微id
  297. * @param $userid string 企微成员userid
  298. * @param $external_userid string 外部联系人userid
  299. * @param $add_tag array 要标记的企业标签列表
  300. * @param $remove_tag array 要移除的企业标签列表
  301. * @return bool|mixed
  302. */
  303. public static function mark_tag($corpid, $userid, $external_userid, $add_tag, $remove_tag, $retry=0)
  304. {
  305. $accessToken = AccessTokenService::getAccessToken($corpid, '编辑客户企业标签');
  306. if(empty($accessToken)) {
  307. Log::logError('编辑客户企业标签', [
  308. 'params' => ['corpid' => $corpid],
  309. 'errmsg' => '令牌获取失败',
  310. ], 'qyWechat');
  311. return false;
  312. }
  313. $requestUri = config('qyWechat.mark_tag');
  314. $requestUri .= $accessToken;
  315. $postData['userid'] = $userid;
  316. $postData['external_userid'] = $external_userid;
  317. if($add_tag) {
  318. $postData['add_tag'] = $add_tag;
  319. }
  320. if($remove_tag) {
  321. $postData['remove_tag'] = $remove_tag;
  322. }
  323. $responseData = HttpService::httpPost($requestUri, json_encode($postData), true);
  324. if($responseData === false && $retry < 5) {
  325. $retry++;
  326. return self::mark_tag($corpid, $userid, $external_userid, $add_tag, $remove_tag, $retry);
  327. }
  328. $responseData = json_decode($responseData, 1);
  329. Log::logInfo('编辑客户企业标签', [
  330. 'params' => [
  331. 'corpid' => $corpid,
  332. 'userid' => $userid,
  333. 'external_userid' => $external_userid,
  334. 'add_tag' => $add_tag,
  335. 'remove_tag' => $remove_tag,
  336. ],
  337. 'response' => $responseData,
  338. ], 'qyWechat');
  339. return $responseData;
  340. }
  341. /**
  342. * 获取企微所有已授权部门列表
  343. * @param $corpid
  344. * @return bool|mixed
  345. */
  346. public static function simplelist($corpid)
  347. {
  348. $accessToken = AccessTokenService::getAccessToken($corpid, '获取企微所有已授权部门列表');
  349. if(empty($accessToken)) {
  350. Log::logError('获取企微所有已授权部门列表', [
  351. 'params' => ['corpid' => $corpid],
  352. 'errmsg' => '令牌获取失败'
  353. ], 'qyWechat');
  354. return false;
  355. }
  356. $requestUri = config('qyWechat.simplelist');
  357. $requestUri .= $accessToken.'&id=';
  358. $response = HttpService::httpGet($requestUri );
  359. $responseData = json_decode($response, true);
  360. Log::logInfo('获取企微所有已授权部门列表', [
  361. 'params' => ['corpid' => $corpid],
  362. 'response' => $responseData,
  363. ], 'qyWechat');
  364. return $responseData;
  365. }
  366. /**
  367. * 获取企业配置了联系我功能的客服列表
  368. * @param $corpid
  369. * @return bool|mixed
  370. */
  371. public static function get_follow_user_list($corpid)
  372. {
  373. $accessToken = AccessTokenService::getAccessToken($corpid, '获取企业配置了联系我功能的客服列表');
  374. if(empty($accessToken)) {
  375. Log::logError('获取企业配置了联系我功能的客服列表', [
  376. 'params' => ['corpid' => $corpid],
  377. 'errmsg' => '令牌获取失败'
  378. ], 'qyWechat');
  379. return false;
  380. }
  381. $requestUri = config('qyWechat.get_follow_user_list');
  382. $requestUri .= $accessToken.'&id=';
  383. $response = HttpService::httpGet($requestUri );
  384. $responseData = json_decode($response, true);
  385. Log::logInfo('获取企业配置了联系我功能的客服列表', [
  386. 'params' => ['corpid' => $corpid],
  387. 'response' => $responseData,
  388. ], 'qyWechat');
  389. return $responseData;
  390. }
  391. /**
  392. * 获取部门详细信息
  393. * @param $corpid
  394. * @param $department_id
  395. * @return bool|mixed
  396. */
  397. public static function get_department_info($corpid, $department_id)
  398. {
  399. $accessToken = AccessTokenService::getAccessToken($corpid, '获取部门详细信息');
  400. if(empty($accessToken)) {
  401. Log::logError('获取部门详细信息', [
  402. 'params' => [
  403. 'corpid' => $corpid,
  404. 'depatment_id' => $department_id,
  405. ],
  406. 'errmsg' => '令牌获取失败'
  407. ], 'qyWechat');
  408. return false;
  409. }
  410. $requestUri = config('qyWechat.get_department_info');
  411. $requestUri .= $accessToken.'&id='.$department_id;
  412. $response = HttpService::httpGet($requestUri );
  413. $responseData = json_decode($response, true);
  414. Log::logInfo('获取部门详细信息', [
  415. 'params' => [
  416. 'corpid' => $corpid,
  417. 'depatment_id' => $department_id,
  418. ],
  419. 'response' => $responseData,
  420. ], 'qyWechat');
  421. return $responseData;
  422. }
  423. /**
  424. * 根据Oauth2授权code获取用户信息
  425. * */
  426. public static function getCustomerInfoByCode($corpid, $code)
  427. {
  428. # 获取SuiteAccessToken
  429. $accessToken = AccessTokenService::getAccessToken($corpid, '根据Oauth2授权code获取用户信息');
  430. if(empty($accessToken)) {
  431. Log::logError('根据Oauth2授权code获取用户信息时令牌获取失败', [
  432. 'corpid' => $corpid,
  433. 'code' => $code
  434. ], 'GetCustomerInfoByCode');
  435. return false;
  436. }
  437. # 获取用户信息API
  438. $getExternalContactUri = config('qyWechat.get_user_info');
  439. $getExternalContactUri .= $accessToken . '&code=' . $code;
  440. $response = HttpService::httpGet($getExternalContactUri);
  441. $responseData = json_decode($response, true);
  442. return $responseData;
  443. }
  444. /**
  445. * 分配在职成员客户
  446. * @param $corpid string 企微id
  447. * @param $handoverUserId string 被接替员工id
  448. * @param $takeoverUserId string 接替员工id
  449. * @param $externalUserIdList array 需要迁移的外部联系人id
  450. * @param $transferSuccessMsg string 迁移成功后为客户发送的提醒消息
  451. * @return mixed
  452. */
  453. public static function transferCustomerOnJob($corpid, $handoverUserId, $takeoverUserId, $externalUserIdList,
  454. $transferSuccessMsg)
  455. {
  456. $accessToken = AccessTokenService::getAccessToken($corpid, '分配在职成员客户');
  457. if(empty($accessToken)) {
  458. Log::logError('分配在职成员客户', [
  459. 'params' => ['corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId,
  460. 'external_userid_list' => $externalUserIdList, 'transfer_success_msg' => $transferSuccessMsg],
  461. 'errmsg' => '令牌获取失败'
  462. ], 'qyWechat');
  463. return false;
  464. }
  465. $url = config('qyWechat.transfer_customer_on_job').$accessToken;
  466. $params['handover_userid'] = $handoverUserId;
  467. $params['takeover_userid'] = $takeoverUserId;
  468. if(!empty($transferSuccessMsg)) {
  469. $params['transfer_success_msg'] = $transferSuccessMsg;
  470. }
  471. $params['external_userid'] = $externalUserIdList;
  472. $result = HttpService::httpPost($url, json_encode($params), true);
  473. $result = json_decode($result, 1);
  474. Log::logInfo('分配在职成员客户', [
  475. 'params' => ['corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId,
  476. 'external_userid_list' => $externalUserIdList, 'transfer_success_msg' => $transferSuccessMsg],
  477. 'responseData' => $result,
  478. ], 'qyWechat');
  479. return $result;
  480. }
  481. /**
  482. * 查询待分配的客户列表
  483. * @param $corpid
  484. * @param $cursor
  485. * @return mixed
  486. */
  487. public static function getUnassignedList($corpid, $cursor, $retry = 0)
  488. {
  489. $accessToken = AccessTokenService::getAccessToken($corpid, '查询待分配的离职成员列表');
  490. if(empty($accessToken)) {
  491. Log::logError('查询待分配的离职成员列表', [
  492. 'params' => ['corpid' => $corpid],
  493. 'errmsg' => '令牌获取失败'
  494. ], 'qyWechat');
  495. return false;
  496. }
  497. $url = config('qyWechat.get_unassigned_list').$accessToken;
  498. $params['cursor'] = $cursor;
  499. $data = HttpService::httpPost($url, json_encode($params), true);
  500. if($data === false && $retry < 3) {
  501. $retry++;
  502. return self::getUnassignedList($corpid, $cursor, $retry);
  503. }
  504. $data = json_decode($data, 1);
  505. Log::logInfo('查询待分配的离职成员列表', [
  506. 'params' => ['corpid' => $corpid, 'cursor' => $cursor],
  507. 'responseData' => $data,
  508. ], 'qyWechat');
  509. return $data;
  510. }
  511. /**
  512. * 分配离职成员的客户
  513. * @param $corpid string 企业id
  514. * @param $handoverUserId string 原跟进成员的userid
  515. * @param $takeoverUserId string 接替成员的userid
  516. * @param $externalUserIdList array 客户的external_userid列表,每次最多分配100个客户
  517. * @return mixed
  518. * 注意:
  519. * 1.external_userid必须是handover_userid的客户(即配置了客户联系功能的成员所添加的联系人)。
  520. * 2.handover_userid必须是已离职用户。
  521. */
  522. public static function transferCustomerQuit($corpid, $handoverUserId, $takeoverUserId, $externalUserIdList)
  523. {
  524. $accessToken = AccessTokenService::getAccessToken($corpid, '分配离职成员的客户');
  525. if(empty($accessToken)) {
  526. Log::logError('分配离职成员的客户', [
  527. 'params' => ['corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId,
  528. 'external_userid_list' => $externalUserIdList],
  529. 'errmsg' => '令牌获取失败'
  530. ], 'qyWechat');
  531. return false;
  532. }
  533. $url = config('qyWechat.transfer_customer_quit').$accessToken;
  534. $params['handover_userid'] = $handoverUserId;
  535. $params['takeover_userid'] = $takeoverUserId;
  536. $params['external_userid'] = $externalUserIdList;
  537. $result = HttpService::httpPost($url, json_encode($params), true);
  538. $result = json_decode($result, 1);
  539. Log::logInfo('分配离职成员的客户', [
  540. 'params' => ['corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId,
  541. 'external_userid_list' => $externalUserIdList],
  542. 'responseData' => $result,
  543. ], 'qyWechat');
  544. return $result;
  545. }
  546. /**
  547. * 客户迁移结果查询
  548. * @param $type int 接替类型 1在职 2离职
  549. * @param $corpid
  550. * @param $handOverUserId string 原跟进员工user_id
  551. * @param $takeOverUserId string 接替成员的user_id
  552. * @param string $cursor string 分页查询的游标
  553. * @return mixed
  554. */
  555. public static function transferResult($type, $corpid, $handOverUserId, $takeOverUserId, $cursor)
  556. {
  557. $accessToken = AccessTokenService::getAccessToken($corpid, '客户迁移结果查询');
  558. if(empty($accessToken)) {
  559. Log::logError('客户迁移结果查询', [
  560. 'params' => [
  561. 'type' => $type,
  562. 'corpid' => $corpid,
  563. 'handover_userid' => $handOverUserId,
  564. 'takeover_userid' => $takeOverUserId,
  565. 'cursor' => $cursor,
  566. ],
  567. 'errmsg' => '令牌获取失败'
  568. ], 'qyWechat');
  569. return false;
  570. }
  571. if(1 == $type) {
  572. $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/transfer_result?access_token='.$accessToken;
  573. } else {
  574. $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/resigned/transfer_result?access_token='.$accessToken;
  575. }
  576. $params['handover_userid'] = $handOverUserId;
  577. $params['takeover_userid'] = $takeOverUserId;
  578. $params['cursor'] = $cursor;
  579. $result = HttpService::httpPost($url, json_encode($params), true);
  580. $result = json_decode($result, 1);
  581. Log::logInfo('客户迁移结果查询', [
  582. 'params' => [
  583. 'type' => $type,
  584. 'corpid' => $corpid,
  585. 'handover_userid' => $handOverUserId,
  586. 'takeover_userid' => $takeOverUserId,
  587. 'cursor' => $cursor,
  588. ],
  589. 'response' => $result,
  590. ], 'qyWechat');
  591. return $result;
  592. }
  593. /**
  594. * 客户群基本信息获取
  595. * */
  596. public static function getGroupChatList($corpid, $ownerFilter, $limit, $cursor, $statusFilter=0, $retry=0)
  597. {
  598. $accessToken = AccessTokenService::getAccessToken($corpid, '客户群基本信息获取');
  599. if(empty($accessToken)) {
  600. Log::logError('客户群基本信息获取', [
  601. 'params' => ['corpid' => $corpid],
  602. 'errmsg' => '令牌获取失败'
  603. ], 'qyWechat');
  604. return false;
  605. }
  606. $url = config('qyWechat.group_chat_list') . $accessToken;
  607. $postData = [
  608. 'status_filter' => $statusFilter,
  609. 'owner_filter' => [
  610. 'userid_list' => $ownerFilter
  611. ],
  612. 'cursor' => $cursor,
  613. 'limit' => $limit
  614. ];
  615. $response = HttpService::httpPost($url, json_encode($postData));
  616. if($response === false && $retry <=5) { // 发起重试
  617. $retry++;
  618. return self::getGroupChatList($corpid, $ownerFilter, $limit, $cursor, $statusFilter, $retry);
  619. }
  620. $responseData = json_decode($response, true);
  621. Log::logInfo('getGroupChatList', (array)$responseData, 'qyWechat');
  622. return $responseData;
  623. }
  624. /**
  625. * 获取客户群详情
  626. * */
  627. public static function getGroupChatDetail($corpid, $chatId, $needName=1, $retry=0)
  628. {
  629. $accessToken = AccessTokenService::getAccessToken($corpid, '客户群基本信息获取');
  630. if(empty($accessToken)) {
  631. Log::logError('客户群详情获取', [
  632. 'params' => ['corpid' => $corpid],
  633. 'errmsg' => '令牌获取失败'
  634. ], 'qyWechat');
  635. return false;
  636. }
  637. $url = config('qyWechat.group_chat_detail') . $accessToken;
  638. $postData = [
  639. 'chat_id' => $chatId,
  640. 'need_name' => $needName
  641. ];
  642. $response = HttpService::httpPost($url, json_encode($postData));
  643. if($response === false && $retry <=5) { // 发起重试
  644. $retry++;
  645. return self::getGroupChatDetail($corpid, $chatId, $needName, $retry);
  646. }
  647. $responseData = json_decode($response, true);
  648. Log::logInfo('getGroupChatDetail', (array)$responseData, 'qyWechat');
  649. return $responseData;
  650. }
  651. /**
  652. * 企业成员user_id转换为open_userid
  653. * */
  654. public static function useridToOpenUserid($corpid, $userIdList)
  655. {
  656. $accessToken = AccessTokenService::getAccessToken($corpid, '企业成员user_id转换为open_userid');
  657. if(empty($accessToken)) {
  658. Log::logError('企业成员user_id转换为open_userid', [
  659. 'params' => ['corpid' => $corpid],
  660. 'errmsg' => '令牌获取失败'
  661. ], 'qyWechat');
  662. return false;
  663. }
  664. $url = config('qyWechat.userid_to_open_userid') . $accessToken;
  665. $postData = [
  666. 'userid_list' => $userIdList,
  667. ];
  668. $response = HttpService::httpPost($url, json_encode($postData));
  669. $responseData = json_decode($response, true);
  670. Log::logInfo('useridToOpenUserid', ['data' => $responseData, 'param' => $userIdList, 'corpid' => $corpid], 'qyWechat');
  671. return $responseData;
  672. }
  673. /**
  674. * 配置客户群进群方式
  675. * @param $corpid string 企微id
  676. * @param $scene integer 场景 1:群的小程序插件 2:群的二维码插件
  677. * @param $remark string 联系方式的备注信息,用于助记,超过30个字符将被截断
  678. * @param $autoCreateRoom int 当群满了后,是否自动新建群。0-否;1-是。 默认为1
  679. * @param $roomBaseName string 自动建群的群名前缀
  680. * @param $roomBaseId int 自动建群的起始序号
  681. * @param $chatIdList array 使用该配置的客户群ID列表,支持5个
  682. * @param $state string 企业自定义的state参数,用于区分不同的入群渠道
  683. * */
  684. public static function addGroupJoinWay(
  685. $corpid, $scene, $chatIdList, $state, $autoCreateRoom=1, $roomBaseName='', $roomBaseId=1, $remark=null
  686. )
  687. {
  688. $accessToken = AccessTokenService::getAccessToken($corpid, '配置客户群进群方式');
  689. if(empty($accessToken)) {
  690. Log::logError('配置客户群进群方式', [
  691. 'params' => [
  692. 'corpid' => $corpid, 'scene' => $scene, 'chat_id_list' => $chatIdList, 'state' => $state, 'auto_create_room' => $autoCreateRoom, 'room_base_name' => $roomBaseName, 'room_base_id' => $roomBaseId, 'remark' => $remark
  693. ],
  694. 'errmsg' => '令牌获取失败'
  695. ], 'qyWechat');
  696. return false;
  697. }
  698. $url = config('qyWechat.add_group_join_way') . $accessToken;
  699. $postData = [
  700. 'scene' => $scene,
  701. 'chat_id_list' => $chatIdList
  702. ];
  703. # 联系方式的备注信息
  704. if($remark)
  705. $postData['remark'] = $remark;
  706. # 当群满了后,是否自动新建群
  707. if(in_array($autoCreateRoom, [0, 1]))
  708. $postData['auto_create_room'] = $autoCreateRoom;
  709. # 自动建群规则
  710. if($roomBaseName)
  711. $postData['room_base_name'] = $roomBaseName;
  712. if(is_numeric($roomBaseId))
  713. $postData['room_base_id'] = $roomBaseId;
  714. # state
  715. if($state)
  716. $postData['state'] = $state;
  717. $response = HttpService::httpPost($url, json_encode($postData));
  718. $responseData = json_decode($response, true);
  719. Log::logInfo('addGroupJoinWay', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  720. return $responseData;
  721. }
  722. /**
  723. * 获取客户群进群方式配置
  724. * @param $corpid string 企微ID
  725. * @param $configId string 联系方式的配置id
  726. * */
  727. public static function getGroupJoinWay($corpid, $configId)
  728. {
  729. $accessToken = AccessTokenService::getAccessToken($corpid, '获取客户群进群方式配置');
  730. if(empty($accessToken)) {
  731. Log::logError('获取客户群进群方式配置', [
  732. 'params' => ['corpid' => $corpid, 'config_id' => $configId],
  733. 'errmsg' => '令牌获取失败'
  734. ], 'qyWechat');
  735. return false;
  736. }
  737. $url = config('qyWechat.get_group_join_way') . $accessToken;
  738. $postData = [
  739. 'config_id' => $configId,
  740. ];
  741. $response = HttpService::httpPost($url, json_encode($postData));
  742. $responseData = json_decode($response, true);
  743. Log::logInfo('getGroupJoinWay', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  744. return $responseData;
  745. }
  746. /**
  747. * 更新客户群进群方式配置
  748. * @param $corpid string 企微id
  749. * @param $configId string 联系方式的配置id
  750. * @param $scene integer 场景 1:群的小程序插件 2:群的二维码插件
  751. * @param $remark string 联系方式的备注信息,用于助记,超过30个字符将被截断
  752. * @param $autoCreateRoom int 当群满了后,是否自动新建群。0-否;1-是。 默认为1
  753. * @param $roomBaseName string 自动建群的群名前缀
  754. * @param $roomBaseId int 自动建群的起始序号
  755. * @param $chatIdList array 使用该配置的客户群ID列表,支持5个
  756. * @param $state string 企业自定义的state参数,用于区分不同的入群渠道
  757. * */
  758. public static function updateGroupJoinWay(
  759. $corpid, $configId, $scene, $chatIdList, $state, $autoCreateRoom=1, $roomBaseName='', $roomBaseId=1, $remark=null
  760. )
  761. {
  762. $accessToken = AccessTokenService::getAccessToken($corpid, '配置客户群进群方式');
  763. if(empty($accessToken)) {
  764. Log::logError('配置客户群进群方式', [
  765. 'params' => [
  766. 'corpid' => $corpid, 'scene' => $scene, 'chat_id_list' => $chatIdList, 'state' => $state, 'auto_create_room' => $autoCreateRoom, 'room_base_name' => $roomBaseName, 'room_base_id' => $roomBaseId, 'remark' => $remark
  767. ],
  768. 'errmsg' => '令牌获取失败'
  769. ], 'qyWechat');
  770. return false;
  771. }
  772. $url = config('qyWechat.update_group_join_way') . $accessToken;
  773. $postData = [
  774. 'config_id' => $configId,
  775. 'scene' => $scene,
  776. 'chat_id_list' => $chatIdList
  777. ];
  778. # 联系方式的备注信息
  779. if($remark)
  780. $postData['remark'] = $remark;
  781. # 当群满了后,是否自动新建群
  782. if(in_array($autoCreateRoom, [0, 1]))
  783. $postData['auto_create_room'] = $autoCreateRoom;
  784. # 自动建群规则
  785. if($roomBaseName)
  786. $postData['room_base_name'] = $roomBaseName;
  787. if(is_numeric($roomBaseId))
  788. $postData['room_base_id'] = $roomBaseId;
  789. # state
  790. if($state)
  791. $postData['state'] = $state;
  792. $response = HttpService::httpPost($url, json_encode($postData));
  793. $responseData = json_decode($response, true);
  794. Log::logInfo('updateGroupJoinWay', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  795. return $responseData;
  796. }
  797. /**
  798. * 删除客户群进群方式配置
  799. * @param $corpid string 企微ID
  800. * @param $configId string 联系方式的配置id
  801. * */
  802. public static function delGroupJoinWay($corpid, $configId)
  803. {
  804. $accessToken = AccessTokenService::getAccessToken($corpid, '删除客户群进群方式配置');
  805. if(empty($accessToken)) {
  806. Log::logError('删除客户群进群方式配置', [
  807. 'params' => ['corpid' => $corpid, 'config_id' => $configId],
  808. 'errmsg' => '令牌获取失败'
  809. ], 'qyWechat');
  810. return false;
  811. }
  812. $url = config('qyWechat.del_group_join_way') . $accessToken;
  813. $postData = [
  814. 'config_id' => $configId,
  815. ];
  816. $response = HttpService::httpPost($url, json_encode($postData));
  817. $responseData = json_decode($response, true);
  818. Log::logInfo('delGroupJoinWay', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  819. return $responseData;
  820. }
  821. /**
  822. * 停止企业群发
  823. * */
  824. public static function cancelMsg($corpid, $msgId)
  825. {
  826. $accessToken = AccessTokenService::getAccessToken($corpid);
  827. if(empty($accessToken)) {
  828. Log::logError('停止企业群发令牌获取失败', [
  829. 'params' => ['corpid' => $corpid, 'msg_id' => $msgId],
  830. ], 'qyWechat');
  831. return false;
  832. }
  833. $url = config('qyWechat.cancel_mass_msg') . $accessToken;
  834. $postData = [
  835. 'msgid' => $msgId,
  836. ];
  837. $response = HttpService::httpPost($url, json_encode($postData));
  838. $responseData = json_decode($response, true);
  839. Log::logInfo('cancelMsg', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  840. return $responseData;
  841. }
  842. // 根据内部员工获取外部联系客户具体方法
  843. public static function getExternalContactList($userId, $corpid, $retry = 0)
  844. {
  845. $accessToken = AccessTokenService::getAccessToken($corpid, '根据员工获取外部客户');
  846. if(!$accessToken) {
  847. Log::logError('获取客户列表时accessToken异常', [
  848. 'params' => ['corpid' => $corpid],
  849. 'errmsg' => '令牌获取失败'
  850. ], 'getCustomerList');
  851. return '令牌获取失败';
  852. }
  853. $url = config('qyWechat.external_contact_list').$accessToken.'&userid='.$userId;
  854. $response = HttpService::HttpGet($url);
  855. if(empty($response) && $retry<5) {
  856. $retry++;
  857. sleep(1);
  858. return self::getExternalContactList($userId, $corpid, $retry);
  859. }
  860. $responseData = json_decode($response, true);
  861. Log::logInfo('获取客户列表响应结果为:', ['data' => $responseData, 'param' => ['corpid' => $corpid, 'user_id' => $userId]
  862. , 'url' => $url], 'getExternalContactList');
  863. return $responseData;
  864. }
  865. /**
  866. * 客户群在职迁移
  867. * */
  868. public static function onJobTransfer($corpid, $chatIdList, $newOwner)
  869. {
  870. $accessToken = AccessTokenService::getAccessToken($corpid);
  871. if(empty($accessToken)) {
  872. Log::logError('【onJobTransfer】客户群在职迁移令牌获取失败', [
  873. 'params' => ['corpid' => $corpid, 'chat_id_list' => $chatIdList, 'new_owner' => $newOwner],
  874. ], 'qyWechat');
  875. return false;
  876. }
  877. $url = config('qyWechat.chat_group_on_job_transfer') . $accessToken;
  878. $postData = [
  879. 'chat_id_list' => $chatIdList,
  880. 'new_owner' => $newOwner
  881. ];
  882. $response = HttpService::httpPost($url, json_encode($postData));
  883. $responseData = json_decode($response, true);
  884. Log::logInfo('onJobTransfer', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  885. return $responseData;
  886. }
  887. /**
  888. * 离职迁移
  889. * */
  890. public static function transfer($corpid, $chatIdList, $newOwner)
  891. {
  892. $accessToken = AccessTokenService::getAccessToken($corpid);
  893. if(empty($accessToken)) {
  894. Log::logError('【OffJobTransfer】客户群离职迁移令牌获取失败', [
  895. 'params' => ['corpid' => $corpid, 'chat_id_list' => $chatIdList, 'new_owner' => $newOwner],
  896. ], 'qyWechat');
  897. return false;
  898. }
  899. $url = config('qyWechat.chat_group_transfer') . $accessToken;
  900. $postData = [
  901. 'chat_id_list' => $chatIdList,
  902. 'new_owner' => $newOwner
  903. ];
  904. $response = HttpService::httpPost($url, json_encode($postData));
  905. $responseData = json_decode($response, true);
  906. Log::logInfo('OffJobTransfer', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  907. return $responseData;
  908. }
  909. /**
  910. * 停止发表企业朋友圈
  911. * */
  912. public static function cancelMomentTask($corpid, $momentId)
  913. {
  914. $accessToken = AccessTokenService::getAccessToken($corpid);
  915. if(empty($accessToken)) {
  916. Log::logError('停止发表企业朋友圈令牌获取失败', [
  917. 'params' => ['corpid' => $corpid, 'moment_id' => $momentId],
  918. ], 'qyWechat');
  919. return false;
  920. }
  921. $url = config('qyWechat.cancel_moment_task') . $accessToken;
  922. $postData = [
  923. 'moment_id' => $momentId,
  924. ];
  925. $response = HttpService::httpPost($url, json_encode($postData));
  926. $responseData = json_decode($response, true);
  927. Log::logInfo('cancelMomentTask', ['data' => $responseData, 'param' => $postData, 'corpid' => $corpid], 'qyWechat');
  928. return $responseData;
  929. }
  930. // 根据内部员工获取外部联系客户具体方法
  931. public static function getCustomerListMethod($params, $accessToken, $retry = 0)
  932. {
  933. $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user?access_token='.$accessToken;
  934. $result = HttpService::httpPost($url, json_encode($params), true);
  935. if(empty($result) && $retry < 3) {
  936. $retry++;
  937. return self::getCustomerListMethod($params, $accessToken, $retry);
  938. }
  939. $result = json_decode($result, 1);
  940. if(isset($result['errcode']) && $result['errcode'] == 0) {
  941. return $result;
  942. } else {
  943. // 请求失败,将响应数据写入日志
  944. Log::logError('获取内部员工对应的外部联系人列表失败:URL'.$url.', 请求参数:'.json_encode($params),
  945. (array)$result, 'get_user_customer_list');
  946. return false;
  947. }
  948. }
  949. // 获取配置了客户联系功能的成员列表
  950. public static function followUserList($corpid, $accessToken = null, $retry = 0)
  951. {
  952. if(empty($corpid) && empty($accessToken)) {
  953. return [];
  954. }
  955. if(empty($accessToken)) {
  956. $accessToken = AccessTokenService::getAccessToken($corpid, '获取配置了客户联系功能的成员列表');
  957. }
  958. $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token='.$accessToken;
  959. $result = HttpService::httpGet($url);
  960. if(empty($result) && $retry<3) {
  961. $retry++;
  962. return self::followUserList($corpid, $accessToken, $retry);
  963. }
  964. $result = json_decode($result, 1);
  965. if(isset($result['errcode']) && $result['errcode'] == 0) {
  966. return [$result['follow_user'], 0];
  967. } else {
  968. $errcode = $result['errcode'] ?? null;
  969. // 请求失败,将响应数据写入日志
  970. Log::logError('获取配置了客户联系功能的成员列表失败,url:'.$url,
  971. (array)$result,
  972. 'follow_user_list');
  973. return [[], $errcode];
  974. }
  975. }
  976. }