Как проверить и заполнить реквизит «Ответственный» перед отменой проведения документа в 1С?

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

При настройке прав доступа и регламентации работы пользователей часто встает задача: запретить рядовым сотрудникам отменять проведение документов, созданных их коллегами, а также автоматически фиксировать автора документа в реквизите Ответственный, если он по какой-то причине оказался пустым.

Рассмотрим, как правильно реализовать подобный контроль в подписке на событие, выясним типичные ошибки при сравнении пользователей и разберем архитектурные нюансы, которые необходимо учесть при промышленной эксплуатации решения.

Базовый алгоритм проверки и заполнения реквизита

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

Посмотрим на пример базовой реализации, которая решает поставленную задачу:


Если НЕ Источник.Метаданные().Реквизиты.Найти("Ответственный") = Неопределено Тогда
    Если НЕ ЗначениеЗаполнено(Источник.Ответственный) Тогда
        Источник.Ответственный = ПараметрыСеанса.ТекущийПользователь;
    ИначеЕсли Источник.Ответственный <> ПараметрыСеанса.ТекущийПользователь Тогда
        Отказ = Истина;
        Сообщить("У вас нет прав на отмену проведения документа другого ответственного лица!");
    КонецЕсли;
КонецЕсли;

Разберем важные детали этой реализации:

  1. Проверка наличия реквизита через метаданные: метод Источник.Метаданные().Реквизиты.Найти("Ответственный") позволяет безопасно определить, есть ли у документа данный реквизит, предотвращая возникновение ошибки отсутствия свойства объекта. Обратите внимание: обращаться к метаданным следует напрямую через Источник.Метаданные(), избегая избыточного вызова Источник.Ссылка.Метаданные().
  2. Типизация данных: частая ошибка начинающих разработчиков — преобразование ссылки пользователя в строку (например, ПараметрыСеанса.ТекущийПользователь + ""). Это некорректно. В реквизите Ответственный всегда должна храниться прямая ссылка на элемент справочника (как правило, СправочникСсылка.Пользователи), и сравнение должно производиться ссылочно.
  3. Заполнение пустого значения: проверка НЕ ЗначениеЗаполнено(Источник.Ответственный) предотвращает перезапись уже установленного автора и срабатывает только тогда, когда документ создается впервые или реквизит был очищен.

Оптимизация кода под реальные бизнес-требования

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

Кроме того, жесткая блокировка неизбежно создаст проблемы в следующих ситуациях:

  1. Увольнение или перевод сотрудника: если ответственный уволен, ни один другой пользователь не сможет снять документ с проведения при закрытии периода или корректировке учета.
  2. Служебные обмены данными: при работе механизмов распределенной информационной базы (РИБ) или выгрузках через универсальный обмен данными попытка проверить текущего пользователя заблокирует синхронизацию.
  3. Регламентные и фоновые задания: в контексте выполнения фоновых задач параметр сеанса ТекущийПользователь может быть не заполнен, что приведет к аварийной остановке процедуры.
  4. Повторная отмена проведения: если документ уже непроведен, бессмысленно блокировать действие, так как движения регистров уже отсутствуют.

Финальный доработанный вариант подписки на событие

С учетом вышеперечисленных ограничений соберем полноценную процедуру-обработчик подписки на событие ПередЗаписью документа:


Процедура ПроверитьОтветственногоПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

    // Исключаем влияние на регламентный обмен данными
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Проверяем наличие реквизита в метаданных конкретного документа
    Если Источник.Метаданные().Реквизиты.Найти("Ответственный") = Неопределено Тогда
        Возврат;
    КонецЕсли;

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

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

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

Альтернативные подходы к разграничению прав

Рассмотрим, какие еще инструменты платформы 1С позволяют решить подобную задачу системно:

  1. Ограничение доступа на уровне записей (RLS): наиболее правильный архитектурный подход. Вместо программных проверок в обработчиках в роли пользователя для документа настраивается условие на изменение: ГДЕ Ответственный = &ТекущийПользователь. В этом случае пользователь физически не увидит кнопки отмены проведения чужих документов в интерфейсе.
  2. Подсистемы Библиотеки стандартных подсистем (БСП): при использовании БСП разграничение прав и передача документов между сотрудниками реализуются штатными профилями групп доступа и механизмами делегирования прав (замещение на период отпуска, передача дел). Это избавляет от необходимости дописывать нетиповой код и усложнять обновление конфигурации.
← На главную