Макет СКД в 1С называют три разные вещи, и путаница между ними съедает часы отладки. Первая — макет отчёта типа «Схема компоновки данных» (обычно ОсновнаяСхемаКомпоновкиДанных) с наборами данных, полями, ресурсами и вариантами. Вторая — МакетКомпоновкиДанных: результат компиляции схемы с настройками, который строится перед выполнением запроса. Третья — свои макеты на вкладке «Макеты» конструктора схемы: области табличного документа, которыми подменяют стандартный вывод группировки, поля или шапки.
Со своим макетом отчёта СКД сталкиваются, когда стандартной таблицы мало: реестр с шапкой и подписями, строка контрагента с ИНН и КПП, итог суммой прописью, двухэтажная шапка. Ниже — настройка макетов группировок, выражения параметров макета, вывод отчёта кодом, отладка запроса, выгрузка в таблицу значений и расшифровка. Код написан для платформы 8.3, имена отчётов, макетов и полей замените на свои.
| Что называют макетом | Где находится | Зачем трогать |
|---|---|---|
| Схема компоновки данных | Макет отчёта, объект СхемаКомпоновкиДанных | Запрос, поля, ресурсы, параметры, варианты настроек |
| Макет компоновки | Создаётся при каждом формировании, объект МакетКомпоновкиДанных | Отладка запроса, ручной вывод, выгрузка в таблицу значений |
| Свой макет области | Вкладка «Макеты» конструктора, хранится внутри схемы | Нестандартный вид строк группировки, шапки, отдельного поля |
| Макет оформления | Параметр вывода «Макет оформления» в настройках варианта | Цвета и шрифты всего отчёта без изменения структуры |
Свой макет не заменяет схему: запрос, отборы и итоги по-прежнему считает СКД, а макет решает только, как нарисовать посчитанную строку.
На вкладке «Макеты» конструктора схемы добавляют четыре вида макетов:
Макеты группировок находят свою группировку по имени. Порядок настройки:
Контрагенты.ПредставлениеКонтрагента.Плата за свой макет — жёсткость. Строка выводится ровно так, как нарисована: поля, которые пользователь добавит в группировку через настройки, в ней не появятся. Если пользователь перестроит структуру варианта и группировка останется без имени, отчёт молча вернётся к стандартному виду.
Выражение параметра пишут на языке выражений СКД, а не на встроенном языке. В нём доступны поля группировки, их реквизиты через точку (Контрагент.ИНН), ресурсы, функции Представление, Формат, ЕстьNull и конструкция Выбор Когда … Тогда … Иначе … Конец. Поле, которого нет среди полей группировки и ресурсов, в строке группировки будет пустым.
| Параметр | Выражение | Результат |
|---|---|---|
| ПредставлениеКонтрагента | Представление(Контрагент) + ", ИНН " + ЕстьNull(Контрагент.ИНН, "") | ООО «Вектор», ИНН 7701234567 |
| Сумма | Формат(СуммаОборот, "ЧДЦ=2") | 125 400,00 |
| Пометка | Выбор Когда СуммаОборот < 0 Тогда "возврат" Иначе "" Конец | возврат |
| СуммаПрописью | МакетыОтчетовСервер.СуммаПрописью(СуммаОборот) | Сто двадцать пять тысяч четыреста рублей 00 копеек |
Последняя строка — вызов экспортной функции общего модуля: туда выносят то, что неудобно писать выражением. Модуль серверный и неглобальный, функцию вызывают через имя модуля:
// Общий модуль МакетыОтчетовСервер: флаг «Сервер», не глобальный
// Сумма прописью для параметра макета СКД.
Функция СуммаПрописью(Сумма) Экспорт
Если ТипЗнч(Сумма) <> Тип("Число") Или Сумма = 0 Тогда
Возврат "";
КонецЕсли;
ПредметИсчисления = "рубль, рубля, рублей, м, копейка, копейки, копеек, ж, 2";
Возврат ЧислоПрописью(Сумма, "Л = ru_RU; ДП = Ложь", ПредметИсчисления);
КонецФункции
// Контрагент с ИНН и КПП одной строкой. Реквизиты приходят параметрами,
// чтобы не выполнять запрос на каждую строку отчёта.
Функция ПредставлениеКонтрагента(Наименование, ИНН, КПП) Экспорт
Реквизиты = Новый Массив;
Если ЗначениеЗаполнено(ИНН) Тогда
Реквизиты.Добавить("ИНН " + ИНН);
КонецЕсли;
Если ЗначениеЗаполнено(КПП) Тогда
Реквизиты.Добавить("КПП " + КПП);
КонецЕсли;
Если Реквизиты.Количество() = 0 Тогда
Возврат Строка(Наименование);
КонецЕсли;
Возврат СтрШаблон("%1 (%2)", Наименование, СтрСоединить(Реквизиты, ", "));
КонецФункцииТипЗнч(Сумма) <> Тип("Число") — у группировки без движений ресурс приходит как NULL, и ЧислоПрописью на нём упадёт.ЧислоПрописью — предмет исчисления: формы слова «рубль», род, то же для копеек и число знаков дробной части.МакетыОтчетовСервер.ПредставлениеКонтрагента(Контрагент.Наименование, Контрагент.ИНН, Контрагент.КПП).Когда кроме таблицы СКД нужны шапка, подписи и настройки печати, стандартное формирование отключают в модуле объекта отчёта. Шапка и подвал берутся из обычного табличного макета, таблицу строит СКД. Параметр Период в схеме — типа СтандартныйПериод.
// Модуль объекта отчёта
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ДокументРезультат.Очистить();
Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Шапка и подвал — из обычного табличного макета отчёта
МакетОтчета = ПолучитьМакет("ШапкаИПодвал");
ОбластьШапки = МакетОтчета.ПолучитьОбласть("Шапка");
ОбластьШапки.Параметры.Заголовок = "Реестр продаж по контрагентам";
ЗначениеПериода = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(
Новый ПараметрКомпоновкиДанных("Период"));
Если ЗначениеПериода <> Неопределено И ЗначениеПериода.Использование Тогда
ОбластьШапки.Параметры.Период = ПредставлениеПериода(
ЗначениеПериода.Значение.ДатаНачала, ЗначениеПериода.Значение.ДатаОкончания);
КонецЕсли;
ДокументРезультат.Вывести(ОбластьШапки);
// Схема и настройки превращаются в макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
ДокументРезультат.Вывести(МакетОтчета.ПолучитьОбласть("Подвал"));
ДокументРезультат.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ДокументРезультат.АвтоМасштаб = Истина;
КонецПроцедурыСтандартнаяОбработка = Ложь — иначе после обработчика платформа выполнит стандартную компоновку сама.КомпоновщикМакета.Выполнить создаёт МакетКомпоновкиДанных: на этом шаге в него попадают свои макеты с вкладки «Макеты» и оформление варианта.Инициализировать со значением Истина разрешает функции общих модулей в выражениях. Без него параметр СуммаПрописью при таком выводе не вычислится.Вывести. ДанныеРасшифровки, переданные в компоновщик и процессор, сохраняют расшифровку ячеек.Отчёт показывает не те цифры — смотрят запрос из МакетКомпоновкиДанных. Это не текст набора из схемы, а результат компиляции: в нём только поля, используемые в варианте, а отборы пользователя превращены в параметры вида &П1. Функция в модуле объекта отчёта возвращает готовый к выполнению Запрос:
// Модуль объекта отчёта
Функция ЗапросМакетаКомпоновки() Экспорт
Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроек.ПолучитьНастройки());
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
Если ТипЗнч(НаборДанных) <> Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
Продолжить;
КонецЕсли;
Запрос = Новый Запрос(НаборДанных.Запрос);
Для Каждого ЗначениеПараметра Из МакетКомпоновки.ЗначенияПараметров Цикл
Запрос.УстановитьПараметр(ЗначениеПараметра.Имя, ЗначениеПараметра.Значение);
КонецЦикла;
Возврат Запрос;
КонецЦикла;
ВызватьИсключение НСтр("ru = 'В макете компоновки нет набора данных типа Запрос'");
КонецФункцииЗапрос у них нет.ЗначенияПараметров содержит и параметры схемы, и сгенерированные для отборов. Лишние параметры запрос игнорирует.Вызов из формы отчёта. Результат попадает в строковый реквизит ТекстЗапросаОтладка, выведенный многострочным полем:
&НаКлиенте
Процедура ПоказатьЗапрос(Команда)
ПоказатьЗапросОтчетаНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПоказатьЗапросОтчетаНаСервере()
ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
Запрос = ОтчетОбъект.ЗапросМакетаКомпоновки();
Строки = Новый Массив;
Строки.Добавить(Запрос.Текст);
Для Каждого Параметр Из Запрос.Параметры Цикл
Строки.Добавить(СтрШаблон("&%1 = %2", Параметр.Ключ, Параметр.Значение));
КонецЦикла;
КоличествоСтрок = Запрос.Выполнить().Выбрать().Количество();
Строки.Добавить("Строк в результате: " + Формат(КоличествоСтрок, "ЧН=0; ЧГ=0"));
ТекстЗапросаОтладка = СтрСоединить(Строки, Символы.ПС);
КонецПроцедурыРеквизитФормыВЗначение("Отчет") отдаёт объект отчёта с текущими настройками формы, включая отборы пользователя. Текст с параметрами переносят в консоль запросов и сравнивают результат с отчётом.
Тот же отчёт выполняют без табличного документа, когда цифры нужны обработке или рассылке. Компоновщику передают тип генератора ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений:
// Общий модуль с флагом «Сервер».
// Период — СтандартныйПериод, как у параметра Период в схеме отчёта.
Функция ДанныеОтчетаВТаблицу(ИмяОтчета, Период) Экспорт
Схема = Отчеты[ИмяОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
Компоновщик.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема));
Компоновщик.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
Компоновщик.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Период", Период);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Компоновщик.ПолучитьНастройки(), , ,
Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , , Истина);
Результат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат Результат;
КонецФункцииСхема.НастройкиПоУмолчанию — основной вариант. Для другого загрузите настройки из коллекции ВариантыНастроек схемы.Выполнить — тип генератора. В таком макете компоновки нет областей: свои макеты и оформление не участвуют, на выходе только колонки.УстановитьОбъект дерево значений.Стандартная ячейка СКД получает расшифровку автоматически. Ячейке своего макета её назначают явно:
Контрагент, а для строк с документами ещё и Регистратор.Отсюда ограничения. Элемент расшифровки знает только перечисленные поля: пропустили Регистратор — документ из ячейки не открыть, а «Расшифровать» не наложит отбор по этому полю. Ячейка без параметра расшифровки на двойной щелчок не реагирует. Своё поведение пишут в обработчике ОбработкаРасшифровки поля табличного документа в форме отчёта:
&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка, ДополнительныеПараметры)
Документ = ЗначениеПоляРасшифровки(ДанныеРасшифровки, Расшифровка, "Регистратор");
Если ЗначениеЗаполнено(Документ) Тогда
СтандартнаяОбработка = Ложь;
ПоказатьЗначение(, Документ);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЗначениеПоляРасшифровки(АдресДанныхРасшифровки, Расшифровка, ИмяПоля)
Если Не ЭтоАдресВременногоХранилища(АдресДанныхРасшифровки) Тогда
Возврат Неопределено;
КонецЕсли;
Данные = ПолучитьИзВременногоХранилища(АдресДанныхРасшифровки);
Если ТипЗнч(Данные) <> Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
Возврат Неопределено;
КонецЕсли;
Возврат НайтиЗначениеПоля(Данные.Элементы[Расшифровка], ИмяПоля);
КонецФункции
&НаСервереБезКонтекста
Функция НайтиЗначениеПоля(ЭлементРасшифровки, ИмяПоля)
Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
Для Каждого ЗначениеПоля Из ЭлементРасшифровки.ПолучитьПоля() Цикл
Если ЗначениеПоля.Поле = ИмяПоля Тогда
Возврат ЗначениеПоля.Значение;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Поля верхних группировок лежат в родительских элементах
Для Каждого Родитель Из ЭлементРасшифровки.ПолучитьРодителей() Цикл
Значение = НайтиЗначениеПоля(Родитель, ИмяПоля);
Если Значение <> Неопределено Тогда
Возврат Значение;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункцииДанныеРасшифровки — строковый реквизит формы с адресом во временном хранилище, его заполняет платформа при формировании. На сервер уходят адрес и идентификатор, а не вся форма.ЭлементРасшифровкиКомпоновкиДанныхПоля обязательна: у элемента группировки метода ПолучитьПоля нет.ПолучитьРодителей() находит поле верхней группировки, например контрагента для строки документа.СтандартнаяОбработка = Ложь ставится только при найденном документе, в остальных ячейках работает основное действие.&НаКлиенте. Компоновщики, процессоры и Запрос на тонком клиенте недоступны.Запрос запросили у набора-объекта или объединения. Проверяйте тип набора, как в ЗапросМакетаКомпоновки.ПолучитьПоля().ПолучитьИзВременногоХранилища.ЕстьNull склеивается со строкой.Истина, или модуль глобальный либо не серверный.Схема — описание: наборы данных, поля, ресурсы, параметры, варианты. Макет компоновки — её компиляция с конкретными настройками: готовый запрос, значения параметров и области вывода. Схему правят в конструкторе, макет компоновки получают кодом через КомпоновщикМакетаКомпоновкиДанных.
Макет ищет группировку по имени. Если у группировки в варианте нет имени, оно другое или пользователь заменил структуру в своих настройках, СКД выводит группировку стандартно и не сообщает об этом.
Да, если в макете есть параметр расшифровки и он назначен ячейке. В элемент расшифровки попадут только поля из его «Выражений полей».
Скомпилируйте макет генератором ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений и выведите результат в таблицу или дерево значений процессором ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений.
Если отчёт нужен в строгой форме — реестр для банка, акт с подписями, двухэтажная шапка — и при этом должен сохранить расшифровку и не снимать типовую конфигурацию с поддержки, проще поручить его разработчику: доработка отчётов и обработок 1С. Приложите пример нужного вида и опишите источники данных в форме размещения задания — исполнители оценят объём до начала работ.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.