Перейти до змісту

Module: Production & Assembly (Виробництво та Збірка)

Статус: ✅ Production MVP + Full UI + Analytics (2026-04-27, Phases A–H).

Модуль відповідає за управління процесами перетворення сировини та компонентів у готову продукцію, розрахунок собівартості, аналітику завантаження складу, забезпеченості замовлень і собівартісних відхилень.

Архітектурний принцип

Списання матеріалів + прихід готової продукції — примітив Essentials, реалізований через документ Manufacturing (backend/essentials/models/manufacturing.py). Аддон production/тонкий плануючий шар: BOM + WorkOrder + variance/WIP accounting + звіти. Якщо аддон вимкнути, виробничий flow працює через ручні Manufacturing документи.


✅ Реалізовано

Phase A — Essentials Manufacturing

  • Manufacturing + ManufacturingInputLine + ManufacturingOutputLine (TransactionModel) з атомарним двостороннім flow.
  • post_manufacturing: FIFO write-off inputs через batch_service.deduct_fifo + receive output batches через receive_batch з actual cost = Σ(inputs.total_cost) × output_qty / Σ(outputs.qty). PostingGroup: Dt output / Ct inventory.
  • unpost_manufacturing: власні reverse-функції, що фільтрують StockTransaction за transaction_type (mixed ISSUE+RECEIPT).
  • Інваріант: StockTransaction + Batch + ItemWarehouseStock + PostingGroup = збігаються до копійки.
  • Коригування залишків — через існуючий DocumentOperation (окремий flow).
  • REST: /api/v1/essentials/manufacturing/ + actions post_document, unpost_document.

Phase B — Production → Manufacturing bridge

  • WorkOrder.manufacturing_document FK на Essentials Manufacturing (SET_NULL).
  • complete_work_order створює Manufacturing з BOM, викликає post_manufacturing, зберігає FK.
  • Idempotent: повторний complete видаляє попередній Manufacturing і створює новий.
  • unpost_work_order → unpost + delete Manufacturing.

Phase C — WIP + Standard cost + Variance

  • BOM.standard_cost_per_unit (Decimal) + BOMLine.standard_input_cost (per-BOM override).
  • ProductionSettings singleton per tenant: variance_account, wip_account.
  • Manufacturing.wip_account (nullable) → якщо set, двохетапний flow: Dt WIP / Ct Inventory, потім Dt Output / Ct WIP (WIP net = 0 після completion, 4 entries замість 2).
  • Variance як окремий PostingGroup з document_type='WorkOrderVariance': якщо actual > standardDt Variance / Ct Output, якщо actual < standardDt Output / Ct Variance.

Phase D — Item type extension

  • Item.item_type розширено: product, material, raw_material, semi_product, finished_goods, service, set.

Phase E — Multi-level BOM + Work Centers + Scrap

  • explode_bom(bom, multiplier) — рекурсивно розгортає multi-level BOM до leaf-level raw materials з cycle detection (ValidationError на A→B→A). REST: GET /api/v1/production/boms/{id}/explode/?qty=N.
  • aggregate_requirements(...) — групування по item_id.
  • BOMLine.scrap_pct — нормативний % браку, що інфлює required quantity на completion.
  • WorkOrder.actual_output_qty — фактичний випуск (override planned) для yield shortfall.
  • Нові masterdata: WorkCenter (capacity, cost/hour, department), Operation (setup/run times, work_center), BOMRouting (sequence of operations per BOM).

Phase F — Frontend config + QC placeholder

  • config/production.ts — групи Master Data, Processes, Reports, Settings.
  • Manufacturing додано до Essentials Sales operations.
  • Item.requires_qc поле — заготівка для Quality integration.

Phase G — Custom UI forms + Reports (сесія 2026-04-27)

Кастомні форми замість генеричних:

  • WorkOrderWorkOrderForm.tsx: shell через useDocumentForm + DocumentFormShell, bundle-fetch form-data/form-refs, preflight-check (BOM/qty/warehouse/accounts), toast з номером створеного Manufacturing, quick-jump pill → Manufacturing form.
  • BOMBOMForm.tsx: useMasterDataForm + inline BOMLine editor, «Розгорнути» action (GET explode endpoint).
  • WorkCenter / Operation / BOMRouting — компактні форми з обчислюваними preview (daily cost, time for 10/100 units, grouped by BOM).
  • Кастомні списки для всіх 5 сутностей з правильними колонками (capacity, times, sequence, linked manufacturing number).
  • ProductionSettings перенесено у загальний /settings?section=production hub (замість окремого пункту меню).

