Привет!

Имеет место быть следующая ситуация.
Ваня уходит в отпуск (на больничный, в командировку едет и т.п.) и на время отсутствия Вани его обязанности выполняет Петя. Но так получается, что у Вани доступ в 1С шире, чем у Пети, т.е. если говорить более предметно - то ролей у него в 1С больше, чем у Пети. Но на время его отсутствия Пете нужно дать те роли, которые стоят у Вани.

Что имеем "из коробки"?
Назначаем Пете роли, где-то записываем себе (или запоминаем) когда их у него требуется отобрать. Но часто про это забывается и в контексте 1С Петя становится Ваней. Непорядок.

Что надо?
Было бы хорошо, если бы была возможность назначать роли по расписанию: кому когда дать, когда забрать.

Как сделать?
Добавляем в систему перечисление ДействияИзмененияРолей со значениями Добавить, Убрать.

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

Добавляем регламентное задание, которое выполняет следующий код:

Процедура ИзменениеРолейПользователей() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
    Запрос.Текст =
    "ВЫБРАТЬ
    |    РасписаниеИзмененияРолейПользователейСрезПоследних.Период,
    |    РасписаниеИзмененияРолейПользователейСрезПоследних.ИмяПользователя КАК ИмяПользователя,
    |    РасписаниеИзмененияРолейПользователейСрезПоследних.Роль,
    |    РасписаниеИзмененияРолейПользователейСрезПоследних.Действие
    |ИЗ
    |    РегистрСведений.РасписаниеИзмененияРолейПользователей.СрезПоследних(&ТекущаяДата, ) КАК РасписаниеИзмененияРолейПользователейСрезПоследних
    |ГДЕ
    |    НЕ РасписаниеИзмененияРолейПользователейСрезПоследних.Выполнено
    |ИТОГИ ПО
    |    ИмяПользователя";
    
    Выборка0 = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока Выборка0.Следующий() Цикл
        
        ПользовательИБ = Неопределено;
        Попытка
            ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(СокрЛП(Выборка0.ИмяПользователя));
        Исключение
            Прервать;
        КонецПопытки;
        
        Если ПользовательИБ = Неопределено Тогда
            Возврат;
        КонецЕсли;
        
        РолиПользователя = ПользовательИБ.Роли;
        
        Выборка1 = Выборка0.Выбрать();
        Пока Выборка1.Следующий() Цикл
            
            Роль = Метаданные.Роли.Найти(Выборка1.Роль);
            Если Роль = Неопределено Тогда
                Возврат;
            КонецЕсли;
            
            Если Выборка1.Действие = Перечисления.ДействияИзмененияРолей.Добавить Тогда
                Если НЕ РолиПользователя.Содержит(Роль) Тогда
                    РолиПользователя.Добавить(Роль);
                КонецЕсли;
            ИначеЕсли Выборка1.Действие = Перечисления.ДействияИзмененияРолей.Убрать Тогда
                Если РолиПользователя.Содержит(Роль) Тогда
                    РолиПользователя.Удалить(Роль);
                КонецЕсли;
            КонецЕсли;
            
            Запись = РегистрыСведений.РасписаниеИзмененияРолейПользователей.СоздатьМенеджерЗаписи();
            Запись.Период = Выборка1.Период;
            Запись.ИмяПользователя = Выборка1.ИмяПользователя;
            Запись.Роль = Выборка1.Роль;
            Запись.Прочитать();
            Запись.Выполнено = Истина;
            Запись.Записать(Истина);
        КонецЦикла;
        
        ПользовательИБ.Записать();
        
    КонецЦикла;
    
КонецПроцедуры


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

Этим можно было бы ограничиться. Но мы же делаем всё для людей, верно? Поэтому для удобства работы добавляем в наш регистр форму записи. В моем случае это управляемая форма, но в обычной суть такая же.

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

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    ТекущийОбъект.ИмяПользователя = Пользователь.Код;
    
КонецПроцедуры


Наводим красоту дальше. В поле Роль назначаем обработчик события НачалоВыбора:

&НаКлиенте
Процедура РольНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ДанныеВыбора = ПолучитьСписокРолей();
    
КонецПроцедуры

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


Таким образом роль мы теперь тоже выбираем из списка, а не заносим руками.

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

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    Пользователь = Справочники.Пользователи.НайтиПоКоду(Запись.ИмяПользователя);
    
КонецПроцедуры


Всё что выше было написано - должно работать на любой типовой конфигурации. На любой не типовой будет работать если там есть справочник Пользователи и процесс авторизации и работа с этим справочником происходит как в типовой. Но даже если это не так - то не составит труда адаптировать вышенаписанное под свой конкретный случай.

Спасибо за внимание.