Как добавить произвольные записи в отчет СКД

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

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

Метод 1: Использование объединения в основном запросе СКД

Это самый прямолинейный способ, который не требует написания кода в модулях. Мы расширяем основной запрос с помощью оператора ОБЪЕДИНИТЬ ВСЕ, добавляя «заглушки» или вычисляемые данные прямо в тело запроса. Проанализируем пример, где к основным продажам товаров добавляется строка «Упаковка».

Рассмотрим структуру такого запроса. Для того чтобы упаковка «приклеилась» к нужной группировке (например, к магазину), нам нужно во второй части объединения получить итоги по этому магазину, но подменить номенклатуру:


ВЫБРАТЬ
    ДвиженияТоваров.Магазин КАК Магазин,
    ДвиженияТоваров.Номенклатура КАК Номенклатура,
    ДвиженияТоваров.СуммаПродажи КАК СуммаПродажи,
    ДвиженияТоваров.СуммаЗакупки КАК СуммаЗакупки,
    ДвиженияТоваров.Количество КАК Количество
ИЗ
    РегистрНакопления.ДвиженияТоваров КАК ДвиженияТоваров
ГДЕ
    ДвиженияТоваров.Период МЕЖДУ &НачалоПериода И &КонецПериода

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДвиженияТоваровОбороты.Магазин,
    ВЫРАЗИТЬ(&УслугаУпаковка КАК Справочник.Номенклатура),
    0, // Сумма продажи упаковки (если она бесплатная)
    ДвиженияТоваровОбороты.КоличествоОборот * &ЦенаУпаковки, // Закупка упаковки
    ДвиженияТоваровОбороты.КоличествоОборот
ИЗ
    РегистрНакопления.ДвиженияТоваров.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ДвиженияТоваровОбороты

Важный нюанс: Чтобы строки встали в правильном порядке, во второй части запроса необходимо соблюдать ту же структуру полей. Если в основном запросе есть поле Регистратор, в «заглушке» его можно оставить пустым (НЕОПРЕДЕЛЕНО) или заполнить значением из первой части через вложенный запрос.

Метод 2: Внешний набор данных (Таблица значений)

Если логика расчета произвольных строк слишком сложная для чистого SQL-запроса (например, требует обращения к файлам на диске или сложного пересчета по алгоритмам), лучше всего использовать Набор данных - объект. Разберем по шагам, как это реализовать.

Во-первых, в схеме компоновки данных создадим новый Набор данных - объект и назовем его, например, ВнешняяТаблица. Добавим в него те же поля, что и в основном наборе данных (Магазин, Номенклатура, Сумма и т.д.).

Затем нам нужно передать данные в этот набор программно. Это делается в модуле объекта отчета (или в обработке) в процедуре ПриКомпоновкеРезультата. Рассмотрим пример кода:


Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Берем управление на себя
    
    // 1. Формируем таблицу значений с нужной структурой
    ТЗ_ДопДанные = Новый ТаблицаЗначений;
    ТЗ_ДопДанные.Колонки.Добавить("Магазин", Новый ОписаниеТипов("СправочникСсылка.Магазины"));
    ТЗ_ДопДанные.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    ТЗ_ДопДанные.Колонки.Добавить("СуммаЗакупки", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
    
    // Заполняем ТЗ произвольной логикой
    НоваяСтрока = ТЗ_ДопДанные.Добавить();
    НоваяСтрока.Магазин = Справочники.Магазины.НайтиПоНаименованию("Главный");
    НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Упаковка");
    НоваяСтрока.СуммаЗакупки = 100;

    // 2. Помещаем таблицу в структуру внешних наборов
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ВнешняяТаблица", ТЗ_ДопДанные);

    // 3. Выполняем стандартную компоновку
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);

    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

В самой схеме СКД создается Набор данных - объединение, в который вкладываются оба набора: и основной запрос, и объект ВнешняяТаблица. СКД автоматически объединит записи по именам полей.

Метод 3: Дублирование записей через Cross Join (Левое соединение)

Этот профессиональный прием позволяет избежать повторного тяжелого обращения к БД. Если нам нужно добавить «Упаковку» строго под каждым проданным товаром, мы можем искусственно «размножить» строки. Выясним, как это работает.

Создадим в запросе временную таблицу из двух строк (назовем их «маркерами»):


ВЫБРАТЬ 1 КАК НомерСтроки ПОМЕСТИТЬ ВТ_Маркеры
ОБЪЕДИНИТЬ ВЫБРАТЬ 2
;
ВЫБРАТЬ
    Продажи.Магазин,
    ВЫБОР 
        КОГДА Маркеры.НомерСтроки = 1 ТОГДА Продажи.Номенклатура
        ИНАЧЕ "Упаковка (" + Продажи.Номенклатура.Наименование + ")"
    КОНЕЦ КАК ПолеНоменклатура,
    ВЫБОР 
        КОГДА Маркеры.НомерСтроки = 1 ТОГДА Продажи.Сумма
        ИНАЧЕ 10 // Фиксированная цена упаковки
    КОНЕЦ КАК ПолеСумма
ИЗ
    РегистрПродаж КАК Продажи
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Маркеры КАК Маркеры ПО (ИСТИНА)

Такой подход гарантирует, что на каждую запись из БД мы получим две: оригинал и доп. строку. Это работает быстрее, чем полноценное объединение двух тяжелых выборок.

Решение проблемы сортировки произвольных строк

Одной из главных проблем при добавлении строк является их перемешивание. Мы хотим, чтобы «Упаковка» шла сразу за своим товаром. Посмотрим на ситуацию глазами СКД: она сортирует данные согласно настройкам. Чтобы «обмануть» систему, проанализируем использование вспомогательных полей.

  1. Добавьте поле порядка: В запросе для основных товаров установите Порядок = 1, для упаковок Порядок = 2.
  2. Настройте сортировку: В настройках группировки СКД добавьте сортировку сначала по основному объекту (например, Номенклатура или Магазин), а затем по вашему полю Порядок.
  3. Используйте скрытые поля: Вы можете добавить поле Порядок в детальные записи, но не выводить его пользователю в настройках «Выбранные поля».

Использование макетов для визуальной вставки

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

В СКД на закладке «Макеты» можно добавить макет для подвала группировки. В ячейках макета можно написать текст «В т.ч. упаковка» и указать параметр, который будет рассчитываться как Количество * 10. При этом в самой структуре данных отчета новых строк не появится, но при выводе в ТабличныйДокумент после каждого товара будет печататься дополнительная строка.

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

← На главную