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

28.05.22

Разработка - СКД

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

 

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.

СКД Объединение ячеек Постобработка Скрытие колонок

См. также

SALE! 20%

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

12000 9600 руб.

02.09.2020    101097    554    385    

598

1C:Предприятие для программистов: Запросы и отчеты. Онлайн-интенсив с 27 ноября по 27 декабря 2023г.

1С-программирование Запросы СКД Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Данный онлайн-курс предусматривает углубленное изучение языка запросов и возможностей системы компоновки данных, которые понадобятся при разработке отчетов, работающих на платформе “1С:Предприятие” в рамках различных прикладных решений. Курс предназначен для тех, кто уже имеет определенные навыки конфигурирования и программирования в системе “1С:Предприятие”, а также для опытных пользователей различных прикладных решений, которые используют в своей работе отчеты разного назначения. Курс является вторым курсом траектории развития 1С-Разработчика, с углубленным изучением тем "Язык запросов" и "Отчеты", которые были рассмотрены в рамках “Базового курса для начинающих 1С-программистов”.

7500 руб.

04.10.2023    2475    48    0    

47

Печать любых непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать любые печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

3480 руб.

22.08.2023    1204    1    4    

3

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    5395    YA_418728146    6    

118

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    14363    112    sapervodichka    106    

123

Система контроля ведения учета [БСП]

Универсальные функции Механизмы типовых конфигураций БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    6648    quazare    8    

107

Модули общего назначения - готовые полезные функции и процедуры конфигураций на БСП

Универсальные функции БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

25.04.2022    13131    quazare    11    

136
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. echo77 1843 28.05.22 15:03 Сейчас в теме
(0) А оформите, пожалуйста код, как код1С и в сниппеты их - так он будет выглядеть компактно и сама публикация станет лучше. Сейчас вижу кучу пустых строк - вроде, кода мало, а выглядит растянуто. Спасибо
DrAku1a; oldcopy; Shmell; ixijixi; RustIG; anatsen; mrChOP93; t278; json; artbear; rpgshnik; +11 Ответить
2. artbear 1443 28.05.22 15:57 Сейчас в теме
(1) Да, код вообще не отформатирован и нечитабелен (
DrAku1a; paybaseme; oldcopy; anatsen; t278; +5 Ответить
11. DrAku1a 1609 04.06.22 08:06 Сейчас в теме
(2) Код читабелен, хотя и не оформлен по стандартам 1С, и развлеченье автора с именами переменных для циклов.
Для I=-ТабДок.ВысотаТаблицы+1 по -ВысотаФ-1 Цикл
			НомерСтроки=-I;
Еще одна вариация "Обратного цикла" (когда нужен шаг -1, а есть только 1)
3. milkers 2802 30.05.22 08:16 Сейчас в теме
(1) (2) - Хорошо, переделаю
4. zqzq 23 30.05.22 09:16 Сейчас в теме
Вариант, когда итог нужно рассчитать лишь на определенном уровне группировок.
Можно в Конструкторе СКД добавить 2 раза ресурс:
1) по умолчанию пустое значение ""
2) указать выражение расчета и указать в "рассчитывать по" нужные группировки.

По сути в статье это и есть (за минусом "&Итоги"), непонятен смысл постобработки. Возможно задача неясно сформулирована в статье.
5. oldcopy 172 30.05.22 12:22 Сейчас в теме
Автор, ну нельзя так код выкладывать, пожалейте читателей, абсолютно нечитабельно.
6. hudyakov74 30.05.22 15:34 Сейчас в теме
это столько букв чтобы объединить что то типа пары ячеек?
7. milkers 2802 30.05.22 21:24 Сейчас в теме
(4) Если вам интересно, прочитайте здесь https://infostart.ru/1c/articles/1101676/?
про использование внутренних функций системы компоновки данных: Вычислить, ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив, ВычислитьВыражениеСГруппировкойТаблицаЗначений.

Частный случай когда система не дает использовать вложенные функции такого рода.
10. zqzq 23 31.05.22 10:46 Сейчас в теме
(7) Про эти функции не только читал, но и использовал на практике. В чём у вас с ними за проблема, так и не понял. Но согласен, что они ведут себя иногда неочевидно.
8. milkers 2802 30.05.22 21:25 Сейчас в теме
(5) Исправил
mrChOP93; EvgeniyOlxovskiy; oldcopy; +3 Ответить
9. milkers 2802 30.05.22 21:25 Сейчас в теме
(6) Всегда готов узнать про более оптимальный вариант.
Оставьте свое сообщение