Как запретить в СКД выбор конкретных подчиненных реквизитов?

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

При разработке отчетов на базе Системы компоновки данных (СКД) часто возникает задача предоставить пользователю гибкость выбора полей, но при этом ограничить доступ к некоторым конфиденциальным или тяжелым для СУБД реквизитам. Типичный пример: у нас есть поле ДокументОснование типа ДокументСсылка. Мы хотим разрешить пользователю выбирать любые дочерние реквизиты этого документа (например, контрагента, организацию, сумму), но запретить выбор конкретного реквизита — например, поля Дата.

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

Способ 1. Интерактивная настройка ограничений без отключения автозаполнения

Самый простой и изящный способ решить задачу — использовать штатные механизмы вкладки «Наборы данных» в конструкторе схемы компоновки данных. Многие разработчики ошибочно полагают, что при включенном флаге «Автозаполнение» мы не можем точечно управлять ограничениями подчиненных полей. Однако платформа позволяет переопределить настройки для любого конкретного пути к данным.

Рассмотрим по шагам, как заблокировать подчиненный реквизит ДокументОснование.Дата:

  1. Откроем схему компоновки данных и перейдем на вкладку «Наборы данных».
  2. В верхней правой части окна найдем таблицу полей нашего набора данных.
  3. Нажмем кнопку «Добавить новое поле» (иконка с зеленым плюсом).
  4. В созданной строке в колонке «Путь к данным» вручную введем точный путь к запрещаемому подчиненному реквизиту: ДокументОснование.Дата.
  5. В колонке «Поле» укажем точно такое же значение: ДокументОснование.Дата.
  6. В этой же строке найдем группу колонок «Ограничение поля» и установим флажки в колонках:
    • «Поле» (запрет выбора в качестве выводимого поля);
    • «Условие» (запрет использования в отборах);
    • «Группа» (запрет использования в группировках);
    • «Упорядочивание» (запрет сортировки по этому полю).

Как это работает: СКД автоматически анализирует структуру метаданных. Когда пользователь пытается развернуть поле ДокументОснование, система видит, что для конкретного пути ДокументОснование.Дата заданы персональные ограничения, которые имеют приоритет над общим автозаполнением. В результате поле Дата просто исчезнет из списка доступных для пользователя, тогда как все остальные реквизиты (ДокументОснование.Организация, ДокументОснование.Контрагент и т.д.) останутся доступными.

Способ 2. Программное ограничение в модуле объекта отчета

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

Разберем пример кода, который необходимо разместить в модуле объекта отчета в предопределенной процедуре ПриКомпоновкеРезультата:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Получаем первый набор данных (как правило, это запрос)
    НаборДанных = СхемаКомпоновкиДанных.НаборыДанных[0]; 
    
    // Проверим, не добавлено ли уже это ограничение ранее, чтобы избежать дублирования
    ИмяПоляДляПоиска = "ДокументОснование.Дата";
    ПолеУжеСуществует = Ложь;
    
    Для Каждого ПолеИзНабора Из НаборДанных.Поля Цикл
        Если ПолеИзНабора.ПутьКДанным = ИмяПоляДляПоиска Тогда
            НовоеПоле = ПолеИзНабора;
            ПолеУжеСуществует = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если Не ПолеУжеСуществует Тогда
        // Создаем новое описание поля в схеме компоновки
        НовоеПоле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
        НовоеПоле.ПутьКДанным = ИмяПоляДляПоиска;
        НовоеПоле.Поле         = ИмяПоляДляПоиска;
        НовоеПоле.Заголовок    = "Дата (скрыто)";
    КонецЕсли;
    
    // Устанавливаем жесткие ограничения на использование поля пользователем
    НовоеПоле.ОграничениеИспользования.Поле         = Истина;
    НовоеПоле.ОграничениеИспользования.Условие      = Истина;
    НовоеПоле.ОграничениеИспользования.Группировка  = Истина;
    НовоеПоле.ОграничениеИспользования.Упорядочивание = Истина;

КонецПроцедуры

Этот способ позволяет гибко управлять доступностью реквизитов «на лету», анализируя параметры сеанса, роли или настройки текущего пользователя.

Способ 3. Использование расширения языка запросов СКД в блоке {ВЫБРАТЬ}

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

Рассмотрим структуру такого запроса:


