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