Shortcut-посилання на Essentials:

  • У Production sidebar з'явилися швидкі посилання на Items, Warehouses, Chart of Accounts, Organizations, Departments, Manufacturing — без дублювання даних, лише UX-доступ з контексту виробництва.
  • Manufacturing posting redirect — гвинтик на WorkOrder відкриває Manufacturing postings (бо WO сам по собі не має PostingGroup окрім variance).

5 аналітичних звітів:

Звіт Файл Суть
Warehouse utilization WarehouseUtilizationReport.tsx SVG візуалізація — полиці хлібу / силоси / склади-будівлі. % = вага-в-наявності / warehouse.capacity_weight_kg (real) або відносний (fallback). Клікабельні імена складів.
Order readiness OrderReadinessReport.tsx Картки з RingProgress per open WorkOrder; explode BOM × current stock → readiness %; shortfall bars per material. KPI: ready/partial/blocked.
Production queue ProductionQueueReport.tsx Swimlane: лейни = WorkCenter групами по підрозділах. Блоки = кроки маршруту WorkOrder по датах. Монохром grays + тільки червоним підсвічено late. Filter by department.
Planned cost CostAnalysisReport.tsx Drill-down таблиця: materials → scrap → routing → computed vs BOM standard. Per-BOM з Expand/Collapse, клікабельне ім'я BOM. Всі фони однакові, variance лише текстом зелений/червоний.
Actual cost ActualCostAnalysisReport.tsx Для періоду: агрегат по Manufacturing docs групованих по source_bom_id. Materials — реальна FIFO. Labor — план з BOMRouting (факт не трекається). Drill-down до кожного Manufacturing документа з клікабельним номером.
Stock balances StockBalancesReport.tsx Excel-подібна таблиця item × warehouse з sub-headers Qty/Amount. Sort, search, filter material/product/warehouse, hide-zeros toggle.

Phase H — Економічна логіка (сесія 2026-04-27)

Seeder з двома сценаріями (core/seeders/production.py): - Bakery (short-cycle) — 5 BOM (хліб, багет, булочки), 3 WC (тістоміс/піч/пакування), 5 operations, 4 routing steps per recipe. ~60 детермінованих WO. - Steel workshop (long-cycle) — 3 multi-level BOM (панель → каркас 6×12 / 12×24), 5 WC (різка/зварка/підготовка/фарбування/складання), 10 operations. 8 long-cycle WO spanning 6 місяців. - Material receipts — 2 GoodsReceipts на всі сировини ~60 днів тому, щоб FIFO мав з чого списувати. - Warehouse capacity — задає capacity_weight_kg / capacity_volume_m3 для demo складів. - Idempotent — детерміновані номери (BK-YYMMDD-NN) + cleanup legacy-random-suffix WO + repost-при-зміні-account + legacy-aggregate-posting detection.

Per-line PostingEntry в Manufacturing (manufacturing_service.py): - Рефакторинг _post_atomic — замість 2-4 агрегованих PostingEntry тепер одна PostingEntry на КОЖЕН матеріал з quantity + product FK. - Для 7 inputs + 1 output → 16 entries у WIP-потоці (було 4). - Проводки стали читабельними: «Ct 3000 Raw Materials — Wheat flour 12 кг = 264 грн».

3-рівневий пріоритет планової ціни: 1. BOMLine.standard_input_cost (own override for this BOM) 2. ItemPrice[price_type=PLAN_COST] — окремий прайс-лист «Планова собівартість» 3. Item.price — catalog fallback

  • Новий PriceType PLAN_COST створюється seeder-ом, 15 материалів мають ItemPrice цього типу.
  • BOMLineSerializer повертає input_item_planning_price + input_item_price — фронтенд бачить обидва.
  • BOM-форма показує колонку «Ціна/од» з ярликом джерела: 22.00 (планова) / 22.00 (своя) / 22.00 (з номенклатури).
  • Обидва звіти (Planned cost і Actual cost materials-standard) використовують той самий helper _effective_unit_price.

Warehouse capacity + real fill %: - Нові поля Warehouse.capacity_weight_kg + capacity_volume_m3 (nullable). - Item.weight / Item.volume (already existed) — тепер використовуються у report: on_hand_qty × item.weight = current_weight_kg. - Warehouse Utilization: якщо capacity задано → real % (вага-в-наявності / capacity); якщо не задано → fallback на relative (column max). Tooltip показує формулу розрахунку.


