Как разделить товары и услуги в печатной форме Заказ покупателя

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В типовых конфигурациях 1С, работающих на обычных формах (таких как УПП 1.3 или УТ 10.3), печатные формы «Счет на оплату» или «Заказ покупателя» зачастую объединяют товары и услуги в одну общую таблицу. Однако бизнес-процессы многих компаний требуют разделения: товары должны быть в одной таблице со своими итогами, услуги — в другой, а возвратная тара — в третьей. Рассмотрим подробно, как реализовать такое разделение, внеся изменения в программный код и логику работы с макетом.

Анализ исходной проблемы в коде

Проанализируем типовую функцию ПолучитьПараметрыПечатиСчетаЗаказа. В стандартном исполнении используется один запрос, который собирает данные из табличных частей Товары, Услуги и ВозвратнаяТара с помощью конструкции ОБЪЕДИНИТЬ ВСЕ. Каждому блоку присваивается числовая Метка (0 — товары, 1 — услуги, 3 — тара), и результат выгружается в одну таблицу значений. При выводе на печать программа просто перебирает эту таблицу в одном цикле, что и приводит к «смешиванию» данных в одной печатной секции.

Чтобы разделить эти данные, нам необходимо либо изменить структуру запроса, используя итоги, либо разделить процесс вывода на несколько последовательных циклов. Рассмотрим оба варианта.

Способ 1. Использование механизма итогов в запросе

Этот метод наиболее элегантен с точки зрения производительности. Мы добавляем в запрос группировку по полю Вид (или Метка) и используем конструкцию ИТОГИ. Это позволит нам получать данные иерархически: сначала заголовок группы (например, «Товары»), затем строки этой группы. Рассмотрим пример реализации такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ""Товары"" КАК Вид,
|   ТЧ.Номенклатура,
|   ТЧ.Количество,
|   ТЧ.Сумма,
|   ТЧ.СуммаНДС
|ИЗ
|   Документ.ЗаказПокупателя.Товары КАК ТЧ
|ГДЕ
|   ТЧ.Ссылка = &ТекущийДокумент
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|   ""Услуги"",
|   ТЧ.Номенклатура,
|   ТЧ.Количество,
|   ТЧ.Сумма,
|   ТЧ.СуммаНДС
|ИЗ
|   Документ.ЗаказПокупателя.Услуги КАК ТЧ
|ГДЕ
|   ТЧ.Ссылка = &ТекущийДокумент
|ИТОГИ
|   СУММА(Количество),
|   СУММА(Сумма),
|   СУММА(СуммаНДС)
|ПО
|   Вид";

Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);
РезультатЗапроса = Запрос.Выполнить();

После выполнения такого запроса мы можем использовать обход по группировкам. Выясним, как правильно обработать этот результат при выводе в табличный документ:

  1. Обход по группировке «Вид»: На этом этапе мы определяем, какую таблицу сейчас выводим. Здесь можно вывести заголовок таблицы (например, «Раздел: Товары»).
  2. Вывод шапки таблицы: Для каждой новой группы мы заново выводим область макета ШапкаТаблицы.
  3. Детальные записи: Внутри цикла по группировке запускаем вложенный цикл по строкам, выводя область Строка.
  4. Итоги по секции: Так как мы использовали ИТОГИ, переменная ВыборкаВид.Сумма будет содержать сумму только по текущему разделу. Это позволяет вывести подвал для каждой таблицы отдельно.

Способ 2. Последовательный вывод через фильтрацию данных

Если мы не хотим кардинально менять структуру типового запроса, представленного в исходном сообщении, можно воспользоваться методом фильтрации уже полученной таблицы значений ЗапросТовары. Проанализируем, как программно разделить вывод в функции СоздатьТабличныйДокументПечатиСчетаЗаказа.

Вместо одного цикла Для каждого ПараметрыПозиции Из ПараметрыПечати.Позиции Цикл, мы организуем несколько блоков вывода. Рассмотрим алгоритм:


// 1. Выводим блок ТОВАРЫ
ТаблицаТоваров = ПараметрыПечати.Позиции.НайтиСтроки(Новый Структура("Метка", 0));
Если ТаблицаТоваров.Количество() > 0 Тогда
    // Выводим заголовок "Товары"
    // Выводим Шапку таблицы
    Для каждого СтрокаТовар Из ТаблицаТоваров Цикл
        // Заполнение параметров и вывод области Строка
    КонецЦикла;
    // Выводим Итоги по товарам
КонецЕсли;

// 2. Выводим блок УСЛУГИ
ТаблицаУслуг = ПараметрыПечати.Позиции.НайтиСтроки(Новый Структура("Метка", 1));
Если ТаблицаУслуг.Количество() > 0 Тогда
    // Выводим заголовок "Услуги" (можно добавить пустую строку для визуального разрыва)
    // Выводим Шапку таблицы
    Для каждого СтрокаУслуга Из ТаблицаУслуг Цикл
        // Заполнение параметров и вывод области Строка
    КонецЦикла;
    // Выводим Итоги по услугам
КонецЕсли;

Важный момент: При таком подходе необходимо следить за нумерацией строк. Если требуется сквозная нумерация по всему документу, индекс строки не должен обнуляться. Если же в каждой таблице нумерация должна начинаться с единицы, необходимо завести локальный счетчик для каждого цикла.

Работа с макетом и областями

Чтобы печатная форма выглядела профессионально, нам не обязательно дублировать области в макете. Разберем, как эффективно использовать имеющиеся ресурсы:

Расчет НДС и итоговых сумм

При разделении таблиц критически важно правильно рассчитать итоги. Рассмотрим ситуацию: если мы выводим две таблицы, покупатель ожидает увидеть итоговую сумму НДС и общую сумму к оплате отдельно по товарам и отдельно по услугам.

В коде 1С это реализуется через метод Итог() таблицы значений или через агрегатные функции запроса. Например, если мы используем подход с фильтрацией таблицы значений ТЗ_Результат:


СуммаПоРазделу = 0;
Для каждого Стр Из НайденныеСтроки Цикл
    СуммаПоРазделу = СуммаПоРазделу + Стр.Сумма;
КонецЦикла;
// Передаем СуммаПоРазделу в область Итог раздела

Не забудьте, что общая сумма «Итого по счету» в самом низу документа должна оставаться неизменной и включать в себя все разделы, независимо от их визуального разделения. Для этого используйте ПараметрыПечати.Всего, который рассчитывается один раз по всей коллекции данных.

Таким образом, разделение товаров и услуг в 1С сводится к двум основным задачам: правильной классификации строк в запросе (через Метки или Виды) и циклическому выводу областей макета для каждой группы этих строк. Использование итогов в запросе является более предпочтительным, так как оно автоматически предоставляет готовые суммы по группировкам, сокращая объем программного кода.

← На главную