AI Asist
v2
Д
Д

Плейбук: прогноз заказы-продажи, статика WB

← Заметки  ·  Раздел: Wildberries  ·  Файл: data/notes/wb/static-orders-sales-forecast-playbook.md

Плейбук: прогноз заказы-продажи, статика WB

Срабатывает, когда пользователь просит:

  • «прогноз заказов и продаж»;
  • «статичный прогноз на месяц»;
  • «прогноз по артикулам с учетом размеров»;
  • «возьми последнюю неделю как эталон»;
  • «прогноз заказы-продажи статика».

Статика означает: не экстраполируем темп роста и не строим тренд. Берём последнюю закрытую неделю как текущий эталон недельного спроса по артикулу и умножаем на число недель.


Когда использовать

Использовать для короткого операционного прогноза поставки/закупки, когда:

  1. Нужен прогноз на 4 недели / месяц.
  2. По артикулу уже есть последняя закрытая неделя заказов.
  3. По размерам недельных данных мало, поэтому размерную сетку надо брать по более длинному окну.

Не использовать как динамический forecast. Если пользователь просит «с учётом темпа роста», нужно делать отдельный сценарий с WoW/трендом.


Магазины

Магазин shop_id
Siluetta WB 3
Tote WB 5

Если магазин не указан, брать из контекста. Если контекста нет — уточнить.


Источники

Метрика Источник
Эталон заказов по артикулу funnel_period.orders_count
Размерная доля orders.tech_size, orders.srid
Выкуп по размеру orders + sales по srid
Продажа/выкуп sales.srid, sale_id NOT LIKE 'R%'
Возврат sales.srid, sale_id LIKE 'R%'
Отмена orders.is_cancel

Главное правило: недельную базу заказов по артикулу брать из funnel_period, а размерную структуру и выкуп по размеру считать по ID через orders/sales.


Периоды

Эталон недели

Последняя закрытая календарная неделя Пн-Вс.

Пример для текущей даты 2026-07-08:

2026-06-29 … 2026-07-05

Брать exact-window из funnel_period:

WHERE period_start = :week_since
  AND period_end = :week_to

Размерная доля

Брать весь доступный период по SKU или согласованное длинное окно, например с мая.

orders.date >= :size_since

Причина: по размерам одной недели мало, сетка может шуметь.

Выкуп по размеру

Брать тот же длинный период, что и размерную долю. Считать по закрытым ID:

Выкуп по размеру = buyout_net / (buyout_net + returns + cancels)

unresolved / в пути в знаменатель не включать.


Формулы

weekly_orders_sku = funnel_period.orders_count за последнюю закрытую неделю
forecast_orders_total = weekly_orders_sku × weeks

size_share = orders_size / orders_all
forecast_orders_size = forecast_orders_total × size_share

buyout_rate_size = buyout_net_size / (buyout_net_size + returned_size + cancelled_size)
forecast_sales_size = forecast_orders_size × buyout_rate_size

Округление:

  • forecast_orders_size округлять до целых штук.
  • forecast_sales_size округлять до целых штук.
  • После округления проверить, что сумма размеров близка к итогу; если расходится на 1-2 шт, поправить самый крупный размер.

SQL: недельный эталон по артикулу

SELECT
  sku,
  nm_id,
  orders_count,
  orders_sum_rub,
  cancel_count,
  buyouts_count,
  buyout_percent
FROM funnel_period
WHERE shop_id = :shop_id
  AND sku = :sku
  AND period_start = :week_since
  AND period_end = :week_to;

Если exact-window нет, не складывать дневные orders как замену без пометки. Сказать, что кабинетная воронка за закрытую неделю не загружена, и при необходимости запустить ingest:

.venv/bin/python scripts/ingest_wb.py --shop-id :shop_id funnel --from YYYY-MM-DD --to YYYY-MM-DD

SQL: размерная доля и выкуп по размеру

