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