Статусы заказов - смена из кода, события и сопоставление с 1С
Меняем статус заказа из кода, ловим смену обработчиком и разбираемся, почему статус не приезжает из 1С.
Решение
Смотрим список статусов и их внешние коды:
$statuses = CSaleStatus::GetList(['SORT' => 'ASC'], [], false, false, ['ID', 'NAME', 'XML_ID', 'SORT']);while ($status = $statuses->Fetch()) { printf("%-4s %-24s xml_id=%s\n", $status['ID'], $status['NAME'], $status['XML_ID'] ?: 'ПУСТО');}Идентификатор статуса - строка, а не число: N для нового, F для выполненного
и свои коды для остальных. Внешний код нужен только обмену, витрине он не виден,
а сортировка задаёт порядок в выпадающем списке менеджера.
Меняем статус объектом заказа:
$order = Bitrix\Sale\Order::load($orderId);$result = $order->setField('STATUS_ID', 'P'); // запускает события и пересчётыif (!$result->isSuccess()) { throw new RuntimeException(implode('; ', $result->getErrorMessages()));}$order->save();Прямая запись поля в базу статус тоже поменяет, но не запустит ни почтовых событий, ни обработчиков. Письмо покупателю не уйдёт, и учётная система о смене не узнает.
Ловим смену статуса обработчиком:
Bitrix\Main\EventManager::getInstance()->addEventHandler( 'sale', 'OnSaleStatusOrderChange', static function (Bitrix\Main\Event $event) { $order = $event->getParameter('ENTITY'); $value = $event->getParameter('VALUE'); // новый статус // здесь свои действия: уведомление, запись в журнал, вызов внешнего API });Событие приходит уже после проверки прав и валидации, но до сохранения. Долгие операции в нём держать нельзя: они удлиняют сохранение заказа для покупателя.
Проверяем, что вернулось из обмена:
$order = Bitrix\Sale\Order::load($orderId);printf("статус %s, версия 1С %s, побывал в обмене: %s\n", $order->getField('STATUS_ID'), $order->getField('VERSION_1C') ?: '-', $order->getField('UPDATED_1C'));Заполненная версия при неизменившемся статусе означает, что обмен заказ видел, а статус не применил: сопоставление по внешнему коду не сошлось.
Сопоставление стоит проверять до запуска обмена в продакшене, а не после. Статусы заводят один раз, внешние коды им проставляют сразу, и дальше справочник не трогают. Переименование статуса безопасно, смена идентификатора - нет: на него ссылается и код сайта, и узел обмена.
Считаем заказы по каждому статусу:
$rows = Bitrix\Sale\Internals\OrderTable::getList([ 'select' => ['STATUS_ID', new Bitrix\Main\Entity\ExpressionField('CNT', 'COUNT(1)')], 'group' => ['STATUS_ID'],]);foreach ($rows as $row) { printf("%-4s %d\n", $row['STATUS_ID'], $row['CNT']);}Такая сводка сразу показывает застрявшие статусы: сотни заказов в промежуточном состоянии означают, что переход дальше никто не делает или он сломан. Смотреть её стоит регулярно, а не только при разборе жалобы.
Отдельная ловушка - права групп на статус. Статус, недоступный группе менеджера, в его списке не появится, и заказ будет выглядеть застрявшим. Проверять это стоит не под администратором, а под учётной записью того, кто работает с заказами.
Типичные проблемы
Статус сменился, а письмо покупателю не ушло.
Статус записан прямым запросом к базе. Почтовое событие отправляет штатный обработчик смены статуса, и мимо API заказа он не вызывается.
Статус из 1С не применяется.
У статуса на сайте пустой внешний код. Обмен сопоставляет статусы по XML_ID, а названия не использует вовсе.
Свой статус пропал после обновления платформы.
Статус заводился правкой таблицы, а не через интерфейс. Обновление приводит справочник статусов к своему виду и чужие строки не сохраняет.
Заказ выполнен, а отгрузка числится несобранной.
Статус заказа и состояние отгрузки - разные поля. Отгрузка меняется своими методами коллекции, и статус заказа её не двигает.
Частые вопросы
Чем статус заказа отличается от статуса отгрузки?
Статус заказа описывает сделку целиком, статус отгрузки - конкретную посылку. У заказа с двумя отгрузками свой статус один, а состояний отгрузки два, и меняются они независимо.
Как добавить свой статус?
Через интерфейс в разделе статусов заказа: там задаётся идентификатор, название, сортировка и права групп. Идентификатор выбирают латиницей и больше не меняют - на него ссылаются код и обмен.
Можно ли запретить переход между некоторыми статусами?
Штатно нет, порядок статусов не задаёт маршрут. Ограничение делают обработчиком на смене статуса: он сравнивает прежнее значение с новым и возвращает ошибку.
Почему статус меняется, а событие не приходит?
Событие OnSaleStatusOrderChange срабатывает только при смене через объект заказа. Массовые операции, написанные запросами к базе, его не вызывают.
Смежное
-
Заказы - оглавление подтемы
-
Настройка магазина по шагам: что за чем включать - место статусов в общей настройке
-
Свойства заказа - что ещё хранится в заказе
-
Обмен заказами с 1С - откуда приходят статусы
-
Каталог и продажи - заказ и его коллекции
-
Заказ из кода: чтение, поиск по номеру, изменение состава - работа с заказом через API
-
Статусы заказа при обмене: возврат из 1С - смена статуса учётной системой
-
Оплаты и отгрузки заказа: объекты, признаки, частичные операции - что стоит за признаками оплаты и отгрузки
-
Отмены и возвраты при обмене: что уезжает в учётную систему - почему отмена не статус
-
Резервирование товара: момент резерва, снятие, доступное количество - что происходит при отмене заказа
-
Уведомления покупателю: письма и SMS по статусам заказа - что уходит покупателю при смене
-
Перенос заказов и клиентов со старого сайта: порядок и сверка - сопоставление чужих статусов
-
Уведомления менеджеру: письмо, чат, эскалация по времени - напоминания о заказах в первом статусе