Плейбук: допоставка WB по статичному прогнозу
Срабатывает, когда пользователь просит:
- «расчет поставки»;
- «сколько допоставить»;
- «допоставка с учетом прогноза»;
- «план поставки по размерам»;
- «куда поставить по регионам»;
- «поставка с учетом ИЛ / локализации» (ранее ИРП — отменён WB для заказов с 13.07.2026;
теперь действует индекс локализации ИЛ, см.
data/knowledge/wb/localization-index.md).
Использует результат плейбука:
data/notes/wb/static-orders-sales-forecast-playbook.md
Цель
Сделать простой операционный план допоставки:
- Сколько штук нужно по размерам на 4 недели.
- Куда разложить поставку по доступным регионам.
- Где есть перекос текущего FBO-остатка и вместо закупки/новой поставки нужно сначала делать перераспределение.
Главный принцип
Для закупки/допоставки основной объем считать от прогноза продаж/выкупов, а не от прогноза заказов.
Но для WB и ИЛ (индекса локализации) обязательно держать в голове, что заказный поток тоже важен:
- прогноз продаж показывает, сколько товара реально будет потреблено;
- прогноз заказов показывает нагрузку на FBO и локализацию;
- если buyout низкий, товар временно уезжает клиентам и часть вернется позже.
В ответе можно показывать оба числа, но рекомендацию по новой поставке делать от прогноза продаж/выкупов, если пользователь не просит страховой запас под весь заказный поток.
Источники
| Метрика | Источник |
|---|---|
| Прогноз заказов/продаж | плейбук static-orders-sales-forecast-playbook.md |
| Текущий FBO | последний stocks_snapshot.quantity |
| В пути к клиенту | stocks_snapshot.in_way_to_client |
| В пути от клиента | stocks_snapshot.in_way_from_client |
| Регион склада | app.reference.warehouses.region_for(warehouse) |
| Доступные регионы поставки | бизнес-контекст / REGION_AVAILABILITY / REDISTRIBUTION_TARGETS |
По задаче с ограниченной поставкой использовать только разрешенные пользователем регионы. Например: «можем поставить только в Центр, Юг, Поволжье».
Обязательные таблицы в ответе
1. Таблица прогноза
Формат:
Размер | Прогноз заказов | Прогноз выкупов/продаж | Текущий FBO | Довезти по продажам
Пример:
Размер | Прогноз заказов | Прогноз выкупов/продаж | Текущий FBO | Довезти по продажам
L | 102 | 34 | 4 | 30
M | 167 | 49 | 6 | 43
S | 114 | 40 | 41 | 0
ИТОГО | 384 | 123 | 51 | 73
Формула:
Довезти по продажам = max(0, Прогноз выкупов/продаж − Текущий FBO)
Если нужно учитывать возвраты из пути:
Доступно с возвратами = FBO + in_way_to_client × (1 − buyout_rate) + in_way_from_client
Но для рабочей поставки по умолчанию не уменьшать план на весь ожидаемый возврат: возвраты не гарантированы по сроку и региону.
Можно упомянуть минимальный сценарий с возвратами отдельно, но не делать его основной рекомендацией без явного запроса.
2. Таблица допоставки
Формат:
Регион поставки | L | M | S | Итого
Пример:
Регион поставки | L | M | S | Итого
Центр | 10 | 12 | 0 | 22
Юг + СК | 9 | 20 | 0 | 29
Поволжье | 11 | 11 | 0 | 22
ИТОГО | 30 | 43 | 0 | 73
Как распределять допоставку по регионам
- Взять регионы, куда пользователь реально может поставить.
- Взять доли спроса по выкупам в этих регионах (канон ниже).
- Нормализовать доли внутри доступного пула.
- Разложить каждую размерную потребность по этим долям.
- Округлить методом наибольших остатков — как в
size_mix.py, не «добить крупнейший».
Если есть текущий региональный перекос по конкретному размеру, распределение допоставки можно смещать в пользу дефицитных регионов, а не строго по долям спроса.
🔴 Что означает регион после 15.08.2026
Склад хранения на FBO не выбирается. Товар сдаётся в ПВЗ, СЦ или ПФЦ, раскладывает
его по складам сам WB; с 29.09.2026 за перевозку от точки сдачи до склада берут 3–7 ₽/л.
Подробности — knowledge-base-mp/wb/fbo/README.md.
Поэтому региональные доли ниже отвечают на «куда физически везти короба и где держать
FBS», а не на «где окажется запас». Обещать клиенту регион на FBO нельзя. Где товар
реально лёг — только через публичную карточку, см. stock-geo-playbook.md.
Канон: доли спроса по округам
Срез 18.09.2026. Живые магазины WB (Siluetta shop 3 + Tote shop 5), весь доступный период: 7 794 заказа, 3 031 выкуп.
| Округ | Доля заказов | Выкуп | Доля выкупов |
|---|---|---|---|
| Москва и МО | 20,9% | 36,5% | 19,7% |
| Южный и СК | 17,7% | 37,1% | 16,9% |
| Приволжский | 17,0% | 37,7% | 16,5% |
| Сибирь + ДВ | 12,7% | 40,8% | 13,3% |
| Северо-Западный | 11,1% | 36,7% | 10,5% |
| Центральный (без МО) | 10,7% | 36,0% | 9,9% |
| Уральский | 7,4% | 40,2% | 7,6% |
| Прочие (СНГ) | 2,5% | 88,5% | 5,6% |
Бакеты — те же 8, что у складов (app.reference.warehouses.REGION_ORDER): Москва и МО
вынесена из Центрального ФО (мы отгружаем их раздельно), Сибирский+Дальневосточный
объединены, Южный+Северо-Кавказский объединены.
Сверено по четырём независимым срезам — shop 3 отдельно, оба живых вместе, последние 120 дней, все три магазина включая закрытый (25 527 заказов). Нигде не разошлось больше чем на 1,5 п.п. География спроса — самая устойчивая величина в наших данных.
Выкуп по округам почти не различается (36–41%), поэтому доля выкупов ≈ доля заказов. Единственное исключение — СНГ: выкуп 88,5%, там заказы практически не отменяются.
Нормализация под доступный пул
Пример для четырёх округов, которые сейчас в REGION_AVAILABILITY = 1.0:
| Округ | Доля в пуле | На 300 шт |
|---|---|---|
| Москва и МО | 31,3% | 94 |
| Южный и СК | 26,8% | 80 |
| Приволжский | 26,2% | 79 |
| Центральный | 15,7% | 47 |
⚠ Эти четыре округа покрывают только 63% спроса. Отбрасываются Сибирь (13,3%), Северо-Запад (10,5%), Урал (7,6%) и СНГ (5,6%).
⚠ Список доступных округов может быть устаревшим. REGION_AVAILABILITY обнулил
Северо-Запад и Урал 26.07.2026 (сгорели Шушары, Екатеринбург выпал из приёмки), но срез
knowledge-base-mp/wb/fbo/warehouses-status-2026-09.md от 16.09 говорит иначе: Уткина
Заводь восстановлен, Екатеринбург после инцидента 07.08 вероятно открыт, Сибирь вообще
без инцидентов — «самый целый макрорегион». 31,4% выкупов — слишком много, чтобы
отбрасывать по устаревшему основанию. Перед расчётом подтверждать пул у пользователя,
а не брать REGION_AVAILABILITY молча.
Как обновить цифры
python scripts/region_mix.py
python scripts/region_mix.py --shop 3 --since 2026-05-21
python scripts/region_mix.py --only "Москва и МО,Южный и СК,Приволжский,Центральный" --plan 300
С Windows уходит на production Hetzner. Read-only.
Метод внутри:
- округ берётся по адресу покупателя —
oblastOkrugName+regionNameизorders.raw_json, черезapp.reference.warehouses.region_for_delivery. Не по складу отгрузки: с 15.08.2026 склад в заказе схлопнут в «Склад WB» и географии не несёт; - выкуп — через
srid(ID с продажей и без возврата по тому же заказу), как вbuyout-playbook.md. Агрегаты по датам не годятся: возврат приезжает позже продажи; - по умолчанию берутся живые магазины 3 и 5. Закрытый shop 1 доступен через
--shop 1, но в дефолт не входит — тянуть доли из закрытого магазина в живой без проверки нельзя.
Когда пересчитывать: доли устойчивы, ежемесячно смысла нет. Поводы — смена ассортимента или ценовой полки, запуск региональной рекламы, изменение состава доступных точек сдачи, накопление ещё ~2 000 выкупов. Обновили — переписать таблицу выше вместе с датой среза и размером выборки.
Перекос остатков и перераспределение
Обязательная пометка в ответе:
Если по размеру текущий FBO уже покрывает прогноз продаж, но товар лежит не там, где спрос, новую поставку по этому размеру не делать. Сначала делать перераспределение между складами.
Типовой случай:
S: прогноз продаж 40 шт, текущий FBO 41 шт → допоставка 0.
Но S перекошен в Центр, а спрос есть в Юге и Поволжье.
Решение: не закупать S, а перераспределить часть S из Центра в Юг/Поволжье.
Почему это важно:
- закупка лишнего размера замораживает деньги;
- товар может лежать в регионе с избытком и не улучшать локализацию;
- для ИЛ важна локальность заказов (ступенчатый КТР по артикулу — см.
data/knowledge/wb/localization-index.md), поэтому перекос FBO может портить локализацию даже при нормальном общем остатке; причём зоны ИЛ — официальные ФО WB (Москва+МО входят в ЦФО, ЮФО+СКФО и СФО+ДФО объединены), а не наши бизнес-кластеры.
SQL: текущий FBO по размерам
SELECT
tech_size,
SUM(quantity) AS fbo,
SUM(in_way_to_client) AS in_way_to_client,
SUM(in_way_from_client) AS in_way_from_client
FROM stocks_snapshot
WHERE shop_id = :shop_id
AND sku = :sku
AND snapshot_at = (
SELECT MAX(snapshot_at)
FROM stocks_snapshot
WHERE shop_id = :shop_id
AND sku = :sku
)
GROUP BY tech_size
ORDER BY tech_size;
SQL: текущий FBO по регионам и размерам
Регион склада лучше считать в Python через:
from app.reference.warehouses import region_for
Базовая выгрузка:
SELECT
warehouse,
tech_size,
SUM(quantity) AS fbo,
SUM(in_way_to_client) AS in_way_to_client,
SUM(in_way_from_client) AS in_way_from_client
FROM stocks_snapshot
WHERE shop_id = :shop_id
AND sku = :sku
AND snapshot_at = (
SELECT MAX(snapshot_at)
FROM stocks_snapshot
WHERE shop_id = :shop_id
AND sku = :sku
)
GROUP BY warehouse, tech_size
ORDER BY warehouse, tech_size;
Расчёт с возвратами, если нужен минимальный сценарий
Если пользователь просит «минимум с учетом возвратов», использовать:
available = FBO + in_way_to_client × (1 − buyout_rate_size) + in_way_from_client
need_min = max(0, forecast_sales_size − available)
В ответе явно подписать:
Это минимальный сценарий. Он рискован, потому что возвраты могут прийти позже нужного срока
и не в тот регион.
Чек-лист
- Есть таблица прогноза: заказы, продажи, FBO, довезти.
- Есть таблица допоставки по регионам и размерам.
- Допоставка считается от прогноза продаж/выкупов, если пользователь не просил иначе.
- Доступные регионы ограничены тем, что указал пользователь; пул подтверждён явно,
а не взят молча из
REGION_AVAILABILITY(он датирован 26.07.2026 и мог устареть). - Сказано, какую долю спроса покрывает выбранный пул округов.
- Указано, что на FBO с 15.08.2026 регион не выбирается: доли задают точку сдачи, а не место хранения.
- Если размер покрыт общим FBO, но есть региональный перекос, указано перераспределение.
- Не уменьшать основной план на ожидаемые возвраты без явного запроса.
- В ответе есть короткий вывод: что покупать/везти, а что не трогать.