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

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

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

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

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

Результат = Новый Структура;

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

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

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

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

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

Возврат Результат;

КонецФункции

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

Если ТипЗнч(ДанныеЗаполнения) = Тип("Строка") И ЭтоАдресВременногоХранилища(ДанныеЗаполнения) Тогда
СтруктураОбъекта = ПолучитьИзВременногоХранилища(ДанныеЗаполнения);

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

Попытка
//заполним реквизиты объекта
ЗаполнитьЗначенияСвойств(Источник, СтруктураОбъекта, , СтрСоединить(ПропускаемыеКлючи, ","));

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

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

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


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

АдресХранилища = СоздатьНовыйДокументНаСервере();

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

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

&НаСервере
Функция СоздатьНовыйДокументНаСервере()

//получаем структуру, повторяющую все реквизиты и табличные части документа
ДокСтруктура = СерверныйОбщийМодуль.СтруктураПоОбъектуМетаданных("Документ.Поступление");

//заполняем структуру нужными данными
ДокСтруктура.Контрагент = Объект.Контрагент;
Для Каждого ТекСтрока Из Объект.Товары Цикл
НоваяСтрока = ДокСтруктура.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрока);
КонецЦикла;

//помещаем заполненную структуру в хранилище и возвращаем адрес хранилища
Возврат ПоместитьВоВременноеХранилище(ДокСтруктура, УникальныйИдентификатор);

КонецФункции

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

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

12 Comments

  1. dandykry

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

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

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

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

    И откроется форма незаписанного заполненного документа

    Reply
  2. AlX0id
    Для использования этого способа потребуется немного модифицировать конфигурацию.

    А нафига этот троллейбус из буханки?

    Гугл давно решил эту проблему за вас: https://helpf.pro/faq/view/1396.html

    Reply
  3. tormozit

    Зачем городить какую то структуру, когда можно просто сериализовать сам объект данных в строку и поместить ее во временное хранилище и затем сразу получить из строки XML натуральный объект и преобразовать его в данные формы?

    Reply
  4. tormozit

    (1) , (2)

    Такие способы имеют недостатки. Например сама форма объекта не сможет скорректировать данные нового объекта при необходимости, т.к. не узнает, что они изменились. И даже если мы ей поможем узнать, то ей для этого придется делать лишний серверный вызов. Оба подхода пригодны, но в своих ситуациях.

    Reply
  5. Трактор

    Не обрабатываются стандартные и общие реквизиты.

    Reply
  6. beefit

    (0), (4) Можно пример, где применение этого метода лучше стандартного открытия формы с параметрами? Я что-то не вникну сходу

    Reply
  7. davlen

    Сам что то подобное делал недавно, но у меня в отличии от автора, заполняются даже элементы формы, которые не являются реквизитами объекта.

    Reply
  8. Serge R

    (6) Можно конечно передать в форму параметры и в ПриСозданииНаСервере() заполнить из параметров. Но это придется писать в каждой такой форме, по моему методу достаточно один раз прописать процедуры и далее добавлять нужные объекты в подписку на событие.

    Reply
  9. Serge R

    (5) Справедливое замечание, добавил их.

    Reply
  10. Serge R

    (1) Простой пример: если в открываемой форме устанавливается видимость или доступность элементов формы в зависимости от значений реквизитов объекта, то если сначала открыть форму, а потом заполнять, придется дополнительно вызывать эти процедуры. При моем способе открывается уже заполненный объект и все эти процедуры отработают автоматически.

    Reply
  11. beefit

    (8), (10)

    Делать заполнение в ПриСозданииНаСервере() довольно странный вариант.

    Для этого есть ОбработкаЗаполнения()

    То что вы передадите вторым параметром в ОткрытьФорму() будет доступно вам в ОбработкаЗаполнения()

    И все нужные вам процедуры из (10) отработают корректно

    Reply
  12. dandykry

    (10)

    Форма = ОткрытьФорму(«Справочники.Банки.ФормаОбъекта», Новый Структура(«КакиеУгодноПараметры») );
    
    ДанныеФормы = Форма.Объект;
    
    ЗаполнитьНаОснованииКакДушеУгодно(ДанныеФормы);
    
    КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
    
    Форма.Элементы.Организация.Видимость = Ложь; //не очень способ но если уж выкручиваться не дописывая конфигурацию
    

    Показать

    Или

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

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

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

    ЗначенияЗаполнения (FillingValues)

    Описание:

    Тип: Структура.

    Параметры заполнения нового объекта.

    Ключ структуры — имя реквизита формы, значение — заполняемое значение.

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

    итд

    А если сильно сильно подумать, то можно взять за основу идею Переопределяемых общих модулей. Добавить в нем ПриСозданииНаСервере. В нужных формах вызвать в событии ПриСозданииНаСервере. Далее в зависимости от открываемой формы и параметров выполнять определенные действия.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *