Initial commit: Ballet Production Suite ERP/CRM foundation

This commit is contained in:
2026-01-24 13:28:54 +01:00
commit 01ae4a09ff
10 changed files with 568 additions and 0 deletions

93
backend/models.py Normal file
View File

@@ -0,0 +1,93 @@
from datetime import datetime
from typing import List, Optional
from sqlmodel import Field, SQLModel, Relationship
# --- User & Auth ---
class User(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
username: str = Field(index=True, unique=True)
hashed_password: str
is_active: bool = Field(default=True)
is_admin: bool = Field(default=False)
# --- Inventory & Materials ---
class Material(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
description: Optional[str] = None
unit: str # e.g., "meters", "units", "grams"
stock_quantity: float = Field(default=0.0)
reorder_level: float = Field(default=0.0)
cost_per_unit: float = Field(default=0.0)
# --- Products ---
class Product(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
sku: str = Field(index=True, unique=True)
description: Optional[str] = None
base_price: float = Field(default=0.0)
estimated_time_hours: float = Field(default=0.0)
# Relationships
orders: List["OrderProductLink"] = Relationship(back_populates="product")
materials: List["ProductMaterialLink"] = Relationship(back_populates="product")
class ProductMaterialLink(SQLModel, table=True):
product_id: Optional[int] = Field(default=None, foreign_key="product.id", primary_key=True)
material_id: Optional[int] = Field(default=None, foreign_key="material.id", primary_key=True)
quantity_required: float
product: Product = Relationship(back_populates="materials")
material: Material = Relationship()
# --- CRM ---
class Client(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
full_name: str = Field(index=True)
email: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
# Measurements (as a JSON or separate fields, keeping it simple for now)
measurements: Optional[str] = None # Or use a JSON type if supported better
orders: List["Order"] = Relationship(back_populates="client")
# --- Orders & Production ---
class OrderStatus(str):
QUOTATION = "Quotation"
PENDING = "Pending"
IN_PRODUCTION = "In Production"
SHIPPED = "Shipped"
DELIVERED = "Delivered"
CANCELLED = "Cancelled"
class Order(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
client_id: int = Field(foreign_key="client.id")
order_date: datetime = Field(default_factory=datetime.utcnow)
status: str = Field(default=OrderStatus.QUOTATION)
total_amount: float = Field(default=0.0)
notes: Optional[str] = None
client: Client = Relationship(back_populates="orders")
products: List["OrderProductLink"] = Relationship(back_populates="order")
class OrderProductLink(SQLModel, table=True):
order_id: Optional[int] = Field(default=None, foreign_key="order.id", primary_key=True)
product_id: Optional[int] = Field(default=None, foreign_key="product.id", primary_key=True)
quantity: int = Field(default=1)
customizations: Optional[str] = None
order: Order = Relationship(back_populates="products")
product: Product = Relationship(back_populates="orders")
class ProductionStep(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
order_id: int = Field(foreign_key="order.id")
step_name: str # e.g., "Corte", "Confección", "Terminado"
status: str = Field(default="Pending") # Pending, In Progress, Completed
assigned_to: Optional[int] = Field(default=None, foreign_key="user.id")
started_at: Optional[datetime] = None
completed_at: Optional[datetime] = None