Русский
Русский
English
Статистика
Реклама

Amocrm

Обзор разработки дополнений для amoCRM, с использованием webHook и виджетов

09.03.2021 18:08:33 | Автор: admin

Содержание

  1. WebHook

  2. Виджет

  3. Техническая поддержка

  4. Итог

Мы не использовали все возможности разработки под amoCRM, ограничились приватным виджетом и webHook, поэтому ниже речь пойдет именно об этом

WebHook

К каждому аккаунту(на пробном только в течении 14 дней)можно установитьwebHook,документация подробно описывает процесс. Разработка каких-либо интеграций при этом не нужна.

В нашем случае было достаточно информации одобавлении сделки.

На сервере по указанному url в файле(в данном случаеindex.php)первым делом необходимо сырые POST данные преобразовать из json в массив php:

//если в сырых POST данных первый символ { значит это jsonif(strlen($sRawPost) > 0 && $sRawPost[0] == "{"){    $sDecode = json_decode($sRawPost, true);    if($sDecode !== null)         $_POST = $sDecode;}

ВgetпараметрыwebHookпри создании новой сделки ничего не приходит, а вpostпримерно следующее:

{    "leads": {        "add": [            {                "id": 4564454,                "name": "Название товара",                "status_id": 7534534,                "price" => 0,                "responsible_user_id": 453453453,                "last_modified": 1612007407,                "modified_user_id": 0,                "created_user_id": 0,                "date_create": 1612007407,                "pipeline_id": 4546445,                "tags": [                    {                        "id": 7899                        "name": tilda                    }                ]            }        ],        "account_id": 19277260        "custom_fields": [            {                "id": 448797,                "name": "name_field",                "code": "code_field",                "values": [                    {                        "value": "string"                    }                ]            }        ],        "created_at": 1612007407,        "updated_at": 1612007407    },    "account": [        {            "subdomain": "subdomain",            "id": 19217260,            "_links": [                "self": "https://subdomain.amocrm.ru"            ]        }    ]}

Очевидно чтоидентифицировать аккаунтиз которого была отправка запроса можно по ключуaccount, аleads["add"][0]["account_id"] == account["id"].

Вleads["add"][0]["tags"]находятсяспециальные метки, которые можно присвоить сделке, и по которым на стороне принимающего сервера можно как-то идентифицировать, в нашем случае нужен был тег со значениемtilda.

Но больший интерес представляетleads["add"][0]["custom_fields"]- этомассив произвольных полей сделки.

Изначально у сделки небольшой список полей и есть только "Основная" группа полей, в которую можнодобавить новые поля, а можнодобавить новую группу и в нее добавить новые поля- есть категоризация полей на стороне веб-интерфейса.

Для редактирования полей сделки нужно зайти в любую сделку или в интерфейс создания новой сделки, затем перейти во вкладку "Настроить".

Редактирование полей сделкиРедактирование полей сделки

Новое поле сделки может быть скрыто из веб-интерфейса для редактирования и может быть доступно только на стороне API.

Для работы с полями сделки на стороне сервера принимающего запрос можно так:

$aAdd = $_POST['leads']['add'][0]; //извлекаем имена полей$aNameCustomFields = array_column($aAdd['custom_fields'], 'name'); //здесь пишем проверку наличия нужных полей //получаем значение поля$idOrder = $aAdd['custom_fields'][array_search('ORDERID', $aNameCustomFields)]['values'][0]['value'];
Добавление нового поля сделкиДобавление нового поля сделки

А дальше все зависит от целей использования webHook :)

Изначально мы делали эту интеграцию для клиента на Tilda, так как у клиента было настроено получение заявок из Tilda в amoCRM. Нам необходимо было отслеживать факт поступления оплаты, однако в amoCRM не поступают такие данные ифакт оплаты не удалось выявить, даже в самом интерфейсе CRM

Виджет

Документация по разработке виджетовдостаточно подробная, и содержит все необходимые данные для работы. Даже есть пример виджетаздесь.

Для начала разработки виджета необходимозарегистрировать приложение, все просто.

Затем необходимо создатьструктуру виджетасостоящую из директорий и файлов.

Код виджета пишется наjavascript, шаблоны виджета наtwig, в js доступенjquery, есть возможность использованияcss

В директории виджета необходимо наличие файлаmanifest.json- файла конфигурации виджета,в документации есть подробное описание, аздесьописаны типы полей. Не забываем олокализацииi18n.

Стоит учесть что виджет подключается только к темобластям сайта, которые будут указаны вmanifest.json

В документации есть разделWEB SDKкоторый также посвящен созданию виджетов.

Не вижу смысла описывать процесс написания виджета, а также его возможности, так какдокументация исчерпывающая:)

