Как вывести номенклатуру в печатной форме с группировкой по складам в 1С

Программист 1С:ERP Управление предприятием Управленческий учет Торговля и дистрибуция
← На главную

При разработке печатных форм для документов типа ЗаказКлиента или РеализацияТоваровУслуг часто возникает задача сгруппировать товары по конкретному признаку, например, по складам. Это необходимо для удобства логистики, чтобы кладовщики разных складов видели только свои позиции в рамках одного общего документа. В данной статье мы разберем, как реализовать такую группировку, как работать с областями макета и как правильно обрабатывать данные во внешней печатной форме.

Анализ задачи и выбор метода группировки

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

  1. Объектный метод: выгрузка табличной части в ТаблицаЗначений, ее сворачивание и поиск строк.
  2. Запросный метод: получение данных через запрос с использованием предложения ИТОГИ ПО.

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

Реализация группировки через таблицу значений

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


// 1. Выгружаем колонку "Склад" во временную таблицу
ТаблицаСкладов = СсылкаНаОбъект.Товары.Выгрузить( , "Склад");

// 2. Сворачиваем таблицу, чтобы остались только уникальные склады
ТаблицаСкладов.Свернуть("Склад");

// 3. Получаем список складов для обхода
СписокСкладов = ТаблицаСкладов.ВыгрузитьКолонку("Склад");

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

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

Вывод информации о складах в шапку документа

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


// Получаем массив уникальных представлений складов
МассивНаименований = ТаблицаСкладов.ВыгрузитьКолонку("Склад");
// Преобразуем массив в одну строку с разделителем
СтрокаВсеСклады = СтрСоединить(МассивНаименований, "; ");

// Заполняем параметр в области шапки
ОбластьШапка.Параметры.СписокСкладов = СтрокаВсеСклады;
ОбластьШапка.Параметры.КоличествоСкладов = МассивНаименований.Количество();

Использование СтрСоединить позволяет избежать написания лишних циклов для склейки строк и автоматизирует обработку разделителей (лишняя точка с запятой в конце строки не появится).

Обработка исключений при печати услуг

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

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


Попытка
    ОбластьСтрока.Параметры.ЕдиницаИзмерения = СтрокаТовар.Номенклатура.ЕдиницаИзмерения;
Исключение
    // Если единицы измерения нет (например, это текстовая строка или услуга)
    ОбластьСтрока.Параметры.ЕдиницаИзмерения = "-";
КонецПопытки;

Более профессиональный подход заключается в проверке типа номенклатуры или проверке заполненности реквизита, но для быстрых внешних форм Попытка является допустимым и надежным инструментом.

Работа с адресом доставки

Часто в печатных формах (например, в Актах доставки) требуется вывести не весь юридический адрес, а только его часть (город, улицу, дом). Если адрес хранится строкой, мы можем воспользоваться функцией СтрРазделить. Разберем пример, как вытащить конкретный фрагмент из строки адреса:


АдресСтрокой = СсылкаНаОбъект.АдресДоставки; // Например: "634059, г. Томск, пр-кт Мира, д.50"
МассивЧастей = СтрРазделить(АдресСтрокой, ",", Ложь);

// Предположим, нам нужны только улица и дом (3-й и 4-й элементы массива)
Если МассивЧастей.Количество() >= 4 Тогда
    РезультатАдрес = МассивЧастей[2] + ", " + МассивЧастей[3];
    ОбластьШапка.Параметры.АдресКратко = СокрЛП(РезультатАдрес);
КонецЕсли;

Важно помнить: индексы в массивах 1С начинаются с нуля. Поэтому третий элемент строки будет иметь индекс [2]. Будьте осторожны: если пользователь ввел адрес вручную без соблюдения формата, порядок элементов может нарушиться. В идеале в 1С:ERP стоит использовать функции из общего модуля УправлениеКонтактнойИнформацией, чтобы получать части адреса по типам (город, улица) гарантированно.

Почему запросы лучше объектного чтения?

Хотя мы подробно разобрали работу с таблицами значений, выясним, почему опытные разработчики рекомендуют использовать Запрос. Когда вы обращаетесь к данным через СсылкаНаОбъект.Товары, а затем внутри цикла пишете ТекущаяСтрока.Номенклатура.Код, система выполняет обращение к базе данных на каждой итерации цикла. Если в документе 100 строк, это 100 лишних микро-запросов, что замедляет печать.

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


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

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

// Обход по группировкам (Складам)
ВыборкаСклад = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаСклад.Следующий() Цикл
    // Выводим заголовок склада
    
    // Обход по детальным записям (Товарам внутри склада)
    ВыборкаТовары = ВыборкаСклад.Выбрать();
    Пока ВыборкаТовары.Следующий() Цикл
        // Выводим строки товаров
    КонецЦикла;
КонецЦикла;

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

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

← На главную