"""Pydantic schemas for receipts API.""" from datetime import datetime, date from decimal import Decimal from typing import Optional, List from pydantic import BaseModel, Field, ConfigDict from app.db.models.receipt import ReceiptType, ReceiptDirection, ReceiptStatus from app.db.models.accounting_entry import EntryType # ============ Accounting Entry Schemas ============ class AccountingEntryBase(BaseModel): """Base schema for accounting entry.""" entry_type: EntryType account_code: str = Field(max_length=20) account_name: Optional[str] = Field(default=None, max_length=200) amount: Decimal partner_id: Optional[int] = None cost_center_id: Optional[int] = None class AccountingEntryCreate(AccountingEntryBase): """Schema for creating an accounting entry.""" pass class AccountingEntryUpdate(BaseModel): """Schema for updating an accounting entry.""" entry_type: Optional[EntryType] = None account_code: Optional[str] = Field(default=None, max_length=20) account_name: Optional[str] = Field(default=None, max_length=200) amount: Optional[Decimal] = None partner_id: Optional[int] = None cost_center_id: Optional[int] = None class AccountingEntryResponse(AccountingEntryBase): """Schema for accounting entry response.""" model_config = ConfigDict(from_attributes=True) id: int receipt_id: int is_auto_generated: bool modified_by: Optional[str] = None modified_at: Optional[datetime] = None sort_order: int # ============ Attachment Schemas ============ class AttachmentResponse(BaseModel): """Schema for attachment response.""" model_config = ConfigDict(from_attributes=True) id: int receipt_id: int filename: str stored_filename: str file_path: str file_size: int mime_type: str uploaded_at: datetime # ============ Receipt Schemas ============ class ReceiptBase(BaseModel): """Base schema for receipt.""" receipt_type: ReceiptType = ReceiptType.BON_FISCAL direction: ReceiptDirection = ReceiptDirection.CHELTUIALA receipt_number: Optional[str] = Field(default=None, max_length=50) receipt_series: Optional[str] = Field(default=None, max_length=20) receipt_date: date amount: Decimal = Field(gt=0) description: Optional[str] = Field(default=None, max_length=500) expense_type_code: Optional[str] = Field(default=None, max_length=20) company_id: int partner_id: Optional[int] = None partner_name: Optional[str] = Field(default=None, max_length=200) cash_register_id: Optional[int] = None cash_register_name: Optional[str] = Field(default=None, max_length=100) cash_register_account: Optional[str] = Field(default=None, max_length=20) class ReceiptCreate(ReceiptBase): """Schema for creating a receipt.""" pass class ReceiptUpdate(BaseModel): """Schema for updating a receipt (DRAFT only).""" receipt_type: Optional[ReceiptType] = None direction: Optional[ReceiptDirection] = None receipt_number: Optional[str] = Field(default=None, max_length=50) receipt_series: Optional[str] = Field(default=None, max_length=20) receipt_date: Optional[date] = None amount: Optional[Decimal] = Field(default=None, gt=0) description: Optional[str] = Field(default=None, max_length=500) expense_type_code: Optional[str] = Field(default=None, max_length=20) partner_id: Optional[int] = None partner_name: Optional[str] = Field(default=None, max_length=200) cash_register_id: Optional[int] = None cash_register_name: Optional[str] = Field(default=None, max_length=100) cash_register_account: Optional[str] = Field(default=None, max_length=20) class ReceiptResponse(ReceiptBase): """Schema for receipt response with all fields.""" model_config = ConfigDict(from_attributes=True) id: int status: ReceiptStatus created_by: str created_at: datetime updated_at: datetime submitted_at: Optional[datetime] = None reviewed_by: Optional[str] = None reviewed_at: Optional[datetime] = None rejection_reason: Optional[str] = None oracle_synced_at: Optional[datetime] = None oracle_act_id: Optional[int] = None oracle_error: Optional[str] = None # Relationships (optional, loaded when needed) attachments: List[AttachmentResponse] = [] entries: List[AccountingEntryResponse] = [] class ReceiptListResponse(BaseModel): """Schema for paginated receipt list response.""" items: List[ReceiptResponse] total: int page: int page_size: int pages: int class ReceiptFilter(BaseModel): """Schema for filtering receipts.""" status: Optional[ReceiptStatus] = None company_id: Optional[int] = None created_by: Optional[str] = None date_from: Optional[date] = None date_to: Optional[date] = None search: Optional[str] = None # Search in description, partner_name page: int = Field(default=1, ge=1) page_size: int = Field(default=20, ge=1, le=100) # ============ Workflow Schemas ============ class WorkflowAction(BaseModel): """Schema for workflow action response.""" success: bool message: str receipt: Optional[ReceiptResponse] = None class RejectRequest(BaseModel): """Schema for rejection request.""" reason: str = Field(min_length=5, max_length=500) class EntriesUpdateRequest(BaseModel): """Schema for bulk updating accounting entries.""" entries: List[AccountingEntryCreate] # ============ Nomenclature Schemas ============ class PartnerOption(BaseModel): """Schema for partner dropdown option.""" id: int name: str code: Optional[str] = None class AccountOption(BaseModel): """Schema for account dropdown option.""" code: str name: str class CashRegisterOption(BaseModel): """Schema for cash register dropdown option.""" id: int name: str account_code: str # 5311, 5121, etc. class ExpenseTypeOption(BaseModel): """Schema for expense type dropdown option.""" code: str name: str account_code: str has_vat: bool vat_percent: Decimal = Decimal("19")