Как реализовать оповещение пользователя о создании документа в 1С:Управление торговлей 10.3?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Архитектурный подход к реализации задачи

Для создания надежной системы уведомлений нам необходимо решить три ключевые подзадачи:

  1. Перехват момента создания документа: Нам нужно гарантированно отловить появление нового документа в транзакции базы данных.
  2. Буферизация (хранение) событий: Оповещения должны храниться в базе данных до тех пор, пока адресат их не прочитает. Это исключит потерю уведомлений, если пользователь был оффлайн.
  3. Доставка и отображение на клиенте: Нам нужно регулярно опрашивать буфер из сеанса целевого пользователя и показывать ему всплывающее окно.

Рассмотрим пошагово реализацию каждого этапа.

Шаг 1. Перехват события создания документа через Подписки на события

На форумах часто предлагают использовать событие ПриПрисвоенииНомера. Мы настоятельно не рекомендуем этот метод. Во-первых, при записи нового документа номер может присваиваться автоматически в самом конце транзакции, либо пользователь может отменить запись после присвоения номера. Во-вторых, этот метод не гарантирует, что документ действительно физически записан в базу данных.

Наиболее надежный способ — использовать подписку на событие ПриЗаписи (OnWrite). Разберем по шагам процесс создания подписки:

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

Проанализируем программный код обработчика подписки:


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

Использование метода ЭтоНовый() внутри транзакции записи гарантирует, что мы реагируем исключительно на факт первичного создания документа, полностью игнорируя последующие перепроведения или редактирования старых документов.

Шаг 2. Проектирование буфера в Регистре Сведений

Для временного хранения неотправленных уведомлений мы создадим непериодический независимый регистр сведений ОчередьОповещенийПользователей. Использование регистра сведений решает проблему потери сообщений: если нужного пользователя нет на рабочем месте, запись будет дожидаться его входа в систему.

Разберем оптимальную структуру регистра сведений:

Теперь напишем вспомогательную процедуру записи события в созданный регистр:


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

Шаг 3. Реализация опроса на клиенте через Обработку Ожидания

Поскольку в обычных формах отсутствует полноценный механизм push-уведомлений в реальном времени (без использования тяжеловесных внешних компонент), мы применим классический паттерн "pull" — периодический опрос базы данных клиентом.

Для этого в модуле обычного приложения (или в глобальном модуле) настроим подключение обработчика ожидания. Оптимальный интервал опроса составляет 10–30 секунд. Более частый опрос может создать избыточную нагрузку на СУБД при большом числе работающих пользователей.

Добавим в процедуру ПриНачалеРаботыСистемы следующий код:


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

Теперь реализуем глобальную процедуру опроса регистра:


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

Процедура удаления отработавших записей выглядит следующим образом:


Процедура УдалитьСобытиеИзОчереди(Пользователь, Документ)
    
    МенеджерЗаписи = РегистрыСведений.ОчередьОповещенийПользователей.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Пользователь = Пользователь;
    МенеджерЗаписи.Документ     = Документ;
    МенеджерЗаписи.Удалить();
    
КонецПроцедуры

Шаг 4. Отображение уведомления на обычных формах

В управляемом приложении доступен удобный метод ПоказатьОповещениеПользователя, выводящий аккуратное окно в правом нижнем углу экрана. В обычном приложении 1С:Предприятие 8.3/8.2 этот метод может работать некорректно или полностью отсутствовать в зависимости от режима запуска сеанса. В качестве готового варианта информирования можно использовать гаджет оповещения о задачах пользователя в УТ 10.3.

Для имитации красивого всплывающего уведомления в правом нижнем углу экрана мы можем создать специальную небольшую вспомогательную форму. Разберем алгоритм ее создания:

  1. Создайте новую обработку ВсплывающееОповещение и добавьте в нее форму (Обычную).
  2. В свойствах формы отключите отображение рамки, заголовка, системных кнопок и кнопки закрытия. Установите режим открытия — Немодальный.
  3. Разместите на форме надпись с текстом сообщения (сделав его в виде гиперссылки) и кнопку "Ознакомлен" (или "Закрыть").
  4. При открытии формы программно рассчитайте координаты ее вывода, чтобы она оказалась точно в правом нижнем углу рабочего стола.

