Программное создание СКД в 1С — это сборка объекта СхемаКомпоновкиДанных прямо в коде: добавляем источник данных, наборы (запрос, объект, объединение), поля, ресурсы и параметры, затем описываем настройки — структуру группировок и выбранные поля — и передаём всё компоновщику макета и процессору компоновки. Каждая вкладка конструктора СКД имеет программный аналог: «Наборы данных» — коллекция НаборыДанных, «Ресурсы» — ПоляИтога, «Вычисляемые поля» — ВычисляемыеПоля, «Настройки» — объект НастройкиКомпоновкиДанных.
Полностью собирать отчёт из кода приходится нечасто. Но тот, кто один раз это сделал, начинает понимать объектную модель СКД и спокойно дорабатывает типовые отчёты программно: добавляет поле в набор, подкладывает внешнюю таблицу, меняет структуру перед выводом. Ниже — последовательный пример с пояснениями и списком ошибок, которые чаще всего ломают такой код.
Когда программная СКД действительно нужна
| Задача | Подход |
|---|---|
| Обычный отчёт с фиксированной структурой | Конструктор СКД во внешнем или встроенном отчёте |
| Универсальная обработка «отчёт по любому справочнику или регистру» | Полностью программная схема |
| Доработка типового отчёта без снятия с поддержки | Получить макет и изменить схему программно |
| Нужен результат в таблице значений для дальнейших расчётов | Схема из конструктора или кода + вывод в коллекцию значений |
| Генератор отчётов по настройкам пользователя | Программная схема и настройки |
На проектах я придерживаюсь правила: если отчёт можно нарисовать в конструкторе — рисую в конструкторе, а код оставляю для того, что меняется динамически. Программная схема хуже читается и сложнее в сопровождении, поэтому каждое её применение должно быть оправдано.
Шаг 1. Схема и источник данных
Источник обязателен, даже если данные берутся из текущей базы. Тип источника — Local, строка соединения пустая.
Схема = Новый СхемаКомпоновкиДанных;
Источник = Схема.ИсточникиДанных.Добавить();
Источник.Имя = "ЛокальнаяБаза";
Источник.ТипИсточникаДанных = "Local";
Источник.СтрокаСоединения = "";Имя источника затем указывается в каждом наборе данных — это частая причина ошибки «Не найден источник данных», если имена не совпали буквально.
Шаг 2. Наборы данных: запрос, объект, объединение
Набор данных «Запрос»
НаборПродажи = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборПродажи.Имя = "Продажи";
НаборПродажи.ИсточникДанных = "ЛокальнаяБаза";
НаборПродажи.АвтоЗаполнениеДоступныхПолей = Истина;
НаборПродажи.Запрос =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Ссылка.Контрагент КАК Контрагент,
| Товары.Количество КАК Количество,
| Товары.Сумма КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Товары.Ссылка.Проведен";Свойство АвтоЗаполнениеДоступныхПолей заставляет платформу взять поля из текста запроса. Явно описывать поля нужно, когда требуется свой заголовок, тип значения, ограничение использования или оформление.
Описание поля набора
Каждый элемент коллекции Поля соответствует строке на вкладке «Наборы данных» конструктора. Чтобы не повторять пять строк на каждое поле, выношу добавление во вспомогательную процедуру:
// Добавляет поле в набор данных схемы компоновки.
//
// Параметры:
// НаборДанных - НаборДанныхЗапросСхемыКомпоновкиДанных, НаборДанныхОбъектСхемыКомпоновкиДанных
// ИмяПоля - Строка - имя поля и путь к данным
// Заголовок - Строка - представление поля в отчёте
// ТипЗначения - ОписаниеТипов, Неопределено
//
Процедура ДобавитьПолеНабора(НаборДанных, ИмяПоля, Заголовок, ТипЗначения = Неопределено)
Поле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
Поле.Поле = ИмяПоля;
Поле.ПутьКДанным = ИмяПоля;
Поле.Заголовок = Заголовок;
Если ТипЗначения <> Неопределено Тогда
Поле.ТипЗначения = ТипЗначения;
КонецЕсли;
КонецПроцедурыРазница между свойствами: Поле — имя колонки в результате запроса или в таблице, ПутьКДанным — имя, по которому поле видно в настройках, выражениях и связях.
ДобавитьПолеНабора(НаборПродажи, "Номенклатура", "Номенклатура");
ДобавитьПолеНабора(НаборПродажи, "Контрагент", "Покупатель");
ДобавитьПолеНабора(НаборПродажи, "Сумма", "Сумма продаж",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));Набор данных «Объект»
Подходит, когда данные уже лежат в таблице значений: результат расчёта, загрузка из файла, ответ внешнего сервиса.
НаборПланы = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
НаборПланы.Имя = "Планы";
НаборПланы.ИсточникДанных = "ЛокальнаяБаза";
НаборПланы.ИмяОбъекта = "ТаблицаПланов";
ДобавитьПолеНабора(НаборПланы, "Номенклатура", "Номенклатура");
ДобавитьПолеНабора(НаборПланы, "СуммаПлан", "План",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));Сама таблица передаётся позже — в процессор компоновки, структурой с ключом ТаблицаПланов. Для набора-объекта поля лучше описывать явно: платформа должна знать их типы.
Набор данных «Объединение»
Это аналог ОБЪЕДИНИТЬ ВСЕ на уровне схемы: в коллекцию Элементы добавляются подчинённые наборы, а поля объединения описываются так же, как у других наборов.
Объединение = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъединениеСхемыКомпоновкиДанных"));
Объединение.Имя = "ФактИПлан";
Подчиненный = Объединение.Элементы.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
Подчиненный.Имя = "ФактИзЗапроса";
// ... запрос и поля подчинённого набораШаг 3. Связи наборов, вычисляемые поля и ресурсы
Связь соответствует вкладке «Связи наборов данных» и работает как левое соединение: источник — главный набор, приёмник — присоединяемый.
Связь = Схема.СвязиНаборовДанных.Добавить();
Связь.НаборДанныхИсточник = "Продажи";
Связь.НаборДанныхПриемник = "Планы";
Связь.ВыражениеИсточник = "Номенклатура";
Связь.ВыражениеПриемник = "Номенклатура";Вычисляемое поле описывается выражением языка выражений СКД:
Отклонение = Схема.ВычисляемыеПоля.Добавить();
Отклонение.ПутьКДанным = "Отклонение";
Отклонение.Заголовок = "Отклонение от плана";
Отклонение.Выражение = "ЕстьNULL(Сумма, 0) - ЕстьNULL(СуммаПлан, 0)";Ресурсы — коллекция ПоляИтога. Без них итоги по группировкам считаться не будут, а числовые поля в группировках выведутся пустыми.
Для Каждого ИмяРесурса Из СтрРазделить("Сумма,СуммаПлан,Отклонение", ",") Цикл
Ресурс = Схема.ПоляИтога.Добавить();
Ресурс.ПутьКДанным = ИмяРесурса;
Ресурс.Выражение = "Сумма(" + ИмяРесурса + ")";
КонецЦикла;Если ресурс нужно считать только в части группировок, перечислите их в массиве Ресурс.Группировки.
Шаг 4. Параметры схемы
Параметры из текста запроса при программной сборке нужно описать в коллекции Параметры самостоятельно, иначе компоновщик не узнает их тип.
ПараметрНачало = Схема.Параметры.Добавить();
ПараметрНачало.Имя = "НачалоПериода";
ПараметрНачало.Заголовок = "Начало периода";
ПараметрНачало.ТипЗначения = Новый ОписаниеТипов("Дата", , ,
Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя));
ПараметрКонец = Схема.Параметры.Добавить();
ПараметрКонец.Имя = "КонецПериода";
ПараметрКонец.Заголовок = "Конец периода";
ПараметрКонец.ТипЗначения = Новый ОписаниеТипов("Дата", , ,
Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя));Значения я устанавливаю уже в настройках через компоновщик настроек — так же, как это делает пользователь в форме отчёта.
Шаг 5. Настройки: структура и выбранные поля
У новой схемы коллекция ВариантыНастроек пустая, поэтому в примерах с ВариантыНастроек[0] вы получите ошибку индекса. Надёжный путь — компоновщик настроек: он строит список доступных полей по схеме и позволяет работать с настройками так же, как в форме отчёта.

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




