Как надежно запретить редактирование реквизитов в 1С:Бухгалтерии предприятия (БП): от свойств формы до контроля на уровне базы данных

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

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

Решение этой задачи может показаться тривиальным: достаточно установить нужное свойство на форме. Однако на практике разработчики сталкиваются с тем, что пользователи находят обходные пути — используют групповое изменение реквизитов, обработку «Изменить выделенные» в списках или программные обработки. В этой статье мы подробно рассмотрим все возможные способы решения этой задачи: от простых визуальных блокировок до гарантированной защиты данных на уровне сервера.

Способ 1. Визуальная блокировка на форме: свойства «Доступность» и «ТолькоПросмотр»

Самый простой и быстрый способ закрыть поле от редактирования — изменить свойства элемента формы. Для этого мы можем использовать два основных свойства: Доступность (Enabled) и ТолькоПросмотр (ReadOnly).

Давайте разберем по шагам, чем отличаются эти свойства и как их правильно применять:

  1. Свойство Доступность (Доступность = Ложь): Полностью блокирует элемент управления на форме. Поле окрашивается в серый цвет, пользователь не может установить в него курсор, скопировать текст из этого поля или нажать на связанные с ним кнопки (например, кнопку выбора или очистки). Это жесткий визуальный запрет.
  2. Свойство ТолькоПросмотр (ТолькоПросмотр = Истина): Элемент формы остается активным, но его значение нельзя изменить. Покупатель или менеджер может выделить текст в этом поле и скопировать его в буфер обмена. Кнопки выбора и очистки становятся неактивными. С точки зрения юзабилити этот вариант предпочтительнее, так как оставляет информацию доступной для копирования.

Рассмотрим, как программно установить эти свойства при открытии формы документа. Для этого откроем модуль формы и в обработчике события ПриСозданииНаСервере напишем следующий код:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Вариант 1: Полная блокировка доступности поля "Вид оплаты"
    Элементы.ВидОплаты.Доступность = Ложь;
    
    // Вариант 2: Перевод поля в режим "Только просмотр" (рекомендуется)
    Элементы.ВидОплаты.ТолькоПросмотр = Истина;
    
КонецПроцедуры

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Если документ проведен, запрещаем изменять вид оплаты всем, кроме администраторов
    Если Объект.Проведен И Не РольДоступна("ПолныеПрава") Тогда
        Элементы.ВидОплаты.ТолькоПросмотр = Истина;
    КонецЕсли;
    
КонецПроцедуры

Проблема обхода клиентской защиты: почему формы недостаточно?

Как совершенно справедливо отметили участники обсуждения на форуме, блокировка элемента управления на форме защищает систему только от «случайного» изменения данных невнимательным пользователем. Она не создает реального барьера для подготовленного человека или для штатных механизмов платформы.

Выделим основные способы, которыми пользователи могут изменить заблокированный реквизит в обход формы:

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

Способ 2. Использование подсистемы БСП «Запрет редактирования реквизитов объектов»

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

Этот механизм предоставляет пользователям удобный интерфейс: ключевые реквизиты формы изначально заблокированы, но в меню «Еще» присутствует кнопка «Разрешить редактирование реквизитов». Доступ к этой кнопке регулируется ролями доступа (например, роль РедактированиеРеквизитовОбъектов).

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

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

  1. Добавим наш документ в состав определяемого типа ОбъектСКонтролируемымиРеквизитами.
  2. В модуле менеджера нашего документа определим экспортную процедуру ПриОпределенииНастроекБлокировкиРеквизитов, в которой укажем, какие именно реквизиты подлежат защите:

// В модуле менеджера документа
Процедура ПриОпределенииНастроекБлокировкиРеквизитов(Настройки) Экспорт
    
    Реквизиты = Новый Массив;
    Реквизиты.Добавить("ВидОплаты");
    Реквизиты.Добавить("Контрагент");
    
    Настройки.Вставить("ИмяРеквизита", Реквизиты);
    
КонецПроцедуры

После этого система автоматически заблокирует указанные поля на управляемой форме при условии, что документ уже сохранен в базе данных.

Способ 3. Гарантированная блокировка изменений в модуле объекта (ПередЗаписью)

Если нам нужна абсолютная гарантия того, что реквизит не будет изменен ни при каких обстоятельствах (включая сторонний программный код, загрузку по XML, OData или групповые обработки), проверку необходимо реализовать на самом низком уровне — в транзакции записи базы данных.

Для этого мы переопределим обработчик события ПередЗаписью в модуле объекта нашего документа. Алгоритм проверки выглядит следующим образом:

  1. Проверяем, не является ли объект новым (для новых документов проверять изменение старого значения не имеет смысла).
  2. Проверяем свойство ОбменДанными.Загрузка. Если идет загрузка данных из другой базы, проверку можно пропустить или, наоборот, сделать более строгой.
  3. Сравниваем текущее значение реквизита со значением, которое уже записано в базе данных.

Важное правило оптимизации: Чтобы получить старое значение реквизита из базы данных, никогда не используйте конструкцию ЭтотОбъект.Ссылка.ИмяРеквизита. Такое обращение является неявным запросом, который считывает из СУБД всю таблицу объекта целиком, что приводит к серьезным задержкам производительности и неоправданному расходу оперативной памяти сервера. Вместо этого мы напишем быстрый точечный запрос.

