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