[modRetailCRM - 2.2.1]

Давненько я ничего не публиковал. Здравствуйте.

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


Список изменений продукта



2.1.0
==============
— Отключена передача способа доставки и оплаты и за ошибки на стороне RetailCRM
— Исправлена передача общей стоимости нескольки разных тоаров
— Добавлена передача стоимости доставки
— Добавлена передача веса товара
— Добавлено разбиение Строки ФИО на отдельные поля
— Добавлена проверка на существование пользователя на стороне RetailCRM

2.2.0
==============
— В объект msDelivery, добавлено дополнительное поле retailcrm_delivery_code, позволяющее указать символьный код доставки из настроек retailCRM, что дает возможность передавать способ доставки при заказе.
— В объект msPayment, добавлено дополнительное поле retailcrm_payment_code, позволяющее указать символьный код способа оплаты из настроек retailCRM, что дает возможность передавать способ оплаты при заказе.













2.2.1 — (11.06.2018)
==============
— В выгрузку заказов добавлен передача способа доставки и способа оплаты

Статья была бы не полной, если я не отвечу на еще один повторяющийся вопрос

Как передать в minishop2 изменения на стороне RetailCRM



Я конечно понимаю, что изменений в магазине может быть огромное количество. Это и работа с товаром, и с клиентами и с заказами. Моя задача — объяснить общее направление мысли и показать пример.

Пример возьмем такой.
  1. Заказ, сделанный в интернет-магазине, плагин передал в RetailCRM
  2. Менеджер, обработав заказ — изменил ему статус в RetailCRM
  3. Обновленный статус должен автоматически выгрузиться в интернет-магазин, и обновить статус заказа на соответствующий
Конечно же в дело вступают всем известные webhooks, которые отлеживают изменения внутри CRM, по заранее заданному сценарию и передают информацию на коннектор сайта. В общем то типовая ситуация для любой современной CRM, но в RetailCRM решил быть оригинальными и спрятали эту возможность достаточно глубоко и неочевидно.

Итак что мы делаем для решения подобных задач.

1. В личном кабинете RetailCRM ищем пункт Коммуникации-Триггеры
2. Создаем новый триггер со следующими параметрами:
  • Событие, которое мы будем отлавливать Изменение заказа
  • Действие, которое будет выполняться при выполнение указанных условий Выполнить HTTP-запрос
  • HTTP метод POST запрос (на самом деле можно и GET — это уже вкусовщина)
  • Адрес: Коннектор на вашем сайте, на котором будет отправляться запрос. Естественно там должна быть программа, принимающая POST запрос и выполняющая необходимые действия. В нашем случае вызывая заказ с принятым id и устанавливая для него переданный статус
  • Условие применения триггера. Здесь нужно написать условие при наступлении которого будет выполняться HTTP запрос к нашему коннектору. Например можно перечислить статусы заказа RetailCRM при указании которых будет выполняться триггер. Допустим Вам нужно передать на сайт окончательный статус Оплачен или Отменен, и не передавать промежуточные статусы Подтвержден, Обработан, Выставлен счет и т.п.
    Для написания подобных условий нужно использовать шаблонизатор (по моему Twig) и предусмотренные для этого методы
    Я подготовил следующее условие
    changeSet.hasChangedField("status") and changeSet.getNewValue("status").getGroupCode() in ["complete", "cancel"]
    Условие расшифровывается так. Если при среди измененных полей есть поле Status и новое значение поля Status находится в группе статусов Выполнен или Отменен — то выполняем действие.

    Подробнее о правилах подготовки и написании триггеров можно узнать в документации
    Правила подготовки триггеров и триггеры
3. Последний параметр настройки триггера — передаваемые на наш коннектор параметры. В случае с моим примером это:
  • id заказа — order = {{ order.getExternalId() }}
  • код статуса status = {{ order.getStatus() }}





4. На нашем сайте коннектор должен принять передаваемую ему информацию, вызвать нужный заказ и поменять ему статус. Код программы получится примерно такой.

<?php
//Подключаем к произвольному файлу MODX API
define('MODX_API_MODE', true);
require_once($_SERVER['DOCUMENT_ROOT'].'/index.php');

$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');
$modx->setLogLevel(modX::LOG_LEVEL_ERROR);