Если виджет используетajax запросы со стороннего сервера(например как было у нас, виджет обращался к нашему серверу), то сервер должен отправлять заголовокAccess-Control-Allow-Origin: *:

header("Access-Control-Allow-Origin: *");

Разработка виджета осуществляется локально, на машине разработчика, тестирование виджета возможно только череззагрузку архива виджетана странице созданной интеграции.

Это не очень удобно, к тому же вmanifest.jsonкаждый разпри загрузке виджета нужно менять версиюwidget.version, иначе обновление виджета произойдет не сразу.

Техническая поддержка

Через чат amoCRM на всех страницах сайта CRM можно быстро получить ответы на многие вопросы. CRM платная для использования, но предоставляется бесплатный доступ на 14 дней. Однако,мы не собирались пользоваться самой CRM, а лишьпредоставлять нашу интеграцию. Возможность разработки виджета возможна только в течении 14 дней. После истечения периода, нам понадобилось продлить пробный период, обратившись в онлайн чат мы получили дополнительные 10 дней. Однако, позже через онлайн-чат удалось выяснить чтодля разработчиков публичных интеграций естьспециальный бесплатныйтехнический аккаунт. Также во время разработки нам потребовалось узнатьip адреса серверов amoCRM, с которых они присылают webHook на наш сервер, тех. поддержка через онлайн чат любезно их предоставила.На момент написания статьи, ip адреса серверов amoCRM не находятся в публичном доступе, узнать информацию о них можно через онлайн-чат на сайте.

Итог

В целом мне понравилось разработка для amoCRM, понятная и объемная документация с примерами, однако загрузка виджета доставляет определенные неудобства.

Подробнее..

Заметки по API Aliexpress. Экспорт заказов в Bitrix24, RetailCRM, amoCRM

20.04.2021 14:21:11 | Автор: admin

Хочу поделиться опытом автоматизации экспорта заказов из Aliexpress в несколько. Приведенные примеры написаны на PHP, но библиотеки для работы с Aliexpress есть и для других языков. Структура запросов и ответов аналогична. Если перед вами стоит задача интеграции Aliexpress, надеюсь, эта статья будет вам полезна.

Итак, предположим, что у вас уже есть магазин на Aliexpress. И вы выбрали пункт меню Разработчикам. На момент публикации наблюдались сбои в локализации консоли разработчика, возможно, они будут исправлены в будущем, но если в консоли не отображаются уже созданные приложения или вход в консоль из кабинета продавца не срабатывает, есть пара советов:

  1. Заходите по ссылке https://seller.aliexpress.ru/login?return_url=https%3A%2F%2Fseller.aliexpress.ru Это исправит глюк с редирекстом на китайскую версию консоли, в которой создать приложение не возможно

  2. Перед входом, разлогиньтесь из под покупателя. Хотя вход будет произведен отдельно, консоль каким-то образом, может оказаться пустой. Т.е. вы войдете не под тем логином, под которым ожидали. Тот же глюк может быть позже, когда доступ для приложения может быть запрещён с ошибкой main account not auth subAccount

В консоли можно скачать SDK для разных языков и создать приложение. В результате у вас в распоряжении окажутся два из 3-х нужных для работы значения - App Key и App Secret. С третьим значением access_token все немного сложнее. Тут необходимо небольшое пояснение. В терминах консоли значения называются App Key, App Secret и access_token, а в терминах SDK, по крайней мере PHP-версии, эти же pачения называются appkey, secretKey и sessionKey. Ключ сессии, он же access_token можно получить двумя способами:

  1. Применив редирект обратно на свой сервер. Т.е. вы пишите приложение для менеджера, который по мере необходимости импортирует заказы из Aliexpress в CRM. Каждый раз он будет переходить из приложения на сайт Aliexpress, нажимать кнопку предоставления полномочий и возвращаться в приложение. При возврате буте получен параметр code, который с помощью curl вызова на https://oauth.aliexpress.com/token можно будет обменять на access_token

  2. Парсинг страницы после перехода по ссылке https://oauth.aliexpress.com/authorize. Ну или однократный вызов с ручным копированием access_token

Оба метода подробно описаны в документации. Там же упомянуто, что срок жизни access_token 1 год. Но не тут то было. Приложение созданное в консоли остается в стадии testing. А для нее срок жизни - 1 сутки. Чтобы опубликовать приложение, нужно отсканировать паспорт через приложение AliPay (российский загранпаспорт подошел). Но и это вам не поможет, т.к. следующий шаг введение номера кредитной карты и телефона, которые, видимо, должны быть выданы в Китае, т.к. ни то ни другое ввести не удается. Обращение в техподдержу Aliexpress в марте 2020 год осталось без ответа.

