Выборочная свертка группировок для СКД

16.01.23

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

Методика разработки отчета на СКД с возможностью свёртки части группировок по заданному программно условию. - свертка по значению поля (неотрицательные - сворачиваются); - свертка подчиненных в иерархии с произвольным количеством уровней.

Скачать исходный код

Наименование Файл Версия Размер
Пример отчетов - заказы на номенклатуру по дате отгрузки
.zip 30,34Kb
3
.zip 30,34Kb 3 Скачать

Задача: создать отчет на СКД таким образом, чтобы в нем некоторые группировки вывелись свернутыми.

Далее рассматриваются два примера — свертка всех группировок по условию на поле (свернуть все группы с неотрицательным значением по родительской группировке) и свертка подчиненной группировки у группировок с иерархией с произвольным количеством уровней.

Решать такую задачу без СКД просто — при выводе очередной строчки отчета требуется использовать методы НачатьГруппуСтрок/ЗакончитьГруппуСтрок. При использовании СКД возникают проблемы:

  • необходимость перехвата вывода определенных группировок
  • отключение автонастройки свертки/развертки групп.
  • анализ изменений в структуре.

Далее в статье используется функция ПолучитьМакетГруппировкиПоПолюГруппировки из типового модуля СтандартныеОтчеты (БП 2.0) / БухгалтерскиеОтчеты (БП 3.0). Если вы делаете отчет для базы, в которой нет этих модулей, текст этих функций вам потребуется перенести в модуль объекта (либо общий модуль, доступный из объекта).

 
 Текст функции, (с) 1с Бухгалтерия Предприятия

Конкретный пример — показать заказы на номенклатуру на дату отгрузки, структура — Номенклатура/Заказы.

 
 СКД, используемая для примера

Отчет формируется типовым образом:

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
	
	СтандартнаяОбработка=Ложь;
	
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
	МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
	ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных, ,ДанныеРасшифровки);
	ДокументРезультат.Очистить();
	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	ПроцессорВывода.УстановитьДокумент(ДокументРезультат);	
			

Задача 0) Для начала рассмотрим более простую задачу — свернуть именованную группировку, которая может оказаться на любом (заранее неизвестном) уровне в структуре. Для сворачивания используется метод ПоказатьУровеньГруппировокСтрок объекта типа ТабличныйДокумент. Этот метод принимает параметр - уровень группировки, аналогичный уровню, показываемому в контекстном меню в разделе "уровни группировок", только нумерация начинается с нуля.

 
 текст для примера, считается что структура "лесенкой" и в группировке поле поиска идет первым.

Задачи 1 и 2) Общая часть.

Для выборочной группировки требуется анализ выводимого макета, для чего используются методы НачатьВывод / Следующий / ВывестиЭлемент / ЗакончитьВывод объекта типа ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент.

Метод Следующий последовательно возвращает объекты типа ЭлементРезультатаКомпоновкиДанных.

Для решения задач используются следующие свойства этого объекта: полная информация о данных выводимой строчки в коллекции «ЗначенияПараметров», имя макета и тип элемента.

Имена макетов и параметров формализованы — все макеты именуются в виде «Макет#», и все параметры - «П#», где # это номер от одного и далее.

Для того чтобы понять, какая группировка выводится, используется функция ПолучитьМакетГруппировкиПоПолюГруппировки, которая возвращает массив объектов типа ОписаниеМакетаОбластиМакетаКомпоновкиДанных, содержащих данную группировку. Этот массив мы перезаписываем в массив строковых имен вида «Макет#», для удобства поиска.


	МакетГруппировкиНом = ПолучитьМакетГруппировкиПоПолюГруппировки(МакетКомпоновкиДанных, "Номенклатура");
	МакетНом = Новый Массив;
	Для Каждого МакетГруппировки Из МакетГруппировкиНом Цикл
		МакетНом.Добавить(МакетГруппировки.Имя);
	КонецЦикла;
	
	МакетГруппировкиЗаказ = ПолучитьМакетГруппировкиПоПолюГруппировки(МакетКомпоновкиДанных, "Заказ");
	МакетЗаказ = Новый Массив;
	Для Каждого МакетГруппировки Из МакетГруппировкиЗаказ Цикл
		МакетЗаказ.Добавить(МакетГруппировки.Имя);
	КонецЦикла;

