Вступление
Однажды на работе прилетает задача: сделать для бухгалтеров отчёт. Простой вроде бы — нажал кнопку, и сразу на печать. Ну что там сложного? Ан нет! Оказалось, что отчёт должен строго соответствовать ГОСТу! Это вам не шутки: никакой ручной правки в Excel, всё чётко по стандарту — шрифты, отступы, расположение реквизитов. Малейшее отклонение — и бухгалтерия не примет.
Итак, отчёт собран в конструкторе СКД (это такая удобная визуальная штука для таблиц с данными). Данные выводит правильно, молодец. Но вот незадача: нет шапки — ни названия, ни дат, ни подписей. И подвала нет — где расшифровка подписей, примечания. А ГОСТ без них — как суп без соли, не годится!
Первым делом был испробован штатный макет конструктора — тот, что находится на вкладке «Макеты» в конструкторе СКД. Перепробовали, как казалось, тогда уже все настройки, но нужного результата добиться не удавалось: шапка отображалась неправильно, а подвал не прилипал к низу страницы.
Пришлось воспользоваться интернетом и поискать еще несколько вариантов. Однако какие бы варианты ни находились, все они требовали то добавить макет в конфигурацию, то использовать очевидно через одно место работающее решение. Лезть в конфигурацию ради внешнего отчёта — это очевидный костыль, а костыли, как справедливо сказано в первой главе «Чистого кода», — зло для любой программы, которую нужно потом поддерживать. А работающее через одно место решение тоже не подходило.
Тогда пришлось подключить все извилины своего мозга и пришла мысль, которая, как назло, раньше не приходила: создать дополнительный макет прямо внутри внешнего отчёта и объединить его с макетом на СКД. Не трогая при этом конфигурацию, а сделать два независимых макета: один — для вывода данных (СКД), другой — для идеального оформления шапки и подвала по ГОСТу. И просто склеить их при компоновке данных. И это наконец-то сработало.
И теперь стоит разобрать этот вариант подробнее.
Разбор решения
После того как в конструкторе уже все сделано, и осталось только добавить шапки и подвал.
Сначала заходим в структуру своего внешнего отчета и создаем дополнительный макет.

Задаем области макета, которые нам нужны, указываем параметры и расположение реквизитов, например, как на картинке задана шапка.

