При разработке отчетов на базе Системы Компоновки Данных (СКД) с использованием внешних наборов данных (например, когда мы передаем таблицу значений в качестве источника) разработчики 1С часто сталкиваются с настоящей «магией». Отчет формируется, но выводит совершенно случайные, «левые» цифры в ресурсах. Однако стоит пользователю нажать на заголовок колонки для сортировки или добавить любой отбор в панели настроек — и данные мгновенно становятся корректными.
Давайте подробно проанализируем эту ситуацию, разберем причины такого нестандартного поведения платформы и выясним, как правильно передавать параметры внешнего набора в СКД.
Рассмотрим классический пример, описанный на форумах разработчиков:
Сначала может показаться, что проблема в оптимизации СКД, вычисляемых полях или даже в кэшировании данных конфигурацией. Но разберем ситуацию глубже. Оказывается, неверные суммы идеально совпадают с суммами за совершенно другой период времени. Почему это происходит?
При использовании внешнего набора данных мы обычно перехватываем формирование отчета в обработчике ПриКомпоновкеРезультата. Нам нужно получить параметры (например, период), выполнить свой запрос, выгрузить результат в таблицу значений и передать его в ПроцессорКомпоновкиДанных.
Посмотрим на пример кода, который вызывает описанную ошибку:
Параметры = КомпоновщикНастроек.Настройки.ПараметрыДанных;
Для Каждого Параметр Из Параметры.Элементы Цикл
Если Параметр.ИдентификаторПользовательскойНастройки = "c37da494-c1dd-4cca-bd7b-763cd52b9c7e" Тогда
Запрос.УстановитьПараметр("ДатаНачала", Параметр.Значение.ДатаНачала); //Дата
Запрос.УстановитьПараметр("ДатаОкончания", Параметр.Значение.ДатаОкончания); //Дата
Прервать;
КонецЕсли;
КонецЦикла;
Проанализируем две критические ошибки в этом коде:
КомпоновщикНастроек.Настройки хранятся базовые (дефолтные) настройки схемы, заданные в конфигураторе. Когда пользователь меняет период на форме отчета, эти изменения пишутся в КомпоновщикНастроек.ПользовательскиеНастройки. Запрос выполняется со старыми (базовыми) датами, в то время как шапка отчета показывает пользовательские.ИдентификаторПользовательскойНастройки в виде жестко зашитой строки — крайне плохая практика. Если кто-то пересоздаст параметр или перенесет схему, идентификатор изменится, и код перестанет работать.Почему помогает сортировка?
Когда пользователь применяет сортировку или фильтр через механизмы БСП, форма может принудительно обновить настройки и вызвать перекомпоновку. Из-за рассинхронизации базовых и пользовательских настроек, при определенных условиях платформа «подтягивает» корректные значения при повторном формировании, либо кэш перезаписывается правильно. Это следствие, а не причина.
Исправим ситуацию. Вместо парсинга сырых коллекций компоновщика по идентификаторам, нам необходимо использовать метод объединения настроек. Рассмотрим, как это сделать правильно.
Метод КомпоновщикНастроек.ПолучитьНастройки() компилирует финальный результат, корректно накладывая пользовательские и фиксированные настройки поверх базовых. Именно из него нужно извлекать параметры по их именам с помощью объекта ПараметрКомпоновкиДанных.
Посмотрим на корректный вариант кода для извлечения дат:
// 1. Получаем сводные настройки (включая пользовательские)
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// 2. Ищем параметр по его системному имени
ПараметрДатаНачала = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ДатаНачала"));
ПараметрДатаОкончания = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ДатаОкончания"));
// 3. Проверяем использование и передаем в запрос
Если ПараметрДатаНачала <> Неопределено И ПараметрДатаНачала.Использование Тогда
Запрос.УстановитьПараметр("ДатаНачала", ПараметрДатаНачала.Значение);
КонецЕсли;
Если ПараметрДатаОкончания <> Неопределено И ПараметрДатаОкончания.Использование Тогда
Запрос.УстановитьПараметр("ДатаОкончания", ПараметрДатаОкончания.Значение);
КонецЕсли;
С таким подходом ваш запрос всегда будет получать именно те даты (или другие параметры), которые пользователь видит на экране своего отчета. Никакой рассинхронизации не произойдет, и цифры будут верными с самого первого нажатия кнопки «Сформировать».
Иногда, из-за длительных экспериментов с некорректным кодом, у пользователей сохраняются битые настройки (как в хранилище вариантов отчета, так и системные). Если вы исправили код, но отчет у конкретного пользователя все еще ведет себя странно, настройки следует очистить.
Рассмотрим служебную процедуру, которая поможет удалить сохраненные системные настройки отчета программно:
Процедура ОчиститьНастройкиНаСервере(ПользовательСсылка, КлючОбъекта = Неопределено)
СтрПользователь = ПользователиСлужебныйКлиентСервер.ПолучитьКраткоеИмяПользователяИБ(ПользовательСсылка.КраткоеНаименование);
Если ЗначениеЗаполнено(СтрПользователь) Тогда
КлючНастройки = Неопределено;
ХранилищеСистемныхНастроек.Удалить(КлючОбъекта, КлючНастройки, СтрПользователь);
КонецЕсли;
КонецПроцедуры
Также, в типовых конфигурациях (БСП), можно посоветовать пользователю зайти в меню «Настройки» -> «Пользовательские настройки» и очистить их вручную, либо просто переименовать сам вариант отчета в конфигураторе (изменить синоним и имя схемы), чтобы платформа восприняла его как новый объект с чистыми настройками.
Подведем итог: При работе с ПриКомпоновкеРезультата всегда устанавливайте СтандартнаяОбработка = Ложь в начале процедуры, получайте параметры исключительно через ПолучитьНастройки() и избегайте поиска элементов компоновщика по GUID. Следуя этим простым правилам, вы обеспечите стабильную и предсказуемую работу СКД.