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