Как в отчете 1С на СКД правильно вывести цены и стоимость остатков товаров?

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

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

Анализ типичных ошибок в запросах к регистрам

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


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

В данном запросе допущены две критические ошибки. Во-первых, обращение идет к физической таблице РегистрСведений.ЦеныНоменклатуры. Это означает, что система попытается найти цену, установленную ровно в ту же секунду, что и период из таблицы остатков. Поскольку цены устанавливаются не каждую неделю, а периодически, соединение по равенству периодов вернет пустые значения. Во-вторых, использование условия ГДЕ по типу цен превращает ЛЕВОЕ СОЕДИНЕНИЕ во внутреннее, отсекая товары, для которых цена не задана.

Шаг 1: Правильное получение цен через виртуальные таблицы

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


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

Здесь мы используем ЕСТЬNULL, чтобы в случае отсутствия цены в системе отчет все равно вывел товар с нулевой ценой, а не скрыл строку целиком. Параметр &КонецПериода в виртуальной таблице цен гарантирует получение самой актуальной цены на дату окончания отчета.

Шаг 2: Решение проблемы отсутствия строк без продаж

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

  1. Перейдем на закладку Наборы данных.
  2. Для поля Период (или ПериодНеделя) установим флаг Обязательное.
  3. В параметрах виртуальной таблицы выберем метод дополнения периодов.
  4. В настройках самого отчета (вкладка «Настройки» -> «Выбранные поля») убедимся, что для группировки по периоду включено дополнение дат.

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

Шаг 3: Настройка ролей полей и расчет итогов

Часто пользователи жалуются, что итоговые суммы в отчете «удваиваются» или «утраиваются» при группировке по периодам. Рассмотрим подробнее, почему это происходит. Если просто просуммировать КоличествоКонечныйОстаток за 4 недели, мы получим не остаток на конец месяца, а сумму четырех остатков. Чтобы этого избежать, настроим Роли:

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

Важный совет по расчету стоимости: крайне не рекомендуется рассчитывать поле СуммаОстатка = Количество * Цена прямо в тексте запроса. Это приведет к ошибкам в общих итогах. Правильнее сделать следующее:

  1. В запросе получаем КоличествоКонечныйОстаток и Цена.
  2. На закладке Вычисляемые поля добавим поле СтоимостьОстатка.
  3. На закладке Ресурсы для этого поля пропишем выражение: Сумма(КоличествоКонечныйОстаток * Цена).

Это гарантирует, что система сначала перемножит количество на цену для каждой номенклатуры, а уже потом корректно сложит эти стоимости в итогах по складам или группам товаров.

Шаг 4: Использование связи наборов данных для точных цен на каждую дату

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

  1. Создадим НаборДанных_Остатки с запросом по регистру накопления.
  2. Создадим НаборДанных_Цены с запросом к РегистрСведений.ЦеныНоменклатуры.СрезПоследних.
  3. На вкладке Связи наборов данных соединим их по полю Номенклатура.
  4. В колонке «Параметры связи» для набора цен укажем, что параметр Период виртуальной таблицы цен должен принимать значение из поля Период набора остатков.

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


ВЫБРАТЬ
    ЦеныНоменклатурыСрезПоследних.Цена КАК Цена,
    ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ПериодЦен, ТипЦен = &ТипЦен) КАК ЦеныНоменклатурыСрезПоследних

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

Заключение

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

← На главную