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