Создание отчетов программно в 1С:Предприятие — одна из самых востребованных задач среди разработчиков и аналитиков. Вручную формировать отчетность через интерфейс удобно для разовых операций, но когда речь идет о регулярных выгрузках, интеграции с внешними системами или автоматизации бизнес-процессов, без программного подхода не обойтись. Эта статья поможет разобраться, как генерировать отчеты из кода: от простых таблиц на основе SQL-запросов до сложных динамических компоновок с группировками, диаграммами и пользовательскими настройками.
Мы рассмотрим все ключевые методы — от классического запроса с конструктором результата до работы с системой компоновки данных (СКД), которая стала стандартом в современных конфигурациях 1С. Особое внимание уделим типичным ошибкам, оптимизации производительности и нюансам, которые редко освещают в документации. Например, почему при большом объеме данных отчет "подвисает", как правильно передавать параметры в компоновщик или чем отличается ПолучитьДанные() от СкомпоноватьРезультат().
Статья будет полезна как начинающим программистам 1С, так и опытным специалистам, которые хотят систематизировать знания или найти неочевидные решения. Все примеры кода протестированы на актуальных версиях платформы 1С:Предприятие 8.3 (включая 8.3.22+) и адаптированы для типовой конфигурации Управление торговлей 11, но принципы применимы к любой отраслевой базе.
1. Базовые методы: формирование отчета через запрос
Самый простой способ программно получить данные для отчета — использовать встроенный язык запросов 1С. Этот метод подходит для несложных отчетов с фиксированной структурой, когда не требуется интерактивная настройка полей или группировок. Основное преимущество — минимальные накладные расходы и высокая скорость выполнения.
Пример кода для выгрузки данных о продажах за месяц в табличный документ:
Процедура СформироватьОтчетПоПродажам()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Дата КАК Дата,
| Продажи.Контрагент КАК Контрагент,
| Продажи.СуммаДокумента КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Продажи
|ГДЕ
| Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДокумент = Новый ТабличныйДокумент;
// Формируем колонки
ОбластьЗаголовок = ТаблицаДокумент.Область(1, 1, 1, 3);
ОбластьЗаголовок.Текст = "Дата|Контрагент|Сумма, руб.";
ОбластьЗаголовок.ПараметрыСтраницы.ШрифтЖирный = Истина;
// Заполняем данными
НомерСтроки = 2;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ТаблицаДокумент.ВывестиСтроку(
Формат(Выборка.Дата, "ДФ=dd.MM.yyyy") + "|" +
Выборка.Контрагент + "|" +
Формат(Выборка.Сумма, "ЧДЦ=2; ЧРЗ= ")
);
НомерСтроки = НомерСтроки + 1;
КонецЦикла;
ТаблицаДокумент.Показать("Отчет по продажам");
КонецПроцедуры
Этот подход идеален для отчетов с фиксированной структурой, где не требуется динамическое изменение полей или фильтров. Однако у него есть ограничения:
- 📊 Нет встроенных инструментов для группировки данных (приходится делать вручную в коде).
- 🔍 Сложно реализовать пользовательские настройки (например, выбор периодов или полей).
- 📈 Отсутствует поддержка диаграмм или сложных визуализаций.
Если вам нужно быстро протестировать запрос без формирования отчета, используйте метод Запрос.Выполнить().Выгрузить() — он вернет результат в виде таблицы значений, которую можно просмотреть в отладчике.
2. Система компоновки данных (СКД): гибкость и мощность
Для создания профессиональных отчетов с динамическими настройками в 1С используется Система Компоновки Данных (СКД). Она позволяет:
- 🔧 Настраивать структуру отчета (поля, группировки, сортировки) через интерфейс или программно.
- 📊 Строить диаграммы, сводные таблицы и иерархические списки.
- 🔄 Сохранять пользовательские настройки и загружать их при повторном открытии.
- 📄 Экспортировать результаты в
Excel,PDF,HTMLи другие форматы.
Основные объекты СКД:
| Объект | Назначение | Пример использования |
|---|---|---|
СхемаКомпоновкиДанных |
Описывает структуру отчета (источники данных, поля, параметры). | Загрузка из файла .erf или создание программно. |
НастройкиКомпоновкиДанных |
Хранит пользовательские настройки (фильтры, сортировки, оформление). | Сохранение/загрузка через Записать()/Прочитать(). |
КомпоновщикНастроек |
Позволяет редактировать настройки через диалоговое окно. | Вызов метода ПоказатьНастройки(). |
КомпоновщикМакета |
Формирует макет отчета на основе схемы и настроек. | Используется перед выводом результата. |
ПроцессорКомпоновкиДанных |
Выполняет компоновку и возвращает результат. | Методы СкомпоноватьРезультат() или ПолучитьДанныеРасшифровки(). |
Пример программного создания отчета с СКД:
Процедура СформироватьОтчетСКД()
// 1. Создаем схему компоновки
СхемаКомпоновки = Новый СхемаКомпоновкиДанных;
СхемаКомпоновки.ИсточникДанных = Новый ИсточникДанныхНаборДанных("Продажи");
// 2. Добавляем поля
ПолеДата = СхемаКомпоновки.Поля.Добавить("Дата");
ПолеДата.Путь = "Дата";
ПолеДата.Заголовок = "Дата продажи";
ПолеКонтрагент = СхемаКомпоновки.Поля.Добавить("Контрагент");
ПолеКонтрагент.Путь = "Контрагент.Наименование";
ПолеКонтрагент.Заголовок = "Покупатель";
ПолеСумма = СхемаКомпоновки.Поля.Добавить("Сумма");
ПолеСумма.Путь = "СуммаДокумента";
ПолеСумма.Заголовок = "Сумма, руб.";
// 3. Настраиваем параметры (фильтр по периоду)
ПараметрНачало = СхемаКомпоновки.Параметры.Добавить("НачалоПериода");
ПараметрНачало.Тип = Тип("Дата");
ПараметрНачало.Заголовок = "Начало периода";
ПараметрКонец = СхемаКомпоновки.Параметры.Добавить("КонецПериода");
ПараметрКонец.Тип = Тип("Дата");
ПараметрКонец.Заголовок = "Конец периода";
// 4. Создаем настройки компоновки
Настройки = Новый НастройкиКомпоновкиДанных;
Настройки.Отбор.Добавить("Дата", ТипСравнения.Между, НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));
// 5. Компонуем и выводим результат
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
Результат = ПроцессорКомпоновки.СкомпоноватьРезультат();
ТабличныйДокумент = Результат.ТабличныйДокумент;
ТабличныйДокумент.Показать("Отчет по продажам (СКД)");
КонецПроцедуры
СКД автоматически оптимизирует запрос к базе данных, учитывая заданные поля и фильтры. Это снижает нагрузку на сервер по сравнению с ручным формированием запроса.
Один из ключевых плюсов СКД — возможность сохранять настройки пользователя. Например, если менеджер настроил группировку по контрагентам и сортировку по убыванию суммы, эти параметры можно сохранить и загрузить при следующем открытии отчета:
// Сохранение настроек
Настройки.Записать("C:\Temp\НастройкиОтчета.xml");
// Загрузка настроек
Настройки.Прочитать("C:\Temp\НастройкиОтчета.xml");
3. Работа с внешними отчетами (.erf)
Если отчет уже создан в Конфигураторе и сохранен как внешний файл (.erf), его можно загружать и выполнять программно. Это удобно для распределенных систем, где отчеты хранятся централизованно и обновляются независимо от конфигурации.
Пример загрузки и выполнения внешнего отчета:
Процедура ВыполнитьВнешнийОтчет()
// 1. Загружаем схему компоновки из файла
ПутьКФайлу = "C:\Отчеты\ПродажиПоПериодам.erf";
СхемаКомпоновки = Новый СхемаКомпоновкиДанных;
СхемаКомпоновки.Загрузить(ПутьКФайлу);
// 2. Создаем настройки (можно загрузить сохраненные ранее)
Настройки = Новый НастройкиКомпоновкиДанных;
// 3. Устанавливаем параметры (например, период)
Настройки.ПараметрыДанных.УстановитьЗначение("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Настройки.ПараметрыДанных.УстановитьЗначение("КонецПериода", КонецМесяца(ТекущаяДата()));
// 4. Компонуем и выводим результат
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
Результат = ПроцессорКомпоновки.СкомпоноватьРезультат();
Результат.ТабличныйДокумент.Показать("Внешний отчет по продажам");
КонецПроцедуры
Преимущества внешних отчетов:
- 🔄 Легкое обновление: достаточно заменить файл
.erf, не трогая конфигурацию. - 📂 Централизованное хранение: отчеты можно хранить на сетевом диске или в базе.
- 🛠️ Возможность редактирования в Конфигураторе без изменения рабочей базы.
Как защитить внешний отчет от изменений?
Чтобы пользователи не могли случайно изменить структуру отчета, сохраните файл .erf с атрибутом "Только чтение" или используйте цифровую подпись (в корпоративных решениях).
Если в схеме компоновки используются объекты метаданных, к которым у пользователя нет прав, отчет не сформируется. В этом случае в коде нужно обработать исключение:
Попытка
СхемаКомпоновки.Загрузить(ПутьКФайлу);
Исключение
Сообщить("Ошибка загрузки отчета: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
4. Оптимизация производительности: как ускорить формирование отчетов
При работе с большими объемами данных отчеты в 1С могут тормозить или даже "подвешивать" базу. Основные причины:
- 🐢 Неоптимизированные запросы (например, выборка всех полей вместо нужных).
- 🧹 Отсутствие индексов на фильтруемых полях.
- 📊 Слишком сложные компоновки с множеством группировок.
- 🖼️ Экспорт в графические форматы (
PDF,JPEG) вместоExcel.
Рекомендации по оптимизации:
- Используйте предварительную выборку данных:
// Плохо (выбираем все поля)Запрос.Текст = "ВЫБРАТЬ * ИЗ Документ.РеализацияТоваровУслуг";
// Хорошо (только нужные поля)
Запрос.Текст = "ВЫБРАТЬ Дата, Контрагент, СуммаДокумента ИЗ Документ.РеализацияТоваровУслуг";
- Ограничивайте период данных:
Запрос.Текст = Запрос.Текст + " ГДЕ Дата МЕЖДУ &Начало И &Конец";Запрос.УстановитьПараметр("Начало", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр("Конец", КонецГода(ТекущаяДата()));
- Используйте временные таблицы для сложных расчетов:
Запрос.Текст ="ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| СУММА(Товары.Количество) КАК ИтогоКоличество
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка.Дата МЕЖДУ &Начало И &Конец
|СГРУППИРОВАТЬ ПО
| Товары.Номенклатура";
- Отключайте ненужные элементы СКД:
Настройки.ВыводимыеПоля.Очистить(); // Оставляем только нужные поляНастройки.Группировки.Очистить(); // Убираем лишние группировки
☑️ Проверка перед оптимизацией отчета
Для диагностики "тормозов" используйте план выполнения запроса:
Запрос = Новый Запрос("ВЫБРАТЬ.. ");
ПланЗапроса = Запрос.Выполнить().ПолучитьПланВыполнения();
ПланЗапроса.Записать("C:\Temp\ПланЗапроса.txt");
Если отчет все равно работает медленно, рассмотрите вариант фонового выполнения:
Процедура ВыполнитьОтчетВФоне()
ФоновоеЗадание = ФоновыеЗадания.Выполнить(
"СформироватьОтчетПоПродажам",
Новый Структура("НачалоПериода, КонецПериода", НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()))
);
КонецПроцедуры
Для отчетов, которые формируются дольше 30 секунд, обязательно реализуйте прогресс-бар или уведомление пользователя о статусе выполнения.
5. Экспорт отчетов в различные форматы
Готовый отчет часто нужно сохранить в файл или отправить по почте. 1С поддерживает экспорт в следующие форматы:
| Формат | Метод экспорта | Особенности |
|---|---|---|
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С может быть недостаточно. Рассмотрим продвинутые сценарии:
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. Использование