Как запретить пользователю отмену проведения документов прошлых периодов в 1С?

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

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

Анализ типичной ошибки в условии проверки периода

Рассмотрим типовую ситуацию. Разработчик создает подписку на событие ПередЗаписью документа и пытается отсечь интервал с помощью проверки даты. В исходном варианте код часто выглядит следующим образом:


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

Проанализируем, почему этот код не выполняет проверку интервала. Выражение НачалоМесяца(ТекущаяДата) <> НачалоМесяца(ТекущаяДата) сравнивает одно и то же значение само с собой. Результат такого сравнения всегда будет равен Ложь, а значит, всё составное условие никогда не выполнится, и отмена проведения не будет заблокирована.

Кроме того, чтобы проверить ограничение на два месяца назад от текущей даты, необходимо обращаться к дате самого документа (Источник.Дата) и сравнивать ее с расчетной датой границы запрета.

Корректный расчет границы даты и базовое решение

Для смещения даты на определенное количество месяцев в платформе 1С предусмотрена функция ДобавитьМесяц(). Если требуется запретить отмену проведения документов, которые были оформлены ранее чем за последние два месяца, условие должно проверять, что дата документа строго меньше вычисленной границы.

Посмотрим на исправленное условие проверки:


Если Источник.Дата < ДобавитьМесяц(ТекущаяДатаСеанса(), -2) Тогда
    // Документ старше двух месяцев
КонецЕсли;

Обратим внимание на знак сравнения: если указать Источник.Дата > ДобавитьМесяц(...), блокировка сработает наоборот — система заблокирует проведение и отмену проведения новых документов, но разрешит менять старые. Поэтому используем именно оператор «меньше» (<).

Уязвимости базового решения и их устранение

Если ограничиться только сравнением Источник.Дата в подписке на событие, в системе остаются логические лазейки. Рассмотрим основные нюансы, о которых важно помнить при разработке надежного механизма:

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

Итоговый вариант обработчика в подписке на событие

Соберем все требования воедино и посмотрим на надежный вариант реализации обработчика подписки на событие ПередЗаписью:


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

    // Проверяем, выполняется ли код в привилегированном режиме
    Если ПривилегированныйРежим() Тогда
        Возврат;
    КонецЕсли;

    // Если у пользователя есть полные права, ограничение не накладываем
    Если РольДоступна("ПолныеПрава") Тогда
        Возврат;
    КонецЕсли;

    // Проверяем роль целевого пользователя
    Если НЕ РольДоступна("ДляЭкономистов") Тогда
        Возврат;
    КонецЕсли;

    // Определяем, происходит ли отмена проведения (явно или сбросом флага)
    СнятиеСПроведения = (РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения)
        ИЛИ (Источник.Ссылка.Проведен И НЕ Источник.Проведен);

    Если НЕ СнятиеСПроведения Тогда
        Возврат;
    КонецЕсли;

    // Рассчитываем граничную дату: начало месяца два месяца назад
    МинимальнаяДата = НачалоМесяца(ДобавитьМесяц(ТекущаяДатаСеанса(), -2));

    // Проверяем как текущую дату в форме, так и дату, сохраненную в базе данных
    Если (Источник.Дата < МинимальнаяДата) ИЛИ (Источник.Ссылка.Дата < МинимальнаяДата) Тогда
        Отказ = Истина;
        ВызватьИсключение "Отмена проведения документов за период ранее " 
            + Формат(МинимальнаяДата, "ДФ=dd.MM.yyyy") + " запрещена!";
    КонецЕсли;

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

Альтернативные способы реализации запрета

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

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