Чек-лист проверки перед обновлением retailCRM с 5.0 на 6.0

Триггеры

В триггерах по аналогии с шаблонами больше не обязательно проверять, что переменная не равна null. Код order.getStatus().getCode() больше не генерирует исключение если order.getStatus() или order равны null, и возвращает null.

Поэтому стоит обратить внимание на код триггеров, где идет обратная проверка (например not in, != и т.п.). Возможно их нужно будет изменить, чтобы они учитывали новое поведение.

Если, например, раньше выражение order.getPaymentStatus().getCode() not in ['paid', 'not-paid'] генерировало исключение, если статус оплаты не указан у заказа, и триггер не выполнялся, то в новой логике левая часть выражения будет возвращать null, который успешно пройдет указанную проверку.

До обновления на 6.0, стоит по Журналу действий найти срабатывания, которые приводят к ошибке, и поправить соответствующим образом триггеры.

Множественные оплаты

В версии 6.0 была добавлена возможность добавлять несколько оплат в рамках одного заказа. Это влечет изменение в модели данных, т.к. у заказа теперь не оплата, а коллекция оплат со всеми вытекающими.

Прежние прямые методы доступа к данным платежа order.getPaymentType(), order.getPaymentStatus(), order.getPaymentDetail() сохранены для совместимости, но работают только в случае одного платежа в заказе.

Появляется коллекция платежей order.getPayments(), а также поле order.fullPaidAt и метод order.getFullPaidAt(), которые возвращают дату полной оплаты заказа.

Особенности работы

Для сохранения совместимости методы объектов, доступных в шаблонах и триггерах, а также методы API v4 и ниже работают по логике «рабочего платежа»:

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

Триггеры

1. [Можно скорректировать ДО обновления] В триггерах условие полной оплаченности заказа нужно проверять с помощью order.fullPaidAt, и реагировать на изменение full_paid_at.

Т.е. выражения, срабатывающие на факт полной оплаты заказа вида

changeSet.hasChangedField("payment_status") and changeSet.getNewValue("payment_status").getCode() == "paid"

нужно заменять на выражения вида

changeSet.hasChangedField("full_paid_at") and changeSet.getNewValue("full_paid_at")

А выражения проверки, что заказ оплачен, вида

order.getPaymentStatus() && order.getPaymentStatus().getCode() == 'paid'

нужно заменять на выражения вида

order.fullPaidAt

2. [Требуется корректировать ПОСЛЕ обновления] Проверку данных платежа в заказе нужно корректировать с учетом того, что оплаты теперь являются коллекцией

Выражения вида

order.getPaymentType() and
order.getPaymentType().getCode() in [ "cash", "bank-card-courier", "bank-card-office", "axiomus", "posthub" ]

нужно заменять на выражения:

а) если хотя бы одна из оплат в заказе указанного типа:

order.payments | contains( item => item.type.code in [ "cash", "bank-card-courier", "bank-card-office", "axiomus", "posthub" ] )

б) если все оплаты заказа указанного типа:

order.payments | every( item => item.type.code in [ "cash", "bank-card-courier", "bank-card-office", "axiomus", "posthub" ] )

API

В старых версиях API мы постарались сохранить максимальную совместимость, которая будет выполняться пока вы не начнете добавлять второй и более платеж в заказ. Как только вы решите работать с мультиоплатами в retailCRM, вам предварительно потребуется перейти на API v5.

1. В /api/v5/orders и /api/v5/orders/get возвращается коллекция платежей order[payments][].

2. Для добавления платежа в заказ появился новый API-метод /api/v5/orders/payments/create, для редактирования — /api/v5/orders/payments/{id}/edit, для удаления — /api/v5/orders/payments/{id}/delete

3. В версиях API v4 и ниже структура данных не изменилась, но данные по оплате заказа возвращаются, только если в заказе одна оплата либо оплат несколько, но только одна из них неоплаченная, в противном случае будут приходить пустые поля. Редактирование оплаты также возможно только, пока ее нет или она одна в заказе.

4. В /api/v*/orders/history истории заказа больше не возвращаются изменения поля order.prepaySum, так как теперь это только сумматор сумм оплаченных платежей

Скидки и округление

Изменения в работе со скидками

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

Покажем на примере. Допустим есть следующий заказ:

| Название |    Цена | Скидка            | Кол-во |    Итого |
|          |         |                   |        |          |
| Шорты    | 600 руб | 50 руб (на товар) |      2 | 1100 руб |
|          |         |                   |        |          |
| Сланцы   | 300 руб |  0 руб (на товар) |      3 |  900 руб |
|                                                 |          |
| Итого                                           | 2000 руб |

Мы дали скидку на заказ 300 рублей.

В версии системы 5.0 и ниже данная скидка будет учтена в общей стоимости заказа:

