Как вывести аналоги с остатками и артикулами в форме списка номенклатуры на обычных формах

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

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

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

Представим ситуацию: у нас есть основной список номенклатуры. При выборе (активации) строки мы хотим видеть в табличном поле ниже все аналоги выбранной позиции. При этом просто вывести записи регистра Аналоги недостаточно — пользователю важно видеть артикул аналога и его текущий остаток на складах. Более того, часто требуется скрывать те аналоги, которых нет в наличии.

Для реализации мы будем использовать стандартный механизм РегистрСведенийСписок, но столкнемся с важным нюансом: данные об остатках не хранятся в регистре аналогов. Это динамические данные, которые нужно "подмешивать" в список в реальном времени.

Шаг 1. Настройка фильтрации аналогов

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

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


Процедура СправочникСписокПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Устанавливаем отбор в табличном поле, которое связано с РегистрСведенийСписок.Аналоги
    ЭлементыФормы.ТабличноеПолеАналоги.Значение.Отбор.Номенклатура.Установить(ТекущиеДанные.Ссылка);
КонецПроцедуры

Важный момент: использование ТекущиеДанные.Ссылка гораздо эффективнее, чем поиск по наименованию, так как ссылка является уникальным идентификатором и индексируется СУБД по умолчанию.

Шаг 2. Добавление колонок "Артикул" и "Остаток"

Поскольку наше табличное поле связано с объектом РегистрСведенийСписок, в нем по умолчанию присутствуют только измерения и ресурсы самого регистра (например, Номенклатура и Аналог). Нам нужно вручную добавить две колонки в табличное поле на форме:

  1. Колонка Артикул (тип Строка).
  2. Колонка Остаток (тип Число).

Эти колонки не будут привязаны к данным (поле Данные в свойствах колонки должно быть пустым), так как мы будем заполнять их программно.

Шаг 3. Использование события ПриПолученииДанных для вывода остатков

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

Разберем правильный подход: использование события ПриПолученииДанных. Этот метод позволяет получить данные сразу для всего пакета строк, которые система планирует отобразить на экране (обычно 20–40 строк), и выполнить всего один запрос.

Рассмотрим пример кода для обработки этого события:


Процедура ТабличноеПолеАналогиПриПолученииДанных(Элемент, ОформленияСтрок)
    // Создаем массив ссылок на аналоги, которые сейчас отображаются в списке
    МассивАналогов = Новый Массив;
    СоответствиеОформлений = Новый Соответствие;

    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        АналогСсылка = ОформлениеСтроки.ДанныеСтроки.Аналог;
        МассивАналогов.Добавить(АналогСсылка);
        СоответствиеОформлений.Вставить(АналогСсылка, ОформлениеСтроки);
    КонецЦикла;

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

    Запрос.УстановитьПараметр("МассивАналогов", МассивАналогов);
    Выборка = Запрос.Выполнить().Выбрать();

    Пока Выборка.Следующий() Цикл
        Оформление = СоответствиеОформлений.Получить(Выборка.Аналог);
        Если Оформление <> Неопределено Тогда
            Оформление.Ячейки.Артикул.УстановитьТекст(Выборка.Артикул);
            Оформление.Ячейки.Остаток.УстановитьТекст(Выборка.Остаток);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Шаг 4. Проблема фильтрации по остаткам

Выясним причину, по которой использование РегистрСведенийСписок накладывает определенные ограничения. В сообщении 0 была задача: выводить только аналоги с остатками.

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

Существует два способа решения этой проблемы:

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

Шаг 5. Оптимизация запроса и индексация

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

  1. Ведущее измерение: В регистре сведений Аналоги измерение Номенклатура должно быть помечено как Ведущее. Это создает индекс, который позволяет 1С мгновенно находить записи при установке отбора.
  2. Параметры виртуальной таблицы: Обратите внимание на код запроса в Шаге 3. Мы передаем фильтр по номенклатуре непосредственно в параметры виртуальной таблицы остатков: ОстаткиНоменклатуры.Остатки(, Номенклатура В (&МассивАналогов)). Это критически важно. Если просто соединить справочник с виртуальной таблицей всех остатков, а затем наложить ГДЕ, запрос будет работать в десятки раз медленнее на больших базах.
  3. ЕСТЬNULL: Всегда используйте эту функцию при левом соединении с остатками, чтобы вместо пустых значений (NULL) пользователь видел корректный "0".

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

← На главную