Простой способ программно открыть заполненную форму нового (незаписанного) документа в тонком клиенте

Программирование - Универсальные функции

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

Итак, сначала нам понадобится добавить немного кода в общие модули.

В серверный общий модуль (в моем примере его имя будет СерверныйОбщийМодуль) добавляем функцию СтруктураПоОбъектуМетаданных() и процедуру ЗаполнитьОбъектИзСтруктурыВоВременномХранилище()

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

	Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
		Результат.Вставить(Реквизит.Имя);
	КонецЦикла;

	Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл
		Результат.Вставить(Реквизит.Имя);
	КонецЦикла;

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

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

Далее, там где мы хотим открыть форму незаписанного документа с уже заполненными данными пишем


&НаКлиенте
Процедура СоздатьЗаполнитьИОткрытьНовыйДокумент()

	АдресХранилища = СоздатьНовыйДокументНаСервере();
	
	ПараметрыОткрытия = Новый Структура("Основание", АдресХранилища);
	ОткрытьФорму("Документ.РасходныйОрдер.ФормаОбъекта", ПараметрыОткрытия, ЭтаФорма, УникальныйИдентификатор);

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

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

Теперь нам нужно чтобы в обработке заполнения открываемого документа вызвалась процедура ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(). Проще всего сделать, это создав подписку на событие ОбработкаЗаполнения. В эту подписку включаем все нужные нам документы (те документы, которые мы хотим открывать и заполнять). В качестве обработчика подписки на событие указываем процедуру ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(). Либо можно непосредственно в процедуре ОбработкаЗаполнения() вызвать СерверныйОбщийМодуль.ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(). 

Вот собственно и все, процедура и функция в общем модуле универсальные и подойдут для любого типа документа/справочника. Добавим их один раз, можно будет открывать подобным образом любой документ/справочник (не забывая включить его в подписку на событие).

14

См. также

Комментарии
Сортировка: Древо
1. dandykry 4 09.06.18 08:45 Сейчас в теме
Форма = ОткрытьФорму("Справочники.Банки.ФормаОбъекта", Новый Структура("КакиеУгодноПараметры") );

ДанныеФормы = Форма.Объект;

ЗаполнитьНаОснованииКакДушеУгодно(ДанныеФормы);

КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);

И откроется форма незаписанного заполненного документа
GROOVY; BigB; ltfriend; +3 Ответить
4. tormozit 4762 09.06.18 09:13 Сейчас в теме
(1) , (2)
Такие способы имеют недостатки. Например сама форма объекта не сможет скорректировать данные нового объекта при необходимости, т.к. не узнает, что они изменились. И даже если мы ей поможем узнать, то ей для этого придется делать лишний серверный вызов. Оба подхода пригодны, но в своих ситуациях.
Aleskey_K; +1 Ответить
6. beefit 13.06.18 10:57 Сейчас в теме
(0), (4) Можно пример, где применение этого метода лучше стандартного открытия формы с параметрами? Я что-то не вникну сходу
8. Serge R 50 13.06.18 16:21 Сейчас в теме
(6) Можно конечно передать в форму параметры и в ПриСозданииНаСервере() заполнить из параметров. Но это придется писать в каждой такой форме, по моему методу достаточно один раз прописать процедуры и далее добавлять нужные объекты в подписку на событие.
11. beefit 14.06.18 11:32 Сейчас в теме
(8), (10)
Делать заполнение в ПриСозданииНаСервере() довольно странный вариант.
Для этого есть ОбработкаЗаполнения()
То что вы передадите вторым параметром в ОткрытьФорму() будет доступно вам в ОбработкаЗаполнения()
И все нужные вам процедуры из (10) отработают корректно
10. Serge R 50 13.06.18 16:29 Сейчас в теме
(1) Простой пример: если в открываемой форме устанавливается видимость или доступность элементов формы в зависимости от значений реквизитов объекта, то если сначала открыть форму, а потом заполнять, придется дополнительно вызывать эти процедуры. При моем способе открывается уже заполненный объект и все эти процедуры отработают автоматически.
12. dandykry 4 14.06.18 15:19 Сейчас в теме
(10)

Форма = ОткрытьФорму("Справочники.Банки.ФормаОбъекта", Новый Структура("КакиеУгодноПараметры") ); 

ДанныеФормы = Форма.Объект; 

ЗаполнитьНаОснованииКакДушеУгодно(ДанныеФормы); 

КопироватьДанныеФормы(ДанныеФормы, Форма.Объект); 

Форма.Элементы.Организация.Видимость = Ложь; //не очень способ но если уж выкручиваться не дописывая конфигурацию
Показать

Или

Форма.УстановитьВидимостьЭлементов() //Где УстановитьВидимостьЭлементов экспортная процедура формы,


Уж если в так пошло то и нужно именно в ПриСозданииНаСервере все заполнять, то:

Расширение управляемой формы для документа (Managed form extension for documents)
ЗначенияЗаполнения (FillingValues)
Описание:

Тип: Структура.
Параметры заполнения нового объекта.
Ключ структуры - имя реквизита формы, значение - заполняемое значение.


ЗначенияЗаполнения = Новый Структура("Организация, Контрагент", МояОрганизация, МойКонтрагент); 
Форма = ОткрытьФорму("Справочники.Банки.ФормаОбъекта", ЗначенияЗаполнения ); 

итд

А если сильно сильно подумать, то можно взять за основу идею Переопределяемых общих модулей. Добавить в нем ПриСозданииНаСервере. В нужных формах вызвать в событии ПриСозданииНаСервере. Далее в зависимости от открываемой формы и параметров выполнять определенные действия.
2. AlX0id 09.06.18 09:08 Сейчас в теме
Для использования этого способа потребуется немного модифицировать конфигурацию.

А нафига этот троллейбус из буханки?
Гугл давно решил эту проблему за вас: https://helpf.pro/faq/view/1396.html
3. tormozit 4762 09.06.18 09:10 Сейчас в теме
Зачем городить какую то структуру, когда можно просто сериализовать сам объект данных в строку и поместить ее во временное хранилище и затем сразу получить из строки XML натуральный объект и преобразовать его в данные формы?
mvxyz; Трактор; +2 Ответить
5. Трактор 1157 13.06.18 09:14 Сейчас в теме
Не обрабатываются стандартные и общие реквизиты.
9. Serge R 50 13.06.18 16:23 Сейчас в теме
(5) Справедливое замечание, добавил их.
7. davlen 59 13.06.18 13:38 Сейчас в теме
Сам что то подобное делал недавно, но у меня в отличии от автора, заполняются даже элементы формы, которые не являются реквизитами объекта.
Оставьте свое сообщение