Селлер женской одежды со своим швейным производством: четыре кабинета на двух маркетплейсах, пять производственных участков, ткани с плечом поставки до 38 дней. Система считает заказ на производство целиком: какие изделия, какими партиями, на каких неделях кроить и шить, какие ткани и когда заказывать, что и когда везти на склады площадок.
У заказчика собственное швейное производство и четыре витрины на двух маркетплейсах. Производство физически одно, а спрос приходит из четырёх мест. Каждую неделю кто-то садился и вручную решал, что подвинуть и куда вставить.
Один и тот же артикул продаётся с четырёх витрин. Чтобы понять, сколько его шить, нужно сложить заказы всех кабинетов, а потом развезти готовое обратно пропорционально их продажам. В таблицах это делалось руками и разъезжалось.
Плечо поставки ткани доходит до 38 дней, а цикл от кроя до склада площадки укладывается в три недели. Значит, решение о заказе ткани принимается за полтора месяца до того, как товар встанет на полку. Пропустил точку заказа - пропустил сезон.
Сколько часов в неделю реально даёт раскрой, швея, утюг, ОТК и комплектовка, не знал никто. План ставился по ощущению, узкое место всплывало в середине недели, когда двигать уже поздно.
Нормы расхода ткани и рубли по операциям лежали в личных калькуляциях. Один и тот же артикул в разных файлах стоил по-разному, и любой расчёт прибыли начинался со спора о цифрах.
Ночью Celery стягивает четыре кабинета двух маркетплейсов в PostgreSQL. Справочники производства и расчётное ядро превращают заказы в партии по неделям. Люди работают в React-портале, менеджеры видят ту же правду в Google-таблице, срочное приходит в Telegram. Внешние системы только читаются: система не пишет на площадки ничего.
Спрос по каждому артикулу собирается из фактических заказов всех четырёх кабинетов, а не из планов и не из желаний. Дальше он раскладывается по неделям горизонта с сезонным коэффициентом категории и ручной поправкой, если менеджер знает то, чего не знает история.
Темп считается по заказам: выкуп приходит позже и смещает картину назад на две недели. Для решения "запускать ли партию" важна скорость спроса сегодня.
У категории свой профиль по месяцам, у отдельного артикула можно задать свой. Коэффициент виден в таблице отдельной колонкой: человек видит, что именно подняло план.
Менеджер может задать темп и множитель руками, с комментарием. Поправка не растворяется в расчёте: в блоке "Почему" она стоит отдельной строкой с автором.
Границы суток - московские. Сервер живёт в UTC, а бизнес считает день по Москве. Пока это не было зафиксировано, вечерние заказы попадали в следующие сутки и темп продаж прыгал на ровном месте. Все периоды аналитики режутся по московскому дню.
Ядро расставляет партии по неделям так, чтобы прибыль горизонта была максимальной, а участки не перегружались. У каждой партии три недели: крой, пошив, доставка. Партия кратна минимальному запуску: настил меньше него не окупает раскрой.
Перебор вариантов запуска с отсечением заведомо худших веток, затем перебалансировка по участкам. Результат это версия расчёта: её можно сравнить с рабочей и только потом сделать рабочей.
Каждый прогон сохраняется отдельной версией с прибылью и числом партий. Прежний рабочий план не исчезает: незапущенные партии закрываются, запущенные живут дальше своим жизненным циклом.
Нет плеча у ткани, нет спецификации у артикула, ставка участка на проверке: движок говорит об этом списком наверху экрана. Молчаливая подстановка значения по умолчанию здесь недопустима: план выглядел бы честным, будучи выдуманным.
То, что не успеваем сшить до того, как полка встанет, показывается рублями рядом с прибылью горизонта. Это единственный способ сравнить "запустить сейчас" и "подождать" в одних единицах.
Пять участков, у каждого своя мощность и своя ставка. Загрузка считается на лету при каждом запросе: посчитанные часы и проценты нигде не хранятся, иначе у загрузки было бы две правды.
Пример: 3 человека по 8 часов, 5 смен, резерв 12%, сторонним 0 часов - это 3 × 8 × 5 × 0,88 = 105,6 часа. Пошив юбки 495 ₽ при ставке швеи 2 202 ₽ за час - это 0,225 часа, то есть 13,5 минуты на штуку; партия 240 штук займёт 54 часа.
Пустота честнее нуля. Если у участка не указано число людей, мощности нет: ячейка серая с причиной "у участка Утюг не указано число людей", а не ноль и не 100%. Если сторонние часы съели всю мощность, часы партий считаются, а процента нет, и в шапке участка цифра остаётся с расшифровкой. Причин может быть несколько, и в ячейке они собираются в одну фразу.
Ткань едет от 9 до 38 дней в зависимости от поставщика. Система берёт неделю кроя, вычитает плечо поставки и запас времени и получает дату, позже которой заказывать уже поздно. Строки с пройденной точкой заказа стоят красными наверху списка.
Две кнопки у строки календаря: первая создаёт заказ с плановой датой прихода, вторая подтверждает приход фактической датой и метрами. Расхождение плана и факта видно и попадает в следующий пересчёт.
К плечу поставки прибавляется запас на срыв срока и на брак. Это настройка, а не константа в коде: срок поставщика меняется звонком, а выкат кода занимает время.
Когда точка заказа проходит, менеджер получает сообщение. Ждать, пока кто-то откроет вкладку, здесь нельзя: пропущенный заказ ткани стоит месяца.
Рабочий план один. Партия проходит шесть состояний, и на каждом переходе система забирает факт: дату и количество. Расхождение с планом видно сразу и участвует в следующем расчёте.
Куда везти, считается, но правится руками. По умолчанию готовая партия делится между кабинетами пропорционально их заказам за период. Менеджер может переписать раскладку: у него бывают причины, которых нет в данных, например приёмка закрыта на конкретном складе.
Внутри работает нормальная теория ограничений. На экране её терминов нет: люди в цехе говорят другими словами, и обучать их словарю ради интерфейса незачем.
| В коде и в ТЗ | В интерфейсе |
|---|---|
| ключ товара, item_key | Артикул |
| спецификация, BOM | Из чего шьём |
| норма расхода | Ткани на 1 штуку, м |
| логистическое плечо | Ткань едет, дней |
| производственный цикл | От кроя до склада, недель |
| буфер | Запас времени |
| точка заказа | Заказать до |
| мощность участка | Часов в неделю |
| перебор с отсечением | кнопка "Рассчитать план" |
| маржа на единицу | Заработок с 1 штуки |
У каждой расчётной цифры есть подсказка "как посчитано": формула словами и числа подстановки. Цифра, которую нельзя объяснить за десять секунд, в этом интерфейсе считается недоделанной.
| Было | Стало |
|---|---|
| Спрос считали по кабинету, а производство одно. | Заказы четырёх кабинетов складываются по ключу товара, а готовая партия развозится обратно пропорционально их продажам. |
| "Что запускать" решал человек с таблицей. | Расчёт предлагает партии по неделям и называет прибыль горизонта и потерянные продажи рублями. Решение остаётся за человеком, но теперь оно с цифрой. |
| Мощность цеха была ощущением. | Пять участков с раздельной мощностью и загрузкой по неделям, красная ячейка видна до того, как неделя началась. |
| Ткань заказывали, когда вспоминали. | Календарь заказа обратным ходом от недели кроя с датой "заказать до" и сигналом в Telegram. |
| Себестоимость жила в личных файлах. | Спецификации загружаются шаблоном и становятся единственным источником норм и рублей операции для всех расчётов. |
| "Почему такая цифра" никто не мог объяснить. | У каждой расчётной цифры подсказка с формулой словами и числами подстановки, а у партии блок "Почему". |
Бизнес-аналитик и строитель систем. Начинаю с бизнес-процесса и контракта данных, потом автоматизирую. Здесь ручной разбор "что подвинуть и куда вставить" заменён расчётом, который умеет себя объяснить.