Как программно запретить изменение документов через групповую обработку в 1С

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

В практике разработки на платформе 1С часто возникает задача ограничить редактирование документов, которые относятся к прошлым периодам. Обычная установка свойства ЭтаФорма.ТолькоПросмотр = Истина; в модуле формы решает проблему лишь частично — только при интерактивном открытии документа пользователем. Однако стандартные и самописные инструменты, такие как «Групповое изменение реквизитов», с легкостью обходят этот запрет, так как они работают напрямую с объектом, минуя его экранную форму.

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

Причина проблемы: форма против объекта

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

Решение 1: Подписка на событие ПередЗаписью

Для реализации контроля на уровне всей системы (конфигурации) лучше всего использовать Подписки на события. Это позволяет не вносить изменения в каждый отдельный модуль документа (например, ПКО, РКО, Заказ), а написать один универсальный обработчик.

Рассмотрим по шагам, как настроить такую проверку:

  1. Создадим общую подписку на событие ПередЗаписью.
  2. В качестве источника выберем типы документов, которые нужно контролировать.
  3. В обработчике события реализуем проверку старой даты документа.

Важный технический нюанс: Чтобы пользователь не мог обмануть систему, изменив дату старого документа на сегодняшнюю, нам нужно проверять не ту дату, которая находится в объекте сейчас (Источник.Дата), а ту, которая записана в базе данных (Источник.Ссылка.Дата).

Проанализируем пример кода для общего модуля:


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

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

    // Проверяем, является ли объект новым. Для новых документов ограничение обычно не действует.
    Если Источник.ЭтоНовый() Тогда
        Возврат;
    КонецЕсли;

    // Получаем первоначальную дату документа из базы данных до момента записи изменений
    ДатаВБазе = Источник.Ссылка.Дата;
    ТекущаяДатаСистемы = ТекущаяДата();
    
    // Определяем разницу в секундах (например, запрет на редактирование старше 30 дней)
    КоличествоСекундВМесяце = 30 * 24 * 60 * 60;

    Если (ТекущаяДатаСистемы - ДатаВБазе) > КоличествоСекундВМесяце Тогда
        // Если условие нарушено, выводим сообщение и отменяем запись
        ТекстСообщения = СтрШаблон("Документ %1 от %2 находится в закрытом периоде. Изменение запрещено!", 
            Источник, Формат(ДатаВБазе, "ДЛФ=D"));
            
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, Источник, , , Отказ);
        Отказ = Истина;
    КонецЕсли;

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

В этом коде мы используем обращение Источник.Ссылка.Дата. Это позволяет нам увидеть «прошлое» документа. Если групповая обработка попытается изменить дату с 01.01.2023 на 15.10.2023, наша проверка все равно увидит дату 01.01.2023 и заблокирует транзакцию.

Решение 2: Использование механизмов БСП «Даты запрета изменения»

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

Рассмотрим, как это работает программно. В модуле объекта или в той же подписке на событие мы можем вызвать метод проверки:


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

Преимущество этого метода в том, что администратор системы сможет менять «глубину» запрета (например, закрывать период не через 30 дней, а в конце каждого месяца) через пользовательский интерфейс, не прибегая к помощи программиста.

Решение 3: Определение контекста групповой записи

Иногда требуется разрешить интерактивное изменение, но запретить именно групповое. Выясним причину, как отличить эти процессы. В типовых обработках БСП «Групповое изменение реквизитов» при записи объекта в структуру ДополнительныеСвойства часто передается признак того, что запись программная.

Мы можем проанализировать ситуацию в коде:


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

Если вы используете самописную обработку, не забудьте добавить в нее код, который будет помечать записываемые объекты:

ОбъектДляЗаписи.ДополнительныеСвойства.Вставить("ЭтоГрупповоеИзменение", Истина);

Решение 4: Разграничение прав на уровне RLS

Это самый радикальный и надежный способ. RLS (Record Level Security) — ограничение прав на уровне записей базы данных. Если настроить шаблон доступа, который запрещает изменение (Update) документов, чья дата меньше определенного значения, то никакая обработка (даже запущенная администратором, если у него нет специальных прав) не сможет изменить объект.

Условие RLS в конфигураторе будет выглядеть примерно так:

ГДЕ Период > &ДатаОграничения

Этот метод работает на уровне SQL-запросов. Платформа просто не даст выполнить команду UPDATE для записей, не подпадающих под условие. Это исключает любые ошибки в программном коде и обходы через внешние обработки.

Подведем итоги

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

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

← На главную