Почему СКД с внешним набором данных показывает неверные цифры до применения сортировки или отбора?

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

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

Давайте подробно проанализируем эту ситуацию, разберем причины такого нестандартного поведения платформы и выясним, как правильно передавать параметры внешнего набора в СКД.

Симптомы проблемы и анализ ситуации

Рассмотрим классический пример, описанный на форумах разработчиков:

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

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

Ошибочный подход: чтение базовых настроек по GUID

При использовании внешнего набора данных мы обычно перехватываем формирование отчета в обработчике ПриКомпоновкеРезультата. Нам нужно получить параметры (например, период), выполнить свой запрос, выгрузить результат в таблицу значений и передать его в ПроцессорКомпоновкиДанных.

Посмотрим на пример кода, который вызывает описанную ошибку:


Параметры = КомпоновщикНастроек.Настройки.ПараметрыДанных;
	
Для Каждого Параметр Из Параметры.Элементы Цикл
	Если Параметр.ИдентификаторПользовательскойНастройки = "c37da494-c1dd-4cca-bd7b-763cd52b9c7e" Тогда
		Запрос.УстановитьПараметр("ДатаНачала",    Параметр.Значение.ДатаНачала);     //Дата
		Запрос.УстановитьПараметр("ДатаОкончания", Параметр.Значение.ДатаОкончания);     //Дата
		Прервать;
	КонецЕсли;
КонецЦикла;

Проанализируем две критические ошибки в этом коде:

  1. Обращение к свойству Настройки: В свойстве КомпоновщикНастроек.Настройки хранятся базовые (дефолтные) настройки схемы, заданные в конфигураторе. Когда пользователь меняет период на форме отчета, эти изменения пишутся в КомпоновщикНастроек.ПользовательскиеНастройки. Запрос выполняется со старыми (базовыми) датами, в то время как шапка отчета показывает пользовательские.
  2. Поиск по GUID: Использование ИдентификаторПользовательскойНастройки в виде жестко зашитой строки — крайне плохая практика. Если кто-то пересоздаст параметр или перенесет схему, идентификатор изменится, и код перестанет работать.

Почему помогает сортировка?
Когда пользователь применяет сортировку или фильтр через механизмы БСП, форма может принудительно обновить настройки и вызвать перекомпоновку. Из-за рассинхронизации базовых и пользовательских настроек, при определенных условиях платформа «подтягивает» корректные значения при повторном формировании, либо кэш перезаписывается правильно. Это следствие, а не причина.

Правильное решение: использование ПолучитьНастройки()

Исправим ситуацию. Вместо парсинга сырых коллекций компоновщика по идентификаторам, нам необходимо использовать метод объединения настроек. Рассмотрим, как это сделать правильно.

Метод КомпоновщикНастроек.ПолучитьНастройки() компилирует финальный результат, корректно накладывая пользовательские и фиксированные настройки поверх базовых. Именно из него нужно извлекать параметры по их именам с помощью объекта ПараметрКомпоновкиДанных.

Посмотрим на корректный вариант кода для извлечения дат:


// 1. Получаем сводные настройки (включая пользовательские)
Настройки = КомпоновщикНастроек.ПолучитьНастройки();

// 2. Ищем параметр по его системному имени
ПараметрДатаНачала = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ДатаНачала"));
ПараметрДатаОкончания = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ДатаОкончания"));

// 3. Проверяем использование и передаем в запрос
Если ПараметрДатаНачала <> Неопределено И ПараметрДатаНачала.Использование Тогда
    Запрос.УстановитьПараметр("ДатаНачала", ПараметрДатаНачала.Значение);
КонецЕсли;

Если ПараметрДатаОкончания <> Неопределено И ПараметрДатаОкончания.Использование Тогда
    Запрос.УстановитьПараметр("ДатаОкончания", ПараметрДатаОкончания.Значение);
КонецЕсли;

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

Дополнение: Очистка зависших пользовательских настроек

Иногда, из-за длительных экспериментов с некорректным кодом, у пользователей сохраняются битые настройки (как в хранилище вариантов отчета, так и системные). Если вы исправили код, но отчет у конкретного пользователя все еще ведет себя странно, настройки следует очистить.

Рассмотрим служебную процедуру, которая поможет удалить сохраненные системные настройки отчета программно:


Процедура ОчиститьНастройкиНаСервере(ПользовательСсылка, КлючОбъекта = Неопределено)
    СтрПользователь = ПользователиСлужебныйКлиентСервер.ПолучитьКраткоеИмяПользователяИБ(ПользовательСсылка.КраткоеНаименование);
    
    Если ЗначениеЗаполнено(СтрПользователь) Тогда
        КлючНастройки = Неопределено;
        ХранилищеСистемныхНастроек.Удалить(КлючОбъекта, КлючНастройки, СтрПользователь); 
    КонецЕсли;
КонецПроцедуры

Также, в типовых конфигурациях (БСП), можно посоветовать пользователю зайти в меню «Настройки» -> «Пользовательские настройки» и очистить их вручную, либо просто переименовать сам вариант отчета в конфигураторе (изменить синоним и имя схемы), чтобы платформа восприняла его как новый объект с чистыми настройками.

Подведем итог: При работе с ПриКомпоновкеРезультата всегда устанавливайте СтандартнаяОбработка = Ложь в начале процедуры, получайте параметры исключительно через ПолучитьНастройки() и избегайте поиска элементов компоновщика по GUID. Следуя этим простым правилам, вы обеспечите стабильную и предсказуемую работу СКД.

← На главную