Как вывести сообщение с параметрами через СообщениеПользователю и обеспечить его работу при групповой обработке?

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

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

Формирование текста сообщения с параметрами

Объект СообщениеПользователю не имеет встроенного конструктора со списком параметров, поэтому итоговый текст формируется перед записью в свойство Текст. Рассмотрим два основных способа формирования строки с параметрами.

Способ 1. Простая конкатенация строк

Если требуется объединить несколько значений, приведем нестроковые переменные к строковому типу с помощью функции Строка():


Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = Строка(Стр.Организация) + " " + Строка(Стр.ОрганизацияП) + " Текст сообщения";
Сообщение.Сообщить();

Способ 2. Использование функции СтрШаблон

Для повышения читаемости кода и удобства локализации рекомендуется применять функцию СтрШаблон(). Разберем пример:


ШаблонТекста = НСтр("ru = 'Организация: %1, Получатель: %2. Обнаружено расхождение сумм!'");
ТекстСообщения = СтрШаблон(ШаблонТекста, Стр.Организация, Стр.ОрганизацияП);

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ТекстСообщения;
Сообщение.Сообщить();

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


ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
    ТекстСообщения,
    ЭтотОбъект.Ссылка,
    "Количество",
    "Товары"
);

Привязка сообщения к данным формы и объекту

Главное преимущество СообщениеПользователю перед Сообщить() — возможность связать предупреждение с конкретным полем на форме или со строкой табличной части. Посмотрим, как это настраивается:

  1. Указание ключа данных: свойство КлючДанных указывает платформе, к какому объекту относится ошибка. Если передать ссылку на документ (ЭтотОбъект.Ссылка), платформа сможет открыть форму объекта прямо из панели сообщений при клике на ошибку.
  2. Указание поля и строки: свойство Поле позволяет подсветить конкретный элемент формы или ячейку табличной части (например, "Товары[0].Количество").
  3. Метод УстановитьДанные: автоматически заполняет контекст сообщения на основе переданного объекта данных.

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указано количество в строке 1!";
Сообщение.Поле = "Товары[0].Количество";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();

Особенности вывода сообщений при групповой обработке

Проанализируем ситуацию: в интерактивном режиме при проведении открытого документа сообщение отображается корректно, а при запуске через групповое перепроведение или обработку сообщений нет. Выделим причины такого поведения:

  1. Код находится в модуле формы: при групповой обработке форма объекта вообще не открывается и не создается. Проведение документов выполняется исключительно через методы модулей объектов и менеджеров. Любые проверки и вызовы Сообщить(), размещенные в обработчиках формы (например, ПередЗаписьюНаСервере или ОбработкаПроверкиЗаполненияНаСервере формы), при пакетной обработке просто не выполняются. Весь контроль данных и проведение должны находиться в модуле объекта (в обработчиках ПередЗаписью, ОбработкаПроверкиЗаполнения или ОбработкаПроведения).
  2. Серверный контекст и фоновые задания: если групповая обработка выполняется в фоновом задании или на стороне сервера, окно сообщений не может открыться сразу. Все сформированные сообщения накапливаются в системном буфере. Чтобы получить и отобразить их в коде обработки, вызывают метод:
    
    МассивСообщений = ПолучитьСообщенияПользователю(Истина);
    Для Каждого ТекСообщение Из МассивСообщений Цикл
        // Обработка или вывод сообщения в лог
    КонецЦикла;
    
    Параметр Истина очищает стек сообщений после их извлечения.
  3. Логирование для пакетных операций: для фоновых процессов и длительных регламентных заданий надежнее фиксировать ошибки в журнале регистрации с помощью ЗаписьЖурналаРегистрации(), так как пользователь может не дождаться окончания работы интерфейса.

Почему табличные части оказываются пустыми в модуле объекта

Частая проблема при переносе кода из формы в модуль объекта — пропуск цикла обхода табличной части или получение пустой таблицы. Разберем основные причины:

  1. Разрыв между реквизитами формы и базы данных: если табличная часть документа рассчитывалась динамически на клиенте или в процедурах формы при открытии и не была физически записана в базу, в модуле объекта коллекция строк окажется пустой. При групповой обработке объект считывается непосредственно из базы данных.
  2. Ошибки при запросах к данным в транзакции: если в модуле объекта выполняется запрос к табличной части документа (например, Документ.РеализацияТоваровУслуг.Товары), запрос обращается к уже сохраненным данным в СУБД. Если объект еще не записан или изменяется в памяти, запрос может вернуть пустоту. Для проверки актуальных данных объекта в памяти в запрос передают выгруженную табличную часть:
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    ВремТЗ.Организация КАК Организация,
        |    СУММА(ВремТЗ.Количество) КАК Количество
        |ПОМЕСТИТЬ ВТ_Товары
        |ИЗ
        |    &ТабличнаяЧасть КАК ВремТЗ
        |СГРУППИРОВАТЬ ПО
        |    ВремТЗ.Организация";
    
    Запрос.УстановитьПараметр("ТабличнаяЧасть", ЭтотОбъект.Товары.Выгрузить());
    РезультатЗапроса = Запрос.Выполнить();
    
  3. Некорректная обработка таблиц значений в цикле: частой ошибкой при обработке строк является свертка таблицы значений внутри итератора:
    
    // ОШИБКА: метод Свернуть нельзя вызывать внутри цикла добавления строк!
    Для Каждого СтрокаТЧ Из ТЧРез Цикл
        ЗаполнитьЗначенияСвойств(ТЗВременная.Добавить(), СтрокаТЧ);
        ТЗВременная.Свернуть("Организация", "Количество"); 
    КонецЦикла;
    
    Постоянная переиндексация и сжатие таблицы при каждой итерации вызывают катастрофическое падение производительности. Правильный подход — сначала перенести все строки, а метод Свернуть() вызвать один раз после завершения цикла, либо агрегировать данные сразу на уровне запроса через СГРУППИРОВАТЬ ПО.
← На главную