Skip to main content

Методика расчёта в прогнозах

В рамках аналитики для Дарксторов и Вайтсторов рассчитываются разли 

1. Совокупное отклонение плана и прогноза

Почасовые величины

Для каждого часа h = 0..23:

  • Прогноз (в тултипе «прогноз»):
    stat = round( cnt_прогноза × extraNorm, 1 )
    где cnt — из forecastStat[restaurant][date][hour].

  • План / факт (вторая колонка):
    plan = round( sum_qty по часу, 1 ), источник зависит от даты:

    • будущее: план из смен сборщиков — часы смен × скорость пользователя (userSpeedAvg или средняя $speed);

    • прошлое / сегодня: факт из ttStat — sum_qty за час.

  • Дельта по часу:

    • прошлое/сегодня: delta = round(plan − stat, 1) (факт минус прогноз);

    • будущее: delta = round((stat − plan) / speed) — нехватка/избыток в чел.-часах.

Дневная совокупная дельта (число на карточке)

ordersDayDeltaRaw = round( round(Σ plan, 1) − round(Σ stat, 1) )

Показывается |ordersDayDeltaRaw| в компактном формате. Знак влияет на цвет фона (>0 — danger, <0 — warning).

Процент отклонения (sMAPE)

По часу:

smape_h = 2 × (plan − stat) / (plan + stat)

«Норма» по часу в прошлом: |delta| ≤ 3 или |smape_h| < 0.15 (15%). Иначе err: недопрогноз / перепрогноз.

По дню (фон карточки, не отдельное число в UI):

daySmape = 2 × (Σplan − Σstat) / (Σplan + Σstat) // если Σplan + Σstat > 0

Зелёный фон, если есть прогноз хотя бы в одном часу (stat > 0) и |daySmape| < 0.15.
В prevDayPlaceTransform.jsonata та же логика явно названа $daySmape; в актуальном dayPlaceTransform формула встроена в $buildOrdersContentColor() без отдельной переменной.

Важно: ordersDayDeltaRaw — это разница сумм в заказах (шт.), а не процент. Процент — только sMAPE для подсветки и почасовых статусов.


2) Выручка

Формула в UI:

dayRevenue = statDayNumber(revenueStat)

statDayNumber берёт число по place.id и дате ($dateStr, запасной ключ $dateStatStr).

Откуда данные:

revenueStat[restaurant][YYYY-MM-DD] = Σ value // time_series type 42 за день

Процент отклонения: в dayPlaceTransform нет sMAPE/плана для выручки — только факт из API; при отсутствии числа показывается «—».


3) Продуктивность

Формула:

dayEmployeesCount = count(distinct userId) по сменам с all = 1

dayProductivity =

если dayRevenue != null:

если dayEmployeesCount \> 0 → dayRevenue / dayEmployeesCount

иначе → 0

иначе → null → в UI «—»

Смысл: выручка за день / число сотрудников на смене

Процент отклонения: нет.


4) Средний заработок

Формула в UI:

dayAvgEarnings = statDayNumber(avgEarningsStat)

Откуда данные:

avgEarningsStat[restaurant][YYYY-MM-DD] = Σ value // time_series type 100

В биндинге поле суммируется ($sum(avgEarnings)), в интерфейсе подпись «Средний заработок» / «Сред. заработок» — это готовое дневное значение из ряда 100, без дополнительного деления в Jsonata.

Процент отклонения: нет.


5) Трудоёмкость — факт / прогноз

Прогноз (чел.-ч)

workHoursByDay = hoursStat[ place.id ][dateStr]

workHoursForecastHours = round( 0.9 × [ h53 + h52, h52 ][0] )

Берётся h53+h52, если есть h53, иначе h52; затем 90% и математическое округление.

Типы 52/53 в time_series — прогнозные часы трудоёмкости.

Факт (чел.-ч)

workHoursFactDuration = Σ duration по сменам дня ($total.duration), иначе 0

В тултипе при наличии stat по полям h51/c51:

факт_часы = [ h51 + c51, h51 ][0]

если нет stat — round(workHoursFactDuration) из смен.

Тип 51 — фактические часы в ряде.

Дельта (бейдж на карточке)

workHoursDelta = workHoursForecastHours − round(workHoursFactDuration)

Отображение: +N / -N / галочка при 0; цвет по порогам (>0−5..0≤−5). Это разница в часах, не процент.

Процент отклонения (sMAPE): для трудоёмкости не используется.