Как вызвать форму или получить ответ пользователя из серверного кода 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При переходе с обычных форм (1С 8.2) на управляемые формы (1С 8.3) разработчики часто сталкиваются с фундаментальным ограничением: серверный код не может напрямую взаимодействовать с интерфейсом пользователя. Команда ОткрытьФорму() или Вопрос() просто не сработают в модуле объекта или в подписке на события. Рассмотрим подробнее, как решить эту задачу современными средствами платформы 1С:Предприятие 8.3, включая использование Системы взаимодействия и механизмов БСП.

Причина проблемы: Разделение контекстов

В управляемом приложении клиент и сервер жестко разделены. Серверный вызов выполняется в отдельном сеансе, который «ничего не знает» о том, какое окно открыто у пользователя в данный момент. Особую сложность представляют подписки на события (например, ПередЗаписью), которые всегда выполняются на сервере и зачастую внутри транзакции базы данных. Попытка остановить выполнение серверного кода в ожидании ответа пользователя приведет к блокировке таблиц БД и катастрофическому падению производительности системы.

Решение 1. Использование Системы взаимодействия (СВ)

Проанализируем инновационный подход, который позволяет организовать асинхронную связь между сервером и клиентом. Система взаимодействия позволяет серверу «отправить сообщение» конкретному пользователю, которое клиентское приложение перехватит и обработает.

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


// Пример на сервере
ТекстСообщения = "ТРЕБУЕТСЯ_КОММЕНТАРИЙ";
ПараметрыДанных = Новый Структура("СсылкаНаОбъект, АдресХранилища", Объект.Ссылка, АдресВХ);

Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение(Контекст);
НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
НовоеСообщение.Текст = ТекстСообщения;
НовоеСообщение.Данные = ПараметрыДанных; // Передаем структуру с данными
НовоеСообщение.Записать();

Шаг 2. Обработка на клиенте. В модуле управляемого приложения или в форме используется обработчик ПриПолученииСообщения. Разберем, как это выглядит:


// В модуле управляемого приложения
Процедура ПриПолученииСообщенияИзСистемыВзаимодействия(Сообщение)
    Если Сообщение.Текст = "ТРЕБУЕТСЯ_КОММЕНТАРИЙ" Тогда
        // Открываем форму ввода комментария
        ПараметрыФормы = Новый Структура("ОбъектСсылка", Сообщение.Данные.СсылкаНаОбъект);
        ОткрытьФорму("ОбщаяФорма.ВводКомментария", ПараметрыФормы);
    КонецЕсли;
КонецПроцедуры

Важное замечание: Этот метод является асинхронным. Серверный код отправит сообщение и продолжит выполнение. Он не будет ждать, пока пользователь введет текст. Поэтому данный способ подходит для пост-обработки или уведомлений, но не для прерывания записи объекта.

Решение 2. Стандартный механизм БСП «Дополнительные проверки»

Выясним наиболее правильный архитектурный путь для типовых конфигураций (БП 3.0, ERP, УТ 11). Вместо того чтобы «мучить» серверную подписку, мы переносим проверку на клиентскую сторону, в модуль формы документа.

Рассмотрим алгоритм реализации:

  1. В модуле объекта в процедуре ПередЗаписью выполняем проверку. Если данных не хватает, устанавливаем Отказ = Истина и передаем сообщение пользователю.
  2. В форме документа переопределяем событие ПередЗаписьюНаСервере или используем расширение для клиентской процедуры ЗаписатьОбъект.
  3. Если сервер вернул отказ из-за отсутствия комментария, клиентский код открывает диалоговое окно ПоказатьВводЗначения() или специальную форму.
  4. После ввода данных пользователем, мы помещаем их в ДополнительныеСвойства объекта и инициируем повторную запись.

Пример передачи данных через дополнительные свойства:


// На клиенте перед повторным вызовом записи
ПараметрыЗаписи = Новый Структура;
ПараметрыЗаписи.Вставить("КомментарийПользователя", ВведенныйТекст);
ЭтотОбъект.Записать(ПараметрыЗаписи);

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

Решение 3. Временное хранилище и обработчик ожидания

Проанализируем ситуацию, когда Система взаимодействия недоступна (например, нет лицензий КОРП или не настроен сервер). В этом случае можно использовать классический опрос (polling).

Серверный код в подписке помещает «заявку» на ввод данных во Временное хранилище или в специально созданный Регистр Сведений. На клиенте в это время работает ПодключитьОбработчикОжидания(), который раз в несколько секунд проверяет наличие новых записей, адресованных текущему пользователю. Как только запись найдена — открывается форма.

Посмотрим на минусы этого подхода:

Критически важный момент: Транзакции и блокировки

Никогда не пытайтесь реализовать модальный диалог внутри транзакции! Если вы используете подписку ПередЗаписью, помните: в этот момент база данных уже захватила блокировки на таблицы. Если программа будет ждать, пока пользователь «сходит попить кофе» перед тем как нажать «ОК» в окне комментария, все остальные пользователи, пытающиеся записать документы того же типа, будут получать ошибку Превышено время ожидания блокировки.

Рекомендация: Если бизнес-логика требует обязательного ввода данных перед завершением записи, единственный верный путь — прервать запись (Отказ = Истина), вывести окно на клиенте и заставить пользователя совершить действие осознанно, после чего инициировать новую транзакцию записи.

Лицензионные условия Системы взаимодействия

Разберем юридические и технические аспекты использования СВ, упомянутые в обсуждении:

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

← На главную