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

16.01.23

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

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

Скачать файлы

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

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

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

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

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

Далее в статье используется функция ПолучитьМакетГруппировкиПоПолюГруппировки из типового модуля СтандартныеОтчеты (БП 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. отправной точкой послужила статья СКД: вывод некоторых группировок свернутыми

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

См. также

SALE! %

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

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

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

12000 10000 руб.

02.09.2020    93021    474    379    

530

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

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

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

01.09.2023    2517    KVIKS    14    

75

Гибкие отборы через СКД на управляемых формах. Демо-обработка

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

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

2 стартмани

07.06.2023    4176    24    quazare    7    

45

Вывод элементов иерархии верхнего уровня на СКД

СКД Платформа 1С v8.3 Абонемент ($m)

Как получить родителя первого уровня иерархического справочника с помощью СКД.

1 стартмани

06.06.2023    3270    echo77    6    

71

Обработка результатов запроса произвольными вычисляемыми полями. Обзор некоторых новых функций СКД

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

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

07.02.2023    4671    quazare    7    

38

Разрабатываем отчет на СКД, содержащий данные из расширения

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

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

17.10.2022    5807    al_zzz    10    

49
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. evn-zorin 32 19.01.23 09:55 Сейчас в теме
Интересно, век живи, век учись)
3. schthaxe 48 19.01.23 14:14 Сейчас в теме
(1) Вообще говоря мой самый первый вариант работал так: я делал копию отчета через процессор вывода в ДЗ в дерево, дерево перегонял в ТЗ, и потом вместо анализа типа результата как в статье - анализировал получившуюся ТЗ, обходя вместе с выводом макетов эту ТЗ.
Конечно по сравнению с старой версией эта - сама элегантность ))) Обычно на эти типы результата никто не смотрит, а зря...
cleaner_it; +1 Ответить
2. AllexSoft 19.01.23 10:41 Сейчас в теме
Любопытно, надо с этим поиграться... вот правда поддерживать такие вещи сложно, кто то поле тебя придет и ничего не поймет зачем так сделано и как это работает.
sys1c; cleaner_it; evn-zorin; +3 Ответить
Оставьте свое сообщение