СКД: расшифровка данных по всей строке

Программирование - Инструментарий

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

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

Еще одним плюсом СКД является расшифровка, которая представляет собой всплывающее меню, содержащее доступные пользователю действия, такие как открытие ссылки на элемент, упорядочивание, группировка, оформление и пр. Если нужно изменить стандартную расшифровку, то можно воспользоваться событием ОбработкаРасшифровки. В этом событии можно сделать неободимые нам действия, получив расшифровку выделенной ячейки. Но что делать, если нам для выполнения каких-нибудь действий нужна расшифровка по всей строке, да еще с учетом группировок.

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

На просторах интернета ни чего подходящего не нашел и сделал в лоб. Посмотрел структуру ДанныеРасшифровки.Элементы, нашел логику, вытащил данные строки.

И так, для получения всей строки нам понадобится немного лука, морковки и имя первого поля (столбца) строки отчета:

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

Для этого пройдемся по структуре ДанныеРасшифровки.Элементы, начиная с начала отчета, и найдем первую расшифровку поля, имя которое совпадает с выделенной ячейкой. Запомним его индекс и пойдем в обратную сторону до "группового элемента" или пока не вернемся к началу отчета. Все, имя первого элемента строки (в переделах текущего уровня группировки) мы знаем.

Имя первого поля в строке нам понадобится, чтобы получить всю строку в текущей группировке, но, сперва нужно получить расшифровку в старших группировках:

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

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

Ну и основная функция, которая производит вышеописанные действия:

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

Также функция считывает данные расшифровки текущей строки, начиная с выделенной ячейки, к началу отчета, пока не дойдем до первого поля, и к концу отчета, пока поля не начнут повторяться.

Дополнительные функции:

Функция ИмяСв(Текст)
	Возврат СтрЗаменить(Текст, "." , "_");
КонецФункции

Процедура СообщениеОтладки(ТекстСообщения)
#Если Клиент Тогда
	ОтладкаВключена = Ложь;
	Если ОтладкаВключена Тогда
		Сообщить(ТекстСообщения);
	КонецЕсли;
#КонецЕсли
КонецПроцедуры

Расшифровка хорошо работает, если иерархия отчета настроена в виде цепочки. Пример обработки приложен.

ЗЫ: Пользуйтесь кодом на здоровье, дорабатывайте, критикуйте его, предлагайте свои «правильные» решения и не будьте жадинами, делитесь кодом)

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

Наименование Файл Версия Размер
Пример отчета для УПП
.erf 13,80Kb
20.12.16
3
.erf 13,80Kb 3 Скачать

См. также

Комментарии
1. Игорь Пашутин (Alien_job) 114 20.12.16 13:17 Сейчас в теме
Имхо, так делать не надо - такой подход блокирует возможность пользовательской настройки отчета. А еще пользователи захотят увидеть в отчете что они изменили и нужно будет редактировать ячейки ТабличногоДокумента, в общем нужно рисовать форму с табличной частью и не парить мозг "исследованиями"

Тут писал то же что и у вас вроде http://infostart.ru/public/383839/
после этого тот отчет сильно оброс требованиями, и выполнять их неудобно т.к. это отчет. Для тех кто всё равно будет есть кактус:

Можно создать макеты полей отчета и указать им в ПараметрРасшифровки всё что нужно (в том числе имя ячейки чтоб потом менять значение в ней). Так стабильнее


	Расшифровка = ТабличныйДокумент.ПолучитьОбласть(ИмяЯчейки).ТекущаяОбласть.Расшифровка;
	Поле = ДанныеРасшифровки.Элементы[Расшифровка];
	КоллекцияПолейРасшифровки = ПрочитатьПараметрыРасшифровки(Поле.ПолучитьПоля());

	ПолеПараметра = КоллекцияПолейРасшифровки.Найти(ИмяПараметра);
	
	Если ПолеПараметра <> Неопределено Тогда
		Результат.Вставить(ИмяПараметра, ПолеПараметра.Значение);
		Возврат Истина;
	КонецЕсли;

...Показать Скрыть
Прикрепленные файлы:
2. Алексей S (info_AlexS) 8 20.12.16 14:53 Сейчас в теме
(1)
такой подход блокирует возможность пользовательской настройки отчет

Такой подход наоборот не блокирует возможность пользовательской настройки отчета. Поясните что именно? А вот если "рисовать форму с табличной частью и не парить мозг исследованиями", то точно никакой пользовательской настройки не будет.
Странно что я не увидел вашу статью, хотя заголовок почти такой же)
С макетами я не очень разобрался, но попробую. Спасибо!

3. Игорь Пашутин (Alien_job) 114 20.12.16 15:11 Сейчас в теме
(2)Если пользователь начнет скрывать ненужные ему колонки и группировки на которые завязано заполнение справочника то нужных данных в расшифровке не станет. Если он поменяет группировки местами и вы будете обрабатывать расшифровку более "верхнего" элемента, то нужных данных в расшифровке не будет. Поэтому вместе с отчетом нужно передавать пользователю инструкцию - здесь трогай, сюда не нажимай.
4. Ruslan Odessa (rus128) 2 21.12.16 13:48 Сейчас в теме
Заметил опечатку ("неободимые") и ошибку (в русском языке нет слова "ни чего").
Оставьте свое сообщение