Сообщения об ошибках в 1С 8.3: от исключения до подсветки поля формы

· 9 мин

Содержание

Сообщить пользователю об ошибке в 1С 8.3 можно тремя основными способами: ВызватьИсключение — если дальше работать нельзя, объект СообщениеПользователю (или ОбщегоНазначения.СообщитьПользователю в конфигурациях на БСП) — если нужно показать проблему и подсветить поле, и ПоказатьПредупреждение — если пользователь должен прочитать текст и нажать «ОК». Технические подробности при этом уходят не на экран, а в журнал регистрации через ЗаписьЖурналаРегистрации.

Частая ошибка новичков — писать Сообщить("Ошибка!") везде подряд. Код продолжает выполняться, документ записывается с неверными данными, а сообщение теряется среди десятка других. Выбор способа зависит от одного вопроса: должна ли операция остановиться.

Какой способ выбрать: сравнение по ситуации

Прежде чем писать код, определите, что происходит после ошибки. От этого зависит всё остальное.

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

Правило практика: пользователь видит короткий понятный текст, администратор — подробности в журнале. Стек вызовов и номер строки модуля на экране бухгалтеру не помогут.

Что должно произойти после ошибки?

Исключения: когда выполнение надо прервать

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

Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
    ВызватьИсключение НСтр("ru = 'Не указан контрагент. Проведение невозможно.'");
КонецЕсли;

Перехват и повторный вызов

Самый частый рабочий шаблон — перехватить ошибку, записать подробности в журнал и пробросить её дальше. Внутри блока Исключение оператор ВызватьИсключение без параметров повторно вызывает то же исключение.

НачатьТранзакцию();
Попытка
    ВыполнитьЗагрузку(ДанныеФайла);
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ИнфоОбОшибке = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации(НСтр("ru = 'Загрузка данных'"),
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(ИнфоОбОшибке));
    ВызватьИсключение;
КонецПопытки;

Не глушите исключения пустым блоком Исключение … КонецПопытки. Код «работает», но данные молча не загружаются, и найти причину потом почти невозможно.

Что важно знать про исключения

  • 🔁 Внутри транзакции после ошибки транзакцию нужно отменить. Продолжать запись в той же транзакции платформа не даст.
  • 🧾 ИнформацияОбОшибке() возвращает объект с описанием, модулем и номером строки. Для экрана берите КраткоеПредставлениеОшибки, для журнала — ПодробноеПредставлениеОшибки.
  • 🆕 В новых версиях платформы (8.3.21 и выше) у оператора появилась расширенная форма с категорией и кодом ошибки. Если конфигурация должна работать и на более ранних версиях, используйте строковую форму.

Сообщения без остановки: СообщениеПользователю и БСП

Когда пользователь ошибся при заполнении, останавливать всё на первой ошибке неудобно. Лучше собрать все замечания разом и показать их рядом с полями. Для этого служит объект СообщениеПользователю.

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = НСтр("ru = 'Укажите склад отгрузки.'");
Сообщение.Поле = "Склад";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();

Свойства, которые реально используются:

  1. Текст — сам текст сообщения.
  2. Поле — имя реквизита или путь к реквизиту табличной части.
  3. ПутьКДанным — путь к данным формы, например "Объект".
  4. КлючДанных — ссылка на объект, к которому относится сообщение.
  5. Метод УстановитьДанные(Объект) — привязывает сообщение к объекту, когда код выполняется в модуле объекта.

Вариант для конфигураций на БСП

В типовых конфигурациях (Бухгалтерия 3.0, ЗУП 3.1, УТ 11 и других на Библиотеке стандартных подсистем) то же самое пишут одной строкой:

ОбщегоНазначения.СообщитьПользователю(
    НСтр("ru = 'Укажите склад отгрузки.'"), ЭтотОбъект, "Склад", , Отказ);

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

Ошибка в строке табличной части

