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