Тести

  • Essentials: 72 тести (Manufacturing: 8 — core invariant, re-post, unpost, atomic rollback, блокування правки posted).
  • Production: 23 тести (base + variance/WIP + multi-level/scrap/routing).
  • Разом: 95 passing.

Основні REST-endpoint'и

Довідники та документи

  • GET/POST /api/v1/production/boms/ + /bom-lines/ + /work-orders/ + /work-centers/ + /operations/ + /bom-routings/
  • GET /api/v1/production/settings/ — singleton за-tenant-ом
  • POST /api/v1/production/work-orders/{id}/post_document/ (alias for /complete/)
  • POST /api/v1/production/work-orders/{id}/unpost_document/ (alias for /cancel/)
  • GET /api/v1/production/boms/{id}/explode/?qty=N — multi-level explosion
  • GET /api/v1/production/boms/{id}/form-data/ + /form-refs/ — bundled UI data

Звіти

  • GET /api/v1/production/reports/warehouse-utilization/
  • GET /api/v1/production/reports/order-readiness/?status=planned,in_progress
  • GET /api/v1/production/reports/queue/?department=<id>
  • GET /api/v1/production/reports/cost-analysis/?bom_id=<id> — planned
  • GET /api/v1/production/reports/actual-cost-analysis/?date_from=&date_to=&bom_id=
  • GET /api/v1/production/reports/stock-balances/?item_type=material|product&warehouse_id=<id>&hide_zero=true

Структура меню Виробництва

Виробництво
├── Довідники
│   ├── Виробничі довідники
│   │   ├── Специфікації (BOM)
│   │   ├── Робочі центри
│   │   ├── Технологічні операції
│   │   └── Маршрути BOM
│   └── Спільні довідники (shortcuts з Essentials)
│       ├── Номенклатура
│       ├── Склади
│       ├── План рахунків
│       ├── Організації
│       └── Підрозділи
├── Процеси
│   └── Виробничі документи
│       ├── Виробничі замовлення (WorkOrder)
│       └── Виробництво (Manufacturing shortcut)
└── Звіти
    ├── Дашборди
    │   ├── Завантаження складу
    │   ├── Забезпеченість замовлень
    │   └── Черга виробництва
    └── Аналітика
        ├── Залишки по складах
        ├── Планова собівартість
        └── Фактична собівартість

Налаштування виробництва — у /settings?section=production

🔬 Технічний борг

Жорсткі ліміти поточної реалізації

  1. Фактичну працю не трекаємо. ActualCostAnalysis для Labor завжди показує план (BOMRouting × Operation.time × WorkCenter.cost_per_hour). Потрібна модель ManufacturingLaborLine або інтеграція з HRM-таймшитами, щоб фіксувати реальні людино-години на кожне проведення.
  2. PostingEntry quantity на per-line — не FIFO per-item. Коли один item з'являється в кількох рядках одного Manufacturing (edge case — зараз в моделі не заборонено), stx_agg поверне сумарну вартість, а ми ділимо її на рядки як вагу. Зазвичай неважливо (редагуй input лінії щоб не дублювати item), але треба пам'ятати.
  3. Warehouse.capacity — тільки для звіту. Немає логіки «відмовити GoodsReceipt якщо склад переповнено». Треба продумати behavior — hard-block чи soft-warning чи ledger.
  4. Capacity тільки weight/volume. Немає полиць/зон/slot-bin. Для «реального» WMS треба окрема модель WarehouseZone + Slot.
  5. ProductionSettings — один singleton на tenant. При multi-factory буде проблема (variance/WIP accounts однакові для всіх цехів).
  6. BOM не версіонується history-way. Якщо змінити BOM.lines після проведення WO — попередні Manufacturing-доки не «заморозять» свою версію BOM. Актуальний BOM завжди актуальний. Для аудиту потрібно snapshoting.
  7. Auto-cascade subassembly WO не реалізовано. Якщо caркас 12×24 вимагає 18 панелей, а їх нема на складі — WO просто падає на FIFO shortage. Треба створювати auto-WO для subassembly.
  8. Seeder прив'язаний до кодів матеріалів. Якщо codes змінити — seeder не знайде. Треба зробити матчинг за item_type + name pattern.