Для того, чтобы получить данные о соблюдении условия свертки анализируется значение параметра П#, относящегося к полю, определяющему проверяемое значение и здесь у нас проблема — нет способа привязать параметр П к полю, как мы это сделали с макетами. Значение Параметра только содержит свойство Выражение, в котором прописано вычисляемое выражение. Для полей, описанных в разделе «Наборы данных», выражение имеет вид «НазваниеНабораДанных.НазваниеПоля», например НаборДанных1.Номенклатура, для вычисляемых же полей свойство «Выражение» содержит нормализованное значение в колонке «выражение»  - добавлена функция «Представление()», расставлены пробелы, регистры для функций, удалены лишние нули в числах, к каждому параметру добавлен набор данных. Поэтому даже просто скопировать значение из этой колонки не всегда получится. Я предлагаю в начало выражения Вычисляемого поля добавить маркер «0 +» и искать по фрагменту "(0 +" - скобка от того что в начале у вас после преобразования будет "Представление(0 +....".

Вложенные группировки выводятся не просто по очереди а в следующем формате:
( (Р) < ( ( (п) ) [( (п) ) ...] ) > ),
где ( - элемент результата со свойством «ТипЭлемента» = ТипЭлементаРезультатаКомпоновкиДанных.Начало,
) - элемент результата со свойством «ТипЭлемента» = ТипЭлементаРезультатаКомпоновкиДанных.Конец,
(Р) — элемент результата для родительской группировки, имеющий свойство «ТипЭлемента» = ТипЭлементаРезультатаКомпоновкиДанных.НачалоИКонец,
(п) — ... для подчиненной группировки (см. (Р) ),
<, > - я обозначил те места между элементами результатов куда следует добавить НачатьГруппуСтрок/ЗакончитьГруппуСтрок соответственно.

То есть каждая группировка имеет тип НачалоИКонец, и обрамляется элементами Начало и Конец, после чего следуют подчиненные группировки, имеющие тип НачалоИКонец, все вместе обрамленные элементами Начало и Конец и каждая по отдельности обрамлена элементами Начало и Конец.

Судя по всему, типовой механизм СКД вешает группы строк на какие то из этих элементов результатов, но на какие - точно узнать невозможно, так как метода определения текущего назначения группы строк на строку нет. И если не соблюдать парность типов элементов при ручном назначении групп строк, то у вас либо получится каша, либо никакой реакции. Парность гарантированно работает.

Общая идея такая — при получении результата типа НачалоИКонец и соблюдении нашего условия мы сразу ставим  НачатьГруппуСтрок, выводим все подчиненные группировки, после чего, соблюдая парность, ставим ЗакончитьГруппуСтрок.

Задача 1) Для отчета в разрезе Номенклатура/Заказ свернуть все группировки номенклатуры без дефицита (то есть таких, для которых остаток товара больше объема заказов).

	
	ИмяПараметраДефицит = Неопределено;
	ПроцессорВывода.НачатьВывод();
	ВыражениеДефицита = "(0 +";
	
	ЗначениеДефицита = 0;
	Пока Истина Цикл
		ЭлементРезультата = ПроцессорКомпоновкиДанных.Следующий();
		Если ЭлементРезультата = Неопределено Тогда
			Прервать;
		КонецЕсли;
		
		ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
		
		Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоИКонец Тогда
			
			Если МакетНом.Найти(ЭлементРезультата.Макет) <> Неопределено Тогда
				
				Если ИмяПараметраДефицит = Неопределено Тогда
					Для каждого Параметр Из МакетКомпоновкиДанных.Макеты[ЭлементРезультата.Макет].Параметры Цикл
						Попытка
							Если ТипЗнч(Параметр.Выражение) = Тип("Строка") И Найти(Параметр.Выражение, ВыражениеДефицита)>0 Тогда
								ИмяПараметраДефицит = Параметр.Имя;
								Прервать
							КонецЕсли;     
						Исключение
						КонецПопытки;
					КонецЦикла; 						
				КонецЕсли;
				
				ЗначениеДефицита = 0;
				
				Если ИмяПараметраДефицит <> Неопределено Тогда
					ЗначениеДефицита = ЭлементРезультата.ЗначенияПараметров[ИмяПараметраДефицит].Значение;
				КонецЕсли;
				Если ЗначениеДефицита>=0 Тогда
					ДокументРезультат.НачатьГруппуСтрок(ЭлементРезультата.ЗначенияПараметров.П1.Значение,Ложь);
				Иначе
					ДокументРезультат.НачатьГруппуСтрок(ЭлементРезультата.ЗначенияПараметров.П1.Значение,Истина);
				КонецЕсли;
				
				//( (Н)!( ( (з) ) ( (з) ) )!)
				УровеньНачала = 0;
				Пока Истина Цикл
					ЭлементРезультата = ПроцессорКомпоновкиДанных.Следующий();
					Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.Начало Тогда
						УровеньНачала = УровеньНачала + 1;
					ИначеЕсли ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.Конец Тогда
						УровеньНачала = УровеньНачала - 1;
					КонецЕсли;
					ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
					Если УровеньНачала = 0 Тогда Прервать КонецЕсли;
				КонецЦикла;
				
				ДокументРезультат.ЗакончитьГруппуСтрок();
				
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	ПроцессорВывода.ЗакончитьВывод();
	
