Как в 1С убрать из списка справочника элементы с нулевым остатком на обычных формах

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

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

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

Почему возникает ошибка «Неправильный путь к данным»?

Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке программно подменить данные в табличном поле кодом ЭлементыФормы.ТабличноеПоле1.Данные = ТЗ система выдает ошибку. Это происходит потому, что в обычных формах элемент управления Табличное поле жестко связан с основным реквизитом формы (например, типом СправочникСписок.Товары). Объект СправочникСписок не является таблицей значений, это специальный динамический объект, который сам считывает данные из базы порциями.

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

Способ №1: Программная установка отбора «В списке»

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

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


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

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

Важный нюанс: Обратите внимание на параметры виртуальной таблицы Остатки. Всегда передавайте условие по складу внутрь параметров (&Период, Склад = &ВыбСклад), а не в секцию ГДЕ. Это значительно ускоряет работу запроса, так как система фильтрует данные на уровне СУБД еще до формирования виртуальной таблицы.

Проблема исчезновения групп (папок) и ее решение

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

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


Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    ТоварыОстатки.Номенклатура КАК Ссылка
    |ПОМЕСТИТЬ ВТ_Остатки
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &ВыбСклад) КАК ТоварыОстатки
    |ГДЕ
    |    ТоварыОстатки.ВНаличииОстаток > 0
    |;
    |
    |ВЫБРАТЬ Ссылка ИЗ ВТ_Остатки
    |ОБЪЕДИНИТЬ
    |ВЫБРАТЬ Ссылка.Родитель ИЗ ВТ_Остатки ГДЕ Ссылка.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
    |ОБЪЕДИНИТЬ
    |ВЫБРАТЬ Ссылка.Родитель.Родитель ИЗ ВТ_Остатки ГДЕ Ссылка.Родитель.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)";

Проанализируем этот запрос: мы выбираем ссылки товаров с остатками и "поднимаемся" по иерархии вверх. Если вложенность справочника большая, можно использовать цикл в коде 1С для перебора всех родителей до самого верхнего уровня и добавления их в общий СписокЗначений.

Способ №2: Использование двух элементов управления на форме

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

  1. Разместим на форме объект Панель с двумя страницами.
  2. На первой странице оставим стандартное Табличное поле, связанное со СправочникСписок.
  3. На второй странице разместим Табличное поле, источником данных для которого будет служить ТаблицаЗначений.
  4. При включении флажка "Скрыть отсутствующие" мы будем переключать текущую страницу панели на вторую, выполнять запрос и загружать данные в ТЗ.

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

Пример заполнения таблицы значений на форме:


// Предположим, ТаблицаОстатков - это реквизит формы с типом ТаблицаЗначений
// ЭлементыФормы.ТабличноеПолеОстатки - элемент управления на второй закладке

РезультатЗапроса = Запрос.Выполнить();
ТаблицаОстатков = РезультатЗапроса.Выгрузить();
ЭлементыФормы.ТабличноеПолеОстатки.СоздатьКолонки();

Способ №3: Использование Построителя Запроса

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

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

Заключение

Мы рассмотрели несколько подходов к скрытию отсутствующих товаров. Для небольших баз идеально подходит Способ №1 (отбор по списку ссылок), так как он требует минимум изменений в интерфейсе. Для крупных информационных баз с интенсивной работой пользователей лучше реализовать Способ №2 с отдельной таблицей значений или специализированной формой подбора, аналогичной той, что используется в типовых конфигурациях "Управление торговлей 10.3" или "УПП".

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

← На главную