Надеюсь в будущем локализация будет доведена до конца и публикация для россиян станет доступна. Таким образом для дальнейшей работы подходит первый способ с нажатием кнопки каждый раз при импорте заказов, но передо мной была поставлена задача - сделать автоматический импорт без участия менеджера.

Я упомяну парсинг с помощью Selenium в конце стать, т.к. проблема с жизнью access_token может перед вами не стоять или решиться исправлением международного механизма публикации приложения.

Думаю, стоит начать с импорта справочника товаров Ailexpress в промежуточную таблица, чтоб присвоить им идентификаторы из CRM.

include "TopSdk.php";date_default_timezone_set('Asia/Shanghai'); $c = new TopClient;$c->appkey = 'xxxxxxxxxxx';$c->secretKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';$sessionKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';$i = 1;$req = new AliexpressSolutionProductListGetRequest;$aeop_a_e_product_list_query = new ItemListQuery;$aeop_a_e_product_list_query->current_page=$i;$aeop_a_e_product_list_query->product_status_type="onSelling";$req->setAeopAEProductListQuery(json_encode($aeop_a_e_product_list_query));$rez = $c->execute($req, $sessionKey);var_dump($rez);

Получаем в $rez список товаров. Обратите внимание на счетчик $i. При первом запросе он будет равен 1, затем его нужно увеличивать, пока он не достигнет $rez->result->total_page и получать следующие страницы с товарами. Предлагаю вам ознакомиться с выводом скрипта. Первое что бросается в глаза машинный перевод названий товаров на английский язык. Это можно исправить на следующем шаге. Или сориентироваться по ссылкам на фотографию. А если товаров не много и перевод однозначный, то английские названия вас тоже могут устроить. Выведем эти названия и id (если ответ на запрос разбивается на несколько страниц, роцедуру нужно повторить для каждой из них)

foreach($rez->result->aeop_a_e_product_display_d_t_o_list->item_display_dto as $item){      echo $item->product_id."\t".$category->subject."\n";}

Если по каждой позиции предусмотрен выбор вариантов (размер, комплектация и т.д.), то нужно для каждого id вызвать метод, возвращающий эти варианты. Этим же методом можно получить оригинальное название товара на русском языке.

$req = new AliexpressSolutionProductInfoGetRequest;$req->setProductId($id);$rez = $c->execute($req, $sessionKey);var_dump ($rez);

В выводе содержится, много полезной информации, мы возьмём только идентификатоы и строки характеристик.

foreach($rez->result->aeop_ae_product_s_k_us->global_aeop_ae_product_sku as $sku){      echo $sku ->id."\t".$sku ->sku_code."\n";}

На этом этапе я столкнулся небольшой проблемой. Надписи в категориях товаров, которые видит покупатель, не возвращаются через API и доступны только через личный кабинет. Я имею ввиду, надписи, которые появляются при наведении на картинку с подвидом товара или надписи, которые сами определяют подвид.

На скриншоте пример с обувью. В карточке товара покупатель видит размер, а в заказ падает часть строки характеристик, по этой части можно понять какой именно Product code выбран. Обычно это штрих код товара. Я предполагаю, что те, кто заводят товар в личном кабинете продавца, ведут учет подкатегорий товара и их соответствие Product code. Я сделал первую сверку товаров и написал несколько простых страничек для пополнения и редактирования таблицы. Осталось получить список заказов и загрузить их в CRM.

$req = new AliexpressSolutionOrderGetRequest;$param0 = new OrderQuery;$param0->create_date_end="2221-12-31 12:12:12";$param0->create_date_start="2021-03-30 12:12:12";$param0->order_status_list = array("PLACE_ORDER_SUCCESS","IN_CANCEL","WAIT_SELLER_SEND_GOODS","SELLER_PART_SEND_GOODS","WAIT_BUYER_ACCEPT_GOODS","FUND_PROCESSING","IN_ISSUE","IN_FROZEN","WAIT_SELLER_EXAMINE_MONEY","RISK_CONTROL", "FINISH");$param0->current_page=$i;$req->setParam0(json_encode($param0));$rez = $c->execute($req, $sessionKey);

Ответ, так же как и в случаях со справочником товаров, разбивается на страницы. Обратите внимание на order_status_list. Он описан документации, которую я упоминал. Насколько я понял, список в моем коде является полным, что может пригодиться, если вы захотите экспортировать заказы во всех статусах.

Информацию по каждому новому заказу нужно получать отдельно. Строки идентифицирующие покупателей как RU shopper и т.п., довольно бесполезны, поэтому полное имя лучше брать из блока доставки. Примерно половина покупателей пишет свои контакты транслитом и не полностью, однако в нашем распоряжении есть номер телефона. По нему можно найти покупателя в накопленной, до начала работы с Aliexpress, базе и привязать соответствующий заказ.

