Как запретить редактирование реквизита в справочнике Должности, если на них работают сотрудники

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

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

Постановка задачи и выбор стратегии решения

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

  1. Визуальный контроль на уровне формы: Сделаем поле недоступным для редактирования при открытии карточки должности, если проверка показала наличие сотрудников.
  2. Контроль целостности данных на уровне объекта: Продублируем проверку в модуле объекта, чтобы предотвратить программное изменение данных через сторонние обработки или групповое изменение реквизитов.

Этап 1. Разработка функции проверки занятости должности

Для начала нам нужно создать эффективный механизм, который ответит на вопрос: «Работает ли кто-то на этой должности?». Рассмотрим, как правильно написать запрос. В обсуждении на форуме предлагалось обращаться к справочнику Сотрудники, однако более профессиональным подходом в современных конфигурациях будет обращение к кадровым регистрам или использование оптимизированного запроса к справочнику сотрудников с учетом особенностей платформы 8.3.

Проанализируем оптимальный код функции, которую следует разместить в модуле менеджера справочника или в привилегированном общем модуле:


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

Почему мы используем именно такой код?

Этап 2. Управление доступностью элементов на управляемой форме

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

В модуле формы элемента пропишем следующий код:


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

Разберем разницу между Доступность = Ложь и ТолькоПросмотр = Истина. В первом случае поле становится серым и его содержимое трудно прочитать. Во втором случае текст остается контрастным, его можно выделить и скопировать, но изменить нельзя. Для пользователя второй вариант предпочтительнее.

Этап 3. Учет прав доступа и использование привилегированного режима

Важный нюанс, который прозвучал в сообщениях форума — это ограничения RLS (Record Level Security). Если у пользователя, открывающего справочник должностей, нет прав на просмотр списка сотрудников определенных подразделений, обычный запрос вернет «пусто», даже если должность занята. В результате поле станет доступным, что является ошибкой безопасности.

Для решения этой проблемы функцию проверки необходимо выполнять в привилегированном режиме. Это позволит запросу игнорировать права доступа текущего пользователя и проверить реальное наличие записей в базе данных.


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

Этап 4. Защита на уровне модуля объекта

Чтобы гарантировать, что данные не будут изменены «в обход» формы, добавим проверку в модуль объекта. Рассмотрим ситуацию: программист запускает обработку «Групповое изменение реквизитов». Форма в этом случае не открывается, и наши визуальные ограничения не сработают. Чтобы этого избежать, используем событие ПередЗаписью.


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

Подведение итогов

Мы проанализировали комплексный подход к защите данных в 1С. Реализация задачи только через форму — это лишь верхушка айсберга. Для создания надежной системы мы объединили несколько техник:

Именно такое сочетание методов позволяет гарантировать стабильность учета и отсутствие ошибок при расчете взносов в крупных организациях с большим штатом сотрудников.

← На главную