AAYMA
RU
Войти

Умный Закуп

Система планирования заказов поставщикам (IEK, Systeme Electric) для Электрокомплекта.

Доведённый продукт
Команда «Light» 26💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Light
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Доведённый продукт

Задача кейса: Автоматический расчёт заказов поставщикам для пополнения склада, с утверждением менеджером

Суть

Система планирования заказов поставщикам (IEK, Systeme Electric) для Электрокомплекта. Она прогнозирует дату дефицита и последний безопасный день заказа с учётом поставки за 45 дней и формирует заказ, который менеджер утверждает и отправляет в WhatsApp, Telegram, на почту, в Excel или CSV для 1С.

Как устроено

Python-движок (pandas, NumPy, openpyxl) читает выгрузки 1С: продажи, остатки, товар в пути, сезонность, MOQ. Он убирает разовые крупные заказы фильтром Hampel, восстанавливает спрос в периоды без товара, учитывает сезонность и тренд, вычитает товар в пути, считает дату окончания запаса и последний безопасный день заказа, количество со страховым запасом и кратностью MOQ, делает бэктест. Результат собирается в web/data.js. Статический сайт на vanilla JS с копией движка в engine.js пересчитывает сценарии прямо в браузере.

Ключевые решения

  • Hampel-фильтр выбросов
  • восстановление спроса при stockout
  • сезонность и тренд
  • страховой запас
  • MOQ-кратность
  • backtest
  • ABC-приоритизация
  • паритет-тесты Python↔JS

Метрики

На реальных данных: 1303 позиции к заказу, 682 — заказать сегодня, 708 ожидаемых дефицитов, 534 критических; критическая потребность ≥14,9 млн ₸, излишки ≈28,9 млн ₸; 32 автотеста пройдены

Особенности

Решение посчитано на реальных выгрузках заказчика и честно оговаривает, что цены есть только у 14,6% позиций. Автотесты сверяют, что Python-расчёт и браузерный движок дают одно и то же. Сайт работает офлайн через PWA. Заказ собирается в два шага (выбор галочками, затем отправка в мессенджер). Есть вкладка ручной проверки: там видно, как на заказ влияют разовый заказ ×30 и «3 месяца без товара».

Стек

Python · pandas · NumPy · openpyxl · SheetJS · JavaScript · SVG · Service Worker · Vercel · pytest · Node.js


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-bd80e77f-light.

README

README.md

Умный Закуп — система прогнозирования дефицита и планирования заказовДефицит забирает прибыль. Излишки забирают деньги из оборота. Система заранее показывает риски и помогает сохранить продажи через 45 дней. Заказчик — ТОО Электрокомплект, команда Light, HACKALEM AI 2026.Запустить сервис Умный Закуп


Поставка занимает около 45 дней. «Умный Закуп» заранее показывает, какой товар закончится, когда наступит последний безопасный день заказа и сколько нужно заказать.

📨 Готовый заказ поставщику — в WhatsApp, Telegram, на почту или в Excel. Какие товары покупать, менеджер выбирает сам: галочками или через поиск. → Как это работает

🌐 Открыть сервис · Что решает · Как запустить · Технологии · Как проверить · Соответствие ТЗ


🎯 Проблема

Компания продаёт тысячи разных товаров. Чтобы понять, что пора заказать, менеджер вручную собирает несколько Excel-файлов: продажи, остатки, товар в пути, сезонность, категории и минимальные партии поставщика.

Такой расчёт занимает много времени. Поэтому его сложно делать часто и одинаково внимательно по каждому товару.

Но поставка идёт примерно полтора месяца. Ошибка, сделанная сегодня, становится заметна только через несколько недель — когда исправить её уже поздно.

Менеджеру приходится принимать решение сразу между двумя рисками:

Если заказать мало или поздноЕсли заказать слишком много
товар закончится до следующей поставкиденьги останутся лежать на складе
клиент не сможет купить нужную позициювырастут расходы на хранение
продажа и маржа будут потеряныне хватит бюджета на действительно нужный товар
клиент может уйти к конкурентучасть ассортимента может устареть

Почему обычного среднего недостаточно

  • В одном месяце мог пройти единичный крупный заказ. Если считать его регулярным спросом, компания закупит лишнее.
  • Когда товара не было на складе, продажи равны нулю. Но это не означает, что спроса не было.
  • Зимой и летом один товар может продаваться по-разному.
  • Часть товара уже едет от поставщика и должна уменьшать новый заказ.
  • Поставщик отгружает товар только определёнными партиями.
  • Пока новый заказ едет 45 дней, спрос продолжает меняться.

Главная проблема не в Excel как таковом. Проблема в том, что бизнес слишком поздно узнаёт о будущем дефиците и слишком поздно замечает деньги, замороженные в лишнем запасе.

💸 Сколько денег можно потерять

Мы проверили сервис на реальных файлах заказчика. В актуальном расчёте (базовый сценарий, данные на 22.09.2026) система нашла:

Что обнаруженоМасштабЧто это означает
Позиций, которые рекомендуется заказать1 303такой объём невозможно качественно пересчитывать вручную каждый день
Заказать сегодня682последний безопасный день заказа уже наступил или прошёл
Ожидаемый дефицит708товар закончится раньше, чем придёт заказ, размещённый сегодня
Критических позиций534существующего запаса может не хватить до прихода следующей поставки
Позиций к заказу с нулевым остатком416часть спроса уже может превращаться в упущенные продажи
Стоимость критической потребности по известным ценамне менее 14,9 млн ₸деньги находятся в зоне срочного решения
Избыточный запас по известным ценамоколо 28,9 млн ₸капитал лежит в товарах, запас которых превышает расчётную потребность