КонецПроцедуры

Прим. При поиске используется Попытка потому что не каждый Параметр имеет поле Выражение. Но это тема для отдельной статьи.

Пример результата данного отчета:

 

 

Задача 2) Для отчета в разрезе Номенклатура/Заказ свернуть все группировки номенклатуры с подчиненными заказами.

В приведенной выше структуре надо поставить тип группировки номенклатуры - Иерархия.

Значения параметров имеют скалярные типы, и номенклатуру мы получаем в виде строки с наименованием. Обычно существует опасность что в базе может быть несколько элементов номенклатуры с одинаковым наименованием, поэтому искать ссылку по наименованию не предлагается. Вместо этого сначала помещаем все результаты в массив. Потом делаем вывод результатов из этого массива, проверяя, не является ли третий результат впереди группировкой «Заказ».

	ПроцессорВывода.НачатьВывод();
	мРезультат = Новый Массив;
	Пока Истина Цикл
	    ЭлементРезультата = ПроцессорКомпоновкиДанных.Следующий();
		мРезультат.Добавить(ЭлементРезультата);
	    Если ЭлементРезультата = Неопределено Тогда Прервать; КонецЕсли;
	КонецЦикла;
	
	Для х=0 по мРезультат.ВГраница()-1 Цикл
		ЭлементРезультата = мРезультат[х];
		
	    ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
		
		Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоИКонец Тогда

			Если МакетНом.Найти(ЭлементРезультата.Макет) <> Неопределено Тогда

				// Если у вас в номенклатуре гарантированно уникальные наименования номенклатуры тогда можно
				// не помещать результаты в массив а использовать проверку вида
				//ЗначРод = ЭлементРезультата.ЗначенияПараметров["П1"].Значение;
				//СсылкаРод = Справочники.Номенклатура.НайтиПоНаименованию(ЗначРод,Истина);
				//Если НЕ СсылкаРод.ЭтоГруппа Тогда
				
				СледЭлт = мРезультат[х+3];
				Если МакетЗаказ.Найти(СледЭлт.Макет) <> Неопределено Тогда

					ДокументРезультат.НачатьГруппуСтрок(ЭлементРезультата.ЗначенияПараметров.П1.Значение,Ложь);

					//( (Н)!( ( (з) ) ( (з) ) )!)
					УровеньНачала = 0;
					Пока Истина Цикл
						х = х+1;
						ЭлементРезультата = мРезультат[х];
						Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.Начало Тогда
							УровеньНачала = УровеньНачала + 1;
						ИначеЕсли ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.Конец Тогда
							УровеньНачала = УровеньНачала - 1;
						КонецЕсли;
						ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
						Если УровеньНачала = 0 Тогда Прервать КонецЕсли;
					КонецЦикла;
					
					ДокументРезультат.ЗакончитьГруппуСтрок();
					
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	ПроцессорВывода.ЗакончитьВывод();
	
КонецПроцедуры

Пример результата:

 

 

К статье прикрепрен примерный СКД, созданный под задачи организации: заказы берутся без пометки на удаление, заказ на который уже выписана реализация считается полностью отгруженным (нет резервирования для допоставки). В группировке Заказ типовое представление заменено на наименование Партнера. Для конфиденциальности на образцах наименования обрезаны. Отчеты работают в УТ11, ERP 2, если необходим вариант для УТ10, напишите в комментариях.

