Как реализовать отбор по состоянию оригинала первичного документа в динамическом списке 1С:ERP

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

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

Почему стандартный отбор выдает ошибку?

Проанализируем архитектуру динамического списка. Когда мы открываем список документов, платформа выполняет SQL-запрос к базе данных. Если поле «Состояние оригинала» в тексте запроса инициализировано как NULL, а его реальное значение рассчитывается или подтягивается позже (в момент отрисовки строк на форме), то для системы компоновки данных (СКД) этого поля «не существует» в контексте базы данных.

Важный момент: Отбор в динамическом списке — это не просто скрытие строк на клиенте, это модификация блока ГДЕ в SQL-запросе. Поскольку СУБД ничего не знает о данных, которые вы планируете вычислить в коде 1С, она не может выполнить фильтрацию. Поэтому нам нужно сделать это поле «осязаемым» для запроса.

Вариант 1. Соединение с регистром в тексте запроса

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

Вместо использования NULL, нам необходимо выполнить ЛЕВОЕ СОЕДИНЕНИЕ с этим регистром. Разберем пример кода для текста запроса:


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

После такого изменения поле СостояниеОригинала становится доступным для стандартных механизмов поиска и отбора. Однако помните, что в типовых решениях (БСП) это поле может добавляться динамически. В этом случае нам придется программно менять свойство ТекстЗапроса у объекта Список при создании формы.

Вариант 2. Двухэтапный отбор через список ссылок

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

Разберем алгоритм действий:

  1. Создадим на форме реквизит (например, ОтборСостояние) и выведем его в шапку формы.
  2. В обработчике события ПриИзменении этого реквизита напишем код для установки отбора.

Пример программной установки отбора:


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

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

Важное ограничение: Этот метод хорошо работает, когда количество документов с определенным состоянием не исчисляется сотнями тысяч. Если документов слишком много, SQL-запрос с условием IN (...) может работать медленно или вызвать ошибку переполнения параметров.

Вариант 3. Использование программного добавления поля в компоновщик

Проанализируем ситуацию, когда поле уже есть в запросе как NULL. Мы можем программно заменить этот фрагмент текста запроса перед открытием формы. Рассмотрим пример, как это сделать в процедуре ПриСозданииНаСервере:


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

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

Нюансы производительности и RLS

Выясним причину, почему разработчики 1С изначально не всегда включают это поле в запрос. Основная причина — производительность. Регистр состояний оригиналов может быть очень объемным. При использовании ЛЕВОЕ СОЕДИНЕНИЕ:

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

← На главную