Как вывести место хранения номенклатуры в табличной части документа в 1С:УТ 10.3?

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

При оформлении складских документов, таких как ПриходныйОрдерНаТовары, кладовщику часто требуется видеть ячейку (место хранения), закрепленную за конкретным товаром на выбранном складе, прямо в строке табличной части. Разберем, как правильно извлечь эти данные из информационной базы и отобразить их в форме документа.

Анализ структуры данных и типичные ошибки

В конфигурации «Управление торговлей 10.3» сведения о размещении товаров хранятся в регистре сведений МестаХраненияНоменклатуры. Измерениями регистра являются Номенклатура, Склад и МестоХранения, а также реквизит Приоритет. Регистр является непериодическим, поэтому использование среза последних к нему неприменимо.

Рассмотрим частые ошибки при попытке динамического отображения места хранения:

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

Решение 1. Прямое получение основного места хранения через функцию

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

Для этого в модуле формы документа опишем функцию получения места хранения с учетом склада шапки документа и приоритета:


Функция ПолучитьМестоХранения(Номенклатура) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    МестаХраненияНоменклатуры.МестоХранения КАК МестоХранения
        |ИЗ
        |    РегистрСведений.МестаХраненияНоменклатуры КАК МестаХраненияНоменклатуры
        |ГДЕ
        |    МестаХраненияНоменклатуры.Номенклатура = &Номенклатура
        |    И МестаХраненияНоменклатуры.Склад = &Склад
        |
        |УПОРЯДОЧИТЬ ПО
        |    МестаХраненияНоменклатуры.Приоритет ВОЗР";

    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("Склад", Склад);

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.МестоХранения;
    КонецЕсли;

    Возврат Неопределено;

КонецФункции

Затем вызовем данную функцию в обработчике события строки табличного поля:


Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)

    Если ЗначениеЗаполнено(ДанныеСтроки.Номенклатура) Тогда
        МестоХранения = ПолучитьМестоХранения(ДанныеСтроки.Номенклатура);
        Если МестоХранения <> Неопределено Тогда
            ОформлениеСтроки.Ячейки.МестоХранения.УстановитьТекст(Строка(МестоХранения));
        КонецЕсли;
    КонецЕсли;

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

Решение 2. Оптимальный вариант с пакетным получением данных

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

  1. Откроем форму документа и перейдем в свойства табличного поля Товары.
  2. Назначим обработчик для события ПриПолученииДанных.
  3. Соберем все ссылки номенклатуры из переданного списка строк и выполним один пакетный запрос.

Посмотрим на пример реализации данного механизма:


Процедура ТоварыПриПолученииДанных(Элемент, ОформленияСтрок)

    // Собираем массив номенклатуры только видимых строк
    МассивНоменклатуры = Новый Массив;
    Для Каждого Оформление Из ОформленияСтрок Цикл
        Если ЗначениеЗаполнено(Оформление.ДанныеСтроки.Номенклатура) Тогда
            МассивНоменклатуры.Добавить(Оформление.ДанныеСтроки.Номенклатура);
        КонецЕсли;
    КонецЦикла;

    Если МассивНоменклатуры.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

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

    Запрос.УстановитьПараметр("Склад", Склад);
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);

    Выборка = Запрос.Выполнить().Выбрать();
    
    // Заполняем соответствие: Номенклатура -> МестоХранения
    СоответствиеМест = Новый Соответствие;
    Пока Выборка.Следующий() Цикл
        // Так как упорядочили по возрастанию приоритета, первое встреченное значение - основное
        Если СоответствиеМест.Получить(Выборка.Номенклатура) = Неопределено Тогда
            СоответствиеМест.Вставить(Выборка.Номенклатура, Выборка.МестоХранения);
        КонецЕсли;
    КонецЦикла;

    // Расставляем текст по ячейкам оформления
    Для Каждого Оформление Из ОформленияСтрок Цикл
        Место = СоответствиеМест.Получить(Оформление.ДанныеСтроки.Номенклатура);
        Если Место <> Неопределено Тогда
            Оформление.Ячейки.МестоХранения.УстановитьТекст(Строка(Место));
        КонецЕсли;
    КонецЦикла;

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

Решение 3. Добавление реквизита в табличную часть

Выясним причину, почему динамический вывод не всегда удобен. Если при оприходовании товаров требуется не просто информировать кладовщика, но и выводить ячейку в печатные формы (например, в приходный ордер или бланк раскладки), правильнее добавить физический реквизит МестоХранения (тип СправочникСсылка.МестаХранения) непосредственно в табличную часть Товары документа.

В этом случае логика работы меняется:

  1. В форме документа в событии ТоварыНоменклатураПриИзменении при выборе товара вызывается поиск основного места хранения.
  2. Найденное значение сразу записывается в строку документа: СтрокаТабличнойЧасти.МестоХранения = НайденноеМесто;.
  3. В табличном поле колонка связывается напрямую с данными строки, что полностью исключает программную обработку событий отрисовки и обеспечивает максимальную скорость работы интерфейса.
← На главную