При следующем получении списка заказов, можно проверить оплату неоплаченных заказов. В таблице загруженных ранее заказов таких записей может быть много, но Aliexpress заказы которые долго были не оплачены, через какое-то время перестает отображать в консоли в статусе ожидает оплаты. Думаю это связано с фиксацией цены. Менеджер, работающий около года с Aliexpress, сказал что стоит проверять заказы, которым не более 20 дней.

$req = new AliexpressSolutionOrderInfoGetRequest;$param1 = new OrderDetailQuery;$param1->ext_info_bit_flag="11111";$param1->order_id=$order;$req->setParam1(json_encode($param1));$rez = $c->execute($req, $sessionKey);$n = str_replace("'","''",$rez->result->data->receipt_address->contact_person); // мягкий знак в ФИО$p = $rez->result->data->receipt_address->phone_country . $rez->result->data->receipt_address->mobile_no;//$p = normalize_phone($p) // здесь могут быть варианты с лишней восьмёркой и т.д.$zi = $rez->result->data->receipt_address->zip;$gor = $rez->result->data->receipt_address->city;$pro = $rez->result->data->receipt_address->province;$adr = $rez->result->data->receipt_address->detail_address;if(isset ($rez->result->data->receipt_address->address2)) $adr .=$rez->result->data->receipt_address->address2;foreach($rez->result->data->child_order_ext_info_list->global_aeop_tp_order_product_info_dto as $item){    $pid = $item->product_id;    $j=json_decode($item->sku);    $s = "";    if(isset ($j->sku[0])) {        $s = $j->sku[0]->pValueId;    }    $cn =$category->quantity;    $pr =$item->unit_price->amount ;    echo $pid."\t". $s." \t " .$cn ." \t ".$pr."\n";}

Этот запрос возвращает данные и о скидке, если вы проводите в вашем магазине на Aliexpress промоакцию.

В заключении, хочу привести еще несколько фрагментов кода. По одному для каждой CRM с которыми мне доводилось работать. Я делаю это, чтобы вся информация по интеграции была в одном месте. Детальные разборы добавления заказов ищутся проще, чем информация по Aliexpress, но если кому-то нужно будет быстро сделать интеграцию, можно взять эти наработки.

Я взял из их своих проектов и отвязал от интеграций (в том числе Алиэкспресса). Каждый пример создает контакт, затем лид/сделку, привязывает к ней контакт и добавляет один товар. Я с удовольствием помогу вам c интеграцией за небольшую плату, если вы решите начать продажи на Алиэкспресс. Тем более что приближается пора отпусков и дополнительные деньги не помешают ни мне, не вам. Почта для связи tlx {cобака} list.ru. Есть большой опыт по интеграции фулфилментов, телефонии и прочего API c различными CRM и общий навык автоматизации.

