Каталог решений - Хитрости СКД. Часть 3

Хитрости СКД. Часть 3

Хитрости СКД. Часть 3

В наличии

Столкнулся с тем, что мне приходится писать гору отчетов. Во многих приходится использовать повторяющиеся приемы. Решил написать шпаргалку, которая, надеюсь пригодится не только мне. В этой статье: Объединение ячеек в отчете только на определенном уровне иерархии, Постобработка итогов в табличном документе, Скрытие колонок в зависимости от количества месяцев в периоде.

Категория:

Описание

 

1. Объединение ячеек в отчете только на определенном уровне иерархии

 

 

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

Удобно воспользоваться функцией Максима Гончарова из публикации Получаем уровень группировки ячейки табличного документа (infostart.ru) ПолучитьТаблицуУровнейПоСтрокам

Весь текст модуля:

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

СтандартнаяОбработка = Ложь;

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

Настройки = КомпоновщикНастроек.ПолучитьНастройки();

АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, Новый УникальныйИдентификатор);

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

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

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

ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных, , ДанныеРасшифровки, Истина);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;

ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных, Истина);

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

ДокументРезультат.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;

ДокументРезультат.АвтоМасштаб = Истина;

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

Функция ОбработатьТабличныйДокумент(ТабДок)

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

мЗапись.УстановитьСтроку("UTF-8");

СериализаторXDTO.ЗаписатьXML(мЗапись,ТабДок);

ТекстXML = мЗапись.Закрыть();

мЧтение = Новый ЧтениеXML;

мЧтение.УстановитьСтроку(ТекстXML);

ПострDOM = Новый ПостроительDOM;

ДанныеDOM = ПострDOM.Прочитать(мЧтение);

//уровни строк

ТаблицаУровнейПоСтрокам = ПолучитьТаблицуУровнейПоСтрокам(ДанныеDOM);

Уровни=ТаблицаУровнейПоСтрокам.Скопировать(,"Уровень");

Уровни.Свернуть("Уровень");

ВысотаФ = ТабДок.ФиксацияСверху;

ШиринаФ = ТабДок.ФиксацияСлева;

ОбъединяемаяОбласть = Неопределено;

ОбластьПоискаЗаголовков=ТабДок.Область(1,,ВысотаФ,);

ОбластьСДР=ТабДок.НайтиТекст("Сумма доп расхода",,ОбластьПоискаЗаголовков);

Если ОбластьСДР=Неопределено Тогда

Возврат ТабДок;

КонецЕсли;

ОбластьДДЗ=ТабДок.НайтиТекст("Документ доп. расходов",,ОбластьПоискаЗаголовков);

Если ОбластьДДЗ=Неопределено Тогда

Возврат ТабДок;

КонецЕсли;

ОбластьОписание=ТабДок.НайтиТекст("Описание",,ОбластьПоискаЗаголовков);

Если ОбластьОписание=Неопределено Тогда

Возврат ТабДок;

КонецЕсли;

Если ОбластьОписание.Лево<ОбластьДДЗ.Лево Тогда

Возврат ТабДок;

КонецЕсли;

СтрокиДопЗатрат= ТаблицаУровнейПоСтрокам.НайтиСтроки(Новый Структура("Уровень",Уровни.Количество()));

Для Каждого СтрокаТаблицыУровнейПоСтрокам из СтрокиДопЗатрат Цикл

НомерСтрокиДЗ = СтрокаТаблицыУровнейПоСтрокам.номер;

ОбластьСтрокиОписания=ТабДок.Область(НомерСтрокиДЗ,ОбластьОписание.Лево, НомерСтрокиДЗ, ОбластьСДР.Лево-1);

ОбластьСтрокиОписания.Объединить();

КонецЦикла;

Возврат ТабДок;

КонецФункции

//&НаСервереБезКонтекста

Функция ПолучитьТаблицуУровнейПоСтрокам(ДанныеDOMТабДок)

