Как разрешить разовое изменение элемента формы в 1С и заблокировать его после записи?

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

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

В этой статье мы подробно разберем, как правильно реализовать такое поведение. Мы рассмотрим три взаимодополняющих уровня защиты данных: визуальный уровень интерфейса (UX/UI), уровень базы данных (модуль объекта) и использование профессионального промышленного механизма из состава Библиотеки Стандартных Подсистем (БСП).

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

Способ 1. Блокировка на уровне интерфейса (UX/UI)

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

В обсуждениях разработчики часто предлагают использовать свойство элемента формы Доступность и устанавливать его в значение Ложь. Однако на практике это не самое лучшее решение с точки зрения удобства пользователя (UX). Рассмотрим подробнее, почему это так.

Когда мы устанавливаем Доступность = Ложь, элемент формы полностью отключается:

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

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

Давайте реализуем программную блокировку в модуле управляемой формы. Наиболее подходящими местами для выполнения этой проверки являются события формы ПриСозданииНаСервере и ПриЧтенииНаСервере.

Проанализируем пример кода для модуля формы:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Проверяем, существует ли уже объект в базе данных (не новый ли он)
    // и заполнено ли ключевое поле, которое мы хотим защитить
    Если ЗначениеЗаполнено(Объект.Ссылка) И ЗначениеЗаполнено(Объект.НомерДоговора) Тогда
        
        // Блокируем элемент управления на форме для изменения
        Элементы.НомерДоговора.ТолькоПросмотр = Истина;
        
    КонецЕсли;
    
КонецПроцедуры

Этот код отлично отрабатывает при открытии уже существующего элемента. А что произойдет, если пользователь открыл новую форму, заполнил реквизит НомерДоговора и нажал кнопку «Записать»? Нам нужно, чтобы сразу после записи поле заблокировалось, не требуя закрытия и повторного открытия формы.

Для этого мы задействуем обработчик события ПослеЗаписиНаСервере:


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

Комбинация этих двух обработчиков обеспечивает бесшовный и понятный для пользователя интерфейс: пока карточка новая — пиши что хочешь; как только нажал кнопку «Записать» — поле зафиксировалось и стало доступно только для чтения.

Способ 2. Защита целостности данных на уровне СУБД (Модуль объекта)

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

Любые ограничения, прописанные исключительно в модуле формы, действуют только тогда, когда пользователь открывает эту форму в интерактивном режиме. Однако данные в 1С могут быть изменены и в обход интерфейса:

  1. Через внешние обработки группового изменения реквизитов.
  2. С помощью фоновых и регламентных заданий.
  3. При интеграции через HTTP-сервисы, Web-сервисы или при обмене данными (РИБ, EnterpriseData).
  4. Через написанный другими разработчиками программный код, который выполняет запись объекта непосредственно в базу данных.

Для того чтобы обеспечить абсолютную гарантию неизменности реквизита, мы должны продублировать бизнес-логику проверки в **модуле объекта** в предопределенной процедуре ПередЗаписью. Это событие вызывается всегда, независимо от того, как именно записывается объект — интерактивно или программно.

Рассмотрим, как реализовать такую проверку в модуле объекта (например, справочника или документа):


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

Важное примечание: Обратите внимание, что для получения старого значения реквизита из базы данных мы используем функцию ОбщегоНазначения.ЗначениеРеквизитаОбъекта(), а не прямое обращение через точку ЭтотОбъект.Ссылка.НомерДоговора. Обращение через точку приводит к неявному считыванию всего объекта из базы данных в память, что снижает производительность системы. Использование специализированных функций БСП позволяет прочитать из базы данных только одно конкретное поле с помощью быстрого SQL-запроса.

Способ 3. Промышленное решение с помощью Библиотеки Стандартных Подсистем (БСП)

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

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

Разберем по шагам, как подключить наш объект к этой подсистеме БСП:

Шаг 1. Регистрация объекта в подсистеме

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


Процедура ПриОпределенииОбъектовСЗаблокированнымиРеквизитами(Объекты) Экспорт
    
    // Регистрируем наш справочник "ДоговорыКонтрагентов" в списке контролируемых объектов
    Объекты.Вставить(Метаданные.Справочники.ДоговорыКонтрагентов.ПолноеИмя());
    
КонецПроцедуры

Шаг 2. Определение списка блокируемых реквизитов

Теперь нам нужно сообщить БСП, какие именно реквизиты внутри нашего объекта подлежат блокировке. Для этого откроем модуль менеджера нашего объекта (в нашем примере — справочника ДоговорыКонтрагентов) и создадим там экспортную функцию ПолучитьБлокируемыеРеквизитыОбъекта:


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

Шаг 3. Подключение логики к форме объекта

Чтобы заблокированные реквизиты правильно обрабатывались интерфейсом формы, нам необходимо интегрировать методы БСП в модуль формы нашего справочника или документа. Откроем модуль формы и добавим вызовы в стандартные процедуры:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Инициализируем блокировку реквизитов на форме при открытии
    ЗапретРедактированияРеквизитовОбъектов.УстановитьБлокировкуРеквизитов(ЭтотОбъект);
    
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    
    // Повторно накладываем блокировку после записи нового или измененного объекта
    ЗапретРедактированияРеквизитовОбъектов.УстановитьБлокировкуРеквизитов(ЭтотОбъект);
    
КонецПроцедуры

При этом подсистема БСП автоматически выполнит следующие действия:

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

Резюме и рекомендации

Мы проанализировали три различных подхода к реализации разового изменения реквизитов в «1С:Предприятии 8.3». Какой из них выбрать для вашего проекта?

Если вы разрабатываете небольшую самописную конфигурацию «с нуля» без использования БСП, то связка Способа 1 (блокировка на форме через ТолькоПросмотр) и Способа 2 (жесткий контроль в модуле объекта ПередЗаписью) является обязательным отраслевым стандартом. Интерфейсная блокировка обеспечивает удобство работы для обычных пользователей, а проверка в модуле объекта гарантирует целостность базы данных при интеграциях и групповых обработках.

Если же ваша разработка ведется на базе любой современной типовой конфигурации 1С, настоятельно рекомендуем использовать Способ 3 (стандартный механизм БСП). Это сэкономит вам время разработки, избавит от написания лишнего кода и предоставит пользователям привычный, стандартизированный интерфейс с возможностью контролируемой разблокировки полей администратором.

← На главную