amoCRM
$subdomain = "xxxxxxxxx";function amo_call($access_token, $link, $data) {$headers = ['Authorization: Bearer ' . $access_token];$curl = curl_init(); //Сохраняем дескриптор сеанса cURLcurl_setopt($curl,CURLOPT_RETURNTRANSFER, true);curl_setopt($curl,CURLOPT_USERAGENT,'amoCRM-oAuth-client/1.0');curl_setopt($curl,CURLOPT_URL, $link);curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'POST');curl_setopt($curl,CURLOPT_POSTFIELDS,json_encode($data));curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);curl_setopt($curl,CURLOPT_HEADER, false);curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 1);curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 2);$out = curl_exec($curl); //Инициируем запрос к API и сохраняем ответ в переменную$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);curl_close($curl);$code = (int)$code;$errors = [400 => 'Bad request',401 => 'Unauthorized',403 => 'Forbidden',404 => 'Not found',500 => 'Internal server error',502 => 'Bad gateway',503 => 'Service unavailable',];try{if ($code < 200 || $code > 204) {return  -1;}}catch(\Exception $e){return  -1;}$response = json_decode($out, true);return  $response;}/* //Это упрощенный способ получения $access_token. Подробнее о получении, вермени жизни и обновлении, см. документацию $link = 'https://' . $subdomain . '.amocrm.ru/oauth2/access_token'; //Формируем URL для запроса$data = ['client_id' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx','client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx','grant_type' => 'authorization_code','code' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx','redirect_uri' => 'http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,];$curl = curl_init(); //Сохраняем дескриптор сеанса cURLcurl_setopt($curl,CURLOPT_RETURNTRANSFER, true);curl_setopt($curl,CURLOPT_USERAGENT,'amoCRM-oAuth-client/1.0');curl_setopt($curl,CURLOPT_URL, $link);curl_setopt($curl,CURLOPT_HTTPHEADER,['Content-Type:application/json']);curl_setopt($curl,CURLOPT_HEADER, false);curl_setopt($curl,CURLOPT_CUSTOMREQUEST, 'POST');curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 1);curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 2);$out = curl_exec($curl); //Инициируем запрос к API и сохраняем ответ в переменную$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);curl_close($curl);$code = (int)$code;$errors = [400 => 'Bad request',401 => 'Unauthorized',403 => 'Forbidden',404 => 'Not found',500 => 'Internal server error',502 => 'Bad gateway',503 => 'Service unavailable',];try{if ($code < 200 || $code > 204) {throw new Exception(isset($errors[$code]) ? $errors[$code] : 'Undefined error', $code);}}catch(\Exception $e){die("Ошибка: ' . $e->getMessage() . PHP_EOL . 'Код ошибки: ' . $e->getCode());}$response = json_decode($out, true);var_dump($response);$access_token = $response['access_token']; //Access токен$refresh_token = $response['refresh_token']; //Refresh токен$token_type = $response['token_type']; //Тип токена$expires_in = $response['expires_in']; //Через сколько действие токена истекает*/$access_token ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";// создаем контакт. В рабочей версии лучше перед этим поискать контакт по номеру телефона. Методом /api/v4/contacts  с параметром filter[custom_fields_values]//тестовые данные$p ="+79000000000";$n= "Петр Петров";$qnt = 1;$ord = "xxxxxxxxxxxxxxxxx";$link='https://'.$subdomain.'.amocrm.ru/api/v2/contacts';$data = array ('add' =>array (0 =>array ('name' => $n,'custom_fields'=>array(array('id' => '953127','values' => array(array("value"=>$p,"enum"=> "MOB"),),),),) ,) ,  ) ;$response = amo_call($access_token, $link, $data);if ($response==-1) {die("что-то пошло не так при добавлении контакта /n");} else {var_dump($response);$cid = $response["_embedded"]["items"][0]["id"];// создаем сделку с привязкой к найденному или созданному контакту$pipeline_id = '4188580';$lead_status_id = '39384853';$lead_name  ="Заказ из Aliexpress  " . $ord;$link='https://'.$subdomain.'.amocrm.ru/api/v2/leads';$data = array ('add' =>  array (0 =>array ('name' => $lead_name,'status_id' => $lead_status_id, //id статуса'pipeline_id' => $pipeline_id,'contacts_id'=>  array ($cid ),), ),);$response = amo_call($access_token, $link, $data);if ($response==-1) {die("что-то пошло не так при добавлении сделки /n");} else {$did = $response["_embedded"]["items"][0]["id"];var_dump($response);// добавляем товары в сделку$link='https://'.$subdomain.'.amocrm.ru/api/v4/leads/'.$did.'/link';$data = array (0 =>array ('to_entity_id' => 327219, //id товара можно посмореть методами api или в html коде страницы товара (не путать с артикулом)'to_entity_type' =>'catalog_elements','metadata' => array("quantity" =>  $qnt,"catalog_id" =>  5321 // id каталога, виден в адресной строке при входе в каталог),),);$response = amo_call($access_token, $link, $data);if ($response==-1) {die("что-то пошло не так при добавлении товаров в сделку /n");} else {var_dump($response);//сообщить об успешно выполнной операции}}
Bitrix24
function b24_call($queryUrl, $queryData) {$curl = curl_init();curl_setopt_array($curl, array(CURLOPT_SSL_VERIFYPEER => 0,CURLOPT_POST => 1,CURLOPT_HEADER => 0,CURLOPT_RETURNTRANSFER => 1,CURLOPT_URL => $queryUrl,CURLOPT_POSTFIELDS => $queryData,));$out =  curl_exec($curl);$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);if ($code < 200 || $code > 204) {return  -1;}curl_close($curl);$response = json_decode($out, true);return  $response;}$p ="+79000000000";$n= "Петр Петров";$zi = "111111";$pro = "Ньюйорская область";$gor = "Ньюджерси";$adr  = "ул. Линкольна дом 1";$qnt = 1;$ord = "xxxxxxxxxxxxxxxxx";//Перед созданием контакта лучше поискать его методом crm.contact.list с параметром array('filter' => array('PHONE' => $ph))$queryUrl  = 'https://xxxxxxxxxx.ru/rest/48/xxxxxxxxxxxxxxxxx/crm.contact.add.json';$queryData = http_build_query(array('fields' => array("NAME"=> $n, "PHONE"  => array(array('VALUE' =>$p, 'VALUE_TYPE' => 'MOBILE')),),'params' => array("REGISTER_SONET_EVENT" => "N")));$response= b24_call($queryUrl, $queryData);    if ($response==-1) {die("что-то пошло не так при добавлении контакта /n");} else {var_dump($response);$cid = $response["result"];echo "!".$cid."!\n";$queryUrl  = 'https://xxxxxxxxxx.ru/rest/48/xxxxxxxxxxxxxxxxx/crm.requisite.add.json';$queryData = http_build_query(array('fields'=> array("PRESET_ID"=> 3,"ENTITY_TYPE_ID"=> 3,"ENTITY_ID"=> $cid,"NAME"=>"Реквизит","ACTIVE"=>"Y","SORT"=>100)));$response= b24_call($queryUrl, $queryData);if ($response==-1) {die("что-то пошло не так при добавлении реквизита /n");} else {var_dump($response);$rid = $response["result"];$queryUrl  = 'https://xxxxxxxxxx.ru/rest/48/xxxxxxxxxxxxxxxxx/crm.address.add.json';$queryData = http_build_query(array('fields'=> array("TYPE_ID"=> 1,"ENTITY_TYPE_ID"=> 8,"ENTITY_ID"=> $rid,"POSTAL_CODE"=> "$zi", "PROVINCE"=> "$pro","CITY"=> "$gor","ADDRESS_1"=> "$adr","COUNTRY"=>  "Россия")));$response= b24_call($queryUrl, $queryData);if ($response==-1) {die("что-то пошло не так при добавлении адреса в реквизит /n");} else {var_dump($response);$lead_name = "Заказ из Aliexpress  " . $ord;$queryUrl  = 'https://xxxxxxxxxx.ru/rest/48/xxxxxxxxxxxxxxxxx/crm.lead.add.json';$queryData = http_build_query(array('fields' => array("TITLE" => $lead_name,"TYPE_ID" => "GOODS","STAGE_ID" => "NEW","CONTACT_ID"=> $cid,"CURRENCY_ID"=>  "RUB",),'params' => array("REGISTER_SONET_EVENT" => "Y")));$response= b24_call($queryUrl, $queryData);if ($response==-1) {die("что-то пошло не так при добавлении сделки /n");} else {var_dump($response);$did = $response["result"];$items = array();$items[] =  array('PRODUCT_ID' => "2968", 'PRICE' => "1.00", 'QUANTITY' => $qnt);$queryUrl  = 'https://xxxxxxxxxx.ru/rest/48/xxxxxxxxxxxxxxxxx/crm.lead.productrows.set.json';$queryData = http_build_query(array("id" => $did,"rows"=>$items));$response= b24_call($queryUrl, $queryData);if ($response==-1) {die("что-то пошло не так при добавлении товаров в сделку /n");} else {var_dump($response);//сообщить об успешно выполнной операции}}}}}
RetailCRM
$crmKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';function retail_call($url, $postData) {$curl = curl_init();curl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);curl_setopt($curl, CURLOPT_FAILONERROR, false);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);curl_setopt($curl, CURLOPT_TIMEOUT, 30);curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);curl_setopt($curl, CURLOPT_POST, true);curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);            $out =  curl_exec($curl);$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);if ($code < 200 || $code > 204) {return  -1;}curl_close($curl);$response = json_decode($out, true);return  $response;}$p ="+79000000000";$n= "Петр Петров";$zi = "111111";$pro = "Ньюйорская область";$gor = "Ньюджерси";$adr  = "ул. Линкольна дом 1";$qnt = 1;$ord = "xxxxxxxxxxxxxxxxx";$url  = 'https://xxxxxxxxxx..ru/api/v5/customers/create';$postData = array('site' =>'xxxxxxxxxx.ru','customer' => json_encode(array('firstName' =>$n,)),'apiKey' => $crmKey,);$rez = retail_call($url, $postData);var_dump($rez);$cid = $rez["id"];$url  = 'https://xxxxxxxxxx.ru/api/v5/orders/create';$postData = array('site' =>'xxxxxxxxxx.ru','order' => json_encode(array('customer'=> array('id' => $cid,),    'items' => array(array('quantity' => 6,'offer'=> array('externalId' => 'xxxxxxxxxxx',)),))),'apiKey' => $crmKey,);$rez = retail_call($url, $postData);var_dump($rez);echo "\n".$rez["id"]."\n";
Selenium (для получения access_token)
from selenium import webdriverfrom time import sleepbrowser = webdriver.Firefox()browser.get("https://seller.aliexpress.ru/")sleep(5)browser.switch_to.frame(browser.find_element_by_css_selector("iframe.iframe-with-loader_iframe__QQc_0"))e = browser.find_element_by_id("fm-login-id")e.send_keys("xxxxxx@xxxxxxxx.ru")e = browser.find_element_by_id("fm-login-password")e.send_keys("xxxxxxxxxxxxx")e = browser.find_element_by_id("fm-login-submit")e.click()sleep(15)browser.get("https://oauth.aliexpress.com/authorize?&response_type=token&client_id=XXXXXXXX&state=1212&view=web&sp=ae")sleep(5)try:    e = driver.find_element_by_id("sub")    e.click()except Exception:    print('Session login')sleep(5)txt = "-1"try:    e = driver.find_element_by_id("wrap")    print(e.get_attribute('innerHTML'))    txt = e.get_attribute('innerHTML')except Exception:    print('Session login')x = txt.split("access_token: ")y = x[1].split("<br>")print y[0]
Подробнее..
Категории: Php , Api , Crm-системы , Amocrm , Bitrix24 , Aliexpress , Retailcrm

