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