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