Как правильно вывести сообщение пользователю при проведении и закрытии документа в 1С:Предприятии 8.3 УФ?

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

При работе с 1С:Предприятием 8.3 в режиме управляемого приложения, многие разработчики сталкиваются с распространенной проблемой: сообщения, выводимые пользователю в процессе проведения документа, исчезают при использовании команды "Провести и закрыть". Пользователь ожидает увидеть подтверждение операции или важное предупреждение, но форма закрывается слишком быстро, унося с собой все сгенерированные уведомления. Давайте вместе разберем, почему так происходит и как мы можем эффективно решить эту задачу, используя VS Code + 1С без лишней рутины: плагин для конфигурации, расширений, EPF/ERF и AI-скиллов — для этого подойдёт разработка 1С в VS Code с ИИ.

Причина проблемы: исчезающие сообщения

Разберем подробнее, почему возникают такие сложности. Когда мы используем команду "Провести и закрыть" в управляемой форме 1С, документ сначала успешно записывается и проводится на сервере. Все серверные события, такие как ПриЗаписиНаСервере или ОбработкаПроведения, выполняются. Если в этих процедурах вызывается метод СообщениеПользователю, система пытается отобразить его в контексте текущей формы документа. Однако, сразу после успешного проведения и записи, форма документа закрывается. В результате, сообщение, которое должно было появиться, исчезает вместе с закрывшейся формой, не давая пользователю возможности его прочитать.

Эта ситуация особенно актуальна для пользователей, которые привыкли видеть подтверждение успешной операции или предупреждение о каких-либо особенностях проведения. Для нас, как разработчиков, ключевая задача — обеспечить видимость этих сообщений независимо от жизненного цикла формы документа (в чем может помочь Skill для ИИ, который научил его отлаживать 1С: смотреть переменные, идти по шагам и глубже разбирать код). Нам необходимо найти способы выводить сообщения таким образом, чтобы они не были привязаны к конкретной форме и оставались на экране после ее закрытия.

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

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

Рассмотрим основные преимущества этого подхода:

  1. Независимость от формы: Уведомление остается видимым даже после закрытия формы документа, поскольку оно привязано к главному окну приложения или рабочему столу пользователя.
  2. Не прерывает работу: Так как это немодальное окно, оно не блокирует дальнейшую работу пользователя в других окнах системы, что улучшает пользовательский опыт.
  3. Интерактивность: Мы можем добавить в такое уведомление гиперссылку, по которой пользователь сможет перейти к объекту или выполнить определенную команду, что значительно повышает удобство использования и информативность.
  4. Клиентский метод: Вызывается на клиенте, что предоставляет большую гибкость в управлении отображением и позволяет нам контролировать момент вывода сообщения уже после серверных операций.

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

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


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

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

Решение 2: Активация главного окна приложения (полезно при отладке внешних печатных форм и обработок)

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

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

Рассмотрим шаги для его реализации. Нам потребуется изменить как клиентский, так и серверный код.

В модуле формы документа, в процедуре ПередЗаписью (которая выполняется на клиенте до отправки данных на сервер), мы можем активизировать основное окно приложения:


// В модуле формы документа
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    // Получаем коллекцию всех открытых окон приложения 1С.
    Окна = ПолучитьОкна();
    // Перебираем окна, чтобы найти основное окно приложения.
    Для каждого Окно Из Окна Цикл
        // Метод Основное() возвращает Истина, если это главное окно.
        Если Окно.Основное() Тогда
            // Активизируем основное окно, переключая на него фокус.
            Окно.Активизировать();
            // После активации основного окна, прерываем цикл, так как наша цель достигнута.
            Прервать;
        КонецЕсли;
    КонецЦикла;
    // Важно: здесь же можно передать какой-либо флаг на сервер (например, через дополнительный параметр
    // или реквизит формы), чтобы сервер "знал", что нужно вывести сообщение.
    // Это гарантирует, что сообщение будет выведено только тогда, когда фокус уже переключен.
КонецПроцедуры

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

В модуле объекта документа, например, в процедуре ОбработкаПроведения, мы создаем и выводим СообщениеПользователю:


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

Таким образом, сообщение будет отображено в панели сообщений главного окна приложения и будет доступно пользователю даже после того, как форма документа закроется. Этот метод более применим, если вам критически важно, чтобы сообщение отобразилось именно в стандартной панели сообщений 1С.

Решение 3: Передача текста сообщения с сервера на клиент

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