Якість коду

  • _post_atomic в manufacturing_service = ~300 рядків. Можна декомпозувати на кроки (FIFO → output → posting → variance).
  • Cost-analysis і Actual-cost-analysis ділять логіку _bom_std_materials / _bom_std_labor — винесено в helpers. Добре.
  • computeFillPct у WarehouseUtilizationReport — клієнтський дубль backend-логіки. Треба вирішити де має бути розрахунок — там або там (зараз обидва місця).

Seed-data проблеми

  • У demo-тенанті Item.price == ItemPrice[PLAN_COST].price (однакові значення). Для production-like тесту треба зробити розрив — тоді буде очевидно що пріоритет працює.
  • Warehouse capacity для всіх складів — «round numbers» (30000 / 15000 / 20000 кг). Для реалізму варто різні (12347, 8902 тощо).

🔮 Deferred / Ideas

P1 — наступна сесія (високий пріоритет)

  • [ ] Labor tracking на Manufacturing. Нова модель ManufacturingLaborLine(document, operation, operator, hours, rate). UI: додати вкладку «Праця» в формі Manufacturing. Звіт Actual cost буде показувати реальний labor замість plan.
  • [ ] Auto-cascade subassembly WO. При complete_work_order: якщо input_item сам має активний BOM і немає на складі — створити вкладений WO автоматично, зв'язати через parent_work_order_id. Prevent infinite recursion (уже є в explode_bom).
  • [ ] BOM snapshoting. При Manufacturing.post — клон BOM.lines у ManufacturingBOMSnapshot для повної відтворюваності аудитом. Cost Analysis (actual) буде використовувати snapshot, не поточний BOM.

P2 — середньострокова перспектива

  • [ ] Capacity planning з календарем. Сторінка-дашборд «Завантаження WC на тиждень». Перетягування WO між датами (react-dnd). На backend: WorkOrder.scheduled_start + scheduled_end, WorkCenterCalendar модель з робочими/вихідними днями.
  • [ ] Quality Control integration. Модель QualityInspection(manufacturing_output_line, status, inspector, notes). Item.requires_qc тригер → output batch у «QC hold» локації до approval. Integration point — essentials_quality plugin (вже є hook-пункт у manufacturing_service).
  • [ ] Price-variance breakdown. Розщеплення material variance на:
    • Price variance = (actual_price − std_price) × actual_qty
    • Quantity variance = std_price × (actual_qty − std_qty) Формула з classical management accounting. У UI — два окремі рядки у summary.
  • [ ] Кастомна форма Warehouse з capacity. Зараз capacity_weight / capacity_volume редагуються лише через generic MasterDataForm. Треба кастомна форма з валідацією + доп. полями zone_count, operating_hours, temperature_controlled.

P3 — стратегічні фічі

  • [ ] Real subcontracting. Мануфактуру виконує зовнішній виконавець. Новий flow: WorkOrder.external_vendor (Client FK), матеріали відправляються Transfer-документом, готова продукція — приходить як GoodsReceipt із BOM-референсом.
  • [ ] Shop Floor UI / Kiosk mode. Планшет у цеху: оператор відкриває поточний крок маршруту → вводить фактичний час → наступний крок. Інтеграція з Labor tracking (P1).
  • [ ] Multi-facility ProductionSettings. Заміна singleton на ProductionSettings(facility) з unique_together(tenant, facility). Facility — нова модель, FK з Organization.
  • [ ] Actual Cost із capacity-утилізацією. Overhead algorithm: якщо WC використовується на 80% від capacity, overhead rate normalized; якщо 30% — overhead стає дорожчий (ідле-час).

P4 — «було б непогано»

  • [ ] Графічний BOM-конструктор (drag-n-drop або tree-view). Поточні generic CRUD + custom forms справляються, але для складних multi-level рецептів було б зручно.
  • [ ] Excel-імпорт BOM. Завантажив .xlsx з шаблоном → створилися BOM + BOMLine.
  • [ ] Gantt-chart WorkOrder execution. На backend уже є scheduled_start/end (якщо P2 буде), можна зображати через mantine-charts.

Історія ключових версій

Дата Фаза Що додано
2026-04-23 A-F Манufacturing + WorkOrder + WIP + Variance + Multi-level BOM + Work Centers + Scrap + Frontend config. 95 тестів passing.
2026-04-27 G-H Кастомні UI-форми для всіх 5 сутностей + 5 аналітичних звітів + per-line PostingEntry + 3-рівневий пріоритет цін (BOMLine override > PLAN_COST price type > Item.price) + Warehouse capacity + seeder з 2 сценаріями + SVG-візуалізація «Полиці / Силоси / Склади».

Пов'язані плани