Чтобы курсор перешёл прямо в нужную ячейку, путь указывают с индексом строки. Индекс начинается с нуля, поэтому из номера строки вычитают единицу.

Для Каждого Строка Из Товары Цикл
    Если Строка.Количество <= 0 Тогда
        Поле = "Товары[" + Формат(Строка.НомерСтроки - 1, "ЧН=0; ЧГ=0") + "].Количество";
        ОбщегоНазначения.СообщитьПользователю(
            СтрШаблон(НСтр("ru = 'Строка %1: количество должно быть больше нуля.'"),
                Строка.НомерСтроки),
            ЭтотОбъект, Поле, , Отказ);
    КонецЕсли;
КонецЦикла;

Формат с ЧГ=0 убирает пробел-разделитель тысяч: без него на строке 1001 путь превратится в Товары[1 000] и привязка не сработает. ЧН=0 нужен, чтобы первая строка дала 0, а не пустую строку.

Глобальный метод Сообщить() по-прежнему работает, но не умеет привязываться к полю. В новом коде используйте СообщениеПользователю или процедуру БСП.

Предупреждения и всплывающие оповещения на клиенте

Иногда сообщение в нижней панели формы легко пропустить, а ошибка серьёзная. Тогда нужно окно, которое пользователь закроет сам.

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

&НаКлиенте
Процедура ПроверитьОстаток(Команда)
    Если Не ОстатокДостаточен() Тогда
        ПоказатьПредупреждение(,
            НСтр("ru = 'Остатка на складе не хватает. Документ не будет проведён.'"),
            , НСтр("ru = 'Недостаточно товара'"));
    КонецЕсли;
КонецПроцедуры

Параметры: описание оповещения (вызывается после закрытия окна), текст, таймаут в секундах, заголовок. Код после вызова выполняется сразу, не дожидаясь нажатия «ОК». Если что-то нужно сделать после закрытия окна, передайте Новый ОписаниеОповещения("ИмяПроцедуры", ЭтотОбъект) и перенесите продолжение туда.

Для ненавязчивого уведомления подходит ПоказатьОповещениеПользователя(Текст, НавигационнаяСсылка, Пояснение, Картинка). Оно всплывает в углу экрана и исчезает само. Хорошо для «Файл выгружен с замечаниями», плохо для настоящих ошибок: его легко не заметить.

Для длительных операций без ошибки, но с ожиданием есть Состояние(Текст) — текст в строке состояния. Это не сообщение об ошибке, но часто снимает вопросы «программа зависла?».

Как сообщения ведут себя в управляемых формах

Управляемая форма живёт на клиенте, а проверки обычно идут на сервере. Отсюда несколько особенностей, на которых спотыкаются даже опытные разработчики.

  • 📨 Сообщения, созданные на сервере через СообщениеПользователю, доставляются на клиент после возврата из серверного вызова. Показывать их отдельно не нужно.
  • 🎯 В модуле формы путь к данным обычно "Объект", а поле — имя реквизита: Сообщение.Поле = "Объект.Склад" или Поле = "Склад" плюс ПутьКДанным = "Объект". Неверный путь — сообщение появится, но поле не подсветится.
  • 🖥️ ПоказатьПредупреждение и ПоказатьОповещениеПользователя на сервере недоступны. Если сервер обнаружил проблему, верните флаг или текст на клиент и покажите окно там.
  • ⏳ В фоновых заданиях окна показать нельзя. Сообщения из фонового задания накапливаются и забираются методом ПолучитьСообщенияПользователю у объекта фонового задания. В БСП это делает подсистема длительных операций автоматически.

Проверка заполнения вместо ручного кода

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

Ошибки при формировании печатных форм и отчётов

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

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

