Как разрешить проведение отдельного документа в 1С 8.2 (Обычные формы) без лишних обращений к базе данных

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С 8.2 часто возникает задача жесткого контроля над процессом проведения или отмены проведения документов. Например, когда бизнес-логика требует, чтобы документ проводился только один раз, а любые повторные действия или отмена проведения разрешались только определенному кругу лиц или при выполнении специфических условий. При этом критически важно соблюсти «чистоту» кода и не создавать лишних блокировок в базе данных. Рассмотрим, как решить эту задачу правильно, избегая чтения констант внутри транзакции.

Проблема использования констант внутри транзакции

Разберем ситуацию, описанную автором: в модуле объекта прописан жесткий отказ в процедуре ОбработкаУдаленияПроведения. Для того чтобы «обойти» этот запрет, разработчик планирует использовать константу, которая временно разрешает операцию. Однако прямое обращение к константе (через Константы.ИмяКонстанты.Получить()) внутри модуля объекта — это плохая практика по нескольким причинам:

  1. Увеличение времени транзакции: Любое обращение к базе данных (SQL-запрос) внутри транзакции увеличивает время её выполнения.
  2. Блокировки: В 1С 8.2 при использовании автоматического режима блокировок чтение константы может наложить разделяемую блокировку (Shared Lock) на всю таблицу констант. Если в этот момент другой процесс попытается записать любую другую константу, возникнет ожидание блокировки, что снижает общую параллельность системы.
  3. Избыточность: Если условие «разрешения» известно еще на этапе открытия формы, нет смысла запрашивать его повторно из базы данных в момент записи.

Проанализируем наиболее эффективные способы передачи контекста из интерфейса (формы) в логику объекта.

Решение №1: Использование механизма ДополнительныеСвойства

Проанализируем самый гибкий и «чистый» подход — использование коллекции ДополнительныеСвойства. Этот механизм специально предназначен для передачи произвольной информации между различными модулями и процедурами в рамках одного экземпляра объекта, не сохраняя эти данные в базе данных.

Посмотрим на алгоритм реализации. В форме документа, в обработчике события ПередЗаписью, мы определяем, нужно ли нам разрешить операцию, и устанавливаем соответствующий флаг.


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

Теперь рассмотрим, как использовать этот флаг в модуле объекта. Поскольку коллекция ДополнительныеСвойства доступна на протяжении всего цикла жизни объекта в памяти, мы можем обратиться к ней в любом обработчике.


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

КонецПроцедуры

Преимущество этого метода: Флаг передается в памяти сервера. Мы прочитали константу один раз в форме (вне транзакции записи), и передали готовое решение в модуль объекта. Это исключает лишние SQL-запросы в момент, когда база данных уже удерживает блокировки на таблицы документа и регистров.

Решение №2: Использование параметров сеанса

Если логика разрешения проведения завязана на конкретного пользователя или его роль (например, «Специально выделенный человек»), выясним, как применить параметры сеанса. Параметры сеанса инициализируются при запуске системы и хранятся в оперативной памяти сервера приложений 1С.

Рассмотрим, почему это эффективно: обращение к ПараметрыСеанса происходит мгновенно, без обращения к SQL-серверу. Это позволяет использовать их непосредственно в модуле объекта без ущерба для чистоты подхода.


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

Использование параметров сеанса — отличный способ избежать «чтения констант на терабайт», как иронично выразились участники обсуждения, сохранив при этом высокую скорость работы кода.

Решение №3: Подписки на события для чистоты кода

Если мы стремимся к максимальной чистоте и не хотим вносить изменения в типовой код модуля объекта (чтобы облегчить последующие обновления конфигурации), рассмотрим вариант с подписками на события. Мы можем создать общую подписку на событие ОбработкаУдаленияПроведения для нужных типов документов.

Разберем шаги реализации:

  1. Создаем в дереве метаданных новый объект Подписка на событие.
  2. В качестве источника выбираем интересующие нас документы.
  3. В качестве события выбираем ОбработкаУдаленияПроведения.
  4. В обработчике подписки прописываем логику проверки ДополнительныеСвойства или ПараметрыСеанса.

Такой подход позволяет централизованно управлять запретами на проведение для всей системы, не «засоряя» модули каждого отдельного документа одинаковым кодом.

Сводная таблица подходов

Проанализируем ситуацию и выберем подходящий инструмент в зависимости от требований:

Метод Когда использовать Влияние на производительность
Дополнительные свойства Когда решение о разрешении принимается в интерфейсе (форме) или внешней обработке. Минимальное (передача данных в памяти).
Параметры сеанса Когда логика зависит от прав или роли текущего пользователя. Минимальное (чтение из кэша сервера приложений).
Чтение константы в модуле Никогда (в высоконагруженных системах). Высокое (лишний запрос + блокировки БД).

Важные замечания по реализации

При реализации проверки в модуле объекта важно помнить, что документ может записываться не только из формы, но и программно (например, через внешнюю обработку или регламентным заданием). Выясним, как подстраховаться в этом случае:

Если вы используете ДополнительныеСвойства, помните: если документ записывается кодом ДокументОбъект.Записать() без предварительного заполнения коллекции свойств, ваша проверка сработает «по умолчанию» (запретит действие). Это правильно с точки зрения безопасности, но может сломать работу некоторых обработок. Поэтому всегда документируйте необходимость передачи технических флагов при программной работе с такими «защищенными» документами.

Таким образом, комбинируя проверку в модуле (для надежности) и предварительную подготовку данных в форме (для производительности), мы получаем стабильное и быстрое решение задачи контроля проведения в 1С 8.2.

← На главную