При переходе с обычных форм (1С 8.2) на управляемые формы (1С 8.3) разработчики часто сталкиваются с фундаментальным ограничением: серверный код не может напрямую взаимодействовать с интерфейсом пользователя. Команда ОткрытьФорму() или Вопрос() просто не сработают в модуле объекта или в подписке на события. Рассмотрим подробнее, как решить эту задачу современными средствами платформы 1С:Предприятие 8.3, включая использование Системы взаимодействия и механизмов БСП.
В управляемом приложении клиент и сервер жестко разделены. Серверный вызов выполняется в отдельном сеансе, который «ничего не знает» о том, какое окно открыто у пользователя в данный момент. Особую сложность представляют подписки на события (например, ПередЗаписью), которые всегда выполняются на сервере и зачастую внутри транзакции базы данных. Попытка остановить выполнение серверного кода в ожидании ответа пользователя приведет к блокировке таблиц БД и катастрофическому падению производительности системы.
Проанализируем инновационный подход, который позволяет организовать асинхронную связь между сервером и клиентом. Система взаимодействия позволяет серверу «отправить сообщение» конкретному пользователю, которое клиентское приложение перехватит и обработает.
Шаг 1. Отправка сообщения с сервера. В серверном модуле (например, в подписке на событие) мы создаем сообщение. Чтобы не захламлять общий чат, можно использовать скрытые обсуждения или специальные контекстные сообщения.
// Пример на сервере
ТекстСообщения = "ТРЕБУЕТСЯ_КОММЕНТАРИЙ";
ПараметрыДанных = Новый Структура("СсылкаНаОбъект, АдресХранилища", Объект.Ссылка, АдресВХ);
Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение(Контекст);
НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
НовоеСообщение.Текст = ТекстСообщения;
НовоеСообщение.Данные = ПараметрыДанных; // Передаем структуру с данными
НовоеСообщение.Записать();
Шаг 2. Обработка на клиенте. В модуле управляемого приложения или в форме используется обработчик ПриПолученииСообщения. Разберем, как это выглядит:
// В модуле управляемого приложения
Процедура ПриПолученииСообщенияИзСистемыВзаимодействия(Сообщение)
Если Сообщение.Текст = "ТРЕБУЕТСЯ_КОММЕНТАРИЙ" Тогда
// Открываем форму ввода комментария
ПараметрыФормы = Новый Структура("ОбъектСсылка", Сообщение.Данные.СсылкаНаОбъект);
ОткрытьФорму("ОбщаяФорма.ВводКомментария", ПараметрыФормы);
КонецЕсли;
КонецПроцедуры
Важное замечание: Этот метод является асинхронным. Серверный код отправит сообщение и продолжит выполнение. Он не будет ждать, пока пользователь введет текст. Поэтому данный способ подходит для пост-обработки или уведомлений, но не для прерывания записи объекта.
Выясним наиболее правильный архитектурный путь для типовых конфигураций (БП 3.0, ERP, УТ 11). Вместо того чтобы «мучить» серверную подписку, мы переносим проверку на клиентскую сторону, в модуль формы документа.
Рассмотрим алгоритм реализации:
ПередЗаписью выполняем проверку. Если данных не хватает, устанавливаем Отказ = Истина и передаем сообщение пользователю.ПередЗаписьюНаСервере или используем расширение для клиентской процедуры ЗаписатьОбъект.ПоказатьВводЗначения() или специальную форму.ДополнительныеСвойства объекта и инициируем повторную запись.Пример передачи данных через дополнительные свойства:
// На клиенте перед повторным вызовом записи
ПараметрыЗаписи = Новый Структура;
ПараметрыЗаписи.Вставить("КомментарийПользователя", ВведенныйТекст);
ЭтотОбъект.Записать(ПараметрыЗаписи);
// На сервере в модуле объекта
Процедура ПередЗаписью(Отказ)
Если ДополнительныеСвойства.Свойство("КомментарийПользователя") Тогда
// Записываем полученный комментарий в регистр или поле объекта
МойРегистр.СоздатьМенеджерЗаписи().ЗаписатьКомментарий(ДополнительныеСвойства.КомментарийПользователя);
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию, когда Система взаимодействия недоступна (например, нет лицензий КОРП или не настроен сервер). В этом случае можно использовать классический опрос (polling).
Серверный код в подписке помещает «заявку» на ввод данных во Временное хранилище или в специально созданный Регистр Сведений. На клиенте в это время работает ПодключитьОбработчикОжидания(), который раз в несколько секунд проверяет наличие новых записей, адресованных текущему пользователю. Как только запись найдена — открывается форма.
Посмотрим на минусы этого подхода:
Никогда не пытайтесь реализовать модальный диалог внутри транзакции! Если вы используете подписку ПередЗаписью, помните: в этот момент база данных уже захватила блокировки на таблицы. Если программа будет ждать, пока пользователь «сходит попить кофе» перед тем как нажать «ОК» в окне комментария, все остальные пользователи, пытающиеся записать документы того же типа, будут получать ошибку Превышено время ожидания блокировки.
Рекомендация: Если бизнес-логика требует обязательного ввода данных перед завершением записи, единственный верный путь — прервать запись (Отказ = Истина), вывести окно на клиенте и заставить пользователя совершить действие осознанно, после чего инициировать новую транзакцию записи.
Разберем юридические и технические аспекты использования СВ, упомянутые в обсуждении:
Таким образом, для реализации задачи «обратной связи» лучше всего подходит сочетание проверки в модуле объекта и обработки отказа на стороне формы. Использование Системы взаимодействия оправдано в случаях, когда нужно инициировать сложные бизнес-процессы или уведомления, не блокирующие основную работу пользователя с документом.