Как настроить отбор в динамическом списке по реквизиту табличной части в 1С 8.3

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

При разработке интерфейсов на управляемых формах в «1С:Предприятие 8.3» программисты часто сталкиваются с задачей фильтрации документов в списке по определенным критериям. Если отбор нужно сделать по стандартным реквизитам шапки (таким как дата, номер или контрагент), то проблем не возникает — платформа позволяет настроить их в два клика. Однако задача существенно усложняется, когда необходимо отфильтровать список документов по реквизиту, который находится внутри табличной части документа. Например, по дополнительной дате подачи или дате отправки строки.

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

В чем сложность отбора по табличной части?

Динамический список по умолчанию считывает данные из основной таблицы документа (его шапки). Если мы попытаемся напрямую наложить отбор по полю табличной части, система выдаст ошибку, так как этого поля просто нет в структуре данных списка. Для решения проблемы нам потребуется выполнить два основных шага:

  1. Перевести динамический список на работу с произвольным запросом и правильно связать его с табличной частью.
  2. Написать программный код для интерактивного выбора периода и установки отбора.

Рассмотрим весь процесс по шагам.

Шаг 1. Архитектурная настройка динамического списка

Для начала откроем форму списка документов в конфигураторе и выберем основной реквизит формы — Список (тип ДинамическийСписок). Проанализируем его свойства:

  1. В палитре свойств реквизита Список установим флаг Произвольный запрос.
  2. Нажмем на ссылку Открыть рядом с этим свойством, чтобы перейти в настройки списка.
  3. В открывшемся окне нажмем кнопку Конструктор запроса.

Важное предупреждение: Если мы просто добавим левое соединение таблицы документов с табличной частью во вкладке «Таблицы и связи», то в режиме предприятия строки документов в списке начнут дублироваться. Документ будет показан столько раз, сколько строк содержится в его табличной части. Это грубая ошибка проектирования интерфейса.

Чтобы избежать дублирования строк, мы воспользуемся механизмом компоновки данных. Выполним следующие действия в Конструкторе запроса:

  1. Перейдем на вкладку Компоновка данных.
  2. Выберем вкладку Условия.
  3. Перетащим поле ДатаВремяПодачи из нашей табличной части (например, Документ.арусТрансфер.Услуги) в список условий компоновки.

Платформа автоматически сгенерирует условие отбора по типу ГДЕ Ссылка В (ВЫБРАТЬ Ссылка ИЗ ... ГДЕ ...). Это позволит использовать поле табличной части в качестве параметра отбора, при этом сам список документов останется плоским, без дублирующихся строк.

Шаг 2. Подготовка интерфейса и реквизитов формы

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

Добавим новый реквизит формы:

После этого создадим команду формы, например, ПериодПодачи, и перетащим ее на командную панель формы в виде кнопки.

Шаг 3. Программный вызов диалога выбора периода

Разберем, как правильно реализовать открытие окна выбора периода в управляемом приложении. Начиная с платформы 8.3, рекомендуется использовать немодальные вызовы окон. Напишем код обработчика нашей команды на клиенте:


&НаКлиенте
Процедура ПериодПодачи(Команда)
    
    // Используем ранее созданный реквизит формы для хранения выбранных дат
    Диалог = Новый ДиалогРедактированияСтандартногоПериода;
    Диалог.Период = ВыбранныйПериодПодачи;
    
    // Задаем описание оповещения, которое сработает после закрытия диалога
    ОписаниеОповещения = Новый ОписаниеОповещения("ВыборПериодаЗавершение", ЭтаФорма);
    
    // Показываем диалог пользователю
    Диалог.Показать(ОписаниеОповещения);
    
КонецПроцедуры

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

Шаг 4. Обработка закрытия диалога и установка отбора

Теперь создадим экспортную процедуру ВыборПериодаЗавершение. Проанализируем логику ее работы. Нам необходимо получить выбранные даты, очистить предыдущие отборы по нашей дате табличной части (чтобы они не накапливались в списке при повторных вызовах) и установить новые граничные значения.

Ниже представлен универсальный рабочий вариант кода:


