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