В процессе разработки в среде 1С:Предприятие 8.3 часто возникает задача: подготовить данные документа программно, а затем показать их пользователю в форме, чтобы он мог проверить результат и самостоятельно принять решение о записи. Типичная ошибка новичка — попытка получить объект, изменить его на сервере и просто передать на клиент. Рассмотрим, почему этот путь ведет к ошибке, и разберем правильные методы решения задачи.
Разберем ситуацию, представленную в одном из сообщений форума. Разработчик пытается создать функцию на сервере, которая возвращает ДокументОбъект, и вызвать её на клиенте для открытия формы. Это приводит к критической ошибке: "Ошибка преобразования данных XDTO: НачалоСвойства: ret... Тип: {http://www.w3.org/2001/XMLSchema}anyType".
Выясним причину этой ошибки. В управляемом приложении 1С существует строгое разделение контекстов. Типы данных, такие как ДокументОбъект, СправочникОбъект и другие «тяжелые» прикладные объекты, существуют только на сервере. Их невозможно передать на клиент напрямую, так как клиент «не знает», как с ними работать. На клиенте мы оперируем ссылками (ДокументСсылка) или специальными структурами — ДанныеФормыСтруктура. Поэтому любая попытка вернуть Объект из функции, выполняющейся &НаСервере, в процедуру &НаКлиенте, закончится ошибкой сериализации.
Проанализируем наиболее изящный способ создания нового документа с уже заполненными реквизитами. Платформа 1С предоставляет штатный механизм параметров формы. Если нам нужно открыть форму нового документа и подставить в нее, например, контрагента и склад, мы должны использовать структуру ЗначенияЗаполнения.
Рассмотрим пример кода:
&НаКлиенте
Процедура ОткрытьНовыйСчет(Команда)
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Контрагент", Объект.КонтрагентКлиента);
ПараметрыЗаполнения.Вставить("Склад", Объект.ОсновнойСклад);
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.СчетНаОплатуПокупателю.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
При таком подходе платформа сама создаст новый объект на сервере, вызовет стандартную процедуру ОбработкаЗаполнения в модуле документа (куда и придет наша структура) и откроет пользователю уже готовую, заполненную форму. Документ при этом в базу еще не записан.
Если задача сложнее (например, нужно заполнить не только простые реквизиты, но и табличные части), или мы работаем с существующим документом, который нужно изменить «на лету» перед показом, нам потребуется метод КопироватьДанныеФормы. Этот метод позволяет перенести данные из прикладного объекта в структуру данных формы.
Разберем алгоритм действий по шагам:
Объект.Посмотрим на пример реализации этой логики:
&НаКлиенте
Процедура ИзменитьИОткрытьФорму(СсылкаНаДокумент)
// Получаем форму (она еще не открыта)
ПараметрыКлюча = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДокумента = ПолучитьФорму("Документ.СчетНаОплатуПокупателю.ФормаОбъекта", ПараметрыКлюча);
// Модифицируем объект через серверную процедуру
МодифицироватьОбъектНаСервере(ФормаДокумента);
// Теперь открываем подготовленную форму
ФормаДокумента.Открыть();
КонецПроцедуры
&НаСервере
Процедура МодифицироватьОбъектНаСервере(ФормаДокумента)
// Извлекаем Объект из данных формы в прикладной объект (ДокументОбъект)
ДокОбъект = ДанныеФормыВЗначение(ФормаДокумента.Объект, Тип("ДокументОбъект.СчетНаОплатуПокупателю"));
// Вносим изменения
ДокОбъект.Комментарий = "Изменено программно перед открытием " + ТекущаяДата();
// Добавим строку в табличную часть для примера
НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Услуга настройки");
НоваяСтрока.Количество = 1;
// Копируем данные обратно в форму
КопироватьДанныеФормы(ДокОбъект, ФормаДокумента.Объект);
КонецПроцедуры
Важный момент: использование ДанныеФормыВЗначение и КопироватьДанныеФормы позволяет работать с объектом на сервере привычными методами, сохраняя при этом интерактивность — пользователь увидит все изменения, но кнопка «Записать» в базе еще не будет нажата.
Бывают ситуации, когда данных для заполнения слишком много (например, результат сложного запроса), и передавать их через параметры структуры неудобно. В этом случае проанализируем механизм Временного хранилища.
Схема работы будет следующей:
ПоместитьВоВременноеХранилище и получаем уникальный адрес (строку).ОткрытьФорму.ПриСозданииНаСервере извлекаем данные по этому адресу и заполняем реквизиты.Посмотрим, как реализовать извлечение данных в модуле формы открываемого документа:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("АдресДанныхЗаполнения") Тогда
ДанныеИзХранилища = ПолучитьИзВременногоХранилища(Параметры.АдресДанныхЗаполнения);
Если ТипЗнч(ДанныеИзХранилища) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(Объект, ДанныеИзХранилища);
КонецЕсли;
// Не забываем удалить данные из хранилища, если они больше не нужны
УдалитьИзВременногоХранилища(Параметры.АдресДанныхЗаполнения);
КонецЕсли;
КонецПроцедуры
Подведем итоги нашего исследования. Для успешного открытия форм с измененными данными необходимо придерживаться следующих правил:
Объект с сервера на клиент — это архитектурное ограничение платформы 8.2/8.3.ОткрытьФорму с ключом ЗначенияЗаполнения.ПолучитьФорму -> КопироватьДанныеФормы.Оповестить() и обработчик ОбработкаОповещения внутри самой формы для обновления данных без переоткрытия окна.Рассмотренные методики позволяют создавать гибкие и отзывчивые интерфейсы, где система берет на себя рутинную работу по заполнению документов, оставляя пользователю контроль над финальным результатом.