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