WITH sales_by AS (
  SELECT
    shop_id,
    srid,
    MAX(CASE WHEN lower(coalesce(sale_id, '')) NOT LIKE 'r%' THEN 1 ELSE 0 END) AS has_sale,
    MAX(CASE WHEN lower(coalesce(sale_id, '')) LIKE 'r%' THEN 1 ELSE 0 END) AS has_return
  FROM sales
  WHERE shop_id = :shop_id
    AND sku = :sku
  GROUP BY shop_id, srid
),
ids AS (
  SELECT
    o.srid,
    o.tech_size,
    o.is_cancel,
    COALESCE(s.has_sale, 0) AS has_sale,
    COALESCE(s.has_return, 0) AS has_return,
    CASE
      WHEN COALESCE(s.has_sale, 0) = 1
       AND COALESCE(s.has_return, 0) = 0
      THEN 1 ELSE 0
    END AS buyout_net,
    CASE
      WHEN o.is_cancel = 0
       AND COALESCE(s.has_sale, 0) = 0
       AND COALESCE(s.has_return, 0) = 0
      THEN 1 ELSE 0
    END AS unresolved
  FROM orders o
  LEFT JOIN sales_by s
    ON s.shop_id = o.shop_id
   AND s.srid = o.srid
  WHERE o.shop_id = :shop_id
    AND o.sku = :sku
    AND o.date >= :size_since
    AND o.date < :size_to
)
SELECT
  tech_size,
  COUNT(*) AS orders_ids,
  SUM(is_cancel) AS cancels,
  SUM(has_sale) AS sold_ids,
  SUM(has_return) AS returned_ids,
  SUM(buyout_net) AS buyout_net_ids,
  SUM(unresolved) AS unresolved_ids,
  ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS size_share_pct,
  ROUND(
    100.0 * SUM(buyout_net)
    / NULLIF(SUM(buyout_net) + SUM(has_return) + SUM(is_cancel), 0),
    1
  ) AS buyout_closed_pct
FROM ids
GROUP BY tech_size
ORDER BY tech_size;

Пример расчёта

Вход:

weekly_orders_sku = 96
weeks = 4
forecast_orders_total = 384

Размерная сетка и выкуп:

L: доля 26.7%, выкуп 33.3%
M: доля 43.6%, выкуп 29.1%
S: доля 29.7%, выкуп 35.1%

Результат:

Размер | Доля | Ср. заказов/нед | Прогноз заказов 4 нед | Выкуп | Прогноз продаж
L      | 26.7% | 25.6            | 102                   | 33.3% | 34
M      | 43.6% | 41.8            | 167                   | 29.1% | 49
S      | 29.7% | 28.6            | 114                   | 35.1% | 40
ИТОГО  | 100%  | 96.0            | 384                   | 32.0% | 123

Формат ответа

База:
- эталон недели: 2026-06-29 … 2026-07-05
- заказы по артикулу: 96/нед
- прогноз: 4 недели
- размерная доля: по всему доступному периоду с 2026-05-01
- выкуп: по закрытым ID через srid

Размер | Доля размера | Средн. заказов/нед | Прогноз заказов 4 нед | Выкуп по размеру | Прогноз продаж
...

После таблицы дать короткий вывод:

  • общий прогноз заказов;
  • общий прогноз продаж/выкупов;
  • какой размер основной по заказам;
  • какой размер лучше по выкупу.

Чек-лист

  1. Эталон недельных заказов взят из funnel_period.orders_count, не из orders.
  2. Неделя закрытая Пн-Вс.
  3. Размерная доля не взята из одной недели, если данных мало.
  4. Выкуп по размеру посчитан через srid, возвраты привязаны к тому же ID.
  5. В пути/unresolved не включены в знаменатель выкупа по закрытым.
  6. В ответе явно сказано, что прогноз статичный: рост WoW не применяется.
Фильтры