При разработке отчетов в системе компоновки данных (СКД), особенно связанных со складским учетом, начинающие программисты часто сталкиваются с проблемой некорректного агрегирования данных. Подобные задачи, например, расчет дней нахождения товаров на складах, часто входят в тестовое задание на должность 1С мидл. Вместо того чтобы показать остаток на конкретный момент времени, система суммирует значения за все периоды, выдавая фантастические цифры в итогах. Рассмотрим подробно, почему это происходит и как настроить отчет так, чтобы КоличествоОстаток отображало реальное положение дел на складе.
Разберем ситуацию: если в вашем отчете по дням остаток на понедельник составлял 10 единиц, а на вторник — 7 единиц, СКД в общих итогах может вывести 17. С точки зрения логики ресурсов, система просто выполнила функцию Сумма(). Для обычных оборотов (приход, расход) это правильно, но для остатков — нет. Для разработчика, выполняющего быстрый анализ данных, очевидно: остаток — это состояние на точку времени, и его итог по иерархии периодов должен соответствовать последнему значению в этом периоде.
Посмотрим на пример запроса, который часто становится источником ошибок:
ВЫБРАТЬ
ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоОстаток,
ТоварыНаСкладахОстаткиИОбороты.КоличествоНачальныйОстаток КАК КоличествоНачальныйОстаток,
ТоварыНаСкладахОстаткиИОбороты.КоличествоПриход КАК КоличествоПриход,
ТоварыНаСкладахОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
ТоварыНаСкладахОстаткиИОбороты.Период
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , ) КАК ТоварыНаСкладахОстаткиИОбороты
В данном случае проблема кроется в использовании псевдонимов. Как только мы переименовываем КоличествоКонечныйОстаток в КоличествоОстаток, система компоновки данных может "потерять" автоматическую связь с ролями метаданных. СКД перестает понимать, что это поле является остатком. Если вы создаете отчет не в конструкторе, а программно, то СКДБилдер поможет упростить программное создание СКД и избежать подобных ошибок ручного описания полей.
Для того чтобы СКД понимала, как обрабатывать данные, нам необходимо вручную настроить вкладку Роли в конструкторе схемы компоновки данных. Проанализируем ключевые параметры этой настройки:
КоличествоНачальныйОстаток) необходимо установить значение "Начальный". Для конечного остатка — "Конечный".Номенклатура, Склад, Характеристика). Это позволит системе правильно схлопывать итоги, если вы убираете одно из измерений из группировки отчета.Как мы выяснили, несимметричные синонимы могут сбивать автоматику СКД. Выясним причину: если вы назвали начальный остаток стандартно, а конечный — по-своему, СКД не сможет автоматически сопоставить их. Рассмотрим пример правильного именования в запросе:
ВЫБРАТЬ
ТоварыНаСкладах.КоличествоНачальныйОстаток КАК КоличествоНачальныйОстаток,
ТоварыНаСкладах.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
Или, если вы используете свои имена, обязательно пропишите их в ролях так, как указано в Шаге 1. Помните: имена полей в запросе могут быть любыми, но в "Ролях" они должны быть связаны общим идентификатором группы остатков.
Часто в отчетах по остаткам требуется вывести стоимость. Посмотрим на типичную ошибку соединения с ценами в запросе:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&КонецПериода, ТипЦен = &ТипЦен) КАК Цены
ПО ТоварыНаСкладах.Номенклатура = Цены.Номенклатура
Проанализируем ситуацию: если ваш отчет строится по дням за целый месяц, такое соединение подтянет одну и ту же цену (на конец месяца) ко всем строкам отчета. В некоторых случаях, когда требуется оптимизация отчетов с набором данных - объект, разработчики применяют более сложные подходы, иногда используя даже две разных схемы в одном отчете для разделения логики получения данных и их представления.
Рассмотрим правильный подход:
Для получения корректных цен на каждый день лучше использовать Связи наборов данных в СКД. Создадим два набора данных:
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты.РегистрСведений.ЦеныНоменклатуры.СрезПоследних.В настройках связи укажем: Источник - Набор1, Приемник - Набор2. Свяжем их по полям Номенклатура и Период. В параметрах таблицы цен для СрезПоследних укажем условие использования периода из первого набора. Таким образом, СКД сама выполнит запрос к ценам для каждой даты остатка.
Перейдем на вкладку Ресурсы. Если роли настроены верно, для поля остатка можно использовать обычную функцию Сумма(КоличествоКонечныйОстаток). СКД, видя роль "Остаток", применит особый алгоритм: по группировкам (Склад, Номенклатура) она будет суммировать, а по временным осям (Период) — брать последнее значение.
Если же вы создаете вычисляемое поле, например, СуммаОстатка = КоличествоОстаток * Цена, в выражении ресурса стоит быть внимательным. Иногда требуется указать расчет через конкретные функции агрегации остатков, но в 90% случаев корректно настроенных ролей в базовых полях достаточно для правильной работы вычисляемых ресурсов.
Для получения корректного последнего значения остатка в СКД мы должны:
ОстаткиИОбороты (или Остатки, если динамика не нужна).Следуя этим правилам, вы получите отчет, который корректно отображает итоговые остатки на любую дату, не суммируя их между собой.