Как программно перебрать номенклатуру из таблицы значений и вывести список в печатную форму?

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

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

Разбор типичных ошибок при работе с таблицей значений

Начинающие программисты часто путают структуру таблицы и её содержимое. Проанализируем ситуацию: когда мы создаем объект ТаблицаЗначений и добавляем в него колонки с помощью метода Колонки.Добавить(), мы создаем только «скелет» таблицы. Если мы сразу запустим цикл по этой таблице, он не выполнится ни разу, так как в таблице нет строк. Кроме того, перебор Для Каждого Колонка Из ТабЗнач.Колонки проходит по описаниям столбцов, а не по самим данным.

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

Способ 1: Классический перебор строк (Базовый уровень)

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

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


Функция СформироватьСписокНоменклатуры(ИсточникДанных)
    ПеременнаяРезультат = "";
    
    // ИсточникДанных может быть Табличной Частью или Таблицей Значений
    Для Каждого Строка Из ИсточникДанных Цикл
        // Проверяем, заполнена ли номенклатура в строке
        Если ЗначениеЗаполнено(Строка.Номенклатура) Тогда
            НаименованиеТовара = Строка.Номенклатура.Наименование;
            
            // Если строка еще пустая, просто добавляем имя, иначе - через запятую
            Если ПустаяСтрока(ПеременнаяРезультат) Тогда
                ПеременнаяРезультат = НаименованиеТовара;
            Иначе
                ПеременнаяРезультат = ПеременнаяРезультат + ", " + НаименованиеТовара;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Возврат ПеременнаяРезультат;
КонецФункции

В данном примере мы используем проверку ПустаяСтрока(ПеременнаяРезультат), чтобы определить, нужно ли ставить разделитель. Это избавляет нас от лишней запятой в самом начале или конце списка.

Способ 2: Использование современного метода СтрСоединить (Продвинутый уровень)

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

Разберем по шагам, как это реализовать:

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

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

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

Оптимизация производительности: Проблема «N+1»

Выясним причину, по которой первый способ может работать медленно на больших документах. Когда мы пишем Стр.Номенклатура.Наименование внутри цикла, система при каждом проходе выполняет отдельный запрос к базе данных, чтобы «дотянуться» до реквизита ссылки. Если в документе 100 строк — будет сделано 100 обращений к БД. Это классическая проблема производительности.

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


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

Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

МассивИмен = Новый Массив;
Пока Выборка.Следующий() Цикл
    МассивИмен.Добавить(Выборка.Наименование);
КонецЦикла;

ИтоговаяСтрока = СтрСоединить(МассивИмен, ", ");

Обратите внимание на ключевое слово РАЗЛИЧНЫЕ в тексте запроса. Проанализируем ситуацию: если в документе одна и та же номенклатура встречается в десяти разных строках (например, с разными характеристиками), в печатной форме нам, скорее всего, нужно упомянуть её название только один раз. Оператор РАЗЛИЧНЫЕ автоматически удалит дубликаты.

Где размещать код формирования строки?

Для корректной работы печатной формы придерживайтесь следующих правил архитектуры:

Рассмотрим финальный вариант вызова функции при заполнении параметров области макета:


// В модуле менеджера при формировании печатной формы
ОбластьМакета.Параметры.СписокТоваров = СформироватьСписокНоменклатуры(ДанныеПечати.Товары);

Таким образом, мы обеспечиваем чистоту кода и высокую скорость работы системы. Использование СтрСоединить в связке с запросом — это наиболее профессиональный подход, который высоко ценится при разработке на платформе 1С.

← На главную