Add Mago4 demo ERP with Python FastAPI
Implements a working in-memory ERP demo inspired by Mago4, covering the core modules: dashboard with KPI widgets, customers, suppliers, products, sales orders, purchase orders, and warehouse inventory. - FastAPI backend with Pydantic models and REST API (auto-docs at /docs) - Jinja2 HTML templates with Mago4-style UI (dark sidebar, blue/orange/ green/red palette, Material Design icons) - In-memory fake database seeded with sample customers, suppliers, products, and orders — ready to swap for SQLAlchemy + SQL Server - Workarounds for Python 3.14 + Starlette 1.3 / Jinja2 compatibility (cache_size=0, new TemplateResponse(request, name, ctx) signature) - launch.json for one-click preview; run.bat for manual startup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class OrderStatus(str, Enum):
|
||||
DRAFT = "draft"
|
||||
CONFIRMED = "confirmed"
|
||||
PARTIALLY_RECEIVED = "partially_received"
|
||||
RECEIVED = "received"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
|
||||
class OrderType(str, Enum):
|
||||
SALES = "sales"
|
||||
PURCHASE = "purchase"
|
||||
|
||||
|
||||
class Customer(BaseModel):
|
||||
id: int
|
||||
code: str
|
||||
name: str
|
||||
email: str
|
||||
phone: str
|
||||
address: str
|
||||
city: str
|
||||
country: str
|
||||
credit_limit: float
|
||||
balance: float
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"code": "CUST001",
|
||||
"name": "Acme Corp",
|
||||
"email": "info@acme.com",
|
||||
"phone": "+39 02 1234567",
|
||||
"address": "Via Roma 10",
|
||||
"city": "Milano",
|
||||
"country": "IT",
|
||||
"credit_limit": 50000,
|
||||
"balance": 15000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Supplier(BaseModel):
|
||||
id: int
|
||||
code: str
|
||||
name: str
|
||||
email: str
|
||||
phone: str
|
||||
address: str
|
||||
city: str
|
||||
country: str
|
||||
payment_terms_days: int
|
||||
balance: float
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"code": "SUPP001",
|
||||
"name": "Global Components Ltd",
|
||||
"email": "sales@globalcomp.com",
|
||||
"phone": "+44 20 7946 0958",
|
||||
"address": "123 Oxford Street",
|
||||
"city": "London",
|
||||
"country": "UK",
|
||||
"payment_terms_days": 30,
|
||||
"balance": 5000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
id: int
|
||||
code: str
|
||||
description: str
|
||||
category: str
|
||||
unit_price: float
|
||||
quantity_in_stock: int
|
||||
reorder_level: int
|
||||
supplier_id: Optional[int] = None
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"code": "PROD001",
|
||||
"description": "Industrial Widget A",
|
||||
"category": "Electronics",
|
||||
"unit_price": 125.50,
|
||||
"quantity_in_stock": 250,
|
||||
"reorder_level": 50,
|
||||
"supplier_id": 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class OrderLine(BaseModel):
|
||||
id: int
|
||||
product_id: int
|
||||
product_code: str
|
||||
product_description: str
|
||||
quantity: float
|
||||
unit_price: float
|
||||
total_amount: float
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"product_id": 1,
|
||||
"product_code": "PROD001",
|
||||
"product_description": "Industrial Widget A",
|
||||
"quantity": 10,
|
||||
"unit_price": 125.50,
|
||||
"total_amount": 1255.00
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SalesOrder(BaseModel):
|
||||
id: int
|
||||
order_number: str
|
||||
order_date: datetime
|
||||
customer_id: int
|
||||
customer_name: str
|
||||
status: OrderStatus
|
||||
lines: List[OrderLine]
|
||||
total_amount: float
|
||||
delivery_date: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"order_number": "SO-2024-001",
|
||||
"order_date": "2024-01-15T10:30:00",
|
||||
"customer_id": 1,
|
||||
"customer_name": "Acme Corp",
|
||||
"status": "confirmed",
|
||||
"lines": [],
|
||||
"total_amount": 2500.00,
|
||||
"delivery_date": "2024-02-15T00:00:00"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PurchaseOrder(BaseModel):
|
||||
id: int
|
||||
order_number: str
|
||||
order_date: datetime
|
||||
supplier_id: int
|
||||
supplier_name: str
|
||||
status: OrderStatus
|
||||
lines: List[OrderLine]
|
||||
total_amount: float
|
||||
expected_delivery_date: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"order_number": "PO-2024-001",
|
||||
"order_date": "2024-01-10T14:00:00",
|
||||
"supplier_id": 1,
|
||||
"supplier_name": "Global Components Ltd",
|
||||
"status": "confirmed",
|
||||
"lines": [],
|
||||
"total_amount": 5000.00,
|
||||
"expected_delivery_date": "2024-02-10T00:00:00"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DashboardWidget(BaseModel):
|
||||
title: str
|
||||
subtitle: Optional[str] = None
|
||||
style: str # "stats", "chart", "grid"
|
||||
size: str = "small" # "small", "medium", "large"
|
||||
icon: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
value: Optional[str] = None
|
||||
format: Optional[str] = None # "money", "number", "date"
|
||||
data: Optional[dict] = None
|
||||
|
||||
|
||||
class Dashboard(BaseModel):
|
||||
widgets: List[List[DashboardWidget]]
|
||||
Reference in New Issue
Block a user