Как сообщить пользователю информацию при нажатии кнопки Провести и закрыть

Программист 1С v8.3 (Управляемые формы)
← На главную

При разработке в среде 1С:Предприятие 8.3 программисты часто сталкиваются со специфической задачей: необходимо вывести пользователю важное информационное сообщение именно в момент проведения документа из формы. Основная сложность заключается в том, что при использовании стандартной команды «Провести и закрыть» форма документа мгновенно закрывается. Если использовать обычный метод Сообщить() или объект СообщениеПользователю, привязанный к текущей форме, сообщение может исчезнуть вместе с окном, и пользователь его просто не заметит.

В этой статье мы подробно разберем, как правильно реализовать проверку данных (например, сравнение значения в документе со значением в регистре) и гарантированно донести информацию до пользователя, даже если форма документа была закрыта сразу после успешного проведения.

Почему не стоит использовать Сообщить() в модуле объекта

Рассмотрим сначала архитектурный аспект. Проведение документа может инициироваться не только из формы, но и программно (например, при групповом перепроведении документов или выполнении регламентного задания). Если мы напишем логику вывода сообщений в обработке проведения в модуле объекта, то при групповой обработке система будет пытаться вывести тысячи окон или логов, что крайне неэффективно и может привести к ошибкам в серверных контекстах.

Поэтому нашу задачу мы будем решать исключительно в модуле формы, так как сообщение носит чисто информационный характер для интерактивного пользователя.

Способ 1: Использование метода ПоказатьОповещениеПользователя

Проанализируем наиболее современный и рекомендуемый подход. Метод ПоказатьОповещениеПользователя создает всплывающее уведомление в нижнем углу экрана. Это уведомление «живет» независимо от формы документа — даже если форма закрылась, оповещение останется видимым в течение нескольких секунд или пока пользователь его не закроет.

Для реализации этого метода нам понадобится обработчик события ПослеЗаписиНаСервере. Именно здесь мы можем точно определить, было ли это проведение, и сравнить необходимые данные.

Разберем пример кода в модуле управляемой формы:


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

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    
    // Проверяем наличие нашего текста сообщения в структуре параметров
    Если ПараметрыЗаписи.Свойство("ТекстИнформационногоСообщения") Тогда
        
        Текст = ПараметрыЗаписи.ТекстИнформационногоСообщения;
        
        // Выводим всплывающее уведомление
        ПоказатьОповещениеПользователя(
            "Результат проведения", 
            ПолучитьНавигационнуюСсылку(Объект.Ссылка), 
            Текст, 
            БиблиотекаКартинок.ИнформационныйСборка
        );
        
    КонецЕсли;
    
КонецПроцедуры

В данном сценарии мы сначала на сервере провели необходимые расчеты, а затем на клиенте вызвали ПоказатьОповещениеПользователя. Этот метод идеален, так как он не блокирует работу интерфейса и гарантирует доставку сообщения.

Способ 2: Использование механизма оповещений (Оповестить)

Если мы хотим, чтобы сообщение отобразилось не просто как всплывающее окно, а, например, в форме списка, из которой был открыт документ, мы можем воспользоваться механизмом Оповестить. Это особенно полезно, когда пользователь нажимает «Провести и закрыть» и возвращается в список документов.

Рассмотрим, как это работает по шагам:

  1. В форме документа в процедуре ПослеЗаписи на клиенте вызывается метод Оповестить().
  2. В форме списка документов создается обработчик события ОбработкаОповещения.
  3. Форма списка «ловит» событие и выводит стандартное сообщение пользователю.

Пример кода для формы документа:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        // Создаем структуру с данными для передачи
        ДанныеСообщения = Новый Структура("Текст, Ссылка", "Документ проведен с превышением показателей", Объект.Ссылка);
        Оповестить("ПроведениеСУсловием", ДанныеСообщения, Объект.Ссылка);
    КонецЕсли;
КонецПроцедуры

Пример кода для формы списка (владельца):


&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ПроведениеСУсловием" Тогда
        // Теперь сообщение будет выведено в контексте формы списка
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Параметр.Текст);
    КонецЕсли;
КонецПроцедуры

Способ 3: Назначение ИдентификатораНазначения для СообщенияПользователю

Выясним причину, по которой обычные сообщения исчезают. По умолчанию объект СообщениеПользователю привязывается к текущей активной форме. Если форма закрывается, платформа считает, что сообщение больше не актуально. Однако у объекта СообщениеПользователю есть свойство ИдентификаторНазначения.

Если мы установим в это свойство уникальный идентификатор формы списка (владельца), то сообщение будет выведено в окне списка, даже когда форма документа уже закрыта. Рассмотрим пример реализации:


&НаСервере
Процедура ПроверитьИВывестиСообщениеНаСервере()
    
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = "Важная информация о проведенном документе";
    
    // Если у формы есть владелец, и это форма
    Если ЭтаФорма.ВладелецФормы <> Неопределено Тогда
        // Назначаем вывод сообщения в форму-владелец
        Сообщение.ИдентификаторНазначения = ЭтаФорма.ВладелецФормы.УникальныйИдентификатор;
    КонецЕсли;
    
    Сообщение.Сообщить();
    
КонецПроцедуры

Важный нюанс: Этот способ требует аккуратности, так как ВладелецФормы не всегда может быть доступен или иметь УникальныйИдентификатор (например, если документ открыт по прямой ссылке, а не из списка).

Работа с очередью сообщений (GetUserMessages)

Проанализируем ситуацию, когда вам нужно программно собрать все накопленные сообщения и передать их куда-то еще. В 1С существует метод ПолучитьСообщенияПользователю(). Он позволяет извлечь массив объектов СообщениеПользователю, которые были сформированы, но еще не показаны пользователю.

Это бывает полезно, если вы выполняете длительную операцию на сервере и хотите в конце собрать все сообщения, возникшие в процессе, чтобы вывести их одним списком или записать в журнал. Однако помните, что после вызова этого метода с параметром УдалятьПолученные = Истина, сообщения удаляются из очереди и не будут автоматически показаны платформой.

Резюме и рекомендации

Подведем итог нашего разбора. Выбор метода зависит от критичности информации:

Используя предложенные методы, вы обеспечите отличный пользовательский опыт и исключите потерю важных данных при работе с документами в режиме «Провести и закрыть».

← На главную