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

16.01.23

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

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Пример отчетов - заказы на номенклатуру по дате отгрузки
.zip 30,34Kb
5
5 Скачать (1 SM) Купить за 1 850 руб.

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

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

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

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

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

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

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

10000 руб.

02.09.2020    159339    872    399    

861

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

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

15.05.2024    8679    implecs_team    6    

47

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

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

3 стартмани

05.02.2024    6989    56    obmailok    21    

79

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

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

1 стартмани

31.01.2024    3145    5    Yashazz    1    

34

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

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

2 стартмани

11.12.2023    10799    23    John_d    25    

124

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

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

05.12.2023    8010    PROSTO-1C    15    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. evn-zorin 33 19.01.23 09:55 Сейчас в теме
Интересно, век живи, век учись)
3. schthaxe 54 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 54 13.10.23 17:33 Сейчас в теме
(4) Вы знаете у меня такое очень смутное ощущение что в группировках СКД просто используется типовой механизм автогруппировки. То есть при формировании СКД отчета неявно но принудительно вызываются методы
НачатьАвтогруппировкуСтрок()/ЗакончитьАвтогруппировкуСтрок().
Либо это те же самые методы, либо очень похожие но отдельно для СКД.
А то, что написано в статье - это просто попытка работать внутри автогруппировки.
Но это моя гипотеза.
6. user2013846 19.03.24 23:12 Сейчас в теме
Если у отчета нет своей формы, то в общей форме ФормаОтчета все переделывается в В БП 3.0 (3.0.147.25)
7. NenavizhySKD 06.08.24 12:22 Сейчас в теме
Зачем в "Задача 0)" вот этот код?
СтрРод = стр.Родитель;
Где эта переменная СтрРод используется?
Оставьте свое сообщение