Как организовать оповещение пользователя из серверного кода и исправить ошибку обращения к общему модулю

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

При разработке в среде 1С:Предприятие 8 начинающие разработчики часто сталкиваются с ситуацией, когда необходимо уведомить пользователя о событии, произошедшем на сервере (например, появление нового заказа или изменение статуса документа). Попытка вызвать клиентскую процедуру из серверного модуля напрямую приводит к ошибке "Переменная не определена" или "Процедура или функция с указанным именем не определена". Разберем подробно, почему так происходит, и как правильно реализовать интерактивные оповещения.

Почему сервер «не видит» клиентский модуль

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

Рассмотрим ситуацию, возникшую в теме: автор создал два модуля — МодулЭльКлиент и МодулЭльСервер. Ошибка возникала по двум причинам:

  1. Попытка вызвать процедуру из МодулЭльКлиент внутри кода МодулЭльСервер.
  2. Отсутствие необходимых флагов в свойствах общего модуля.

Шаг 1: Правильная настройка общих модулей

Выясним причину, по которой модуль может быть «не виден» в коде. Проверим свойства ваших модулей в конфигураторе:

Для серверного модуля (МодулЭльСервер):

Для клиентского модуля (МодулЭльКлиент):

Шаг 2: Использование обработчика ожидания

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

Разберем важные требования к этому методу, согласно синтакс-помощнику:

  1. Имя процедуры передается в виде строки.
  2. Процедура должна быть экспортируемой (слово Экспорт).
  3. Процедура должна находиться либо в модуле управляемого приложения, либо в глобальном общем модуле, либо в модуле формы.

Посмотрим на пример правильной инициализации в модуле управляемого приложения или в форме:


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

Шаг 3: Реализация моста между клиентом и сервером

Теперь создадим алгоритм, который будет работать правильно. Вместо того чтобы пытаться вызвать клиентское оповещение с сервера, мы сделаем наоборот: клиентская процедура будет вызывать серверную функцию, получать результат и показывать его пользователю.

Проанализируем код в серверном модуле МодулЭльСервер:


// Функция возвращает массив ссылок на новые заказы
Функция ПолучитьСписокОткрытыхЗаказов() Экспорт
    МассивЗаказов = Новый Массив;
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЗаказКлиента.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.ЗаказКлиента КАК ЗаказКлиента
        |ГДЕ
        |   ЗаказКлиента.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Открыт)";
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        МассивЗаказов.Добавить(Выборка.Ссылка);
    КонецЦикла;
    
    Возврат МассивЗаказов;
КонецФункции

Теперь реализуем клиентскую часть в модуле МодулЭльКлиент или модуле управляемого приложения:


Процедура ПроверитьНовыеЗаказыДляМенеджера() Экспорт
    // Вызываем серверную функцию для получения данных
    СписокЗаказов = МодулЭльСервер.ПолучитьСписокОткрытыхЗаказов();
    
    Для Каждого ТекущийЗаказ Из СписокЗаказов Цикл
        // Формируем текст и навигационную ссылку для интерактивности
        ТекстОповещения = "Поступил новый открытый заказ!";
        НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(ТекущийЗаказ);
        
        // Показываем всплывающее окно
        ПоказатьОповещениеПользователя(
            "Внимание!", 
            НавигационнаяСсылка, 
            "Заказ №" + ТекущийЗаказ.Номер, 
            БиблиотекаКартинок.Важное);
    КонецЦикла;
КонецПроцедуры

Шаг 4: Создание кликабельных ссылок

В тексте обсуждения автор спрашивал, можно ли сделать так, чтобы пользователь кликнул на сообщение и открылся документ. Использование метода ПоказатьОповещениеПользователя — это идеальное решение.

Разберем подробнее его параметры:

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

Оптимизация производительности

Выясним, как сделать систему оповещений более легкой. Если у вас в базе работает много пользователей, и каждый из них каждые 2 минуты будет запускать тяжелый запрос к таблице заказов, это может создать избыточную нагрузку на сервер БД.

Рекомендуем рассмотреть следующие улучшения:

  1. Регламентное задание: Пусть один раз в минуту фоновое задание на сервере проверяет заказы и записывает информацию о нуждающихся в уведомлении пользователях в специальный Регистр Сведений (например, ОчередьУведомлений).
  2. Легкий запрос: Клиентский обработчик ожидания будет опрашивать не таблицу заказов, а этот регистр, фильтруя записи только по текущему пользователю. После вывода оповещения запись из регистра удаляется.
  3. Система взаимодействия: Если ваша версия платформы и лицензии позволяют, используйте встроенную СистемуВзаимодействия. Она позволяет серверу отправлять Push-уведомления клиенту мгновенно через механизм СообщенияСистемыВзаимодействия, что полностью избавляет от необходимости использовать таймеры и лишние запросы.

Таким образом, мы выяснили, что основная ошибка заключалась в попытке смешивания контекстов. Следуя правилу "Клиент запрашивает — Сервер отвечает", вы сможете построить надежную и функциональную систему оповещений в любой конфигурации 1С.

← На главную