Как в отчете СКД вывести продажи и остатки по складам в виде колонок без искажения данных?

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

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

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

В чем причина пропадания строк и ошибок в остатках?

Проанализируем типовую ошибку при попытке использовать объединение запросов (ОБЪЕДИНИТЬ ВСЕ). Запрос разработчика обычно выглядит так:


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

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

ВЫБРАТЬ
    ТоварыНаСкладахОстатки.Номенклатура,
    0,
    0,
    ТоварыНаСкладахОстатки.Склад,
    ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&ПериодОстатков) КАК ТоварыНаСкладахОстатки

При таком подходе возникают две ключевые сложности:

  1. Отбор по продажам: Если пользователь устанавливает в общих настройках отчета отбор вида КоличествоОборот > 0, СКД встраивает это условие в секцию ГДЕ для всего результирующего набора. В строках второй ветки (остатки) поле КоличествоОборот заполнено нулем, поэтому компоновщик просто отсекает все записи с остатками. В итоге в отчете остаются только продажи, а остатки исчезают.
  2. Отбор по складу: В строках с продажами колонка Склад заполнена значением NULL. При наложении стандартного отбора Склад = &Склад отсекаются все строки с продажами, так как значение NULL не проходит проверку на равенство.

Вариант 1. Использование двух наборов данных и связей СКД (Рекомендуемый способ)

Рассмотрим наиболее надежный архитектурный подход в СКД — разделение потоков данных на два независимых набора («НаборДанных - Запрос») с последующей настройкой связи между ними. Это позволяет полностью изолировать отборы по разным аналитикам и гарантировать правильный расчет итогов.

Разберем реализацию по шагам:

  1. Создание Набора данных «Продажи»:
    
    ВЫБРАТЬ
        ПродажиОбороты.Номенклатура КАК Номенклатура,
        ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
        ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
    ИЗ
        РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты
    

    Здесь выбираются только товарные позиции и их оборотные показатели.

  2. Создание Набора данных «Остатки»:
    
    ВЫБРАТЬ
        ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
        ТоварыНаСкладахОстатки.Склад КАК Склад,
        ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, {Склад.* КАК Склад}) КАК ТоварыНаСкладахОстатки
    

    Обратите внимание на использование расширения языка запросов СКД {Склад.* КАК Склад} в параметрах виртуальной таблицы остатков. Это позволяет передавать отбор по складам непосредственно в запрос остатков, не затрагивая выборку продаж.

  3. Настройка связей наборов данных:

    Перейдем на вкладку «Связи наборов данных» и добавим новую строку:

    1. Источник связи: Продажи.
    2. Приемник связи: Остатки.
    3. Условие связи: Номенклатура = Номенклатура.
    4. Параметры: При необходимости оптимизации производительности можно передать поле Номенклатура из первого набора в параметр виртуальной таблицы остатков, чтобы СКД считывала остатки только по проданным позициям.

Вариант 2. Исправление единого запроса с «ОБЪЕДИНИТЬ ВСЕ»

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

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


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

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

ВЫБРАТЬ
    ТоварыНаСкладахОстатки.Номенклатура,
    0,
    0,
    ТоварыНаСкладахОстатки.Склад,
    ТоварыНаСкладахОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(
        &ПериодОстатков,
        Номенклатура В (
            ВЫБРАТЬ РАЗЛИЧНЫЕ
                ПродажиОбороты.Номенклатура
            ИЗ
                РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК ПродажиОбороты
        ) {Склад.* КАК Склад}
    ) КАК ТоварыНаСкладахОстатки

Чтобы отбор по продажам не удалял строки с остатками, настроим его правильно в схеме компоновки:

  1. На вкладке «Наборы данных» для поля Склад в колонке «Роль» обязательно взводим флаг «Игнорировать NULL».
  2. Отбор по оборотам продаж накладываем не в общих отборах отчета, а в отборе конкретной группировки Номенклатура (вкладка «Отбор» группировки).
  3. В качестве условия указываем агрегатную функцию по ресурсу: СУММА(КоличествоОборот) > 0.
  4. В свойствах элемента отбора изменяем параметр «Применение отбора» на значение «После группировки или для иерархии». В этом случае компоновщик сначала сгруппирует строки продаж и остатков по номенклатуре, вычислит сумму продаж, а затем отсечет товары без продаж, сохранив сопутствующие остатки.

Настройка структуры отчета (Таблица: Номенклатура в строках, склады в колонках)

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

Рассмотрим настройку ресурсов на вкладке «Ресурсы»:

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

Настроим структуру на вкладке «Настройки»:

  1. Добавим элемент структуры типа «Таблица».
  2. В секцию «Строки» таблицы добавим группировку Номенклатура.
  3. В секцию «Колонки» таблицы добавим группировку Склад.
  4. Выделим группировку колонок (Склад), перейдем на ее вкладку «Выбранные поля», отключим авто-выбор и включим туда исключительно ресурс КоличествоОстаток.
  5. В общих выбранных полях отчета (или в выбранных полях строки Номенклатура) укажем поля КоличествоОборот и СтоимостьОборот.

В результате СКД сформирует корректную кросс-таблицу: для каждой номенклатуры будут выведены итоговые показатели продаж за период, а справа сформируются отдельные колонки по выбранным складам с актуальными остатками товаров без искажения итогов.

← На главную