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