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>
194 lines
4.7 KiB
Python
194 lines
4.7 KiB
Python
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]]
|