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