[!IMPORTANT] Цена заполнена только примерно у 14,6% позиций к заказу. Поэтому 14,9 млн ₸ — не полная возможная потеря и не прогноз упущенной прибыли, а минимальная видимая сумма критической потребности. Полный денежный риск выше. Для точного расчёта потерянной прибыли нужны цены по всем товарам и их маржинальность.

Компания теряет деньги сразу в двух местах:

Нет товара → нет продажи → нет выручки и прибыли

Слишком много товара → деньги заморожены → их нельзя вложить в нужные позиции

💡 Что мы создали

«Умный Закуп» собирает разрозненные данные в одно решение и заранее предупреждает менеджера о рисках.

Вместо вопроса:

«Что у нас закончилось?»

сервис помогает ответить:

«Что закончится через несколько недель и что нужно заказать уже сегодня?»

Экран «Что делать сегодня»: показатели, заказ по поставщикам и графики

Первый экран отвечает на один вопрос: что менеджеру нужно сделать сегодня:

  • 4 показателя, которые не пересекаются: нет на складе · срок заказа наступил · заказать на этой неделе · стоимость заказа (с долей позиций, у которых известна цена);
  • карточка каждого поставщика — сколько позиций заказать сегодня и кнопки «Выбрать товары», WhatsApp, Telegram;
  • графики: статусы позиций, заказы по неделям, поставщики, группы товаров;
  • 10 главных действий: просроченные и «дефицит сейчас» → ранняя дата окончания запаса → категория A → больший дефицит до прихода поставки. Отсутствие цены приоритет не снижает.

Сверху выбираются поставщик, склад и категория (группа товаров) — весь дашборд пересчитывается.

Как проходит работа

flowchart LR
    A[Продажи, остатки и товар в пути] --> B[Прогноз будущего спроса]
    B --> C[Дата возможного дефицита]
    C --> D[Последний безопасный день заказа]
    D --> E[Готовый заказ с объяснением]

    style A fill:#eff6ff,stroke:#2563eb
    style B fill:#eff6ff,stroke:#2563eb
    style C fill:#fff7ed,stroke:#f97316
    style D fill:#fef2f2,stroke:#dc2626
    style E fill:#f0fdf4,stroke:#16a34a

Система:

  1. загружает историю продаж и остатки;
  2. убирает влияние единичных крупных заказов;
  3. восстанавливает спрос за периоды, когда товара не было;
  4. учитывает сезонность и устойчивое изменение спроса;
  5. проверяет товар, который уже находится в пути;
  6. прогнозирует, когда закончится текущий запас;
  7. рассчитывает последний безопасный день заказа;
  8. предлагает количество с учётом страхового запаса и минимальной партии;
  9. объясняет рекомендацию обычными словами;
  10. формирует заказ поставщику: менеджер выбирает товары и отправляет заказ в WhatsApp, Telegram, на почту, в Excel или CSV для 1С.

🚀 Как запустить

Вариант 1 — онлайн, без установки (рекомендуем для проверки): откройте https://umny-zakup.vercel.app. Работает круглосуточно на компьютере и телефоне; после первого открытия — и без интернета.

Вариант 2 — локально, без установки: скачайте репозиторий и откройте файл web/index.html в браузере. Данные уже рассчитаны, сервер не нужен.

Вариант 3 — пересчитать на выгрузках 1С и запустить тесты (нужны Python 3.10+ и, для сверки с браузером, Node.js 18+):

git clone https://github.com/BAITC-Hacks/hack-bd80e77f-light.git
cd hack-bd80e77f-light

python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt

python -m engine.build             # чтение Excel → расчёт → web/data.js и output/*.xlsx (~30 сек)
PYTHONPATH=. pytest -q             # автотесты требований ТЗ → 32 passed
python3 -m http.server 8000 --directory web   # открыть http://localhost:8000

Новые выгрузки 1С кладутся в папки IEK/ и Systeme electric/ с теми же именами файлов; после python -m engine.build сервис показывает свежие данные. Онлайн-версия обновляется командой bash scripts/deploy.sh.

🛠 Технологии и архитектура

ЧастьТехнологииЗачем
РасчётPython 3, pandas, NumPyчтение выгрузок 1С, очистка выбросов, stockout, сезонность, тренд, заказ, проверка на прошлом
Excelopenpyxl (Python), SheetJS (браузер)чтение файлов партнёра, выгрузка заказа в Excel
ИнтерфейсHTML, CSS, JavaScript без фреймворков, графики на SVGбыстрый статический сайт, работает с файла и офлайн
Пересчёт в браузереweb/engine.js — копия расчёта Pythonмгновенный пересчёт при смене сценария, сроков, выбора товаров
ОфлайнService Worker, Web App Manifestработа без интернета после первого открытия
ХостингVercel (статический сайт, CDN)круглосуточная работа без сервера
Качествоpytest + Node.js32 автотеста: требования ТЗ, календарь, сценарии, сверка Python ↔ браузер
МониторингGitHub Actions + scripts/check_site.jsпроверка сайта каждые 3 часа
flowchart LR
    A["Выгрузки 1С"] --> B["Расчёт<br/>Python"] --> C["Сайт"] --> D["Заказ: Excel · 1С · WhatsApp"]

✅ Как проверить решение

За 2 минуты в браузере — откройте https://umny-zakup.vercel.app:

