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