ТаблицаУровней = Новый ТаблицаЗначений;

ТаблицаУровней.Колонки.Добавить("Номер",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));

ТаблицаУровней.Колонки.Добавить("Уровень",Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0)));

УзлыУровнейDOMТабДок = ДанныеDOMТабДок.ПолучитьЭлементыПоИмени("vg");

ПредКонецГруппировки = 0;

Для инд = 0 по УзлыУровнейDOMТабДок.Количество() - 1 Цикл

УзелГруппы = УзлыУровнейDOMТабДок[инд];

НачалоГруппировки = 0;

КонецГруппировки = 0;

Для н = 0 По УзелГруппы.ДочерниеУзлы.Количество() - 1 Цикл

ПодУзел = УзелГруппы.ДочерниеУзлы[н];

Если ПодУзел.ИмяУзла = "b" Тогда

НачалоГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));

ИначеЕсли ПодУзел.ИмяУзла = "e" Тогда

КонецГруппировки = Число(СокрЛП(ПодУзел.ТекстовоеСодержимое));

КонецЕсли;

КонецЦикла;

Если НачалоГруппировки = 0 Тогда Продолжить КонецЕсли;

// если конца группировки не оказалось, то одна позиция в подгруппе

Если КонецГруппировки = 0 Тогда

КонецГруппировки = НачалоГруппировки

КонецЕсли;

//конец область увеличить нужно на 1

КонецГруппировки = КонецГруппировки + 1;

РодительскийУровень = 0;

Для Номер = НачалоГруппировки по КонецГруппировки Цикл

строкаТаблицы = ТаблицаУровней.Найти(Номер, "Номер");

Если строкаТаблицы = Неопределено Тогда

строкаТаблицы = ТаблицаУровней.Добавить();

строкаТаблицы.Номер = Номер;

строкаТаблицы.Уровень = РодительскийУровень + 1;

Если Номер = НачалоГруппировки Тогда

РодительскийУровень = 1;

КонецЕсли;

Иначе

Если Номер = НачалоГруппировки Тогда

РодительскийУровень = строкаТаблицы.Уровень

Иначе

строкаТаблицы.Уровень = РодительскийУровень + 1;

КонецЕсли;

КонецЕсли;

КонецЦикла;

КонецЦикла;

Возврат ТаблицаУровней;

КонецФункции

Суть алгоритма проста:

Получаем с помощью функции ПолучитьТаблицуУровнейПоСтрокам таблицу уровней для каждой строки табличного документа, находим в заголовках нужные теги, чтобы сориентироваться какие ячейки в строке объединять, находим строки с нужным уровнем и в каждой объединяем ячейки.

 

2. Постобработка итогов в табличном документе.

Иногда возможностей СКД не хватает, чтоб сформировать особенно хитрые итоги. Выход этой ситуации опять же описан у Максима Гончарова в публикации Получаем уровень группировки ячейки табличного документа (infostart.ru).

Я опишу лишь некоторые дополнения. Вариант, когда итог нужно рассчитать лишь на определенном уровне группировок.

В ресурсах делаем так, чтоб в нужной группировке, вместо чисел стояли литералы “ &Итоги”:

 

 

Код модуля можно взять из верхнего примера. Привожу отличия в коде:

Функция ОбработатьТабличныйДокумент(ТабДок)

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

мЗапись.УстановитьСтроку("UTF-8");

СериализаторXDTO.ЗаписатьXML(мЗапись,ТабДок);

ТекстXML = мЗапись.Закрыть();

мЧтение = Новый ЧтениеXML;

мЧтение.УстановитьСтроку(ТекстXML);

ПострDOM = Новый ПостроительDOM;

ДанныеDOM = ПострDOM.Прочитать(мЧтение);

//уровни строк

ТаблицаУровнейПоСтрокам = ПолучитьТаблицуУровнейПоСтрокам(ДанныеDOM);

