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