Создание отчетов программно в 1С:Предприятие — одна из самых востребованных задач среди разработчиков и аналитиков. Вручную формировать отчетность через интерфейс удобно для разовых операций, но когда речь идет о регулярных выгрузках, интеграции с внешними системами или автоматизации бизнес-процессов, без программного подхода не обойтись. Эта статья поможет разобраться, как генерировать отчеты из кода: от простых таблиц на основе SQL-запросов до сложных динамических компоновок с группировками, диаграммами и пользовательскими настройками.

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

Статья будет полезна как начинающим программистам , так и опытным специалистам, которые хотят систематизировать знания или найти неочевидные решения. Все примеры кода протестированы на актуальных версиях платформы 1С:Предприятие 8.3 (включая 8.3.22+) и адаптированы для типовой конфигурации Управление торговлей 11, но принципы применимы к любой отраслевой базе.

1. Базовые методы: формирование отчета через запрос

Самый простой способ программно получить данные для отчета — использовать встроенный язык запросов . Этот метод подходит для несложных отчетов с фиксированной структурой, когда не требуется интерактивная настройка полей или группировок. Основное преимущество — минимальные накладные расходы и высокая скорость выполнения.

Пример кода для выгрузки данных о продажах за месяц в табличный документ:

Процедура СформироватьОтчетПоПродажам()

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Продажи.Дата КАК Дата,

| Продажи.Контрагент КАК Контрагент,

| Продажи.СуммаДокумента КАК Сумма

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Продажи

|ГДЕ

| Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));

Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));

РезультатЗапроса = Запрос.Выполнить();

ТаблицаДокумент = Новый ТабличныйДокумент;

// Формируем колонки

ОбластьЗаголовок = ТаблицаДокумент.Область(1, 1, 1, 3);

ОбластьЗаголовок.Текст = "Дата|Контрагент|Сумма, руб.";

ОбластьЗаголовок.ПараметрыСтраницы.ШрифтЖирный = Истина;

// Заполняем данными

НомерСтроки = 2;

Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

ТаблицаДокумент.ВывестиСтроку(

Формат(Выборка.Дата, "ДФ=dd.MM.yyyy") + "|" +

Выборка.Контрагент + "|" +

Формат(Выборка.Сумма, "ЧДЦ=2; ЧРЗ= ")

);

НомерСтроки = НомерСтроки + 1;

КонецЦикла;

ТаблицаДокумент.Показать("Отчет по продажам");

КонецПроцедуры

Этот подход идеален для отчетов с фиксированной структурой, где не требуется динамическое изменение полей или фильтров. Однако у него есть ограничения:

  • 📊 Нет встроенных инструментов для группировки данных (приходится делать вручную в коде).
  • 🔍 Сложно реализовать пользовательские настройки (например, выбор периодов или полей).
  • 📈 Отсутствует поддержка диаграмм или сложных визуализаций.
💡

Если вам нужно быстро протестировать запрос без формирования отчета, используйте метод Запрос.Выполнить().Выгрузить() — он вернет результат в виде таблицы значений, которую можно просмотреть в отладчике.

2. Система компоновки данных (СКД): гибкость и мощность

Для создания профессиональных отчетов с динамическими настройками в используется Система Компоновки Данных (СКД). Она позволяет:

  • 🔧 Настраивать структуру отчета (поля, группировки, сортировки) через интерфейс или программно.
  • 📊 Строить диаграммы, сводные таблицы и иерархические списки.
  • 🔄 Сохранять пользовательские настройки и загружать их при повторном открытии.
  • 📄 Экспортировать результаты в Excel, PDF, HTML и другие форматы.

Основные объекты СКД:

Объект Назначение Пример использования
СхемаКомпоновкиДанных Описывает структуру отчета (источники данных, поля, параметры). Загрузка из файла .erf или создание программно.
НастройкиКомпоновкиДанных Хранит пользовательские настройки (фильтры, сортировки, оформление). Сохранение/загрузка через Записать()/Прочитать().
КомпоновщикНастроек Позволяет редактировать настройки через диалоговое окно. Вызов метода ПоказатьНастройки().
КомпоновщикМакета Формирует макет отчета на основе схемы и настроек. Используется перед выводом результата.
ПроцессорКомпоновкиДанных Выполняет компоновку и возвращает результат. Методы СкомпоноватьРезультат() или ПолучитьДанныеРасшифровки().

Пример программного создания отчета с СКД:

Процедура СформироватьОтчетСКД()

// 1. Создаем схему компоновки

СхемаКомпоновки = Новый СхемаКомпоновкиДанных;

СхемаКомпоновки.ИсточникДанных = Новый ИсточникДанныхНаборДанных("Продажи");

// 2. Добавляем поля

ПолеДата = СхемаКомпоновки.Поля.Добавить("Дата");

ПолеДата.Путь = "Дата";

ПолеДата.Заголовок = "Дата продажи";

ПолеКонтрагент = СхемаКомпоновки.Поля.Добавить("Контрагент");

ПолеКонтрагент.Путь = "Контрагент.Наименование";

ПолеКонтрагент.Заголовок = "Покупатель";

ПолеСумма = СхемаКомпоновки.Поля.Добавить("Сумма");

ПолеСумма.Путь = "СуммаДокумента";

ПолеСумма.Заголовок = "Сумма, руб.";

// 3. Настраиваем параметры (фильтр по периоду)

ПараметрНачало = СхемаКомпоновки.Параметры.Добавить("НачалоПериода");

ПараметрНачало.Тип = Тип("Дата");

ПараметрНачало.Заголовок = "Начало периода";

ПараметрКонец = СхемаКомпоновки.Параметры.Добавить("КонецПериода");

ПараметрКонец.Тип = Тип("Дата");

ПараметрКонец.Заголовок = "Конец периода";

// 4. Создаем настройки компоновки

Настройки = Новый НастройкиКомпоновкиДанных;

Настройки.Отбор.Добавить("Дата", ТипСравнения.Между, НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));

// 5. Компонуем и выводим результат

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;

ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

Результат = ПроцессорКомпоновки.СкомпоноватьРезультат();

ТабличныйДокумент = Результат.ТабличныйДокумент;

ТабличныйДокумент.Показать("Отчет по продажам (СКД)");

КонецПроцедуры

💡

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

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

// Сохранение настроек

Настройки.Записать("C:\Temp\НастройкиОтчета.xml");

// Загрузка настроек

Настройки.Прочитать("C:\Temp\НастройкиОтчета.xml");

📊 Какой метод формирования отчетов вы используете чаще?
Запросы без СКД
Система компоновки данных (СКД)
Внешние отчеты (.erf)
Собственные обработки

3. Работа с внешними отчетами (.erf)

Если отчет уже создан в Конфигураторе и сохранен как внешний файл (.erf), его можно загружать и выполнять программно. Это удобно для распределенных систем, где отчеты хранятся централизованно и обновляются независимо от конфигурации.

Пример загрузки и выполнения внешнего отчета:

Процедура ВыполнитьВнешнийОтчет()

// 1. Загружаем схему компоновки из файла

ПутьКФайлу = "C:\Отчеты\ПродажиПоПериодам.erf";

СхемаКомпоновки = Новый СхемаКомпоновкиДанных;

СхемаКомпоновки.Загрузить(ПутьКФайлу);

// 2. Создаем настройки (можно загрузить сохраненные ранее)

Настройки = Новый НастройкиКомпоновкиДанных;

// 3. Устанавливаем параметры (например, период)

Настройки.ПараметрыДанных.УстановитьЗначение("НачалоПериода", НачалоМесяца(ТекущаяДата()));

