Полезные процедуры по работе с СКД и табличными документами (часть 2)

27.09.16

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

Еще несколько универсальных процедур

Скачать файл

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

Наименование По подписке [?] Купить один файл
Пример к публикации 8.3 (ОФ+УФ).erf
.erf 18,75Kb
41
41 Скачать (1 SM) Купить за 1 850 руб.

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

1. Работа с расшифровками. Получение значений группировок для текущей ячейки

На данную тему уже есть публикации. Но универсальных процедур на эту тему я не нашел. 

Имеем отчет следующего вида

Когда пользователь кликает по ячейке требуется:

  • Определить, например, Подразделение, соответствующее текущей ячейке
  • Определить значения всех группировок, соответствующих текущей ячейке

Предлагаемые процедуры решают данную задачу за несколько строк, например, так:

Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
	СтандартнаяОбработка = Ложь;
	ОчиститьСообщения();
	
	// 1
	ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
								"Подразделение", 
								ДанныеРасшифровки, 
								Расшифровка);
	Сообщить("Подразделение : " + ТекущееПодразделение);
	
	// 2
	ПоляРасшифровкиВВидеТаблицы = ПолучитьПоляРасшифровкиВВидеТаблицы(
								Расшифровка, 
								ДанныеРасшифровки);
	Для Каждого Строка Из ПоляРасшифровкиВВидеТаблицы Цикл
		ТекстСообщения = 
			"Уровень: " + Строка.Уровень + ";	" + 
			"Поле: " + Строка.Поле + ";	" + 
			"Значение: " + Строка.Значение + ";	";
			
			Сообщить(ТекстСообщения);
	КонецЦикла;
	
КонецПроцедуры

При выполнении данного кода получим примерно следующий вывод

Подразделение : Пискаревка

Уровень: 0;     Поле: Количество;       Значение: ;	
Уровень: 1;     Поле: Склад;            Значение: Розничный;	
Уровень: 2;     Поле: Подразделение;    Значение: Пискаревка;	
Уровень: 3;     Поле: Регион;           Значение: Северный р-н;	
Уровень: 1;     Поле: ВидТовара;        Значение: Аксессуары;	
Уровень: 1;     Поле: Товар;            Значение: Термос;

Отмечу несколько моментов:

  • Данные процедуры получают только значения группировок и не получают значения ресурсов. Например, поле Количество в описанном примере содержит значение NULL
  • Поле Уровень в таблице расшифровки рассчитывается от нижней группировки к верхней. Для горизонтальных и вертикальных группировок уровень считается раздельно
Сами процедуры
Функция ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(ИмяГруппировки, ДанныеРасшифровки, ТекущаяРасшифровка) Экспорт
	
	ПоляРасшифровки = ПолучитьПоляРасшифровкиВВидеТаблицы(ТекущаяРасшифровка, ДанныеРасшифровки);
	НайденнаяСтрока = ПоляРасшифровки.Найти(ИмяГруппировки, "Поле");
	Если Не НайденнаяСтрока = Неопределено Тогда
		Возврат НайденнаяСтрока.Значение;
	КонецЕсли;
	
	// Пример вызова:
	//Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
	//	Склад = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке("Склад", ДанныеРасшифровки, Расшифровка);
	//КонецПроцедуры
КонецФункции

Функция ПолучитьПоляРасшифровкиВВидеТаблицы(ТекущаяРасшифровка, ДанныеРасшифровки) Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Уровень"); // уровень группировки в структуре отчета СКД
	Результат.Колонки.Добавить("Поле"); // имя поля или группировки
	Результат.Колонки.Добавить("Значение");
	Результат.Колонки.Добавить("Идентификатор"); // идентификаторв в коллекции ДанныеРасшифровки.Элементы
	
	ДобавитьПолеРасшифровкиВТаблицуРекурсивно(Результат, ТекущаяРасшифровка, ДанныеРасшифровки);
	
	Возврат Результат;
	
	// Пример вызова:
	//Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
	//	ПоляРасшифорвки = ПолучитьПоляРасшифровкиВВидеТаблицы(Расшифровка, ДанныеРасшифровки);
	//КонецПроцедуры
КонецФункции

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

2. Получение области шапки в отчете СКД

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

Рассмотрим типовую задачу. Есть отчет следующего вида.


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

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

3. Печать нескольких табличных документов с различными параметрами.

