Проекты / сквозной анализ цепи поставок
Проект · Python, SQL, DuckDB, 1С, симуляцияСквозной анализ цепи поставок
Когда товара нет на полке магазина, важно понять, где в цепочке «поставщик - склад - магазин» возникла проблема: от этого зависит, кто и что должен исправить. Расчёт восстанавливает движение товара по дням на всех этапах и для каждого дня дефицита в магазине называет причину.
Данные синтетические. Это симуляция сети магазинов электроники: 60 моделей смартфонов Apple, поставщик, 3 склада и 30 магазинов, 1 августа - 31 октября 2025 года, включая выход iPhone 17. Разбор использует только то, что есть в учётной системе: заказы поставщику, журнал движений и текущий остаток. Таблицы устроены как выгрузки из 1С: справочники со ссылками-GUID, журнал движений с видом движения «приход/расход», как в регистре накопления, и заказы поставщику с заказанным и подтверждённым количеством. В симуляцию специально заложены проблемы на каждом этапе, чтобы проверить, что разбор их находит. Названия моделей реальные, цены и объёмы условные.
- Задача. Дефицит в магазине может возникнуть на любом этапе: поставщик недопоставил, закупщик заказал мало, склад не довёз. Без разбора непонятно, кому и что исправлять.
- Что сделано. Восстановлены остатки каждого склада и магазина на каждый день, а для каждого дня дефицита причина определяется по пяти простым правилам - от магазина вверх по цепочке.
- Результат. Дефицит стоил сети около 308 млн ₽ - 5,4% продаж. 77% этих потерь - ошибки внутри сети, в закупе и распределении, которые можно исправить; остальное - нехватка товара у поставщика.
1. Как движется товар
Учётная система хранит только текущий остаток и журнал движений. Остаток на каждый прошлый день восстанавливается «откатом» назад: из сегодняшнего остатка вычитаются все движения после нужного дня. Так получена полная история по каждому складу и магазину - она совпала с истинной из симуляции в 100% случаев.
Дефицит в магазине бывает двух видов: весь день без товара (3 685 «магазино-дней» за период) и товар закончился за день (6 957). Во втором случае часть покупателей приходит, когда товара уже нет.
| Склад / магазин | 01.08 | 04.08 | 11.08 | 18.08 | 25.08 | 01.09 | 08.09 | 15.09 | 22.09 | 29.09 | 06.10 | 13.10 | 20.10 | 27.10 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 51 | 114 | 176 | 254 | 277 | 246 | 272 | 326 | 433 | 579 | 462 | 493 | 439 | 322 | |
| Краснодар 012 | 6 | 14 | 19 | 27 | 44 | 31 | 20 | 26 | 42 | 60 | 44 | 39 | 51 | 37 |
| Нижний Новгород 004 | 4 | 11 | 28 | 20 | 23 | 29 | 27 | 28 | 40 | 46 | 43 | 54 | 43 | 23 |
| Краснодар 009 | 5 | 10 | 14 | 29 | 23 | 18 | 16 | 23 | 42 | 55 | 35 | 41 | 47 | 39 |
| Нижний Новгород 007 | 9 | 13 | 16 | 17 | 14 | 24 | 30 | 36 | 37 | 51 | 40 | 32 | 28 | 27 |
| Санкт-Петербург 014 | 2 | 9 | 16 | 33 | 21 | 12 | 20 | 25 | 21 | 42 | 33 | 40 | 24 | 19 |
| Воронеж 011 | 5 | 9 | 8 | 15 | 16 | 13 | 14 | 20 | 28 | 51 | 44 | 39 | 32 | 20 |
| Нижний Новгород 010 | 3 | 5 | 13 | 20 | 18 | 12 | 15 | 22 | 33 | 38 | 30 | 39 | 22 | 20 |
| Воронеж 013 | 1 | 4 | 7 | 7 | 16 | 18 | 18 | 16 | 35 | 41 | 33 | 34 | 29 | 28 |
| Нижний Новгород 006 | 3 | 9 | 11 | 21 | 17 | 15 | 25 | 24 | 31 | 37 | 23 | 19 | 22 | 24 |
| Нижний Новгород 008 | 6 | 12 | 15 | 10 | 16 | 19 | 19 | 22 | 25 | 36 | 25 | 24 | 29 | 17 |
| Санкт-Петербург 003 | 2 | 3 | 9 | 17 | 21 | 15 | 21 | 16 | 27 | 35 | 28 | 36 | 23 | 18 |
| Краснодар 001 | 2 | 6 | 8 | 9 | 5 | 19 | 17 | 34 | 23 | 35 | 33 | 33 | 20 | 17 |
| Ростов-на-Дону 005 | 1 | 6 | 5 | 18 | 20 | 10 | 14 | 15 | 25 | 28 | 34 | 26 | 32 | 19 |
| Нижний Новгород 002 | 2 | 3 | 7 | 11 | 23 | 11 | 16 | 19 | 24 | 24 | 17 | 37 | 37 | 14 |
| 29 | 102 | 93 | 134 | 190 | 187 | 176 | 226 | 277 | 437 | 435 | 371 | 302 | 169 | |
| Самара 020 | 4 | 16 | 14 | 16 | 26 | 19 | 22 | 32 | 38 | 59 | 57 | 43 | 30 | 23 |
| Пермь 015 | 2 | 17 | 10 | 20 | 20 | 24 | 21 | 25 | 41 | 54 | 64 | 46 | 31 | 19 |
| Казань 017 | 3 | 12 | 11 | 15 | 29 | 18 | 16 | 24 | 38 | 46 | 46 | 46 | 32 | 14 |
| Уфа 018 | 3 | 12 | 4 | 18 | 24 | 20 | 27 | 34 | 22 | 36 | 36 | 34 | 29 | 14 |
| Уфа 022 | 1 | 7 | 8 | 12 | 10 | 22 | 26 | 16 | 26 | 43 | 36 | 37 | 37 | 17 |
| Пермь 016 | 5 | 11 | 12 | 10 | 13 | 18 | 13 | 18 | 23 | 47 | 43 | 40 | 18 | 16 |
| Самара 023 | 2 | 9 | 6 | 14 | 16 | 18 | 14 | 16 | 21 | 40 | 39 | 35 | 34 | 17 |
| Уфа 024 | 3 | 8 | 9 | 15 | 21 | 17 | 12 | 17 | 23 | 37 | 32 | 36 | 33 | 15 |
| Екатеринбург 021 | 1 | 6 | 11 | 7 | 25 | 13 | 10 | 22 | 25 | 35 | 44 | 27 | 29 | 14 |
| Пермь 019 | 5 | 4 | 8 | 7 | 6 | 18 | 15 | 22 | 20 | 40 | 38 | 27 | 29 | 20 |
| 22 | 77 | 93 | 133 | 202 | 216 | 243 | 297 | 282 | 333 | 308 | 289 | 325 | 250 | |
| Омск 029 | 4 | 19 | 25 | 23 | 32 | 38 | 44 | 56 | 51 | 68 | 48 | 46 | 65 | 47 |
| Омск 030 | 6 | 5 | 8 | 26 | 38 | 31 | 33 | 50 | 50 | 62 | 56 | 54 | 61 | 49 |
| Новосибирск 028 | 4 | 16 | 15 | 22 | 19 | 40 | 58 | 46 | 41 | 51 | 63 | 51 | 53 | 39 |
| Омск 026 | 3 | 15 | 17 | 12 | 34 | 42 | 42 | 55 | 55 | 50 | 44 | 49 | 50 | 31 |
| Омск 025 | 4 | 11 | 11 | 22 | 43 | 32 | 41 | 52 | 45 | 45 | 52 | 43 | 51 | 41 |
| Новосибирск 027 | 1 | 11 | 17 | 28 | 36 | 33 | 25 | 38 | 40 | 57 | 45 | 46 | 45 | 43 |
2. Как определяется причина
Для каждого дня дефицита разбор идёт по цепочке вверх и останавливается на первом ответе «да». Статус модели - новинка или выводимая - не важен: если товар продаётся, его нужно закупать.
3. Где теряются деньги
Потери дня без товара - все ожидаемые продажи этого дня. Если товар закончился за день, учёт не видит покупателей, пришедших позже; их число оценивается по среднему спросу и утреннему остатку - покупатели приходят случайно, и эту случайность можно посчитать.
Старт продаж iPhone 17. Новинки продаются с 27 сентября, но на них пришлось 113 млн ₽ - 37% всех потерь за период. Неделя с 29 сентября - пик всего периода: 56 млн ₽ потерь, из них 44 млн - новинки, больше всего iPhone 17 Pro. Главная причина - не квота поставщика, а распределение: на него приходится 60% потерь по новинкам, на дефицит у поставщика - 28%. 62% потерь - дни, когда товар закончился к вечеру: на старте спрос в разы выше обычного, и запаса магазина хватает ненадолго, хотя на складе товар есть. На старт новинки стоит поднимать запасы и частоту пополнения магазинов, а не только объём закупа.
4. Сквозная картина по одному товару
Один товар на всех этапах сразу - iPhone 16 Pro 256GB Black Titanium. Сверху - сколько закупщик заказал и сколько подтвердил поставщик, в середине - остаток каждого склада, внизу - сколько магазинов этого склада были в дефиците. Видно, как недопоставка и неравномерный закуп доходят до полок: пока один склад пуст, у его магазинов растёт дефицит.
5. Хватает ли запасов
Запас в днях - остаток, делённый на средние продажи в день; для склада - на продажи всех его магазинов. В среднем магазин держит 4,4 дня продаж товара, склад - 5,8 дня продаж своего региона. Пары «товар - магазин» и «товар - склад» сгруппированы по среднему запасу, и для каждой группы посчитано, как часто товар был в дефиците.
Склад с запасом до 5 дней продаж региона пуст 25% дней, с запасом 5-7 дней - 5%. Узкое место - склады с малым запасом: так держится 30% пар «товар - склад», и именно они чаще всего оставляют магазины без пополнения.
У магазинов с запасом до 3 дней продаж товар в дефиците 12% дней, с запасом больше 10 дней - 6%. Поднимать запасы магазинов сверх 3-5 дней почти бесполезно: полка пустеет прежде всего тогда, когда пуст склад.
При этом 80% потерь в дни, когда товар закончился за день, пришлись на время, когда товар на складе был: такие магазины можно было пополнить больше или раньше.
6. Прогноз закупа после дефицита
Закупщик заказывает по средним отгрузкам склада за три недели. Пока склад пуст, отгрузок нет, прогноз падает - и следующий заказ снова оказывается маленьким: дефицит продлевает сам себя. Такая ошибка исправляется один раз - изменением правила прогноза.
7. Проверка
В симуляцию заранее заложены проблемы на каждом этапе: перебои у поставщика, недозаказы и перезаказы, неравномерный закуп дефицитного товара, пропуски пополнения магазинов. Разбор о них не знает и находит их только по учётным данным.
8. Выводы и рекомендации
Дефицит обошёлся сети примерно в 308 млн ₽ за три месяца. Из них 48% - распределение между складом и магазинами, 29% - закуп, 23% - нехватка у поставщика. Значит, большую часть потерь сеть может сократить сама, без изменений у поставщика.
- Пополнять магазины, пока на складе есть товар. Распределение - самая дорогая причина: 48% потерь. 80% потерь в дни, когда товар закончился к вечеру, пришлись на время, когда он лежал на складе. Нужен ежедневный отчёт «на складе есть - в магазине пусто или почти пусто» и более частое пополнение быстро продающихся позиций. Запас поднимать не везде, а там, где его меньше 3 дней продаж: в этой группе дефицит 12% дней против 8% при 3-5 днях.
- Держать на складах запас хотя бы на 5-7 дней продаж региона. Склад с запасом до 5 дней пуст 25% дней, с запасом 5-7 дней - 5%. Сейчас так мало держится 30% пар «товар - склад»: это точечное изменение закупа по этим позициям, а не рост всех запасов.
- Изменить правило прогноза закупа. Прогноз по отгрузкам склада после дефицита занижает следующий заказ - так объясняется 47% потерь с итогом «ошибка закупа». Прогноз стоит строить по продажам магазинов региона в дни, когда товар был, - тогда пустой склад не будет уменьшать заказ.
- Готовить старт новинок отдельно. Новинки дали 37% всех потерь за несколько недель продаж. На первые две недели после старта - повышенный запас в магазинах и пополнение по фактическому ажиотажному спросу, а не по обычному плану.
- Делить дефицитный товар между складами по спросу. Когда поставщик даёт меньше заказа, перекос закупа стоил 15 млн ₽: один регион получал с запасом, другой оставался пустым. При недопоставке подтверждённый объём стоит распределять пропорционально продажам регионов.
- Сделать разбор регулярным. Расчёт работает на данных, которые уже есть в учётной системе. Еженедельная тепловая карта дефицита и разбор причин показывают, кому ставить задачу - закупке, складу или переговорам с поставщиком, - и позволяют проверить, дали ли изменения эффект.