from enum import Enum from typing import Any, Dict, List, Optional from pydantic import BaseModel class QuotationStatus(str, Enum): draft = "draft" sent = "sent" accepted = "accepted" rejected = "rejected" class QuotationItemCreate(BaseModel): product_id: Optional[str] = None description: Optional[str] = None description_en: Optional[str] = None description_gr: Optional[str] = None unit_type: str = "pcs" # pcs / kg / m unit_cost: float = 0.0 discount_percent: float = 0.0 quantity: float = 1.0 vat_percent: float = 24.0 sort_order: int = 0 class QuotationItemInDB(QuotationItemCreate): id: str quotation_id: str line_total: float = 0.0 class QuotationCreate(BaseModel): customer_id: str title: Optional[str] = None subtitle: Optional[str] = None language: str = "en" # en / gr order_type: Optional[str] = None shipping_method: Optional[str] = None estimated_shipping_date: Optional[str] = None global_discount_label: Optional[str] = None global_discount_percent: float = 0.0 shipping_cost: float = 0.0 shipping_cost_discount: float = 0.0 install_cost: float = 0.0 install_cost_discount: float = 0.0 extras_label: Optional[str] = None extras_cost: float = 0.0 comments: List[str] = [] quick_notes: Optional[Dict[str, Any]] = None items: List[QuotationItemCreate] = [] # Client override fields (for this quotation only; customer record is not modified) client_org: Optional[str] = None client_name: Optional[str] = None client_location: Optional[str] = None client_phone: Optional[str] = None client_email: Optional[str] = None # Legacy quotation fields is_legacy: bool = False legacy_date: Optional[str] = None # ISO date string, manually set legacy_pdf_path: Optional[str] = None # Nextcloud path to uploaded PDF class QuotationUpdate(BaseModel): title: Optional[str] = None subtitle: Optional[str] = None language: Optional[str] = None status: Optional[QuotationStatus] = None order_type: Optional[str] = None shipping_method: Optional[str] = None estimated_shipping_date: Optional[str] = None global_discount_label: Optional[str] = None global_discount_percent: Optional[float] = None shipping_cost: Optional[float] = None shipping_cost_discount: Optional[float] = None install_cost: Optional[float] = None install_cost_discount: Optional[float] = None extras_label: Optional[str] = None extras_cost: Optional[float] = None comments: Optional[List[str]] = None quick_notes: Optional[Dict[str, Any]] = None items: Optional[List[QuotationItemCreate]] = None # Client override fields client_org: Optional[str] = None client_name: Optional[str] = None client_location: Optional[str] = None client_phone: Optional[str] = None client_email: Optional[str] = None # Legacy quotation fields is_legacy: Optional[bool] = None legacy_date: Optional[str] = None legacy_pdf_path: Optional[str] = None class QuotationInDB(BaseModel): id: str quotation_number: str customer_id: str title: Optional[str] = None subtitle: Optional[str] = None language: str = "en" status: QuotationStatus = QuotationStatus.draft order_type: Optional[str] = None shipping_method: Optional[str] = None estimated_shipping_date: Optional[str] = None global_discount_label: Optional[str] = None global_discount_percent: float = 0.0 shipping_cost: float = 0.0 shipping_cost_discount: float = 0.0 install_cost: float = 0.0 install_cost_discount: float = 0.0 extras_label: Optional[str] = None extras_cost: float = 0.0 comments: List[str] = [] quick_notes: Dict[str, Any] = {} subtotal_before_discount: float = 0.0 global_discount_amount: float = 0.0 new_subtotal: float = 0.0 vat_amount: float = 0.0 final_total: float = 0.0 nextcloud_pdf_path: Optional[str] = None nextcloud_pdf_url: Optional[str] = None created_at: str updated_at: str items: List[QuotationItemInDB] = [] # Client override fields client_org: Optional[str] = None client_name: Optional[str] = None client_location: Optional[str] = None client_phone: Optional[str] = None client_email: Optional[str] = None # Legacy quotation fields is_legacy: bool = False legacy_date: Optional[str] = None legacy_pdf_path: Optional[str] = None class QuotationListItem(BaseModel): id: str quotation_number: str title: Optional[str] = None customer_id: str status: QuotationStatus final_total: float created_at: str updated_at: str nextcloud_pdf_url: Optional[str] = None is_legacy: bool = False legacy_date: Optional[str] = None legacy_pdf_path: Optional[str] = None class QuotationListResponse(BaseModel): quotations: List[QuotationListItem] total: int class NextNumberResponse(BaseModel): next_number: str