При настройке обмена данными между конфигурациями 1С с помощью «Конвертации данных 2.0» часто возникает задача контроля целостности данных. Типичный сценарий: при загрузке документов (например, Поступление товаров и услуг) необходимо убедиться, что вся номенклатура, указанная в документе, существует в базе-приемнике. Если элемент не найден, процесс должен быть остановлен, а пользователю выведено информативное сообщение с данными из базы-источника. Разберем пошагово, как реализовать этот механизм, используя обработчики событий и глобальные параметры.
Для того чтобы информация о ненайденных объектах была доступна на разных этапах загрузки, нам необходимо инициализировать таблицу значений в глобальных параметрах конвертации. Это позволит нам не только выводить сообщения, но и принимать решение об отмене загрузки всего пакета данных.
Перейдем в дерево правил на вкладку «Алгоритмы/Запросы» и выберем глобальный обработчик «Перед загрузкой данных». Пропишем инициализацию таблицы:
// Создаем таблицу для фиксации ошибок поиска
ТаблицаОшибокПоиска = Новый ТаблицаЗначений;
ТаблицаОшибокПоиска.Колонки.Добавить("КодИсточника");
ТаблицаОшибокПоиска.Колонки.Добавить("НаименованиеИсточника");
ТаблицаОшибокПоиска.Колонки.Добавить("ТипОбъекта");
// Помещаем таблицу в параметры, чтобы она была доступна везде
Параметры.Вставить("ОшибкиЗагрузки", ТаблицаОшибокПоиска);
Параметры.Вставить("ПрерватьЗагрузкуИзЗаОшибок", Ложь);
Также важно убедиться, что параметр добавлен на вкладке «Параметры» самой конвертации с установленной галочкой «При загрузке».
Часто поля, по которым идет поиск (например, уникальный идентификатор или артикул), неинформативны для пользователя. Нам нужно передать «читаемые» данные (наименование, код) из источника в приемник, даже если они не участвуют в сопоставлении. Рассмотрим использование структуры ВходящиеДанные в ПКО (Правило конвертации объектов) Номенклатуры.
В обработчике «Перед выгрузкой» для ПКО Номенклатура сформируем дополнительные данные:
// Передаем данные для информационных сообщений в приемник
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("НаименованиеДляЛога", Источник.Наименование);
СтруктураДанных.Вставить("КодДляЛога", Источник.Код);
ВходящиеДанные = СтруктураДанных;
Теперь проанализируем самый важный этап — поиск объекта в приемнике. Основная работа будет происходить в обработчике «Поля поиска» ПКО Номенклатура. Нам нужно самостоятельно проверить наличие объекта и, если он не найден, записать информацию в нашу таблицу ошибок.
Рассмотрим пример кода, который выполняет поиск по коду, а при неудаче — фиксирует ошибку:
// Пытаемся найти объект стандартным способом по коду
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Ссылка
|ИЗ
| Справочник.Номенклатура
|ГДЕ
| Код = &Код И ЭтоГруппа = &ЭтоГруппа";
Запрос.УстановитьПараметр("Код", СвойстваПоиска["Код"]);
Запрос.УстановитьПараметр("ЭтоГруппа", СвойстваПоиска["ЭтоГруппа"]);
РезультатПоиска = Запрос.Выполнить().Выбрать();
Если РезультатПоиска.Следующий() Тогда
СсылкаНаОбъект = РезультатПоиска.Ссылка;
Иначе
// Объект не найден в приемнике!
// Получаем данные, переданные через ВходящиеДанные
КодИст = "";
НаимИст = "";
Если ВходящиеДанные <> Неопределено Тогда
ВходящиеДанные.Свойство("КодДляЛога", КодИст);
ВходящиеДанные.Свойство("НаименованиеДляЛога", НаимИст);
КонецЕсли;
// Добавляем запись в нашу глобальную таблицу ошибок
НоваяСтрока = Параметры.ОшибкиЗагрузки.Добавить();
НоваяСтрока.КодИсточника = ?(ЗначениеЗаполнено(КодИст), КодИст, СвойстваПоиска["Код"]);
НоваяСтрока.НаименованиеИсточника = НаимИст;
НоваяСтрока.ТипОбъекта = "Номенклатура";
// Устанавливаем флаг критической ошибки
Параметры.ПрерватьЗагрузкуИзЗаОшибок = Истина;
// Сообщаем системе, что поиск завершен (объект не найден)
СсылкаНаОбъект = Неопределено;
ПрекратитьПоиск = Истина;
КонецЕсли;
Важный нюанс: использование ПрекратитьПоиск = Истина и СсылкаНаОбъект = Неопределено гарантирует, что система не будет пытаться создать новый объект, если в правилах стоит настройка «Не создавать новых объектов».
Выясним, как остановить процесс загрузки всех последующих документов, если хотя бы одна номенклатура не была найдена. Для этого воспользуемся глобальным обработчиком «Перед загрузкой объекта».
Проанализируем ситуацию: если наш флаг Параметры.ПрерватьЗагрузкуИзЗаОшибок установлен в значение Истина, мы должны запретить загрузку любых последующих объектов.
Если Параметры.ПрерватьЗагрузкуИзЗаОшибок Тогда
Отказ = Истина;
// Можно вывести сообщение в журнал регистрации или в окно сообщений
Сообщить("Загрузка объекта " + ТипЗнч(Объект) + " отменена из-за отсутствия нормативно-справочной информации.");
КонецЕсли;
Если же стоит задача прервать загрузку немедленно и полностью (откатив транзакцию), можно использовать более жесткий метод в обработчике «При загрузке» или «Поля поиска»:
Если ОбъектНеНайден Тогда
ВызватьИсключение "Критическая ошибка: Номенклатура '" + НаимИст + "' не найдена. Загрузка прервана.";
КонецЕсли;
Однако стоит помнить, что ВызватьИсключение прервет выполнение обработки немедленно, и финальные сообщения могут не успеть вывестись в удобном виде. Поэтому вариант с установкой флага Отказ = Истина в обработчике «Перед загрузкой объекта» является более гибким.
После завершения цикла загрузки (или попытки загрузки) нам нужно показать пользователю список всех проблемных элементов. Рассмотрим обработчик «После загрузки данных». Этот код выполнится один раз в самом конце.
Если Параметры.ОшибкиЗагрузки.Количество() > 0 Тогда
Сообщить("--- ОШИБКИ ЗАГРУЗКИ: НЕ НАЙДЕНЫ ЭЛЕМЕНТЫ В ПРИЕМНИКЕ ---");
Для Каждого СтрОшибка Из Параметры.ОшибкиЗагрузки Цикл
ТекстСообщения = СтрШаблон("Тип: %1, Код источника: %2, Название: %3",
СтрОшибка.ТипОбъекта,
СтрОшибка.КодИсточника,
СтрОшибка.НаименованиеИсточника);
Сообщить(ТекстСообщения);
КонецЦикла;
Сообщить("---------------------------------------------------------");
КонецЕсли;
ПослеЗагрузки. Выполните обход табличной части «Товары» и проверьте Строка.Номенклатура.Пустая(). Если ссылка пустая, установите Отказ = Истина для всего документа.Сообщить() используйте метод ЗаписьЖурналаРегистрации(). Это позволит администратору базы найти причину ошибки, даже если сеанс обмена был закрыт.Таким образом, мы построили надежную систему контроля: собираем данные об отсутствующих объектах через ВходящиеДанные, фиксируем их в глобальной ТаблицеЗначений в обработчике Поля поиска и блокируем дальнейшую загрузку через флаг в обработчике Перед загрузкой объекта. Этот подход минимизирует появление документов с «пустыми» реквизитами в базе-приемнике.