Сообщение об ошибке пользователю в 1С 8.3: от Сообщить() до своей формы
Содержание
Чтобы вывести окно ошибки в 1С, на клиенте вызовите ПоказатьПредупреждение(, "Текст ошибки") — появится модальное по виду окно с кнопкой «ОК». Если нужно не просто показать текст, а прервать операцию и откатить транзакцию, используйте ВызватьИсключение "Текст ошибки"; — платформа сама покажет окно с ошибкой. Для ошибок заполнения, которые надо привязать к полю формы, подходит объект СообщениеПользователю.
Способов вывести сообщение об ошибке в 1С 8.3 шесть, и выбирают их по двум вопросам: где выполняется код (клиент или сервер) и должна ли ошибка остановить выполнение. Всё ниже относится к платформе 8.3 и управляемым формам, а не к конкретной конфигурации: работает одинаково в БП, ЗУП, УТ и в своих разработках.
Какой способ показа ошибки выбрать: сравнение
| Способ | Где работает | Останавливает код | Что видит пользователь |
|---|---|---|---|
Сообщить() | клиент и сервер | нет | строка в панели сообщений внизу формы |
СообщениеПользователю | клиент и сервер | нет | сообщение с переходом к полю |
ПоказатьПредупреждение() | только клиент | нет | окно с текстом и кнопкой «ОК» |
ВызватьИсключение | клиент и сервер | да, с откатом транзакции | стандартное окно ошибки |
ПоказатьОповещениеПользователя() | только клиент | нет | всплывающее уведомление в углу экрана |
ЗаписьЖурналаРегистрации() | клиент и сервер | нет | ничего, запись видит администратор |
| Своя форма | открывается на клиенте | нет | окно, оформленное как вам нужно |
💡 Правило для повседневной разработки: проверка заполнения — СообщениеПользователю, фатальная ошибка в логике — ВызватьИсключение, итог фоновой операции — оповещение, всё, что нужно разбирать потом, — дополнительно в журнал регистрации.
Сообщить() и СообщениеПользователю: вывод ошибки в панель сообщений
Функция Сообщить()
Самый короткий способ вывести текст ошибки:
Сообщить("Не указан контрагент. Документ не записан.");
Сообщение появляется в панели сообщений формы. Вызов работает и на клиенте, и на сервере: серверные сообщения копятся и показываются пользователю, когда управление вернётся на клиент.
Минус — сообщение ни к чему не привязано. Пользователь видит текст, но не понимает, какое поле исправлять. В новых разработках Сообщить() оставляют для быстрой отладки.
Объект СообщениеПользователю
Тот же вывод, но с привязкой к полю формы. Клик по сообщению переводит курсор в нужное поле, а само поле подсвечивается.
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен контрагент";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();
Если сообщение формируется в модуле объекта, привязку делают через данные:
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Дата документа не может быть больше текущей";
Сообщение.Поле = "Дата";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
В конфигурациях на БСП (а это почти все типовые) есть готовая обёртка, которая делает то же одной строкой и сразу выставляет флаг отказа:
ОбщегоНазначения.СообщитьПользователю("Не заполнен контрагент", ЭтотОбъект, "Контрагент", , Отказ);
На клиенте и в общих модулях клиент-сервер используют ОбщегоНазначенияКлиент.СообщитьПользователю или ОбщегоНазначенияКлиентСервер.СообщитьПользователю.
Отказ от записи вместе с сообщением
Само сообщение ничего не останавливает. Чтобы документ не записался, в обработчике нужно выставить параметр Отказ:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если Не ЗначениеЗаполнено(Контрагент) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен контрагент";
Сообщение.Поле = "Контрагент";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Платформа сама добавит общее окно «Не удалось записать…», а список причин окажется в панели сообщений.
Окно предупреждения: ПоказатьПредупреждение() и ПоказатьВопрос()
Когда нужно именно окно поверх формы, а не строка внизу, используют ПоказатьПредупреждение(). Метод работает только на клиенте.
&НаКлиенте
Процедура ПроверитьИВыполнить(Команда)
Если Не ЗначениеЗаполнено(Объект.Склад) Тогда
ПоказатьПредупреждение(, "Выберите склад перед заполнением табличной части.", , "Ошибка заполнения");
Возврат;
КонецЕсли;
ЗаполнитьНаСервере();
КонецПроцедуры
Параметры по порядку: описание оповещения о закрытии, текст, таймаут в секундах, заголовок окна. Окно блокирует интерфейс, но код после вызова не ждёт нажатия «ОК». Поэтому в примере стоит Возврат.
Если после закрытия окна нужно что-то сделать, передайте ОписаниеОповещения:
&НаКлиенте
Процедура ПоказатьОшибкуИЗакрыть()
Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияПредупреждения", ЭтотОбъект);
ПоказатьПредупреждение(Оповещение, "Документ заблокирован другим пользователем.");
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияПредупреждения(ДополнительныеПараметры) Экспорт
Закрыть();
КонецПроцедуры
Когда у ошибки есть варианты действий («Повторить» / «Отмена»), подходит ПоказатьВопрос() с режимом РежимДиалогаВопрос.ПовторитьОтмена или РежимДиалогаВопрос.ДаНет. Ответ приходит в процедуру оповещения как значение КодВозвратаДиалога.
Почему старый Предупреждение() выдаёт ошибку
Синхронные Предупреждение() и Вопрос() — модальные. В свойствах корня конфигурации есть «Режим использования модальности». Если там стоит «Не использовать» (так в новых конфигурациях и во всех типовых), вызов падает с текстом:
Использование модальных окон в данном режиме запрещено!
Не переключайте режим модальности в типовой конфигурации ради одного окна: модальные окна не работают в веб-клиенте на части браузеров и в мобильном клиенте, а правка свойства снимает конфигурацию с полной поддержки. Перепишите вызов на ПоказатьПредупреждение().
ВызватьИсключение: окно ошибки с остановкой выполнения
ВызватьИсключение прерывает выполнение кода. Если исключение никто не перехватил, пользователь видит стандартное окно ошибки с вашим текстом, а открытая транзакция откатывается.
Если Остаток < Количество Тогда
ВызватьИсключение "Недостаточно товара на складе. Остаток: " + Формат(Остаток, "ЧГ=0");
КонецЕсли;
Это единственный способ из списка, который гарантированно не даст коду пойти дальше. Его ставят там, где продолжение приведёт к неверным данным: в проведении, в обработке обмена, в расчёте.
Перехват и повторный выброс
Исключение можно поймать, записать подробности и показать пользователю короткий текст:
Попытка
ВыполнитьРасчет();
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("Расчет.Ошибка", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(Инфо));
ВызватьИсключение "Расчёт не выполнен: " + КраткоеПредставлениеОшибки(Инфо);
КонецПопытки;
Что есть для разбора ошибки:
- 🔹
ОписаниеОшибки()— текст ошибки одной строкой; - 🔹
ИнформацияОбОшибке()— объект со свойствамиОписание,ИмяМодуля,НомерСтроки,ИсходнаяСтрока,Причина; - 🔹
КраткоеПредставлениеОшибки()— текст для пользователя, без технических подробностей; - 🔹
ПодробноеПредставлениеОшибки()— текст со стеком вызовов, для журнала.
В новых релизах платформы эти функции доступны и через менеджер ОбработкаОшибок (например, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Инфо)); там же есть клиентский метод ОбработкаОшибок.ПоказатьИнформациюОбОшибке(Инфо), который открывает стандартное окно ошибки для уже перехваченного исключения.
ВызватьИсключение; без текста внутри блока Исключение пробрасывает ту же ошибку дальше, сохраняя исходную информацию.
Пустой блок Исключение … КонецПопытки — худший вариант. Ошибка исчезает: окна нет, в журнале пусто, данные могут остаться наполовину записанными. Хотя бы пишите её в журнал регистрации.
Всплывающее оповещение вместо модального окна
ПоказатьОповещениеПользователя() выводит небольшое уведомление в правом нижнем углу. Оно не мешает работать и исчезает само. Метод клиентский.
&НаКлиенте
Процедура ПослеВыгрузки(Результат, ДополнительныеПараметры) Экспорт
Если Не Результат.Успешно Тогда
ПоказатьОповещениеПользователя("Выгрузка не выполнена",
ПолучитьНавигационнуюСсылку(Объект.Ссылка),
Результат.ТекстОшибки, , СтатусОповещенияПользователя.Важное);
КонецЕсли;
КонецПроцедуры
Параметры: заголовок, действие при нажатии (навигационная ссылка или ОписаниеОповещения), пояснение, картинка, статус, ключ уникальности. Со статусом Важное оповещение остаётся в центре оповещений, и пользователь найдёт его позже.
Когда оповещение уместно, а когда нет:
- ✅ результат фонового задания или пакетной обработки;
- ✅ неудачная отправка в ЭДО или по почте, если пользователь уже ушёл в другое окно;
- ❌ ошибка, после которой нельзя продолжать: уведомление легко не заметить.
Запись ошибки в журнал регистрации
Журнал регистрации — не способ показать ошибку, а способ её сохранить. Пользователь закрыл окно и забыл текст, а администратор найдёт запись с временем, пользователем и стеком.
ЗаписьЖурналаРегистрации("Обмен.ЗагрузкаКонтрагентов",
УровеньЖурналаРегистрации.Ошибка,
Метаданные.Справочники.Контрагенты,
СсылкаНаКонтрагента,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Имя события лучше строить иерархически, через точку: по нему потом фильтруют журнал.
Где смотреть записи:
- В пользовательском режиме типовых конфигураций — раздел
Администрирование → Обслуживание, группа отчётов администратора, ссылка «Журнал регистрации». - В любой базе —
Функции для технического специалиста → Стандартные → Журнал регистрации(команда «Функции для технического специалиста» включается в параметрах программы). - В конфигураторе —
Администрирование → Журнал регистрации.
В журнале поставьте отбор по уровню «Ошибка» и по имени события — так вы отсечёте тысячи служебных записей.
Своя форма для вывода ошибки
Стандартного окна мало, если ошибок несколько, нужен длинный текст с прокруткой или кнопка «Скопировать для поддержки». Тогда делают общую форму.
Пошагово:
- В конфигураторе создайте общую форму, например
ФормаОшибки. - Добавьте реквизит
ТекстОшибки(строка неограниченной длины) и выведите его полем многострочного текста только для просмотра. - В обработчике
ПриСозданииНаСерверезаполните реквизит из параметра:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ТекстОшибки = Параметры.ТекстОшибки;
Если Параметры.Свойство("Заголовок") Тогда
Заголовок = Параметры.Заголовок;
КонецЕсли;
КонецПроцедуры
- Откройте форму из клиентского кода:
&НаКлиенте
Процедура ПоказатьФормуОшибки(Текст)
ПараметрыФормы = Новый Структура("ТекстОшибки, Заголовок", Текст, "Ошибки при загрузке");
ОткрытьФорму("ОбщаяФорма.ФормаОшибки", ПараметрыФормы, ЭтотОбъект, , , , ,
РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
Режим БлокироватьОкноВладельца даёт поведение модального окна без нарушения режима модальности. Для типовой конфигурации форму добавляют в расширение, чтобы не снимать основную конфигурацию с поддержки.
Вывод ошибок в разных режимах запуска
Один и тот же код ведёт себя по-разному в зависимости от того, кто и как его вызвал.
| Контекст | Что увидит пользователь | Что делать |
|---|---|---|
| Тонкий и веб-клиент, управляемые формы | всё, что описано выше | асинхронные методы Показать… |
| Толстый клиент, обычное приложение | работают и модальные Предупреждение(), Вопрос() | в новом коде всё равно лучше асинхронные |
| Серверный вызов из формы | сообщения доходят после возврата на клиент | окна открывайте на клиенте по результату вызова |
| Фоновое задание | ничего, пока форма сама не заберёт сообщения | ФоновоеЗадание.ПолучитьСообщенияПользователю() |
| Регламентное задание | никого нет | только журнал регистрации |
| HTTP-сервис, веб-сервис, COM-соединение | окон нет | текст ошибки в ответе + журнал |
Частая ловушка — вызов клиентского метода в серверной процедуре. Конфигуратор при синтаксическом контроле подскажет, что ПоказатьПредупреждение на сервере недоступен. Правильная схема: сервер возвращает текст ошибки или структуру с флагом, клиент решает, как его показать.
&НаКлиенте
Процедура Загрузить(Команда)
ТекстОшибки = ЗагрузитьНаСервере();
Если ЗначениеЗаполнено(ТекстОшибки) Тогда
ПоказатьПредупреждение(, ТекстОшибки, , "Загрузка не выполнена");
КонецЕсли;
КонецПроцедуры
В фоновом задании СообщениеПользователю не пропадает: сообщения копятся у задания. Форма, которая ждёт завершения, забирает их методом ПолучитьСообщенияПользователю(Истина) у объекта задания и выводит сама. В БСП это уже сделано в механизме длительных операций.
Ошибки при выводе сообщений, которые встречаются в коде
Разработчики чаще всего спотыкаются на этом:
- ⚠️ Код после
ПоказатьПредупреждение()выполняется сразу. Ждут, что он остановится, как старыйПредупреждение(). НуженВозвратили продолжение в процедуре оповещения. - ⚠️ Сообщение есть, а отказа нет.
СообщениеПользователювыведено,Отказне выставлен — документ записывается с ошибкой. - ⚠️ Неверный путь в
Поле. В модуле формы пишут"Объект.Контрагент", а в модуле объекта — просто"Контрагент"вместе сУстановитьДанные. Перепутали — сообщение выводится, но к полю не переходит. - ⚠️ Склейка числа со строкой без формата.
"Остаток: " + Остатокдаст «1 250» с разделителем групп разрядов, а в коде, номерах и ссылках это лишний пробел. ИспользуйтеФормат(Остаток, "ЧГ=0")илиСтрШаблон(). - ⚠️ Технический текст пользователю. Бухгалтеру
ПодробноеПредставлениеОшибкисо стеком не поможет. Ему — короткий текст, стек — в журнал. - ⚠️ Сообщения в цикле. Тысяча строк в панели сообщений равна ни одной. Соберите ошибки в массив и выведите сводку или откройте свою форму со списком.
Как вывести ошибку с переносом строки?
Символы.ПС между частями текста: "Строка 1" + Символы.ПС + "Строка 2". Работает во всех способах показа.Можно ли закрыть окно предупреждения автоматически?
ПоказатьПредупреждение() — таймаут в секундах. По его истечении окно закроется само, а процедура оповещения всё равно вызовется.Как очистить панель сообщений перед новой проверкой?
ОчиститьСообщения() на клиенте. Иначе пользователь увидит вперемешку старые и новые ошибки.Откатывается ли транзакция при ВызватьИсключение внутри Попытки?
ОтменитьТранзакцию(), а не пытаться продолжить запись.Как показать ошибку на английском, если у пользователя другой язык?
НСтр("ru = 'Не заполнен контрагент'; en = 'Counterparty is not filled'"). Платформа выберет строку по языку пользователя.