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

13.01.24

Разработка - Универсальные функции

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

 

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)

 

Другие разработки автора:

Подсистема штрихкодирования серий номенклатуры (УТ 11, КА, ERP)Подсистема штрихкодирования серий номенклатуры (УТ 11, КА, ERP)
Подсистема 'Входной контроль' для ERP ,КА , УТ 11
Подсистема 'Входной контроль' для ERP ,КА , УТ 11
Электронный обходной лист (расширение) для ERP, ЗУП, КА
Отправка электронных писем по задолженностям клиентов (ERP, УТ 11)Отправка электронных писем по задолженностям клиентов (ERP, УТ 11)
Excel Studio for 1CExcel Studio for 1C
Настраиваемый управленческий балансНастраиваемый управленческий баланс
Динамические отчеты СКД
Динамические отчеты СКД
Фоновая отправка уведомлений
Генератор кодаГенератор кода

 

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

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

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

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

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

См. также

SALE! 15%

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

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

10000 руб.

02.09.2020    159417    872    399    

861

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

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

12000 руб.

02.02.2019    36761    43    22    

41

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

Стандартные конфигурации ERP, КА, УТ 11 позволяют работать с штрихкодированием серий. Есть только одно суровое ограничение – на упаковке должна быть этикетка для номенклатуры и отдельно для серии. Во многих случаях это критически неудобно.

12000 руб.

19.04.2021    22812    64    44    

57

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

Настраиваемый управленческий баланс в 1С предназначен для всех конфигураций, тестирован на: “Управление торговлей”, “Управление производственным предприятием”, “Комплексная автоматизация”, "ERP","УТ11". Содержит конструкторские средства для изменения состава статей баланса и их иерархии, формирования запросов для получения данных по статьям, изменения настроек отчетов для удобного формирования отчетов расшифровки по каждой из статей. Предусмотрено ручное введение данных по статьям баланса в виде ведомостей по датам.

12000 руб.

22.05.2011    98302    115    108    

188

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

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

21.05.2024    20126    dimanich70    81    

144

СКД WEB-интеграция Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Долгое время поддерживаю web-портал, в котором появилась необходимость создавать отчеты. Просмотрев различные фреймворки на js, я решил сделать свое решение, которое позволяло бы быстро разрабатывать и добавлять новые отчеты на web-портал.

2 стартмани

11.12.2023    10804    23    John_d    25    

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

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

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