ШагЧто сделатьЧто должно получиться
1Посмотреть главный экран4 показателя, карточки IEK и Systeme Electric, графики, 10 главных действий
2Открыть любую строку в «10 главных действий»Карточка товара: «Заказать N шт сегодня», дата окончания запаса, календарь остатка, вклад каждого фактора в штуках
3«Параметры» → сценарий «Защитный»Все цифры пересчитываются мгновенно (больше позиций к заказу)
4Сверху выбрать категорию, например «Автоматы и защита»Дашборд и заказ пересчитываются только по этой группе
5Карточка Systeme Electric → «Выбрать товары»Шаг 1: галочки, поиск, «Снять все», «+ Добавить»
6«Далее: проверить и отправить»Шаг 2: список выбранного и текст сообщения; кнопки WhatsApp, Telegram, Почта, Excel, «Для 1С (CSV)»
7Вкладка «Проверить расчёт» → «+ Разовый заказ ×30»Заказ почти не меняется — разовый заказ исключён (требование ТЗ 7.4)
8Там же → «3 месяца без товара»Спрос восстановлен, а не занижен (требование ТЗ 7.3)
9Вкладка «Методика и данные»Алгоритм, проверка прогноза на прошлом, охват данных, реестр допущений

Автоматически (вариант 3 из «Как запустить»):

PYTHONPATH=. pytest -q      # ожидается: 32 passed
node scripts/check_site.js  # проверка онлайн-версии: ✅ Сайт работает

Тесты по требованиям ТЗ: tests/test_requirements.py (пять требований Must have), tests/test_calendar.py (безопасный день, stockout, товар в пути, сценарии, граница месяца), tests/test_parity.py (Python и браузер считают одинаково, цены, бюджет, экспорт), tests/test_coverage.py (охват данных).

⏰ Главное отличие: сервис говорит не только «сколько», но и «когда»

Количество само по себе не спасает от дефицита. Если заказать на неделю позже, товар всё равно придёт с опозданием.

Поэтому для каждой позиции сервис строит календарь будущего остатка:

Сегодня
   ↓
товар ежедневно продаётся
   ↓
учитываются запланированные приходы
   ↓
определяется возможная дата окончания запаса
   ↓
из этой даты вычитается срок поставки и дни на согласование
   ↓
получается последний безопасный день заказа
Последний безопасный день = дата окончания запаса − срок поставки (45 дн) − согласование (3 дн)

Пример из данных — автомат ВА47-29 10А IEK: запаса хватит до 19 октября, а заказ, размещённый сегодня, придёт только 9 ноября.

gantt
    title Календарь остатка: автомат ВА47-29 10А IEK
    dateFormat YYYY-MM-DD
    axisFormat %d.%m
    section Склад
    Запас на складе              :done, s1, 2026-09-22, 2026-10-19
    Дефицит — товара нет         :crit, s2, 2026-10-19, 2026-11-09
    section Заказ сегодня
    Согласование 3 дн            :a1, 2026-09-22, 3d
    Поставка 45 дн               :a2, after a1, 45d

Последний безопасный день для этого товара был 1 сентября — сервис показывает статус «Просрочено» и дефицит ≈ 2 225 шт до прихода заказа.

Товар в пути учитывается только с датой прихода и только начиная с этой даты. Товар без даты (в файле Systeme Electric) не считается прибывшим вовремя: сервис показывает его отдельно и просит уточнить дату. Спрос месяца распределяется по дням, поэтому месячный сезонный объём сохраняется и на границах месяцев.

Менеджер видит понятный статус:

СтатусЗначение
🔴 Дефицит сейчастовара уже нет, хотя ожидаемый спрос существует
🔴 Просроченобезопасная дата заказа уже прошла
🟠 Сегоднярешение нужно принять сегодня
🟡 На этой неделедо безопасной даты осталось не больше семи дней
🟢 Позжезапас пока позволяет отложить заказ
⚪ Недостаточно данныхистории пока недостаточно для надёжного вывода (меньше 3 месяцев продаж) — даты не выдумываются

Статус действий отдельный от срочности и ABC-категории: он отвечает на вопрос «когда действовать», а срочность — «насколько велик риск».

Календарь будущих заказов

🔎 Почему менеджер может доверять рекомендации

Сервис не показывает необъяснимое число. Для каждой позиции он раскрывает расчёт.

Например:

При спросе 3 185 шт./мес. и остатке 1 406 шт. (+1 800 в пути) товар закончится примерно 19 октября. Поставка 45 дн. + 3 дн. на согласование: последний безопасный день был 1 сентября (21 дн. назад) — заказывать нужно немедленно. Рекомендуется 6 072 шт.: прогноз 7 962 + страховой 1 315 − остаток 1 406 − в пути 1 800 = 6 072, округлено до кратности 12.

— реальное объяснение сервиса для автомата ВА47-29 (1ф) 10А IEK

В карточке товара можно увидеть:

  • реальные продажи по месяцам;
  • очищенный спрос без случайных всплесков;
  • периоды, когда товара не было;
  • сезонное изменение спроса;
  • текущий остаток;
  • товар в пути и ожидаемую дату прихода;
  • страховой запас;
  • минимальную партию поставщика;
  • прогноз остатка с новым заказом и без него;
  • вклад каждого фактора в штуках: сезонность, тренд, восстановленный спрос, исключённые разовые продажи, остаток, товар в пути, страховой запас, округление до MOQ;
  • качество данных по позиции: есть ли цена, кратность, достаточно ли истории.

Карточка критического товара: даты, дефицит до прихода, календарь остатка, вклад факторов

📨 Отправка заказа в WhatsApp и Telegram

Сервис умеет отправлять заказ поставщику в WhatsApp, Telegram и на почту, а также выгружать его в Excel. Какие товары покупать, менеджер выбирает сам — отправка идёт в два понятных шага.

sequenceDiagram
    actor M as Менеджер
    participant S as Умный Закуп
    participant W as WhatsApp / Telegram
    M->>S: «Выбрать товары» у поставщика
    S-->>M: Шаг 1 — рекомендованные товары отмечены
    M->>S: снимает лишнее, добавляет через поиск, правит количество
    M->>S: «Далее: проверить и отправить»
    S-->>M: Шаг 2 — список выбранного и текст сообщения
    M->>S: нажимает «WhatsApp» (это согласование)
    S->>W: открывает чат с готовым текстом заказа
    M->>W: выбирает поставщика и отправляет
    Note over S,W: Сервис ничего не отправляет сам

