В типовых конфигурациях (например, УТ 10.3, УПП, Комплексная автоматизация) механизм значений по умолчанию основан на плане видов характеристик НастройкиПользователей и связанном с ним регистре.
Однажды в одной светлой голове возникла мысль - а почему бы не сделать свои значения по умолчанию для каждого документа или справочника? И процесс пошел.
Рецепт не такой уж и сложный. Судите сами.
Нам понадобятся:
Общий неглобальный модуль - 1 шт. (Я создал новый и назвал ПодпискиНаСобытия, вы можете использовать любой удобный)
Подписки на события ОбработкаЗаполнения- 2 шт. Одна - на документы, одна - на справочники.
Регистр сведений - 1 шт.
Я назвал его ПользовательскиеШаблоныЗаполнения (или как вам угодно назвать).
Измерения:
Пользователь - справочник Пользователи
Настройка - Строка, 255 знаков (В большинстве случаев должно хватать)
Ресурсы:
Значение - ХранилищеЗначения
Реквизиты:
ВидНастройки - Строка, 20 (В нашем примере там будет всегда записано либо слово "Справочники" либо "Документы")
Все просто. Мы заполняем реквизиты шапки нужными нам значениями, записываем в храилище значения, и при создании нового документа или справочника подставляем их.
Но дьявол, как известно, кроется в деталях.
Для начала разберемся с формой записи нашего регистра.
Прежде всего, поясню, почему вид настройки и настройка были выбраны в виде строки. Это сделано с целью обращения к метаданным через квадратные скобки - т.е. из конструкции Метаданные[ВидНастройки][Настройка] мы получим например
Метаданные.Справочники.Номенклатура или Метаданные.Документа.РеализацияТоваровУслуг.
Чтобы все работало корректно, нам понадобится немного докрутить поведение элементов управления.
ВидНастройки мы представим в виде переключателя, и укажем список выбора с двумя значениями "Документы" и "Справочники"
Поле Настройка заполним программно:
&НаСервере
Процедура ЗаполнитьПоМетаданнымНаСервере(ВидНастройки)
Элементы.Настройка.СписокВыбора.Очистить();
ТЗМетаданных.Очистить();
ПредставлениеНастройки = "";
ТаблицаШаблонаЗаполнения.Очистить();
Для Каждого ВидМетаданных Из Метаданные[ВидНастройки] Цикл
Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
СтрТЗ = ТЗМетаданных.Добавить();
СтрТЗ.Имя = ВидМетаданных.Имя;
СтрТЗ.Синоним = ВидМетаданных.Синоним;
КонецЦикла;
КонецПроцедуры
ТЗМетаданных - это таблица значений, которую мы используем для сопоставления имени и синонима метаданных, чтобы пользователь выбирал привычные "Договоры контрагентов", а в настройку записывался идентификатор ДоговорыКонтрагентов.
На форму мы вынесем реквизит ПредставлениеНастройки, и при его изменении будем менять настройку.
&НаКлиенте
Процедура НастройкаПриИзменении(Элемент)
ОтборТЗ = Новый Структура("Синоним", ПредставлениеНастройки);
НайденныеСтроки = ТЗМетаданных.НайтиСтроки(ОтборТЗ);
Если НайденныеСтроки.Количество() = 1 Тогда
Запись.Настройка = ТЗМетаданных.НайтиСтроки(ОтборТЗ)[0].Имя;
НастройкаПриИзмененииНаСервере();
КонецЕсли;
КонецПроцедуры
При выборе настройки мы заполняем таблицу шаблона. В нашем примере мы заполняем только ссылочные реквизиты и реквизиты-перечисления. По большому счету, можно сделать список с пометками, и дать пользователю самостоятельно выбирать нужные реквизиты, но это в данном материале не рассматривается.
&НаСервере
Процедура НастройкаПриИзмененииНаСервере()
ОбъектМетаданных = Метаданные[Запись.ВидНастройки][Запись.Настройка];
ТаблицаШаблонаЗаполнения.Очистить();
Для Каждого МетаРеквизит Из ОбъектМетаданных.Реквизиты цикл
ЭтоНужныйТип = Ложь;
Для Каждого МетаТип Из МетаРеквизит.Тип.типы() Цикл
ЭтоСправочник = Справочники.ТипВсеСсылки().СодержитТип(МетаТип);
ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(МетаТип);
ЭтоПеречисление = Перечисления.ТипВсеСсылки().СодержитТип(МетаТип);
Если ЭтоСправочник ИЛИ ЭтоДокумент ИЛИ ЭтоПеречисление Тогда
СтрТЗ = ТаблицаШаблонаЗаполнения.Добавить();
СтрТЗ.Поле = МетаРеквизит.Имя;
СтрТЗ.ПредставлениеПоля = МетаРеквизит.Синоним;
СтрТЗ.Значение = Новый (МетаТип);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
И при записи мы помещаем заполненный шаблон в хранилище:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
ТекущийОбъект.Значение = Новый ХранилищеЗначения(ТаблицаШаблонаЗаполнения.Выгрузить());
КонецПроцедуры
Полный листинг всего модуля формы я приведу в конце материала.
С формой разобрались, осталось совсем чуть-чуть.
У нас есть две подписки на события. В первой тип источника указываем "ДокументСсылка", во второй "СправочикСсылка".
В общем модуле пишем обработчик:
Процедура РС_ЗаполнениеСправочниковИзНастроекПользователя(Источник, ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) Экспорт
Если ДанныеЗаполнения = Неопределено Тогда
ДанныеЗаполнения = Новый Структура;
КонецЕсли;
Запрос = Новый Запрос("ВЫБРАТЬ
| РС_НастройкиПользователей.Пользователь,
| РС_НастройкиПользователей.Настройка,
| РС_НастройкиПользователей.Значение,
| РС_НастройкиПользователей.ВидНастройки
|ИЗ
| РегистрСведений.РС_НастройкиПользователей КАК РС_НастройкиПользователей
|ГДЕ
| РС_НастройкиПользователей.Пользователь = &Пользователь
| И РС_НастройкиПользователей.Настройка = &Настройка
| И РС_НастройкиПользователей.ВидНастройки = &ВидНастройки");
Запрос.УстановитьПараметр("Пользователь", ПользователиКлиентСервер.АвторизованныйПользователь());
Запрос.УстановитьПараметр("Настройка", Источник.Метаданные().Имя);
Запрос.УстановитьПараметр("ВидНастройки", "Справочники");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Хранилище = Выборка.Значение;
ТаблицаШаблонаЗаполнения = Хранилище.Получить();
Для Каждого СтрокаШаблона Из ТаблицаШаблонаЗаполнения Цикл
Если ЗначениеЗаполнено(СтрокаШаблона.Значение) Тогда
ДанныеЗаполнения.Вставить(СтрокаШаблона.Поле, СтрокаШаблона.Значение);
Если Метаданные.Справочники[Источник.Метаданные().Имя].Реквизиты[СтрокаШаблона.Поле].ЗаполнятьИзДанныхЗаполнения Тогда
ДанныеЗаполнения.Вставить(СтрокаШаблона.Поле, СтрокаШаблона.Значение);
Иначе
Источник[СтрокаШаблона.Поле] = СтрокаШаблона.Значение;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Вот здесь-то нам и пригодятся наши строковые реквизиты "Настройка" и "ВидНастройки".
На этом все.
P.S.:
Как и обещал, листинг модуля формы записи регистра сведений.
&НаКлиенте
Процедура НастройкаПриИзменении(Элемент)
ОтборТЗ = Новый Структура("Синоним", ПредставлениеНастройки);
НайденныеСтроки = ТЗМетаданных.НайтиСтроки(ОтборТЗ);
Если НайденныеСтроки.Количество() = 1 Тогда
Запись.Настройка = ТЗМетаданных.НайтиСтроки(ОтборТЗ)[0].Имя;
НастройкаПриИзмененииНаСервере();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура НастройкаПриИзмененииНаСервере()
ОбъектМетаданных = Метаданные[Запись.ВидНастройки][Запись.Настройка];
ТаблицаШаблонаЗаполнения.Очистить();
Для Каждого МетаРеквизит Из ОбъектМетаданных.Реквизиты цикл
ЭтоНужныйТип = Ложь;
Для Каждого МетаТип Из МетаРеквизит.Тип.типы() Цикл
ЭтоСправочник = Справочники.ТипВсеСсылки().СодержитТип(МетаТип);
ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(МетаТип);
ЭтоПеречисление = Перечисления.ТипВсеСсылки().СодержитТип(МетаТип);
Если ЭтоСправочник ИЛИ ЭтоДокумент ИЛИ ЭтоПеречисление Тогда
СтрТЗ = ТаблицаШаблонаЗаполнения.Добавить();
СтрТЗ.Поле = МетаРеквизит.Имя;
СтрТЗ.ПредставлениеПоля = МетаРеквизит.Синоним;
СтрТЗ.Значение = Новый (МетаТип);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если Не ЗначениеЗаполнено(Запись.ВидНастройки) Тогда
Запись.ВидНастройки = "Документы";
ЗаполнитьПоМетаданнымНаСервере(Запись.ВидНастройки);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьПоМетаданнымНаСервере(ВидНастройки)
Элементы.Настройка.СписокВыбора.Очистить();
ТЗМетаданных.Очистить();
ПредставлениеНастройки = "";
ТаблицаШаблонаЗаполнения.Очистить();
Для Каждого ВидМетаданных Из Метаданные[ВидНастройки] Цикл
Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
СтрТЗ = ТЗМетаданных.Добавить();
СтрТЗ.Имя = ВидМетаданных.Имя;
СтрТЗ.Синоним = ВидМетаданных.Синоним;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ВидНастройкиПриИзменении(Элемент)
ЗаполнитьПоМетаданнымНаСервере(Запись.ВидНастройки);
КонецПроцедуры
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
ТекущийОбъект.Значение = Новый ХранилищеЗначения(ТаблицаШаблонаЗаполнения.Выгрузить());
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//Вставить содержимое обработчика
Если Не ЗначениеЗаполнено(Параметры.Ключ.Пользователь) Тогда
Запись.Пользователь = ПользователиКлиентСервер.АвторизованныйПользователь();
КонецЕсли;
Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
Элементы.Пользователь.ТолькоПросмотр = Истина;
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
Запрос = Новый Запрос("ВЫБРАТЬ
| РС_НастройкиПользователей.Пользователь,
| РС_НастройкиПользователей.Настройка,
| РС_НастройкиПользователей.Значение,
| РС_НастройкиПользователей.ВидНастройки
|ИЗ
| РегистрСведений.РС_НастройкиПользователей КАК РС_НастройкиПользователей");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ХЗ = Выборка.Значение;
ТЗ = ХЗ.Получить();
КонецЦикла;
ХЗ = ТекущийОбъект.Значение;
ТЗ = ХЗ.Получить();
ТаблицаШаблонаЗаполнения.Загрузить(ТЗ);
Попытка
Для Каждого ВидМетаданных Из Метаданные[Запись.ВидНастройки] Цикл
Элементы.Настройка.СписокВыбора.Добавить(ВидМетаданных.Синоним);
СтрТЗ = ТЗМетаданных.Добавить();
СтрТЗ.Имя = ВидМетаданных.Имя;
СтрТЗ.Синоним = ВидМетаданных.Синоним;
КонецЦикла;
ПредставлениеНастройки = Метаданные[Запись.ВидНастройки][Запись.Настройка].Синоним;
Исключение
КонецПопытки;
КонецПроцедуры
Всем спасибо за потраченное время! Буду рад любой критике и комментариям.