При разработке функционала в 1С:Предприятии часто возникает задача оповестить другого пользователя о каком-либо событии. При этом мы сталкиваемся с необходимостью выбора между различными типами уведомлений: от навязчивых, требующих немедленной реакции, до более мягких, информационных, которые пользователь может просмотреть в удобное для него время. В частности, речь идет о механизме "колокольчика" – центра оповещений, который показывает счетчик новых событий и позволяет ознакомиться с ними по клику. Стандартная функция ПоказатьОповещениеПользователя, к сожалению, работает только для текущего пользователя, вызвавшего её.
В этой статье мы подробно разберем, какие стандартные механизмы в 1С:Управление торговлей 11 (на базе Библиотеки стандартных подсистем) могут быть использованы для оповещения других пользователей, а также рассмотрим, как реализовать собственный, если типовые решения не полностью удовлетворяют нашим требованиям по виду и поведению оповещений.
Мы будем искать способ, который позволяет отображать оповещения именно в "колокольчике" в правом верхнем углу интерфейса, как это делают системные уведомления, а не в виде всплывающих окон по центру экрана, которые могут быть слишком навязчивыми.
Одним из наиболее мощных и универсальных механизмов для коммуникации между пользователями в 1С является Система взаимодействия (СВ). Она предоставляет широкие возможности для обмена сообщениями, создания чатов, обсуждения объектов информационной базы и отправки различных уведомлений. Мы можем использовать СВ для отправки оповещений другому пользователю.
Как работает Система взаимодействия для оповещений?
Сообщения, отправленные через СВ, приходят в клиент 1С и отображаются в специальной панели или окне чата. Если сообщение содержит ссылку на объект информационной базы (например, документ или элемент справочника), пользователь может быстро перейти к нему. Хотя это не тот же самый "колокольчик" для произвольных системных оповещений, СВ является менее навязчивым способом информирования по сравнению с центральными всплывающими напоминаниями.
Преимущества Системы взаимодействия:
Особенности лицензирования СВ:
Для использования Системы взаимодействия не обязательно приобретать корпоративную лицензию платформы 1С. Фирма "1С" предоставляет бесплатный хостинг для сервера взаимодействия, который можно использовать для небольших команд. Если же у вас есть необходимость развернуть сервер взаимодействия на собственном оборудовании, то потребуется либо корпоративная лицензия на платформу, либо отдельная лицензия на "Сервер взаимодействия". Мы рекомендуем уточнить текущие условия лицензирования на официальных ресурсах 1С.
Пример программной отправки сообщения через Систему взаимодействия:
Для отправки сообщения конкретному пользователю или группе пользователей через СВ, мы можем использовать функции из общих модулей Библиотеки стандартных подсистем (БСП). Рассмотрим простой пример:
// Предполагается, что СистемаВзаимодействия включена в конфигурации
// и доступны соответствующие общие модули БСП.
// Получим идентификатор пользователя, которому хотим отправить сообщение
// (например, по его имени пользователя).
// Необходимо реализовать функцию поиска пользователя по его имени или другим данным.
&НаСервере
Функция ПолучитьПользователяИБ(ИмяПользователя)
Пользователь = Пользователи.НайтиПоИмени(ИмяПользователя);
Возврат Пользователь;
КонецФункции
&НаСервере
Процедура ОтправитьОповещениеЧерезСВНаСервере(ИдентификаторПолучателя, ТекстСообщения, СсылкаНаОбъект = Неопределено)
// В зависимости от версии БСП и настроек, модуль и функции могут отличаться.
// Примерный вызов функции отправки сообщения.
МодульУправленияВзаимодействием = ОбщиеМодули.Найти("УправлениеВзаимодействием");
Если МодульУправленияВзаимодействием <> Неопределено Тогда
Если МодульУправленияВзаимодействием.ПоддерживаетсяРаботаССВ() Тогда
// Идентификаторы пользователей могут быть строками (ПолныйИдентификаторПользователя)
// или объектами "Пользователь".
Получатели = Новый Массив();
Получатели.Добавить(ИдентификаторПолучателя);
ПараметрыСообщения = Новый Структура();
ПараметрыСообщения.Вставить("Текст", ТекстСообщения);
Если СсылкаНаОбъект <> Неопределено Тогда
ПараметрыСообщения.Вставить("СсылкаНаПредмет", СсылкаНаОбъект);
КонецЕсли;
// Пример функции отправки сообщения, может быть в модуле ОбменСообщениямиКлиентСервер или УправлениеВзаимодействием
// Точное имя функции и её параметры зависят от версии БСП.
// Например, УправлениеВзаимодействием.ОтправитьСообщение(Получатели, ТекстСообщения);
// Или более универсальный механизм через общие процедуры
ОбщиеМодули.УправлениеВзаимодействием.ОтправитьСообщениеПользователям(Получатели, ТекстСообщения, СсылкаНаОбъект);
// Для более продвинутой работы с СВ может потребоваться использование объекта "СообщениеСистемыВзаимодействия"
// и его программное заполнение.
КонецЕсли;
КонецЕсли;
КонецПроцедуры
// Пример вызова на клиенте или из другого серверного модуля
&НаКлиенте
Процедура КнопкаОтправитьОповещениеНажатие(Команда)
ПользовательВася = ПолучитьПользователяИБ("Вася");
Если ПользовательВася <> Неопределено Тогда
ТекстОповещения = "Важный документ создан: Заказ клиента №123 от 01.01.2024.";
// Здесь можно передать ссылку на созданный документ
// Например, СсылкаНаДокумент = Документы.ЗаказКлиента.НайтиПоНомеру("123");
// ОтправитьОповещениеЧерезСВНаСервере(ПользовательВася, ТекстОповещения, СсылкаНаДокумент);
ОтправитьОповещениеЧерезСВНаСервере(ПользовательВася, ТекстОповещения);
Сообщить("Сообщение Васе отправлено через Систему взаимодействия.");
Иначе
Сообщить("Пользователь 'Вася' не найден.");
КонецЕсли;
КонецПроцедуры
В этом примере мы видим, как можем программно отправить сообщение, которое появится у пользователя "Вася" в его панели взаимодействия. Если мы добавим ссылку на объект, пользователь сможет сразу перейти к нему. Для поиска актуальных процедур и точного синтаксиса вызовов в используемой конфигурации можно использовать справочник описания методов API БСП.
Механизм Задач, присутствующий в УТ 11 и БСП, является стандартным способом для делегирования работы и оповещения пользователей о необходимости выполнения каких-либо действий. При создании задачи для конкретного пользователя, ему приходит уведомление о новой задаче.
Как работают Задачи для оповещений?
Задачи обычно генерируют "напоминания" или отображаются в списках задач, требующих выполнения. Уведомления о новых задачах могут появляться в центре оповещений (колокольчике) как элемент списка задач, но чаще они сопровождаются более навязчивыми всплывающими окнами, требующими реакции пользователя (например, "Отложить" или "Выполнить"). Именно из-за этой навязчивости механизм задач не всегда подходит для простых информационных оповещений, которые мы хотим видеть только в "колокольчике".
Преимущества механизма Задач:
Недостатки для нашей цели:
Как мы уже выяснили, для нас критично, чтобы оповещение было менее навязчивым. Задачи, как правило, стремятся получить внимание пользователя и требуют определенной реакции, что делает их менее подходящими для фоновых информационных уведомлений в "колокольчике". Они больше похожи на "напоминания" в привычном смысле.
Пример программного создания Задачи:
Создание задачи программно осуществляется через объект Задачи.ЗадачаИсполнителя:
// Предполагается, что подсистема "Задачи" включена и настроена.
&НаСервере
Процедура СоздатьЗадачуДляПользователяНаСервере(ИмяПолучателя, ТекстЗадачи, СсылкаНаПредмет = Неопределено)
// Найдем пользователя по имени
Получатель = Пользователи.НайтиПоИмени(ИмяПолучателя);
Если Получатель = Неопределено Тогда
Сообщить("Пользователь '" + ИмяПолучателя + "' не найден.", СтатусСообщения.Внимание);
Возврат;
КонецЕсли;
Попытка
ЗадачаОбъект = Задачи.ЗадачаИсполнителя.СоздатьЗадачу();
ЗадачаОбъект.Предмет = СсылкаНаПредмет; // Ссылка на документ/справочник, к которому относится задача
ЗадачаОбъект.Наименование = ТекстЗадачи;
ЗадачаОбъект.Описание = ТекстЗадачи;
ЗадачаОбъект.Исполнитель = Получатель;
ЗадачаОбъект.СрокИсполнения = ТекущаяДата() + 60*60*24; // Срок на 1 день
ЗадачаОбъект.Важность = Перечисления.ВариантыВажностиЗадачи.Обычная;
ЗадачаОбъект.ДатаНачала = ТекущаяДата();
ЗадачаОбъект.ДатаОкончания = ТекущаяДата() + 60*60*24;
// Определяем, кем создана задача (автор задачи)
// Можно указать текущего пользователя или специального пользователя системы
ЗадачаОбъект.Автор = Пользователи.ТекущийПользователь();
// Записываем задачу
ЗадачаОбъект.Записать();
Сообщить("Задача для пользователя '" + ИмяПолучателя + "' успешно создана: " + ТекстЗадачи);
Исключение
Сообщить("Ошибка при создании задачи: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
КонецПопытки;
КонецПроцедуры
// Пример вызова на клиенте
&НаКлиенте
Процедура КнопкаСоздатьЗадачуНажатие(Команда)
СоздатьЗадачуДляПользователяНаСервере("Петя", "Проверьте новый приходный ордер №500.");
КонецПроцедуры
После создания такой задачи, Петя получит уведомление о ней. В зависимости от настроек, это может быть всплывающее окно или запись в списке задач, которая также отобразится в "колокольчике" как новый элемент в категории "Задачи".
Если ни Система взаимодействия, ни Задачи не обеспечивают в точности требуемое поведение – а именно, простое, неинтрузивное оповещение в "колокольчике" для другого пользователя, аналогичное ПоказатьОповещениеПользователя, но инициируемое не самим пользователем – мы можем реализовать собственный механизм. Этот подход дает нам полный контроль над логикой и внешним видом оповещений.
Принцип работы собственного механизма:
ПоказатьОповещениеПользователя для текущего пользователя, тем самым отобразив его в "колокольчике". После отображения оповещения в регистре будет установлен статус "Прочитано" или "Отображено", чтобы оно не появлялось повторно.Шаг 1: Создание регистра сведений "ОповещенияПользователей"
Мы создадим новый регистр сведений с примерно такой структурой:
Пользователь (Тип: СправочникСсылка.Пользователи) - Кому предназначено оповещение.УникальныйИдентификатор (Тип: Строка, Длина: 36) - Уникальный идентификатор оповещения для предотвращения повторного показа.ТекстОповещения (Тип: Строка, Неограниченная) - Текст сообщения, которое будет отображаться.СсылкаНаОбъект (Тип: Произвольный) - Ссылка на объект, к которому относится оповещение (необязательно).ДатаСоздания (Тип: Дата) - Дата и время создания оповещения.Прочитано (Тип: Булево) - Признак того, что оповещение уже было отображено пользователю.Шаг 2: Программная запись оповещений в регистр (серверный модуль)
Создадим функцию на сервере, которая будет добавлять новые записи в наш регистр:
// В серверном общем модуле или модуле объекта
Процедура ДобавитьОповещениеДляПользователя(Пользователь, ТекстОповещения, СсылкаНаОбъект = Неопределено)
Если Пользователь = Неопределено Тогда
Возврат;
КонецЕсли;
НаборЗаписей = РегистрыСведений.ОповещенияПользователей.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Пользователь.Установить(Пользователь);
НаборЗаписей.Прочитать();
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Пользователь = Пользователь;
НоваяЗапись.УникальныйИдентификатор = Новый УникальныйИдентификатор();
НоваяЗапись.ТекстОповещения = ТекстОповещения;
НоваяЗапись.СсылкаНаОбъект = СсылкаНаОбъект;
НоваяЗапись.ДатаСоздания = ТекущаяДата();
НоваяЗапись.Прочитано = Ложь;
Попытка
НаборЗаписей.Записать();
Исключение
ЗаписьЖурналаРегистрации(
"Оповещения",
УровеньЖурналаРегистрации.Ошибка,
Метаданные.РегистрыСведений.ОповещенияПользователей,
,
"Ошибка при записи оповещения: " + ОписаниеОшибки()
);
КонецПопытки;
КонецПроцедуры
// Пример использования:
// ДобавитьОповещениеДляПользователя(Документы.ЗаказКлиента.НайтиПоНомеру("00000001").Ответственный,
// "Новый заказ №00000001 ожидает согласования.",
// Документы.ЗаказКлиента.НайтиПоНомеру("00000001"));
Шаг 3: Настройка ОбработчикаОжидания на клиенте
Мы будем использовать обработчик ожидания, который будет периодически опрашивать регистр сведений на сервере. Для этого нам понадобится процедура на клиенте и функция на сервере.
Серверная функция для проверки новых оповещений:
// В серверном общем модуле
&НаСервере
Функция ПолучитьНепрочитанныеОповещенияДляТекущегоПользователя()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОповещенияПользователей.УникальныйИдентификатор КАК УникальныйИдентификатор,
| ОповещенияПользователей.ТекстОповещения КАК ТекстОповещения,
| ОповещенияПользователей.СсылкаНаОбъект КАК СсылкаНаОбъект
|ИЗ
| РегистрСведений.ОповещенияПользователей КАК ОповещенияПользователей
|ГДЕ
| ОповещенияПользователей.Пользователь = &ТекущийПользователь
| И ОповещенияПользователей.Прочитано = ЛОЖЬ
|УПОРЯДОЧИТЬ ПО
| ОповещенияПользователей.ДатаСоздания";
Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.ТекущийПользователь());
Выборка = Запрос.Выполнить().Выбрать();
СписокОповещений = Новый Массив();
Пока Выборка.Следующий() Цикл
СписокОповещений.Добавить(Новый Структура("УникальныйИдентификатор, ТекстОповещения, СсылкаНаОбъект",
Выборка.УникальныйИдентификатор,
Выборка.ТекстОповещения,
Выборка.СсылкаНаОбъект));
КонецЦикла;
Возврат СписокОповещений;
КонецФункции
&НаСервере
Процедура УстановитьСтатусПрочитаноДляОповещения(УникальныйИдентификатор)
НаборЗаписей = РегистрыСведений.ОповещенияПользователей.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Пользователь.Установить(Пользователи.ТекущийПользователь());
НаборЗаписей.Отбор.УникальныйИдентификатор.Установить(УникальныйИдентификатор);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() > 0 Тогда
НаборЗаписей[0].Прочитано = Истина;
Попытка
НаборЗаписей.Записать();
Исключение
ЗаписьЖурналаРегистрации(
"Оповещения",
УровеньЖурналаРегистрации.Ошибка,
Метаданные.РегистрыСведений.ОповещенияПользователей,
,
"Ошибка при обновлении статуса оповещения: " + ОписаниеОшибки()
);
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Клиентская процедура для ОбработчикаОжидания:
Эту процедуру мы можем подключить, например, в модуле управляемого приложения или в модуле основной формы, которая открывается при старте:
// В модуле управляемого приложения или в глобальном клиентском общем модуле
Перем гИдентификаторОбработчикаОжиданияОповещений Экспорт;
&НаКлиенте
Процедура УстановитьОбработчикОжиданияОповещений() Экспорт
Если гИдентификаторОбработчикаОжиданияОповещений = Неопределено Тогда
гИдентификаторОбработчикаОжиданияОповещений = ПодключитьОбработчикОжидания("ПроверитьНовыеОповещения", 10, Истина); // Проверка каждые 10 секунд
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОтключитьОбработчикОжиданияОповещений() Экспорт
Если гИдентификаторОбработчикаОжиданияОповещений <> Неопределено Тогда
ОтключитьОбработчикОжидания(гИдентификаторОбработчикаОжиданияОповещений);
гИдентификаторОбработчикаОжиданияОповещений = Неопределено;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьНовыеОповещения() Экспорт
// Вызываем серверную функцию для получения новых оповещений
СписокОповещений = ПолучитьНепрочитанныеОповещенияДляТекущегоПользователя();
Для Каждого Оповещение Из СписокОповещений Цикл
ОписаниеОповещения = Новый ОписаниеОповещения("ОповещениеОтображено", ЭтотОбъект, Оповещение.УникальныйИдентификатор);
// Показываем оповещение в центре оповещений
Если Оповещение.СсылкаНаОбъект <> Неопределено Тогда
ПоказатьОповещениеПользователя(Оповещение.ТекстОповещения, ОписаниеОповещения, , Оповещение.СсылкаНаОбъект);
Иначе
ПоказатьОповещениеПользователя(Оповещение.ТекстОповещения, ОписаниеОповещения);
КонецЕсли;
// Устанавливаем статус "прочитано" на сервере
УстановитьСтатусПрочитаноДляОповещения(Оповещение.УникальныйИдентификатор);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ОповещениеОтображено(ИмяМетода, ИдентификаторОповещения) Экспорт
// Этот метод вызывается, когда пользователь взаимодействовал с оповещением в центре оповещений,
// например, кликнул по нему.
// Если нужно выполнить какие-то действия после взаимодействия пользователя,
// можно реализовать их здесь.
// Например, открыть объект по ссылке, если оповещение его содержало.
КонецПроцедуры
Подключение обработчика при старте системы:
В модуле управляемого приложения в процедуре ПриНачалеРаботыСистемы() или ПриНачалеРаботыСистемыКлиент() мы можем вызвать УстановитьОбработчикОжиданияОповещений(), чтобы он начал работать сразу после входа пользователя в систему. Не забывайте отключать обработчик ожидания при завершении работы с системой или при выходе пользователя, чтобы избежать утечек памяти и лишней нагрузки.
Преимущества собственного механизма:
Недостатки собственного механизма:
Критически важно понимать разницу между "оповещением" и "напоминанием", поскольку это было ключевым моментом в обсуждении. Мы специально ищем "оповещение" как индикатор в "колокольчике", а не "напоминание" как центральное всплывающее окно.
В нашем случае, когда мы говорим об оповещении другого пользователя, мы стремимся к поведению "колокольчика", которое ассоциируется именно с первым типом уведомлений.
Мы рассмотрели несколько подходов к оповещению других пользователей в 1С:Управление торговлей 11.
При выборе подхода всегда анализируйте, насколько критично для вас точное отображение в "колокольчике" и неинтрузивность, или же функционала Системы взаимодействия или Задач будет достаточно для решения вашей бизнес-задачи. Учитывайте также затраты на разработку и поддержку каждого из предложенных вариантов.