| Название |    Цена | Скидка            | Кол-во |    Итого |
|          |         |                   |        |          |
| Шорты    | 600 руб | 50 руб (на товар) |      2 | 1100 руб |
|          |         |                   |        |          |
| Сланцы   | 300 руб |  0 руб (на товар) |      3 |  900 руб |
|                                                 |          |
| Скидка на заказ                                 |  300 руб |
|                                                 |          |
| Итого                                           | 1700 руб |

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

| Название |    Цена | Скидка            | Кол-во |    Итого |
|          |         |                   |        |          |
| Шорты    | 600 руб | 50 руб (на товар) |      2 |  980 руб |
|          |         | 60 руб (на заказ) |        |          |
|          |         |                   |        |          |
| Сланцы   | 300 руб |  0 руб (на товар) |      3 |  720 руб |
|          |         | 60 руб (на заказ) |        |          |
|                                                 |          |
| Итого                                           | 1700 руб |

Стоимость заказа в таком случае рассчитывается так: (600 – 50 – 60) x 2 + (300 – 60) x 3 = 1700

API

API v4

В API v4 поля скидок order[discount], order[discountPercent], order[items][][discount], order[items][][discountPercent] в заказе остаются без изменений и доступны как на запись, так и на чтение.

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

order = {
    // ...
    "discount": 300,
    "items": [
        {
            "offer": { "externalId": "1" },
            "initialPrice": 600,
            "discount": 50,
            "quantity": 2
        },
        {
            "offer": { "externalId": "2" },
            "initialPrice": 300,
            "quantity": 3
        }
    ],
    // ...
}

В API-методах получения заказов состав и значения полей будут аналогичными:

{
    // ...
    "discount": 300,
    "items": [
        {
            "offer": { "externalId": "1" },
            "initialPrice": 600,
            "discount": 50,
            "quantity": 2
        },
        {
            "offer": { "externalId": "2" },
            "initialPrice": 300,
            "quantity": 3
        }
    ],
    // ...
}

API v5

В методах создания и редактирования заказа /api/v5/orders/create, /api/v5/orders/{externalId}/edit, /api/v5/orders/upload можно передавать скидки на заказ и товары в полях order[discountManualAmount], order[discountManualPercent], order[items][][discountManualAmount], order[items][][discountManualPercent], при этом скидки на заказ будут распределяться между товарами.

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

order = {
    // ...
    "discountManualAmount": 300,
    "items": [
        {
            "offer": { "externalId": "1" },
            "initialPrice": 600,
            "discountManualAmount": 50,
            "quantity": 2
        },
        {
            "offer": { "externalId": "2" },
            "initialPrice": 300,
            "quantity": 3
        }
    ],
    // ...
}

В методах получения заказов /api/v5/orders, /api/v5/orders/{externalId} возвращается итоговая расчетная денежная скидка на единицу товара для каждой позиции товара в поле order[items][][discountTotal], которая учитывает и скидки на текущий товар, и скидки на заказ, распределенные между товарами.

{
    // ...
    "items": [
        {
            "offer": { "externalId": "1" },
            "initialPrice": 600,
            "discountTotal": 110,
            "quantity": 2
        },
        {
            "offer": { "externalId": "2" },
            "initialPrice": 300,
            "discountTotal": 60,
            "quantity": 3
        }
    ],
    // ...
}

Триггеры и шаблоны

В объекте OrderProduct поля OrderProduct.discount и OrderProduct. discountPercent теперь считаются устаревшими. Нужно использовать поле OrderProduct. discountTotal, которое возвращает итоговую денежную скидку на единицу товара c учетом всех скидок на товар и заказ. При обращении к полю OrderProduct.discount будет возвращено значение поля OrderProduct.discountTotal, при обращении к полю OrderProduct.discountPercent — будет всегда возвращаться 0.

Крайние случаи при распределении скидки на заказ между товарами

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

Допустим, есть заказ со следующим составом:

| Название |    Цена | Скидка            | Кол-во |    Итого |
|          |         |                   |        |          |
| Шорты    | 600 руб | –                 |      3 | 1800 руб |
|                                                 |          |
| Итого                                           | 1800 руб |

Мы добавляем скидку на заказ 10 рублей. Системе нужно распределить скидку заказа между всеми единицами товаров, которых в заказе 3 штуки.

По умолчанию при попытке указания такой скидки для заказа системой будет выдано сообщение об ошибке. Что важно, ошибка будет выдаваться, как если вы оформляете такой заказ в системе, так и через API, независимо от версии API.

Если же в системе включена настройка «Корректировать скидку на заказ» в разделе Настройки > Заказы, то система скорректирует скидку на заказ до ближайшего делимого значения (в данном случае изменит скидку на заказ с 10 рублей на 9,99 рублей).

Округление

В версии 6.0 добавлена функция округления, которую можно включить в разделе Настройки > Заказы. Округление, если его включить, применяется к позициям товаров в заказе. Та стоимость, что откидывается от суммы товара в результате округления, идет в скидку товара.

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


Редакция от 29.08.2018 09:30