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