При разработке печатных форм в 1С часто возникает задача преобразования данных, которые хранятся в табличной части документа «россыпью», в структурированный вид для пользователя. Типичный пример — работа с наборами. В информационной базе набор может состоять из нескольких строк (комплектующих), чтобы корректно списать остатки со склада, но в печатной форме для клиента или внутреннего отчета требуется вывести одну строку с названием набора и общей суммой.
В этой статье мы разберем, как модифицировать код формирования печатной формы, чтобы при наличии признака «набор» программа объединяла позиции и выводила их корректно.
Прежде всего, проанализируем ситуацию. В документе Возврат товаров на вкладке Товары обычно присутствуют колонки, указывающие на принадлежность строки к набору. Это может быть либо булево поле ЭтоНабор, либо ссылочное поле НоменклатураНабора (в которое записывается «виртуальный» владелец комплектующих). Наша цель — изменить алгоритм вывода так, чтобы вместо перечисления всех составляющих через запятую или отдельными строками, мы получали красивый суммированный результат.
Чтобы программа «увидела» наборы, нам необходимо вытянуть соответствующий признак из базы данных. Если мы используем типовую или близкую к ней конфигурацию, в запросе к табличной части документа нужно обязательно добавить поле, отвечающее за связь. Рассмотрим пример добавления поля НоменклатураНабора в текст запроса:
ТекстЗапроса = "ВЫБРАТЬ
| ВозвратТоваровТовары.Номенклатура КАК Номенклатура,
| ВозвратТоваровТовары.Количество КАК Количество,
| ВозвратТоваровТовары.СуммаВключаяНДС КАК СуммаСНДС,
| ВозвратТоваровТовары.НоменклатураНабора КАК НоменклатураНабора,
| ВЫБОР
| КОГДА ВозвратТоваровТовары.НоменклатураНабора <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ЭтоЧастьНабора
|ИЗ
| Документ.ВозвратТоваровОтПокупателя.Товары КАК ВозвратТоваровТовары
|ГДЕ
| ВозвратТоваровТовары.Ссылка = &Ссылка";
Здесь мы создали дополнительное вычисляемое поле ЭтоЧастьНабора, которое поможет нам в коде быстро определять логику вывода строки.
Теперь рассмотрим, как изменить исходный код, предоставленный автором вопроса. Основная проблема исходного кода заключалась в том, что он просто «склеивал» всю номенклатуру в одну длинную строку. Нам же нужно реализовать проверку: если товар является частью набора, мы должны обрабатывать его особым образом.
Проанализируем алгоритм с использованием условий Если...Тогда:
ОбластьМакета = Макет.ПолучитьОбласть("строка");
СуммаИтого = 0;
СписокТоваров = "";
Пока Выборка.Следующий() Цикл
// Выясним, имеем ли мы дело с набором
Если ЗначениеЗаполнено(Выборка.НоменклатураНабора) Тогда
// Если это набор, выводим наименование именно набора, а не комплектующей
НаименованиеДляПечати = СокрЛП(Выборка.НоменклатураНабора) + " (набор)";
Иначе
// Если обычный товар
НаименованиеДляПечати = СокрЛП(Выборка.Номенклатура);
КонецЕсли;
// Добавляем к общей строке, если нужно вывести списком
СписокТоваров = СписокТоваров + НаименованиеДляПечати + " , ";
СуммаИтого = СуммаИтого + Выборка.СуммаСНДС;
КонецЦикла;
// Убираем лишнюю запятую в конце
Если СтрДлина(СписокТоваров) > 0 Тогда
СписокТоваров = Сред(СписокТоваров, 1, СтрДлина(СписокТоваров) - 3);
КонецЕсли;
ОбластьМакета.Параметры.товар = СписокТоваров;
ОбластьМакета.Параметры.цена = СуммаИтого;
ТабличныйДокумент.Вывести(ОбластьМакета);
Если в документе один и тот же набор состоит из 5 позиций, приведенный выше код выведет название набора 5 раз. Чтобы этого избежать и вывести набор одной строкой в таблице, лучше сначала выгрузить данные запроса в Таблицу Значений и «схлопнуть» (свернуть) их.
Рассмотрим подробнее этот профессиональный подход:
ТЗ_Товары.ТоварДляПечати, в которую запишем название набора или название обычного товара.Свернуть() по колонке с названием, суммируя количества и суммы.
ТЗ_Товары = Запрос.Выполнить().Выгрузить();
// Добавим колонку, по которой будем группировать
ТЗ_Товары.Колонки.Добавить("ТоварДляПечати", Новый ОписаниеТипов("Строка"));
Для Каждого СтрокаТЗ Из ТЗ_Товары Цикл
Если ЗначениеЗаполнено(СтрокаТЗ.НоменклатураНабора) Тогда
СтрокаТЗ.ТоварДляПечати = СокрЛП(СтрокаТЗ.НоменклатураНабора);
Иначе
СтрокаТЗ.ТоварДляПечати = СокрЛП(СтрокаТЗ.Номенклатура);
КонецЕсли;
КонецЦикла;
// Сворачиваем таблицу: одинаковые названия объединятся, цифры сложатся
ТЗ_Товары.Свернуть("ТоварДляПечати", "Количество, СуммаСНДС");
// Теперь выводим в макет уже сгруппированные данные
Для Каждого СтрокаТЗ Из ТЗ_Товары Цикл
ОбластьМакета = Макет.ПолучитьОбласть("СтрокаТаблицы");
ОбластьМакета.Параметры.Товар = СтрокаТЗ.ТоварДляПечати;
ОбластьМакета.Параметры.Количество = СтрокаТЗ.Количество;
ОбластьМакета.Параметры.Сумма = СтрокаТЗ.СуммаСНДС;
ТабличныйДокумент.Вывести(ОбластьМакета);
КонецЦикла;
При реализации вывода наборов важно помнить о нескольких моментах, которые могут повлиять на корректность учета:
Свернуть() может возникнуть погрешность округления в 1 копейку. Проанализируйте, допустимо ли это для вашей формы. Для внутренних актов возврата это обычно не критично, но для налоговых документов (УПД) лучше оставлять построчный вывод.КлючСвязи, которое уникально для каждой группы строк одного набора.Выясним, как лучше оформить область в макете. Чтобы вывести данные «в виде таблицы», как просил автор темы, необходимо в макете создать именованную строку (например, с именем строка), где параметры Товар, Количество и Цена расположены в соответствующих ячейках с границами (сеткой).
Использование метода ТабличныйДокумент.Вывести() внутри цикла обеспечит автоматическое построчное формирование таблицы. Если же вы хотите выделить наборы визуально (например, жирным шрифтом), можно создать в макете две разные области: СтрокаОбычная и СтрокаНабора, и вызывать их в коде в зависимости от условия ЭтоЧастьНабора.
Таким образом, мы выяснили, что задача решается не простым изменением текстовой переменной, а правильной подготовкой данных (группировкой в запросе или в таблице значений) и использованием условной логики при заполнении параметров макета.