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