Как вывести остатки товаров в списке номенклатуры в 1С:Управление торговлей 11?

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

Вывод текущих остатков непосредственно в форму списка справочника Номенклатура — это одна из самых частых задач, с которыми сталкиваются разработчики при адаптации конфигурации под нужды пользователей. В типовых решениях на базе 1С:ERP 2.0 (включая УТ 11) эта задача имеет свои особенности, связанные с производительностью системы и использованием механизмов динамических списков.

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

Почему колонка не появляется при обычном редактировании формы?

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

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

Корректный запрос для динамического списка

Чтобы вывести остатки, нам необходимо соединить основную таблицу справочника с виртуальной таблицей остатков регистра накопления ТоварыНаСкладах.Остатки. Рассмотрим пример правильного запроса, который минимизирует риск дублирования строк:


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

Важный момент: использование группировки СГРУППИРОВАТЬ ПО и агрегатной функции СУММА критически необходимо. Если товар учитывается в разрезе складов или характеристик, то без группировки в списке номенклатуры одна и та же позиция может продублироваться столько раз, на скольких складах она числится.

Программная реализация в форме списка

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

Разберем пример кода для модуля формы:


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

Проблема производительности и «Основной таблицы»

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

Однако, как только вы добавляете сложное соединение с виртуальной таблицей остатков и используете СГРУППИРОВАТЬ ПО, СУБД становится сложнее оптимизировать запрос. На больших базах данных (с сотнями тысяч позиций) это может привести к заметным «тормозам» при прокрутке списка.

Рекомендации для оптимизации:

  1. Убедитесь, что в свойствах динамического списка по-прежнему указана Основная таблица.
  2. Если список начал тормозить, рассмотрите возможность вывода остатков не в общую колонку, а в отдельную панель «Сведения о товаре», которая обновляется только при активизации строки (событие ПриАктивизацииСтроки).
  3. Используйте индексирование по полю Номенклатура в регистрах, если создаете собственные регистры накопления.

Штатные альтернативы в УТ 11

Прежде чем приступать к кодингу, проанализируем штатные возможности 1С:Управление торговлей. Разработчики фирмы «1С» знают о проблемах производительности при прямом выводе остатков в список, поэтому предложили альтернативные механизмы:

Панель «Наличие и цены». В правой части формы списка номенклатуры часто расположена скрытая или сворачиваемая панель. Она позволяет увидеть остатки по складам для текущего выделенного товара, не замедляя работу всего списка.

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

Использование расширений для доработки

Если вы работаете в типовой конфигурации, крайне не рекомендуется вносить изменения напрямую. Лучше создать Расширение и перехватить процедуру ПриСозданииНаСервере. Это позволит вам сохранить поддержку конфигурации и легко обновлять систему в будущем. В расширении вы сможете безопасно изменить текст запроса объекта Список, добавив нужные поля из регистра накопления.

Посмотрим на алгоритм действий через расширение:

  1. Создаем новое расширение.
  2. Добавляем в расширение форму списка справочника Номенклатура.
  3. Добавляем в расширение регистр накопления ТоварыНаСкладах (для возможности использования в запросе).
  4. Создаем обработчик &После("ПриСозданииНаСервере") и прописываем логику изменения Список.ТекстЗапроса.

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

← На главную