Где начать: кнопка «Отправить заказ» в шапке сайта или кнопки «☑ Выбрать товары», WhatsApp, Telegram на карточке поставщика — все ведут в шаг 1.

Шаг 1 из 2 — выбрать товары

Шаг 1: выбор товаров галочками и поиском

  • Сервис заранее отмечает товары, которые нужно заказать сегодня (можно переключить на «+ эта неделя» или «Весь заказ»).
  • Галочки у каждой позиции, кнопки «Отметить все» и «Снять все» — чтобы выбрать с нуля.
  • Поиск по названию, коду 1С или артикулу; любой товар поставщика можно добавить кнопкой «+ Добавить», даже если сервис его не рекомендовал.
  • Количество правится прямо в списке. Внизу всегда видно: «Выбрано: N позиций · штук · сумма» и кнопка «Далее: проверить и отправить».

Шаг 2 из 2 — проверить и отправить

Шаг 2: список выбранного, предпросмотр сообщения и кнопки WhatsApp, Telegram, Почта, Excel

  • Список только выбранных товаров и предпросмотр сообщения — ровно тот текст, который уйдёт: поставщик, позиции и штуки, сумма и список «код — товар — количество» (до 50 позиций целиком, иначе первые 30 и ссылка на Excel).
  • Кнопки WhatsApp, Telegram, Почта открывают мессенджер или почту с этим текстом; получателя выбирает менеджер. Excel скачивается только отдельной кнопкой, на телефоне «Поделиться файлом» отправляет его сразу.
  • «← Изменить выбор» возвращает к шагу 1.

Сервис ничего не отправляет сам — как требует ТЗ: нажатие кнопки отправки и есть подтверждение ответственного сотрудника (заказ отмечается согласованным на этом устройстве). Коммерческие данные лучше отправлять с рабочего номера.

🧪 Проверить расчёт на своих числах

Менеджер может сам ввести продажи по месяцам, остаток, товар в пути, срок поставки, кратность и разовые заказы — и сразу увидеть заказ, дату окончания запаса, последний безопасный день, формулу и график. Расчёт тот же, что и для реальных товаров: шаги очистки, восстановления, сезонности и тренда перенесены в браузер и проверяются тестом на совпадение с Python.

  • Взять реальный товар по коду 1С — результат совпадает с основным расчётом (сервис это показывает: «✓ Совпадает»), дальше можно менять цифры.

  • Проверить требования ТЗ одной кнопкой: «+ разовый заказ ×30» (заказ не меняется), «3 месяца без товара» (спрос восстанавливается), «сделать сезонным», «товар в пути с датой / без даты» — с показом «было → стало».

  • Все параметры (срок поставки, согласование, пересмотр, прирост) можно задать точным числом, а не только ползунком.

  • Добавить новый товар в заказ. Введите название, код и поставщика — кнопка «+ Добавить в заказ поставщику» добавит товар в дашборд, таблицу заказа и отправку в WhatsApp / Telegram с пометкой «добавлен вручную». Удаляется одной кнопкой.

Данные ручной проверки и добавленные товары хранятся только в браузере пользователя.

Проверить расчёт на своих числах

🎚 Три сценария и бюджет

Одни и те же данные можно посчитать при разных допущениях. Переключатель сценария мгновенно пересчитывает количество, даты, риск, стоимость и график товара.

СценарийСпросСрок поставкиУровень сервиса A / B / C
Экономный−10%текущий90% / 80% / 70%
Базовыйпрогнозтекущий95% / 90% / 80%
Защитный+20%+15 дней98% / 95% / 90%

Это демонстрационные допущения, а не вероятности; они лежат в одном месте (engine/forecast.py → SCENARIOS). Разница между сценариями — не «экономия»: для этого нужны проверенные маржа и стоимость хранения.

Сравнение сценариев

Приоритизация заказа при ограниченном бюджете. Если задать доступный бюджет, сервис включает позиции по приоритету: «Дефицит сейчас» и «Просрочено» → ранняя дата окончания → категория A → больший дефицит. В бюджет попадают только позиции с известной ценой. Позиции без цены не считаются бесплатными: они показаны отдельно, а критичные из них остаются в предупреждениях. В таблице видны метки «в бюджете», «не поместилось», «нет цены».

🔬 Проверка прогноза на прошлом

Мы «вернулись» в 1 марта 2026 года: алгоритм видел только данные до этой даты (продажи, остатки, накладные, сезонность по полным годам) и спрогнозировал спрос на март–май. Затем прогноз сравнили с фактическими продажами.

«Умный Закуп»Среднее за 12 мес (как в Excel)
Ошибка прогноза (WAPE)23,1%29,1%
Смещение (bias)+0,6%+16,2% (систематически завышает)
Категория A — WAPE19,4%25,6%

Простое среднее завышает спрос на 16% — это прямой путь к замороженным деньгам. Для редких товаров (категория C) ошибка выше: при штучных продажах это ожидаемо. Проверка измеряет точность прогноза спроса и не доказывает предотвращённые дефициты — для этого нужна точная история ежедневных остатков и поступлений.

Проверка прогноза на прошлом

🧹 Как система защищает деньги от лишней закупки

Один большой заказ клиента не всегда означает, что такой же объём будет продаваться каждый месяц.

Мы сравнили два расчёта:

  • обычный расчёт, который принимает все продажи за регулярный спрос;
  • расчёт «Умного Закупа», который отделяет единичные крупные продажи от постоянного спроса.

