События оформления заказа - свои проверки, запрет и допданные
Вмешиваемся в оформление заказа: добавляем свои проверки, дописываем данные и разбираемся, почему обработчик иногда срабатывает не тогда, когда ожидалось.
Решение
Подключаем обработчик события заказа:
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler('sale', 'OnSaleOrderBeforeSaved', ['\\Vendor\\OrderRules', 'beforeSaved']);// событие поднимается и при оформлении, и при правке заказа в админкеСобытие срабатывает на любом сохранении заказа, а не только при оформлении покупателем. Правка менеджером и обмен с учётной системой поднимают его так же, и проверка, рассчитанная на витрину, начинает мешать работе склада.
Запрещаем заказ с понятным сообщением:
public static function beforeSaved(\Bitrix\Main\Event $event): \Bitrix\Main\EventResult{ $order = $event->getParameter('ENTITY'); if ($order->getPrice() < 1000 && $order->getField('DELIVERY_ID') == 3) { return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, [ 'ERROR' => new \Bitrix\Main\Error('Курьером доставляем от 1000 рублей'), ]); } return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);}Отказ возвращается результатом самого события, а не исключением. Текст ошибки при этом попадает на страницу оформления, и покупатель понимает, что именно нужно поменять в заказе.
Дописываем свои данные до сохранения:
$props = $order->getPropertyCollection();foreach ($props as $prop) { if ($prop->getField('CODE') === 'SOURCE') { $prop->setValue($_COOKIE['utm_source'] ?? 'direct'); // источник заказа }}Свои значения кладут в свойства заказа до его сохранения. Запись после сохранения означает второй заход в базу и второе срабатывание событий, а на обмене такой заказ уезжает без ваших данных.
Уносим тяжёлое из оформления:
// в обработчике только пометка, работа - отдельным заданиемCAgent::AddAgent('\\Vendor\\Crm::pushNewOrders();', 'main', 'N', 60);// вызов внешней системы прямо здесь задержит покупателя на её таймаут// агент с периодом в минуту разбирает накопленное и переживает отказы сетиОбработчик выполняется в том же запросе, что и оформление. Обращение к внешней системе прямо в нём добавляет к ожиданию покупателя всё её время ответа, а её недоступность превращает в отказ оформления.
Проверки стоит держать рядом с их причиной, а не размазывать по коду. Условие доставки живёт в ограничениях службы, условие оплаты - в платёжной системе, и в обработчик попадает только то, чему в настройках места нет.
Событие после сохранения годится для уведомлений, а до сохранения - для проверок и правок. Перепутанный порядок даёт знакомую картину: письмо ушло, а заказ не сохранился.
Обработчик обязан спокойно переживать повторный вызов. Заказ пересохраняется при оплате, отгрузке и правке менеджером, и код, который добавляет позицию или шлёт письмо без проверки, делает это каждый раз.
Типичные проблемы
Менеджер не может сохранить заказ в админке.
Проверка, написанная для витрины, срабатывает и при правке из административной части. Событие поднимается при любом сохранении заказа, а не только при оформлении.
Покупатель видит пустую страницу вместо сообщения.
В обработчике брошено исключение вместо возврата ошибки. Текст ошибки доходит до формы оформления только через результат события.
Оформление стало долгим.
В обработчике идёт обращение к внешней системе. Оно выполняется в том же запросе и добавляет к ожиданию своё время.
Письмо уходит, а заказа нет.
Уведомление отправляется в событии до сохранения заказа. Для уведомлений берут событие после успешного сохранения.
Позиция добавляется в заказ дважды.
Обработчик не проверяет, сделал ли он это раньше. Заказ пересохраняется при оплате и отгрузке, и код срабатывает заново.
Частые вопросы
Как отличить оформление от правки менеджером?
По признаку нового заказа и по контексту запроса. Проверку для витрины ограничивают публичной частью.
Где регистрировать обработчик?
В файле с обработчиками своего решения. Регистрация в шаблоне страницы работает только на этой странице.
Можно ли поменять сумму заказа в обработчике?
Да, но осторожно: расчёт к этому моменту уже сделан. Надёжнее менять цену позиции правилом корзины.
Что делать, если внешняя система обязательна?
Ставить заказ в очередь и подтверждать позже. Синхронная зависимость от чужой доступности стоит потерянных заказов.
Смежное
- Оформление заказа - оглавление подтемы
- Своё поле в оформлении заказа: свойство, группа, свой тип - где заводят проверяемые поля
- Заказ из кода не сохраняется: разбор причин - когда обработчик отменяет заказ
- Оформление заказа: настройка компонента и правка шаблона - сам компонент оформления
- Обработчик события: регистрация, аргументы, отмена действия - как устроены события
- Вызов внешнего сервиса из кода: таймауты, повторы, журнал - куда выносить обращение наружу
- Каталог и продажи - устройство магазина целиком
- События корзины: подарки, ограничения, пересчёт - события на шаг раньше оформления
- Электронная торговля в аналитике: события, покупка, сверка - что отправляют после заказа