[modRetailCRM] - Интеграция с RetailCRM

Представляю модуль для интеграции популярного сервиса RetailCRM с MODX.





Работа из коробки



Небольшой функционал предусмотрен сразу же при установке приложения.
  1. Плагин срабатывающий на событие onUserSave, автоматически создает новый контакт в CRM при регистрации нового пользователя в MODX. Данное событие срабатывает в том числе при оформлении заказа в интернет-магазине.
  2. Плагин срабатывающий на событие msOnCreateOrder, автоматические создает новый заказ в CRM при оформлении заказа в MiniShop2
На данный момент я просто не знаю, какие еще возможности обязательно нужно включить в работу из коробки. Пишите свое мнение в комментариях. Основные повторяющиеся идеи обязательно внедрим.

Ручной режим



Дополнение основано на собственной библиотеке RetailCRM и в ручном режиме поддерживает ВЕСЬ функционал доступный через API RetaiCRM

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

//Вызываем приложение
if (!$RetailCrm = $modx->getService('RetailCrm','modretailcrm',MODX_CORE_PATH.'components/modretailcrm/model/modretailcrm/')) {
    $modx->log(1, '[RetailCrm] - Not found class RetailCrm');
    return;
} 
//Получаем список всех заказов одного клиента из CRM
$filters = array();
$filter['customer'] = '+7 701 987 65 43';
$orders = $RetailCrm->ordersList($filter);
//Массив $filters - позволяет фильтровать данные, указав, например, номер или Имя клиента.

//Создаем новый контакт
$customer = array();
$customer['firstName'] = 'Федор';
$customer['lastName'] = 'Бондарчук';
$customer['email'] = 'mail@mail.ru';
$customer['phones'][]['number'] =  '+7 701 987 65 43';
$RetailCrm->customersCreate($customer);

Все доступные методы и их параметры вы можете просмотреть в API RetaiCRM. У Сервиса отличная документация.
Точный вызов того или иного метода — можно найти в файле класса ApiClient внутри дополнения.
Как правило метод вроде /api/v4/customers/create вызывается как customersCreate

Основное преимущество — гибкость в разработке


Главная идея — в том, что мы можем используя существующую библиотеку, передавать в CRM любые данные с сайта, и наоборот получать любую информацию из CRM. Возможности очень гибкие. Мы никак не привязаны к MiniShop2, например.
Можно написать собственные сниппеты и плагины работающие с ShopKeeper.
Совсем не обязательно вообще привязываться к интернет-магазинам.
Совсем простой сниппет позволит создавать в CRM контакт при заполнении классической контактной формы на сайте (пример я написал выше).

Предварительная настройка


Естественно у вас должен быть аккаунт в RetailCRM.
В системных настройках сайта (раздел modretailcrm) Вам нужно указать API ключ, адрес вашей CRM и символьный код сайта. Все эти данные Вы можете посмотреть в личном кабинете RetailCRM

Приложение на данный момент находится на модерации в Modstore.pro, на днях будет опубликовано.
Если кому то не терпится попробовать — могу выслать установочный пакет на E-mail.

Обсуждаем компонент в комментариях. Постараюсь ответить на любые вопросы.
Также готов обсудить персональную адаптацию приложения под ваши конкретные проекты.
Николай Савин
05 мая 2017, 20:15
modx.pro
2
6 214
+8
Поблагодарить автора Отправить деньги

Комментарии: 46