Уровни=ТаблицаУровнейПоСтрокам.Скопировать(,"Уровень");

Уровни.Свернуть("Уровень");

ВысотаФ = ТабДок.ФиксацияСверху;

ШиринаФ = ТабДок.ФиксацияСлева;

ОбъединяемаяОбласть = Неопределено;

МассивИтоговСальдоСр=Новый Массив(Уровни.Количество()+1);

Для I=0 по Уровни.Количество() Цикл

МассивИтоговСальдоСр[I] =0;

КонецЦикла;

СписокРядов=Новый СписокЗначений;

СписокКолонок=Новый СписокЗначений;

ОбластьПоиска=ТабДок.НайтиТекст("&Итоги");

Пока ТипЗнч(ОбластьПоиска)<>Тип("Неопределено") Цикл

ОбработатьОбластьПоиска(ОбластьПоиска, СписокКолонок, СписокРядов,ТабДок);

КонецЦикла;

СписокКолонок.СортироватьПоЗначению(НаправлениеСортировки.Возр);

ТекУровень= Уровни.Количество()-1;

МаксУровень= ТекУровень;

ЗапрУровень= ТекУровень+1;

Для ИндексКолонки=0 По СписокКолонок.Количество()-1 Цикл

Для I=-ТабДок.ВысотаТаблицы+1 по -ВысотаФ-1 Цикл

НомерСтроки=-I;

строкаУровняПоСтрокам = ТаблицаУровнейПоСтрокам.Найти(НомерСтроки,"Номер");

Если строкаУровняПоСтрокам <> Неопределено Тогда

УровеньСтроки=строкаУровняПоСтрокам.Уровень;

Если УровеньСтроки= ЗапрУровень Тогда

Продолжить;

ИначеЕсли УровеньСтроки= МаксУровень Тогда

ЗначениеСтроки= ОбластьВЧисло(СписокКолонок[ИндексКолонки].Значение, НомерСтроки, ТабДок);

МассивИтоговСальдоСр[УровеньСтроки-1]=МассивИтоговСальдоСр[УровеньСтроки-1]+ЗначениеСтроки;

ТекУровень= УровеньСтроки;

ИначеЕсли УровеньСтроки< ТекУровень Тогда

ТекУровень= УровеньСтроки;

ЗначениеСтроки=МассивИтоговСальдоСр[УровеньСтроки];

МассивИтоговСальдоСр[УровеньСтроки-1]=МассивИтоговСальдоСр[УровеньСтроки-1]+ЗначениеСтроки;

МассивИтоговСальдоСр[УровеньСтроки]=0;

ТабДок.Область(НомерСтроки, СписокКолонок[ИндексКолонки].Значение, НомерСтроки, СписокКолонок[ИндексКолонки].Значение).ГоризонтальноеПоложение=ГоризонтальноеПоложение.Право;

ТабДок.Область(НомерСтроки, СписокКолонок[ИндексКолонки].Значение, НомерСтроки, СписокКолонок[ИндексКолонки].Значение).Текст=Формат(ЗначениеСтроки,"ЧДЦ=2");

КонецЕсли

Иначе

ЗначениеСтроки= ОбластьВЧисло(СписокКолонок[ИндексКолонки].Значение, НомерСтроки, ТабДок);

МассивИтоговСальдоСр[0]=МассивИтоговСальдоСр[0]+ЗначениеСтроки;

КонецЕсли;

КонецЦикла;

ТабДок.Область(ТабДок.ВысотаТаблицы, СписокКолонок[ИндексКолонки].Значение, ТабДок.ВысотаТаблицы, СписокКолонок[ИндексКолонки].Значение).ГоризонтальноеПоложение=ГоризонтальноеПоложение.Право;

ТабДок.Область(ТабДок.ВысотаТаблицы, СписокКолонок[ИндексКолонки].Значение, ТабДок.ВысотаТаблицы, СписокКолонок[ИндексКолонки].Значение).Текст=Формат( МассивИтоговСальдоСр[0],"ЧДЦ=2");

