Как запретить добавление новых строк в независимый регистр сведений при сохранении возможности их редактирования

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

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

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

Проблема механизма замещения в независимых регистрах

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

  1. Удаление старой записи (запись пустого набора по старому ключу).
  2. Запись новой записи (набор с новыми измерениями).

Именно поэтому проверка ЭтотОбъект.Количество() в событии ПередЗаписью не всегда дает понимание, новая это запись или измененная. Нам нужно использовать более тонкие инструменты контроля.

Способ 1. Блокировка на уровне формы записи

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

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


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

Этот метод хорош тем, что пользователь сразу видит ограничения и не тратит время на заполнение данных, которые не удастся сохранить.

Способ 2. Контроль в модуле набора записей (надежный метод)

Если данные в регистр могут попадать не только через форму, но и через загрузки или программный код, необходимо реализовать проверку в модуле набора записей. Рассмотрим ситуацию, когда нам нужно гарантировать наличие записи в БД перед её сохранением.

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


Процедура ПередЗаписью(Отказ, Замещать)
    
    // Проверка актуальна только если запись инициирована не в привилегированном режиме
    Если Отказ Или ОбменДанными.Загрузка Или РольДоступна("АдминистраторРегистра") Тогда
        Возврат;
    КонецЕсли;

    // Проанализируем набор. Если он пустой (удаление), разрешаем.
    Если ЭтотОбъект.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

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

КонецПроцедуры

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

Способ 3. Использование признака "Утверждено" и RLS

Рассмотрим более архитектурный подход. Мы можем добавить в регистр дополнительный реквизит СозданоАдминистратором (тип Булево).

  1. Создаем роль, которая имеет право изменять этот реквизит.
  2. Для обычных пользователей настраиваем RLS (Record Level Security) на чтение и изменение только тех записей, где СозданоАдминистратором = Истина.
  3. В модуле набора записей прописываем логику: при создании новой записи обычным пользователем поле СозданоАдминистратором всегда устанавливается в Ложь.

В итоге: обычный пользователь сможет создать запись, но она тут же "исчезнет" для него (или он получит ошибку доступа при сохранении), так как у него нет прав на работу с неутвержденными данными. Изменять же записи, которые предварительно создал и "утвердил" администратор, он сможет без проблем.

Способ 4. Вынос логики в привилегированную обработку

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

  1. Убираем у роли пользователя право Запись для регистра.
  2. Создаем обработку с табличной частью, имитирующей регистр.
  3. При сохранении данных в обработке вызываем серверную процедуру в привилегированном модуле.
  4. В этой процедуре программно открываем набор записей, находим нужную строку по измерениям и меняем ресурсы.

Пример кода в привилегированном модуле:


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

Резюме

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

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

← На главную