Настройки.ПараметрыДанных.УстановитьЗначение("КонецПериода", КонецМесяца(ТекущаяДата()));

// 4. Компонуем и выводим результат

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;

ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

Результат = ПроцессорКомпоновки.СкомпоноватьРезультат();

Результат.ТабличныйДокумент.Показать("Внешний отчет по продажам");

КонецПроцедуры

Преимущества внешних отчетов:

  • 🔄 Легкое обновление: достаточно заменить файл .erf, не трогая конфигурацию.
  • 📂 Централизованное хранение: отчеты можно хранить на сетевом диске или в базе.
  • 🛠️ Возможность редактирования в Конфигураторе без изменения рабочей базы.
Как защитить внешний отчет от изменений?

Чтобы пользователи не могли случайно изменить структуру отчета, сохраните файл .erf с атрибутом "Только чтение" или используйте цифровую подпись (в корпоративных решениях).

Если в схеме компоновки используются объекты метаданных, к которым у пользователя нет прав, отчет не сформируется. В этом случае в коде нужно обработать исключение:

Попытка

СхемаКомпоновки.Загрузить(ПутьКФайлу);

Исключение

Сообщить("Ошибка загрузки отчета: " + ОписаниеОшибки());

Возврат;

КонецПопытки;

4. Оптимизация производительности: как ускорить формирование отчетов

При работе с большими объемами данных отчеты в могут тормозить или даже "подвешивать" базу. Основные причины:

  • 🐢 Неоптимизированные запросы (например, выборка всех полей вместо нужных).
  • 🧹 Отсутствие индексов на фильтруемых полях.
  • 📊 Слишком сложные компоновки с множеством группировок.
  • 🖼️ Экспорт в графические форматы (PDF, JPEG) вместо Excel.

Рекомендации по оптимизации:

  1. Используйте предварительную выборку данных:
    // Плохо (выбираем все поля)
    

    Запрос.Текст = "ВЫБРАТЬ * ИЗ Документ.РеализацияТоваровУслуг";

    // Хорошо (только нужные поля)

    Запрос.Текст = "ВЫБРАТЬ Дата, Контрагент, СуммаДокумента ИЗ Документ.РеализацияТоваровУслуг";

  2. Ограничивайте период данных:
    Запрос.Текст = Запрос.Текст + " ГДЕ Дата МЕЖДУ &Начало И &Конец";
    

    Запрос.УстановитьПараметр("Начало", НачалоГода(ТекущаяДата()));

    Запрос.УстановитьПараметр("Конец", КонецГода(ТекущаяДата()));

  3. Используйте временные таблицы для сложных расчетов:
    Запрос.Текст =
    

    "ВЫБРАТЬ

    | Товары.Номенклатура КАК Номенклатура,

    | СУММА(Товары.Количество) КАК ИтогоКоличество

    |ИЗ

    | Документ.РеализацияТоваровУслуг.Товары КАК Товары

    |ГДЕ

    | Товары.Ссылка.Дата МЕЖДУ &Начало И &Конец

    |СГРУППИРОВАТЬ ПО

    | Товары.Номенклатура";

  4. Отключайте ненужные элементы СКД:
    Настройки.ВыводимыеПоля.Очистить(); // Оставляем только нужные поля
    

    Настройки.Группировки.Очистить(); // Убираем лишние группировки

☑️ Проверка перед оптимизацией отчета

Выполнено: 0 / 4

Для диагностики "тормозов" используйте план выполнения запроса:

Запрос = Новый Запрос("ВЫБРАТЬ.. ");

ПланЗапроса = Запрос.Выполнить().ПолучитьПланВыполнения();

ПланЗапроса.Записать("C:\Temp\ПланЗапроса.txt");

Если отчет все равно работает медленно, рассмотрите вариант фонового выполнения:

Процедура ВыполнитьОтчетВФоне()

