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