3, 'base_uri' => $baseUrl, 'verify' => false, 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' ] ]); if($type == 'get'){ $request = $client->requestAsync($type, $url, [ 'query' => $options ]); }else{ $request = $client->postAsync($url, [ 'form_params' => $options ]); } $promise = $request->then(function (ResponseInterface $request) use ($url, $options) { $contents = $request->getBody()->getContents(); debug_log(['ResponseInterface', $contents, $url, $options], __CLASS__ . '.log'); return json_decode($contents, true); }, function (\Exception $exception) use ($url, $options) { if($exception instanceof RequestException){ $contents = $exception->getResponse()->getBody()->getContents(); debug_log(['RequestException', $contents, $url, $options], __CLASS__ . '.log'); return json_decode($contents, true); }else{ debug_log(['RequestException', 'ExceptionErr', $exception->getMessage()], __CLASS__ . '.log'); \Yii::error([__METHOD__, __LINE__, $exception]); } }); return $promise->wait(); } public static function api($store_id = 0, $_a = '', $params = [], $action = '/cyy/auth/index', $type = 'post') { $config = self::conf($store_id); $baseUrl = $config['mochatUrl']; if($config['refresh_time'] < time()){ $response = self::sendRequest('post', $baseUrl, $baseUrl . '/open-api/access_token/get', [ 'corp_id' => $config['corp_id'], 'token' => $config['token'], ]); if(isset($response['code'])){ if($response['code'] != 200){ debug_log(['code!=200', 'access_token/get', $response, $store_id, $type], __CLASS__ . '.log'); }else{ $access_token = $response['data']['access_token']; $expires_in = $response['data']['expires_in']; self::setAccessToken($store_id, $access_token, $expires_in); $config['access_token'] = $access_token; } }else{ return $response; } } $params['access_token'] || $params['access_token'] = $config['access_token']; $params['_a'] || $params['_a'] = $_a; $response = self::sendRequest($type, $baseUrl, $baseUrl . $action, $params); if(isset($response['code'])){ if($response['code'] != 200){ debug_log(['code!=200', $response, $store_id, $type, $action, $params], __CLASS__ . '.log'); }else{ $response['code'] = 0; } } return $response; } public static function conf($store_id = 0, $refresh = 0) { if(isset(self::$confs[$store_id]) && !$refresh){ return self::$confs[$store_id]; } $conf = Option::get(OptionSetting::MOCHAT_API, $store_id, 'store')['value']; if($conf){ $conf = json_decode($conf, true); }else{ $conf = [ 'mochatUrl' => '', ]; } self::$confs[$store_id] = $conf; return $conf; } public static function saveConf($store_id = 0, $config = []) { $config['refresh_time'] = $config['refresh_time'] < time() ? time() : $config['refresh_time']; $set = Option::set(OptionSetting::MOCHAT_API, json_encode($config), $store_id, 'store'); self::conf($store_id, 1); return $set; } public static function getConf($store_id = 0, $key = '') { $config = self::conf($store_id); return $config[$key]; } public static function setConf($store_id = 0, $key = '', $val = '') { $config = self::conf($store_id); if(is_string($key)){ $key = [$key]; $val = [$val]; } foreach($key as $i => $item){ $config[$item] = $val[$i]; } return self::saveConf($store_id, $config); } public static function setConfCorpId($store_id = 0, $corp_id = '') { return self::setConf($store_id, 'corp_id', $corp_id); } public static function setAccessToken($store_id = 0, $access_token = '', $expires_in = '') { $refresh_time = time() + $expires_in; return self::setConf($store_id, ['access_token', 'refresh_time'], [$access_token, $refresh_time]); } public static function isopen($store_id = 0) { $isopen = self::getConf($store_id, 'isopen'); return empty($isopen) ? 0 : 1; } public static function getUserByStoreSaasuser($store_id = 0, $saas_user = []) { $user = User::find()->where([ 'store_id' => $store_id, 'binding' => $saas_user['mobile'], 'is_delete' => 0, ])->one(); return $user; } public static function userToExternalUserid($store_id = 0, $user_id = 0) { if(empty($user_id)){ return [ 'code' => 1, 'msg' => '用户不存在', ]; } $user = User::findOne($user_id); $saasUser = SaasUser::findOne(['mobile' => $user['binding']]); $phone = $saasUser ? $saasUser->mobile : ''; $openid = $user ? $user->wechat_open_id : ''; $unionid = $user ? $user->wechat_union_id : ''; $contact = self::contactUnionidToExternalUserid($store_id, $phone, $openid, $unionid); return $contact; } public static function userInRoom($store_id = 317, $roomId = '', $user_id = '') { $contact = self::userToExternalUserid($store_id, $user_id); if($contact['code'] != 0){ debug_log([__METHOD__, $contact], __CLASS__ . '.log'); return false; } $wxExternalUserid = $contact['data']['wx_external_userid']; $roomMem = self::workRoomMembers($store_id, $roomId, 2); if($roomMem['code'] != 0){ debug_log([__METHOD__, $roomMem], __CLASS__ . '.log'); return false; } debug_log([__METHOD__, $wxExternalUserid, $roomMem['data']], __CLASS__ . '.log'); // var_dump($roomMem['data'], $wxExternalUserid);die; foreach($roomMem['data'] as $item){ if($item['wxExternalUserid'] == $wxExternalUserid){ // var_dump($item);die; return true; } } return false; // return self::workInRoom($store_id, $roomId, $wxExternalUserid); } public static function sendMsg($queue = true, $store_id = 84, $type = 1, $saas_user_id = 0, $extData = []) { try{ if(!self::isopen($store_id)){ return; // throw new \Exception('未开启scrm功能' . $store_id); } if(!$saas_user_id){ return; // throw new \Exception('$saas_user_id = 0' . $store_id); } // $queue = time(); if($queue === 1 || $queue === true){ $cacheK = func_get_args(); $cacheV = cache()->get($cacheK); if($cacheV){ debug_log([__FUNCTION__, '$cacheV', $cacheV], __CLASS__ . '.log'); return; } cache()->set($cacheK, 1, 60); $queue = queue_push(new \app\jobs\mochat\SendMsgJob([ 'queue_time' => time(), 'store_id' => $store_id, 'type' => $type, 'saas_user_id' => $saas_user_id, 'extData' => $extData, ])); debug_log(['sendMsg $queue', $queue], __CLASS__ . '.log'); return $queue; } $queue_time = $queue; debug_log(['sendMsg', func_get_args()], __CLASS__ . '.log'); $msgType = [ self::MSG_TYPE_CLICK_STORE => '点击商城', self::MSG_TYPE_VIEW_GOODS => '浏览商品', self::MSG_TYPE_SUBMIT_ORDER => '下单商品', self::MSG_TYPE_PAY_ORDER => '购买商品', self::MSG_TYPE_VIEW_COUPON => '查看优惠券', self::MSG_TYPE_GET_COUPON => '领取优惠券', ]; if(!isset($msgType[$type])){ throw new \Exception('$type参数错误' . $type); } $saasUser = SaasUser::findOne($saas_user_id); $extData['goods_id'] && $goods = Goods::findOne($extData['goods_id']); $extData['coupon_id'] && $coupon = Coupon::findOne($extData['coupon_id']); $title = '用户' . $msgType[$type] . '提醒'; $desc1 = [ '客户名称:' . ($saasUser ? $saasUser->name : ''), $goods ? ('商品名称:' . $goods->name) : '', $coupon ? ('优惠券名称:' . $coupon->name) : '', '查看时间:' . date('Y-m-d H:i:s', $queue_time), ]; $desc = '
' . implode('
', $desc1) . '
'; $user = self::getUserByStoreSaasuser($store_id, $saasUser); $phone = $saasUser ? $saasUser->mobile : ''; $openid = $user ? $user->wechat_open_id : ''; $unionid = $user ? $user->wechat_union_id : ''; $contact = self::contactUnionidToExternalUserid($store_id, $phone, $openid, $unionid); if($contact['code'] != 0){ debug_log(['sendMsg contactUnionidToExternalUserid err', func_get_args(), $contact], __CLASS__ . '.log'); // return $contact; } $wxExternalUserid = $contact['data']['wx_external_userid']; $sendMsg_wxUserId = self::getConf($store_id, 'sendMsg_wxUserId'); $content = $title . "\n" . $desc . "\n"; if(empty($wxExternalUserid)){ $content = "【新客户提醒】\n" . "客户手机:" . $phone . "\n" . "————————\n" . $content; }else{ $contactId = $contact['data']['contactId']; $agentId = self::getConf($store_id, 'agentId'); $urlSidebar = self::getConf($store_id, 'mochatUrl_sidebar'); $link = $urlSidebar . '/contact?agentId=' . $agentId . '&contactId=' . $contactId; $content .= "————————\n" . '查看>>'; self::contactAddFollow($store_id, $wxExternalUserid, implode(' ', $desc1), $title); } $res = self::employeeSendMsg($store_id, $content, $sendMsg_wxUserId); return $res; } catch (\Exception $ex) { \Yii::error($ex); return [ 'code' => 1, 'msg' => $ex->getMessage(), ]; } } public static function orderList($store_id, $wxExternalUserid = '', $roomId = '') { if($roomId){ $cond = self::getRoomPhone($store_id, $roomId); } if($wxExternalUserid){ $cond = self::getContactPhone($store_id, $wxExternalUserid); } if(empty($cond['mobiles']) && empty($cond['openids']) && empty($cond['unionids'])){ return [ 'code' => 1, 'msg' => '暂无数据', ]; } $form = new OrderListForm(); $form->setAttributes(all_params(), 0); $form->setAttributes($cond, 0); $form->store_id = $store_id; return $form->search(); } public static function searchCond($details) { $res = [ 'mobiles' => [], 'openids' => [], 'unionids' => [], ]; foreach($details as $detail){ if(!empty($detail['phone'])){ $res['mobiles'][] = $detail['phone']; } if(!empty($detail['openid'])){ $res['openids'][] = $detail['openid']; } if(!empty($detail['unionid'])){ $res['unionids'][] = $detail['unionid']; } } return $res; } public static function getContactPhone($store_id = 317, $wxExternalUserids = []) { if(is_string($wxExternalUserids)){ $wxExternalUserids = [$wxExternalUserids]; } $list = []; foreach($wxExternalUserids as $wxExternalUserid){ $detail = self::contactDetail($store_id, $wxExternalUserid); $list[] = $detail['data']; } return self::searchCond($list); } public static function getRoomPhone($store_id = 317, $roomId = '') { $res = self::workRoomMembers($store_id, $roomId); $list = []; if($res['data']){ foreach($res['data'] as $item){ $list[] = $item['wxExternalUserid']; } } return self::getContactPhone($store_id, $list); } public static function employeeList($store_id = 317, $name = null, $page = 1, $pageSize = 30) { $params = [ 'page' => $page, 'pageSize' => $pageSize, ]; $name && $params['name'] = $name; $res = self::api($store_id, '', $params, '/open-api/employee/list', 'get'); return $res; } public static function contactList($store_id = 317) { $res = self::api($store_id, '', [], '/open-api/contact/list', 'get'); var_dump($res);die; } public static function contactDetail($store_id = 317, $wxExternalUserid = '') { $res = self::api($store_id, '', [ 'wxExternalUserid' => $wxExternalUserid, ], '/open-api/contact/detail', 'get'); return $res; } public static function workRoomMembers($store_id = 317, $roomId = '', $status = 1, $type = 2) { $res = self::api($store_id, '', [ 'roomId' => $roomId, 'status' => $status, 'type' => $type, ], '/open-api/workRoom/members', 'get'); return $res; } public static function workRoomList($store_id = 317, $options = []) { $res = self::api($store_id, '', [ 'page' => $options['page'] ?? 1, 'perPage' => $options['perPage'] ?? 30, ], '/open-api/workRoom/index', 'get'); return $res; } public static function workInRoom($store_id = 317, $roomId = '', $wxExternalUserid = '') { $res = self::api($store_id, '', [ 'wxExternalUserid' => $wxExternalUserid, 'roomId' => $roomId, ], '/open-api/contact/room', 'post'); // var_dump($roomId, $wxExternalUserid, $res);die; if($res['code'] == 0){ if($res['data'] && $res['data']['page']){ return $res['data']['page']['total'] ? true : false; } } return false; } public static function contactUnionidToExternalUserid($store_id = 317, $phone = '', $openid = '', $unionid = '') { $res = self::api($store_id, '', [ 'unionid' => $unionid, 'openid' => $openid, 'phone' => $phone, ], '/open-api/contact/unionidToExternalUserid', 'get'); return $res; } public static function contactAddFollow($store_id = 317, $wxExternalUserid = '', $content = '', $eventName = '') { $res = self::api($store_id, '', [ 'wxExternalUserid' => $wxExternalUserid, 'content' => $content, 'eventName' => $eventName, ], '/open-api/contact/addFollow'); return $res; } public static function employeeSendMsg($store_id = 317, $content = '', $wxUserId = '', $msgType = 'text') { $params = [ 'msgType' => $msgType, 'content' => $content, ]; $wxUserId && $params['wxUserId'] = $wxUserId; $res = self::api($store_id, '', $params, '/open-api/employee/sendMsg'); return $res; } }