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

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

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

Суть проблемы и исходная ситуация

Рассмотрим практический сценарий. В документе ЗаказПокупателя необходимо разрешить пользователям со специальной ролью БИТ_СТ_Дедактор изменять реквизит ДатаРезерва в табличной части Товары, даже если дата документа меньше текущей даты (то есть заказ был создан «задним числом» или в прошлых периодах). Для обычных операторов такое изменение должно быть заблокировано.

Разработчик добавил проверку прав в процедуру ПриОткрытии формы документа, однако столкнулся с тем, что система либо выдает ошибку и блокирует форму, либо (после изменения кода) открывает форму без ошибок, но табличная часть всё равно остается недоступной для редактирования.

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

---

Анализ логической ошибки в проверке прав

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


Если (НЕ БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПравоАдминистратор1С) 
   ИЛИ (НЕ БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПраво("БИТ_СТ_Дедактор")) Тогда

Проанализируем работу этого условия с точки зрения алгебры логики. Здесь используется оператор ИЛИ совместно с отрицанием НЕ. Согласно законам де Моргана, выражение (НЕ А) ИЛИ (НЕ Б) эквивалентно выражению НЕ (А И Б). Это означает, что условие вернет значение Ложь только в одном единственном случае — когда у текущего пользователя есть обе роли одновременно (и Администратор, и Дедактор).

Если у пользователя есть роль БИТ_СТ_Дедактор, но нет роли ЕстьПравоАдминистратор1С, то выражение вычисляется так:

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

Правильный вариант написания условия: необходимо проверять, что у пользователя отсутствует и та, и другая роль. Это можно записать двумя способами:


// Вариант 1: Использование оператора "И" для отрицаний
Если (НЕ БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПравоАдминистратор1С) 
   И (НЕ БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПраво("БИТ_СТ_Дедактор")) Тогда

Или более лаконично:


// Вариант 2: Отрицание общей группы условий с оператором "ИЛИ"
Если НЕ (БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПравоАдминистратор1С 
   ИЛИ БИТ_СТ_ПовторноеИспользованиеЗначений.ЕстьПраво("БИТ_СТ_Дедактор")) Тогда

---

Почему табличная часть остается недоступной после исправления кода?

Допустим, логическая ошибка в коде исправлена, и условие больше не блокирует табличную часть при открытии формы. Однако пользователь с ролью БИТ_СТ_Дедактор всё равно не может отредактировать реквизиты. Разберем скрытые механизмы платформы «1С:Предприятие» и типовых конфигураций, которые вызывают эту проблему.

1. Платформенное свойство «ТолькоПросмотр» всей формы. Если в процессе работы других процедур (например, общих механизмов УПП при проверке даты запрета изменения данных) всей форме было присвоено свойство ЭтаФорма.ТолькоПросмотр = Истина, то изменить доступность подчиненных элементов управления невозможно. Любые попытки написать ЭлементыФормы.Товары.ТолькоПросмотр = Ложь будут проигнорированы платформой, пока форма заблокирована целиком.

2. Право «Интерактивное изменение проведенных» в конфигураторе. Поскольку документ ЗаказПокупателя уже проведен (на что указывает проверка Если Проведен Тогда), платформа 1С на уровне ролей и прав доступа проверяет у пользователя право на изменение проведенных документов. Если у роли БИТ_СТ_Дедактор в конфигураторе для объекта Документ.ЗаказПокупателя не взведен флаг Интерактивное изменение проведенных, форма откроется в режиме «Только просмотр» автоматически, независимо от любого программного кода в модуле формы.

3. Кэширование прав в модулях с повторным использованием значений. Функции проверки прав часто размещают в модулях с повторным использованием возвращаемых значений (например, БИТ_СТ_ПовторноеИспользованиеЗначений). Если администратор добавил роль пользователю «на лету» в режиме Конфигуратора, изменения не вступят в силу для текущего сеанса пользователя. Более того, закэшированные функции модуля будут возвращать старое значение Ложь. Требуется обязательный перезапуск сеанса «1С:Предприятия» пользователем.

---

Пошаговое руководство по решению задачи

Чтобы предоставить пользователям с ролью БИТ_СТ_Дедактор возможность выборочного редактирования реквизита ДатаРезерва в закрытом периоде или в проведенном документе, выполним следующие действия.

Шаг 1. Проверка настроек роли в конфигураторе

Откроем конфигуратор, найдем роль БИТ_СТ_Дедактор. В дереве объектов метаданных перейдем к документу ЗаказПокупателя и убедимся, что для него установлены следующие права:

Шаг 2. Разработка алгоритма в процедуре «ПриОткрытии»

Вместо полной блокировки формы или табличной части применим подход «мягкой блокировки». Разрешим редактирование формы в целом, но программно заблокируем все элементы управления формы, кроме табличной части Товары. А внутри табличной части сделаем доступной для изменения исключительно колонку ДатаРезерва.

Посмотрим на пример реализации такого алгоритма:


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

Проанализируем преимущества предложенного кода:

  1. Выборочная защита данных. Пользователь с ролью БИТ_СТ_Дедактор не сможет случайно или намеренно изменить ключевые реквизиты документа (контрагента, сумму, количество номенклатуры), так как они заблокированы на уровне элементов формы.
  2. Обход ограничений даты запрета. Установка свойства ЭтаФорма.ТолькоПросмотр = Ложь принудительно открывает форму для записи, а ручной обход элементов гарантирует, что регламентированные данные останутся в безопасности.
  3. Корректная обработка исключений. Попытка обращения к свойству ТолькоПросмотр у кнопок или панелей обернута в блок Попытка...Исключение, что предотвращает аварийное завершение работы программы при открытии формы.
← На главную