Результат моделирования на предоставленных данных:

ЭффектРезультат
Потенциально лишнее количество без очистки данных49 497 единиц
Стоимость потенциально лишнего пополнения по известным ценамоколо 8,35 млн ₸

Это означает: если считать любой крупный заказ постоянным спросом, компания может направить миллионы тенге в товар, который затем будет долго лежать на складе.

📊 Что получает менеджер

БылоСтало
Несколько Excel-файловОдин экран с общей картиной
Ручной расчёт каждой позицииАвтоматический расчёт всего ассортимента
Реакция после окончания товараПредупреждение заранее
Только количество заказаКоличество и крайняя дата решения
Непонятная итоговая цифраОбъяснение по каждой позиции
Риск забыть товар в путиПриходы учитываются по датам
Ручная подготовка результатаГотовая выгрузка в Excel

Менеджер может изменить предложенное количество перед выгрузкой. Система помогает принять решение, но не принимает его вместо человека.

💰 Какой экономический результат мы нашли

На предоставленных данных система уже выявила два отдельных финансовых резерва:

1. Защита от лишней закупки

Фильтрация единичных крупных продаж уменьшила модельную закупку на 49 497 единиц. По товарам, где цена известна, это примерно 8,35 млн ₸ модельно меньшей закупки (по себестоимости, без учёта маржи).

2. Деньги в избыточном запасе

Сервис нашёл около 28,9 млн ₸, находящихся в запасах сверх расчётной потребности на шесть месяцев — и это только по позициям с известной ценой.

Эти две суммы нельзя автоматически складывать: они отражают разные виды риска и могут частично пересекаться.

Честный вывод: система уже нашла, где компания может не потратить лишние 8,35 млн ₸ и где около 28,9 млн ₸ капитала требует проверки и возможного высвобождения. Но это пока найденный финансовый резерв, а не деньги на банковском счёте.

Чтобы резерв превратился в реальную прибыль, компания должна:

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

После пилота экономический эффект считается просто:

Реально сохранённые деньги =
предотвращённые лишние закупки
+ высвобождённый запас
+ сохранённая маржа от предотвращённого дефицита
− стоимость внедрения и хранения

Так мы сможем честно сказать не только «система рассчитала заказ», а:

«Компания сохранила X тенге и получила Y тенге дополнительной маржи благодаря тому, что нужный товар был в наличии вовремя».

🧾 Какие данные используются

ДанныеЗачем они нужны
История продажпонять реальный темп спроса
Остаткиопределить, на сколько времени хватит товара
Товар в путине заказать повторно то, что уже едет
Даты ожидаемого приходапонять, успеет ли поставка до дефицита
Сезонностьучитывать месяцы высокого и низкого спроса
Категория A/B/Cопределить важность позиции и размер защиты
MOQокруглить заказ до партии, которую примет поставщик
Ценапосчитать стоимость решения там, где цена известна

Товары связываются между файлами по коду 1С. Персональные данные клиентов не используются.

✅ Что выполнено по заданию

Сверка с каждым пунктом технического задания ТОО «Электрокомплект».

Пункт ТЗТребованиеКак выполнено
3Расчёт по складу или категории → список с обоснованием → проверка и корректировка → утверждениеСверху выбираются поставщик, склад (в выгрузке один — Алматы) и категория (группа товаров) — весь дашборд пересчитывается. Обоснование у каждой позиции, правка количества, «Согласовать заказ»
4История продаж, сезонность, рост, остатки, товар в пути, категории, прогноз прироста, упущенный спросВсё входит в расчёт — см. Методология расчёта
4Выявлять и исключать разовые крупные заказы, включая продажи одному клиентуПоиск по накладным — см. Алгоритм исключения выбросов. Поля клиента в выгрузке партнёра нет — проверка по клиенту заменена проверкой по накладной (честно указано в сервисе)
5Выход: артикул, поставщик, количество, обоснование, срочность — таблица/дашборд с экспортомДашборд, таблица «Заказ поставщикам», экспорт в Excel и CSV для 1С, отправка в WhatsApp / Telegram / почту
7.1Все источники влияют на результатТест меняет каждый источник (товар в пути, остаток, прирост, сезонность, MOQ, категория ABC) и проверяет изменение заказа
7.2Сезонность и устойчивый ростПрогноз повторяет сезонный профиль; тренд год к году (−30…+50 %)
7.3Упущенный спрос при stockoutСпрос в месяцы без товара восстанавливается; потребность выше, чем по «сырым» продажам
7.4Разовый крупный заказ не раздувает регулярное количествоТест: заказ ×30 меняет рекомендацию меньше чем на 10 %
7.5Список по поставщикам, объяснение каждой строкиРазбивка IEK / Systeme Electric, текстовое обоснование и таблица вклада факторов в штуках
8Опционально: приоритет по риску дефицитаСтатусы «Дефицит сейчас → Просрочено → Сегодня → Неделя», последний безопасный день заказа, календарь
8Опционально: минимальная партия и условия поставщикаКратность (MOQ) из файлов, срок поставки по каждому поставщику
8Опционально: тренды спроса по категориямВкладка «Аналитика»: динамика спроса по группам товаров, сезонность
8Опционально: выгрузка/рассылка заказа поставщикуWhatsApp, Telegram, почта, Excel, CSV для 1С — только после действия менеджера
9Нельзя отправлять заказ без подтверждения сотрудникаСервис ничего не отправляет сам: нажатие «Согласовать и отправить» — действие менеджера
9Нельзя использовать неанонимизированные данные клиентовДанных о клиентах в расчёте нет; номера накладных в опубликованные данные не выгружаются
9Приватность, объяснимость, устойчивость к выбросам, совместимость с учётной системойПоиск закрыт (noindex); объяснение каждой строки; медиана/MAD и фильтр Хампеля; коды 1С сохраняются как текст, CSV для загрузки в 1С
10Репозиторий, README: методология, алгоритм исключения выбросов, инструкция запускаЭтот README: методология, алгоритм выбросов, запуск

