from datetime import datetime from decimal import Decimal from sqlalchemy import DateTime, ForeignKey, Integer, Numeric, String from sqlalchemy.orm import Mapped, mapped_column, relationship from db import Base class Customer(Base): __tablename__ = "customer" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(120), nullable=False) email: Mapped[str] = mapped_column(String(200), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) invoices: Mapped[list["Invoice"]] = relationship( back_populates="customer", cascade="all, delete-orphan" ) class Invoice(Base): __tablename__ = "invoice" id: Mapped[int] = mapped_column(Integer, primary_key=True) number: Mapped[str] = mapped_column(String(40), nullable=False, unique=True) customer_id: Mapped[int] = mapped_column(ForeignKey("customer.id"), nullable=False) issued_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) due_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) status: Mapped[str] = mapped_column(String(20), default="draft") customer: Mapped[Customer] = relationship(back_populates="invoices") line_items: Mapped[list["LineItem"]] = relationship( back_populates="invoice", cascade="all, delete-orphan" ) payments: Mapped[list["Payment"]] = relationship( back_populates="invoice", cascade="all, delete-orphan" ) class LineItem(Base): __tablename__ = "line_item" id: Mapped[int] = mapped_column(Integer, primary_key=True) invoice_id: Mapped[int] = mapped_column(ForeignKey("invoice.id"), nullable=False) description: Mapped[str] = mapped_column(String(200), nullable=False) quantity: Mapped[int] = mapped_column(Integer, default=1) unit_price: Mapped[Decimal] = mapped_column(Numeric(10, 2), default=0) invoice: Mapped[Invoice] = relationship(back_populates="line_items") class Payment(Base): __tablename__ = "payment" id: Mapped[int] = mapped_column(Integer, primary_key=True) invoice_id: Mapped[int] = mapped_column(ForeignKey("invoice.id"), nullable=False) amount: Mapped[Decimal] = mapped_column(Numeric(10, 2), nullable=False) method: Mapped[str] = mapped_column(String(20), default="cash") paid_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) invoice: Mapped[Invoice] = relationship(back_populates="payments")