Почему не срабатывает подписка на событие ОбработкаПроведения после обмена и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки интеграций между различными базами 1С, например, между центральной базой и мобильным приложением, программисты часто сталкиваются с тем, что документы, прилетающие через Web-сервисы или XML-обмен, ведут себя «тихо». Документ появляется в базе, он может даже иметь статус Проведен, но связанные с ним подписки на события или логика в модуле объекта не отрабатывают. Разберем подробно, почему так происходит и какие механизмы платформы 1С на это влияют.

Причина 1: Различие между статусом Проведен и процессом проведения

Проанализируем базовый механизм работы платформы. В 1С статус документа Проведен — это системный реквизит булевого типа. При обмене данными, особенно через XDTO или ручной парсинг XML, часто происходит простая загрузка свойств. Если в пакете данных стоит признак того, что документ проведен, платформа просто записывает это значение в базу данных.

Важный нюанс: событие ОбработкаПроведения (и все соответствующие подписки на него) вызывается исключительно в том случае, если документ записывается с явным указанием режима: Объект.Записать(РежимЗаписиДокумента.Проведение). Если же выполняется обычный метод Объект.Записать(), даже если свойство Проведен установлено в Истина, платформа не запускает механизм формирования движений и не инициирует события проведения. Мы получаем «мертворожденный» документ: флаг стоит, а действий нет.

Причина 2: Влияние свойства ОбменДанными.Загрузка

Рассмотрим основной механизм, который отключает логику при обменах — свойство ОбменДанными.Загрузка. По умолчанию во многих типовых и самописных механизмах загрузки этому свойству присваивается значение Истина. Это делается для того, чтобы объект записался «как есть», без лишних проверок заполнения и дополнительных расчетов.

Однако установка этого флага имеет критические последствия для проведения:


Если ОбменДанными.Загрузка Тогда
    Возврат;
КонецЕсли;

Даже если проверка в коде отсутствует (как в случае автора темы), само платформенное ограничение не даст выполнить полноценное проведение в момент загрузки данных.

Решение проблемы через программное проведение

Выясним, как правильно организовать загрузку документа через Web-сервис, чтобы все подписки сработали. Правильный алгоритм должен состоять из двух этапов: сначала мы создаем объект в базе «как данные», а затем инициируем его проведение как бизнес-событие.

Рассмотрим пример кода, который стоит использовать в методе Web-сервиса:


// 1. Создаем или находим документ, заполняем реквизиты
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// ... заполнение данных из XDTO ...

// 2. Записываем объект в режиме загрузки, чтобы он просто появился в БД
НовыйДокумент.ОбменДанными.Загрузка = Истина;
НовыйДокумент.Записать();

// 3. Теперь, если документ должен быть проведен, проводим его отдельно
Если ДолженБытьПроведен Тогда
    // Важно: создаем новый объект или сбрасываем флаг загрузки
    ДокументОбъект = НовыйДокумент.Ссылка.ПолучитьОбъект();
    ДокументОбъект.ОбменДанными.Загрузка = Ложь;
    
    Попытка
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
    Исключение
        ЗаписьЖурналаРегистрации("Обмен.ОшибкаПроведения", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
    КонецПопытки;
КонецЕсли;

В этом случае при выполнении метода Записать(РежимЗаписиДокумента.Проведение) платформа честно запустит процедуру ОбработкаПроведения и все связанные подписки на событие.

Решение через изменение события подписки (ПриЗаписи)

Если специфика обмена не позволяет выполнять полноценное проведение (например, из-за неполноты данных для формирования движений в момент загрузки), проанализируем альтернативный вариант, к которому пришел автор темы. Это использование события ПриЗаписи.

Событие ПриЗаписи срабатывает всегда, когда вызывается метод Записать(), независимо от режима (Запись, Проведение или ОтменаПроведения). Однако здесь кроется ловушка: это событие может срабатывать слишком часто. Чтобы логика (например, выгрузка в XML) не дублировалась, добавим проверку состояния документа.

Пример кода для подписки на событие ПриЗаписи:


Процедура ПодпискаПриЗаписи(Источник, Отказ) Экспорт
    
    // Если это загрузка данных, обычно мы ничего не выгружаем обратно
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Проверяем, что документ проведен и это именно запись проведенного документа
    Если Источник.Проведен Тогда
        // Выполняем нашу логику (например, выгрузку в XML)
        ВыгрузитьДокументВXML(Источник);
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание: использование ПриЗаписи вместо ОбработкаПроведения оправдано, если вам нужно реагировать на факт появления проведенного документа в базе, даже если само "таинство" проведения (расчет регистров) не совершалось в текущем сеансе.

Проверка контекста выполнения: Внешнее соединение и Сервер

Посмотрим на технические настройки модулей. Если обмен идет через Web-сервис или COM-соединение, крайне важно проверить свойства общего модуля, в котором находится процедура подписки. Должны быть установлены флаги:

  1. Сервер — так как код Web-сервиса исполняется на стороне сервера.
  2. Внешнее соединение — если используется COM или специфические виды подключений.
  3. Вызов сервера — если планируется обращение к модулю из клиентского контекста.

Также проанализируем использование инструкций препроцессора. Если код обернут в #Если Клиент Тогда, то при вызове через Web-сервис он просто будет проигнорирован, так как контекст исполнения — серверный.

Принудительный вызов логики подписки

Если вы не хотите менять режим записи и не хотите переносить логику в другое событие, можно рассмотреть вариант прямого вызова процедуры из модуля объекта. Рассмотрим, как это сделать:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // Основная логика проведения
    // ...
    
    // Принудительный вызов логики, которая обычно живет в подписке
    МойОбщийМодульИнтеграция.ВыполнитьВыгрузкуПослеПроведения(ЭтотОбъект);
КонецПроцедуры

Этот способ менее изящен, так как нарушает принцип слабой связанности (модуль объекта начинает "знать" о модуле интеграции), но он гарантирует выполнение кода даже при программной записи, если вы вызываете проведение вручную.

Итоги и рекомендации

Подведем итог нашему разбору. Если после обмена не срабатывает подписка на проведение, выполните следующие шаги:

  1. Убедитесь, что в коде загрузки используется РежимЗаписиДокумента.Проведение, а не просто Записать().
  2. Проверьте флаг ОбменДанными.Загрузка — если он Истина, проведение не запустится платформенно.
  3. Проверьте свойства общего модуля (флаги "Сервер", "Внешнее соединение").
  4. Если проведение в момент обмена невозможно или избыточно, используйте подписку на ПриЗаписи с обязательной фильтрацией по Источник.Проведен.

Правильное управление режимами записи и понимание жизненного цикла объекта в 1С при обмене данными — залог стабильной работы распределенных систем.

← На главную