Предлагаемая процедура помещает массив табличных документов в один файл PDF с использованием объекта ПакетОтображаемыхДокументов. Такой подход удобно использовать, когда, например, нужно несколько отчетов собрать в один файл, причем для каждого необходимо использовать отдельный масштаб 

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

Заключение

Все процедуры тестировались на версии платформы 8.3. 

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

Уточнение 

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

Постобработка табличного документа СКД - это зло. ОДНАКО, существуют случаи, когда без нее не обойтись. И тогда постобработка уже становится не "злом", а "крайней мерой". В нашей среде принято ссылаться на популярных авторов, которые описывают возможности СКД. Но при этом упускается из вида, что эти возможности покрывают не все возможные случаи, с которыми приходится сталкиваться на практике. Когда напишешь 30-40 отчетов на СКД для капризных клиентов, понимаешь что у этого инструмента есть ограничения. Так вот эти ограничения НИГДЕ не описаны. Сталкиваясь с ними каждый разработчик начинает придумывать свой велосипед. Я постарался восполнить данный пробел и описал решения таких задач, которые нельзя (или очень трудоемко) решать настройками. Существенным недостатком моих двух публикаций является то, что я предлагаю решение проблемы без ее подробного описания. Из-за этого возникает ряд непониманий со стороны других разработчиков, которые с данными проблемами не сталкивались, или им удавалось их обойти (но не  решить)

См. также

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

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

10000 руб.

02.09.2020    157605    856    399    

859

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

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

15.05.2024    8274    implecs_team    6    

46

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

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

3 стартмани

05.02.2024    6830    54    obmailok    21    

79

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

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

1 стартмани

31.01.2024    3113    5    Yashazz    1    

34

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

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

2 стартмани

11.12.2023    10657    23    John_d    25    

124

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

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

05.12.2023    7811    PROSTO-1C    14    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. r0610201 315 27.09.16 08:51 Сейчас в теме
Выровнять заголовки по центру можно вообще без кода при помощи условного оформления.
2. json 3349 27.09.16 09:15 Сейчас в теме
(1) r0610201, спасибо за комментарий. Но предполагаю, что вы невнимательно прочитали публикацию.
Существует ряд случаев, когда условным оформлением это сделать проблематично. Об этом сказано в статье.
German_Tagil; +1 Ответить
3. soulsteps 73 27.09.16 11:14 Сейчас в теме
В этой процедуре

Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ОчиститьСообщения();

// 1
ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
"Подразделение",
ДанныеРасшифровки,
Расшифровка);
Сообщить("Подразделение : " + ТекущееПодразделение);

// 2
ПоляРасшифровкиВВидеТаблицы = ПолучитьПоляРасшифровкиВВидеТаблицы(
Расшифровка,
ДанныеРасшифровки);
Для Каждого Строка Из ПоляРасшифровкиВВидеТаблицы Цикл
ТекстСообщения =
"Уровень: " + Строка.Уровень + "; " +
"Поле: " + Строка.Поле + "; " +
"Значение: " + Строка.Значение + "; ";

Сообщить(ТекстСообщения);
КонецЦикла;

КонецПроцедуры

не обнаружил передачу (локальное определение) переменной ДанныеРасшифровки? Хотя идет обращение по коду:
ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
"Подразделение",
ДанныеРасшифровки,
Расшифровка);
Обработку не скачивал, смотрю только код. Если это какая-то глобальная переменная или параметр формы, просьба уточнить, возможно ДанныеРасшифровки = Расшифровка?
user717534; +1 Ответить
4. json 3349 27.09.16 11:18 Сейчас в теме
(3) soulsteps,
Расширение формы отчета (Report form extension)
ДанныеРасшифровки (DetailsData)
Использование:

Чтение и запись.
Описание:

Тип: ДанныеРасшифровкиКомпоновкиДанных.
Содержит данные расшифровки последнего выполненного отчета.

Доступность:

Толстый клиент.

В тексте приведен пример для обычных форм. В управляемых формах в этой переменной хранится не сам объект, а ссылка на него во временном хранилище. Эти нюансы учтены в приложенном к статье примере
5. soulsteps 73 27.09.16 13:42 Сейчас в теме
(4) я это и хотел услышать (уточнение))
user717534; +1 Ответить
14. ol_xak 26 06.02.19 17:42 Сейчас в теме
(3)А ведь вопрос был правильный
15. json 3349 07.02.19 08:34 Сейчас в теме
(14) ответил же на вопрос. Или ответ не понятен?
В управляемых формах есть реквизит формы ДанныеРасшифровки, в котором хранится адрес во временном хранилище, а в обычных формах в этом реквизите хранятся сами данные

Для обычных форм:
	// 1
	ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
								"Подразделение", 
								ДанныеРасшифровки, 
								Расшифровка);


Для управляемых:
	// 1
	ТекущееПодразделение = ПолучитьЗначениеПоИмениГруппировкиВРасшифровке(
								"Подразделение", 
								ПолучитьИзВременногоХранилища(ДанныеРасшифровки), 
								Расшифровка);
16. ol_xak 26 07.02.19 15:47 Сейчас в теме
(15) Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
откуда в данной процедуре появляется переменная ДанныеРасшифровки
17. json 3349 07.02.19 15:59 Сейчас в теме
(16) читайте внимательно предыдущее сообщение. Там все разжевано.
В управляемых формах есть реквизит формы ДанныеРасшифровки
18. ol_xak 26 07.02.19 16:51 Сейчас в теме
(17)А в обычной форме? Я не критикую, просто пытаюсь использовать предложенный метод, но не получается. Где взять ДанныеРасшифровки в процедуре РезультатОбработкаРасшифровки? Использую неуправляемую форму обработки.
19. json 3349 07.02.19 16:58 Сейчас в теме
(18) по обычной форме цитата из справки

Расширение формы отчета (Report form extension)
ДанныеРасшифровки (DetailsData)
Использование:

Чтение и запись.
Описание:

Тип: ДанныеРасшифровкиКомпоновкиДанных.
Содержит данные расшифровки последнего выполненного отчета.

Доступность:

Толстый клиент.
Показать


То есть расширение формы отчета имеет такой реквизит ДанныеРасшифровки. В форме отчета он есть по умолчанию (если основной реквизит формы - внешний или внутренний отчет).

Разница между параметрами Расшифровка и ДанныеРасшифровки следующая:
в ДанныеРасшифровки - хранятся данные по всему сформированному отчету
в Расшифровка - хранится ключ, по которому можно искать в ДанныеРасшифровки. Этот ключ хранится в значении ячейки, по которой кликает пользователь
6. Поручик 4692 27.09.16 19:59 Сейчас в теме
(0) Не обращай внимания на критиканов.
user717534; +1 Ответить
7. PrinzOfMunchen 84 29.09.16 05:19 Сейчас в теме
Недавно писал нечто подобное, описанному в первом примере. Только мне надо было получить ВСЕ значения полей группировки и детальных записей (без ресурсов) в виде плоской таблицы, где колонки - это выбранные поля. Знатные извращения...))
8. Nuuq 76 02.11.16 13:13 Сейчас в теме
А есть пример по образу сделать получение области итогов СКД по вертикали и общие по горизонтали - программно добавить туда новое поле и заполнить его?
9. Yashazz 4789 07.11.16 21:01 Сейчас в теме
Забавно. Тоже буквально вчера понадобилось выгрести значения текущей расшифровки, всех полей уровня и, естесссно, родительских группировок. Тоже сделал через таблицу значений. Подумывал сериализовать "ДанныеРасшифровки" и поиграться с её xdto, но там не оказалось ничего интересного. Остальное - тоже, в общем, очевидные вещи.

Автор прав, пост-обработка это зло. Но иногда зла не хватает)) Могу от себя добавить, что ввиду непредсказуемости внешнего вида результатного табличного документа делаю такие пост-обработки, привязываясь к специально заданным расшифровкам, перегоняя моксель в его сериализованный вид xml и орудуя уже в нём. Так хоть меньше шансов обломаться, если юзверь перенастроит СКД. Так что рекомендую отказаться от дикости вроде "ВысотаТаблицы" и работать через xpath или объекты DOM. Ей-ей, надёжнее)

10. rasswet 82 09.11.16 08:07 Сейчас в теме
спасибо, интересные вещи.
11. German_Tagil 43 10.11.16 20:33 Сейчас в теме
12. Makushimo 160 11.11.16 06:31 Сейчас в теме
13. AzagTot 41 11.11.16 12:00 Сейчас в теме
Спасибо! Очень полезный цикл статей.
А кто знает как можно сдвинуть таблицу на несколько колонок? Чтобы вывод начинался не с первой колонки, а, например, с 3-й. При этом другие таблицы в отчете должны остаться без изменения.
Оставьте свое сообщение