Антон
Антон
06 мая 2017, 08:43
0
А есть пример с минишопом?
Нужно передать данные о корзине, заказчике, доставке, оплате.
    Николай Савин
    06 мая 2017, 09:10
    +1
    <?php
    if (!$RetailCrm = $modx->getService('RetailCrm','modretailcrm',MODX_CORE_PATH.'components/modretailcrm/model/modretailcrm/')) {
        $modx->log(1, '[RetailCrm] - Not found class RetailCrm');
        return;
    } 
    $site = $modx->getOption('modretailcrm_siteCode');
    /** @var modX $modx */
    switch ($modx->event->name) {
       
        case 'msOnCreateOrder':
            $Address = $msOrder->getOne('Address');
            $orderData = array();
            $orderData['customer']['externalId'] = $Address->get('user_id');
            //Отправляем данные клиента
            if ($profile = $modx->getObject('modUserProfile', $Address->get('user_id'))) {
                $customer = array();
                $customer['externalId'] =  $Address->get('user_id');
                $customer['firstName'] = $profile->fullname;
                $customer['email'] = $profile->email;
                if(!empty($profile->phone)){
                    $customer['phones'][]['number'] = $profile->phone;
                }
                if(!empty($profile->mobilephone)){
                    $customer['phones'][]['number'] = $profile->mobilephone;
                }
                $response = $RetailCrm->customersCreate($customer, $site);  
            }
            
            $orderData['externalId'] = $Address->get('id');
            $orderData['firstName'] = $Address->get('receiver');
            $orderData['phone'] = $Address->get('phone');
            $orderData['email'] = $Address->get('email');
            
            $Products = $msOrder->getMany('Products');
            
            $items = array();
            $key = 0;
            foreach ($Products as $pr) {
                $options = $pr->toArray();
                $orderData['items'][$key]['initialPrice'] = $pr->get('cost');
                $orderData['items'][$key]['purchasePrice'] = $pr->get('cost');
                $orderData['items'][$key]['productName'] = $pr->get('name');
                $orderData['items'][$key]['quantity'] = $pr->get('count');
                $orderData['items'][$key]['offer']['externalId'] = $pr->get('id');
                $key ++;
    		}
            //Указываем какие поля заполняются в корзине
            $fields = array(
                'index' => 'Индекс', 
                'country' => 'Страна', 
                'region' => 'Регион', 
                'city' => 'Город', 
                'metro' => 'Метро', 
                'street' => 'Улица', 
                'building' => 'Дом', 
                'room' => 'Квартира\офис',
                'comment' => 'Комментарий к адресу'
            );
            $address = '';
            foreach($fields as $field=>$comment){
                if(!empty($Address->get($field))){
                    $address .= $comment.':'.$Address->get($field).' ';
                    $orderData['delivery']['address'][$field] = $Address->get($field);
                }
            }
            $orderData['delivery']['address']['text'] = $address;
    //Оплата и доставка довольно индивидуальны
    //Если надо заполнять данные о сервисе и методе доставки заполняем поля раздела order[delivery] 
    	//Данные об оплате заполняются в order[paymentType] order[paymentStatus] order[paymentDetail]
            $response = $RetailCrm->ordersCreate($orderData, $site);
          
            break;
    }
    Raimei
    06 мая 2017, 10:57
    +1
    Грац! Шикарное дополнение, особенно нравится НЕпривязка к minishop'у.
    Виталий
    06 мая 2017, 12:00
    0
      Алексей Шумаев
      14 мая 2017, 00:00
      +1
      Николай, у меня после установки лог забит ошибками
      ... xpdo.class.php : 503) Path specified for package modsendpulse is not a valid or accessible directory: ...
      modsendpulse не устанавливал.
        Николай Савин
        15 мая 2017, 14:02
        0
        Спасибо за сигнал. Я использовал заготовку от modsendpulse. Видимо где то забыл заменить адрес каталога.
          Алексей Шумаев
          15 мая 2017, 17:12
          +1
          Вот уж не за что, это Вам — спасибо!
          Заметил, что лог забивается сам по себе, без каких-то действий на сайте (он тестовый у меня). Как будто cron работает )
        Алексей Шумаев
        24 мая 2017, 16:34
        +1
        Николай, а будет ли обновление? Чтобы лог отдохнул )
          Николай Савин
          28 мая 2017, 19:30
          0
          Да конечно, на днях будет. Никак не выделю время с работой.
            Николай Савин
            19 июня 2017, 14:54
            0
            Выпустил обновление. Баг устранен.
              Алексей Шумаев
              27 июня 2017, 10:16
              0
              Не совсем:
              (ERROR @ /core/xpdo/xpdo.class.php: 503) Path specified for package modsendpulse is not a valid or accessible directory: core/components/modsendpulse/model/

              Источник здесь: components/modretailcrm/index.class.php
            Андрей
            26 июля 2017, 22:12
            0
            Подскажите, а смена статуса в админке магазина передается в retailCRM?
              Николай Савин
              27 июля 2017, 22:00
              0
              Нет в исходном плагине прописана отправка данных пользователя и отправка заказа, у которого соответственно статус Новый.
              Для отправки обновления статуса нужно дописать плагин на событие msOnChangeOrderStatus

              Я честно говоря не знаю, будет ли сейчас работать метод обновления, так как RetailCRM сейчас выпустили обновление API. Что то изменили, что то добавили, некоторые методы убрали. Надо тестировать короче.
              Алексей Шумаев
              22 августа 2017, 17:25
              0
              Только руки дошли…
              В общем, у кого осталась ошибка с «modsendpulse» в логе после обновления, уберите «modsendpulse» из системной настройки minishop2 «extension_packages»
                Алексей Шумаев
                05 сентября 2017, 13:53
                0
                Если не верно указать адрес retailCRM (modretailcrm_urlCrm), то будет
                PHP message: PHP Fatal error:  Uncaught Error: Class 'InvalidJsonException' not found in /home/xxx/xxx/xxx/components/modretailcrm/model/modretailcrm/Response/ApiResponse.php:52
                Ошибка не очевидная… Наверно желательно добавить проверку нужных настроек в начале + добавить исключение, я так понимаю.
                  Дмитрий
                  27 февраля 2018, 10:43
                  0
                  Добрый день.
                  Если пользователь есть в админке после оформления заказа выдает ошибку, данные не передаются в CRM
                  [customer.externalId] => Customer with externalId=6 not found. Order externalId=43.
                  Если пользователя нет админке, создает нового и данные в CRM передает

                  Подскажите как поправить. Спасибо.
                    Николай Савин
                    27 февраля 2018, 10:47
                    0
                    Здравствуйте. Надо тестировать, так сходу не подскажу решение.
                    Oleg Pimanov
                    19 октября 2018, 12:44
                    0
                    Добрый день! Такой вопрос, заказчик захотел подружить «Мой склад» и Retail CRM, при передаче заказа в Retail CRM к заказу надо добавить поле «Внешний код», которое есть в «Мой склад». Точнее не добавить, а вставить вместо id товара, чтобы Мой склад мог понять какой товар куплен и сброшен в заказе в Retail CRM. Это через tv поля можно сделать?
                      Николай Савин
                      19 октября 2018, 12:55
                      0
                      Да, почему бы и нет. Правильнее было бы не TV использовать, а добавить новое свойство товара. Это уменьшит время оформления заказа. Ну и подставляйте новый идентификатор в массив товаров, поле externalID, в плагине
                      Oleg Pimanov
                      19 октября 2018, 18:11
                      0
                      У Вас модуль передает id товара вот этой строчкой

                      $orderData['items'][$key]['offer']['externalId'] = $product['externalId'];
                      
                      Для того, чтобы мой склад понял, что упало в заказе в Retail CRM, должно быть типа так

                      $orderData['items'][$key]['offer']['externalId'] = $product['externalCode'];

                      При такой настрйоке не срабатывает ничего, заказ не отправляется в Retail CRM
                        Николай Савин
                        19 октября 2018, 18:38
                        0
                        В конце плагина есть закомментированная строчка записи результата в лог. Нужно раскомментировать и посмотреть какая будет ошибка
                        Oleg Pimanov
                        22 октября 2018, 11:51
                        0
                        Добрый день! Такой вопрос, а по какому полю Retail CRM понимаеьт какой товар заказали и сравнивает его с своей структурой, которую мы туда загрузили.
                          Николай Савин
                          22 октября 2018, 12:51
                          0
                          Вообще при выгрузке нужно указывать идентификатор товара в поле ExternalID
                          Если Вы этого не делали, тогда отдельного специального поля для связи товаров в различных системах нет.

                          В таком случае, можно перед передачей заказа в RetailCRM, получить идентификаторы товара, используя поиск по товарам в CRM

                          Для этого в плагине, там где начинается перебор товаров заказа, можно добавить дополнительный поисковый запрос в RetailCRM
                          $store_response = $modRetailCrm->request->storeProducts(array('name' => $product['article']), 1, 20);  
                          if($store_response->getStatusCode() == 200){
                                  $product_id = $store_response['products'][0]['offers'][0]['id'];
                            }
                          $orderData['items'][$key]['offer']['id'] = $product_id;
                          Здесь вы ищите на складе RetailCRM товар, у которого наименование совпадает с артикулом в minishop2. Если такой товар найден получаем его id.
                          Разумеется фокус сработает, если указанные данные у товаров в разных системах один и тот же.
                          Никто не мешает искать по другим общим параметрам.

                          Важно также понимать, что эти дополнительные запросы занимают время и заказ передается дольше, а клиент в этот момент сидит и смотрит на экран корзины.
                            Oleg Pimanov
                            08 ноября 2018, 22:28
                            0
                            Доброй ночи! Выше код, который я прописал, работает, но почему — то предает только правильно количество товара и цену, а название товара передает всегда одно и то же.
                              Николай Савин
                              09 ноября 2018, 15:43
                              0
                              В этом случае ни цену, ни название товара вообще передавать не нужно, они есть в базе RetailCRM. Достаточно передавать идентификатор
                                Oleg Pimanov
                                09 ноября 2018, 15:47
                                0
                                Я, наверное не так выразился, в самой Retail CRM, когда туда заказ приходит, там в заказе вот имя товара высвечивается одно и то же, хотя остальные параметры (цена и количетсво) как надо.
                                  Николай Савин
                                  09 ноября 2018, 15:49
                                  0
                                  Ну значит у тебя либо все товары с одним и тем же именем, либо ты передаешь один и тот же id товара
                                    Oleg Pimanov
                                    09 ноября 2018, 15:51
                                    0
                                    В админке все товары разные и при выгрущке структуры в Retail тоже разные,
                                      Николай Савин
                                      09 ноября 2018, 15:52
                                      0
                                      Ну значит происходит магия
                                        Oleg Pimanov
                                        09 ноября 2018, 17:50
                                        0
                                        Retail CRM связана с «Мой склад», выгрузка структуры в Retail CRM просиходит с помощью мануала от «Мой склад», по идее этот никак не должно влиять на заказ, который приходит из minishop2, но сейчас приходит заказ с одинковым названием, но разными ценами и количеством
                                          Oleg Pimanov
                                          16 ноября 2018, 22:24
                                          0
                                          В общем, магия или нет, но 85 строчка была такой
                                          $orderData['items'][$key]['productName'] = $product['name'];
                                          
                                          а должна быть такой
                                          $orderData['items'][$key]['name'] = $product['name'];
                                          
                                          И вставка вот этого кода не нужна
                                          $store_response = $modRetailCrm->request->storeProducts(array('name' => $product['article']), 1, 20);  
                                          if($store_response->getStatusCode() == 200){
                                                  $product_id = $store_response['products'][0]['offers'][0]['id'];
                                            }
                                          $orderData['items'][$key]['offer']['id'] = $product_id;
                                          
                                            Oleg Pimanov
                                            16 ноября 2018, 22:41
                                            0
                                            Предыдущий комментарий ошибочный.
                                            У меня чехарда с сайтом идет, вот этот код вставляю и работает, ничего более не меняю
                                            В общем, магия или нет, но код вот такой должен быть
                                            <pre>
                                            $store_response = $modRetailCrm->request->storeProducts(array('name' => $product['name']), 1, 20);  
                                            if($store_response->getStatusCode() == 200){
                                                    $product_id = $store_response['products'][0]['offers'][0]['id'];
                                              }
                                            $orderData['items'][$key]['offer']['id'] = $product_id;
                                            </pre>
                                            
                            Oleg Pimanov
                            22 октября 2018, 14:07
                            0
                            Спасибо, это сработало, для «Мой склад» теперь все передается. Вы можете это добавить себе в Ваш плагин, так как смогие их используют вмесет, «Мой склад» и «Retail CRM»
                              Николай Савин
                              22 октября 2018, 14:11
                              +1
                              Хотя бы плюсик к статье поставьте вместе со спасибо,
                              По существу Не уверен что такая доработка плагина нужна. Вы пока второй на 130 загрузок, кто такое спрашивает.
                                Oleg Pimanov
                                22 октября 2018, 14:15
                                0
                                Ну может быть, к статье не могу поставить плюсик, не дает, а вот к ответу да, могу.
                              Руслан
                              24 января 2020, 14:05
                              0
                              Здравствуйте!
                              Ваш модуль использует устаревшую версию АПИ v4 и если да то когда вы планируете на v5 переводить?
                              Спасибо!
                                Николай Савин
                                24 января 2020, 14:09
                                0
                                Это откуда у вас такая информация позвольте спросить?
                                  Руслан
                                  24 января 2020, 14:19
                                  0
                                  исключительно из вашего поста "… Как правило метод вроде /api/v4/customers/create вызывается как customersCreate..." :) извините если ошибся в выводах
                                    Николай Савин
                                    24 января 2020, 14:22
                                    0
                                    Пост 17 года, вполне может быть на момент написания была еще 4, а то и третья версия API.
                                    На данный момент в компоненте пятая актуальная версия. Нормально все.
                                      Руслан
                                      24 января 2020, 14:27
                                      0
                                      Спасибо! в ближайшие пару дней покупаю однозначно у нас вообще нестандартная связка из двух баз 1С ут10 и ут11 товары льются в единый каталог в црм и из этих баз на сайт по складам остатки и цены и на сайте не все товары из этих баз, а новые создаются на сайте только из ут11 и всё это моими обработками по АПИ сайта, а дальше с сайта по разным правилам на разные магазины в црм льются заказы(но это все на кскарт и мне предстоит все адаптировать на MODX и ваш модуль просто вовремя мне попался на глаза иначе я думал с нуля писать придется!)
                              Руслан
                              26 октября 2020, 20:12
                              0
                              Здравствуйте,

                              Компонент приобрел недавно, прошу помощи в настройке или в устранение причины. Устанавливал не я, а другой человек с которым на связи.

                              Есть две пока что выявленной причины:

                              1. Сдэк. При выборе тарифа в карточке заказа выдает ошибку. Написал в сдэк получил ответ: " Так как вы пользуетесь модулем сторонней компании, по вопросам настройки, работы и доработки, вам необходимо обращаться к разработчикам данного модуля ...."
                              Глубоко по другим КС не смотрел и не настраивал, но выбор тарифа у Шиптора или Боксберри — работает.

                              2. UIS телефония. Ответа точного не получил по их части проблема или нет, по телефону проверили настройки базовые, сказали все ок. Проблема в том, что при звонке не появляется окошко о входящем звонке где отображается данные о покупателе да и в целом нет уведомления, что был пропущенный, а так же вместе с оператором заметили, что нет кнопки «трубка» там где она должна быть, чтобы можно было сразу позвонить из СРМ
                              Но там где сохраняются разговоры они есть и их прослушать можно, но опять же нет кнопки «трубка»
                                Николай Савин
                                26 октября 2020, 20:21
                                0
                                Добрый день. Я так понимаю речь о неполадках внутри самой CRM?
                                Мой компонент не имеет к этому никакого отношения. Он работает ТОЛЬКО на сайте.
                                  Руслан
                                  26 октября 2020, 20:32
                                  0
                                  Я сам не понимаю в чем именно проблема, пока что все перекидывают стрелки на других. Жду ответа от самого РетейлСРМ. За ответ и быстроту респект!
                                Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                                46