Из песочницы Работа с enterprise как мы не сделали систему аналитики для SaaS сервиса

08.08.2020 16:12:48 | Автор: admin
Мы сильно обрадовались новому контракту и уже представляли, как логотип клиента приукрасит наше портфолио. Но все оказалось не так радужно. Расскажем, как мы работали с дочкой крупной российской IT-компании, и почему у нас не получилось сделать крутой проект.



О проекте


Продукт клиента SaaS в сфере B2B, который работает по формату абонентской платы. Пользователь регистрируется, проходит авторизацию, пополняет свой счет и использует сервис.
Наша задача помочь клиенту собрать аналитику. Для этого нужно было выстроить процессы колл-центра, внедрить CRM и свести сквозную аналитику по ключевым показателям.

Структура процессов


Перед тем, как заниматься аналитикой, нужно подготовить ландшафт для ее сбора: структурировать процессы продаж и настроить интеграции с сервисами. В процессах мы обнаружили несколько проблем:

  1. Менеджеры отвлекались на ненужные этапы воронки продаж, и их работа никак не контролировалась;
  2. Отчеты по продажам ежедневно выгружались из админки вручную;
  3. Было мало конверсионных событий для сбора аналитики.

Далее сделали карту со структурой взаимодействия всех систем. В ней показано, по какой логике должны идти события, и на каких этапах собирается аналитика. Основные данные берем из CRM и соотносим их с данными по рекламе и конверсиям. Собираем в myBI, визуализируем в Power BI.