Отчеты тестировались на версии Платформы 1С:Предприятие 8.3 (8.3.21.1622), хотя старые версии отчета работали в УТ10 с платформ версии 8.3.5. Теоретически должно работать на любой платформе с поддержкой СКД.

P.S. отправной точкой послужила статья СКД: вывод некоторых группировок свернутыми

СКД система компоновки данных группировка макет параметр свертка строк. процессор вывода

См. также

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

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

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

10000 руб.

02.09.2020    124507    681    389    

732

Генератор схемы компоновки данных (СКД), написание кода схемы программно

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

По выбранной схеме компоновки данных генерирует программный код, который генерирует СКД, аналогичную исходной схеме. Есть дополнительные инструменты для просмотра дерева схемы, сравнение исходной схемы и полученной по коду, а также сравнение изменений в сгенерированном коде для исходной схемы и для измененной.

3 стартмани

05.02.2024    4325    29    obmailok    19    

67

Набор-объект для СКД по тексту или запросу

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

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    2127    2    Yashazz    0    

30

СКД на JavaScript в 1С

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

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

2 стартмани

11.12.2023    8345    20    John_d    25    

123

Использование менеджера временных таблиц в СКД

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

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

05.12.2023    4884    PROSTO-1C    13    

62

Модель СКД

Инструментарий разработчика СКД Платформа 1С v8.3 Система компоновки данных Абонемент ($m)

DSL для работы с СКД.

1 стартмани

15.11.2023    5986    15    kalyaka    5    

86

Пользовательские настройки отчетов 1С. Часть 1. Простые и расширенные настройки

СКД Инструкции пользователю Платформа 1С v8.3 Конфигурации 1cv8 1С:Бухгалтерия 3.0 Россия Бесплатно (free)

Простые приемы работы с отчетами на СКД. Что нужно знать пользователю про настройку отчетов, чтобы использовать их на полную катушку.

18.09.2023    7246    accounting_cons    7    

29

Разрыв страницы в СКД. Легко!

СКД Платформа 1С v8.3 Система компоновки данных Бесплатно (free)

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

01.09.2023    4729    KVIKS    15    

80
Комментарии
Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. evn-zorin 32 19.01.23 09:55 Сейчас в теме
Интересно, век живи, век учись)
3. schthaxe 53 19.01.23 14:14 Сейчас в теме
(1) Вообще говоря мой самый первый вариант работал так: я делал копию отчета через процессор вывода в ДЗ в дерево, дерево перегонял в ТЗ, и потом вместо анализа типа результата как в статье - анализировал получившуюся ТЗ, обходя вместе с выводом макетов эту ТЗ.
Конечно по сравнению с старой версией эта - сама элегантность ))) Обычно на эти типы результата никто не смотрит, а зря...
cleaner_it; +1 Ответить
2. AllexSoft 19.01.23 10:41 Сейчас в теме
Любопытно, надо с этим поиграться... вот правда поддерживать такие вещи сложно, кто то поле тебя придет и ничего не поймет зачем так сделано и как это работает.
sys1c; cleaner_it; evn-zorin; +3 Ответить
4. Smollsan 06.10.23 13:58 Сейчас в теме
Респект автору, который погружается в такие адские дебри!
В моем случае нужно было просто свернуть все группировки при выводе, метод ДокументРезультат.ПоказатьУровеньГруппировокСтрок() не помогал. Использовал часть кода из статьи - заработало!
schthaxe; +1 Ответить
5. schthaxe 53 13.10.23 17:33 Сейчас в теме
(4) Вы знаете у меня такое очень смутное ощущение что в группировках СКД просто используется типовой механизм автогруппировки. То есть при формировании СКД отчета неявно но принудительно вызываются методы
НачатьАвтогруппировкуСтрок()/ЗакончитьАвтогруппировкуСтрок().
Либо это те же самые методы, либо очень похожие но отдельно для СКД.
А то, что написано в статье - это просто попытка работать внутри автогруппировки.
Но это моя гипотеза.
6. user2013846 19.03.24 23:12 Сейчас в теме
Если у отчета нет своей формы, то в общей форме ФормаОтчета все переделывается в В БП 3.0 (3.0.147.25)
Оставьте свое сообщение