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