Проанализируем пример кода в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если идет обмен данными, пропускаем стандартные проверки (при необходимости)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Для новых документов контроль изменения не требуется
    Если ЭтоНовый() Тогда
        Возврат;
    КонецЕсли;
    
    // Запросом получаем только текущее значение реквизита "ВидОплаты" из БД
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ОплатаПокупателя.ВидОплаты КАК ВидОплатыОригинал
        |ИЗ
        |	Документ.ОплатаПокупателя КАК ОплатаПокупателя
        |ГДЕ
        |	ОплатаПокупателя.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        
        // Если значение в памяти отличается от значения в базе данных
        Если ЭтотОбъект.ВидОплаты <> Выборка.ВидОплатыОригинал Тогда
            
            // Проверяем права пользователя. Разрешаем изменение только Администраторам.
            Если Не РольДоступна("ПолныеПрава") И Не РольДоступна("Администрирование") Тогда
                
                Отказ = Истина; // Отменяем транзакцию записи объекта в базу данных
                
                // Выводим информативное сообщение пользователю
                Сообщение = Новый СообщениеПользователю;
                Сообщение.Текст = "Вы не имеете права изменять реквизит ""Вид оплаты"" в записанном документе!";
                Сообщение.Поле = "ВидОплаты";
                Сообщение.УстановитьДанные(ЭтотОбъект);
                Сообщение.Сообщить();
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Данный подход является наиболее надежным стандартом разработки. Даже если пользователь найдет способ обойти форму, СУБД просто отклонит транзакцию записи и вернет ошибку.

Способ 4. Ограничение прав доступа на уровне полей (Field-Level Security)

Платформа 1С:Предприятие 8 позволяет настраивать права доступа не только к метаданным в целом (например, ко всему документу), но и детально разграничивать права на чтение и изменение отдельных реквизитов (полей) объекта.

Разберем, как настроить такое ограничение в конфигураторе:

  1. Найдем в дереве метаданных роль, назначенную обычным пользователям (например, ДобавлениеИзменениеДокументовОплаты).
  2. Перейдем на вкладку «Шаблоны ограничений» или напрямую выберем объект Документ.ОплатаПокупателя в списке прав роли.
  3. В списке реквизитов снимем флажок Редактирование напротив поля ВидОплаты.

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

Важное предупреждение: Использование ограничений на уровне полей требует высокой квалификации разработчика. Если вы случайно закроете права на Чтение критически важного реквизита, стандартные отчеты и запросы в системе могут начать аварийно завершаться с ошибками нарушения прав доступа, если в них не используется конструкция РАЗРЕШЕННЫЕ.

Способ 5. Реализация ограничений через Расширения конфигурации

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

Рассмотрим, как красиво решить задачу блокировки с помощью механизма Расширений конфигурации:

  1. Создадим новое расширение конфигурации (или откроем существующее).
  2. Добавим в расширение наш документ (например, ОплатаПокупателя) и его реквизит ВидОплаты.
  3. В расширении создадим обработчик события ПередЗаписью в модуле объекта с аннотацией &Перед:

&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем, изменен ли реквизит, используя логику из Способа 3
    Если Не ЭтоНовый() И Не ОбменДанными.Загрузка Тогда
        
        // Получаем старое значение из базы данных с помощью запроса
        Запрос = Новый Запрос("ВЫБРАТЬ ВидОплаты ИЗ Документ.ОплатаПокупателя ГДЕ Ссылка = &Ссылка");
        Запрос.УстановитьПараметр("Ссылка", Ссылка);
        Выборка = Запрос.Выполнить().Выбрать();
        
        Если Выборка.Следующий() Тогда
            Если ЭтотОбъект.ВидОплаты <> Выборка.ВидОплаты Тогда
                Если Не РольДоступна("ПолныеПрава") Тогда
                    Отказ = Истина;
                    ВызватьИсключение "Редактирование поля ""Вид оплаты"" запрещено политикой безопасности!";
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 6. Включение механизма «История данных» для административного контроля

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

Этот механизм позволяет фиксировать любые изменения полей:

Чтобы задействовать этот механизм, достаточно открыть свойства нужного документа в конфигураторе и для свойства ИсторияДанных установить значение Использовать. После этого вы всегда сможете открыть историю версий объекта прямо из пользовательского режима, увидеть нарушителя и провести административную работу (лишить премии или вынести предупреждение), не усложняя программный код системы.

Резюме и рекомендации по выбору решения

Для наглядности объединим все рассмотренные методы в общую таблицу рекомендаций:

Метод защиты Уровень надежности Сложность реализации Когда применять
ТолькоПросмотр / Доступность на форме Низкий (обходится через групповую обработку) Очень низкая Для защиты от случайных ошибок ввода пользователем на форме.
Механизм блокировки реквизитов БСП Средний (защищает форму и штатное групповое изменение) Средняя Рекомендуемый стандарт для типовых конфигураций 1С (БП, ERP, УТ).
Проверка ПередЗаписью в модуле объекта Абсолютный (защищает на уровне СУБД) Средняя Для критически важных полей, изменение которых нарушит учет или обмены.
Ограничение прав доступа в Ролях (FLS) Абсолютный (на уровне платформы) Высокая (требует тщательного тестирования) Для жесткого разделения прав между группами пользователей.
Платформенная История Данных Информационный контроль Очень низкая Когда важен аудит изменений, а не жесткие технические запреты.

Выбирайте подходящий инструмент исходя из бизнес-требований вашей задачи. Оптимальным решением для 1С:Бухгалтерии является совместное использование свойств формы (для удобства работы интерфейса) и обработчика ПередЗаписью в расширении конфигурации (для гарантированной безопасности ваших данных).

← На главную