Для Каждого Документ Из МассивОбъектов Цикл
    Если Не ЗначениеЗаполнено(Документ.Организация) Тогда
        ОбщегоНазначения.СообщитьПользователю(
            СтрШаблон(НСтр("ru = 'Документ %1 не напечатан: не заполнена организация.'"),
                Документ),
            Документ);
        Продолжить;
    КонецЕсли;
    // вывод печатной формы документа
КонецЦикла;

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

Отчёты

Для отчёта есть два варианта:

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

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

Журнал регистрации: подробности для администратора

Пользователь видит «Не удалось загрузить файл». Администратору нужно знать, какой файл, на какой строке и почему. Это задача журнала регистрации.

ЗаписьЖурналаРегистрации(
    НСтр("ru = 'Обмен с банком.Загрузка выписки'", ОбщегоНазначения.КодОсновногоЯзыка()),
    УровеньЖурналаРегистрации.Ошибка,
    Метаданные.Документы.СписаниеСБанковскогоСчета,
    ,
    ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));

Параметры: имя события, уровень, объект метаданных, данные (ссылка), комментарий. Есть ещё шестой — режим транзакции.

Советы по журналу:

  • 🏷️ Имя события делайте иерархическим через точку: «Обмен с банком.Загрузка выписки». В журнале по нему удобно фильтровать.
  • 🌐 Имя события пишите на основном языке конфигурации (в БСП — с кодом основного языка), чтобы оно не зависело от языка пользователя, у которого случилась ошибка.
  • 📊 Уровни: Ошибка, Предупреждение, Информация, Примечание. Не пишите всё подряд с уровнем Ошибка — администратор перестанет на него реагировать.

Посмотреть записи можно в пользовательском режиме: в разделе Администрирование → Обслуживание (так он называется в Бухгалтерии 3.0), или в конфигураторе через меню Администрирование → Журнал регистрации.

Тексты ошибок: единый стиль и перевод на другие языки

Плохой текст ошибки — «Ошибка выполнения операции». Хороший отвечает на два вопроса: что не так и что делать.

ПлохоХорошо
Ошибка!Не указан склад. Выберите склад в шапке документа.
Неверные данныеСтрока 3: цена 0. Укажите цену или удалите строку.
Ошибка при записиДокумент не записан: период закрыт до 31.03. Обратитесь к главному бухгалтеру.

НСтр и СтрШаблон

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

Текст = СтрШаблон(
    НСтр("ru = 'Остаток товара %1 на складе %2: %3. Нужно: %4.'; en = 'Stock of %1 in %2: %3. Required: %4.'"),
    Номенклатура, Склад, Остаток, Требуется);

Не склеивайте фразу из кусков через +: при переводе порядок слов меняется, и СтрШаблон с параметрами %1, %2 решает эту проблему. Метод есть в платформе с версии 8.3.6.

Договоритесь в команде о едином формате: начинать с объекта ошибки, заканчивать действием, без восклицательных знаков и слова «Ошибка» в начале — окно и так красное.

Частые вопросы

Почему сообщение появилось, но поле не подсветилось?
Неверно указан путь. Проверьте Поле и ПутьКДанным: в модуле формы данные обычно лежат в Объект, а индекс строки табличной части начинается с нуля.
Можно ли показать окно предупреждения из серверной процедуры?
Нет. На сервере нет интерфейса. Верните текст или признак ошибки на клиент и вызовите ПоказатьПредупреждение в клиентской процедуре.
Чем отличается Отказ = Истина от ВызватьИсключение в ПередЗаписью?
Отказ отменяет запись без прерывания кода и позволяет вывести несколько сообщений. Исключение обрывает выполнение сразу, показывается только его текст.
Куда деваются сообщения из фонового задания?
Они копятся в самом задании. Их получают методом ПолучитьСообщенияПользователю объекта фонового задания и выводят на клиенте.
Почему пользователь видит текст «{ОбщийМодуль…(25)}: …»?
На экран попало подробное представление ошибки. Для пользователя используйте КраткоеПредставлениеОшибки, а подробное пишите в журнал регистрации.