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