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