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. Полезные ссылки:
Другие разработки автора:
Акция! Вы можете скачать архив всех моих разработок, которые я предлагаю за StartMone, по Специальной цене: //infostart.ru/public/960899/#archive
PS: Надеюсь вам понравится эта и другие мои разработки на //infostart.ru/profile/48714/.
Очень жду ваших комментариев и пожеланий.
Молочников Олег Spb. 2024