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