Этто Плюс — Закупки  ›  Методика финансовых метрик

← к рекомендациям

О чём эта страница

На главной странице сверху висят четыре цифры — это сводный финансовый портрет текущего пула рекомендаций. Ниже разбираем, как считается каждая, из каких полей в МойСклад берутся данные, и где формула делает упрощения, которые имеет смысл уточнить со временем.

Содержание: ① Упущ. выгода / неделя ② Нужно заказать всего ③ Сумма закупки (бюджет) ④ Маржа этого заказа Глоссарий полей

① Упущенная выгода / неделя 689 778 ₽

Сколько денег компания теряет за неделю прямо сейчас из-за дефицита товара — в сумме по всем 1011 pending-рекомендациям к закупке.

упущ_выгода_недели = max(0, ср_продажи_день × 7 − доступный_остаток) × цена_продажи
// складываем по всем SKU в рекомендациях

Логика: если на складе осталось столько, что хватит на неделю — упущения нет. Если нет (например, средняя продажа 3 шт/день, а на складе 5 шт.) — за неделю мы могли продать 21 шт., но продадим только 5; разницу × цену продажи и теряем.

Пример (топ-1 по упущ. выгоде): Топ трикотажный облегченный ЭттоПлюс 25108 Размер 50-60 · слоновая кость
ср. продажи / день0.867 шт.
× 7 дней6.07 шт.
− доступный остаток0 шт.
= дефицит за неделю6.07 шт.
× цена продажи2100 ₽
упущ. выгода / нед12 744 ₽
Почему «нетто»-продажи (с учётом возвратов). ср_продажи_день берётся из витрины marts.velocity.avg_daily, которая считается как (отгрузки 90д − возвраты 90д) / 90. Это уже чистый сигнал спроса.

② Нужно заказать всего 9 159 шт.

Сумма рекомендованных закупок в штуках по всем pending-строкам.

кол-во к закупке (SKU) = max(0, ⌈ср_продажи_день × 60⌉ − доступно_по_МС)
доступно_по_МС = остатокрезерв + ожидание (в пути)
всего = Σ по всем SKU в рекомендациях

Логика: на каждом SKU стремимся к запасу на 60 дней вперёд. Если на складе уже больше — рекомендуем 0 (и SKU не попадает в список). 60 дней выбраны как разумная цель: достаточно, чтобы не перезаказывать каждую неделю, и не слишком много, чтобы не омертвлять капитал в неликвиде.

Эта метрика рассчитывается прямо при формировании рекомендаций (см. marts.recommendations.qty_recommended). На главной странице её можно уменьшить — закупщик может ввести своё число при утверждении (кнопка «±»).

③ Сумма закупки (бюджет) 6 583 850 ₽

Сколько денег нужно потратить, чтобы закрыть все pending-рекомендации по закупочным ценам.

стоимость заказа (SKU) = кол-во_к_закупке × эффективная_закупка
эффективная_закупка = COALESCE(buy_price, sale_price × 0.3)
всего = Σ по всем SKU
Важное упрощение. В МойСклад у клиента закупочная цена заполнена примерно у 70% SKU (703 из 1011 в текущей выборке). Для остальных мы берём sale_price × 0.3 как грубую оценку (наценка ~3× для plus-size, значение уточнено клиентом 17.05.2026). После того как клиент дозальёт реальные закупки в карточки товаров, эта цифра станет точной.
Пример: Топ трикотажный облегченный ЭттоПлюс 25108 Размер 50-60 · слоновая кость
кол-во к закупке124 шт.
цена продажи2100 ₽
закупочная (или sale × 0.3)624 ₽
сумма закупки77 376 ₽

④ Маржа этого заказа 18 873 175 ₽

Сколько чистых денег принесёт заказ, если всё закупленное будет распродано по цене продажи (валовая маржа без учёта операционных расходов).

потенц. выручка (SKU) = кол-во_к_закупке × цена_продажи
маржа (SKU) = потенц. выручкастоимость заказа
всего = Σ по всем SKU

Потенциальная выручка по этому пулу: 25 457 025 ₽.
Затраты: 6 583 850 ₽.
Маржа: 18 873 175 ₽.

Пример: Топ трикотажный облегченный ЭттоПлюс 25108 Размер 50-60 · слоновая кость
потенц. выручка+ 260 400 ₽
− сумма закупки− 77 376 ₽
маржа заказа183 024 ₽
Что НЕ учтено в маржe (важно): логистика, таможня, банковская комиссия эквайринга, аренда магазинов, ФОТ, скидки, маркетинг. Это валовая маржа товара по чек-цене. Чистая операционная маржа всегда ниже.

Глоссарий полей

Откуда берутся исходные значения:

ср_продажи_день
marts.velocity.avg_daily = qty_90d / 90, где qty_90d — отгрузки за 90 дней минус возвраты за 90 дней. Источник: staging.sales_position (поднимается из raw.demand и raw.salesreturn МойСклад).
доступный_остаток (= "Доступно" в МС)
В формуле дозакупки используется то же самое значение «Доступно», которое МС показывает в карточке заказа поставщику: Остаток − Резерв + Ожидание (в пути).
Технически у нас это складывается из marts.stock_current.available (= quantity − reserve) плюс in_transit_total по всем складам. Источник: МойСклад API report/stock/bystore. Обновляется при каждом ETL-проходе.
почему qty=0 при остатке=0
Если на складе остаток 0, но в пути уже едет N шт. — система видит: доступно = 0 − 0 + N. Если N покрывает 60 дней спроса по текущим продажам, кол-во к закупке = 0 (заказывать не нужно, всё уже в пути). В обосновании строки тогда видно «в пути N шт».
цена_продажи (sale_price)
marts.product_master.sale_price = первая позиция массива salePrices из карточки товара МойСклад, делённая на 100 (API возвращает в копейках).
buy_price (закупочная)
marts.product_master.buy_price = buyPrice.value из карточки, делённая на 100. Заполнена не у всех SKU — там, где пусто, используем sale_price × 0.3.
кол-во_к_закупке
marts.recommendations.qty_recommended = max(0, ⌈avg_daily × 60⌉ − available_total).
ABC, XYZ
marts.velocity.abc_class — ABC по выручке за 90 дней (80/15/5).
marts.velocity.xyz_class — XYZ по коэф. вариации продаж (≤0.5 → X, ≤1.0 → Y, >1.0 → Z).

Где это посчитано

Скоркард-агрегаты вычисляются на лету при каждом открытии главной страницы (SQL-запрос в api/main.py, функция index). Это значит, что любая утверждённая или отклонённая рекомендация сразу пересчитает все четыре числа — в реальном времени.

Витрины (marts.*), на которых строится этот расчёт, перестраиваются ETL-задачей — каждые 30 минут инкрементально и по запросу полностью. Свежесть данных написана в шапке главной страницы — «Последний ETL: …».