При разработке или доработке отчетов на базе Системы Компоновки Данных (СКД) разработчики часто сталкиваются с неприятной ситуацией: в код добавлено формирование новых колонок, данные собираются корректно, таблица значений передается в процессор компоновки, но в итоговом табличном документе эти колонки упорно не появляются. Давайте подробно разберем эту ситуацию, проанализируем частые ошибки и рассмотрим оптимальные способы решения проблемы.
Как показывает практика и обсуждение данной проблемы, в 90% случаев причина кроется не в ошибке кода, а в механизме работы платформы 1С с пользовательскими настройками отчетов. При открытии отчета СКД подтягивает тот состав полей, который был сохранен ранее (пользователем вручную или системой автоматически). Если вы добавили новое поле в схему, старый вариант отчета о нем ничего не знает и, соответственно, не выводит.
Рассмотрим, как разработчики обычно пытаются решить эту проблему, и как это делать правильно.
ИдентификаторыОбъектовМетаданных или запустить обработку обновления вариантов отчетов. Тогда новые настройки применятся у всех пользователей автоматически без их участия.Проанализируем программный код подготовки внешней таблицы данных. Часто разработчики создают таблицу значений вручную, прописывая типы колонок через КвалификаторыЧисла, а затем обходят результат запроса в цикле, добавляя строки.
Посмотрим на пример такого неоптимального подхода:
КЧ = Новый КвалификаторыЧисла(20,2);
Массив = Новый Массив;
Массив.Добавить(Тип("Число"));
ОписаниеТиповЧ = Новый ОписаниеТипов(Массив, , ,КЧ);
ТаблицаДанных.Колонки.Добавить("ОбъемПродажТовары", ОписаниеТиповЧ);
// ... добавление других колонок ...
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;
Этот подход работает медленно, требует написания большого объема рутинного кода и увеличивает вероятность опечаток (например, несовпадение имени колонки в таблице и в выборке). Разберем, как сделать это гораздо элегантнее и быстрее.
Вместо ручного конструирования достаточно выгрузить результат запроса напрямую в таблицу значений. Платформа 1С сама создаст все нужные колонки с идеальным совпадением типов данных:
// Выполняем запрос и сразу получаем готовую таблицу значений со всеми типизированными колонками
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
Одна эта строка заменяет десятки строк ручного объявления колонок и цикл обхода выборки, полностью исключая ошибку несовпадения типов между переданной таблицей и схемой СКД.
Даже если мы идеально сформировали таблицу значений в коде, СКД не увидит новые данные автоматически. При использовании источника данных типа "Набор данных - Объект" необходимо соблюдать строгие правила.
ТаблицаДанных) должны совпадать с точностью до символа. Если в схеме СКД поля нет, система просто проигнорирует эту колонку при загрузке внешнего набора.Если добавленные колонки содержат числовые показатели (например, ОбъемПродажТовары или БаллыЗаТовар), и мы хотим выводить по ним итоги в группировках, их необходимо добавить на вкладку "Ресурсы".
Важный нюанс: для ресурсов обязательно должно быть прописано выражение агрегации. Например, Сумма(ОбъемПродажТовары). Если выражение ресурса не задано или содержит синтаксическую ошибку, поле не сможет быть рассчитано для группировочных записей и в отчет не выведется.
Рассмотрим еще одну распространенную проблему, присутствующую в исходном алгоритме — динамическую склейку текста запроса с помощью условий Текст = Текст + " ГДЕ ".
Если ЗначениеЗаполнено(СотрудникДляРасчета) и не ЗначениеЗаполнено(мМагазин) Тогда
Текст = Текст + " ГДЕ РасчетБалловСистемыМотивации.Сотрудник = &СотрудникДляРасчета";
ИначеЕсли ЗначениеЗаполнено(СотрудникДляРасчета) и ЗначениеЗаполнено(мМагазин) Тогда
// ... и так далее
Такой подход делает код нечитаемым, сложным в отладке и морально устаревшим. Давайте выясним причину, почему в современной разработке так делать не стоит, и перепишем логику правильно.
Даже если вы используете внешний набор данных, язык запросов 1С позволяет обрабатывать необязательные параметры без изменения самого текста запроса. Если параметр может быть не заполнен, условие пишется следующим образом:
ВЫБРАТЬ
// ... поля ...
ИЗ
РегистрСведений.РасчетБалловСистемыМотивации КАК РасчетБаллов
ГДЕ
(&СотрудникДляРасчета = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)
ИЛИ РасчетБаллов.Сотрудник = &СотрудникДляРасчета)
И (&Магазин = ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка)
ИЛИ РасчетБаллов.Магазин = &Магазин)
Идеальное решение: Перенести запрос из программного кода непосредственно в саму схему СКД (использовать "Набор данных - Запрос"). СКД обладает мощнейшим механизмом — расширением языка запросов. Используя конструкции в фигурных скобках {ГДЕ РасчетБаллов.Сотрудник.*}, мы поручаем системе самой определять, нужно ли накладывать условие. СКД автоматически подставит фильтр в запрос только в том случае, если пользователь установил отбор по этому полю в настройках отчета.