if($_POST['status'] && $_POST['order']){
	//Принимаем параметры
	$status = trim( filter_input(INPUT_POST,'status',  FILTER_SANITIZE_STRING) );
	$order = trim( filter_input(INPUT_POST,'order',  FILTER_SANITIZE_STRING) );
	
	//Указываем какой статус заказа минишопа соответствует каждому возможному варианту RetailCRM
	$new_status = 0;
	switch($status){
		case 'sh-send':
			$new_status = 3;
			break;
		case 'cancel-other':
			$new_status = 4;
			break;
	}
	
	//Вызываем объект заказа и меняем ему статус
	$order = $modx->getObject('msOrder', array('num' => $order));
	if($order && $new_status > 0){
		$order->set('status', $new_status);
		$order->save();
	}
}
Николай Савин
Николай Савин
12 июня 2018, 09:25
modx.pro
3 658

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

Dmitry
10 июля 2018, 16:03
Заказы не передаются, добавил в плагин строчку печати в лог, получаю такую ошибку:
[2018-07-10 15:52:03] (ERROR @ /home/s14252/www/meat/cache/includes/elements/modplugin/19.include.cache.php : 93) [modRetailCRM]  Order Response RetailCrm\Response\ApiResponse Object
(
    [statusCode:protected] => 400
    [response:protected] => Array
        (
            [success] => 
            [errorMsg] => Order is not loaded
            [errors] => Array
                (
                    [customer.externalId] => Customer with externalId=2 not found. Order externalId=16.
                )

        )

)
Буду благодарен за совет, как исправить.
    Николай Савин
    10 июля 2018, 16:12
    Вы обновляли компонент? По идее в свежей версии эта проблема устранена.
      Dmitry
      10 июля 2018, 16:37
      Хм, установил компонент из репозитория только сегодня. Установилась версия 2.0.0. Нужно обновить как-то вручную?
        Николай Савин
        10 июля 2018, 16:39
        Текущая версия 2.2.1 Нужно устанавливать из репозитория modstore.pro. Все свежие версии и обновления там. За наводку спасибо дойдут руки обновлю в официальном
          Dmitry
          10 июля 2018, 16:43
          Спасибо за ответ, обновился из репозитория modstore.pro, всё заработало.
Pavel Zarubin
16 сентября 2018, 02:17
После установки и ввода ключа упала админка.
php 7.2

P.s. Не знаю зачем такой компонент нужен в extension_packages. Он не влияет на работу modx'a, так зачем его инициализировать без надобности?
    Pavel Zarubin
    16 сентября 2018, 02:25
    Проверил ошибку дважды, если установить компонент и указать сначала api ключ, то админка сразу падает не давая заполнить другие настройки. Вычистил класс, заполнил настройки и все завелось.А еще не знаю насколько корректно оставлять в комментариях доступы к демо-магазину
