Статья создана для того, чтобы развеять миф: «Сервисы интеграции» — это только коннектор для Шины.
Покажу пример с «ПоказатьОповещениеПользователя», в этом примере не будет Шины от слова совсем.
У меня была не самая свежая БСП 3.1.6.118, на ней и буду демонстрировать, но вообще не принципиально.
В БСП есть расширение «_ДемоПустоеРасширение», в нем создал «Сервис интеграции» и Канал «_ОповещенияПользователей» для отправки:
В БСП есть форма текущие дела, добавим ее в расширение «_ДемоПустоеРасширение»:
Добавим обработчик события формы ПриОткрытии (После): _ДемоПустоеРасширениеПриОткрытииПосле
&НаКлиенте
Перем СтруктураПользователяФормы;
&НаКлиенте
Процедура _ДемоПустоеРасширениеПриОткрытииПосле(Отказ)
СтруктураПользователяФормы = ПолучитьСтруктуруПользователя();
// установил срабатывание раз в 15 секунд
ПодключитьОбработчикОжидания("ПолучитьСообщенияДляОповещения", 15, Ложь);
КонецПроцедуры
&НаСервере
Функция ПолучитьСтруктуруПользователя()
ВключенПривилегированныйРежим = Ложь;
Если Не ПривилегированныйРежим() Тогда
ВключенПривилегированныйРежим = Истина;
УстановитьПривилегированныйРежим(ВключенПривилегированныйРежим);
КонецЕсли;
ТекПользовательФормы = ПользователиИнформационнойБазы.ТекущийПользователь();
СтруктураПользователяФормы = Новый Структура("Имя,Идентификатор",
ТекПользовательФормы.Имя,
Строка(ТекПользовательФормы.УникальныйИдентификатор));
Если ВключенПривилегированныйРежим Тогда
ВключенПривилегированныйРежим = Ложь;
УстановитьПривилегированныйРежим(ВключенПривилегированныйРежим);
КонецЕсли;
Возврат СтруктураПользователяФормы;
КонецФункции
&НаКлиенте
Процедура ПолучитьСообщенияДляОповещения()
МассивСообщений = ПолучитьСообщения("_ДляОповещения", "_ОповещенияПользователей", СтруктураПользователяФормы);
Если МассивСообщений.Количество() > 0 Тогда
Для Каждого ТекСообщение Из МассивСообщений Цикл
Если Не ТекСообщение.Свойство("Сообщение") Тогда
Продолжить;
КонецЕсли;
Если ТекСообщение.Свойство("НавигационнаяСсылка") Тогда
ПоказатьОповещениеПользователя(ТекСообщение.Сообщение
,ТекСообщение.НавигационнаяСсылка
,?(ТекСообщение.Свойство("Отправитель"),ТекСообщение.Отправитель,""),
,СтатусОповещенияПользователя.Важное
,ТекСообщение.Идентификатор);
Иначе
ПоказатьОповещениеПользователя(ТекСообщение.Сообщение,
,?(ТекСообщение.Свойство("Отправитель"),ТекСообщение.Отправитель,""),
,СтатусОповещенияПользователя.Важное
,ТекСообщение.Идентификатор);
КонецЕсли;
КонецЦикла;
Если МассивСообщений.Количество() > 0 Тогда
ОчиститьВсеСообщенияНаСервере("_ДляОповещения", "_ОповещенияПользователей", МассивСообщений);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСообщения(Сервис, Канал, ПользовательФормы)
Отбор = Новый Структура;
Отбор.Вставить("КодПолучателя", ПользовательФормы.Идентификатор);
ПараметрыОтбора = Новый Соответствие;
ПараметрыОтбора.Вставить("ТипСообщения", "Оповещение");
СообщенияСервиса = СервисыИнтеграции[Сервис][Канал].ВыбратьСообщения(Отбор);
МассивСообщений = Новый Массив;
Для Каждого текСообщение Из СообщенияСервиса Цикл
СткруктураСообщения = Новый Структура;
СткруктураСообщения.Вставить("Идентификатор", текСообщение.Идентификатор);
РазмерСообщения = текСообщение.Параметры.Получить("РазмерСообщения");
Если РазмерСообщения <> Неопределено Тогда
РазмерБуфера = Число(РазмерСообщения);
Иначе
РазмерБуфера = 1024;
КонецЕсли;
// Читаем тело сообщения++
Если РазмерБуфера = 0 Тогда
ВходящееСообщение = "";
Иначе
Тело = Новый БуферДвоичныхДанных(0);
Буфер = Новый БуферДвоичныхДанных(РазмерБуфера);
Поток = текСообщение.ПолучитьТелоКакПоток();
Пока Истина Цикл
Прочитано = Поток.Прочитать(Буфер, 0, РазмерБуфера);
Если Прочитано > 0 Тогда
Тело = Тело.Соединить(Буфер);
КонецЕсли;
Если Прочитано < РазмерБуфера Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ВходящееСообщение = ПолучитьСтрокуИзБуфераДвоичныхДанных(Тело);
КонецЕсли;
Если Не ПустаяСтрока(ВходящееСообщение) Тогда
РезультатJS = ЧтениеДанныхИзJSON(ВходящееСообщение);
Если РезультатJS.Отработал Тогда
ТелоРезультат = РезультатJS.Результат;
СткруктураСообщения.Вставить("Сообщение", ТелоРезультат.Сообщение);
СткруктураСообщения.Вставить("НавигационнаяСсылка",
ТелоРезультат.НавигационнаяСсылка);
СткруктураСообщения.Вставить("Отправитель", ТелоРезультат.Отправитель);
КонецЕсли;
КонецЕсли;
МассивСообщений.Добавить(СткруктураСообщения);
КонецЦикла;
Возврат МассивСообщений;
КонецФункции
&НаСервереБезКонтекста
Процедура ОчиститьВсеСообщенияНаСервере(Сервис, Канал, МассивСообщений = Неопределено)
Если ЗначениеЗаполнено(МассивСообщений) Тогда
Для Каждого ИдентификаторСообщения Из МассивСообщений Цикл
СервисыИнтеграции[Сервис][Канал].УдалитьСообщения(ИдентификаторСообщения);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
// Функция Десериализует строку JSON в формат данных 1С
//
// Параметры:
// СтрокаJSON - Строка - JSON
//
// Возвращаемое значение:
// Результат - Структура
// Отработал - Булево - Выполнено или нет
// ТекстОшибки - Строка - Текст ошибки если функция отработала с ошибкой
// Результат - ЛюбоеЗначение - Данные в формате 1С
//
&НаСервереБезКонтекста
Функция ЧтениеДанныхИзJSON(СтрокаJSON) Экспорт
Результат = Новый Структура("Отработал, ТекстОшибки", Истина, "");
Попытка
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Результат.Вставить("Результат",ПрочитатьJSON(ЧтениеJSON));
Исключение
Результат.Отработал = Ложь;
Результат.ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Возврат Результат;
КонецФункции
Пояснение по коду:
- В обработчике события «ПриОткрытии» считываем параметры текущего пользователя и запускаем обработчик ожидания раз в 15 секунд. Параметры пользователя нам нужны для поиска сообщений, адресованных только ему.
- В обработчике считываем сообщения и выводим в цикле их содержание используя функционал «ПоказатьОповещениеПользователя».
- После вывода оповещения удаляем сообщения.
Расширение приложено к данной статье «_ДемоПустоеРасширение.cfe»
Активируем «Сервис интеграции» воспользовавшись типовой обработкой или обработкой «Настройка сервисов интеграции».
Никакие параметры не заполняем, так как мы к Шине не цепляемся.
Для примера я создал обработку, которую приложил к данной статье «СоздатьСообщениеДляОповещения.epf»
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Метаданные.СервисыИнтеграции.Количество() > 0 Тогда
Для Каждого СервисИнтеграции Из Метаданные.СервисыИнтеграции Цикл
Элементы.Сервис.СписокВыбора.Добавить(СервисИнтеграции.Имя,СервисИнтеграции.Имя);
КонецЦикла;
Если Элементы.Сервис.СписокВыбора.Количество() > 0 Тогда
Сервис = Элементы.Сервис.СписокВыбора[0];
СервисПриИзмененииНаСервере();
КонецЕсли;
КонецЕсли;
// Для получения списка пользователей нужны административные права++
ВключенПривилегированныйРежим = Ложь;
Если Не ПривилегированныйРежим() Тогда
ВключенПривилегированныйРежим = Истина;
УстановитьПривилегированныйРежим(ВключенПривилегированныйРежим);
КонецЕсли;
ТекПользовательФормы = ПользователиИнформационнойБазы.ТекущийПользователь();
ИмяОтпраителя = ТекПользовательФормы.Имя;
ИдентификаторОтправителя = Строка(ТекПользовательФормы.УникальныйИдентификатор);
ВыборкаПользователей = ПользователиИнформационнойБазы.ПолучитьПользователей(); // Получаем список пользователей
Для Каждого ЭлементМассива Из ВыборкаПользователей Цикл
Элементы.Получатель.СписокВыбора.Добавить(Строка(ЭлементМассива.УникальныйИдентификатор), ЭлементМассива.Имя);
КонецЦикла;
Если ВключенПривилегированныйРежим Тогда
ВключенПривилегированныйРежим = Ложь;
УстановитьПривилегированныйРежим(ВключенПривилегированныйРежим);
КонецЕсли;
// Для получения списка пользователей нужны административные права--
КонецПроцедуры
&НаКлиенте
Процедура СервисПриИзменении(Элемент)
СервисПриИзмененииНаСервере();
КонецПроцедуры
&НаСервере
Процедура СервисПриИзмененииНаСервере()
Если Элементы.Канал.СписокВыбора.Количество() > 0 Тогда
Элементы.Канал.СписокВыбора.Очистить();
КонецЕсли;
текСервис = Метаданные.СервисыИнтеграции.Найти(Сервис);
Если текСервис <> Неопределено Тогда
КаналаСервисаИнтеграцииОтправка = Метаданные.СвойстваОбъектов.НаправлениеСообщенияКаналаСервисаИнтеграции.Отправка;
Для Каждого текКаналСервиса Из текСервис.КаналыСервисаИнтеграции Цикл
Если текКаналСервиса.НаправлениеСообщения = КаналаСервисаИнтеграцииОтправка Тогда
Элементы.Канал.СписокВыбора.Добавить(текКаналСервиса.Имя, текКаналСервиса.Имя);
КонецЕсли;
КонецЦикла;
Если Элементы.Канал.СписокВыбора.Количество() > 0 Тогда
Канал = Элементы.Канал.СписокВыбора[0];
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОтправитьСообщение(Команда)
ОтправитьСообщениеНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОтправитьСообщениеНаСервере()
// храним сообщение 60 дней
ДатаУстаревания = ТекущаяДатаСеанса() + 60 * 86400;
СообщениеСервиса = СервисыИнтеграции[Сервис].СоздатьСообщение(ДатаУстаревания);
// вставляем идентификаторы
СообщениеСервиса.КодПолучателя = Получатель;
СообщениеСервиса.КодОтправителя = ИдентификаторОтправителя;
СтруктураТела = Новый Структура("Сообщение, НавигационнаяСсылка, Отправитель",
Сообщение, ТекстоваяСсылка, ИмяОтпраителя);
// передавать будем в формате json
РезультатJS = ЗаписатьДанныеВJSON(, СтруктураТела);
ТекстСообщения = ?(РезультатJS.Отработал, РезультатJS.Результат, "");
Тело = СообщениеСервиса.ПолучитьТелоКакПоток();
Буфер = ПолучитьБуферДвоичныхДанныхИзСтроки(ТекстСообщения);
Тело.Записать(Буфер, 0, Буфер.Размер);
Тело.Закрыть();
// размер тела
СообщениеСервиса.Параметры.Вставить("РазмерСообщения", Буфер.Размер);
// тип сообщения, для выборки
СообщениеСервиса.Параметры.Вставить("ТипСообщения", "Оповещение");
СервисыИнтеграции[Сервис][Канал].ОтправитьСообщение(СообщениеСервиса);
КонецПроцедуры
// Функция возвращает чаще всего используемые ПараметрыЗаписиJSON (JSONWriterSettings)
//
// Возвращаемое значение:
// Результат - Структура - Стандартное заполнение
//
Функция СтандартныеПараметрыJSON() Экспорт
Результат = Новый Структура;
Результат.Вставить("ПереносСтрок", ПереносСтрокJSON.Нет);
Результат.Вставить("СимволОтступа", " ");
Результат.Вставить("ИспользоватьДвойныеКавычки", Истина);
Результат.Вставить("ЭкранированиеСимволов", ЭкранированиеСимволовJSON.Нет);
Результат.Вставить("ЭкранироватьАмперсанд", Ложь);
Результат.Вставить("ЭкранироватьОдинарныеКавычки", Ложь);
Результат.Вставить("ЭкранироватьРазделителиСтрок", Ложь);
Результат.Вставить("ЭкранироватьУгловыеСкобки", Ложь);
Результат.Вставить("ЭкранироватьСлеш", Ложь);
Возврат Результат;
КонецФункции
// Функция переводит данные в формат JSON
//
// Параметры:
// ВходящиеПараметры - Структура - Параметры формирование JSON
// ВходныеДанные - ЛюбоеЗначение - Данные которые нужно перевести в JSON
//
// Возвращаемое значение:
// Результат - Структура
// Отработал - Булево - Выполнено или нет
// ТекстОшибки - Строка - Текст ошибки если функция отработала с ошибкой
// Результат - Строка - JSON
//
Функция ЗаписатьДанныеВJSON(ВходящиеПараметры = Неопределено, ВходныеДанные = "") Экспорт
Результат = Новый Структура("Отработал, ТекстОшибки", Истина, "");
Если ВходящиеПараметры = Неопределено Тогда
ВходящиеПараметры = СтандартныеПараметрыJSON();
КонецЕсли;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ВходящиеПараметры.ПереносСтрок,
ВходящиеПараметры.СимволОтступа,
ВходящиеПараметры.ИспользоватьДвойныеКавычки,
ВходящиеПараметры.ЭкранированиеСимволов,
ВходящиеПараметры.ЭкранироватьУгловыеСкобки,
ВходящиеПараметры.ЭкранироватьРазделителиСтрок,
ВходящиеПараметры.ЭкранироватьАмперсанд,
ВходящиеПараметры.ЭкранироватьОдинарныеКавычки,
ВходящиеПараметры.ЭкранироватьСлеш);
Попытка
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ПроверятьСтруктуру = Истина;
ЗаписьJSON.УстановитьСтроку(ПараметрыJSON);
ЗаписатьJSON(ЗаписьJSON, ВходныеДанные);
Результат.Вставить("Результат", ЗаписьJSON.Закрыть());
Исключение
Результат.Отработал = Ложь;
Результат.ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Возврат Результат;
КонецФункции
Пояснение по коду:
1 В обработчике события «ПриСозданииНаСервере» добавляем список сервисов и каналов.
Считываем Имя и Идентификатор текущего пользователя, для поля ИмяОтправителя.
Считываем Имя и Идентификаторы всех пользователей, для поля Пользователь.
Идентификатор будет служить для идентификации получателя и отправителя.
2 В создаваемых сообщениях устанавливаем дату устаревания 60 дней после текущей даты.
3 Тело сообщения — это структура в формате JSON, в которую сохраняем текст сообщения, имя автора и навигационную ссылку на объект (необязательно).
Открываем два окна под Руководителем и Администратором.
От Руководителя шлем сообщение Администратору, затем после того, как Администратор его прочитает, отправим сообщение руководителю:
Заключение:
Вот таким незамысловатым способом мы использовали новый механизм «Сервисы интеграции». Как вы видите, этот механизм может решать не только интеграционные задачи.
Я считаю, что механизм неплохой и перспективный, если вы его еще не трогали, присмотритесь к нему.
На этом статью завершаю.
Всем желаю профессионального роста и интересных задач!
Полезные ссылки:
Поинтегрируем: нужна ли Шина вам? – Статья, с которой начался цикл статей по интеграции.
Три инструмента для сервисов интеграции – Бесплатные инструменты по работе с сервисами интеграции.
PAPI-tools – Проект на GitHub содержащий исходники обработок, которые будут первоначально выкладываться в данном проекте, а в будущем перетекать в подсистему PAPI (релиз подсистемы запланирован на 19.05.2024)
Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор? – Статья описывает механизм «Сервисы интеграции» изнутри и снаружи