feat: add production templates API and documentation for manufacturing phase 2

- Implemented CRUD operations for production templates, including listing, retrieving, creating, updating, and deactivating templates.
- Introduced a new API contract for production runs, detailing the lifecycle from creation to completion, including handling of stock inputs and outputs.
- Documented the architecture, requirements, entity model, and API contract for the manufacturing phase 2, ensuring clarity on the production process and its integration with existing systems.
This commit is contained in:
2026-07-31 10:22:40 +05:30
parent 415ac94ab2
commit 7d6e597389
80 changed files with 11037 additions and 886 deletions
+70
View File
@@ -0,0 +1,70 @@
"""Run the whole manufacturing smoke suite in dependency order.
python Backend/smoke/run_all.py
Order matters: m4 creates the isolated SMOKE-PRD warehouse and drains it, m5 consumes the
run m4 leaves with its terminal stage InProgress. Each script is individually re-runnable,
but m5 deliberately refuses to run twice against an already-approved terminal stage — that
guard is what stops it silently asserting against the wrong state.
Prerequisites: ERPCore on :5224 and AuthHex on :5602 (override with ERP_SMOKE_API /
ERP_SMOKE_AUTH / ERP_SMOKE_USER / ERP_SMOKE_PASSWORD).
"""
from __future__ import annotations
import re
import subprocess
import sys
from pathlib import Path
SCRIPTS = [
("M2 templates + graph validation", "m2_templates.py"),
("M3 run creation / board / quantities", "m3_runs.py"),
("M4 stage start / complete / approve / transfer", "m4_stage_actions.py"),
("M4b UOM conversion on stock inputs", "m4b_uom_conversion.py"),
("M5 terminal receipt + cost pool", "m5_receipt.py"),
("M6+M7 leftover / rework / cancel", "m6_m7_leftover_rework_cancel.py"),
]
SUMMARY = re.compile(r"^(\S+): (\d+)/(\d+) assertions passed")
def main() -> int:
here = Path(__file__).parent
results = []
failed = False
for label, script in SCRIPTS:
print(f"\n{'=' * 70}\n{label} ({script})\n{'=' * 70}", flush=True)
proc = subprocess.run(
[sys.executable, script, *sys.argv[1:]],
cwd=here, capture_output=True, text=True, encoding="utf-8", errors="replace",
)
sys.stdout.write(proc.stdout)
if proc.stderr.strip():
sys.stderr.write(proc.stderr)
passed = total = 0
for line in proc.stdout.splitlines():
m = SUMMARY.match(line.strip())
if m:
passed, total = int(m.group(2)), int(m.group(3))
results.append((label, passed, total, proc.returncode))
if proc.returncode != 0:
failed = True
print(f"\n{'=' * 70}\nSUITE SUMMARY\n{'=' * 70}")
grand_passed = grand_total = 0
for label, passed, total, rc in results:
grand_passed += passed
grand_total += total
state = "OK " if rc == 0 else "FAIL"
print(f" [{state}] {label:<48} {passed}/{total}")
print(f"\n TOTAL: {grand_passed}/{grand_total} assertions"
+ (" — ALL GREEN" if not failed else " (SUITE FAILED)"))
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())