Как вывести цены в форме подбора номенклатуры в 1С?

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

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

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

Анализ типичной ошибки: почему запрос в цикле — это плохо

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

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


&НаКлиенте
Процедура ЗаполнитьЦены(Команда)
    // Ошибка: обращение только к одной текущей строке
    ТД = Элементы.СписокНоменклатуры.ТекущиеДанные;
    ТД.Цена = ЗаполнитьЦеныНаСервере(ТД.Номенклатура);
КонецПроцедуры

Выясним причину неэффективности такого подхода:

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

Способ №1: Использование произвольного запроса в Динамическом списке

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

Во-первых, откроем форму подбора в конфигураторе и найдем основной реквизит формы (обычно это Список или СписокНоменклатуры) с типом ДинамическийСписок. В свойствах этого реквизита необходимо установить флаг Произвольный запрос и перейти по ссылке Настройка списка.

Во-вторых, отредактируем текст запроса. Нам нужно добавить ЛЕВОЕ СОЕДИНЕНИЕ с виртуальной таблицей среза последних регистра сведений ЦеныНоменклатуры. Рассмотрим пример такого запроса:


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

Важные моменты при написании запроса:

Способ №2: Обработка события ПриПолученииДанныхНаСервере

Если структура запроса динамического списка слишком сложна или формируется программно (как в типовых решениях УТ 11 или КА 2), можно использовать событие списка ПриПолученииДанныхНаСервере. Этот метод позволяет дозаполнить данные только для тех строк, которые реально отобразились на экране пользователя.

Рассмотрим алгоритм реализации:

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

Пример кода для реализации этого метода:


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

Преимущество этого метода: Мы не перегружаем основной запрос списка и получаем данные только для 20-40 строк, видимых пользователю, что работает крайне быстро.

Особенности работы в типовых конфигурациях (КА 2, ERP, УТ 11)

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

Рекомендуемая стратегия:

Проверка настроек отображения

Иногда программный код написан верно, но колонка с ценой всё равно пуста. Разберем, на что обратить внимание:

  1. Использовать всегда: В настройках динамического списка (вкладка "Поля") найдите ваше поле Цена и установите флажок "Использовать всегда". Это гарантирует, что платформа включит это поле в SQL-запрос, даже если пользователь скрыл колонку.
  2. Путь к данным: Убедитесь, что у добавленного элемента формы (Поле ввода) в свойстве ПутьКДанным указано именно Список.Цена.
  3. Обновление параметров: Если пользователь меняет дату документа или тип цен, не закрывая подбор, необходимо вызвать Элементы.Список.Обновить(), чтобы сработал новый срез последних.

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

← На главную