Как правильно заполнять реквизит табличной части при ограничении прав и когда нужен привилегированный режим в 1С?

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

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

Анализ механизма прав: «Редактирование» против «Изменения»

Для правильного проектирования логики важно четко разделять уровни контроля прав доступа, заложенные в платформе 1С:

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

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

Ошибки при передаче данных формы между клиентом и сервером

Рассмотрим типичную ошибку при вызове серверных процедур из клиентских обработчиков событий формы. Код клиента:


&НаКлиенте
Процедура ПереченьНоменклатурыНоменклатураПриИзменении(Элемент)
    СтрокаТабличнойЧасти = Элементы.ПереченьНоменклатуры.ТекущиеДанные;
    // Попытка передать строку формы на сервер вызывает ошибку типов
    УстановитьЦенуНаСервере(СтрокаТабличнойЧасти);
КонецПроцедуры

Переменная СтрокаТабличнойЧасти на клиенте имеет тип ДанныеФормыЭлементКоллекции. Данный тип нельзя напрямую передавать параметром в серверные процедуры с контекстом формы. Посмотрим на два корректных способа организации работы с табличной частью.

Способ 1. Получение значения функцией и присвоение на клиенте (Рекомендуемый)

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


&НаСервереБезКонтекста
Функция ПолучитьЦенуНоменклатуры(Знач Номенклатура, Знач ДатаДокумента)
    Возврат РаботаСоСправочниками.РозничнаяЦена(ДатаДокумента, Номенклатура);
КонецФункции

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

Способ 2. Поиск строки по идентификатору на сервере

Если требуется выполнить сложный комплексный расчет всей строки целиком на сервере формы, передадим числовой идентификатор текущей строки:


&НаКлиенте
Процедура ПереченьНоменклатурыНоменклатураПриИзменении(Элемент)
    ИдентификаторСтроки = Элементы.ПереченьНоменклатуры.ТекущаяСтрока;
    Если ИдентификаторСтроки <> Неопределено Тогда
        ЗаполнитьСтрокуНаСервере(ИдентификаторСтроки);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьСтрокуНаСервере(ИдентификаторСтроки)
    СтрокаТабличнойЧасти = Объект.ПереченьНоменклатуры.НайтиПоИдентификатору(ИдентификаторСтроки);
    Если СтрокаТабличнойЧасти <> Неопределено Тогда
        СтрокаТабличнойЧасти.Цена = РаботаСоСправочниками.РозничнаяЦена(Объект.Дата, СтрокаТабличнойЧасти.Номенклатура);
        СтрокаТабличнойЧасти.Сумма = СтрокаТабличнойЧасти.Количество * СтрокаТабличнойЧасти.Цена;
    КонецЕсли;
КонецПроцедуры

Способ 3. Управление доступностью элементов через свойства формы

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


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

Как поступить, если право «Изменение» полностью отключено в роли?

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

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

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