&НаКлиенте
Процедура ВыборПериодаЗавершение(Период, ДополнительныеПараметры) Экспорт
    
    // Если пользователь закрыл окно крестиком или нажал "Отмена"
    Если Период = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Запоминаем выбор в реквизите формы для сохранения истории
    ВыбранныйПериодПодачи = Период;
    
    ДатаНачала   = Период.ДатаНачала;
    ДатаОкончания = Период.ДатаОкончания;
    
    // Указываем точный путь к реквизиту табличной части в компоновке данных.
    // Формат: "ИмяТабличнойЧасти.ИмяРеквизита"
    ИмяПоляОтбора = "Услуги.ДатаВремяПодачи"; 
    ПолеОтбора = Новый ПолеКомпоновкиДанных(ИмяПоляОтбора);
    
    // Очищаем старые отборы по этому полю, чтобы избежать дублирования условий
    Индекс = Список.Отбор.Eлементы.Количество() - 1;
    Пока Индекс >= 0 Цикл
        Элемент = Список.Отбор.Элементы[Индекс];
        Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") 
            И Элемент.ЛевоеЗначение = ПолеОтбора Тогда
            Список.Отбор.Элементы.Удалить(Индекс);
        КонецЕсли;
        Индекс = Index - 1;
    КонецЦикла;
    
    // Устанавливаем левую границу периода (Больше или равно)
    Если ЗначениеЗаполнено(ДатаНачала) Тогда
        НовыйОтбор = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        НовыйОтбор.ЛевоеЗначение  = ПолеОтбора;
        НовыйОтбор.ВидСравнения   = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
        НовыйОтбор.ПравоеЗначение = ДатаНачала;
        НовыйОтбор.Использование  = Истина;
        НовыйОтбор.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
    КонецЕсли;
    
    // Устанавливаем правую границу периода (Меньше или равно)
    Если ЗначениеЗаполнено(ДатаОкончания) Тогда
        НовыйОтбор = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        NewОтбор.ЛевоеЗначение  = ПолеОтбора;
        НовыйОтбор.ВидСравнения   = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
        // Объект "СтандартныйПериод" автоматически приводит дату окончания к концу дня (23:59:59)
        НовыйОтбор.ПравоеЗначение = ДатаОкончания; 
        НовыйОтбор.Использование  = Истина;
        НовыйОтбор.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
    КонецЕсли;
    
КонецПроцедуры

Альтернативный вариант: Использование функций БСП

Если ваша конфигурация создана на основе типового решения от 1С (например, 1С:Бухгалтерия, 1С:УНФ или 1С:ERP), то в ней гарантированно присутствует Библиотека Стандартных Подсистем (БСП). В этом случае процесс написания кода значительно упрощается.

Мы можем избавиться от ручного поиска и удаления элементов отбора в коллекции. Достаточно вызвать встроенную функцию общего назначения ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка. Она автоматически найдет старые условия по указанному имени поля и обновит их новыми значениями, либо создаст новые, если отборов еще не было.

Посмотрим, как лаконично будет выглядеть процедура завершения с использованием БСП:


&НаКлиенте
Процедура ВыборПериодаЗавершение(Период, ДополнительныеПараметры) Экспорт
    
    Если Период = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ВыбранныйПериодПодачи = Период;
    
    // Установка нижней границы периода
    ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
        Список, 
        "Услуги.ДатаВремяПодачи", 
        Период.ДатаНачала, 
        ВидСравненияКомпоновкиДанных.БольшеИлиРавно, 
        "Начало периода", 
        ЗначениеЗаполнено(Период.ДатаНачала)
    );
    
    // Установка верхней границы периода
    ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
        Список, 
        "Услуги.ДатаВремяПодачи", 
        Период.ДатаОкончания, 
        ВидСравненияКомпоновкиДанных.МеньшеИлиРавно, 
        "Конец периода", 
        ЗначениеЗаполнено(Период.ДатаОкончания)
    );
    
КонецПроцедуры

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

Резюме

Мы успешно решили поставленную задачу. Для того чтобы сделать отбор динамического списка по табличной части документа, мы перевели список в режим произвольного запроса, настроили его связь во вкладке компоновки данных «Условия» (что предотвратило дублирование строк) и написали программную установку отборов по двум границам периода. Теперь пользователи формы списка смогут мгновенно находить документы по датам внутренних табличных частей.

← На главную