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