В практике разработки на платформе 1С часто возникает задача: ограничить права пользователей таким образом, чтобы они не могли создавать новые записи в независимом регистре сведений, но имели право изменять ресурсы в уже существующих строках. Стандартная система ролей 1С не позволяет разделить право на "Изменение" и "Добавление" для регистра сведений — существует только общее право Запись.
В этой статье мы подробно разберем, почему стандартные методы контроля в модуле набора записей могут не срабатывать, и рассмотрим несколько эффективных стратегий решения этой задачи.
Прежде чем переходить к решениям, проанализируем, как платформа работает с независимыми регистрами. Когда пользователь нажимает кнопку "Записать", 1С выполняет запись набора. Если в процессе редактирования были изменены измерения, платформа фактически выполняет две операции в рамках одной транзакции:
Именно поэтому проверка ЭтотОбъект.Количество() в событии ПередЗаписью не всегда дает понимание, новая это запись или измененная. Нам нужно использовать более тонкие инструменты контроля.
Это самый простой и дружелюбный к пользователю метод. Если мы запретим изменять измерения в форме, пользователь технически не сможет создать "новую" запись путем модификации существующей. Разберем шаги реализации:
В модуле формы записи регистра используем обработчик ПриЧтенииНаСервере. Нам нужно определить, открыта ли существующая запись или создается новая.
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Проверяем, является ли запись новой по пустому ключу
Если Объект.КлючЗаписи.Пустой() Тогда
// Если это новая запись, и у пользователя нет спец. роли — закрываем доступ
Если Не РольДоступна("ПолныеПрава") И Не РольДоступна("АдминистраторРегистра") Тогда
ТолькоПросмотр = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "У вас нет прав на создание новых записей в этом регистре.";
Сообщение.Сообщить();
КонецЕсли;
Иначе
// Если запись существует, запрещаем менять измерения, оставляя доступ к ресурсам
Для Каждого РеквизитФормы Из ЭтаФорма.Элементы Цикл
// Предположим, измерения называются "Организация" и "Номенклатура"
Если РеквизитФормы.Имя = "Организация" Или РеквизитФормы.Имя = "Номенклатура" Тогда
РеквизитФормы.ТолькоПросмотр = Истина;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Этот метод хорош тем, что пользователь сразу видит ограничения и не тратит время на заполнение данных, которые не удастся сохранить.
Если данные в регистр могут попадать не только через форму, но и через загрузки или программный код, необходимо реализовать проверку в модуле набора записей. Рассмотрим ситуацию, когда нам нужно гарантировать наличие записи в БД перед её сохранением.
В обработчике ПередЗаписью модуля набора записей мы выполним запрос к физической таблице базы данных. Если запись с такими измерениями отсутствует — значит, это попытка добавления новой строки.
Процедура ПередЗаписью(Отказ, Замещать)
// Проверка актуальна только если запись инициирована не в привилегированном режиме
Если Отказ Или ОбменДанными.Загрузка Или РольДоступна("АдминистраторРегистра") Тогда
Возврат;
КонецЕсли;
// Проанализируем набор. Если он пустой (удаление), разрешаем.
Если ЭтотОбъект.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Для каждой записи в наборе проверяем её существование в БД
Для Каждого Запись Из ЭтотОбъект Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| 1
|ИЗ
| РегистрСведений.НашРегистр КАК НашРегистр
|ГДЕ
| НашРегистр.Измерение1 = &Измерение1
| И НашРегистр.Измерение2 = &Измерение2";
Запрос.УстановитьПараметр("Измерение1", Запись.Измерение1);
Запрос.УстановитьПараметр("Измерение2", Запись.Измерение2);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
// Записи с такими измерениями еще нет в базе — это создание новой
ТекстСообщения = СтрШаблон("Добавление новых записей запрещено (%1, %2)",
Запись.Измерение1, Запись.Измерение2);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , , , Отказ);
Отказ = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: этот метод заблокирует и изменение измерений в существующих записях, так как смена измерения технически создает новый ключ, которого еще нет в базе. Это именно то поведение, которое требуется для обеспечения целостности справочных данных.
Рассмотрим более архитектурный подход. Мы можем добавить в регистр дополнительный реквизит СозданоАдминистратором (тип Булево).
СозданоАдминистратором = Истина.СозданоАдминистратором всегда устанавливается в Ложь.В итоге: обычный пользователь сможет создать запись, но она тут же "исчезнет" для него (или он получит ошибку доступа при сохранении), так как у него нет прав на работу с неутвержденными данными. Изменять же записи, которые предварительно создал и "утвердил" администратор, он сможет без проблем.
Если ни один из вышеперечисленных методов не подходит, проанализируем вариант с полной блокировкой прав на запись в регистр для обычных пользователей. Чтобы они могли менять ресурсы, создадим специальную обработку или используем форму-посредник.
Запись для регистра.Пример кода в привилегированном модуле:
Процедура ОбновитьРесурсРегистраПривилегированно(КлючЗаписи, НовоеЗначениеРесурса) Экспорт
МенеджерЗаписи = РегистрыСведений.НашРегистр.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, КлючЗаписи);
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Ресурс = НовоеЗначениеРесурса;
МенеджерЗаписи.Записать(Истина); // Замещение существующей записи
Иначе
ВызватьИсключение "Запись не найдена. Создание новых записей запрещено.";
КонецЕсли;
КонецПроцедуры
Выбор метода зависит от ваших требований к производительности и интерфейсу:
Помните, что использование запросов в модуле набора записей может незначительно снизить скорость массовой записи данных, поэтому всегда проверяйте свойство ОбменДанными.Загрузка, чтобы не замедлять работу планов обмена.