Посмотрим на пример позиционирования формы при ее открытии:


Процедура ПриОткрытии()
    
    // Примерный расчет координат на основе разрешения экрана.
    // В реальных задачах можно использовать COM-объект "Wscript.Shell" для точного определения.
    ШиринаЭкран = 1920; 
    ВысотаЭкран = 1080;
    
    ЭтаФорма.Ширина = 300;
    ЭтаФорма.Высота = 120;
    
    ЭтаФорма.Лево = ШиринаЭкран - ЭтаФорма.Ширина - 50;
    ЭтаФорма.Верх = ВысотаЭкран - ЭтаФорма.Высота - 100;
    
    // Настраиваем автозакрытие формы через 7 секунд, если пользователь не кликнул по ней
    ПодключитьОбработчикОжидания("ЗакрытьФормуАвтоматически", 7);
    
КонецПроцедуры

Альтернативный вариант: Использование современных каналов коммуникации

Описанный выше метод опроса регистра сведений отлично подходит, если пользователи постоянно находятся внутри интерфейса 1С. Однако на практике сотрудники часто сворачивают программу или работают вне офиса. В этом случае крайне эффективным решением становится интеграция 1С с мессенджерами, в частности, создание Telegram-бота.

Этот способ позволяет отправлять уведомления асинхронно, мгновенно и без создания дополнительной нагрузки на базу данных 1С постоянными запросами опроса регистра сведений. Разберем по шагам, как настроить отправку сообщений в Telegram при создании документа:

  1. Создайте бота в Telegram через официального бота @BotFather и получите токен доступа (Token API).
  2. Узнайте ID чата пользователя или группы, куда будут приходить оповещения (например, с помощью бота @userinfobot).
  3. В подписке на событие ПриЗаписи, которую мы создали на Шаге 1, вместо записи в регистр сведений вызывайте процедуру отправки HTTP-запроса на сервер Telegram.

Рассмотрим пример кода отправки сообщения в Telegram:


Процедура ОтправитьОповещениеВTelegram(ТекстСообщения, ТокенБота, ИДЧата) Экспорт
    
    // Формируем URL для отправки API-запроса
    АдресРесурса = "bot" + ТокенБота + "/sendMessage";
    
    // Подготавливаем параметры запроса
    ПараметрыЗапроса = "chat_id=" + ИДЧата + "&text=" + КодироватьСтроку(ТекстСообщения, СпособКодированияСтроки.URLКодирование);
    
    // Настраиваем безопасное SSL-соединение
    ssl = Новый ЗащищенноеСоединениеOpenSSL();
    
    Попытка
        HTTPСоединение = Новый HTTPСоединение("api.telegram.org", 443, , , , , ssl);
        HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса + "?" + ПараметрыЗапроса);
        HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
        
        Если HTTPОтвет.КодСостояния <> 200 Тогда
            ЗаписьЖурналаРегистрации("Telegram.Ошибка", УровеньЖурналаРегистрации.Предупреждение, , , 
                "Код ответа сервера: " + HTTPОтвет.КодСостояния + ". Ответ: " + HTTPОтвет.ПолучитьТелоКакСтроку());
        КонецЕсли;
    Исключение
        ЗаписьЖурналаРегистрации("Telegram.КритическаяОшибка", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Этот код отправляет текстовое сообщение напрямую на сервера Telegram. Пользователь моментально получит уведомление на своем мобильном устройстве или персональном компьютере, даже если программа 1С в этот момент закрыта. При необходимости оповещения через корпоративный мессенджер подойдёт инструмент для отправки сообщений в Rocket.Chat через API.

Резюме

Мы детально проанализировали задачу оповещения пользователей в конфигурации «Управление торговлей 10.3» и рассмотрели два наиболее жизнеспособных решения. Классическая схема «Подписка на событие -> Регистр Сведений -> Обработчик ожидания» является полностью автономной, независимой от интернета и надежно хранит историю непрочитанных сообщений непосредственно внутри базы данных. Альтернативный вариант с интеграцией Telegram современен, разгружает СУБД от частых регламентных запросов и позволяет держать сотрудников в курсе событий компании в режиме 24/7.

← На главную