Как автоматически предоставлять и ограничивать права пользователей в 1С по расписанию (в выходные и праздничные дни)?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

В практике администрирования систем на платформе «1С:Предприятие» часто возникает классическая дилемма: менеджерам по продажам или операторам склада периодически требуется расширенный доступ в базу (например, для проведения документов задним числом, изменения цен или отгрузки без предоплаты). Особенно остро эта проблема встает в выходные и праздничные дни, когда ответственных руководителей нет на рабочем месте, а бизнес-процессы не должны останавливаться. Ручное переключение ролей системным администратором каждую пятницу вечером и каждый понедельник утром — крайне неэффективный процесс, требующий автоматизации.

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

Особенности платформы 1С, о которых важно знать заранее

Перед тем как приступать к написанию кода или созданию регламентных заданий, необходимо учесть фундаментальные технические особенности работы платформы «1С:Предприятие 8» с правами доступа:

  1. Кэширование ролей при запуске сеанса. Платформа считывает состав ролей пользователя исключительно в момент инициализации сеанса (при входе в программу). Если регламентное задание добавит пользователю роль в субботу в 00:01, а сам пользователь оставил сеанс запущенным с вечера пятницы, новые права у него не появятся до тех пор, пока он полностью не перезапустит программу. Аналогично, если в понедельник утром у него заберут роль, он сможет продолжать работать с повышенными правами в рамках старого открытого сеанса.
  2. Конфликт с механизмами БСП (Библиотеки стандартных подсистем). В современных конфигурациях (например, ERP, КА 2, УТ 11, БП 3.0) прямое изменение ролей у объекта ПользовательИнформационнойБазы через конфигуратор или программно приведет к тому, что БСП при ближайшем обновлении или входе пользователя автоматически сотрет эти изменения. В БСП права определяются через справочник ГруппыДоступа. Программное изменение прав должно производиться только через работу с объектами БСП.
  3. Производственный календарь. Простое использование функции ДеньНедели() не учитывает государственные праздники и переносы рабочих дней (например, когда суббота объявляется рабочей, а понедельник — выходным). Для корректного определения выходных дней необходимо использовать данные производственного календаря.

Ниже мы подробно разберем четыре основных метода автоматизации этого процесса.


Решение 1: Две учетные записи для одного сотрудника (Организационно-технический метод)

Этот метод является самым простым в реализации и не требует внесения масштабных изменений в конфигурацию. Мы создаем для сотрудника две учетные записи в справочнике «Пользователи»:

Чтобы избежать злоупотреблений (когда сотрудник заходит под «выходной» учетной записью в обычный рабочий день), мы добавим жесткую проверку времени входа.

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


Процедура ПередНачаломРаботыСистемы(Отказ)
    
    ТекущееИмяПользователя = ИмяПользователя();
    
    // Проверяем, является ли пользователь "выходным" по суффиксу в имени
    Если Найти(ТекущееИмяПользователя, "(Выходной день)") > 0 Тогда
        
        // Определяем текущий день недели
        ТекущаяДата = ТекущаяДата();
        НомерДняНедели = ДеньНедели(ТекущаяДата);
        
        // Разрешаем вход только в субботу (6) и воскресенье (7)
        Если НомерДняНедели < 6 Тогда
            Предупреждение("Вход под учетной записью выходного дня разрешен только в субботу и воскресенье!");
            Отказ = Истина;
            Возврат;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Преимущества метода: Простота реализации, отсутствие необходимости динамически менять структуру прав пользователей в базе данных, нет проблем с кэшированием ролей.

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


Решение 2: Динамический RLS через параметры сеанса (Оптимальный технический метод)

Если мы хотим решить задачу изящно и прозрачно для пользователя (чтобы он работал под своей единственной учетной записью), лучшим решением будет использование механизма RLS (ограничение доступа на уровне записей) совместно с параметрами сеанса.

Использование функции ТекущаяДата() непосредственно в шаблонах ограничений RLS крайне негативно сказывается на производительности СУБД. Проанализируем правильный подход: мы будем вычислять доступность прав при старте сеанса и записывать результат в булевый параметр сеанса, который затем использует быстрый шаблон RLS.

Разберем по шагам реализацию этого метода:

Шаг 1. В конфигураторе создадим новый параметр сеанса с именем РазрешеноРедактированиеВВыходные (тип: Булево).

Шаг 2. В модуле сеанса в процедуре УстановкаПараметровСеанса напишем код инициализации этого параметра. Мы будем проверять текущий день недели и сверяться с производственным календарем:


Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
    
    // Инициализируем параметр по умолчанию как Ложь
    ПараметрыСеанса.РазрешеноРедактированиеВВыходные = Ложь;
    
    // Проверяем, входит ли пользователь в список тех, кому разрешен доступ в выходные
    ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
    
    // Для примера проверим роль пользователя. 
    // Если у пользователя есть роль "МенеджерПоПродажам", проверяем дату
    Если РольДоступна("МенеджерПоПродажам") Тогда
        
        ТекущаяДата = ТекущаяДата();
        ДеньНедели = ДеньНедели(ТекущаяДата);
        
        // Если сегодня суббота или воскресенье
        Если ДеньНедели = 6 Или ДеньНедели = 7 Тогда
            ПараметрыСеанса.РазрешеноРедактированиеВВыходные = Истина;
        Иначе
            // Дополнительно проверим производственный календарь из базы данных
            // (если в вашей конфигурации есть такой регистр)
            ПараметрыСеанса.РазрешеноРедактированиеВВыходные = ПроверитьПраздникПоКалендарю(ТекущаяДата);
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Шаг 3. В правах нужной роли (например, роли, ограничивающей изменение документов прошлых периодов) пропишем условие RLS на чтение/изменение для защищаемых объектов:

ГДЕ &РазрешеноРедактированиеВВыходные = ИСТИНА

Это условие отрабатывает на стороне СУБД мгновенно, не перегружая систему и не вызывая задержек при чтении списков документов.


Решение 3: Программное переключение ролей через регламентные задания

Если нам требуется именно физическое добавление и удаление ролей (или групп доступа БСП) у пользователей по расписанию, мы можем реализовать регламентное задание, которое будет запускаться дважды в неделю: в ночь на субботу (для включения прав) и в ночь на понедельник (для их отключения).

Рассмотрим более современный и правильный вариант для конфигураций на БСП — динамическое добавление пользователя в специальную Группу доступа.

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


Процедура УправлениеПравамиВыходногоДня(РежимВключения) Экспорт
    
    // Находим предопределенную или созданную заранее группу доступа
    ГруппаВыходногоДня = Справочники.ГруппыДоступа.НайтиПоНаименованию("Доступ в выходные дни");
    
    Если ГруппаВыходногоДня.Пустая() Тогда
        ЗаписьЖурналаРегистрации("Управление правами", УровеньЖурналаРегистрации.Предупреждение, , , 
            "Группа доступа 'Доступ в выходные дни' не найдена!");
        Возврат;
    КонецЕсли;
    
    ГруппаОбъект = ГруппаВыходногоДня.ПолучитьОбъект();
    
    // Нам нужен список пользователей, которым разрешено давать эти права
    // Будем использовать созданный нами ранее Регистр Сведений "ПользователиДляВыдачиРолей"
    СписокРазрешенныхПользователей = ПолучитьСписокРазрешенныхПользователей();
    
    Если РежимВключения Тогда
        // Добавляем пользователей в группу доступа
        Для Каждого ТекущийПользователь Из СписокРазрешенныхПользователей Цикл
            
            СтрокаПользователя = ГруппаОбъект.Пользователи.Найти(ТекущийПользователь, "Пользователь");
            Если СтрокаПользователя = Неопределено Тогда
                НоваяСтрока = ГруппаОбъект.Пользователи.Добавить();
                НоваяСтрока.Пользователь = ТекущийПользователь;
                
                ЗаписьЖурналаРегистрации("Управление правами", УровеньЖурналаРегистрации.Информация, , , 
                    "Пользователю " + ТекущийПользователь + " временно предоставлены права выходного дня.");
            КонецЕсли;
            
        КонецЦикла;
    Иначе
        // Понедельник: полностью очищаем таблицу пользователей в этой группе доступа
        ГруппаОбъект.Пользователи.Очистить();
        ЗаписьЖурналаРегистрации("Управление правами", УровеньЖурналаРегистрации.Информация, , , 
            "Временные права выходного дня у всех пользователей аннулированы.");
    EndIf;
    
    ГруппаОбъект.Записать();
    
    // Решаем проблему кэширования сеансов: принудительно завершаем активные сеансы этих пользователей,
    // чтобы они зашли заново и получили новые права
    ЗавершитьАктивныеСеансыПользователей(СписокРазрешенныхПользователей);
    
КонецПроцедуры

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


Процедура ЗавершитьАктивныеСеансыПользователей(СписокПользователей)
    
    СеансыИнформационнойБазы = ПолучитьСеансыИнформационнойБазы();
    
    Для Каждого Сеанс Из СеансыИнформационнойБазы Цикл
        
        // Сверяем пользователя сеанса с нашим списком
        Если СписокПользователей.Найти(Сеанс.Пользователь) <> Неопределено Тогда
            // Исключаем текущий сеанс, под которым запущено само регламентное задание
            Если Сеанс.НомерСеанса <> НомерСеансаИнформационнойБазы() Тогда
                ЗавершитьСеансИнформационнойБазы(Сеанс);
            КонецЕсли;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важное примечание: Чтобы избежать потери несохраненных данных пользователями (если они работали в этот момент), рекомендуется запускать отключение прав глубокой ночью (например, в 03:00 ночи понедельника), когда активных пользователей гарантированно нет в системе.


Решение 4: Динамический обход ограничений через расширение конфигурации (Рекомендуемый метод без изменения прав)

Если база данных находится на поддержке и мы не хотим менять структуру ролей, групп доступа или создавать дублирующих пользователей, мы можем применить механизм расширений. Мы перехватим запись документов и будем временно включать привилегированный режим, если запись происходит в выходной день.

Рассмотрим пример реализации. Создадим расширение конфигурации и добавим в него обработчик события ПередЗаписью для необходимых документов (например, РеализацияТоваровУслуг):


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

Этот метод является наиболее безопасным и чистым с точки зрения архитектуры СУБД:


Сравнительный анализ решений

Подведем итоги и выберем оптимальный вариант в зависимости от условий работы вашей компании:

  1. Если у вас старая конфигурация (например, УПП 1.3 или УТ 10.3) без БСП: Проще всего использовать Решение 1 (две учетные записи) или написать регламентное задание по прямому добавлению ролей (аналогично Решению 3).
  2. Если у вас современная база на БСП и жесткие требования безопасности: Используйте Решение 4 (динамический обход через расширение с ведением логов в Журнале регистрации). Это гарантирует стабильность системы и защитит исторические данные от случайного удаления.
  3. Если требуется комплексное разграничение видимости данных (например, видеть определенные склады только по выходным): Используйте Решение 2 (динамический RLS через параметры сеанса).
← На главную