Воронки продаж


Продажи у клиента велись в Enybox CRM, их мы перенесли в amoCRM для удобства интеграции. Логику продаж получилось собрать в три воронки.


Три последовательные воронки

Первая воронка консультации. Нужна была, чтобы довести клиента до регистрации на платформе. Вторая воронка фиксация первых оплат. Далее пользователь подтверждал свою регистрацию. А мы, в свою очередь, отмечали момент оплаты и каждое новое пополнение.

Как должна была работать аналитика


Изначальные события Итоговые события
Форма обратной связи Форма обратной связи
Регистрация в сервисе Регистрация в сервисе
Первое пополнение
Тестирование (опционально при небольшом пополнении)
Повторные пополнения
Отказ от использования (прогрев через ОП)

Для нормальной работы системы аналитики нужно собирать все события = отмечать конверсионные действия. События уже попадали в систему аналитики, но изначально их было только два типа, что недостаточно для отчетов.

Отображение данных


Пример дашборда

После того, как собирались данные по конверсиям, нужно было сделать из них отчет. Основной инструмент визуализации данных Microsoft Power BI.

В момент конверсии на сайте генерировался отдельный ID для синхронизации рекламных систем и CRM. По этому ID мы связывали данные расходов и доходов. Так мы соотносили данные и могли строить по ним отчеты.

Юнит экономика. Retention



График rolling-retention'а сервиса с 1 по 12 месяц

Retention показывает, насколько пользователи вовлечены в приложение, и как часто они в него возвращаются. Но из-за того, что сервис работает в формате пополнений, пришлось поменять этот показатель на rolling-retention. Он показывает то же самое что и ретеншн, но подразумевает что все время, которое пользователь не пополнял кабинет, он тоже использовал сервис.

Конверсия в первое пополнение



Конверсия сильно зависела от количества новых клиентов и начала их оплат. Первые 9 месяцев мы получали примерно по 430 новых регистраций и по 90 оплат от новых пользователей ежемесячно. Конверсия в покупку в месяц регистрации составила 20%, по данным за 12 месяцев.

Помимо стандартных показателей


Была возможность видеть аналитику по касаниям клиента как в моменте простого перехода на сайт, так и в момент регистрации и дальнейших оплат. Накапливали данные, чтобы найти самые конверсионные цепочки:

