Yandex Metrika
sanches.free 16 просмотров

Уведомления интернет-магазина Bitrix: письмо «новый заказ» вручную и штатные Notify

Система сама шлёт письмо о новом заказе, но если вы отменили отправку на этапе оформления (через события или свою логику), позже может понадобиться повторить событие SALE_NEW_ORDER — например, после онлайн-оплаты. В штатном API нет «короткого» вызова; ниже — разбор полей и аккуратная отправка через CEvent::Send с учётом того же хука, что использует ядро.

Ограничение по смыслу

Механика рассчитана на «свежий» заказ: массив полей совпадает с тем, что собирает ядро при первой отправке. Для отмены и оплаты есть отдельные обёртки — не подменяйте их произвольным текстом письма.

Ручная отправка SALE_NEW_ORDER

Класс ниже собирает корзину в текст списка, заполняет макроподстановки (номер, дата, пользователь, BCC, публичная ссылка для гостей) и перед отправкой отдаёт управление обработчикам EVENT_ON_ORDER_NEW_SEND_EMAIL. Если какой-то модуль вернёт стоп — письмо не уходит. Обратите внимание: переменная $eventName и разделитель строк корзины должны быть заданы явно (в исходных сниппетах это часто опускали).

getBasket();
        if ($basketDeck) {
            $plainList = $basketDeck->getListOfFormatText();
            if (!empty($plainList)) {
                $glue = "\n";
                foreach ($plainList as $rowText) {
                    $ledgerRibbon .= $rowText . $glue;
                }
            }
        }

        $fields = [
            'ORDER_ID' => $purchase->getField('ACCOUNT_NUMBER'),
            'ORDER_REAL_ID' => $purchase->getField('ID'),
            'ORDER_ACCOUNT_NUMBER_ENCODE' => urlencode(urlencode($purchase->getField('ACCOUNT_NUMBER'))),
            'ORDER_DATE' => $purchase->getDateInsert()->toString(),
            'ORDER_USER' => self::resolveBuyerName($purchase),
            'PRICE' => \SaleFormatCurrency($purchase->getPrice(), $purchase->getCurrency()),
            'BCC' => Option::get('sale', 'order_email', 'order@' . ($_SERVER['SERVER_NAME'] ?? '')),
            'EMAIL' => self::resolveBuyerEmail($purchase),
            'ORDER_LIST' => $ledgerRibbon,
            'SALE_EMAIL' => Option::get('sale', 'order_email', 'order@' . ($_SERVER['SERVER_NAME'] ?? '')),
            'DELIVERY_PRICE' => $purchase->getDeliveryPrice(),
            'ORDER_PUBLIC_URL' => \Bitrix\Sale\Helpers\Order::isAllowGuestView($purchase)
                ? \Bitrix\Sale\Helpers\Order::getPublicLink($purchase)
                : '',
        ];

        $dispatch = true;
        $templateAlias = 'SALE_NEW_ORDER';

        foreach (\GetModuleEvents('sale', \Bitrix\Sale\Notify::EVENT_ON_ORDER_NEW_SEND_EMAIL, true) as $legacyHook) {
            if (\ExecuteModuleEventEx($legacyHook, [$purchase->getId(), &$templateAlias, &$fields]) === false) {
                $dispatch = false;
            }
        }

        $siteRow = SiteTable::getById($purchase->getSiteId())->fetch();

        if ($dispatch) {
            $mailer = new \CEvent();
            $mailer->Send(
                'SALE_NEW_ORDER',
                $purchase->getField('LID'),
                $fields,
                'Y',
                '',
                [],
                $siteRow['LANGUAGE_ID'] ?? ''
            );
        }
    }

    private static function resolveBuyerEmail(Order $purchase): string
    {
        $mailbox = '';
        $propsDeck = $purchase->getPropertyCollection();
        if ($propsDeck && ($cell = $propsDeck->getUserEmail())) {
            $mailbox = (string) $cell->getValue();
        }
        if ($mailbox === '') {
            $u = UserTable::getList([
                'select' => ['EMAIL'],
                'filter' => ['=ID' => $purchase->getUserId()],
            ])->fetch();
            $mailbox = (string)($u['EMAIL'] ?? '');
        }
        return $mailbox;
    }

    private static function resolveBuyerName(Order $purchase): string
    {
        $alias = '';
        $propsDeck = $purchase->getPropertyCollection();
        if ($propsDeck && ($cell = $propsDeck->getPayerName())) {
            $alias = (string) $cell->getValue();
        }
        if ($alias === '') {
            $u = UserTable::getList([
                'select' => ['ID', 'LOGIN', 'NAME', 'LAST_NAME', 'SECOND_NAME', 'EMAIL'],
                'filter' => ['=ID' => $purchase->getUserId()],
            ])->fetch();
            if ($u) {
                $alias = \CUser::FormatName(
                    \CSite::GetNameFormat(null, $purchase->getSiteId()),
                    $u,
                    true
                );
            }
        }
        return $alias;
    }
}

Вызов: \Acme\Sale\NotifyManualPulse::sendOrderNew($order); при уже загруженном Order.

Отмена и оплата

Для штатных текстов «заказ отменён» и «заказ оплачен» используйте API модуля — при этом соблюдаются внутренние проверки «отправить можно один раз» и только при корректном статусе:

$purchase = \Bitrix\Sale\Order::load(9184);
\Bitrix\Sale\Notify::sendOrderCancel($purchase);

$purchase = \Bitrix\Sale\Order::load(9184);
\Bitrix\Sale\Notify::sendOrderPaid($purchase);
  • Отмена имеет смысл только для реально отменённого заказа.
  • Для тонкой настройки шаблонов и подстановок смотрите также материалы про почтовые события и дополнительные поля писем заказа в том же разделе.

Не хотите копаться сами?

Починю за 1-3 дня. Без предоплаты — оплата по результату.

15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии