AAYMA
RU
Войти

StockPilot AI

Локальная панель планирования закупок: по шести Excel-выгрузкам (продажи, остатки, товар в пути, MOQ, сезонность) рассчитывает рекомендуемые заказы…

Рабочий MVP
Команда «N Turbo» 11💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: N Turbo
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Рабочий MVP

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

Суть

Локальная панель планирования закупок: по шести Excel-выгрузкам (продажи, остатки, товар в пути, MOQ, сезонность) рассчитывает рекомендуемые заказы поставщику со статусами срочности и объяснением расчёта. LLM не используется.

Как устроено

Шесть xlsx импортируются через ExcelJS и связываются по Коду 1С с проверкой контрольных заголовков. Продажи очищаются, в расходных накладных за 24 месяца ищутся выбросы по IQR (порог Q3 + 1.5 × IQR). Регулярный спрос — среднее за 12 месяцев с коррекцией на долю аномалий. Прогноз = спрос × рост (0.5–1.5) × сезонность (0.7–1.3) × (1 + stockout%). Заказ = ceil(max(0, прогноз − свободный остаток − в пути)/кратность) × кратность. При неполных данных заказ блокируется. На выходе статусы срочности, модальное окно с объяснением и экспорт CSV.

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

  • IQR anomaly detection
  • moving average demand
  • YoY growth factor
  • seasonality index
  • MOQ rounding
  • CSV export with formula escaping

Особенности

Аккуратная работа с данными: выбросы по IQR ищутся на уровне накладных, коэффициенты роста и сезонности ограничены, ошибочные колонки AP/AQ исходного отчёта явно исключены. Если данных не хватает, заказ блокируется, а не показывается нулём. Весь проект сдан одним коммитом.

Стек

Next.js · TypeScript · React · ExcelJS


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

README

README.md

StockPilot AI

Локальный MVP для планирования закупок Systeme Electric. Next.js + TypeScript, React и ExcelJS. Показывает KPI, рекомендации, срочность, аномалии IQR, объяснение расчёта и экспорт CSV. Статистический расчёт выполняется без внешней LLM и без отправки данных третьим лицам.

Запуск

Из корня репозитория, в обычной среде с Node.js 22+ и npm:

npm ci
npm run build
npm run start

Открыть http://127.0.0.1:3000. Для разработки: npm run dev.

На текущем компьютере Node.js доступен в локальной среде Codex, а npm установлен локально в игнорируемой .tools. Скрипт подставляет эти пути, если Node/npm отсутствуют в PATH:

powershell -ExecutionPolicy Bypass -File .\start.ps1 -Production

Без -Production запускается dev-сервер. Скрипт ничего не устанавливает. Если порт 3000 уже занят запущенным StockPilot, достаточно открыть адрес в браузере.

Локальные данные

Положите шесть исходных .xlsx в data/raw/. Excel не включаются в Git. Нужен ровно один файл каждого типа; суффиксы (1), (2) допустимы, одновременные дубликаты отклоняются.

Префикс файлаИсточник
MOQ Лист_1: C — Код 1С, D — артикул, E — кратность
Ежемесячные продажиЛист_1: B — Код 1С, C — артикул, E:AK — месячные продажи
Товар в путиTDSheet: C — Код 1С, E — категория, AZ — свободный остаток, BC — в пути
Ежемесячные остаткиЛист_1: C — Код 1С, E:AK — месячная история остатков
Динамика продажЛист_1: A — дата, D — Код 1С, H — количество; C — тип документа
СезонностьПервый лист: A4:A6 — годы, B:M — месячные агрегаты

Импорт настроен на проверенную структуру: месячные колонки январь 2024 — сентябрь 2026. Контрольные заголовки проверяются, при изменении формата требуется обновить mapping. Файлы открываются только для чтения на сервере через /api/data. Импорт кэшируется в памяти по именам, размерам и времени изменения файлов; кнопка «Обновить данные» перечитывает изменённые источники. Результаты не сохраняются на диск и не помещаются в public.

Основной ключ — Код 1С, строка с сохранением ведущих нулей и _. Названия не участвуют в объединении. Дубликаты кодов в товарных таблицах и конфликты артикулов отклоняются. Ассортимент — объединение кодов источников. Товары без нужных данных видны со статусом «Проверить данные», заказ для них не вычисляется.

Расчёт

