Как реализовать отбор в списке документов по условию «ИЛИ» (Касса или Касса-получатель) в обычных формах 1С?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

В процессе разработки в среде «1С:Предприятие» на обычных формах программисты часто сталкиваются с аппаратным ограничением платформы при работе с элементом управления ДокументСписок (или ЖурналДокументовСписок). Стандартный механизм отборов в обычных формах связывает все добавляемые поля исключительно по логическому условию «И». Но что делать, если перед нами стоит задача отобразить документы, в которых заданная касса пользователя может быть как кассой-отправителем (реквизит Касса), так и кассой-получателем (реквизит КассаПолучатель)?

В рамках этой статьи мы подробно разберем пять практических методов решения этой задачи, проанализируем их плюсы, минусы и особенности реализации.

Способ 1. Использование встроенного механизма «Критерии отбора»

Это наиболее нативный, быстрый и производительный метод, предусмотренный самой платформой «1С:Предприятие» для обхода ограничения логического «ИЛИ».

Разберем по шагам, как настроить этот механизм в конфигураторе:

  1. Создадим новый объект метаданных в ветке «Критерии отбора» (например, назовем его ДокументыПоКассе).
  2. На вкладке «Данные» укажем тип значения, по которому будет производиться фильтрация. В нашем случае это СправочникСсылка.Кассы.
  3. Перейдем на вкладку «Состав». Здесь нам необходимо отметить галочками те реквизиты документов, по которым платформа будет осуществлять поиск. Находим документ ВнутреннееПеремещениеНаличныхДенежныхСредств и отмечаем реквизиты Касса и КассаПолучатель.

Как это работает на уровне СУБД? Платформа автоматически сформирует оптимизированный поисковый запрос к базе данных, связав выбранные реквизиты по условию «ИЛИ» с использованием существующих индексов. Чтобы вывести этот список пользователю, достаточно программно открыть форму критерия отбора, передав туда в качестве параметра текущую основную кассу пользователя.

Способ 2. Переход на управляемую форму списка в обычном приложении

Если конфигурация работает в режиме совместимости, позволяющем использовать управляемые формы в обычном приложении, мы можем заменить стандартную обычную форму списка документов на управляемую.

В управляемых формах за вывод списков отвечает объект ДинамическийСписок, работающий на базе системы компоновки данных (СКД). СКД без проблем поддерживает группировку условий отбора по логическому «ИЛИ».

Рассмотрим пример программной настройки такого отбора при создании формы на сервере:


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

Этот способ является наиболее гибким, так как позволяет динамически изменять условия прямо в пользовательском интерфейсе.

Способ 3. Запрос + отбор по списку ссылок (с оптимизацией)

На форумах часто критикуют подход, при котором сначала запросом выбираются нужные документы, а затем их массив передается в отбор списка с видом сравнения ВидСравнения.ВСписке. Основной аргумент против — низкая производительность при росте базы данных.

Однако этот метод вполне жизнеспособен, если внедрить в него обязательные правила оптимизации:

  1. Ограничение по периоду: Никогда не делайте запрос по всей базе данных. Ограничьте выборку разумным интервалом (например, текущий месяц или квартал).
  2. Лимитирование выборки: Используйте конструкцию ПЕРВЫЕ N в тексте запроса, чтобы не перегружать оперативную память клиента, если документов окажется слишком много.
  3. Индексация полей: Убедитесь, что для реквизитов Касса и КассаПолучатель в свойствах метаданных документа установлено значение «Индексировать» или «Индексировать с дополнительным упорядочиванием». Без индексов СУБД будет выполнять полное сканирование таблицы (Table Scan), что приведет к сильным зависаниям.

Проанализируем пример реализации такого подхода в модуле обычной формы списка:


Процедура УстановитьОтборПоКассам()
    
    ОсновнаяКасса = ПолучитьОсновнуюКассуПользователя();
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1000
        |	Док.Ссылка КАК Ссылка
        |ИЗ
        |	Документ.ВнутреннееПеремещениеНаличныхДенежныхСредств КАК Док
        |ГДЕ
        |	Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
        |	И (Док.Касса = &ОсновнаяКасса ИЛИ Док.КассаПолучатель = &ОсновнаяКасса)";
        
    Запрос.УстановитьПараметр("ОсновнаяКасса", ОсновнаяКасса);
    // Ограничиваем выборку последними 3 месяцами для быстродействия
    Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДобавитьМесяц(ТекущаяДата(), -3)));
    Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
    
    ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
    МассивСсылок = ТаблицаРезультата.ВыгрузитьКолонку("Ссылка");
    
    // Применяем отбор к стандартному списку документов обычной формы
    ОтборСсылка = ДокументСписок.Отбор.Ссылка;
    ОтборСсылка.ВидСравнения = ВидСравнения.ВСписке;
    ОтборСсылка.Значение.Очистить();
    Для Каждого Ссылка Из МассивСсылок Цикл
        ОтборСсылка.Значение.Добавить(Ссылка);
    КонецЦикла;
    ОтборСсылка.Использование = Истина;
    
КонецПроцедуры

Способ 4. Реализация через вспомогательный Регистр Сведений

Для крупных высоконагруженных систем отличным архитектурным решением станет денормализация данных с использованием вспомогательного регистра.

Разберем алгоритм его проектирования:

  1. Создаем непериодический независимый регистр сведений СвязиДокументовИКасс.
  2. Определяем измерения: Касса (тип СправочникСсылка.Кассы) и Документ (тип ДокументСсылка.ВнутреннееПеремещениеНаличныхДенежныхСредств).
  3. В модуле документа в обработчиках событий записи или проведения пишем логику: при сохранении документа формируются две записи в этот регистр (одна для кассы-отправителя, вторая для кассы-получателя).
  4. На форме списка документов мы можем наложить отбор, связав отображаемый список с записями этого регистра. Сделать отбор по одной кассе в данном регистре будет максимально просто и быстро, так как поле Касса является проиндексированным измерением.

Способ 5. Ограничение доступа на уровне записей (RLS)

Механизм RLS (Row Level Security) часто упоминается как самый надежный способ решения подобных задач, особенно если цель заключается в физическом сокрытии данных от пользователя из соображений безопасности.

Однако при использовании RLS для отбора по «ИЛИ» нужно учитывать критически важные нюансы:

Таким образом, использовать RLS следует исключительно в тех случаях, когда это обусловлено жесткими требованиями информационной безопасности компании, а не просто желанием отфильтровать интерфейс для удобства пользователя.

← На главную