Эдвард Ерохин
17 октября 2018, 12:45
Подскажите, правильно ля и понял. Для того чтоб заказы падали в CRM, нужно туда добавить весь каталог товаров? Сейчас в CRM приходит только пользователь а заказ не падает
    Николай Савин
    17 октября 2018, 12:48
    Нет не правильно.
    Если товар в CRM не создан, то заказ все равно создается на основе присылаемых данных (название, цена, опции)
    Если товары в базе CRM уже есть, то достаточно послать идентификатор товара, а все данные подтянутся из базы
      Эдвард Ерохин
      17 октября 2018, 12:51
      а как отследить ошибку? заказ в CRM не падает, только новый пользователь. Лог ошибок чистый
        Эдвард Ерохин
        17 октября 2018, 13:09
        В общем, если ставить по умолчанию доставку новая почта то не работает из коробки. Убрал новую почту все гуд) Спасибо за компонент, буду настраивать!
          Николай Савин
          17 октября 2018, 13:11
          В плагине, в самом конце есть закомментированная строчка логгирования.
          Достаточно ее раскомментировать и будет запись в журнал, с достаточно подробным описанием ошибки.
      Андрей
      24 октября 2018, 21:56
      Все настроил по инструкции — ничего в RetailCRMне передается. Вообще. Как включить логирование — в плагине не нашел строки такой.
        Александр
        24 октября 2018, 22:55
        Значит неправильно настроили. Компонент работает как надо, проверено
          Андрей
          24 октября 2018, 22:59
          Вопрос был таков:
          Как включить логирование — в плагине не нашел строки такой.
          То что там все работает я не сомневаюсь, а хочу выяснить проблему. Что касается правильно или неправильной настройки, то я думаю там в 3 строках не трудно разобраться и вряд ли сделать ошибку…
          Николай Савин
          26 октября 2018, 07:55
          Вот после этой строки в плагине
          $response = $modRetailCrm->request->ordersCreate($orderData, $site);
          можно включить логгирование
          $modx->log(1, print_r($response, 1));
          Мне очень нравится как API RetailCRM возвращает ошибки. Все предельно понятно
            Андрей
            26 октября 2018, 08:40
            Спасибо)
            Вот что получаю:
            RetailCrm\Response\ApiResponse Object
            (
            [statusCode:protected] => 400
            [response:protected] => Array
            (
            [success] =>
            [errorMsg] => Order is not loaded
            [errors] => Array
            (
            [items[0].properties[modifications][value]] => Product property value in the order content is not specified
            )

            )

            )
              Николай Савин
              26 октября 2018, 08:44
              Насколько я понял, у тебя что то не то с модификациями. Может просто пустые.
              Попробуй, распечатай перед отправкой массив с данными, может что-то будет более ясно.

              $modx->log(1, print_r($orderData, 1));
                Андрей
                26 октября 2018, 09:03
                Array
                (
                    [customer] => Array
                        (
                            [externalId] => 2
                        )
                
                    [externalId] => 1810/15
                    [firstName] => Иван
                    [phone] => 
                    [email] => email@email.ru
                    [lastName] => Иванов
                    [patronymic] => Иванович
                    [items] => Array
                        (
                            [0] => Array
                                (
                                    [initialPrice] => 3000.00
                                    [purchasePrice] => 3000.00
                                    [productName] => Плитка индукционная настольная Сага-2 (ТМ Великие реки)
                                    [quantity] => 1
                                    [offer] => Array
                                        (
                                            [externalId] => 100
                                        )
                
                                    [properties] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [name] => modifications
                                                    [value] => Array
                                                        (
                                                        )
                
                                                )
                
                                            [1] => Array
                                                (
                                                    [name] => modification
                                                    [value] => 0
                                                )
                
                                        )
                
                                )
                
                        )
                
                    [weight] => 1.8
                    [delivery] => Array
                        (
                            [address] => Array
                                (
                                    [index] => 170001
                                    [region] => Тверская обл.
                                    [city] => Тверь
                                    [text] => Индекс:170001 
                                Регион:Тверская обл. 
                                Город:Тверь 
                                
                                )
                
                            [cost] => 0
                            [code] => sdek-sklad-doors
                        )
                
                    [customerComment] => 
                    [payments] => Array
                        (
                            [0] => Array
                                (
                                    [type] => cash
                                )
                
                        )
                
                )
                Можно ли сделать какое-то условие, если модификация пустая не учитывать ее?
                  Николай Савин
                  26 октября 2018, 10:11
                  Ну как я и сказал. Если у свойства товара пустое значение — RetailCRM вернет ошибку.
                  Можно ли сделать какое-то условие, если модификация пустая не учитывать ее?
                  Ответить
                  Можно — разрешаю.
                    Андрей
                    26 октября 2018, 10:18
                    Самое интересное, что у товара вообще нет опций, и нет модификаций. По идее если их нет, то они не должны учитываться никак…
                    Можно — разрешаю.
                    У вас хорошее чувство юмора) Помогите справиться с этой задачей)) Может быть еще кому-то пригодиться.
                      Николай Савин
                      26 октября 2018, 10:22
                      С какой задачей? Перебрать массив опций и проверить их на пустоту? Это основа PHP: циклы и условия. Если ты не знаешь как делать подобные вещи — то лучше обратись в раздел работа.
                        Андрей
                        26 октября 2018, 10:25
                        Это надо проверять в плагине вашего компонента или где-то в другом месте?
                        Почему компонент не работает из коробки с товарами без опций. Там нет никаких модификаций и опций, а он не работает…
                          Николай Савин
                          26 октября 2018, 10:30
                          на 130 с лишним скачиваний — он почему то у тебя одного не работает. Тебе не кажется, что проблема не в компоненте, а где то еще?
                            Андрей
                            26 октября 2018, 10:31
                            Судя по длинным веткам обсуждений, то у меня то у кого-то еще вылезают разные проблемы в нем. И почему-то везде они решаются а в данном случае помощи судя по всему ждать не приходится.
                            Николай Савин
                            26 октября 2018, 10:34
                            Потому что ты просишь чтобы за тебя все сделали, разжевали и готовое на блюдечке вынесли.
                            Андрей
                            26 октября 2018, 10:39
                            Точно… я же забыл что у нас здесь сообщество великих гуру… И свысока спускаться не по статусу большинству…
                            Николай Савин
                            26 октября 2018, 11:17
                            Верно заметил. Сообщество, а не детский сад. Здесь нянечек нет. Не нравится — не используй. Сделай сам.
                            Андрей
                            26 октября 2018, 11:20
                            Да действительно иногда проще самому сделать, чем тратить время на пустую болтовню с горе разработчиками
        Nikita
        15 декабря 2018, 16:31
        Николай, спасибо большое за помощь в адаптации и доработки компонента )))
        Сделал все как просил ) Респект.
          Ильяс
          25 декабря 2018, 08:49
          Благодарю Николая за отличную техническую поддержку. Были сложности в интеграции, но при обращении все решилось оперативно. По мимо интеграции, была обновлена версия компонента и даны рекомендации по сайту в целом. Спасибо!
            Антон
            25 декабря 2018, 23:48
            A это у меня одного так, что на сайте версия 2.2.3-пл и она не обновляется, даже не видит обновления, говорит, что у меня самая последняя версия, хотя на модсторе уже 2.4… Или там какая-то замута с тем, что компонент стал платный и теперь пока не купишь, никак не обновиться?
              Николай Савин
              26 декабря 2018, 05:02
              Именно так. Обновления только после покупки!
                Антон
                26 декабря 2018, 09:27
                А будет какой-нибудь пост с описанием того, что там в новой платной версии появилось?
                  Николай Савин
                  26 декабря 2018, 09:29
                  Это все есть на странице программы в разделе История изменений
                  История modRetailCRM 2.4.1 — (14.12.2018)

                  Добавлена смена статуса платежа в CRM
                  2.4.0 — (14.12.2018)

                  Настроен учет промо-кодов и скидкок компонента msPromoCode
                  Исправлены мелкие ошибки плагина.
                  Добавлены подписи популярных свойств size,color для передачи нормально читаемых опций
                  Добавлено обнаружение msOptionsPrice2 и заготовка под передачу опций
                  ==============

                  2.3.3 — (13.12.2018)

                  Новая системная настройка — Перечень статусов заказов, которые будет слушать плагин
                  Мелкие правки в плагине

                  2.3.2 — (13.12.2018)

                  В объект msOrderStatus, добавлено дополнительное поле retailcrm_status_code, позволяющее указать символьный код статуса заказа из настроек retailCRM.
                  Настроено отслеживание изменения статуса заказа.
                  В ближайшее время будут еще изменения. Как минимум синхронизация статусов заказов в обе стороны. Я над этим работаю.
              Антон
              26 декабря 2018, 18:05
              Возможно это дурацкий вопрос, но я нигде в справочнике апи не могу найти метод, чтоб с сайта товары в црмку загрузить. В версии компонента 2.2.3 используется 4 или 5я версия протокола апи? Всё, что я нашел, это какое-то описание полей класса товара тут. Но метод для создания товара через апи не могу найти. Или может в компоненте уже есть готовое решение для экспорта в црм справочника товаров?
                Николай Савин
                26 декабря 2018, 19:07
                 Хороший вопрос. Товары конечно выгружаются из сайта в CRM, причем поддерживается автоматическая и ручная синхронизация. Но работает это не через API — все проще.
                Как и для ЯндексМаркета формируется xml страница с YML каталогом. RetailCRM его прекрасно понимает. Важно понимать что в YML нет торговых предложений. То есть кроссовки не важно какого цвета и размера это один и тот же товар с одной ценой. А цвет и размер передается уже просто как опция заказа.

                RetailCRM в этом плане пошли дальше и сделали поддержку торговых предложений. Тут уже можно разбить один товар на несколько. К примеру по цвету или размеру. Такой формат называтся ICML — это расширение YML формата. Как правильно сформировать ICML файл можно подробно прочитать здесь

                Я даже могу дать пошаговую инструкцию по выгрузке товаров (YML формат, попроще)
                1. Создаем отдельную XML страницу, называем ее icml
                2. Пишет примерно такое содержание из двух сниппетов
                <?xml version="1.0" encoding="UTF-8"?>
                <yml_catalog date="{"" | date : "Y-m-d H:i:s"}">
                    <shop>
                        <name>{'site_name' | option}</name>
                        <company>{'site_name' | option}</company>
                        <url>{'site_url' | option}</url>
                        <currencies>
                            <currency id="RUR" rate="1"/>
                        </currencies>
                        <categories>
                            {'!pdoResources' | snippet : [
                            'parents' => 0,
                            'level' => 10,
                            'limit' => 0,
                            'showHidden' => 0,
                            'where' => ['class_key' => 'msCategory'],
                            'sortby' => 2,
                            'tpl' => '@INLINE <category id="{$id}" parentId="{$parent}">{$pagetitle}</category>'
                            ]}
                        </categories>
                        <offers>
                            {'!msProducts' | snippet : [
                            'parents' => 2,
                            'level' => 10,
                            'limit' => 0,
                            'tpl' => '@INLINE
                                <offer id="{$id}" productId="{$id}" available="true">
                                    <url>{$id | url : ["scheme" => "full"]}</url>
                                    <price>{$price | replace : " " : ""}</price>
                                    <categoryId>{$parent}</categoryId>
                        	        <purchasePrice>{"msProductOptions" | snippet : ["product" => $id, "onlyOptions" => "opt_prices"]}.00</purchasePrice>
                        	        {if $old_price > 0}<oldprice>{$old_price  | replace : " " : ""}</oldprice>{/if}
                                    <currencyId>RUR</currencyId>
                                    <vendor>{$vendor.name}</vendor>
                                    <vendorCode>{$article | replace : "&" : "AND"}</vendorCode>
                                    <manufacturer_warranty>true</manufacturer_warranty>
                                    <picture>{"site_url" | config | replace : "ru/" : "ru"}{$image}</picture>
                                    <name>{$pagetitle | replace : "&" : "AND"}</name>
                                </offer>
                            '
                            ]}
                        </offers>
                    </shop>
                </yml_catalog>
                3. Идем в RetailCRM — администрирование — магазины — каталог.
                Выбираем там «загружать из ICML» — указываем ссылку на нашу XML страницу — ставим отметку загрузить сейчас и жмем сохранить.
                Все после этого по идее каталог товаров будет загружен автоматически — причем CRM сама будет переодически (раз в день по моему) обновлять товары в базе.

                Ну и после этого важно понимать, что передавать товары в плагине заказ не нужно — нужно передать лишь идентификаторы товара и если надо опции. Остальные данные (название, цена, картинка) уже подгрузятся сами из базы CRM.

                Надеюсь все понятно объяснил. Могу в рамках техподдержки помочь все это настроить (после покупки конечно)
                  Антон
                  27 декабря 2018, 02:29
                  Ух-ты, удобно, спасибо. Сам бы никогда не узнал про такое. То есть плагин подправить надо, чтоб из данных о товарах в заказе только айдишник отправлялся, так?
                    Антон
                    27 декабря 2018, 02:42
                    Единственная беда — у меня сайт падает с 500 ошибкой при генерации этого юмл. 11к товаров. Если ставить лимит на товары до 10к, то работает, 10к+ — 500 ошибка. Причём в логах пусто. Может это какое-то ограничение мсПродуктс?
                      Николай Савин
                      27 декабря 2018, 07:19
                      У тебя сервер же выдает ошибку. Смотри логи сервера. Скорее всего превышен лимит выделенных ресурсов. В таком случае тебе нужно не на лету генерировать страницу, а через консоль отдельный XML файл генерировать.
                      Антон
                      27 декабря 2018, 02:49
                      А если црмке скормить выгрузку для яндекс-маркета, сработает, или там поля не так называются?
                        Антон
                        27 декабря 2018, 02:51
                        А, да, там поля другие.
                          Николай Савин
                          27 декабря 2018, 07:16
                          Ниче не другие поля. я же выше написал, что RetailCRM понимает YML и его ICML это расширение YML. На всякий случай YML — это Yandex Market Language — то есть формат придуманный маркетом.
                      Varelkka
                      16 января 2019, 15:10
                      Спасибо за оперативную компетентную помощь в доработке компонента под индивидуальные задачи!
                        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                        48