Всё это проверяют 32 автоматических теста (PYTHONPATH=. pytest -q): пять требований ТЗ, календарь остатка (безопасный день, дефицит сейчас, нулевой спрос, приход до и после дефицита, товар без даты, MOQ, граница месяца), порядок сценариев, отсутствие утечки будущего в проверке прогноза, а также сверка: расчёт в браузере совпадает с эталоном на Python на 54 комбинациях. Отдельно проверяется, что отсутствующая цена не превращается в ноль, покрытие ценами считается верно, бюджетный режим не теряет критичные позиции без цены, а в Excel коды 1С сохраняются как текст и нет NaN/undefined.

🧭 Охват данных и допущения

На вкладке «Методика и данные» видно, какая часть каталога дошла до расчёта и что взято из файлов заказчика, а что задано командой:

ШагТоваров
Исходный каталог (коды 1С в файлах продаж и остатков)3 561
Есть хотя бы одна продажа или остаток3 533
Опубликовано в сервисе2 944
В прогнозе (3+ месяцев истории, ненулевой спрос)2 335
Рекомендовано к заказу (базовый сценарий)1 303

Исключено 617: у 28 нет ни продаж, ни остатков, ни товара в пути; 589 не продавались последние 6 месяцев и не лежат на складе — заказывать нечего.

Реестр допущений перечисляет 21 параметр с источником: «файл заказчика», «вычислено из истории» или «допущение команды Light». Например, срок поставки 45 дней — допущение команды (оценено по датам в файле «Путь ИЭК»), сезонность — файл заказчика плюс профиль товара.

В Excel-выгрузке есть лист «Параметры»: дата данных, сценарий, сроки поставки, факторы расчёта, покрытие ценами и отметка «поставщику ничего не отправлено».

Как перейти от демо к пилоту (вход по ролям, данные через API, журнал согласований, интеграция с 1С) — в docs/PILOT_ARCHITECTURE.md.

🔐 Безопасность

  • Система ничего не отправляет поставщику автоматически.
  • Менеджер проверяет и может изменить количество.
  • «Отметить согласованным» сохраняет отметку только на этом устройстве — это не журнал согласований; Excel подготовлен для проверки и последующего импорта в учётную систему.
  • Номера накладных в опубликованных данных не хранятся. В выгрузке партнёра нет поля клиента, поэтому проверка «крупные продажи одному клиенту» невозможна — разовые заказы ищутся по накладной.
  • Финальный заказ появляется только после решения человека.
  • Персональные данные клиентов не используются.
  • Если данных недостаточно, сервис сообщает об этом, а не придумывает результат.
  • Отсутствующая цена показывается как «Нет данных», а не 0 ₸; стоимость заказа всегда подписана как неполная, если цены известны не везде.
  • В выгрузке каждая строка помечена «Черновик, не отправлен» или «Утверждён, не отправлен поставщику».

🚀 Как развивать решение дальше

Следующие данные позволят точнее считать деньги и риски:

  1. цены и маржинальность по всему ассортименту;
  2. клиентские резервы и подтверждённые заказы;
  3. плановые и фактические даты поставок;
  4. стоимость хранения;
  5. история ручных решений менеджера;
  6. товары-заменители;
  7. планы отдела продаж по крупным проектам.

После этого сервис сможет показывать:

  • точную потерянную прибыль из-за дефицита;
  • надёжность каждого поставщика (интерфейс уже готов и ждёт плановые и фактические даты приходов);
  • бюджетный режим по всему ассортименту, а не только по позициям с ценой;
  • варианты замены отсутствующего товара;
  • фактическую экономию после внедрения;
  • уведомления в Telegram о наступлении безопасной даты заказа.

🧮 Методология расчёта

flowchart LR
    A["Очистка<br/>выбросов"] --> B["Спрос без<br/>дефицита"] --> C["Сезон<br/>и тренд"] --> D["Заказ<br/>+ страх. запас"] --> E["Дата<br/>заказа"]
    style D fill:#f0fdf4,stroke:#16a34a
    style E fill:#fef2f2,stroke:#dc2626

Расчёт идёт по каждому артикулу. Все параметры собраны в начале engine/forecast.py.

  1. Очистка от разовых заказов и всплесков — см. алгоритм ниже.
  2. Восстановление упущенного спроса (stockout). Остаток известен на начало каждого месяца, конец месяца = начало следующего. Доля месяца в наличии: оба нуля → ≈ 10 % (или 40 %, если продажи всё же были), один ноль → 60 %, иначе 100 %. Спрос в таком месяце = max(факт, min(ожидаемый, факт + (1 − доля) × ожидаемый)), где ожидаемый считается только по месяцам с товаром.
  3. Сезонность. Коэффициенты поставщика из файла «Сезонность» + собственный профиль товара по полным годам (вес до 60 %).
  4. Уровень и тренд. Уровень — средний спрос за 6 последних месяцев без сезонности. Тренд — последние 6 месяцев к тем же месяцам год назад, ограничен −30…+50 %. Прогноз прироста рынка — ручная поправка менеджера.
  5. Страховой запас = z × σ × √(срок поставки + период пересмотра); z по категории ABC (частота заказов за 12 мес.): A — 95 %, B — 90 %, C — 80 % уровня сервиса.
  6. Заказ = прогноз на (срок поставки + пересмотр) + страховой запас − остаток − товар в пути с датой прихода, округление вверх до кратности (MOQ).
  7. Календарь остатка и срочность. Остаток по дням на 180 дней (месячный прогноз распределён по дням, приходы товара в пути — по датам). Последний безопасный день = дата окончания запаса − срок поставки − согласование. Статусы: Дефицит сейчас · Просрочено · Сегодня · На этой неделе · Позже · Недостаточно данных (меньше 3 мес. истории).