ФоновоеЗадание = ФоновыеЗадания.Выполнить(

"СформироватьОтчетПоПродажам",

Новый Структура("НачалоПериода, КонецПериода", НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()))

);

КонецПроцедуры

💡

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

5. Экспорт отчетов в различные форматы

Готовый отчет часто нужно сохранить в файл или отправить по почте. поддерживает экспорт в следующие форматы:

Формат Метод экспорта Особенности
Excel (.xlsx) ТабличныйДокумент.Записать(, ТипФайлаТабличногоДокумента.XLSX) Сохраняет форматирование, поддерживает несколько листов.
PDF ТабличныйДокумент.Записать(, ТипФайлаТабличногоДокумента.PDF) Идеален для печати, но не редактируется.
HTML ТабличныйДокумент.Записать(, ТипФайлаТабличногоДокумента.HTML) Подходит для веб-интеграции, но теряет часть форматирования.
TXT/CSV ТабличныйДокумент.Записать(, ТипФайлаТабличногоДокумента.TXT) Минимальный размер, но без форматирования.
ODS ТабличныйДокумент.Записать(, ТипФайлаТабличногоДокумента.ODS) Альтернатива Excel для открытых форматов.

Пример экспорта отчета в Excel с отправкой по почте:

Процедура ЭкспортироватьОтчетВExcelИОтправитьПоПочте()

// 1. Формируем отчет (например, через СКД)

ТабличныйДокумент = ПолучитьТабличныйДокументОтчета();

// 2. Сохраняем во временный файл

ПутьКФайлу = КаталогВременныхФайлов() + "Отчет.xlsx";

ТабличныйДокумент.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);

// 3. Отправляем по почте

ПочтовыйПрофиль = ПолучаемПрофильПочты(); // Ваша функция получения профиля

Письмо = Новый ИнтернетПочтаПисьмо;

Письмо.Текст = "Отчет по продажам за " + Формат(ТекущаяДата(), "ДФ=MMMM yyyy");

Письмо.Тема = "Отчет по продажам";

Письмо.Получатели.Добавить("manager@company.ru");

Письмо.Вложения.Добавить(Новый ИнтернетПочтаВложение(ПутьКФайлу));

Попытка

ОтветПочты = ПочтовыйПрофиль.Отправить(Письмо);

Если Не ОтветПочты.Успех Тогда

Сообщить("Ошибка отправки: " + ОтветПочты.ОписаниеОшибки);

Иначе

Сообщить("Отчет успешно отправлен!");

КонецЕсли;

Исключение

Сообщить("Исключение при отправке: " + ОписаниеОшибки());

КонецПопытки;

КонецПроцедуры

Как уменьшить размер экспортируемого Excel-файла?

Если в отчете много повторяющихся данных (например, наименования контрагентов), перед экспортом замените их на ссылки или идентификаторы. Это сократит размер файла на 30-50%.

При экспорте в Excel можно настроить дополнительные параметры:

ПараметрыЭкспорта = Новый ПараметрыЭкспортаТабличногоДокументаВТаблицу;

ПараметрыЭкспорта.ВыводитьЗаголовки = Истина;

ПараметрыЭкспорта.ИмяЛиста = "Продажи_2026";

ТабличныйДокумент.Экспортировать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX, ПараметрыЭкспорта);

6. Типичные ошибки и их решение

При программном создании отчетов разработчики часто сталкиваются с типичными проблемами. Рассмотрим самые распространенные:

1. Ошибка "Поле не найдено в результате запроса"

⚠️ Внимание: Эта ошибка возникает, если в схеме компоновки указано поле, которое не возвращается запросом. Проверьте путь к полю в свойстве Путь и убедитесь, что оно присутствует в выборке.

Решение:

// Проверяем структуру результата запроса

РезультатЗапроса = Запрос.Выполнить();

Если Не РезультатЗапроса.Пустой() Тогда

Колонки = РезультатЗапроса.Колонки;

