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