🧹 Алгоритм исключения выбросов

Цель — чтобы разовая крупная продажа не превратилась в регулярную закупку. Два слоя:

flowchart LR
    N["Крупная накладная"] --> Q{"Повтор 4+ мес.?"} -- да --> K["Оставить"]
    Q -- нет --> X["Исключить"]

1. Разовые заказы по накладным. Для каждого артикула по всем расходным накладным считаются устойчивые к выбросам статистики — медиана и MAD (медианное абсолютное отклонение) размера отгрузки. Накладная признаётся разовым крупным заказом, если одновременно:

  • объём > медиана + 6 × MAD и > Q3 + 3 × IQR;
  • объём ≥ 5 медиан;
  • накладная даёт ≥ 25 % продаж артикула за месяц;
  • по артикулу не меньше 8 накладных (иначе «обычный» заказ не определить).

Такие накладные вычитаются из регулярного спроса и показываются в карточке товара. Защита от ложных срабатываний: если крупные заказы повторяются (в 4+ месяцах или в > 20 % месяцев продаж), это постоянный оптовый покупатель — такой спрос регулярный и не исключается.

2. Фильтр Хампеля по месячному ряду (для периода без накладных и всплесков без документа). Окно ±3 месяца; значение выше медиана + 3 × 1,4826 × MAD и выше 2 медиан срезается до границы, а не удаляется. Месяцы без товара в «норму» окна не входят — иначе обычные продажи после дефицита ошибочно считались бы всплеском.

Клиент. В ТЗ — «включая крупные продажи одному клиенту». В выгрузке партнёра поля клиента нет (дата, документ, товар, склад, количество), поэтому разовый заказ определяется по накладной. При появлении обезличенного ID клиента правило расширяется на серию накладных одного клиента.

Проверка: тест добавляет заказ в 30 раз больше месячного спроса — рекомендация меняется меньше чем на 10 %, а без фильтра выросла бы более чем в 2 раза. Тест на постоянного оптовика подтверждает, что регулярные крупные покупки не удаляются.

Техническая информация: формулы и структура проекта

Как устроен расчёт

Для каждого товара система:

  1. находит и исключает нетипичные единичные продажи;
  2. восстанавливает ожидаемый спрос в периоды отсутствия товара;
  3. учитывает сезонность и устойчивый тренд;
  4. прогнозирует спрос на срок поставки и следующий цикл заказа;
  5. добавляет страховой запас;
  6. вычитает текущий остаток и подтверждённый товар в пути;
  7. округляет результат до минимальной партии поставщика.
Рекомендуемый заказ = прогноз спроса на (срок поставки + период пересмотра)
                    + страховой запас (z по ABC и сценарию × σ × √горизонт)
                    − текущий остаток
                    − подтверждённый товар в пути (с датой прихода)
                    → округление вверх до кратности поставщика

Последний безопасный день = дата окончания запаса − срок поставки − согласование

Одна и та же функция расчёта есть в Python (engine/forecast.py → plan) и в браузере (web/engine.js → plan); тест tests/test_parity.py проверяет, что они дают одинаковый результат. Проверка прогноза на прошлом — engine/backtest.py.

Структура проекта

hack-bd80e77f-light/
├── engine/
│   ├── loaders.py          # чтение и нормализация выгрузок 1С
│   ├── forecast.py         # алгоритм: выбросы, stockout, сезонность, тренд, заказ, календарь
│   ├── backtest.py         # проверка прогноза на прошлом
│   ├── coverage.py         # охват каталога и причины исключения
│   └── build.py            # сборка web/data.js и Excel
├── web/                    # сайт: index.html, app.js, engine.js, styles.css, data.js, sw.js
├── tests/                  # 32 автотеста (pytest + сверка с браузером через Node.js)
├── scripts/                # deploy.sh — публикация, check_site.js — проверка сайта
├── docs/                   # скриншоты, PILOT_ARCHITECTURE.md — план пилота
├── IEK/, Systeme electric/ # данные партнёра
├── output/                 # Excel с рекомендациями
├── assets/readme/          # оформление README
├── requirements.txt, vercel.json
└── README.md

Точный заказ — это товар на полке, деньги в обороте и продажа, которую компания не потеряла.

🌐 Открыть сервис: umny-zakup.vercel.app

Создано командой Light для ТОО «Электрокомплект» на HACKALEM AI 2026

Техническое задание заказчика

Звёзды
⭐ 0
Форки
0
Язык
JavaScript
Последний push
в прошлом месяце
Коммиты
33
Авторы
1
Файлы
71
Ветки
1

Авторы коммитов

ndyussemba 33

История коммитов

  • 2026-09-23 17:48README: minimal outlier diagramndyussemba
  • 2026-09-23 17:48README: compact methodology and outlier diagramsndyussemba
  • 2026-09-23 17:46README: compact architecture diagramndyussemba
  • 2026-09-23 17:44README: visible quick start, technologies and architecture, verification steps for jury, 5 new diagramsndyussemba
  • 2026-09-23 17:39Add a manually entered product to the supplier order from the check tabndyussemba
  • 2026-09-23 17:36TZ compliance: category/warehouse selection for whole dashboard and order, CSV export for 1C, README methodology + outlier algorithm + full TZ checklistndyussemba
  • 2026-09-23 17:31Tighten README value banner layoutndyussemba
  • 2026-09-23 17:27Recompose README banners without text distortionndyussemba
