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

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

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

Почему происходит задвоение данных?

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

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

  1. В ОРП за день по номенклатуре «Куртка» числится продажа: 1 шт. на сумму 500 рублей.
  2. Эта строка сформировалась из двух чеков:
    • Чек №1: Продажа за 2000 руб. (Причина скидки: «Персонал»).
    • Чек №2: Возврат за 1500 руб. (Причина скидки: «Брак»).

Если мы просто соединим таблицу регистра с таблицей чеков по номенклатуре и характеристике, система найдет две подходящие записи в чеках для одной записи в регистре. В результате в отчете появятся две строки, и итоговая сумма реализации (500 руб.) выведется дважды, превратившись в 1000 руб. Это классическая проблема связи «один ко многим».

Способ 1. Использование временных таблиц и группировки (SQL-метод)

Проанализируем самый надежный способ решения проблемы внутри одного набора данных — запроса. Чтобы избежать «размножения» строк, нам нужно гарантировать, что для каждой уникальной комбинации «Документ ОРП + Номенклатура + Характеристика» найдется только одна причина скидки.

Для этого мы воспользуемся механизмом временных таблиц. Сначала подготовим уникальный список причин.

Шаг 1. Создание временной таблицы с причинами:


ВЫБРАТЬ
    ЧекККМТовары.Ссылка.ДокументОснование КАК ОРП,
    ЧекККМТовары.Номенклатура КАК Номенклатура,
    ЧекККМТовары.ХарактеристикаНоменклатуры КАК Характеристика,
    МАКСИМУМ(ЧекККМТовары.ПричинаРучнойСкидки) КАК ПричинаСкидки
ПОМЕСТИТЬ ВТ_ПричиныСкидок
ИЗ
    Документ.ЧекККМ.Товары КАК ЧекККМТовары
ГДЕ
    ЧекККМТовары.Ссылка.Проведен
    И ЧекККМТовары.ПричинаРучнойСкидки <> ЗНАЧЕНИЕ(Справочник.ПричиныСкидок.ПустаяСсылка)
СГРУППИРОВАТЬ ПО
    ЧекККМТовары.Ссылка.ДокументОснование,
    ЧекККМТовары.Номенклатура,
    ЧекККМТовары.ХарактеристикаНоменклатуры
;

Обратите внимание на использование функции МАКСИМУМ. Если в разных чеках по одному товару были разные причины, эта функция выберет одну из них (по алфавиту или коду), тем самым «схлопнув» данные до одной строки. Это критически важно для предотвращения задвоения.

Шаг 2. Соединение с основными данными:

Теперь мы можем смело соединять нашу временную таблицу с данными регистра Продажи.Обороты.


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

Способ 2. Связи наборов данных в СКД

Рассмотрим альтернативный подход, который часто удобнее в реализации, если вы не хотите переписывать весь основной запрос отчета. Мы можем использовать два разных набора данных (Data Sets).

  1. НаборДанных1 (Запрос): Здесь мы получаем основные данные из регистра Продажи. Это чистые суммы и количества.
  2. НаборДанных2 (Запрос): Здесь мы пишем запрос к ЧекККМ.Товары, выбирая только Номенклатуру, Характеристику, Ссылку на ОРП и Причину скидки. Обязательно используем СГРУППИРОВАТЬ ПО, чтобы для каждой номенклатуры была одна строка.

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

Важный нюанс: В настройках связи для СКД по умолчанию используется левое соединение. Если в НабореДанных2 по ключу связи будет найдено несколько строк, СКД все равно продублирует строку из первого набора. Поэтому группировка во втором наборе данных с использованием функции МАКСИМУМ остается обязательным условием!

Способ 3. Вычисляемые поля и агрегатные функции

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

Проанализируем этот алгоритм:

  1. В запросе оставляем соединение, которое дает задвоение (много строк с разными причинами).
  2. В СКД на вкладке «Ресурсы» для поля ПричинаСкидки прописываем выражение:

СоединитьСтроки(ТаблицаЗначений(Различные ПричинаСкидки), ", ")

  1. Для полей ресурсов Сумма и Количество устанавливаем рассчитываемое значение через МАКСИМУМ или СРЕДНЕЕ (в зависимости от структуры группировок), либо, что более правильно, грамотно настраиваем роль поля «Остатки/Обороты» в схеме компоновки.

Однако помните, что работа с СоединитьСтроки может замедлить отчет на больших объемах данных. Для стандартных задач первый способ с временными таблицами является наиболее производительным и «чистым» с точки зрения архитектуры 1С.

Резюме и рекомендации

Подведем итоги. Чтобы победить задвоение строк при связи регистра с документами:

Следуя этим правилам, мы добьемся того, что отчет будет выводить корректные суммы реализации, при этом обогащая данные информацией о причинах скидок из первичных чеков ККМ.

← На главную