Прошлая публикация по СКД показала, что тема актуальная, поэтому решил написать еще одну статью с универсальными процедурами для построения отчетов из моей копилки.
1. Работа с расшифровками. Получение значений группировок для текущей ячейки
На данную тему уже есть публикации. Но универсальных процедур на эту тему я не нашел.
Имеем отчет следующего вида
Когда пользователь кликает по ячейке требуется:
- Определить, например, Подразделение, соответствующее текущей ячейке
- Определить значения всех группировок, соответствующих текущей ячейке
Предлагаемые процедуры решают данную задачу за несколько строк, например, так:
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ОчиститьСообщения();
// 1
ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
"Подразделение",
ДанныеРасшифровки,
Расшифровка);
Сообщить("Подразделение : " + ТекущееПодразделение);
// 2
ПоляРасшифровкиВВидеТаблицы = ПолучитьПоляРасшифровкиВВидеТаблицы(
Расшифровка,
ДанныеРасшифровки);
Для Каждого Строка Из ПоляРасшифровкиВВидеТаблицы Цикл
ТекстСообщения =
"Уровень: " + Строка.Уровень + "; " +
"Поле: " + Строка.Поле + "; " +
"Значение: " + Строка.Значение + "; ";
Сообщить(ТекстСообщения);
КонецЦикла;
КонецПроцедуры
При выполнении данного кода получим примерно следующий вывод
Подразделение : Пискаревка
Уровень: 0; Поле: Количество; Значение: ;
Уровень: 1; Поле: Склад; Значение: Розничный;
Уровень: 2; Поле: Подразделение; Значение: Пискаревка;
Уровень: 3; Поле: Регион; Значение: Северный р-н;
Уровень: 1; Поле: ВидТовара; Значение: Аксессуары;
Уровень: 1; Поле: Товар; Значение: Термос;
Отмечу несколько моментов:
- Данные процедуры получают только значения группировок и не получают значения ресурсов. Например, поле Количество в описанном примере содержит значение NULL
- Поле Уровень в таблице расшифровки рассчитывается от нижней группировки к верхней. Для горизонтальных и вертикальных группировок уровень считается раздельно
Сами процедуры
Функция ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(ИмяГруппировки, ДанныеРасшифровки, ТекущаяРасшифровка) Экспорт
ПоляРасшифровки = ПолучитьПоляРасшифровкиВВидеТаблицы(ТекущаяРасшифровка, ДанныеРасшифровки);
НайденнаяСтрока = ПоляРасшифровки.Найти(ИмяГруппировки, "Поле");
Если Не НайденнаяСтрока = Неопределено Тогда
Возврат НайденнаяСтрока.Значение;
КонецЕсли;
// Пример вызова:
//Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
// Склад = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке("Склад", ДанныеРасшифровки, Расшифровка);
//КонецПроцедуры
КонецФункции
Функция ПолучитьПоляРасшифровкиВВидеТаблицы(ТекущаяРасшифровка, ДанныеРасшифровки) Экспорт
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Уровень"); // уровень группировки в структуре отчета СКД
Результат.Колонки.Добавить("Поле"); // имя поля или группировки
Результат.Колонки.Добавить("Значение");
Результат.Колонки.Добавить("Идентификатор"); // идентификаторв в коллекции ДанныеРасшифровки.Элементы
ДобавитьПолеРасшифровкиВТаблицуРекурсивно(Результат, ТекущаяРасшифровка, ДанныеРасшифровки);
Возврат Результат;
// Пример вызова:
//Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
// ПоляРасшифорвки = ПолучитьПоляРасшифровкиВВидеТаблицы(Расшифровка, ДанныеРасшифровки);
//КонецПроцедуры
КонецФункции
Процедура ДобавитьПолеРасшифровкиВТаблицуРекурсивно(ТаблицаРасшифровки, ТекущаяРасшифровка, ДанныеРасшифровки, Уровень = 0)
ЭлементРасшифровки = ДанныеРасшифровки.Элементы[ТекущаяРасшифровка];
УровеньРодителя = Уровень;
Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
УровеньРодителя = УровеньРодителя + 1;
МассивПолей = ЭлементРасшифровки.ПолучитьПоля();
Для Каждого Поле Из МассивПолей Цикл
НоваяСтрока = ТаблицаРасшифровки.Добавить();
НоваяСтрока.Поле = Поле.Поле;
НоваяСтрока.Значение = Поле.Значение;
НоваяСтрока.Уровень = Уровень;
НоваяСтрока.Идентификатор = ЭлементРасшифровки.Идентификатор;
КонецЦикла;
КонецЕсли;
МассивРодителей = ЭлементРасшифровки.ПолучитьРодителей();
Для Каждого Родитель Из МассивРодителей Цикл
ДобавитьПолеРасшифровкиВТаблицуРекурсивно(
ТаблицаРасшифровки,
Родитель.Идентификатор,
ДанныеРасшифровки,
УровеньРодителя);
КонецЦикла;
КонецПроцедуры
2. Получение области шапки в отчете СКД
Существует ряд случаев, когда необходимо получить область шапки в сформированном табличном документе СКД. . Примером могут служить случаи, когда для некоторых ячеек в шапке нельзя задать макет или условное оформление, скажем для заголовка ресурсов или заголовка группы полей.
Рассмотрим типовую задачу. Есть отчет следующего вида.
Требуется все заголовки в шапке выровнять по центру. Данную задачу можно выполнить с помощью макетов СКД. Но в этом случае возникают проблемы, когда пользователь изменяет состав и порядок полей в отчете. Намного проще решить эту задачу при постобработке результата:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ВывестиСКДВТабличныйДокумент(
СхемаКомпоновкиДанных,
ДокументРезультат,
КомпоновщикНастроек);
МассивОбластейШапок = ПолучитьМассивОбластейШапокТабличногоДокументаСКД(ДокументРезультат);
МассивОбластейШапок[0].ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
КонецПроцедуры
Сами процедуры
Функция ПолучитьМассивОбластейШапокТабличногоДокументаСКД(ДокументРезультат) Экспорт
МассивОбластей = Новый Массив;
Для НомерСтроки = 1 По ДокументРезультат.ВысотаТаблицы Цикл
Если НЕ ЭтоЯчейкаШапки(ДокументРезультат.Область(НомерСтроки, 1)) Тогда
Продолжить;
КонецЕсли;
КоординатыПравогоНижнегоУглаШапки = ПолучитьКоординатыПравогоНижнегоУглаШапки(ДокументРезультат, НомерСтроки);
МассивОбластей.Добавить(
ДокументРезультат.Область(
НомерСтроки,
1,
КоординатыПравогоНижнегоУглаШапки.Верх,
КоординатыПравогоНижнегоУглаШапки.Лево )
);
НомерСтроки = КоординатыПравогоНижнегоУглаШапки.Верх;
КонецЦикла;
Возврат МассивОбластей;
КонецФункции
Функция ЭтоЯчейкаШапки(Ячейка)
Возврат Ячейка.РежимИзмененияРазмераКолонки = РежимИзмененияРазмера.БыстроеИзменение;
КонецФункции
Функция ПолучитьКоординатыПравогоНижнегоУглаШапки(ТабличныйДокумент, ПерваяСтрокаШапки)
ПоследняяСтрокаШапки = ПерваяСтрокаШапки;
Для НомерСтроки = ПерваяСтрокаШапки+1 По ТабличныйДокумент.ВысотаТаблицы Цикл
Если НЕ ЭтоЯчейкаШапки(ТабличныйДокумент.Область(НомерСтроки,1)) Тогда
Прервать;
КонецЕсли;
ПоследняяСтрокаШапки = НомерСтроки;
КонецЦикла;
Для НомерКолонки = -ТабличныйДокумент.ШиринаТаблицы По -1 Цикл
Если ЭтоЯчейкаШапки(ТабличныйДокумент.Область(ПерваяСтрокаШапки, -НомерКолонки)) Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Возврат Новый Структура("Верх,Лево", ПоследняяСтрокаШапки, -НомерКолонки);
КонецФункции
3. Печать нескольких табличных документов с различными параметрами.
Предлагаемая процедура помещает массив табличных документов в один файл PDF с использованием объекта ПакетОтображаемыхДокументов. Такой подход удобно использовать, когда, например, нужно несколько отчетов собрать в один файл, причем для каждого необходимо использовать отдельный масштаб
Процедура ОбъединитьМассивТабличныхДокументовВФайлПДФ(МассивТабличныхДокументов, ИмяФайла) Экспорт
Пакет = Новый ПакетОтображаемыхДокументов;
Для каждого ТабличныйДокумент из МассивТабличныхДокументов Цикл
ЭлементПакета = Пакет.Состав.Добавить();
ДокументРезультат = Новый ТабличныйДокумент;
ДокументРезультат.Вывести(ТабличныйДокумент); // если не делать такой финт, то в некоторых случаях программа падает с системной ошибкой
ЗаполнитьЗначенияСвойств(ДокументРезультат, ТабличныйДокумент);
ЭлементПакета.Данные = ПоместитьВоВременноеХранилище(ДокументРезультат);
КонецЦикла;
Пакет.ЗаписатьФайлДляПечати(ИмяФайла);
КонецПроцедуры
Заключение
Все процедуры тестировались на версии платформы 8.3.
Прикладываю внешний отчет с примерами для обычных и управляемых форм к описанным в данной публикации приемам.
Уточнение
Хочу особо отметить следующее: в этой и предыдущей статье я привел несколько процедур по постобработке табличного документа СКД. НО я также, как и остальные негативно высказавшиеся комментаторы стараюсь и очень рекомендую всем разработчикам ПО МАКСИМУМУ задействовать возможности СКД, и не использовать доработку кодом, если можно обойтись без этого.
Постобработка табличного документа СКД - это зло. ОДНАКО, существуют случаи, когда без нее не обойтись. И тогда постобработка уже становится не "злом", а "крайней мерой". В нашей среде принято ссылаться на популярных авторов, которые описывают возможности СКД. Но при этом упускается из вида, что эти возможности покрывают не все возможные случаи, с которыми приходится сталкиваться на практике. Когда напишешь 30-40 отчетов на СКД для капризных клиентов, понимаешь что у этого инструмента есть ограничения. Так вот эти ограничения НИГДЕ не описаны. Сталкиваясь с ними каждый разработчик начинает придумывать свой велосипед. Я постарался восполнить данный пробел и описал решения таких задач, которые нельзя (или очень трудоемко) решать настройками. Существенным недостатком моих двух публикаций является то, что я предлагаю решение проблемы без ее подробного описания. Из-за этого возникает ряд непониманий со стороны других разработчиков, которые с данными проблемами не сталкивались, или им удавалось их обойти (но не решить)