""" Modele Pydantic pentru facturi - Compatibile cu aplicația Flask existentă """ from pydantic import BaseModel, Field, validator from datetime import date from typing import Optional, List, Literal from decimal import Decimal class InvoiceBase(BaseModel): """Model de bază pentru factură - mapează exact pe rezultatul query-ului Flask""" nume: str = Field(description="Numele partenerului") nract: int = Field(description="Numărul actului") dataact: Optional[date] = Field(description="Data actului") datascad: Optional[date] = Field(description="Data scadentă") contract: Optional[str] = Field(description="Numărul contractului") cod_fiscal: Optional[str] = Field(description="Codul fiscal") reg_comert: Optional[str] = Field(description="Registrul comerțului") cont: Optional[str] = Field(description="Contul contabil") valuta: str = Field(default="RON", description="Valuta (RON, EUR, USD, etc.)") class Invoice(InvoiceBase): """Model complet pentru factură cu calcule financiare""" totctva: Decimal = Field(description="Total cu TVA", decimal_places=2) achitat: Decimal = Field(description="Suma achitată", decimal_places=2) soldfinal: Decimal = Field(description="Soldul final", decimal_places=2) css_class: Literal["", "invoice-paid", "invoice-overdue"] = Field( default="", description="Clasa CSS pentru stilizare" ) @validator('css_class', always=True) def determine_css_class(cls, v, values): """Determină automat clasa CSS bazată pe status factură""" if 'soldfinal' in values and 'datascad' in values: sold = values['soldfinal'] data_scad = values['datascad'] if sold < 1: return 'invoice-paid' elif data_scad and data_scad < date.today() and sold != 0: return 'invoice-overdue' return '' class InvoiceFilter(BaseModel): """Filtru pentru căutarea facturilor""" company: str = Field(description="Codul firmei (schema Oracle)") partner_type: Literal["CLIENTI", "FURNIZORI"] = Field(description="Tipul partenerului") luna: Optional[int] = Field(default=None, ge=1, le=12, description="Luna contabilă (1-12)") an: Optional[int] = Field(default=None, ge=2000, le=2100, description="Anul contabil") partner_name: Optional[str] = Field(description="Filtru după nume") cont: Optional[str] = Field(description="Filtru după cont contabil") only_unpaid: bool = Field(default=True, description="Doar neachitate") min_amount: Optional[Decimal] = Field(description="Suma minimă") max_amount: Optional[Decimal] = Field(description="Suma maximă") page: int = Field(default=1, ge=1, description="Pagina") page_size: int = Field(default=50, ge=1, le=10000000, description="Mărimea paginii") class InvoiceListResponse(BaseModel): """Răspuns pentru lista de facturi""" invoices: List[Invoice] total_count: int filtered_count: int total_amount: Decimal page: int page_size: int has_more: bool accounting_period: Optional[dict] = Field(default=None, description="Perioada contabilă (an, luna)") # Total sold din TOATE facturile filtrate (nu doar pagina curentă) total_sold_all: Decimal = Field(default=Decimal('0.00'), description="Total sold din toate facturile filtrate") class InvoiceSummary(BaseModel): """Rezumat pentru facturi - pentru dashboard""" company: str partner_type: str total_invoices: int total_amount: Decimal paid_amount: Decimal outstanding_amount: Decimal overdue_amount: Decimal overdue_count: int