Как программно вывести окно с напоминанием другому пользователю при создании задачи в УТ 11.0?

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

В процессе разработки в конфигурации 1С:Управление торговлей 11.0 (особенно в старых релизах, таких как 11.0.6.9) программисты часто сталкиваются с задачей оперативного оповещения пользователей. Типичный сценарий: один пользователь создает задачу или запускает бизнес-процесс, а у исполнителя должно мгновенно (или с минимальной задержкой) всплыть окно-напоминание.

Сложность заключается в том, что старые версии УТ 11.0 базируются на ранних редакциях Библиотеки стандартных подсистем (БСП 1.2.1.11). В этих редакциях еще не существовало удобных и привычных сегодня методов клиентского программного интерфейса, таких как НапоминанияПользователяClient.НапомнитьВУказанноеВремя. Давайте детально разберем, как обойти это ограничение, почему стандартный механизм БСП может не срабатывать сразу и как реализовать надежное оповещение своими силами.

Выясняем причину: разница версий БСП

Если вы попытаетесь использовать в УТ 11.0 конструкцию:

НапоминанияПользователяКлиент.НапомнитьВУказанноеВремя(Текст, Время, Предмет)

система выдаст ошибку, так как этого метода попросту нет в глобальном поиске по конфигурации. Данный метод появился только в БСП версии 2.0 и выше (что соответствует релизам УТ 11.1 и новее). Тем не менее, сам регистр сведений НапоминанияПользователя в системе присутствует. Это означает, что базовая архитектура хранения напоминаний заложена, но программные интерфейсы для работы с ней разработчику старой конфигурации приходится прописывать вручную.

Решение №1: Прямая запись в регистр сведений «Напоминания пользователя»

Поскольку готовых серверных или клиентских общих процедур для создания напоминания в БСП 1.2 нет, мы можем записать данные напрямую в регистр сведений НапоминанияПользователя. Делать это необходимо на стороне сервера, например, в подписке на событие ПриЗаписи задачи или непосредственно в модуле объекта задачи при ее создании.

Рассмотрим пример кода, который создает напоминание для конкретного исполнителя задачи:


Процедура СоздатьНапоминаниеИсполнителю(СсылкаНаЗадачу, Исполнитель, СрокНапоминания) Экспорт

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

КонецПроцедуры

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

Почему запись создана, но напоминание не всплывает?

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

  1. Опрос по расписанию (Pull-модель): Механизм напоминаний в 1С построен не на мгновенной отправке данных от сервера к клиенту (Push), а на периодическом опросе базы данных со стороны клиентского приложения (Pull). При старте системы подключается обработчик ожидания (обычно это процедура ПроверитьТекущиеНапоминания), который считывает данные из регистра раз в несколько минут (по умолчанию от 5 до 15 минут). Оповещение не всплывет мгновенно — нужно дождаться срабатывания обработчика.
  2. Кэширование на клиенте: Модули повторного использования на клиенте кэшируют список напоминаний. Даже если вы принудительно вызовете проверку, клиентское приложение может вернуть старый пустой результат из кэша, не обращаясь к серверу повторно.
  3. Отключенные функциональные опции: Проверьте, включена ли в настройках системы константа, отвечающая за использование напоминаний (в разделе органайзера). Если опция отключена, обработчик ожидания на клиенте просто не инициализируется при запуске сеанса.
  4. Индивидуальные настройки пользователя: В старых версиях УТ настройки вывода оповещений могли зависеть от персональных параметров. Убедитесь, что у пользователя-получателя в настройках выставлено отображение уведомлений «Во всплывающем окне».

Решение №2: Создание собственного легковесного механизма оповещений

Если штатный механизм БСП 1.2 работает нестабильно из-за многочисленных доработок старой конфигурации или не обеспечивает требуемую скорость реакции, гораздо проще и надежнее внедрить собственный легковесный механизм оповещения через очередь сообщений.

Давайте разберем по шагам, как это реализовать:

Шаг 1. Создание вспомогательного регистра

Создадим новый регистр сведений ОчередьОповещенийПользователей со следующей структурой:

Шаг 2. Запись в очередь при создании задачи

В модуле объекта задачи в процедуре ПриЗаписи добавим несложный код для регистрации оповещения:


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

Шаг 3. Подключение обработчика ожидания на клиенте

В модуле управляемого приложения в процедуре ПриНачалеРаботыСистемы подключим быстрый и легкий обработчик ожидания, который будет проверять наличие новых записей каждые 30–60 секунд:


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

Шаг 4. Чтение очереди и вывод оповещения

В глобальном или обычном неглобальном общем модуле (например, ОповещенияКлиент) создаем процедуру обработки:


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

На стороне сервера (в модуле ОповещенияСервер) мы считываем накопленные строки и сразу же удаляем их из регистра, чтобы избежать повторного показа:


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

Решение №3: Использование Системы взаимодействия (1С:Диалог)

Если ваша конфигурация работает на платформе 1С:Предприятие версии 8.3.10 и выше, вы можете полностью отказаться от тяжелых регламентных заданий, регистров очереди и частых обработчиков ожидания, нагружающих сервер СУБД. Идеальным инструментом для мгновенной отправки сообщений между пользователями является Система взаимодействия.

При таком подходе в момент создания задачи серверный код отправляет push-сообщение получателю через объект СистемаВзаимодействия. Пользователь получает уведомление в течение доли секунды, прямо в интерфейсе платформы 1С.

Разберем базовый пример программной отправки сообщения:


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

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

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

Система взаимодействия избавит базу данных от лишней транзакционной нагрузки и обеспечит моментальную доставку уведомлений без зависаний сессий пользователей.

← На главную