Параметры доступны в «Настроить расчёт». Горизонт по умолчанию — 1 будущий календарный месяц, это пользовательский сценарий, не lead time. Дата данных определяется максимальной датой операций; для текущего набора — 22.09.2026, начало прогноза — октябрь 2026. Неполный сентябрь исключён из базы, прогноз не является рекомендацией покрытия оставшихся дней сентября.

  1. Очистка. Отрицательные месячные продажи ограничиваются нулём; исходные значения остаются в деталях. Отрицательные операции исключаются только из IQR, повторно из месячных продаж не вычитаются. Пропуски количества операций не становятся нулём. Пустые месяцы по явно включённой настройке принимаются за ноль; при отключении исключаются из среднего.
  2. IQR. Для каждого кода берутся положительные строки расходных накладных за 24 завершённых месяца, минимум 8 наблюдений. Квартили — линейная интерполяция, порог Q3 + 1.5 × (Q3 − Q1). Всё выше порога отмечается как аномалия. Строки заказов покупателей не включаются. Номера документов не используются как ID клиентов.
  3. Регулярный спрос. Для каждого месяца: max(0, monthly_sales) × (1 − anomaly_excess / positive_transaction_quantity). Доля ограничена диапазоном 0–1. При отключённой коррекции множитель равен 1. Затем берётся среднее за последние 12 завершённых месяцев (сентябрь 2025 — август 2026). История операций и месячный отчёт расходятся, поэтому перенос доли аномалий — явное приближение, а не точная сверка продаж.
  4. Рост. Отношение сумм последних трёх полных месяцев к тем же месяцам прошлого года. Используется очищенная история с той же IQR-коррекцией. Множитель ограничен 0,5–1,5. При отсутствующей или нулевой базе применяется 1 с объяснением.
  5. Сезонность. Для каждого полного прошлого года из файла сезонности месячный агрегат делится на среднемесячный. Индексы полных 2024–2025 годов усредняются; множитель ограничен 0,7–1,3. Неполный 2026 год исключён. Единица агрегатов не подтверждена; это опциональная общая сезонная форма, не персональная сезонность SKU.
  6. Stockout. По умолчанию 0%, выключено. Слайдер 0–50% задаёт ручное сценарное увеличение, не восстановленные потери. Месячные остатки не преобразуются в выдуманные интервалы отсутствия.
  7. Прогноз. Для каждого будущего месяца: regular_demand × growth × seasonality × (1 + stockout_percent / 100). Сумма по горизонту 1–6 месяцев.
  8. Заказ. ceil(max(0, forecast − free_stock − in_transit) / order_multiple) × order_multiple. Кратность берётся только из MOQ-файла. Резерв повторно не вычитается из уже свободного остатка. Неизвестные/отрицательные остатки, отсутствующая положительная целая кратность или отсутствие базы блокируют заказ.

AP/AQ и коэффициенты товарной сводки не используются: AP ошибочно включает 13 месяцев, AQ делит результат на 12. Расхождения сентябрьских продаж и кратности отмечены в карточках. Кратность не приравнивается к минимальному заказу. Метка «24.09» не используется как подтверждённая ETA: товар в пути вычитается по условию MVP, дата фактической доступности неизвестна.

Срочность и интерфейс

  • «Критично»: нужен заказ, свободный остаток равен нулю.
  • «Скоро закончится»: нужен заказ, запас в месяцах меньше половины выбранного горизонта.
  • «Плановый заказ»: остальной положительный заказ.
  • «Запас достаточен»: заказ равен нулю.
  • «Проверить данные»: расчёт заказа заблокирован пропусками.

Покрытие считается по свободному остатку и среднему прогнозу, без предположения о lead time. Порог срочности — правило MVP, а не согласованный SLA.

Поиск работает по артикулу, Коду 1С и названию. Быстрые кнопки: ATN000343, BLNZA000011, U734M. Есть фильтр срочности, сортировка, страницы по 20 строк и модальное объяснение с исходной историей. CSV экспортирует все строки текущего фильтра, включая параметры сценария и замечания; UTF-8 BOM, разделитель ;, потенциальные формулы экранируются. Пропущенные значения остаются пустыми, заблокированный заказ не выдаётся за 0.

Проверки

npm test
npm run check
npm run build
git status --short
git ls-files -- data/raw/
git check-ignore -- data/raw/

Тесты проверяют очистку, IQR, пропуски, пределы коэффициентов, горизонт, вычет запаса, округление, stockout-сценарий и CSV. Интеграционный тест читает реальные исходники с суффиксом (2), проверяет три SKU, уникальность кодов и допустимость всех заказов; при отсутствии этого локального набора тест пропускается.

Ограничения MVP

Нет customer ID, lead time, минимального заказа и фактических stockout intervals. Нет подтверждённой ETA поставок. Нельзя точно отделить разовые проектные продажи от регулярных по клиентам. Нет авторизации, БД, сохранения сценариев или отправки заказов; сервер привязан к 127.0.0.1, рассчитан на локальную демонстрацию. Сценарии сбрасываются при обновлении страницы. Годовые агрегаты сезонности имеют неподтверждённую единицу. Отчёты расходятся, поэтому рекомендации требуют проверки закупщиком. Excel не пересчитываются и не изменяются.

Документация используемых библиотек: Next.js, ExcelJS.

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

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

Nurbolat Abdikarim 1

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

  • 2026-09-23 17:28Build StockPilot AI MVP for Systeme ElectricNurbolat Abdikarim
Структура репозитория (19 файлов)
.gitignore
README.md
app/api/data/route.ts
app/globals.css
app/layout.tsx
app/page.tsx
components/dashboard.tsx
lib/csv.ts
lib/engine.ts
lib/importer.ts
lib/types.ts
next-env.d.ts
next.config.ts
package-lock.json
package.json
start.ps1
tests/engine.test.ts
tests/import.test.ts
tsconfig.json

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

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

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