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