Блокировка поля в карточке документа или справочника. Не ахти-какая наука, но если у вас 67 реквизитов для 9 групп пользователей при 4 разных ролях, то это весьма упрощает жизнь:
Итак, что нам необходимо для решения этой задачи? Да всего ничего - 2 параметра!
Собственно этого хватит, чтобы собрать себе 2 функции для работы. Можно заморочиться и сделать все в одной, но зачем если это требуется не так уж и часто?
Итак, с чего мы начнем? Если вы никогда не создавали функции, то это дело увлекательное и полезное как в плане работы, так и опыта. Открываем Компоненты - Утилиты разработчика - Функции ISBL. Далее создаем новую Функцию и даем ей имя, и определяем ее группу. Я дал функциям названия ButtonOR и ControlOR где OR - Only Read, и внес их в группу "Работа с правами доступа". Вы можете сделать и иначе.
Далее нам надо создать три параметра:
После сохранения нового элемента, мы заходим в раздел "Текст". Теперь мы находимся в закромах нашей функции, в ее "Сердце", где и дадим описание действия.
Для Кнопки, мы должны определить элемент формы при помощи команды: "Form = Object.Form" и "Action = Form.Actions".
Для поля карточки, нам и этого делать не нужно, так как мы будем обращаться к имени Реквизита.
Наше "определение" указывает на активные элементы формы карточки, но для конкретизации элемента, нам надо указать на его имя (Имя кнопки или Поля), которое мы будем передавать через параметр Button или ContrPol. В них мы будем использовать следующий Код:
Для Кнопки: Action.FindAction(Button).Visible
Для Поля: Book.Requisites(ContrPol).CanGUIWrite
Теперь, осталось применить наш последний параметр (OnlRead), что по-умолчанию = FALSE (Ложь). Он нам нужен, чтобы было удобнее откатывать наши блокировки назад, простой сменой FALSE на TRUE и обратно.
Составляем элементарную проверку на равенство FALSE для определения действия: "if OnlRead" и на выходе получаем функцию для "Сокрытия кнопки":
Form = Object.Form
Action = Form.Actions
if OnlRead
Action.FindAction(Button).Visible = TRUE //Если "Правда" (TRUE) - кнопка видимая
else
Action.FindAction(Button).Visible = FALSE //Если "Ложь" (FALSE) - кнопка НЕ Видимая
endif
Или еще короче:
Form = Object.Form
Action = Form.Actions
Action.FindAction(Button).Visible = not OnlRead
И Функцию по блокировки полей карточки:
if OnlRead
Object.Requisites(ContrPol).CanGUIWrite = True //Если не TRUE - Поле Блокировано
else
Object.Requisites(ContrPol).CanGUIWrite = False //Если FALSE - Поле Доступное
endif
Или еще короче и изящнее:
Object.Requisites(ContrPol).CanGUIWrite = OnlRead
Теперь в нашем коде, достаточно написать "ButtonOR(Object;"InsertUpdateDB";TRUE)" для удаления с глаз кнопки, или наоборот "ButtonOR(Object;"InsertUpdateDB")" для ее возвращения на карточку.
И для Полей то же самое "ControlOR(Object;"Дополнение";TRUE)" и "ControlOR(Object;"Дополнение")".
А если вам необходимо сделать эту операцию не один десяток раз, то вам сильно поможет следующий код:
RequisitesTabMain = 'LongString;Дата5;' &
'Дополнение;Депозитарий;ДаНет1;Наименование;ВеселенькиПример'
foreach ReqName in CSubString(RequisitesTabMain; ';')
ControlOR(Object;ReqName) // Или ControlOR(Object;ReqName;TRUE)
endforeach
Данный пример специально расписан немного коряво, чтобы было видно более отчетливо, что наполнение Переменной "RequisitesTabMain" строками (LongString; Дата5; Дополнение; Депозитарий; ДаНет1; Наименование; ВеселенькиПример), может быть очень длинным с переносами и так далее.
В любом случае, это не сложный и довольно легкий пример, которого многим не хватает в первые годы работы или при работе с постоянными проверками на доступы. Если кому интересно как резать доступы, то вот вам небольшая подборочка примеров реализации с применением вышеназванных Функций:
CurrentUser = ServiceFactory.GetUserByName(Application.Connection.UserName) // Опреледеляем User`а
//Далее вычислим Роли с повышенными приоритетами, например Финансового Директора и Бухгалтера:
FinDir = ServiceFactory.GetRoleMembers(ServiceFactory.GetRoleByName('ФинДир'); NIL)
BuchRole = ServiceFactory.GetRoleMembers(ServiceFactory.GetRoleByName('Бухгалтер'); NIL)
// Ну и сразу проверим, вхож ли пользователь в эти роли (Это можно сделать и потом)
IsFinDir = FinDir.Find(CurrentUser)
IsBuch = BuchRole.Find(CurrentUser)
//Теперь Фильтруем постепенно срезая права в карточке:
if CurrentUser.UserType = utAdministrator // Проверяем: Админ ли это
MessageBox("InfoBox";"Добро пожаловать, Админ!") //По сути, ничего не делаем, это же Админ.
else // А что если это не Админ?
ButtonOR(Object;"Delete";TRUE) // Сразу срезаем кнопку на удаление
if ServiceFactory.GetGroupMembers(ServiceFactory.GetGroupByName('Bro')).Find(CurrentUser)
// Проверяем, входит ли пользователь в группу BRO, если да, то приветствуем его:
MessageBox("InfoBox";"Привет, Бро!")
ButtonOR(Object;"UpdateDate";TRUE) // Бро, конечно нам друг, но даты менять ему нельзя!
else
if IsFinDir or IsBuch
// Проверяем, ФинДир это или Бухгалтер, если да, то просто убираем ненужные им поля:
ControlOR(Object;"Tdate";TRUE) // Пример без шутки
ControlOR(Object;"FinansyD";TRUE) // Пример без шутки
else
// Всем остальным - рубим права без жалости:
RequisitesTabMain = 'PMSourcers;T8BookDirection;Работник;ДаНет2;' &
'PMProductType;ДаНет22;PMConnectionType;PMBook3;LongString;Дополнение;PMGenres1Level;' &
'PMEditionType;ИДСпр;PMPublishingHouse;Город;PMYear;LongString2;' &
'PMAgeRestrictions;PMGenres2Level;Дата25;Дата26;PMPrintKind;Дата16;' &
'ДаНет28;Текст2;Tekst4;ДаНет3;PMLanguages;ДаНет8;PMMultivolumeEdition;Дополнение4'
foreach ReqName in CSubString(RequisitesTabMain; ';')
ControlOR(Object;ReqName;TRUE)
endforeach
endif
endif
endif
Понятно, что это просто грубые примеры, по которым несложно понять всю эту кухню. В реальности все эти параметры надо не только описать грамотно, но и расположить верно, чтобы не возникали конфликты в работе кода, чтобы сотрудник с повышенными правами не страдал от того, что находится ниже иного уполномоченного.
Но в целом - всего что написано выше, вполне достаточно, чтобы начать работу по разграничению прав в любой из карточек СЭД Директум.
P.S.: Касательно создания чего-то нового - не забывайте писать комментарии в структуре кода. Подумайте о себе и о том, кто будет разбираться в вашем коде после вас.
Самая частая ошибка новичков, на моем опыте, при блокировке полей - это прописывание блокировки, но не прописывание разблокировки
Что то вроде этого (на событии форма показ):
Проблема такого кода в том, что у справочников может быть много записей, но форма одна. В буквальном смысле для набора данных с несколькими записями используется один объект формы, в который только подставляются данные. И если мы для первой записи справедливо заблокировали поле, а потом нажмем стрелочку (или pageDown), перейдем на следующую запись, а в ней, например, не нужно блокировать это поле, то оно останется заблокированным.
Помимо явной блокировки, когда нет прав нужно всегда прописывать явную разблокировку, если права есть.
Ну в принципе логично, если предполагать изменение прав. В примере показана ситуация:
1. Можно все и всем
2. Если ты Админ, то все так и остается
3. Если ты не Админ - будем срезать ваши права.
Варианта, что данные уже могут быть заблокированы, я и не вносил в данной статье.
Блокировки, конечно же, используются шире, чем: "Если не админ, то срезаем права"
Например, разрешить автору менять свою карточку, а остальным дать только просмотр - весьма распространенный кейс.
у нас в ряде записей некоторые поля блокируются в зависимости от того, на каком этапе согласования находится документ, это помимо блокировки по группам пользователей
Делал как-то раз подобный функционал. Задача состояла в том, чтобы менять состояния контролов на форме в зависимости от нескольких одновременно влияющих факторов, как то: роль пользователя в процессе, этап согласования, комбинации данных в карточке, наличие/отсутствие замещения.
В итоге, чтобы не писать монструозный код с просчетом всех комбинаций, сделал следующий механизм расчета прав:
И запускается собственно сам расчет прав доступа, который обрабатывает списки правил и реквизитов и для каждого реквизита устанавливает доступ согласно принципу - если текущему пользователю разрешен доступ к реквизиту по всем спискам правил, влияющим на реквизит (по сути - производится перемножение состояний), то реквизит включается, иначе реквизит отключается.
Ну, я в свое время даже кнопку винтил для расширения прав с указанием причины доступа и записью этого действия. Сотрудники группы Аудита потом смотрели эти записи и делали выводы. Ну там не ахти какая задумка была, но сам факт второй линии контроля немного дисциплинировала. Плюс к этой кнопке тоже не каждый доступ имел (Не все ее видели).
Я еще забыл такую полезную штуку как официальное сокрытие информации (CanGUIRead ):
После такого, поле будет выглядеть так:
А так да, как писал выше Михаил Тарасов:
Кейс на открытые данные для Автора, Админа и конкретной группы -
Авторизуйтесь, чтобы написать комментарий