Все коммиты (33)
  • 2026-09-23 17:27Two-step order wizard: 1) choose items, 2) preview message and send via WhatsApp/Telegram/emailndyussemba
  • 2026-09-23 17:23Send buttons no longer download Excel; full order list in message (up to 50 lines); Excel only on demandndyussemba
  • 2026-09-23 17:20Fix: WhatsApp/Telegram open via real links (not blocked by browser), Excel downloads after; fallback linkndyussemba
  • 2026-09-23 17:18Refine README banner proportions and external CTAndyussemba
  • 2026-09-23 17:13Visible WhatsApp/Telegram send buttons (header, supplier cards, order sheet), 'Select items' button, README sectionndyussemba
  • 2026-09-23 17:08Manual item selection in supplier order (checkboxes, search, add any item); compact KPI and supplier cardsndyussemba
  • 2026-09-23 17:02Supplier order flow: review, approve, send via WhatsApp/Telegram/email; non-overlapping KPIs; one-line answer in SKU cardndyussemba
  • 2026-09-23 16:51Fix: parameters panel scrolls inside, page scroll locked while openndyussemba
  • 2026-09-23 16:46Dashboard redesign: slide-out parameters, 4 KPI cards, status donut, weekly orders, suppliers and groups chartsndyussemba
  • 2026-09-23 16:38Remove gap between README bannersndyussemba
  • 2026-09-23 16:36Refresh compact README hero and service CTAndyussemba
  • 2026-09-23 16:34Data coverage funnel, assumptions registry, pilot architecture doc, Parameters sheet in Excel exportndyussemba
  • 2026-09-23 16:14Manual calculation check tab, exact inputs, Hampel fix after stockouts, single 'order today' definition, honest wording, no invoice numbers in public datandyussemba
  • 2026-09-23 15:40Move site monitoring out of org repo (Actions disabled for the organization)ndyussemba
  • 2026-09-23 15:3924/7: offline mode (service worker), site monitoring every 3h, CI tests, deploy scriptndyussemba
  • 2026-09-23 15:18Усилить заголовок README через ценность прибылиndyussemba
  • 2026-09-23 15:09Deploy to Vercel: live link in README, noindex, hosting configndyussemba
  • 2026-09-23 14:59Early stockout warning: Today screen, safe order date, scenarios, budget mode, data quality, backtest, parity testsndyussemba
  • 2026-09-23 14:55Переписать README для бизнес-аудиторииndyussemba
  • 2026-09-23 14:37README: stock calendar section, real-data results, screenshotsndyussemba
  • 2026-09-23 14:36Stock calendar: order-by dates, daily stock projection, calendar tab, testndyussemba
  • 2026-09-23 14:19Web app: purchase manager dashboard, SKU card, analytics, approval and Excel export; README presentationndyussemba
  • 2026-09-23 14:09Engine: data loaders, forecast algorithm, requirement tests, web data buildndyussemba
  • 2026-09-23 13:59Add partner data: IEK and Systeme Electric (sales, stock, in-transit, seasonality, MOQ)ndyussemba
  • 2026-09-23 13:49Add README: methodology, outlier algorithm, run instructionsndyussemba
Структура репозитория (71 файлов)
.gitignore
.vercelignore
HackAlem AI_ Автоматизация формирования заказов поставщикам.docx
IEK/MOQ  ИЭК.xlsx
IEK/Динамика продаж_2025-2026.xlsx
IEK/Ежемесячные остатки продукции за последние 2 года  ИЭК.xlsx
IEK/Ежемесячные продажи в количественном выражении за последние 2 года.xlsx
IEK/Путь ИЭК 22.09.2026.xlsx
IEK/Сезонность ИЭК.xlsx
README.md
Systeme electric/MOQ SystemElectric.xlsx
Systeme electric/Динамика продаж_Syseme Electric_2025-2026.xlsx
Systeme electric/Ежемесячные остатки SystemElectric 2024-2026.xlsx
Systeme electric/Ежемесячные продажи в кол-м выражении SystemElectric 2024-2026.xlsx
Systeme electric/Сезонность SystemElectric 2024-2026.xlsx
Systeme electric/Товар в пути_SystemElectric на 22.09.2026.xlsx
assets/readme/hero.png
assets/readme/open-service-v2.svg
assets/readme/open-service-v3.svg
assets/readme/open-service-v4.svg
assets/readme/open-service.svg
assets/readme/title-banner-compact-v2.png
assets/readme/title-banner-compact-v3.png
assets/readme/title-banner-compact.png
assets/readme/title-banner-v4.png
assets/readme/title-banner.png
assets/readme/value-banner-v2.png
assets/readme/value-banner-v3.png
assets/readme/value-banner-v4.png
assets/readme/value-banner.png
docs/PILOT_ARCHITECTURE.md
docs/analytics.png
docs/backtest.png
docs/calendar.png
docs/critical.png
docs/dashboard.png
docs/drawer.png
docs/method.png
docs/sandbox.png
docs/scenarios.png
docs/send-order-2.png
docs/send-order.png
docs/today.png
engine/__init__.py
engine/backtest.py
engine/build.py
engine/coverage.py
engine/forecast.py
engine/loaders.py
output/Рекомендации_заказов.xlsx
requirements.txt
scripts/check_site.js
scripts/deploy.sh
tests/js/run_engine.js
tests/js/unit.js
tests/test_calendar.py
tests/test_coverage.py
tests/test_parity.py
tests/test_requirements.py
vercel.json
web/app.js
web/assumptions.js
web/coverage.js
web/data.js
web/engine.js
web/icon.svg
web/index.html
web/manifest.webmanifest
web/robots.txt
web/styles.css
web/sw.js

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.