И задан подвал:
![]()
Теперь заходим в объект своего внешнего отчета и создаем событие "ПриКомпоновкеРезультата":
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
Далее прописываем действия, которые необходимы для объединения макета, который формируется компоновщиком данных, и дополнительного макета, который мы создали в структуре отчета.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартную обработку
Настройки = КомпоновщикНастроек.ПолучитьНастройки(); // Получаем настройки отчета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Создаем макет компоновки данных
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ДокументРезультат.Очистить();
///////////////
// Получаем дополнительный макет с описанием вывода логотипа
МакетЗаголовокПодвал = ПолучитьМакет("ПодвалШапка");
// Получаем область Заголовок
ОбластьЗаголовок = МакетЗаголовокПодвал.ПолучитьОбласть("Шапка");
ОбластьЗаголовок.Параметры.ДатаНачала = Формат(Настройки.ПараметрыДанных.Элементы[4].Значение.ДатаНачала, "ДФ=MMMM");
ОбластьЗаголовок.Параметры.ГодШапки = Формат(Настройки.ПараметрыДанных.Элементы[4].Значение.ДатаНачала, "ДФ=y");
ОбластьЗаголовок.Параметры.Организация = Настройки.ПараметрыДанных.Элементы[20].Значение;
ОбластьЗаголовок.Параметры.ИНН = Настройки.ПараметрыДанных.Элементы[20].Значение.ИНН;
ОбластьЗаголовок.Параметры.Отделение = "";
ОбластьЗаголовок.Параметры.Ферма = "";
ОбластьЗаголовок.Параметры.Бригада = "";
Сейчас = ТекущаяДата();
ОбластьЗаголовок.Параметры.Число = Формат(Сейчас, "ДФ=d");
ОбластьЗаголовок.Параметры.Месяц = Формат(Сейчас, "ДФ=MM");
ОбластьЗаголовок.Параметры.Год = Формат(Сейчас, "ДФ=yyyy");
//ОбластьЗаголовок.Параметры.ПредставлениеПериода = Настройки.ПараметрыДанных.Элементы[7].Значение;
ДокументРезультат.Вывести(ОбластьЗаголовок);
///////////////
// Выводим результат отчета в табличный документ "ДокументРезультат"
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Получаем область Заголовок
ОбластьПодвал = МакетЗаголовокПодвал.ПолучитьОбласть("Подвал");
ДокументРезультат.Вывести(ОбластьПодвал);
КонецПроцедуры
Код хорошо прокомментирован, но мы все-таки разберем подробнее, что мы сделали.
Первым делом отключили стандартную обработку. Это позволяет выполнять события не в той последовательности, в которой они выполняются по умолчанию.
СтандартнаяОбработка = Ложь;
Теперь получаем через компоновщик настроек текущие настройки отчёта (период, отборы, параметры), которые пользователь выбрал на форме. Они понадобятся позже для подстановки в шапку (например, дата, организация).
Настройки = КомпоновщикНастроек.ПолучитьНастройки(); // Получаем настройки отчета
После этого нужно создать макет компоновки данных. Из внешнего отчёта извлекается макет с именем "ОсновнаяСхемаКомпоновкиДанных"— это и есть та самая таблица, которую вы настроили в конструкторе СКД. На основе схемы и настроек строится готовый макет, который позже будет заполнен данными.
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
Теперь инициализируем процессор компоновки. Процессор — это движок, который выполнит запросы, соберёт данные и подготовит их к выводу. Он пока не выводит результат, а только готовит.
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
Очистим табличный документ, который будет показан пользователю от предыдущих выводов.
ДокументРезультат.Очистить();
Теперь приступаем к работе с дополнительным макетом. Из отчета получаем наш дополнительный макет "ПодвалШапка".
МакетЗаголовокПодвал = ПолучитьМакет("ПодвалШапка");
Получим область шапки.
ОбластьЗаголовок = МакетЗаголовокПодвал.ПолучитьОбласть("Шапка");
Далее необходимо заполнить параметры области. В параметры шапки подставляются значения из настроек отчёта (период, организация, ИНН) и текущая дата.
ОбластьЗаголовок.Параметры.ДатаНачала = Формат(Настройки.ПараметрыДанных.Элементы[4].Значение.ДатаНачала, "ДФ=MMMM");
ОбластьЗаголовок.Параметры.ГодШапки = Формат(Настройки.ПараметрыДанных.Элементы[4].Значение.ДатаНачала, "ДФ=y");
ОбластьЗаголовок.Параметры.Организация = Настройки.ПараметрыДанных.Элементы[20].Значение;
ОбластьЗаголовок.Параметры.ИНН = Настройки.ПараметрыДанных.Элементы[20].Значение.ИНН;
ОбластьЗаголовок.Параметры.Отделение = "";
ОбластьЗаголовок.Параметры.Ферма = "";
ОбластьЗаголовок.Параметры.Бригада = "";
Сейчас = ТекущаяДата();
ОбластьЗаголовок.Параметры.Число = Формат(Сейчас, "ДФ=d");
ОбластьЗаголовок.Параметры.Месяц = Формат(Сейчас, "ДФ=MM");
ОбластьЗаголовок.Параметры.Год = Формат(Сейчас, "ДФ=yyyy");
Шапка выводится в итоговый табличный документ первой — сверху.
ДокументРезультат.Вывести(ОбластьЗаголовок);
После вывода шапки нужно добавить основную часть отчета. В коде создаётся процессор вывода, который берёт подготовленные процессором компоновки данные и выводит их в тот же табличный документ — сразу после шапки. Это таблица, сформированная СКД.
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Из того же дополнительного макета берем область "Подвал" и выводим в конце всех таблиц.
ОбластьПодвал = МакетЗаголовокПодвал.ПолучитьОбласть("Подвал");
ДокументРезультат.Вывести(ОбластьПодвал);
Заключение
Итак, мы детально разобрали практическую задачу, с которой, смею предположить, сталкивался почти каждый разработчик отчётов на СКД. Суть её до боли знакома: как добавить в отчёт нестандартную шапку и подвал, при этом строго соблюдая требования ГОСТа, но не внося ни единого изменения в конфигурацию. Штатные средства СКД, а именно встроенный макет на одноимённой вкладке, часто пасуют перед жёсткими типографскими требованиями: шапка может «уплыть», подвал — не прижаться к низу страницы, а нумерация — съехать.
Предложенный в статье способ оказался не просто рабочим, а проверенным. Он заключается в создании дополнительного макета прямо внутри внешнего отчёта и последующем программном объединении этого макета с основным макетом СКД в событии ПриКомпоновкеРезультата. Мы наглядно показали, как отключить стандартную обработку, получить настройки, инициализировать процессоры, а затем вывести сначала кастомную шапку, потом основную таблицу (сформированную СКД), и в самом конце — подвал.
Весь этот механизм был разобран на конкретном, «живом» примере — отчёте «О движении скота и птицы на ферме».
Описанный подход даёт разработчику главное — чистоту архитектуры. Никаких костылей в виде правки общих макетов или расширений. При этом он обеспечивает полностью кастомизированный печатный вид, который можно верстать как угодно: логотипы, рамки, нестандартные шрифты, объединение ячеек — всё, что позволяет табличный документ 1С. А бухгалтеры остаются довольны, потому что отчёт выглядит именно так, как требует проверяющая организация. Никаких доработок в Excel, никаких ручных правок.
Метод универсален. Он подходит не только для строгих ГОСТ-отчётов, но и для любых ситуаций, когда стандартных средств оформления СКД становится недостаточно: внутренние бланки, акты сверки, счета-фактуры, договоры, реестры документов — всё это можно реализовать по той же схеме.
Разумеется, этот метод не претендует на звание «единственно правильного». Существуют и другие подходы: использование расширений, сложные макеты оформления внутри схемы СКД, вывод через табличный документ в обход компоновки. У каждого свои плюсы и минусы. Наш же вариант проверен.
Если вдруг кто-то из коллег знает более интересное или изящное решение — пожалуйста, поделитесь! Очень интересно будет узнать что-то новое, обменяться опытом и, возможно, найти ещё более простой способ.
Вступайте в нашу телеграмм-группу Инфостарт