В процессе управления продажами перед руководством и аналитиками часто возникает задача: оценить, насколько реальные показатели выполнения плана на текущий день соответствуют итоговым ожиданиям к концу месяца. Если у вас внедрена конфигурация 1С:Управление нашей фирмой (УНФ) или любая другая торговая система на платформе 1С, стандартных отчетов по продажам может не хватать. Возникает необходимость добавить колонку с динамическим прогнозом выполнения плана продаж.
В этой статье мы подробно рассмотрим, как реализовать механизм математического прогнозирования (методом линейной экстраполяции или Run Rate) в системе компоновки данных (СКД) 1С. Мы разберем как сложные решения на уровне языка запросов, так и более простые способы настройки через вычисляемые поля СКД, а также научимся делать прогноз более точным с учетом рабочих и праздничных дней.
Прежде чем приступать к написанию кода в 1С, давайте разберем математическую модель, которую мы хотим построить. Предположим, у нас есть плановые показатели на месяц и фактические продажи на текущую дату (например, на 15-е число месяца). Нам необходимо понять, какую сумму продаж мы получим в конце месяца, если текущий темп (тенденция) сохранится.
Проанализируем базовый алгоритм линейного прогнозирования:
Рассмотрим конкретный пример. План продаж на месяц составляет 20 000 рублей. На 15-й день месяца фактические продажи составили 8 000 рублей. Проведем расчет:
8 000 / 15 = 533.33 рублей.533.33 * 30 = 16 000 рублей.(16 000 / 20 000) * 100 = 80%.Теперь выясним, как реализовать эту математическую модель непосредственно внутри структуры СКД в 1С.
Если вы привыкли проектировать логику отчетов на уровне базы данных, лучшим решением будет вычисление временных интервалов прямо в запросе. Для этого мы будем использовать функции встроенного языка запросов 1С: РАЗНОСТЬДАТ, НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА.
Ключевая проблема при написании запроса — правильно рассчитать количество прошедших дней и общее количество дней в месяце, избегая при этом жесткого кодирования дат. Платформа 1С позволяет динамически получать эти сведения из одного параметра — даты окончания отчета (&КонецПериода).
Рассмотрим по шагам, как вычисляются нужные нам интервалы в запросе:
Мы берем разность в днях между началом месяца даты отчета и самой датой отчета. Так как функция РАЗНОСТЬДАТ считает разницу между границами, нам необходимо добавить 1, чтобы учесть текущий день:
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ), &КонецПериода, ДЕНЬ) + 1
Для определения общего количества дней в текущем месяце (с учетом високосных годов и разной длины месяцев — 28, 29, 30 или 31 день) мы берем разность дат между началом и концом этого месяца:
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ), КОНЕЦПЕРИОДА(&КонецПериода, МЕСЯЦ), ДЕНЬ) + 1
При составлении запроса крайне важно защитить алгоритм от деления на ноль. Например, если отчет формируется в самую первую секунду месяца (1-го числа), разность дат может вернуть некорректное значение или спровоцировать системную ошибку. Используем условную конструкцию ВЫБОР.
Проанализируем пример готового пакета запроса СКД для вычисления прогноза:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура.КатегорияНоменклатуры КАК КатегорияТовара,
ЕСТЬNULL(ПланыПродаж.СуммаОборот, 0) КАК СуммаПлана,
ЕСТЬNULL(ПродажиОбороты.СуммаВыручкиОборот, 0) КАК СуммаВыполнения,
// Вычисляем количество прошедших дней
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ), &КонецПериода, ДЕНЬ) + 1 КАК ПрошлоДней,
// Вычисляем общее число дней в месяце
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ), КОНЕЦПЕРИОДА(&КонецПериода, МЕСЯЦ), ДЕНЬ) + 1 КАК ВсегоДней в Месяце
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ПланыПродаж.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПланыПродаж
ПО ПродажиОбороты.Номенклатура.КатегорияНоменклатуры = ПланыПродаж.Номенклатура.КатегорияНоменклатуры
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ИсходныеДанные.КатегорияТовара,
ВТ_ИсходныеДанные.СуммаПлана,
ВТ_ИсходныеДанные.СуммаВыполнения,
// Рассчитываем процент выполнения на текущую дату
ВЫБОР
КОГДА ВТ_ИсходныеДанные.СуммаПлана = 0 ТОГДА 0
ИНАЧЕ Округлить((ВТ_ИсходныеДанные.СуммаВыполнения / ВТ_ИсходныеДанные.СуммаПлана) * 100, 2)
КОНЕЦ КАК ПроцентВыполненияНаДату,
// Прогноз выполнения в денежном выражении (Run Rate)
ВЫБОР
КОГДА ВТ_ИсходныеДанные.ПрошлоДней = 0 ТОГДА 0
ИНАЧЕ (ВТ_ИсходныеДанные.СуммаВыполнения / ВТ_ИсходныеДанные.ПрошлоДней) * ВТ_ИсходныеДанные.ВсегоДнейВМесяце
КОНЕЦ КАК ПрогнозВыполненияСумма
ИЗ
ВТ_ИсходныеДанные КАК ВТ_ИсходныеДанные
Этот подход гарантирует высокую скорость работы отчета, так как все математические операции выполняются непосредственно СУБД на сервере перед выводом в СКД.
Если вы не хотите усложнять текст исходного запроса или предпочитаете работать в визуальном конструкторе СКД, платформа предоставляет прекрасную альтернативу — вкладку «Вычисляемые поля». На этом этапе мы можем оперировать ресурсами и реквизитами, используя стандартные функции СКД.
Выполним настройку по шагам:
ПрошлоДнейРазностьДат(НачалоПериода(&КонецПериода, "Месяц"), &КонецПериода, "День") + 1ВсегоДнейРазностьДат(НачалоПериода(&КонецПериода, "Месяц"), КонецПериода(&КонецПериода, "Месяц"), "День") + 1ПрогнозВыполненияВыбор Когда ПрошлоДней = 0 Тогда 0 Иначе (СуммаВыполнения / ПрошлоДней) * ВсегоДней КонецПреимущество вычисляемых полей заключается в том, что ваш запрос остается лаконичным, а вся прикладная математика легко перенастраивается в пользовательском режиме без изменения структуры метаданных конфигурации.
Линейный прогноз по календарным дням (описанный в предыдущих разделах) отлично подходит для непрерывных производств или интернет-магазинов, работающих без выходных. Однако в реальном бизнесе продажи распределяются неравномерно. В сегменте оптовой торговли (B2B) в субботу и воскресенье отгрузки обычно равны нулю. Если рассчитывать прогноз просто делением на календарные дни, то в начале недели прогноз будет искусственно завышаться, а после выходных — резко падать.
Для решения этой проблемы профессиональные аналитики строят прогнозы на основе рабочих дней по производственному календарю предприятия.
Давайте разберем, как модифицировать наш отчет для интеграции с производственным календарем 1С. Во всех типовых конфигурациях (включая УНФ) присутствует регистр сведений РегистрСведений.ДанныеПроизводственногоКалендаря.
Нам потребуется внести изменения в запрос СКД, чтобы получить точное количество рабочих дней:
ВЫБРАТЬ
// Считаем рабочие дни, которые уже прошли в этом месяце до текущей даты отчета
СУММА(ВЫБОР
КОГДА Календарь.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий), ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК ПрошлоРабочихДней,
// Считаем общее число рабочих дней в текущем месяце
СУММА(ВЫБОР
КОГДА КалендарьВесьМесяц.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий), ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК ВсегоРабочихДней
ПОМЕСТИТЬ ВТ_РабочиеДни
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК КалендарьВесьМесяц
ПО (КалендарьВесьМесяц.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ) И КОНЕЦПЕРИОДА(&КонецПериода, МЕСЯЦ))
ГДЕ
Календарь.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&КонецПериода, МЕСЯЦ) И &КонецПериода
После получения этих данных в запросе, расчет прогноза продаж будет выглядеть следующим образом:
Прогноз = (СуммаВыполнения / ПрошлоРабочихДней) * ВсегоРабочихДней
Этот метод полностью нивелирует «эффект выходных дней» и предоставляет руководству коммерческой службы максимально точные аналитические ожидания.
Мы детально рассмотрели три различных способа реализации математического прогнозирования в 1С. Подведем итоги их применимости:
Помните, что линейный прогноз (Run Rate) незаменим для новых торговых точек, у которых еще нет накопленной статистики продаж за прошлые периоды. По мере развития вашего бизнеса и накопления истории за 1–2 года, вы сможете перейти к более сложным моделям прогнозирования (например, учитывающим коэффициент сезонности или тренды прошлых лет).