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