В практике разработки на платформе 1С часто возникает задача анализа оборачиваемости товаров или прогнозирования спроса. Одной из базовых метрик здесь является среднее число продаж за определенный период. Рассмотрим подробно, как реализовать расчет этого показателя в контексте документа ВнутреннийЗаказ, используя механизм компоновки данных (СКД) и язык запросов 1С.
Представим ситуацию: в документе ВнутреннийЗаказ необходимо вывести информацию о том, сколько единиц конкретной номенклатуры продавалось в среднем за последние три месяца. Это поможет менеджеру принять решение о необходимости закупки. Для решения нам понадобится связать данные табличной части документа с виртуальной таблицей оборотов регистра накопления Продажи.
Первое, на что стоит обратить внимание — это правильное обращение к виртуальной таблице ПродажиОбороты. Опытные разработчики знают, что получение всех оборотов с последующей фильтрацией в секции ГДЕ — это ошибка, приводящая к падению производительности. Разберем, как правильно передать параметры.
Проанализируем структуру запроса. Нам необходимо получить сумму продаж, при этом ограничив период тремя месяцами от даты документа или текущей даты. В запросе это выглядит следующим образом:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.КоличествоОборот КАК КоличествоОборот
ИЗ
РегистрНакопления.Продажи.Обороты(
ДОБАВИТЬКДАТЕ(&ДатаКонца, МЕСЯЦ, -3),
&ДатаКонца,
,
) КАК ПродажиОбороты
Важно понимать разницу между "тремя месяцами" и "кварталом". Как справедливо отмечено в обсуждении, если мы укажем периодичность КВАРТАЛ, система может разбить данные по календарным интервалам (например, отдельно за 4-й квартал прошлого года и 1-й квартал текущего), что не даст нам нужной суммы для деления. Нам нужен именно скользящий период.
При соединении документа с регистром продаж мы используем ЛЕВОЕ СОЕДИНЕНИЕ. Это критически важно, так как по товару в заказе могло не быть продаж вовсе, но он все равно должен остаться в списке. Однако левое соединение порождает значения NULL там, где данных в регистре нет.
Рассмотрим пример правильного соединения и обработки пустых значений:
ВЫБРАТЬ
ВнутреннийЗаказТовары.Номенклатура КАК Номенклатура,
ВнутреннийЗаказТовары.Количество КАК Заказано,
ЕСТЬNULL(ПродажиОбороты.КоличествоОборот, 0) / 3 КАК СреднееЗа3Месяца
ИЗ
Документ.ВнутреннийЗаказ.Товары КАК ВнутреннийЗаказТовары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
ПО ВнутреннийЗаказТовары.Номенклатура = ПродажиОбороты.Номенклатура
ГДЕ
ВнутреннийЗаказТовары.Ссылка = &Ссылка
Обратите внимание на функцию ЕСТЬNULL. Без неё любая попытка поделить пустое значение на 3 приведет к тому, что в колонке среднего значения будет пустота, что некорректно с точки зрения пользователя.
Если в документе ВнутреннийЗаказ содержится большое количество строк, прямое соединение с виртуальной таблицей может замедлить работу. Проанализируем более профессиональный подход — использование временных таблиц:
ВТ_ТоварыЗаказа.Продажи.Обороты, устанавливая в параметрах виртуальной таблицы отбор по номенклатуре из нашей временной таблицы.Это позволит системе 1С не высчитывать обороты по всей базе за 3 месяца, а сосредоточиться только на нужных позициях.
Чтобы отчет работал динамически от текущей даты без принудительного ввода параметров пользователем, выясним, как настроить выражения в СКД. Перейдем на закладку "Параметры" и для ДатаКонца укажем выражение ТекущаяДата().
Для параметра НачалоПериода можно использовать более сложную конструкцию, чтобы всегда захватывать три полных месяца:
ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&КонецПериода, "МЕСЯЦ"), "МЕСЯЦ", -2)
Такой подход позволит избежать ситуации, когда расчет идет от середины текущего месяца, что может искажать "среднее" значение из-за неполного периода.
При делении количества на 3 мы почти всегда будем получать дробное число. Для корректного отображения в запросе можно использовать функцию ВЫРАЗИТЬ, например: ВЫРАЗИТЬ(Результат КАК ЧИСЛО(15, 2)).
Однако в СКД рекомендуется другой способ. Выясним причину: если мы округлим значение прямо в запросе, то при расчете общих итогов по группировкам может возникнуть погрешность округления. Лучше оставить число в первозданном виде, а на вкладке "Наборы данных" или "Оформление" в поле "Оформление" задать форматную строку ЧЦ=15; ЧДЦ=2. Это обеспечит визуальную точность без потери данных для расчетов.
Рассмотрим ситуацию, которую часто упускают начинающие разработчики. Среднее число продаж "3 штуки в месяц" может быть ложным, если товара фактически не было на складе 2 месяца из 3-х. В этом случае реальный спрос гораздо выше.
Для продвинутого решения задачи рекомендуется анализировать не просто обороты продаж, но и остатки на каждый день периода. Если КоличествоОстаток был равен 0, этот день не должен участвовать в расчете "среднего", так как продаж не могло быть физически. Это превращает задачу из простого деления на 3 в расчет "средних продаж в дни наличия товара".
Мы разберем по шагам итоговый алгоритм создания механизма:
Товары документа ВнутреннийЗаказ.ПродажиОбороты по полю Номенклатура.ЕСТЬNULL для обработки отсутствующих продаж.ДОБАВИТЬКДАТЕ.ТекущаяДата().Следуя этим правилам, мы получим надежный и производительный инструмент для анализа продаж, который поможет бизнесу точнее планировать складские запасы.