Давайте разберем схему реализации этого подхода по шагам:

  1. Формирование сообщения на сервере: В серверной процедуре (например, ПриЗаписиНаСервере, ОбработкаПроведения или отдельной экспортной серверной функции формы) выполняется вся необходимая логика и проверки для формирования текста сообщения. Вместо непосредственного вызова СообщениеПользователю, мы сохраняем этот текст во временную переменную или реквизит формы, который не сохраняется в базе данных. Этот реквизит будет доступен на клиенте после завершения серверного вызова.
  2. Передача на клиент: После выполнения серверной логики и формирования текста сообщения, это значение возвращается на клиент. Если мы используем серверную функцию формы, она просто возвращает строку или структуру с данными. Если это реквизит формы, то после серверного вызова его значение будет доступно на клиенте автоматически.
  3. Отображение на клиенте: В клиентской процедуре формы, например, ПослеЗаписиНаСервере (если мы передаем текст через реквизит формы) или в обработчике команды, которая вызвала запись (если мы вызывали серверную функцию), мы анализируем полученное значение. Если текст сообщения не пустой (т.е., есть что показать), мы выводим его пользователю. Для вывода мы можем использовать ПоказатьОповещениеПользователя, Предупреждение, или даже Сообщить, если форма еще открыта. Наиболее предпочтительным является ПоказатьОповещениеПользователя из-за его независимости от формы.

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

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

В модуле формы документа создадим экспортную серверную функцию, которая будет формировать сообщение:


// В модуле формы документа
&НаСервере
Функция СформироватьСообщениеОПроведенииНаСервере()
    ТекстСообщения = "";
    // Здесь размещается сложная логика, которая требует доступа к серверным данным,
    // объекту документа или другим серверным функциям.
    // Например, мы можем проверить состояние объекта после проведения.
    
    // Получаем текущий объект документа формы.
    ОбъектДокумента = РеквизитФормыВЗначение("Объект");
    
    Если ОбъектДокумента.Проведен Тогда
        Если ОбъектДокумента.СуммаДокумента < 100 Тогда
            ТекстСообщения = "Документ проведен с небольшой суммой (" + Формат(ОбъектДокумента.СуммаДокумента, "ЧЦ=10; ЧДЦ=2") + "). Рекомендуется проверить детали.";
        Иначе
            ТекстСообщения = "Документ №" + ОбъектДокумента.Номер + " от " + Формат(ОбъектДокумента.Дата, "ДФ=dd.MM.yyyy") + " успешно проведен!";
        КонецЕсли;
    Иначе
        ТекстСообщения = "Документ не был проведен. Возможно, возникли ошибки.";
    КонецЕсли;
    
    // Возвращаем сформированный текст сообщения на клиент.
    Возврат ТекстСообщения;
КонецФункции

Затем, на клиенте, в процедуре ПослеЗаписи или в обработчике команды, мы вызываем эту серверную функцию и выводим сообщение:


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

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

Решение 4: Использование Библиотеки стандартных подсистем (БСП)

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

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

Чтобы гарантировать показ сообщения после закрытия формы, всегда инициируйте его вывод из клиентского кода. Это означает, что если в БСП есть функция, которая выводит сообщения, мы должны вызывать ее из клиентской процедуры формы, передавая ей необходимую информацию, полученную с сервера. Функции БСП призваны упростить разработку, но не отменяют базовых принципов взаимодействия клиента и сервера в 1С.

Например, если у вас есть серверный код, который определяет, что нужно сообщить пользователю, он может вернуть эту информацию на клиент, а уже на клиенте вы вызываете соответствующую функцию БСП для отображения:


// В модуле объекта или общем модуле на сервере
// Эта функция выполняет логику проведения и формирует сообщение.
Функция ПолучитьРезультатПроведенияССообщением(ДокументСсылка)
    // ... логика проведения документа ...
    
    // Пример формирования текста сообщения на сервере.
    ТекстСообщения = "Документ " + ДокументСсылка + " обработан и готов.";
    
    // Можно вернуть не только текст, но и структуру, содержащую тип сообщения
    // (информация, предупреждение, ошибка), флаги и т.д., для более гибкого отображения на клиенте.
    Возврат ТекстСообщения;
КонецФункции

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

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

Заключение и рекомендации

Мы подробно рассмотрели различные подходы к выводу сообщений пользователю при проведении и закрытии документов в 1С:Предприятии 8.3 Управляемые формы. Выяснили, что проблема исчезающих сообщений связана с их привязкой к закрывающейся форме документа, и для ее решения необходимо переносить логику отображения сообщений на клиентскую сторону.

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

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

Запомните главное правило: если сообщение должно быть видно после закрытия формы, его отображение должно быть инициировано на клиенте. Это позволит нам создавать более удобные, информативные и интуитивно понятные интерфейсы для пользователей 1С, значительно улучшая их взаимодействие с системой.

← На главную