В процессе разработки интеграций между различными базами 1С, например, между центральной базой и мобильным приложением, программисты часто сталкиваются с тем, что документы, прилетающие через Web-сервисы или XML-обмен, ведут себя «тихо». Документ появляется в базе, он может даже иметь статус Проведен, но связанные с ним подписки на события или логика в модуле объекта не отрабатывают. Разберем подробно, почему так происходит и какие механизмы платформы 1С на это влияют.
Проанализируем базовый механизм работы платформы. В 1С статус документа Проведен — это системный реквизит булевого типа. При обмене данными, особенно через XDTO или ручной парсинг XML, часто происходит простая загрузка свойств. Если в пакете данных стоит признак того, что документ проведен, платформа просто записывает это значение в базу данных.
Важный нюанс: событие ОбработкаПроведения (и все соответствующие подписки на него) вызывается исключительно в том случае, если документ записывается с явным указанием режима: Объект.Записать(РежимЗаписиДокумента.Проведение). Если же выполняется обычный метод Объект.Записать(), даже если свойство Проведен установлено в Истина, платформа не запускает механизм формирования движений и не инициирует события проведения. Мы получаем «мертворожденный» документ: флаг стоит, а действий нет.
Рассмотрим основной механизм, который отключает логику при обменах — свойство ОбменДанными.Загрузка. По умолчанию во многих типовых и самописных механизмах загрузки этому свойству присваивается значение Истина. Это делается для того, чтобы объект записался «как есть», без лишних проверок заполнения и дополнительных расчетов.
Однако установка этого флага имеет критические последствия для проведения:
Проведение. Если вы попытаетесь выполнить Объект.Записать(РежимЗаписиДокумента.Проведение) при установленном ОбменДанными.Загрузка = Истина, система выдаст ошибку, так как проведение подразумевает расчеты, которые в режиме загрузки запрещены.
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Даже если проверка в коде отсутствует (как в случае автора темы), само платформенное ограничение не даст выполнить полноценное проведение в момент загрузки данных.
Выясним, как правильно организовать загрузку документа через Web-сервис, чтобы все подписки сработали. Правильный алгоритм должен состоять из двух этапов: сначала мы создаем объект в базе «как данные», а затем инициируем его проведение как бизнес-событие.
Рассмотрим пример кода, который стоит использовать в методе Web-сервиса:
// 1. Создаем или находим документ, заполняем реквизиты
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// ... заполнение данных из XDTO ...
// 2. Записываем объект в режиме загрузки, чтобы он просто появился в БД
НовыйДокумент.ОбменДанными.Загрузка = Истина;
НовыйДокумент.Записать();
// 3. Теперь, если документ должен быть проведен, проводим его отдельно
Если ДолженБытьПроведен Тогда
// Важно: создаем новый объект или сбрасываем флаг загрузки
ДокументОбъект = НовыйДокумент.Ссылка.ПолучитьОбъект();
ДокументОбъект.ОбменДанными.Загрузка = Ложь;
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
ЗаписьЖурналаРегистрации("Обмен.ОшибкаПроведения", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
В этом случае при выполнении метода Записать(РежимЗаписиДокумента.Проведение) платформа честно запустит процедуру ОбработкаПроведения и все связанные подписки на событие.
Если специфика обмена не позволяет выполнять полноценное проведение (например, из-за неполноты данных для формирования движений в момент загрузки), проанализируем альтернативный вариант, к которому пришел автор темы. Это использование события ПриЗаписи.
Событие ПриЗаписи срабатывает всегда, когда вызывается метод Записать(), независимо от режима (Запись, Проведение или ОтменаПроведения). Однако здесь кроется ловушка: это событие может срабатывать слишком часто. Чтобы логика (например, выгрузка в XML) не дублировалась, добавим проверку состояния документа.
Пример кода для подписки на событие ПриЗаписи:
Процедура ПодпискаПриЗаписи(Источник, Отказ) Экспорт
// Если это загрузка данных, обычно мы ничего не выгружаем обратно
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Проверяем, что документ проведен и это именно запись проведенного документа
Если Источник.Проведен Тогда
// Выполняем нашу логику (например, выгрузку в XML)
ВыгрузитьДокументВXML(Источник);
КонецЕсли;
КонецПроцедуры
Обратите внимание: использование ПриЗаписи вместо ОбработкаПроведения оправдано, если вам нужно реагировать на факт появления проведенного документа в базе, даже если само "таинство" проведения (расчет регистров) не совершалось в текущем сеансе.
Посмотрим на технические настройки модулей. Если обмен идет через Web-сервис или COM-соединение, крайне важно проверить свойства общего модуля, в котором находится процедура подписки. Должны быть установлены флаги:
Также проанализируем использование инструкций препроцессора. Если код обернут в #Если Клиент Тогда, то при вызове через Web-сервис он просто будет проигнорирован, так как контекст исполнения — серверный.
Если вы не хотите менять режим записи и не хотите переносить логику в другое событие, можно рассмотреть вариант прямого вызова процедуры из модуля объекта. Рассмотрим, как это сделать:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Основная логика проведения
// ...
// Принудительный вызов логики, которая обычно живет в подписке
МойОбщийМодульИнтеграция.ВыполнитьВыгрузкуПослеПроведения(ЭтотОбъект);
КонецПроцедуры
Этот способ менее изящен, так как нарушает принцип слабой связанности (модуль объекта начинает "знать" о модуле интеграции), но он гарантирует выполнение кода даже при программной записи, если вы вызываете проведение вручную.
Подведем итог нашему разбору. Если после обмена не срабатывает подписка на проведение, выполните следующие шаги:
РежимЗаписиДокумента.Проведение, а не просто Записать().ОбменДанными.Загрузка — если он Истина, проведение не запустится платформенно.ПриЗаписи с обязательной фильтрацией по Источник.Проведен.Правильное управление режимами записи и понимание жизненного цикла объекта в 1С при обмене данными — залог стабильной работы распределенных систем.