ВЫБРАТЬ
    Продажи.ДокументОснование КАК ДокументОснование,
    Продажи.ДокументОснование.Контрагент КАК Контрагент,
    Продажи.ДокументОснование.Организация КАК Организация
{ВЫБРАТЬ
    ДокументОснование,
    Контрагент,
    Организация}
ИЗ
    РегистрНакопления.Продажи КАК Продажи

Проанализируем этот метод. Его главное преимущество — жесткий контроль структуры запроса на уровне СУБД. Однако у него есть существенный недостаток, о котором упоминали участники обсуждения: нам приходится отказываться от автозаполнения для этой ветки метаданных. Если в конфигурацию будут добавлены новые реквизиты для документа-основания, они не появятся в отчете автоматически. Разработчику придется вручную корректировать текст запроса и секцию {ВЫБРАТЬ}.

Способ 4. Ограничение прав доступа (RLS)

Если поле Дата документа-основания вообще не должно фигурировать в отчетах конкретного пользователя по соображениям безопасности, правильным решением будет ограничение прав доступа на уровне платформы (Role-Based Security или RLS).

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

Важная уязвимость СКД: как не допустить обход ограничений через сохраненные настройки

Разберем критически важный нюанс поведения платформы 1С. Любые визуальные ограничения (установка флажков ограничений в схеме компоновки) влияют только на интерактивные действия пользователя в текущем сеансе. Они не дают выбрать поле в список выводимых или в отборы прямо сейчас.

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

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    ЗапрещенныйПуть = "ДокументОснование.Дата";
    
    // 1. Очищаем выбранные поля в основных настройках
    ОчиститьЗапрещенныеПоляВКоллекции(КомпоновщикНастроек.Настройки.Выбор.Элементы, ЗапрещенныйПуть);
    
    // 2. Очищаем отборы в основных настройках
    ОчиститьЗапрещенныеОтборы(КомпоновщикНастроек.Настройки.Отбор.Элементы, ЗапрещенныйПуть);
    
    // 3. Аналогично обрабатываем пользовательские настройки
    ОчиститьЗапрещенныеПоляВКоллекции(КомпоновщикНастроек.ПользовательскиеНастройки.Элементы, ЗапрещенныйПуть);

КонецПроцедуры

Процедура ОчиститьЗапрещенныеПоляВКоллекции(КоллекцияЭлементов, ЗапрещенныйПуть)
    
    Индекс = КоллекцияЭлементов.Количество() - 1;
    Пока Индекс >= 0 Цикл
        Элемент = КоллекцияЭлементов[Индекс];
        Если ТипЗв(Элемент) = Тип("ВыбранноеПолеКомпоновкиДанных") Тогда
            Если Строка(Элемент.Поле) = ЗапрещенныйПуть Тогда
                КоллекцияЭлементов.Удалить(Элемент);
            КонецЕсли;
        ИначеЕсли ТипЗв(Элемент) = Тип("ГруппаВыбранныхПолейКомпоновкиДанных") Тогда
            ОчиститьЗапрещенныеПоляВКоллекции(Элемент.Элементы, ЗапрещенныйПуть);
        КонецЕсли;
        Индекс = Индекс - 1;
    КонецЦикла;
    
КонецПроцедуры

Процедура ОчиститьЗапрещенныеОтборы(КоллекцияЭлементов, ЗапрещенныйПуть)
    
    Индекс = КоллекцияЭлементов.Количество() - 1;
    Пока Индекс >= 0 Цикл
        Элемент = КоллекцияЭлементов[Индекс];
        Если ТипЗв(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
            Если Строка(Элемент.ЛевоеЗначение) = ЗапрещенныйПуть Тогда
                КоллекцияЭлементов.Удалить(Элемент);
            КонецЕсли;
        ИначеЕсли ТипЗв(Элемент) = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
            ОчиститьЗапрещенныеОтборы(Элемент.Элементы, ЗапрещенныйПуть);
        КонецЕсли;
        Индекс = Индекс - 1;
    КонецЦикла;
    
КонецПроцедуры

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

UX-прием: скрытие полей в виртуальные папки служебных реквизитов

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

Для решения этой проблемы можно применить красивый интерфейсный прием — сгруппировать "лишние" реквизиты в специальную служебную папку:

  1. На вкладке «Наборы данных» нажмем кнопку «Добавить папку».
  2. Назовем созданную папку, например, ТехническиеРеквизиты.
  3. Перетащим туда подчиненные поля или укажем их путь к данным с префиксом папки (например, ТехническиеРеквизиты.ДокументОснованиеДата).

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

← На главную