В процессе разработки механизмов интеграции между базами 1С часто возникает ситуация, когда в момент проведения документа в одной базе необходимо выполнить действие в другой (например, через веб-сервис) и сообщить пользователю о результате. Основная сложность заключается в том, что в управляемом интерфейсе 1С 8.3 процедура ОбработкаПроведения выполняется на сервере в транзакции. Если форма документа настроена на закрытие после успешного проведения, стандартные сообщения, сформированные через СообщениеПользователю, могут просто не успеть отобразиться или исчезнуть вместе с контекстом закрытой формы.
Разберем подробно несколько сценариев решения этой задачи: от использования временных хранилищ и дополнительных свойств до создания полноценной очереди уведомлений через регистр сведений.
Этот способ считается наиболее элегантным, если нам нужно вывести информацию сразу после записи объекта, при этом понимая, что форма самого объекта может быть закрыта. Идея заключается в том, чтобы "протащить" массив сообщений из серверного модуля объекта в клиентский модуль формы, а затем изменить ИдентификаторНазначения этих сообщений, чтобы они привязались к форме списка (владельцу), которая остается открытой.
Проанализируем ситуацию пошагово:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Ваш код обращения к внешней базе
РезультатИнтеграции = ИнтеграцияСВнешнейБазой.СоздатьЗаказ(ЭтотОбъект);
Если Не РезультатИнтеграции.Успех Тогда
// Не ставим Отказ = Истина, так как по условию проведение должно завершиться
ЭтотОбъект.ДополнительныеСвойства.Вставить("ОшибкаВнешнейБазы", РезультатИнтеграции.ТекстОшибки);
КонецЕсли;
КонецПроцедуры
ПослеЗаписиНаСервере. Здесь мы проверяем наличие данных в дополнительных свойствах и передаем их в параметры записи, которые доступны на клиенте.
&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
Если ТекущийОбъект.ДополнительныеСвойства.Свойство("ОшибкаВнешнейБазы") Тогда
ТекстОшибки = ТекущийОбъект.ДополнительныеСвойства.ОшибкаВнешнейБазы;
// Формируем сообщение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Заказ проведен локально, но во второй базе возникла ошибка: " + ТекстОшибки;
Сообщение.Сообщить();
// Перехватываем сообщения, чтобы передать их на клиент
МассивСообщений = ПолучитьСообщенияПользователю(Истина);
ПараметрыЗаписи.Вставить("ПерехваченныеСообщения", МассивСообщений);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
Если ПараметрыЗаписи.Свойство("ПерехваченныеСообщения") Тогда
МассивСообщений = ПараметрыЗаписи.ПерехваченныеСообщения;
Для Каждого ТекСообщение Из МассивСообщений Цикл
// Если форма закрывается, привязываем сообщение к форме-владельцу
Если ВладелецФормы <> Неопределено Тогда
ТекСообщение.ИдентификаторНазначения = ВладелецФормы.УникальныйИдентификатор;
КонецЕсли;
ТекСообщение.Сообщить();
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Если документ проводится не из формы (например, групповым перепроведением или из формы списка), метод с ДополнительныеСвойства формы не сработает. В таком случае выясним причину и применим более надежный архитектурный подход — очередь сообщений в регистре сведений.
Рассмотрим алгоритм реализации:
ОчередьУведомленийПользователей. Поля: Пользователь (Ресурс), ТекстСообщения (Ресурс), ДатаСобытия (Измерение).
// В модуле объекта
Запись = РегистрыСведений.ОчередьУведомленийПользователей.СоздатьМенеджерЗаписи();
Запись.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Запись.ТекстСообщения = "Ошибка при создании заказа в базе №2: " + ОписаниеОшибки;
Запись.ДатаСобытия = ТекущаяДата();
Запись.Записать();
Модуле управляемого приложения создадим обработчик ожидания, который будет периодически проверять этот регистр и выводить сообщения через ПоказатьОповещениеПользователя.
// В модуле управляемого приложения
Процедура ПриНачалеРаботыСистемы()
ПодключитьОбработчикОжидания("ПроверитьНовыеУведомления", 60); // раз в минуту
КонецПроцедуры
Процедура ПроверитьНовыеУведомления() Экспорт
Уведомления = ПолучитьУведомленияССервера();
Для Каждого Уведомление Из Уведомления Цикл
ПоказатьОповещениеПользователя("Внимание! Ошибка интеграции", , Уведомление.Текст);
КонецЦикла;
КонецПроцедуры
Преимущество данного метода в том, что сообщение гарантированно дойдет до пользователя, вне зависимости от того, в какой форме он находится и закрыл ли он документ. Это особенно критично для "неразумных" пользователей, которые могут не заметить обычное всплывающее сообщение в углу экрана.
Проанализируем современный способ, доступный в платформе 8.3 — Систему взаимодействия. Если в вашей организации настроен сервер взаимодействия, это самый правильный путь для оперативных уведомлений.
Вы можете программно отправить сообщение от имени "Системного бота" конкретному пользователю. Это сообщение появится как всплывающее окно в интерфейсе 1С, похожее на сообщение в мессенджере. На сервере в процедуре проведения код будет выглядеть примерно так:
Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение(КлючОбсуждения);
НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
НовоеСообщение.Текст = "Ошибка синхронизации заказа " + Объект.Номер;
НовоеСообщение.Записать();
Это решение полностью снимает проблему контекста форм и транзакций, так как сообщение системы взаимодействия живет отдельно от транзакции данных документа.
Выясним важный технический момент: обращение к веб-сервисам внутри ОбработкаПроведения является потенциально опасным. Если внешняя база будет отвечать долго (таймаут), транзакция в вашей текущей базе будет висеть, блокируя таблицы. Рассмотрим правильную архитектуру:
Такой подход обеспечивает высокую отказоустойчивость системы и не заставляет пользователя ждать окончания сетевого запроса при каждом нажатии кнопки "Провести".
Если вам нужно быстрое решение для типовой конфигурации вроде УТ 11.4 без изменения архитектуры обмена:
ДополнительныеСвойства), если работа ведется преимущественно из формы документа.Помните, что использование ВызватьИсключение в данном контексте недопустимо, так как это приведет к отмене проведения заказа в первой базе, что противоречит вашей бизнес-задаче.