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

События при оплате заказа в Bitrix Sale D7: заказ и отдельный платёж

Два уровня — два события

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

Заказ: OnSaleOrderSaved

Обработчик получает \Bitrix\Main\Event. Полезные параметры: ENTITY — экземпляр \Bitrix\Sale\Order, VALUES — предыдущие значения полей. Реагировать имеет смысл только на переход флага «оплачен» из отрицательного состояния в Y; без сравнения с VALUES обработчик сработал бы на каждом сохранении уже оплаченного заказа.

Платёж: OnSalePaymentEntitySaved

Здесь ENTITY\Bitrix\Sale\Payment. Служебные «внутренние» операции обычно отсекают по \Bitrix\Sale\PaySystem\Manager::getInnerPaySystemId(). Для срабатывания на момент оплаты у конкретного платежа проверяют пару VALUES['PAID'] и текущее поле PAID, затем при необходимости поднимают $payment->getOrder() и getPaymentCollection().

Ниже — один класс с регистрацией обоих хендлеров; вызовите register() из init.php или загрузчика своего модуля.

namespace Acme\SaleHooks;

use Bitrix\Main\Event;
use Bitrix\Main\EventManager;
use Bitrix\Main\Loader;
use Bitrix\Sale\PaySystem\Manager;

final class LedgerPayPulse
{
    public static function register(): void
    {
        $hub = EventManager::getInstance();
        $hub->addEventHandler('sale', 'OnSaleOrderSaved', [self::class, 'onOrderSaved']);
        $hub->addEventHandler('sale', 'OnSalePaymentEntitySaved', [self::class, 'onPaymentSaved']);
    }

    public static function onOrderSaved(Event $signal): void
    {
        if (!Loader::includeModule('sale')) {
            return;
        }

        $purchase = $signal->getParameter('ENTITY');
        $priorFlags = $signal->getParameter('VALUES') ?? [];

        if (!$purchase instanceof \Bitrix\Sale\Order) {
            return;
        }

        if ($purchase->getField('PAYED') !== 'Y') {
            return;
        }

        if (($priorFlags['PAYED'] ?? '') !== 'N') {
            return;
        }

        /* PAYED: N → Y на уровне заказа */
    }

    public static function onPaymentSaved(Event $signal): void
    {
        if (!Loader::includeModule('sale')) {
            return;
        }

        $installment = $signal->getParameter('ENTITY');
        $priorFlags = $signal->getParameter('VALUES') ?? [];

        if (!$installment instanceof \Bitrix\Sale\Payment) {
            return;
        }

        if ((int) $installment->getField('PAY_SYSTEM_ID') === (int) Manager::getInnerPaySystemId()) {
            return;
        }

        if (($priorFlags['PAID'] ?? '') !== 'N' || $installment->getField('PAID') !== 'Y') {
            return;
        }

        $basketOrder = $installment->getOrder();
        /* PAID: N → Y у конкретного платежа; при необходимости — $basketOrder->getPaymentCollection() */
        /* далее своя логика */
    }
}

/* LedgerPayPulse::register(); */

Практические замечания

  • Оба события приходят после записи сущности; отмена оплаты — отдельная ветка полей и сценариев.
  • Тяжёлые интеграции лучше выносить в очередь или агента, чтобы не растягивать HTTP‑хит оплаты.
  • Соседние темы: события при создании и сохранении заказа и работа с платёжными системами — смотрите по ссылкам в материалах раздела магазина.

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

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

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