$corpid ]; if(empty($corpid)) { Log::logInfo('getCorCustomerList 企业id为空 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '企业id为空'], 2004]; } // 判断键是否存在 $redisKey = 'Playlet::getCorCustomerList-'.$corpid; $value = RedisModel::get($redisKey); if(!empty($value)) { Log::logInfo('getCorCustomerList 操作太快 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '操作太快'], 2007]; } // 根据企业id获取accessToken $accessToken = AuthorizeCorp::getAccessToken($corpid, '全量获取企业部门、标签和员工信息'); if(empty($accessToken)) { Log::logInfo('getCorCustomerList 获取企业access_token失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '获取企业access_token失败'], 2000]; } // 根据企业获取部门列表 $departmentList = self::getCorDepartmentList($corpid, $accessToken); if(empty($departmentList)) { Log::logInfo('getCorCustomerList 部门权限获取失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '部门权限获取失败'], 2001]; } // 将部门信息保存到本地 foreach($departmentList as $department) { $departmentId = $department['id']; $res = wechatWorkService::getDepartmentInfo($departmentId, $corpid, $accessToken); if(!empty($res)) { DjDepartment::departmentInfoSave($corpid, $res); } $res = wechatWorkService::departmentUserList($corpid, $departmentId, $accessToken); if(isset($res['errcode']) && $res['errcode'] == 0) { if(!empty($res['userlist'])) { // 将员工信息保存入库 foreach($res['userlist'] as $user) { $userId = DjUser::departmentUserSave($corpid, $user); } } else { Log::logInfo('getCorCustomerList 获取内部员工信息为空 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); } } else { Log::logInfo('getCorCustomerList 获取内部员工信息失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '获取内部员工信息失败'], 2002]; } } # 获取所有企业标签 $data1 = wechatWorkService::getCorTagList($corpid); if(!empty($data1)) { // Log::logInfo('getCorCustomerList 获取企业标签失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); // return [['error' => '获取企业标签失败'], 2005]; // } else { $re1 = wechatWorkService::tagDataSave($corpid, 1, $data1); if(!$re1) { Log::logInfo('getCorCustomerList 保存企业标签失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '保存企业标签失败'], 2006]; } } # 获取所有客户群 RedisModel::lPush(ChatGroup::CHAT_GROUP_BASIC_INFO_RDS, json_encode(['corpid' => $corpid], 256)); // 获取所有已激活客服列表 $followUserList = DjUser::getUserIdList($corpid); $followUserList = json_decode(json_encode($followUserList), 1); // 循环处理配置了客户联系功能的员工,拉取对应的客户信息 // 如果使用没有配置联系我的内部员工id来请求数据的话,接口会返回user_id异常的错误信息 $followUserListArr = array_chunk($followUserList, 100); foreach ($followUserListArr as $userArr) { $value['corpid'] = $corpid; $value['user_list'] = $userArr; RedisModel::lPush(AuthorizeCorp::SYNC_CORP_CUSTOMER, json_encode($value)); } RedisModel::set($redisKey, time()); RedisModel::expire($redisKey, 600); return [['info' => '获取成功'], 0]; } public static function syncCorpData($corpid) { $requestData = [ 'corpid' => $corpid ]; $subject = config('app.name') . '于' . date('d日H:i:s') . '响应异常'; try{ if(empty($corpid)) { Log::logError('syncCorpData',[ 'params' => $requestData, 'errmsg' => '企微id为空', ], 'interface'); return [['error' => '企业id为空'], 2004]; } // 判断键是否存在 $redisKey = 'Playlet::getCorCustomerList-'.$corpid; $value = RedisModel::get($redisKey); if(!empty($value)) { Log::logError('syncCorpData', [ 'params' => $requestData, 'errmsg' => '请求频率超限制', ], 'interface'); return [['error' => '操作太快'], 2007]; } // 根据企业id获取accessToken $accessToken = AuthorizeCorp::getAccessToken($corpid, '全量获取企业部门、标签和员工信息'); if(empty($accessToken)) { Log::logError('syncCorpData', [ 'params' => $requestData, 'errmsg' => '获取企业access_token失败', ], 'interface'); return [['error' => '获取企业access_token失败'], 2000]; } // 根据企业获取部门列表 $departmentResponse = QyCommon::simplelist($corpid); if(isset($departmentResponse['errcode']) && $departmentResponse['errcode'] == 0) { $departmentList = $departmentResponse['department_id']; } else { Log::logError('syncCorpData', [ 'params' => $requestData, 'errmsg' => '部门权限获取失败', 'response' => $departmentResponse, ], 'interface'); $content = '同步企微信息--获取授权部门列表失败'; EmailQueue::rPush($subject, nl2br($content), ['song.shen@kuxuan-inc.com'], config('app.name')); return [['error' => '部门权限获取失败'], 2001]; } if(empty($departmentList)) { Log::logError('syncCorpData', [ 'params' => $requestData, 'errmsg' => '获取部门列表为空', 'response' => $departmentResponse, ], 'interface'); return [['error' => '获取部门列表为空'], 2009]; } // 将部门信息保存到本地 foreach($departmentList as $department) { $departmentId = $department['id']; $departmentInfoResponse = QyCommon::get_department_info($corpid, $departmentId); if(isset($departmentInfoResponse['errcode']) && $departmentInfoResponse['errcode'] == 0) { $departmentInfo = $departmentInfoResponse['department']; if(!empty($departmentInfo)) { DjDepartment::departmentInfoSave($corpid, $departmentInfo); } } $res = wechatWorkService::departmentUserList($corpid, $departmentId, $accessToken); if(isset($res['errcode']) && $res['errcode'] == 0) { if(!empty($res['userlist'])) { // 将员工信息保存入库 foreach($res['userlist'] as $user) { $userId = DjUser::departmentUserSave($corpid, $user); } } else { Log::logInfo('syncCorpData 获取内部员工信息为空 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); } } else { Log::logInfo('syncCorpData 获取内部员工信息失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '获取内部员工信息失败'], 2002]; } } # 获取所有企业标签 $data1 = wechatWorkService::getCorTagList($corpid); if(empty($data1)) { Log::logInfo('syncCorpData 获取企业标签失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '获取企业标签失败'], 2005]; } else { $re1 = wechatWorkService::tagDataSave($corpid, 1, $data1); if(!$re1) { Log::logInfo('syncCorpData 保存企业标签失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return [['error' => '保存企业标签失败'], 2006]; } } $followUserList = DjUser::getUserIdList($corpid); $followUserList = json_decode(json_encode($followUserList), 1); // 循环处理配置了客户联系功能的员工,拉取对应的客户信息 // 如果使用没有配置联系我的内部员工id来请求数据的话,接口会返回user_id异常的错误信息 $followUserListArr = array_chunk($followUserList, 100); foreach ($followUserListArr as $userArr) { $value['corpid'] = $corpid; $value['user_list'] = $userArr; RedisModel::lPush(AuthorizeCorp::SYNC_CORP_CUSTOMER, json_encode($value)); } RedisModel::set($redisKey, time()); RedisModel::expire($redisKey, 600); return [['info' => '获取成功'], 0]; } catch (\Exception $exception) { Log::logError('syncCorpData',[ 'params' => $requestData, 'exception' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'trace' => $exception->getTraceAsString(), ], 'interface'); $subject = config('app.name') . '于' . date('d日H:i:s') . '抛出异常'; $content = $exception->getMessage() . "\r\n\r\n" . $exception->getTraceAsString(); EmailQueue::rPush($subject, nl2br($content), ['song.shen@kuxuan-inc.com'], config('app.name')); return [['errcode' => '系统异常'], 400]; } } // 根据企业id获取企业部门列表 public static function getCorDepartmentList($corpid, $accessToken = null) { if(empty($corpid) && empty($accessToken)) { return []; } if(empty($accessToken)) { //根据企业id获取对应的access_token $accessToken = AuthorizeCorp::getAccessToken($corpid, '根据企业id获取企业部门列表'); } // 部门id。获取指定部门及其下的子部门(以及子部门的子部门等等,递归)。 如果不填,默认获取全量组织架构 $url = 'https://qyapi.weixin.qq.com/cgi-bin/department/simplelist?access_token='.$accessToken.'&id='; $result = HttpService::httpGet($url); $result = json_decode($result, 1); Log::logInfo('获取企业部门列表,URL'.$url, (array)$result, 'department'); if(isset($result['errcode']) && $result['errcode'] == 0) { // 请求成功 $departmentList = $result['department_id']; return $departmentList; } else { // 请求失败,将响应数据写入日志 EmailQueue::rPush('获取企业部门列表失败', json_encode([ 'corpid' => $corpid, 'result' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return []; } } // 根据部门id获取部门详情 public static function getDepartmentInfo($departmentId, $corpid, $accessToken = null) { if((empty($corpid) && empty($accessToken)) || empty($departmentId)) { return []; } if(empty($accessToken)) { //根据企业id获取对应的access_token $accessToken = AuthorizeCorp::getAccessToken($corpid, '根据部门id获取部门详情'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/department/get?access_token='.$accessToken.'&id='.$departmentId; $result = HttpService::httpGet($url); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { return $result['department']; } else { // 请求失败,将响应数据写入日志 Log::logError('获取部门详情失败,URL:'.$url, (array)$result, 'department'); EmailQueue::rPush('获取部门详情失败', json_encode([ 'corpid' => $corpid, 'department_id' => $departmentId, 'result' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return []; } } // 获取部门下的员工列表 public static function departmentUserList($corpid, $departmentId, $accessToken = null) { if((empty($corpid) && empty($accessToken)) || empty($departmentId)) { return []; } if(empty($accessToken)) { //根据企业id获取对应的access_token $accessToken = AuthorizeCorp::getAccessToken($corpid, '获取部门下的员工列表'); } $fetchChild = 1; // 是否递归获取子部门下面的成员:1-递归获取,0-只获取本部门 $url = 'https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token='.$accessToken.'&department_id='.$departmentId.'&fetch_child='.$fetchChild; $result = HttpService::httpGet($url); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { return $result; } else { // 请求失败,将响应数据写入日志 Log::logError('获取部门下的成员列表失败,URL:'.$url, (array)$result, 'get_department_user_list'); EmailQueue::rPush('获取部门下的成员列表失败', json_encode([ 'corpid' => $corpid, 'department_id' => $departmentId, 'result' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return []; } } // 根据内容员工获取外部客户外层方法(有分页,需要循环获取) public static function getCustomerListByUserId($corpid, $userList, $accessToken = null) { if(empty($corpid) || empty($userList)) { return []; } $params = [ 'userid_list' => $userList, 'cursor' => '', 'limit' => 100 ]; $flag = true; $result = null; $count = 0; while ($flag) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '根据员工获取外部客户'); try{ $result = wechatWorkService::getCustomerListMethod($params, $accessToken, $corpid); // if($corpid == 'wwdfec0bcee287d5c5') { // Log::logInfo('同步客户', ['corpid' => $corpid, 'user_list' => $userList, 'res' =>$result], 'get_corp_customer_list'); // } if(!$result) { $flag = false; } if(!empty($result['external_contact_list'])) { // 将数据保存入库,并进行翻页查询 self::userCustomerDataSave($result['external_contact_list'], $corpid); $count += count($result['external_contact_list']); } # 全部都没有许可时直接返回错误码 if(isset($result['errcode']) && $result['errcode'] == 701008) { foreach($userList as $userId) { RedisModel::lPush(self::SYNC_FAIL_USER_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId ])); } $flag = false; } if(isset($result['errcode']) && $result['errcode'] == 60111) { # 部分客服userid不存在(在放入队列之后客服离职了) // 提取客服userid,将异常userid从数据中排除,然后将处理好的数据重新赛回待处理队列 $errmsg = $result['errmsg'] ?? ''; preg_match("/`(.*)`/i", $errmsg, $userArr); if(isset($userArr[1]) && !empty($userArr[1])) { $userId = $userArr[1]; $key = array_search($userId, $userList); unset($userList[$key]); RedisModel::lPush(AuthorizeCorp::DAILY_SYNC_CORP_CUSTOMER, json_encode([ 'corpid' => $corpid, 'user_list' => array_values($userList), ])); } else { EmailQueue::rPush('同步客服对应客户列表中处理userid异常', json_encode([ 'corpid' => $corpid, 'user_list' => $userList, 'result' => $result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); } $flag = false; } # 部分客服没有许可时会返回无许可客服列表 if(!empty($result['fail_info']['unlicensed_userid_list']) && empty($params['cursor'])) { foreach($result['fail_info']['unlicensed_userid_list'] as $userId) { RedisModel::lPush(self::SYNC_FAIL_USER_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId ])); } } if(empty($result['next_cursor'])) { $flag = false; } else { $params['cursor'] = $result['next_cursor']; } } catch (\Exception $exception) { Log::logError('获取企业微信客户数据异常',[ 'exception' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), ], 'sync_corp_customer_exception'); $subject = config('app.name') . '于' . date('d日H:i:s') . '抛出异常'; $content = $exception->getMessage() . "\r\n\r\n" . $exception->getTraceAsString(); EmailQueue::rPush($subject, nl2br($content), ['song.shen@kuxuan-inc.com'], config('app.name')); } } self::checkoutResponse($corpid, $userList, $count); Log::logInfo('获取客户列表结果记录', [ 'corpid' => $corpid, 'user_list' => $userList, 'count' => $count ], 'get_corp_customer_list'); } // 根据内部员工获取外部联系客户具体方法 public static function getCustomerListMethod($params, $accessToken, $corpid, $retry = 0) { $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user?access_token='.$accessToken; $result = HttpService::httpPost($url, json_encode($params), true); $result = mb_convert_encoding($result, "UTF-8"); $result = json_decode($result, 1); if((empty($result) || (isset($result['errcode']) && in_array($result['errcode'], [-1]))) && $retry < 5) { sleep(2); $retry++; return self::getCustomerListMethod($params, $accessToken, $corpid, $retry); } if(isset($result['errcode']) && in_array($result['errcode'], [0, 701008, 60111, 610023])) { return $result; } else { // 请求失败,将响应数据写入日志 Log::logError('获取内部员工对应的外部联系人列表失败:URL'.$url.', 请求参数:'.json_encode(array_merge($params, ['corpid' => $corpid])), (array)$result, 'get_user_customer_list'); EmailQueue::rPush('获取内部员工对应的外部联系人列表失败', json_encode([ 'url' => $url, 'params' => array_merge($params, ['corpid' => $corpid]), 'result' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return false; } } public static function checkoutResponse($corpid, $userList, $count) { # 当同步单个客服时,对比同步下来的客户数与客户总数,查看是否完全同步 if(count($userList) == 1) { $response = QyCommon::getExternalContactList($corpid, current($userList)); if(isset($response['errcode'])) { if(0 == $response['errcode']) { $customerCount = count($response['external_userid']); } else if (in_array($response['errcode'], [701008, 84061])) { $customerCount = 0; } else { $customerCount = 0; EmailQueue::rPush('获取客户列表结果异常', json_encode([ 'corpid' => $corpid, 'user_id' => current($userList), 'response' => $response ]), ['song.shen@kuxuan-inc.com'], '猎羽系统'); } if($customerCount > $count) { EmailQueue::rPush('批量获取客户数据数少于实际客户数', json_encode([ 'corpid' => $corpid, 'user_id' => current($userList), 'real_count' => $customerCount, 'get_count' => $count ]), ['song.shen@kuxuan-inc.com'], '猎羽系统'); } } } } // 内部员工以及外部客户联系等数据保存入库 public static function userCustomerDataSave($data, $corpid) { try{ foreach($data as $item) { // 企业成员客户跟进信息 $followInfo = $item['follow_info']; // 客户基本信息 $externalContact = $item['external_contact']; \DB::beginTransaction(); // 保存客户信息,并返回客户id $customerId = Customer::externalContactDataSave($corpid, $externalContact); // 保存员工客户跟进信息 if($customerId > 0) { // $followInfoId = CustomerRelation::followInfoDataSave($corpid, $followInfo, $customerId, // $externalContact['external_userid']); $followInfoId = CustomerDetails::followInfoDataSave($corpid, $followInfo, $customerId, $externalContact); // 自动打日期标签 // TagService::autoMarkCustomerAddDateTag($corpid, $customerId, $followInfo); if($followInfoId > 0) { // // 如果标签列表不为空,则将标签信息也一并记录下来 // if(isset($followInfo['tag_id']) && !empty($followInfo['tag_id'])) { // $customerRes = CustomerTag::customerTagSave($corpid, $followInfo, $externalContact, // $customerId); // if($customerRes > 0) { // \DB::commit(); // } else { // \DB::rollBack(); // } // } else { \DB::commit(); // } } else { \DB::rollBack(); } } else { \DB::rollBack(); $params = $item; $params['corpid'] = $corpid; // 保存用户信息异常 Log::logError('保存客户信息失败, 参数'.json_encode($params), [], 'external_contract_data_save'); } } } catch (\Exception $exception) { EmailQueue::rPush('保存客户信息失败', $exception->getTraceAsString(), ['xiaohua.hou@kuxuan-inc.com'], '保存客户信息失败'); \DB::rollBack(); // 保存用户信息异常 Log::logError('保存客户信息失败', [ 'exception' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), ], 'external_contract_data_save'); } } // 获取配置了客户联系功能的成员列表 public static function followUserList($corpid, $accessToken = null) { if(empty($corpid)) { return []; } if(empty($accessToken)) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '获取配置了客户联系功能的成员列表'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token='.$accessToken; $result = HttpService::httpGet($url); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { return [$result['follow_user'], 0]; } else { $errcode = $result['errcode'] ?? null; // 请求失败,将响应数据写入日志 Log::logError('获取配置了客户联系功能的成员列表失败,url:'.$url, (array)$result, 'follow_user_list'); EmailQueue::rPush('获取配置了客户联系功能的成员列表失败', json_encode([ 'corpid' => $corpid, 'result' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return [[], $errcode]; } } // 获取企业标签 public static function getCorTagList($corpid, Array $tagId = [], Array $groupId = [], $accessToken = null) { if(empty($corpid) && empty($accessToken)) { return []; } if(empty($accessToken)) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '获取企业标签'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list?access_token='.$accessToken; $params = []; if(!empty($tagId)) { $params['tag_id'] = $tagId; } if(!empty($groupId)) { $params['group_id'] = $groupId; } $result = HttpService::httpPost($url, json_encode($params), true); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { return $result['tag_group']; } else { // 请求失败,将响应数据写入日志 Log::logError('获取企业下所有标签失败,url:'.$url, (array)$result, 'get_cor_tag_list'); EmailQueue::rPush('获取企业下标签失败', json_encode([ 'corpid' => $corpid, 'url' => $url, 'request' => (array)$result ]), ['song.shen@kuxuan-inc.com'], '猎羽'); return []; } } // 获取所有企业规则组标签 public static function getStrategyTagList($corpid, $strategyId = null, Array $tagId = [], Array $groupId = [], $accessToken = null) { if(empty($corpid) && empty($accessToken)) { return []; } if(empty($accessToken)) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '获取所有企业规则组标签'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_strategy_tag_list?access_token='.$accessToken; $params = []; if(!empty($strategyId)) { $params['strategy_id'] = $strategyId; } if(!empty($tagId)) { $params['tag_id'] = $tagId; } if(!empty($groupId)) { $params['group_id'] = $groupId; } $result = HttpService::httpPost($url, json_encode($params), true); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { return $result['tag_group']; } else { // 请求失败,将响应数据写入日志 Log::logError('获取企业下所有规则组标签失败,URL:'.$url.',参数:'.json_encode($params), (array)$result, 'get_strategy_tag_list'); return []; } } // 标签信息保存入库 public static function tagDataSave($corpid, $type, $data) { if(empty($corpid) || empty($data)) { return false; } try{ // 添加编辑标签 if(isset($data['group_id'])) { $groupRes = TagGroup::dataSave($corpid, $type, $data); if(!empty($data['tag'])) { foreach($data['tag'] as $tag) { $tagRes = Tag::dataSave($corpid, $data['group_id'], $tag); if(0 == $tagRes) { return false; } } } if(0 == $groupRes) { return false; } } else { // 获取企业下所有标签 foreach($data as $group) { $groupRes = TagGroup::dataSave($corpid, $type, $group); if(!empty($group['tag'])) { foreach($group['tag'] as $tag) { $tagRes = Tag::dataSave($corpid, $group['group_id'], $tag); if(0 == $tagRes) { return false; } } } if(0 == $groupRes) { return false; } } } } catch (\Exception $exception) { Log::logError('标签信息保存入库失败', [ 'exception' => $exception->getMessage(), 'line' => $exception->getLine(), 'file' => $exception->getFile() ], 'tag_data_save'); } return true; } /** * 根据客户跟进关系表中标签信息 * @param $corpid -企业id * @param $type -标签类型 1企业标签 2用户自定义标签 3规则组标签 * @param $data -标签数据 * @return bool */ public static function updateCustomerTag($corpid, $type, $data) { if(empty($corpid) || empty($data)) { return false; } \DB::begintransaction(); foreach($data as $group) { $item['group_name'] = $group['group_name']; $item['type'] = $type; if(!empty($group['tag'])) { foreach($group['tag'] as $tag) { $item['tag_name'] = $tag['name']; $res = CustomerTag::updateCustomerTag($corpid, $tag['id'], $item); if($res == 0) { \DB::rollBack(); return false; } } } } \DB::commit(); return true; } /* * 创建企业标签 * $corpid 企业id 获取access_token用 * $groupId 标签组id 可为空 * $groupName 标签组名称,最长为30个字符 可为空,$groupId和$groupName不能同时为空 * $order 标签组次序值,order值大的排序靠前。有效的值范围是[0, 2^32) 可为空 * $tag 标签数组 * $name 标签名称,最长30个字符,必传 * $order 标签次序值 可为空 */ public static function addCorpTag($corpid, $groupId, $groupName, $order, $tag, $accessToken = null) { if(empty($corpid) || empty($tag) || (empty($groupName) && empty($groupId))) { return false; } if(empty($accessToken)) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '创建企业标签'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_corp_tag?access_token='.$accessToken; $params['tag'] = $tag; if(!empty($groupId)) { $params['group_id'] = $groupId; } if(!empty($groupName)) { $params['group_name'] = $groupName; } if(!empty($order)) { $params['order'] = $order; } $result = HttpService::httpPost($url, json_encode($params), true); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { // 将数据保存入库 $res = self::tagDataSave($corpid, 1, $result['tag_group']); if($res) { return true; } else { return false; } } else { Log::logError('新增企业标签失败, URL:'.$url.', 请求参数:'.json_encode($params), (array)$result, 'add_corp_tag'); return false; } } /* * 编辑客户企业标签 * @param $corpid string 企业id * @param $userId string 添加外部联系人的userid 必传 * @param $externalUserId string 外部联系人userid 必传 * @param $addTag array 要标记的标签id列表 可为空 * @param $removeTag array 要移除的标签id列表 可为空 add_tag和remove_tag不可同时为空。 * @param null $accessToken * @return bool */ public static function markTag($corpid, $userId, $externalUserId, $addTag, $removeTag, $accessToken = null, $retry = 0) { if((empty($corpid) && empty($accessToken)) || empty($userId) || empty($externalUserId)) { return false; } if(empty($accessToken)) { $accessToken = AuthorizeCorp::getAccessToken($corpid, '编辑客户企业标签'); } $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag?access_token='.$accessToken; $params['userid'] = $userId; $params['external_userid'] = $externalUserId; if(!empty($addTag)) { $params['add_tag'] = $addTag; } if(!empty($removeTag)) { $params['remove_tag'] = $removeTag; } $result = HttpService::httpPost($url, json_encode($params), true); $result = json_decode($result, 1); Log::logInfo('客户打标签接口', [ 'corpid' => $corpid, 'params' => $params, 'response' => $result ], 'markTag'); $returnFlag = false; if(isset($result['errcode']) && $result['errcode'] == 0) { //编辑成功了,还需要处理本地的数据 TagService::updateLocalCustomerTagSecond($corpid, $userId, $externalUserId, $addTag, $removeTag); $returnFlag = true; } else { // 员工不在企微 跳过不处理 if('60111' == $result['errcode']) { $returnFlag = true; } // 不存在的客户联系关系 跳过不处理 if('84061' == $result['errcode']) { RedisModel::lPush(CustomerDetails::CUSTOMER_LOSS_INFO_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserId ], 256)); $returnFlag = true; } if(in_array($result['errcode'], [45033, 45035, -1])) { if($retry < 5){ $retry++; $seconds = rand(1,5); sleep($seconds); return self::markTag($corpid, $userId, $externalUserId, $addTag, $removeTag, null, $retry); } } EmailQueue::rPush('【'.$corpid.'】客户打标签失败', json_encode([ 'url' => $url, 'params' => $params, 'result' => $result ], 256), ['song.shen@kuxuan-inc.com'], '猎羽系统'); } return $returnFlag; } public static function convertUseridToOpenid($corpid, $userId) { if(empty($corpid) || empty($userId)) { return false; } $accessToken = AuthorizeCorp::getAccessToken($corpid, 'UserId转换OpenId'); $url = 'https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid?access_token='.$accessToken; $params['userid'] = $userId; $result = HttpService::httpPost($url, json_encode($params), true); $result = json_decode($result, 1); if(isset($result['errcode']) && $result['errcode'] == 0) { // 请求成功了 return $result['openid']; } else { return false; } } }