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