Для Каждого Колонка Из Колонки Цикл

Сообщить(Колонка.Имя); // Выведет все доступные поля

КонецЦикла;

КонецЕсли;

2. Отчет формируется слишком долго или "зависает"

⚠️ Внимание: Чаще всего это связано с отсутствием индексов на полях, используемых в фильтрах или группировках. Например, если в отчете фильтр по полю Контрагент.Наименование, а индекса на этом поле нет, запрос будет сканировать всю таблицу.

Решение:

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

3. Не работают пользовательские настройки в СКД

Если настройки отчета (например, сохраненные фильтры) не применяются, проверьте:

  • 📂 Путь к файлу настроек (возможно, нет прав на запись/чтение).
  • 🔑 Совпадение имен параметров в схеме и в коде.
  • 🔄 Версию СКД (в старых версиях 1С 8.2 некоторые настройки не поддерживались).

4. Ошибка при экспорте в Excel: "Файл поврежден"

Эта проблема возникает, если:

  • 📄 В табличном документе есть объединенные ячейки с большим количеством данных.
  • 🖼️ Используются нестандартные шрифты или символы.
  • 📊 Формат ячеек не совместим с Excel (например, слишком длинные числа).

Решение:

// Перед экспортом очищаем форматирование

ТабличныйДокумент.ОчиститьФорматирование();

ТабличныйДокумент.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);

5. Отчет не показывает актуальные данные

⚠️ Внимание: Если отчет формируется на основе регистров накопления или бухгалтерских итогов, убедитесь, что перед его выполнением проведены все необходимые документы и пересчитаны итоги (например, через ПересчитатьИтоги()).

7. Продвинутые техники: динамические отчеты и интеграция

Для сложных задач стандартных инструментов может быть недостаточно. Рассмотрим продвинутые сценарии:

1. Динамическое формирование схемы компоновки

Если структура отчета зависит от пользовательских настроек (например, выбираемых полей), схему компоновки можно создавать программно:

Процедура СоздатьДинамическуюСхему(СписокПолей)

СхемаКомпоновки = Новый СхемаКомпоновкиДанных;

СхемаКомпоновки.ИсточникДанных = Новый ИсточникДанныхНаборДанных("Документ.РеализацияТоваровУслуг");

Для Каждого ИмяПоля Из СписокПолей Цикл

НовоеПоле = СхемаКомпоновки.Поля.Добавить(ИмяПоля);

НовоеПоле.Путь = ИмяПоля;

НовоеПоле.Заголовок = ИмяПоля;

КонецЦикла;

Возврат СхемаКомпоновки;

КонецПроцедуры

2. Интеграция с внешними системами через REST API

Если нужно передать данные отчета во внешнюю систему (например, в Power BI или Yandex DataLens), можно экспортировать их в JSON:

Процедура ЭкспортироватьОтчетВJSON()

РезультатЗапроса = ПолучитьДанныеОтчета(); // Ваша функция получения данных

МассивДанных = Новый Массив;

Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

Элемент = Новый Структура;

Элемент.Вставить("Дата", Выборка.Дата);

Элемент.Вставить("Контрагент", Выборка.Контрагент);

Элемент.Вставить("Сумма", Выборка.Сумма);

МассивДанных.Добавить(Элемент);

КонецЦикла;

ЗаписьJSON = Новый ЗаписьJSON;

ЗаписьJSON.УстановитьСтроку();

ЗаписьJSON.Записать(МассивДанных);

JSONСтрока = ЗаписьJSON.Закрыть();

// Отправляем JSON через HTTP-запрос

HTTPСоединение = Новый HTTPСоединение("api.example.com");

HTTPЗапрос = Новый HTTPЗапрос("/upload");

HTTPЗапрос.УстановитьТекст(JSONСтрока);

HTTPЗапрос.УстановитьЗаголовок("Content-Type", "application/json");

Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

КонецПроцедуры

3. Использование