Как запретить проведение и редактирование документов старше месяца в 1С?

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

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

В этой статье мы подробно разберем два основных способа решения этой задачи: использование встроенного типового механизма конфигурации и создание собственного программного ограничения через механизм подписок на события.

Способ 1. Использование типового механизма «Дата запрета изменения»

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

Для активации и настройки этого механизма выполним следующие шаги:

  1. Перейдем в раздел Администрирование, далее выберем пункт Настройки пользователей и прав.
  2. Установим флаг напротив опции Даты запрета изменения и перейдем по ссылке Настроить.
  3. В открывшемся окне мы можем настроить правила запрета. Важное преимущество стандартного механизма — поддержка динамических дат запрета. Вместо указания фиксированного календарного дня, мы можем выбрать относительное значение, например, «Конец прошлого месяца» или «Предыдущий день». Система будет автоматически сдвигать границу запрета без участия администратора.
  4. Мы можем настроить правила как для всех пользователей сразу, так и индивидуально (например, разрешить изменять прошлые периоды только определенным бухгалтерам или руководителям, оставив запрет для рядовых менеджеров).

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

Способ 2. Создание подписки на событие «ПередЗаписью»

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

Разберем по шагам, как правильно создать и запрограммировать подписку на событие для контроля даты документов.

Шаг 1. Создание общего модуля

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

Шаг 2. Создание объекта «Подписка на событие»

В дереве конфигурации найдем ветку Общие -> Подписки на события, добавим новую подписку и настроим её свойства:

Шаг 3. Реализация безопасного и надежного программного кода

При написании обработчика подписки крайне важно избежать ошибок, которые часто допускают начинающие разработчики. Проанализируем эти нюансы:

  1. Отсутствие контекста формы: Внутри общего модуля подписки недоступна переменная ЭтотОбъект. Вместо нее используется первый параметр процедуры — Источник, который и представляет собой записываемый документ.
  2. Выполнение на сервере: Подписки выполняются в транзакции на стороне сервера. Использование интерактивных методов вроде Предупреждение() или Вопрос() приведет к критической ошибке и аварийному завершению сеанса пользователя. Для вывода сообщений мы должны использовать объект СообщениеПользователю.
  3. Обход проверки через изменение даты: Хитрый пользователь может попытаться обойти запрет: сначала изменить дату старого проведенного документа на сегодняшнюю, записать его, провести, а затем вернуть исходную дату обратно. Чтобы закрыть эту уязвимость, мы должны контролировать не только новую дату документа, но и его первоначальную дату, сохраненную в базе данных (через обращение к Источник.Ссылка.Дата).
  4. Ограничение для администраторов: Нам необходимо предусмотреть возможность обхода этого правила для учетных записей администраторов или пользователей с полными правами.

С учетом всех требований напишем правильный, отказоустойчивый код в общем модуле:


Процедура ПроверитьДатуДокументаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    
    // Если документ загружается в рамках обмена данными (РИБ или интеграция), проверку выполнять не нужно
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Разрешаем запись без ограничений пользователям с полными правами
    Если РольДоступна("ПолныеПрава") Тогда
        Возврат;
    КонецЕсли;
    
    // Вычисляем границу запрета (текущая дата минус 30 дней в секундах)
    СекундВМесяце = 30 * 24 * 60 * 60; // 2 592 000 секунд
    ГраницаЗапрета = ТекущаяДатаСеанса() - СекундВМесяце;
    
    // Проверка 1: Попытка провести или записать новый/изменяемый документ, дата которого уже в закрытом периоде
    Если Источник.Дата <= ГраницаЗапрета Тогда
        
        // Запрещаем проведение старого документа
        Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
            Отказ = Истина;
            ТекстОшибки = "Отказано в проведении! Дата документа (" + Формат(Источник.Дата, "ДФ=dd.MM.yyyy") + ") старше одного месяца.";
            ВывестиСообщениеПроцедуры(ТекстОшибки, Источник);
            Возврат;
        КонецЕсли;
        
        // Запрещаем отмену проведения или изменение старого проведенного документа
        Если Источник.Проведен И РежимЗаписи = РежимЗаписиДокумента.Запись Тогда
            Отказ = Истина;
            ТекстОшибки = "Запрещено редактирование и перезапись проведенных документов старше одного месяца!";
            ВывестиСообщениеПроцедуры(ТекстОшибки, Источник);
            Возврат;
        КонецЕсли;
        
    КонецЕсли;
    
    // Проверка 2: Защита от изменения даты существующего старого документа в базе
    Если ЗначениеЗаполнено(Источник.Ссылка) Тогда
        
        // Получаем дату документа напрямую из базы данных до начала записи изменений
        СтараяДатаДокумента = Источник.Ссылка.Дата;
        
        Если СтараяДатаДокумента <= ГраницаЗапрета Тогда
            // Если документ изначально лежал в закрытом периоде, а пользователь пытается перенести его в открытый
            Если Источник.Дата > ГраницаЗапрета Тогда
                Отказ = Истина;
                ТекстОшибки = "Запрещено изменять дату у документов, созданных более месяца назад!";
                ВывестиСообщениеПроцедуры(ТекстОшибки, Источник);
                Возврат;
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;

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

Процедура ВывестиСообщениеПроцедуры(ТекстСообщения, ИсточникДокумент)
    
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = ТекстСообщения;
    Сообщение.УстановитьДанные(ИсточникДокумент);
    Сообщение.Сообщить();
    
КонецПроцедуры

Разбор работы алгоритма

Рассмотрим подробнее, как именно функционирует написанный код:

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

← На главную