В процессе ведения учета в системах «1С:Предприятие» регулярно возникает классическая задача: необходимо закрыть период для редактирования. Однако стандартная ситуация усложняется, когда закрыть нужно не все документы сразу, а только определенный их вид — например, Реализации товаров и услуг, оставив при этом возможность корректировать складские накладные, закупки или кассовые ордера. Такая необходимость часто возникает перед окончательным закрытием месяца, когда коммерческий отдел уже сдал отчетность, а бухгалтерия и склад еще продолжают сверку.
В этой статье мы подробно разберем, как реализовать точечный запрет изменения документов конкретного типа до определенной даты. Мы проанализируем как простые программные методы, так и современные безопасные практики платформы «1С:Предприятие 8» и Библиотеки стандартных подсистем (БСП).
Существует распространенное заблуждение, что типовой механизм даты запрета изменений закрывает период полностью для всей базы данных и всех документов. В современных конфигурациях на базе БСП (таких как ERP, Комплексная автоматизация, Управление торговлей, Бухгалтерия предприятия и УНФ) это не так.
Стандартный функционал поддерживает гибкую настройку «По разделам и объектам». Давайте разберем, как его использовать:
Если ваша конфигурация существенно доработана или документ является полностью самописным, мы можем программно связать его со стандартным механизмом БСП. Для этого используются процедуры переопределяемого модуля ДатыЗапретаИзмененияПереопределяемый. Нам понадобятся процедуры ПриЗаполненииРазделовДатЗапретаИзменения и ЗаполнитьИсточникиДанныхДляПроверкиЗапретаИзменения. Интеграция нашего документа в этот общий модуль позволит администраторам системы управлять ограничениями через стандартный и удобный интерфейс БСП без написания лишнего кода.
Если стандартный механизм БСП по каким-то причинам не подходит или требуется реализовать жесткую кастомную логику, лучшим решением будет использование Подписки на события. Этот подход позволяет избежать изменения типового модуля объекта самого документа, что существенно облегчает последующие обновления конфигурации.
Создадим подписку на событие ПередЗаписью для документа реализации. Но при написании обработчика важно учесть критические нюансы, которые часто упускают начинающие разработчики.
Рассмотрим правильный шаблон кода для обработчика подписки:
Процедура ПередЗаписьюДокументаРеализацииПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// 1. Обязательная проверка на загрузку данных.
// Если идет обмен данными, блокировка не должна нарушать синхронизацию.
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// 2. Разрешаем беспрепятственное создание новых документов.
Если Источник.ЭтоНовый() Тогда
Возврат;
КонецЕсли;
// 3. Получаем граничную дату (ее можно хранить в константе или регистре сведений)
ДатаЗапрета = Константы.ДатаОграниченияРеализаций.Получить();
Если Не ЗначениеЗаполнено(ДатаЗапрета) Тогда
Возврат;
КонецЕсли;
// 4. Проверяем, попадает ли документ в закрытый период.
// Важно проверять как старую дату документа (в БД), так и новую дату, которую пытается записать пользователь.
Если Источник.Дата < ДатаЗапрета Тогда
Отказ = Истина;
ВызватьИсключение "Редактирование документов реализации до " + Формат(ДатаЗапрета, "ДФ=dd.MM.yyyy") + " запрещено!";
КонецЕсли;
// Дополнительно проверяем оригинальную дату документа из базы данных,
// чтобы пользователь не мог "обхитрить" систему, перенеся старый документ в открытый период.
СсылкаНаДокумент = Источник.Ссылка;
СтараяДата = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаДокумент, "Дата");
Если СтараяДата < ДатаЗапрета И Источник.Дата >= ДатаЗапрета Тогда
Отказ = Истина;
ВызватьИсключение "Запрещено переносить документы реализации из закрытого периода!";
КонецЕсли;
КонецПроцедуры
Важное предупреждение: Блокировки только при записи недостаточно! Пользователь может попытаться обойти запрет, просто пометив документ на удаление или удалив его физически. Чтобы исключить эту уязвимость, необходимо создать вторую подписку на событие ПередУдалением для этого же документа и выполнять аналогичную проверку даты там.
Если нам требуется гарантировать стопроцентную защиту данных (например, от продвинутых пользователей, запускающих внешние обработки в обход интерфейса), то самым надежным решением станет ограничение на уровне записей — RLS (Record Level Security). Этот механизм работает непосредственно на уровне SQL-запросов к СУБД.
Для реализации этого подхода выполним следующие шаги:
ГДЕ Дата >= &ГраницаЗапретаИзмененияРеализаций
ГраницаЗапретаИзмененияРеализаций инициализируем при старте системы, считывая значение из соответствующей константы.В этом случае платформа сама заблокирует любые попытки изменения данных на самом глубоком уровне, включая программную перезапись из внешних обработок.
Вызывать жесткий Отказ = Истина в момент нажатия кнопки «Записать» — это плохой тон разработки. Пользователь может потратить много времени на заполнение табличной части документа, нажать «Записать» и потерять всю проделанную работу из-за всплывшей ошибки.
Мы должны предупредить пользователя заранее и сделать форму доступной только для чтения. Сделать это можно двумя путями:
Вариант А (Интеграция с БСП): Если в конфигурации используется БСП, мы можем вызвать специальный метод в процедуре ПриЧтенииНаСервере модуля формы нашего документа:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Метод автоматически проверит правила запрета и заблокирует форму
ДатыЗапретаИзменения.ОбъектПриЧтенииНаСервере(ЭтотОбъект, ТекущийОбъект);
КонецПроцедуры
Этот метод самостоятельно проанализирует все ограничения, установит для формы свойство ТолькоПросмотр = Истина, заблокирует кнопки «ОК», «Записать» и «Провести», а также выведет красивую наглядную панель вверху формы с предупреждением о том, что редактирование объекта запрещено.
Вариант Б (Собственная логика): Если БСП отсутствует, мы можем написать простую проверку в процедуре ПриОткрытии или ПриЧтенииНаСервере на форме документа:
&НаСервере
Процедура УстановитьДоступностьФормы()
ДатаЗапрета = Константы.ДатаОграниченияРеализаций.Получить();
Если ЗначениеЗаполнено(ДатаЗапрета) И Объект.Дата < ДатаЗапрета И Не Объект.Ссылка.Пустая() Тогда
ЭтотОбъект.ТолькоПросмотр = Истина;
КонецЕсли;
КонецПроцедуры
Чтобы пользователи не тратили время на открытие каждого документа для проверки возможности его редактирования, настроим визуальное выделение закрытых документов прямо в списках (журналах продаж).
Для этого задействуем Условное оформление динамического списка:
Дата < &ДатаЗапрета.Благодаря этому интерфейс системы станет дружелюбным и интуитивно понятным, а пользователи сразу увидят, какие документы закрыты для корректировок.
Подводя итог, отметим: для комплексного решения задачи лучше всего сочетать Подписку на событие ПередЗаписью (как надежный бэкенд-контроль) и установку свойства ТолькоПросмотр на форме (для удобства пользователей). Такой тандем обеспечит безопасность данных и сохранит лояльность пользователей к системе.