Пользователь увидел рекламу пошел на сайт спустя время зашел и поискал в контексте зарегистрировался, но не оплатил погрели письмом предложили тест драйв потестил ОП дожал на первую оплату 3 года стабильных оплат.

Что пошло не так


В самом начале инициаторы проекта отложили старт до осени (обратились весной). Такие пробелы в работе происходили не раз. Но мы не задумывались об этом и принимали как должное. Главными проблемами были коммуникация и бюрократия в процессах нашего клиента. Так можно изобразить весь временной отрезок работы над проектом:



Медленная разработка


Причиной пробелов в разработке была структура работы клиента. Мы работали совместно с командой клиента и часть задач можно было выполнить только на его стороне по причине высокой секьюрности процессов.
Два спринта пропустили месяц потеряли

Все менеджеры и разработчики на их стороне работали по двухнедельным итерациям. Но они постоянно ставили наш проект последним по приоритету и часто наши задачи не попадали в спринт.

Плохая коммуникация и отсутствие экспертизы


За время проекта менеджер со стороны клиента (стейкхолдер) поменялся пять раз. Наверное все знают то чувство, когда проект, над которым ты работаешь вдруг становится не интересен клиенту. Но даже это можно решить.

Сложнее было разбираться с некомпетентностью стейкхолдеров. Один из них был отличным руководителем, который хорошо разбирался в своем продукте. Но он не понимал даже базовых принципов построения процессов продаж. Мы потратили несколько встреч, чтобы переубедить его убрать из воронки продаж этап со статусом Как дела?.

Представьте себе воронку продажи, как на рисунке выше. В одном из этапов менеджерам нужно узнать как дела у клиента. Как думаете, что произойдет с аналитикой конверсий такой воронки?

Менеджеры будут узнавать как дела у клиента вместо продвижения его по воронке, статус не тривиален. Не очевидно когда его ставить: после первого контакта или после квалификации. В итоге сделки прыгают туда-сюда по воронке или просто стоят, вместо последовательного движения.
В процессе продажи невозможно ставить промежуточные этапы, в которых будут накапливаться сделки. Иначе вся аналитика превратится в кашу, а менеджеры потеряют кучу контактов.


Факапы с нашей стороны


Мы не учли пропускную способность системы. На одно событие платформы в пике мы передавали до 10 запросов к amoCRM, чтобы выполнить логику бизнес-процессов.

100 000 ивентов в сутки * 10 запросов к amoCRM = 1 000 000 запросов в сутки

1 000 000 запросов в сутки / 10 запросов в секунду (ограничение амо) = 100 000 секунд = 27 часов

Итог: синхронизация никогда не закончится

Изначально выбрали amoCRM, так как проходи по лимиту запросов к системе. Но с течением развития проекта требования и функции увеличились и мы уперлись в лимит.
Мы выбрали неподходящий инструмент. AmoCRM физически не подходит для обработки большого количества запросов.
Также ошибка была в том, что мы разрабатывали все на GO, и за это отвечал один специалист. Когда он ушел, осталась гора legacy кода, который никто не смог бы разобрать. Но, к сожалению, или к счастью это не было нужно.

Опять все сломали


Этот кейс еще один пример проекта, который закопали в согласованиях и куче неоправданного менеджмента.

Нам не хватило экспертности в техническом плане. Клиенту устойчивости в управлении и желания довести проект до конца.

Но это опыт. Благодаря ему теперь подобные задачи выглядят максимально тривиально и мы уже воспроизвели подобное решение в рамках другого проекта.

Как можно было избежать неудачи


Чтобы не повторять таких кейсов в будущем, мы выделили аспекты, которые нужно соблюдать в работе с enterprise клиентами.

  1. Держать контакт с менеджером проекта: понимать его мотивацию; помогать ему защищать презентации перед руководителями. Делать все, чтобы стейкхолдер не потерял интерес к проекту.
  2. Соблюдать структуру коммуникации. Все важные чекпоинты проекта фиксировать по почте. Все обсуждения на встречах собирать в краткое резюме. Так специалистам со стороны клиента будет проще находиться в контексте действий. Не нужно будет каждый раз восстанавливать цепочку событий.
  3. Определять мотивацию специалистов со стороны клиента при старте работ. Если проект не стоит в их KPI и он изначально в низком приоритете завершить его будет практически невозможно.
  4. Думать наперед. Даже при разработке MVP нужно смотреть, на узкие места, которые могут возникнуть в будущем. Проект всегда расширяется и важно предусмотреть структуру, чтобы не переписывать весь код с нуля.



Автор статьи Фёдор Анисимов, маркетолог LAND PRO.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru