gifts2017

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

Опубликовал Алексей Леонов (axelerleo) в раздел Программирование - Практика программирования

В данном материале рассматривается процесс разработки механизма заполнения документов и справочников по шаблону.
Материал большой, букв много, так что не судите строго. :)
Данный механизм подойдет как для типовых конфигураций, так и для отраслевых и самописных.
В типовых конфигурациях есть некоторые алгоритмы заполнения предопределенными значениями при создании нового документа или справочника (например, организация по умолчанию, склад по умолчанию), и т.п.
Но что если в поступлении нам надо подставлять один склад, в реализации - другой, а в самописном документе - третий? Именно такую механику предусматривает данный механизм.
Он не претендует на полноценное решение, но может стать хорошей основой для дальнейшей разработки.

В типовых конфигурациях (например, УТ 10.3, УПП, Комплексная автоматизация) механизм значений по умолчанию основан на плане видов характеристик  НастройкиПользователей и связанном с ним регистре.

Однажды в одной светлой голове возникла мысль - а почему бы не сделать свои значения по умолчанию для каждого документа или справочника? И процесс пошел.

Рецепт не такой уж и сложный. Судите сами.

Нам понадобятся:

Общий неглобальный модуль  - 1 шт. (Я создал новый и назвал ПодпискиНаСобытия, вы можете использовать любой удобный)

Подписки на события ОбработкаЗаполнения- 2 шт. Одна - на документы, одна - на справочники.

Регистр сведений - 1 шт.

Я назвал его ПользовательскиеШаблоныЗаполнения (или как вам угодно назвать).

Измерения:

Пользователь - справочник Пользователи

Настройка - Строка, 255 знаков (В большинстве случаев должно хватать)

Ресурсы:

Значение - ХранилищеЗначения

Реквизиты:

ВидНастройки - Строка, 20  (В нашем примере там будет всегда записано либо слово "Справочники" либо "Документы")

Все просто. Мы заполняем реквизиты шапки нужными нам значениями, записываем в храилище значения, и при создании нового документа или справочника подставляем их.

Но дьявол, как известно, кроется в деталях.

Для начала разберемся с формой записи нашего регистра.

Прежде всего, поясню, почему вид настройки и настройка были выбраны в виде строки. Это сделано с целью обращения к метаданным через квадратные скобки - т.е. из конструкции Метаданные[ВидНастройки][Настройка] мы получим например

Метаданные.Справочники.Номенклатура или Метаданные.Документа.РеализацияТоваровУслуг.

 

Чтобы все работало корректно, нам понадобится немного докрутить поведение элементов управления.

ВидНастройки мы представим в виде переключателя, и укажем список выбора с двумя значениями "Документы" и "Справочники"

Поле Настройка заполним программно:

&НаСервере
Процедура ЗаполнитьПоМетаданнымНаСервере(ВидНастройки)
	
	Элементы.Настройка.СписокВыбора.Очистить();
	ТЗМетаданных.Очистить();
	ПредставлениеНастройки = "";
	ТаблицаШаблонаЗаполнения.Очистить();
	
	Для Каждого ВидМетаданных Из Метаданные[ВидНастройки] Цикл
		
		Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
		СтрТЗ = ТЗМетаданных.Добавить();
		СтрТЗ.Имя = ВидМетаданных.Имя;
		СтрТЗ.Синоним = ВидМетаданных.Синоним;
	КонецЦикла;
	
КонецПроцедуры

ТЗМетаданных - это таблица значений, которую мы используем для сопоставления имени и синонима метаданных, чтобы пользователь выбирал привычные "Договоры контрагентов", а в настройку записывался идентификатор ДоговорыКонтрагентов.

На форму мы вынесем реквизит ПредставлениеНастройки, и при его изменении будем менять настройку.

&НаКлиенте
Процедура НастройкаПриИзменении(Элемент)
	ОтборТЗ = Новый Структура("Синоним", ПредставлениеНастройки);
	НайденныеСтроки = ТЗМетаданных.НайтиСтроки(ОтборТЗ);
	Если НайденныеСтроки.Количество() = 1 Тогда
		Запись.Настройка = ТЗМетаданных.НайтиСтроки(ОтборТЗ)[0].Имя;
		НастройкаПриИзмененииНаСервере();
	КонецЕсли;
	
КонецПроцедуры

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

 

&НаСервере
Процедура НастройкаПриИзмененииНаСервере()
	
	ОбъектМетаданных = Метаданные[Запись.ВидНастройки][Запись.Настройка];
	ТаблицаШаблонаЗаполнения.Очистить();
	Для Каждого МетаРеквизит Из ОбъектМетаданных.Реквизиты цикл
		
		ЭтоНужныйТип = Ложь;
		Для Каждого МетаТип Из МетаРеквизит.Тип.типы() Цикл
			ЭтоСправочник = Справочники.ТипВсеСсылки().СодержитТип(МетаТип);
			ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(МетаТип);
			ЭтоПеречисление = Перечисления.ТипВсеСсылки().СодержитТип(МетаТип);
			
			Если ЭтоСправочник ИЛИ ЭтоДокумент ИЛИ ЭтоПеречисление Тогда
				СтрТЗ = ТаблицаШаблонаЗаполнения.Добавить();
				СтрТЗ.Поле = МетаРеквизит.Имя;
				СтрТЗ.ПредставлениеПоля = МетаРеквизит.Синоним;
				СтрТЗ.Значение = Новый (МетаТип);
				Прервать;
			КонецЕсли;
		КонецЦикла;	
		
	КонецЦикла;
	
КонецПроцедуры

И при записи мы помещаем заполненный шаблон в хранилище:

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	ТекущийОбъект.Значение = Новый ХранилищеЗначения(ТаблицаШаблонаЗаполнения.Выгрузить());
	
КонецПроцедуры

Полный листинг всего модуля формы я приведу в конце материала.

 

С формой разобрались, осталось совсем чуть-чуть.

 

У нас есть две подписки на события. В первой тип источника указываем "ДокументСсылка", во второй "СправочикСсылка".

 

В общем модуле пишем обработчик:

Процедура РС_ЗаполнениеСправочниковИзНастроекПользователя(Источник, ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) Экспорт
	
	Если ДанныеЗаполнения = Неопределено Тогда
		ДанныеЗаполнения = Новый Структура;
	КонецЕсли;
	
	Запрос = Новый Запрос("ВЫБРАТЬ
	|	РС_НастройкиПользователей.Пользователь,
	|	РС_НастройкиПользователей.Настройка,
	|	РС_НастройкиПользователей.Значение,
	|	РС_НастройкиПользователей.ВидНастройки
	|ИЗ
	|	РегистрСведений.РС_НастройкиПользователей КАК РС_НастройкиПользователей
	|ГДЕ
	|	РС_НастройкиПользователей.Пользователь = &Пользователь
	|	И РС_НастройкиПользователей.Настройка = &Настройка
	|	И РС_НастройкиПользователей.ВидНастройки = &ВидНастройки");
	Запрос.УстановитьПараметр("Пользователь", ПользователиКлиентСервер.АвторизованныйПользователь());
	Запрос.УстановитьПараметр("Настройка", Источник.Метаданные().Имя);
	Запрос.УстановитьПараметр("ВидНастройки", "Справочники");
						  
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Хранилище = Выборка.Значение;
		ТаблицаШаблонаЗаполнения = Хранилище.Получить();
		Для Каждого СтрокаШаблона Из ТаблицаШаблонаЗаполнения Цикл
			Если ЗначениеЗаполнено(СтрокаШаблона.Значение) Тогда
				ДанныеЗаполнения.Вставить(СтрокаШаблона.Поле, СтрокаШаблона.Значение);
				Если Метаданные.Справочники[Источник.Метаданные().Имя].Реквизиты[СтрокаШаблона.Поле].ЗаполнятьИзДанныхЗаполнения Тогда
					ДанныеЗаполнения.Вставить(СтрокаШаблона.Поле, СтрокаШаблона.Значение);
				Иначе
					Источник[СтрокаШаблона.Поле] = СтрокаШаблона.Значение;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

 

Вот здесь-то нам и пригодятся наши строковые реквизиты "Настройка" и "ВидНастройки".

 

На этом все.

 

P.S.:

Как и обещал, листинг модуля формы записи регистра сведений.

&НаКлиенте
Процедура НастройкаПриИзменении(Элемент)
	ОтборТЗ = Новый Структура("Синоним", ПредставлениеНастройки);
	НайденныеСтроки = ТЗМетаданных.НайтиСтроки(ОтборТЗ);
	Если НайденныеСтроки.Количество() = 1 Тогда
		Запись.Настройка = ТЗМетаданных.НайтиСтроки(ОтборТЗ)[0].Имя;
		НастройкаПриИзмененииНаСервере();
	КонецЕсли;
	
КонецПроцедуры

&НаСервере
Процедура НастройкаПриИзмененииНаСервере()
	
	ОбъектМетаданных = Метаданные[Запись.ВидНастройки][Запись.Настройка];
	ТаблицаШаблонаЗаполнения.Очистить();
	Для Каждого МетаРеквизит Из ОбъектМетаданных.Реквизиты цикл
		
		ЭтоНужныйТип = Ложь;
		Для Каждого МетаТип Из МетаРеквизит.Тип.типы() Цикл
			ЭтоСправочник = Справочники.ТипВсеСсылки().СодержитТип(МетаТип);
			ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(МетаТип);
			ЭтоПеречисление = Перечисления.ТипВсеСсылки().СодержитТип(МетаТип);
			
			Если ЭтоСправочник ИЛИ ЭтоДокумент ИЛИ ЭтоПеречисление Тогда
				СтрТЗ = ТаблицаШаблонаЗаполнения.Добавить();
				СтрТЗ.Поле = МетаРеквизит.Имя;
				СтрТЗ.ПредставлениеПоля = МетаРеквизит.Синоним;
				СтрТЗ.Значение = Новый (МетаТип);
				Прервать;
			КонецЕсли;
		КонецЦикла;	
		
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если Не ЗначениеЗаполнено(Запись.ВидНастройки) Тогда
		Запись.ВидНастройки = "Документы";
		ЗаполнитьПоМетаданнымНаСервере(Запись.ВидНастройки);
	КонецЕсли;
	
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьПоМетаданнымНаСервере(ВидНастройки)
	
	Элементы.Настройка.СписокВыбора.Очистить();
	ТЗМетаданных.Очистить();
	ПредставлениеНастройки = "";
	ТаблицаШаблонаЗаполнения.Очистить();
	
	Для Каждого ВидМетаданных Из Метаданные[ВидНастройки] Цикл
		
		Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
		СтрТЗ = ТЗМетаданных.Добавить();
		СтрТЗ.Имя = ВидМетаданных.Имя;
		СтрТЗ.Синоним = ВидМетаданных.Синоним;
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ВидНастройкиПриИзменении(Элемент)
	
	ЗаполнитьПоМетаданнымНаСервере(Запись.ВидНастройки);

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

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	ТекущийОбъект.Значение = Новый ХранилищеЗначения(ТаблицаШаблонаЗаполнения.Выгрузить());
	
КонецПроцедуры

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	//Вставить содержимое обработчика
	Если Не ЗначениеЗаполнено(Параметры.Ключ.Пользователь) Тогда
		Запись.Пользователь = ПользователиКлиентСервер.АвторизованныйПользователь();
	КонецЕсли;
	Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		Элементы.Пользователь.ТолькоПросмотр = Истина;
	КонецЕсли;
	
КонецПроцедуры

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
	
	Запрос = Новый Запрос("ВЫБРАТЬ
	|	РС_НастройкиПользователей.Пользователь,
	|	РС_НастройкиПользователей.Настройка,
	|	РС_НастройкиПользователей.Значение,
	|	РС_НастройкиПользователей.ВидНастройки
	|ИЗ
	|	РегистрСведений.РС_НастройкиПользователей КАК РС_НастройкиПользователей");
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		ХЗ = Выборка.Значение;
		ТЗ = ХЗ.Получить();
	КонецЦикла;
	ХЗ = ТекущийОбъект.Значение;
	ТЗ = ХЗ.Получить();
	ТаблицаШаблонаЗаполнения.Загрузить(ТЗ);
	Попытка
		Для Каждого ВидМетаданных Из Метаданные[Запись.ВидНастройки] Цикл
			
			Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
			СтрТЗ = ТЗМетаданных.Добавить();
			СтрТЗ.Имя = ВидМетаданных.Имя;
			СтрТЗ.Синоним = ВидМетаданных.Синоним;
		КонецЦикла;
		
		ПредставлениеНастройки = Метаданные[Запись.ВидНастройки][Запись.Настройка].Синоним;
		
	Исключение
	КонецПопытки;
	
КонецПроцедуры
 

Всем спасибо за потраченное время! Буду рад любой критике и комментариям.

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

Наименование Файл Версия Размер
Конфигурация Заполнение по шаблонам 6
.cf 29,31Kb
22.06.15
6
.cf 29,31Kb Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. aspirator 23 (aspirator23) 06.06.15 15:43
Вроде бы и ничего гениального, но в практике пригодится.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа