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