МассивИтоговСальдоСр[0]=0;

КонецЦикла;

Возврат ТабДок;

КонецФункции

Функция ОбластьВЧисло(НомерКолонки, НомерСтроки, Знач ТабДок)

Перем ПД, ТекстПД;

ТекстПД=ТабДок.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки).Текст;

ПД=?(ТекстПД="",0,Число(ТекстПД));

Возврат ПД;

КонецФункции

Процедура ОбработатьОбластьПоиска( ОбластьПоиска, Знач СписокКолонок, Знач СписокРядов,ТабДок);

Если ТипЗнч(ОбластьПоиска)<>Тип("Неопределено") и ОбластьПоиска.ШиринаКолонки>0 Тогда

Если СписокРядов.НайтиПоЗначению(ОбластьПоиска.Верх)=Неопределено Тогда

СписокРядов.Добавить(ОбластьПоиска.Верх);

КонецЕсли;

Если СписокКолонок.НайтиПоЗначению(ОбластьПоиска.Лево)=Неопределено Тогда

СписокКолонок.Добавить(ОбластьПоиска.Лево);

КонецЕсли;

КонецЕсли;

ОбластьПоиска_Право= ОбластьПоиска.Право;

ОбластьПоиска_Низ= ОбластьПоиска.Низ;

Если ОбластьПоиска_Право+1>ТабДок.ШиринаТаблицы Тогда

ОбластьПоиска_Низ= ОбластьПоиска_Низ+1;

Иначе

ОбластьПоиска_Право= ОбластьПоиска.Право+1;

КонецЕсли;

ОбластьПоиска=ТабДок.НайтиТекст("&СальдоСр",ТабДок.Область(ОбластьПоиска_Низ, ОбластьПоиска_Право, ОбластьПоиска_Низ, ОбластьПоиска_Право));

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

 

Алгоритм простой. Получаем уровни для каждой строки как и раньше, находим наши литералы и для нужных строк и колонок считаем наши итоги и помещаем их вместо литералов. Сразу отвечу на вопрос, функции СКД ВычислитьВыражение( ) для расчета таких итогов не получилось использовать из за их использовании на предыдущем уровне вложенности.

 

3. Скрытие колонок в зависимости от количества месяцев в периоде

 

Нужно добавить поле “ЭтоОбщиеИтоги” в Вычисляемые поля.

 

 

Также добавить дважды это поле в Ресурсы для общего итога и остальных группировок:

 

 

В параметры нужно добавить реквизит КМ (количество месяцев)

 

 

В условное оформление нужно поместить примерно следующее:

 

 

В этом примере колонки ОтклПроц,ОтклРуб,Комментарий скрываются во всех месяцах, кроме общих итогов. Колонки ОтклПроц,ОтклРуб скрываются везде если период отчета не равен 2 месяцам, что позволяет их сравнить.

Поле текст надо устанавливать=””, для корректной работы функции суммирования выделенных ячеек.

Таким образом мы получаем отчет с разверткой по месяцам, где в итогах всегда присутствует колонка комментарий и появляются отклонения исли период равен 2 месяцам.

 

4. Полезные ссылки:

Хитрости компоновки данных: произвольная иерархия для внешней таблицы данных в отчетах на СКД. (infostart.ru)

Хитрости компоновки данных: программное формирование заголовков отчета и колонок без использования макетов. (infostart.ru)

 

Акция! Вы можете скачать архив всех моих разработок, которые я предлагаю за StartMone, по Специальной  цене:  //infostart.ru/public/960899/#archive

PS: Надеюсь вам понравится эта и другие мои разработки на //infostart.ru/profile/48714/.

Очень жду ваших комментариев  и пожеланий.

Молочников Олег Spb. 2022.

has been added to your cart:
Оформление заказа