Сообщения об ошибках в 1С 8.3: от исключения до подсветки поля формы
Содержание
Сообщить пользователю об ошибке в 1С 8.3 можно тремя основными способами: ВызватьИсключение — если дальше работать нельзя, объект СообщениеПользователю (или ОбщегоНазначения.СообщитьПользователю в конфигурациях на БСП) — если нужно показать проблему и подсветить поле, и ПоказатьПредупреждение — если пользователь должен прочитать текст и нажать «ОК». Технические подробности при этом уходят не на экран, а в журнал регистрации через ЗаписьЖурналаРегистрации.
Частая ошибка новичков — писать Сообщить("Ошибка!") везде подряд. Код продолжает выполняться, документ записывается с неверными данными, а сообщение теряется среди десятка других. Выбор способа зависит от одного вопроса: должна ли операция остановиться.
Какой способ выбрать: сравнение по ситуации
Прежде чем писать код, определите, что происходит после ошибки. От этого зависит всё остальное.
| Способ | Прерывает выполнение | Где работает | Когда применять |
|---|---|---|---|
ВызватьИсключение | Да | Клиент и сервер | Продолжать нельзя: нет данных, нарушена целостность |
СообщениеПользователю | Нет | Клиент и сервер | Ошибка заполнения, нужно подсветить поле |
ОбщегоНазначения.СообщитьПользователю | Нет (но умеет ставить Отказ) | Клиент и сервер | То же, в конфигурациях на БСП |
ПоказатьПредупреждение | Нет, окно асинхронное | Только клиент | Важное уведомление, которое нельзя пропустить |
ПоказатьОповещениеПользователя | Нет | Только клиент | Ненавязчивое всплывающее уведомление |
ЗаписьЖурналаРегистрации | Нет | Сервер и клиент | Для администратора, не для пользователя |
Правило практика: пользователь видит короткий понятный текст, администратор — подробности в журнале. Стек вызовов и номер строки модуля на экране бухгалтеру не помогут.
ВызватьИсключение с понятным текстом. Если это внутри транзакции — сначала откат, затем повторный вызов исключения.ОбщегоНазначения.СообщитьПользователю с параметром Отказ в обработчике проверки заполнения. Сообщения копятся, запись отменяется один раз.СообщениеПользователю без прерывания или ПоказатьОповещениеПользователя на клиенте.ПоказатьПредупреждение с обработчиком оповещения.Исключения: когда выполнение надо прервать
ВызватьИсключение останавливает текущий код и передаёт управление ближайшему блоку Исключение. Если такого блока нет, платформа показывает пользователю окно с текстом ошибки, а операция (запись, проведение, обработка команды) отменяется.
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
ВызватьИсключение НСтр("ru = 'Не указан контрагент. Проведение невозможно.'");
КонецЕсли;
Перехват и повторный вызов
Самый частый рабочий шаблон — перехватить ошибку, записать подробности в журнал и пробросить её дальше. Внутри блока Исключение оператор ВызватьИсключение без параметров повторно вызывает то же исключение.
НачатьТранзакцию();
Попытка
ВыполнитьЗагрузку(ДанныеФайла);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ИнфоОбОшибке = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(НСтр("ru = 'Загрузка данных'"),
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнфоОбОшибке));
ВызватьИсключение;
КонецПопытки;
Не глушите исключения пустым блоком Исключение … КонецПопытки. Код «работает», но данные молча не загружаются, и найти причину потом почти невозможно.
Что важно знать про исключения
- 🔁 Внутри транзакции после ошибки транзакцию нужно отменить. Продолжать запись в той же транзакции платформа не даст.
- 🧾
ИнформацияОбОшибке()возвращает объект с описанием, модулем и номером строки. Для экрана беритеКраткоеПредставлениеОшибки, для журнала —ПодробноеПредставлениеОшибки. - 🆕 В новых версиях платформы (8.3.21 и выше) у оператора появилась расширенная форма с категорией и кодом ошибки. Если конфигурация должна работать и на более ранних версиях, используйте строковую форму.
Сообщения без остановки: СообщениеПользователю и БСП
Когда пользователь ошибся при заполнении, останавливать всё на первой ошибке неудобно. Лучше собрать все замечания разом и показать их рядом с полями. Для этого служит объект СообщениеПользователю.
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = НСтр("ru = 'Укажите склад отгрузки.'");
Сообщение.Поле = "Склад";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Свойства, которые реально используются:
Текст— сам текст сообщения.Поле— имя реквизита или путь к реквизиту табличной части.ПутьКДанным— путь к данным формы, например"Объект".КлючДанных— ссылка на объект, к которому относится сообщение.- Метод
УстановитьДанные(Объект)— привязывает сообщение к объекту, когда код выполняется в модуле объекта.
Вариант для конфигураций на БСП
В типовых конфигурациях (Бухгалтерия 3.0, ЗУП 3.1, УТ 11 и других на Библиотеке стандартных подсистем) то же самое пишут одной строкой:
ОбщегоНазначения.СообщитьПользователю(
НСтр("ru = 'Укажите склад отгрузки.'"), ЭтотОбъект, "Склад", , Отказ);
Параметры по порядку: текст, ключ данных, поле, путь к данным, Отказ. Последний параметр процедура сама установит в Истина. Это удобно в ОбработкаПроверкиЗаполнения: каждая проверка добавляет сообщение и взводит отказ, а запись отменяется один раз в конце.
Ошибка в строке табличной части
Чтобы курсор перешёл прямо в нужную ячейку, путь указывают с индексом строки. Индекс начинается с нуля, поэтому из номера строки вычитают единицу.
Для Каждого Строка Из Товары Цикл
Если Строка.Количество <= 0 Тогда
Поле = "Товары[" + Формат(Строка.НомерСтроки - 1, "ЧН=0; ЧГ=0") + "].Количество";
ОбщегоНазначения.СообщитьПользователю(
СтрШаблон(НСтр("ru = 'Строка %1: количество должно быть больше нуля.'"),
Строка.НомерСтроки),
ЭтотОбъект, Поле, , Отказ);
КонецЕсли;
КонецЦикла;
Формат с ЧГ=0 убирает пробел-разделитель тысяч: без него на строке 1001 путь превратится в Товары[1 000] и привязка не сработает. ЧН=0 нужен, чтобы первая строка дала 0, а не пустую строку.
Глобальный метод Сообщить() по-прежнему работает, но не умеет привязываться к полю. В новом коде используйте СообщениеПользователю или процедуру БСП.
Предупреждения и всплывающие оповещения на клиенте
Иногда сообщение в нижней панели формы легко пропустить, а ошибка серьёзная. Тогда нужно окно, которое пользователь закроет сам.
В режиме без модальности (а он включён в современных типовых конфигурациях) модальный Предупреждение() не используют. Вместо него — асинхронный ПоказатьПредупреждение:
&НаКлиенте
Процедура ПроверитьОстаток(Команда)
Если Не ОстатокДостаточен() Тогда
ПоказатьПредупреждение(,
НСтр("ru = 'Остатка на складе не хватает. Документ не будет проведён.'"),
, НСтр("ru = 'Недостаточно товара'"));
КонецЕсли;
КонецПроцедуры
Параметры: описание оповещения (вызывается после закрытия окна), текст, таймаут в секундах, заголовок. Код после вызова выполняется сразу, не дожидаясь нажатия «ОК». Если что-то нужно сделать после закрытия окна, передайте Новый ОписаниеОповещения("ИмяПроцедуры", ЭтотОбъект) и перенесите продолжение туда.
Для ненавязчивого уведомления подходит ПоказатьОповещениеПользователя(Текст, НавигационнаяСсылка, Пояснение, Картинка). Оно всплывает в углу экрана и исчезает само. Хорошо для «Файл выгружен с замечаниями», плохо для настоящих ошибок: его легко не заметить.
Для длительных операций без ошибки, но с ожиданием есть Состояние(Текст) — текст в строке состояния. Это не сообщение об ошибке, но часто снимает вопросы «программа зависла?».
Как сообщения ведут себя в управляемых формах
Управляемая форма живёт на клиенте, а проверки обычно идут на сервере. Отсюда несколько особенностей, на которых спотыкаются даже опытные разработчики.
- 📨 Сообщения, созданные на сервере через
СообщениеПользователю, доставляются на клиент после возврата из серверного вызова. Показывать их отдельно не нужно. - 🎯 В модуле формы путь к данным обычно
"Объект", а поле — имя реквизита:Сообщение.Поле = "Объект.Склад"илиПоле = "Склад"плюсПутьКДанным = "Объект". Неверный путь — сообщение появится, но поле не подсветится. - 🖥️
ПоказатьПредупреждениеиПоказатьОповещениеПользователяна сервере недоступны. Если сервер обнаружил проблему, верните флаг или текст на клиент и покажите окно там. - ⏳ В фоновых заданиях окна показать нельзя. Сообщения из фонового задания накапливаются и забираются методом
ПолучитьСообщенияПользователюу объекта фонового задания. В БСП это делает подсистема длительных операций автоматически.
Проверка заполнения вместо ручного кода
Для простых обязательных реквизитов код писать не нужно. В свойствах реквизита в конфигураторе установите «Проверка заполнения: Выдавать ошибку». Платформа сама выведет стандартное сообщение и подсветит поле при записи. Свой код в ОбработкаПроверкиЗаполнения нужен для условных проверок: «склад обязателен, только если вид операции — отгрузка».
Ошибки при формировании печатных форм и отчётов
Печать и отчёты — особый случай. Пользователь нажимает «Печать» для десяти документов, и в одном из них не хватает данных. Останавливать печать всех десяти из-за одного неправильно.
Рабочий подход в конфигурациях на БСП: в процедуре формирования печатной формы пропустить проблемный объект и вывести сообщение с привязкой к нему.
Для Каждого Документ Из МассивОбъектов Цикл
Если Не ЗначениеЗаполнено(Документ.Организация) Тогда
ОбщегоНазначения.СообщитьПользователю(
СтрШаблон(НСтр("ru = 'Документ %1 не напечатан: не заполнена организация.'"),
Документ),
Документ);
Продолжить;
КонецЕсли;
// вывод печатной формы документа
КонецЦикла;
Остальные документы напечатаются, а сообщение со ссылкой на проблемный откроет его по двойному щелчку.
Отчёты
Для отчёта есть два варианта:
- Вывести сообщение через
СообщениеПользователюи не формировать результат, если без параметра отчёт бессмыслен (например, не выбран период). - Вывести текст прямо в табличный документ результата — если отчёт частично сформирован и нужно показать, какие данные не попали.
Второй вариант удобнее, когда отчёт отправляют по почте или сохраняют в файл: сообщение из нижней панели формы в файл не попадёт, а строка в табличном документе — попадёт.
Журнал регистрации: подробности для администратора
Пользователь видит «Не удалось загрузить файл». Администратору нужно знать, какой файл, на какой строке и почему. Это задача журнала регистрации.
ЗаписьЖурналаРегистрации(
НСтр("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)}: …»?
КраткоеПредставлениеОшибки, а подробное пишите в журнал регистрации.