Как исправить исчезновение полей в динамическом списке под неполноправным пользователем?

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

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

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

Почему пропадают поля: природа проблемы

Рассмотрим ситуацию на примере. У нас есть динамический список, который выбирает данные из регистра сведений ОбъектыИнтегрированныеС1СДокументооборотом. В этом регистре есть измерение Объект, имеющее тип ЛюбаяСсылка. Это означает, что в поле может храниться ссылка на абсолютно любой документ или справочник системы.

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

  1. Анализирует все таблицы, которые входят в составной тип (в случае с ЛюбаяСсылка — это сотни таблиц).
  2. Проверяет наличие прав Чтение и, что критично для динамического списка, прав на Просмотр для каждого из этих типов.
  3. Если у пользователя отсутствуют права хотя бы на один тип, входящий в состав поля ЛюбаяСсылка, или если механизмы RLS накладывают сложные ограничения на связанные таблицы, платформа может принять решение скрыть данные этого поля для обеспечения безопасности.

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


ВЫБРАТЬ
    ОбъектыИнтегрированныеС1СДокументооборотом.Объект КАК ОбъектИС,
    ОбъектыИнтегрированныеС1СДокументооборотом.ИдентификаторОбъектаДО КАК ИдентификаторОбъектаДО
ПОМЕСТИТЬ вт
ИЗ
    РегистрСведений.ОбъектыИнтегрированныеС1СДокументооборотом КАК ОбъектыИнтегрированныеС1СДокументооборотом
ГДЕ
    ОбъектыИнтегрированныеС1СДокументооборотом.Объект ССЫЛКА Документ.ПриобретениеТоваровУслуг
;

ВЫБРАТЬ
    вт.ОбъектИС КАК ОбъектИС,
    СостоянияСогласованияВДокументообороте.Состояние КАК Состояние
ИЗ
    вт КАК вт
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСогласованияВДокументообороте КАК СостоянияСогласованияВДокументообороте
    ПО (СостоянияСогласованияВДокументообороте.ИдентификаторОбъектаДО = вт.ИдентификаторОбъектаДО)

Несмотря на то, что мы явно ограничили выборку типом Документ.ПриобретениеТоваровУслуг через оператор ССЫЛКА, для платформы поле ОбъектИС все равно остается «подозрительным» составным типом. Под пользователем «Бухгалтер» поле Состояние (перечисление) может исчезать, так как оно связано через цепочку соединений с объектом неопределенного типа.

Решение 1: Использование конструкции ВЫБОР КОГДА для типизации

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

Выясним, как изменится наш запрос:


ВЫБРАТЬ
    вт.ОбъектИС КАК ОбъектИС,
    ВЫБОР
        КОГДА СостоянияСогласованияВДокументообороте.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.НеСогласован)
            ТОГДА ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.НеСогласован)
        КОГДА СостоянияСогласованияВДокументообороте.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.НаСогласовании)
            ТОГДА ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.НаСогласовании)
        КОГДА СостоянияСогласованияВДокументообороте.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.Согласован)
            ТОГДА ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.Согласован)
        ИНАЧЕ ЗНАЧЕНИЕ(Перечисление.СостоянияСогласованияВДокументообороте.ПустаяСсылка)
    КОНЕЦ КАК Состояние
ИЗ
    вт КАК вт
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСогласованияВДокументообороте КАК СостоянияСогласованияВДокументообороте
    ПО вт.ИдентификаторОбъектаДО = СостоянияСогласованияВДокументообороте.ИдентификаторОбъектаДО

Почему это работает? Используя ВЫБОР КОГДА, мы фактически создаем «вычисляемое поле». Платформа при генерации SQL-запроса видит конкретные значения перечисления, и механизмы автоматического скрытия составных типов перестают блокировать вывод всей колонки. Мы как бы «обманываем» систему оптимизации прав, предоставляя ей уже готовый результат сопоставления.

Решение 2: Приведение типов через ВЫРАЗИТЬ

Более правильным с точки зрения производительности и архитектуры 1С является использование оператора ВЫРАЗИТЬ. Если мы знаем, что в рамках данного динамического списка нас интересуют только конкретные типы документов, мы должны явно сообщить об этом платформе.

Проанализируем ситуацию: если поле имеет тип ЛюбаяСсылка, платформа пытается соединиться со всеми таблицами БД. Если мы напишем ВЫРАЗИТЬ(Поле КАК Документ.ПриобретениеТоваровУслуг), список таблиц для проверки прав сократится до одной.

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


ВЫБРАТЬ
    ВЫРАЗИТЬ(ОбъектыИнтегрированныеС1СДокументооборотом.Объект КАК Документ.ПриобретениеТоваровУслуг) КАК ОбъектИС,
    ОбъектыИнтегрированныеС1СДокументооборотом.ИдентификаторОбъектаДО КАК ИдентификаторОбъектаДО
ИЗ
    РегистрСведений.ОбъектыИнтегрированныеС1СДокументооборотом КАК ОбъектыИнтегрированныеС1СДокументооборотом
ГДЕ
    ОбъектыИнтегрированныеС1СДокументооборотом.Объект ССЫЛКА Документ.ПриобретениеТоваровУслуг

Этот метод позволяет избежать избыточных проверок RLS и часто возвращает «пропавшие» колонки на место.

Решение 3: Проверка прав «Просмотр»

Иногда корень проблемы лежит не в запросе, а в настройках ролей. Важно помнить различие:

Если у пользователя есть право на чтение документа ПриобретениеТоваровУслуг, но в роли снята галочка Просмотр, динамический список скроет это поле. Проверьте роли пользователя и убедитесь, что право просмотра дано как на сами объекты, так и на используемые в соединениях регистры и перечисления.

Решение 4: Установка основной таблицы

В настройках динамического списка (свойство ОсновнаяТаблица) крайне желательно указывать конкретную таблицу метаданных. Если основная таблица не задана, платформа применяет максимально жесткие правила проверки прав ко всем источникам в запросе. Установка основной таблицы позволяет системе оптимизировать запросы к данным и правам доступа, что часто решает проблему «невидимых» колонок.

Дополнительные советы

Если вышеперечисленные методы не помогают, можно прибегнуть к следующим приемам:

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

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

← На главную