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