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