from typing import Literal, Optional, List from datetime import datetime, date from decimal import Decimal from pydantic import BaseModel, Field from .models import ( DestinationOriginCove, OperationType, Currency, TransportType, WeightUnit, ) # --- Base Schemas --- class InvoiceHeaderBase(BaseModel): """Base fields for Invoice Header""" system: Optional[str] = Field(None, max_length=12, description="System of origin") operation_type: Optional[OperationType] = Field( ..., description="Operation type: imp/exp/sm/ctm" ) invoice_type: Optional[str] = Field( None, max_length=5, description="Invoice type key" ) document_type: str = Field( ..., max_length=3, description="Document type (Regimen Aduanero)" ) invoice_number: Optional[str] = Field( None, max_length=100, description="Invoice number" ) project_number: Optional[str] = Field( None, max_length=14, description="Project number" ) purchase_order: Optional[str] = Field( None, max_length=50, description="Purchase order" ) related_doc_id: Optional[int] = Field( None, description="Related document ID for rectifications" ) alternate_invoice: Optional[str] = Field( None, max_length=99, description="Alternate invoice" ) invoice_ref: Optional[str] = Field( None, max_length=19, description="Invoice reference" ) proforma_number: Optional[str] = Field( None, max_length=20, description="Proforma number" ) invoice_date: date = Field(..., description="Invoice date") emission_date: Optional[date] = Field(None, description="Emission date") is_updated: bool = Field(False, description="Status") updated_date: Optional[datetime] = Field(None, description="Update date") who_updated: Optional[str] = Field(None, max_length=20, description="Who updated") capture_user: Optional[str] = Field(None, max_length=20, description="Capture user") traffic_light_status: Optional[str] = Field( None, max_length=50, description="Traffic light status" ) process_log: Optional[str] = Field( None, max_length=300, description="Processing log" ) is_updated_rec: Optional[int] = Field(None, description="Reception status") is_updated_rep: Optional[str] = Field( None, max_length=2, description="Report status" ) observation_es: Optional[str] = Field(None, description="Observations in Spanish") observation_en: Optional[str] = Field(None, description="Observations in English") comments_status: Optional[str] = Field(None, description="Comments status") vu_observations: Optional[str] = Field( None, max_length=500, description="VUCEM observations" ) cfdi_uuid: Optional[str] = Field(None, max_length=100, description="CFDI UUID") path_pdf: Optional[str] = Field( None, max_length=500, description="Path to PDF file" ) path_xml: Optional[str] = Field( None, max_length=500, description="Path to XML file" ) subcompany: Optional[str] = Field(None, max_length=5, description="Subcompany") party_count: Optional[int] = Field(None, description="Quantity of parties") generate_id: Optional[bool] = Field(False, description="Generate ID") generate_desc_parties: Optional[str] = Field( None, max_length=12, description="Generate description of parties" ) apply_manual_discount: Optional[bool] = Field( False, description="Apply manual discount" ) is_bulk: Optional[bool] = Field(None, description="Is bulk") download_substance: Optional[bool] = Field(None, description="Download substance") download_class: Optional[bool] = Field(None, description="Download class") download_def: Optional[bool] = Field(None, description="Definitive download") payment_terms: Optional[str] = Field( None, max_length=200, description="Payment terms" ) handling_fees: Optional[Decimal] = Field(None, description="Handling fees") option_iv18: Optional[str] = Field(None, max_length=50, description="Option IV18") enajenation_goods: Optional[bool] = Field(None, description="Enajenation of goods") class InvoiceComplianceMxBase(BaseModel): """Base fields for Compliance MX""" pedimento_id: Optional[int] = Field(None, description="Pedimento id") pedimento_r1: Optional[int] = Field(None, description="Pedimento id (R1)") pedimento_k1: Optional[int] = Field(None, description="Pedimento id (K1)") remesa: Optional[int] = Field(None, description="Remesa") aduana: Optional[str] = Field(None, max_length=5, description="Customs office") port_of_entry: Optional[str] = Field( None, max_length=6, description="Port of entry" ) destination: Optional[str] = Field( None, max_length=3, description="Destination code" ) manifest_number: Optional[str] = Field( None, max_length=15, description="Manifest number" ) provider_header: str = Field(None, max_length=20, description="Provider header") provider_id: int = Field(None, description="Provider ID") sold_to_header: str = Field(None, max_length=20, description="Sold to header") sold_to_id: int = Field(None, description="Sold to ID") shipped_to_header: str = Field(None, max_length=20, description="Shipped to header") shipped_to_id: int = Field(None, description="Shipped to ID") shipped_by_header: Optional[int] = Field( None, max_length=20, description="Shipped by header" ) shipped_by_id: Optional[int] = Field(None, description="Shipped by ID") customs_broker_id: int = Field(None, description="Customs broker ID") customs_broker_us_id: Optional[int] = Field( None, description="US customs broker ID" ) broker_invoice_num: Optional[str] = Field( None, max_length=20, description="Broker invoice number" ) broker_invoice_date: Optional[date] = Field(None, description="Broker invoice date") is_mixed: Optional[bool] = Field(False, description="Is mixed operation") waste_type: Optional[str] = Field(None, max_length=1, description="Waste type") scrap_type: Optional[str] = Field(None, max_length=1, description="Scrap type") appendix_17: Optional[int] = Field(None, description="Appendix 17") is_regime_change: Optional[bool] = Field(False, description="Is regime change") which_exchange_rate: Optional[str] = Field( None, max_length=5, description="Which exchange rate" ) value_method: Optional[str] = Field(None, max_length=2, description="Value method") act_value: Optional[str] = Field(None, max_length=5, description="Act value") is_pedimento_pending: bool = Field(..., description="Is pedimento pending") is_owner_of_goods: Optional[bool] = Field(False, description="Is owner of goods") generate_balances: Optional[bool] = Field(False, description="Generate balances") was_reviewed_by_company: Optional[bool] = Field( None, description="Was reviewed by company" ) edocument: Optional[str] = Field(None, max_length=50, description="E-document") electronic_signature: Optional[str] = Field( None, max_length=999, description="Electronic signature" ) certificate_number: Optional[str] = Field( None, max_length=99, description="Certificate number" ) niu_number: Optional[str] = Field(None, max_length=19, description="NIU number") bill_of_lading_count: Optional[str] = Field( None, max_length=12, description="Bill of lading count" ) addendum_vu: Optional[str] = Field( None, max_length=204, description="VUCEM addendum" ) origin_destination_cove: Optional[DestinationOriginCove] = Field( "franja_front_norte", max_length=20, description="Origin/Destination COVE" ) vucem_operation_num: Optional[str] = Field( None, max_length=19, description="VUCEM operation number" ) customs_person_line: Optional[int] = Field(None, description="Customs person line") contingency_mode: Optional[bool] = Field(None, description="Contingency mode") enclosure: Optional[str] = Field(None, max_length=4, description="Enclosure") guide_type_to_identify: Optional[str] = Field( None, max_length=1, description="Guide type to identify" ) location: Optional[str] = Field(None, max_length=200, description="Location") dot_code: Optional[str] = Field(None, max_length=20, description="DOT code") subdivision: Optional[str] = Field(None, max_length=20, description="Subdivision") acts_as: Optional[str] = Field(None, max_length=20, description="Acts as") movement_type: Optional[str] = Field( None, max_length=31, description="Movement type" ) office_document: Optional[str] = Field( None, max_length=30, description="Office document" ) reason_export: Optional[str] = Field( None, max_length=1, description="Reason for export" ) signature_key: Optional[str] = Field( None, max_length=10, description="Signature key" ) sem_id: Optional[int] = Field(None, description="SEM ID") class InvoiceFinancialsBase(BaseModel): """Base fields for Financials""" currency: Currency = Field(None, max_length=7, description="Currency code") currency_type: Optional[str] = Field("USD", description="Currency type") exchange_rate: Decimal = Field(0.00, description="Exchange rate") exchange_rate_mm: Optional[Decimal] = Field( None, description="Exchange rate currency to currency" ) value_mn: Optional[Decimal] = Field(None, description="Value in MXN") value_me: Optional[Decimal] = Field(None, description="Value in foreign currency") value_mc: Optional[Decimal] = Field(None, description="Value in third currency") customs_value_mn: Optional[Decimal] = Field( None, description="Customs value in MXN" ) customs_value_me: Optional[Decimal] = Field( None, description="Customs value in foreign currency" ) raw_material_value_mn: Optional[Decimal] = Field( None, description="Raw material value in MXN" ) raw_material_value_me: Optional[Decimal] = Field( None, description="Raw material value in foreign currency" ) aggregate_value_mn: Optional[Decimal] = Field( None, description="Aggregate value in MXN" ) aggregate_value_me: Optional[Decimal] = Field( None, description="Aggregate value in foreign currency" ) aggregate_value_mc: Optional[Decimal] = Field( None, description="Aggregate value in third currency" ) mexican_value_mn: Optional[Decimal] = Field( None, description="Mexican merchandise value in MXN" ) mexican_value_me: Optional[Decimal] = Field( None, description="Mexican merchandise value in foreign currency" ) mexican_value_mc: Optional[Decimal] = Field( None, description="Mexican merchandise value in third currency" ) national_packaging_mn: Optional[Decimal] = Field( None, description="National packaging in MXN" ) national_packaging_me: Optional[Decimal] = Field( None, description="National packaging in foreign currency" ) national_packaging_mc: Optional[Decimal] = Field( None, description="National packaging in third currency" ) freight: Optional[Decimal] = Field(None, description="Freight cost") insurance: Optional[Decimal] = Field(None, description="Insurance cost") insurance_value: Optional[Decimal] = Field(None, description="Insurance value") packaging: Optional[Decimal] = Field(None, description="Packaging") other_increments: Optional[Decimal] = Field(None, description="Other increments") total_increments_mn: Optional[Decimal] = Field( None, description="Total increments in MXN" ) total_increments_me: Optional[Decimal] = Field( None, description="Total increments in foreign currency" ) iva_mn: Optional[Decimal] = Field(None, description="IVA in MXN") iva_me: Optional[Decimal] = Field(None, description="IVA in foreign currency") iva_mc: Optional[Decimal] = Field(None, description="IVA in third currency") iva_factor: Optional[Decimal] = Field(None, description="IVA factor") tax_value_me: Optional[Decimal] = Field( None, description="Tax value in foreign currency" ) seal_value_2500: Optional[bool] = Field(None, description="Seal value 2500") total_quantity: Optional[Decimal] = Field(None, description="Total quantity") gross_weight: Optional[Decimal] = Field(None, description="Gross weight") net_weight: Optional[Decimal] = Field(None, description="Net weight") bundle_count: Optional[int] = Field(None, description="Bundle count") weight_factor: Optional[Decimal] = Field(None, description="Weight factor") class InvoiceLogisticsBase(BaseModel): """Base fields for Logistics""" carrier_id: Optional[str] = Field(None, max_length=10, description="Carrier ID") transport_id: Optional[str] = Field(None, max_length=10, description="Transport ID") transport_us_id: Optional[str] = Field( None, max_length=10, description="US transport ID" ) transport_type: TransportType = Field( "none", max_length=15, description="Transport type" ) transport_num: Optional[str] = Field( None, max_length=20, description="Transport number" ) transport_mode: Optional[str] = Field( 30, max_length=15, description="Transport mode" ) driver_name: Optional[str] = Field(None, max_length=80, description="Driver name") is_rail: Optional[bool] = Field(False, description="Is rail transport") rail_id: Optional[str] = Field(None, max_length=31, description="Rail ID") vehicle_num: Optional[str] = Field( None, max_length=20, description="Vehicle number" ) license_plate: Optional[str] = Field( None, max_length=20, description="License plate" ) license_plate_complete: Optional[str] = Field( None, max_length=40, description="Complete license plate" ) trailer_num: Optional[str] = Field( None, max_length=20, description="Trailer number" ) seal_number: Optional[str] = Field(None, max_length=15, description="Seal number") guide_number: Optional[str] = Field(None, max_length=20, description="Guide number") bill_number: Optional[str] = Field(None, max_length=15, description="Bill number") reference_number: Optional[str] = Field( None, max_length=14, description="Reference number" ) shipment_number: Optional[str] = Field( None, max_length=19, description="Shipment number" ) incoterm: Optional[str] = Field(None, max_length=5, description="Incoterm") identifier_1: Optional[str] = Field(None, max_length=2, description="Identifier 1") complement_1: Optional[str] = Field(None, max_length=30, description="Complement 1") identifier_2: Optional[str] = Field(None, max_length=2, description="Identifier 2") complement_2: Optional[str] = Field(None, max_length=30, description="Complement 2") weight_type: WeightUnit = Field( default="kgs", max_length=3, description="Weight type" ) container_types: Optional[str] = Field( None, max_length=500, description="Container types" ) vehicle_data: Optional[str] = Field( None, max_length=500, description="Vehicle data" ) origin_location: Optional[str] = Field( None, max_length=200, description="Origin location" ) destination_location: Optional[str] = Field( None, max_length=200, description="Destination location" ) transport_itinerary: Optional[str] = Field( None, max_length=1000, description="Transport itinerary" ) destination_goods: Optional[str] = Field( None, max_length=50, description="Destination of goods" ) entry_exit_date: Optional[date] = Field(None, description="Entry/Exit date") delivery_date: Optional[date] = Field(None, description="Delivery date") delivered_status: Optional[bool] = Field(False, description="Delivered status") received_by: Optional[str] = Field(None, max_length=50, description="Received by") payment_date: Optional[date] = Field(None, description="Payment date") payment_receipt_num: Optional[str] = Field( None, max_length=20, description="Payment receipt number" ) is_ctm_process: Optional[bool] = Field(False, description="Is CTM process") # Continuation Tab Fields equipment_reviewed: Optional[bool] = Field(False, description="Equipment reviewed") is_subdivision: Optional[bool] = Field(False, description="Is subdivision") acts_as_cd: Optional[bool] = Field(False, description="Acts as CD") pedimento_arrived: Optional[bool] = Field(False, description="Pedimento arrived") green_light_mx: Optional[bool] = Field(False, description="Green light Mexico") green_light_us: Optional[bool] = Field(False, description="Green light USA") red_light_mx: Optional[bool] = Field(False, description="Red light Mexico") red_light_us: Optional[bool] = Field(False, description="Red light USA") class InvoiceSalesDetailsBase(BaseModel): """Base fields for Sales Details""" line_number: int = Field(..., description="Line number") sales_order: Optional[str] = Field(None, max_length=20, description="Sales order") colors_description: Optional[str] = Field( None, max_length=49, description="Colors description" ) square_color_code: Optional[str] = Field( None, max_length=1, description="Square color code" ) line_bundles: Optional[int] = Field(None, description="Line bundles count") class InvoiceCollectionsBase(BaseModel): """Base fields for Collections""" line_number: int = Field(..., description="Line number") invoice_number: Optional[str] = Field( None, max_length=15, description="Invoice number" ) concept: Optional[str] = Field(None, max_length=100, description="Concept") # --- Create Schemas --- class InvoiceComplianceMxCreate(InvoiceComplianceMxBase): """Schema for creating Compliance MX""" pass class InvoiceFinancialsCreate(InvoiceFinancialsBase): """Schema for creating Financials""" pass class InvoiceLogisticsCreate(InvoiceLogisticsBase): """Schema for creating Logistics""" pass class InvoiceSalesDetailsCreate(InvoiceSalesDetailsBase): """Schema for creating Sales Details""" pass class InvoiceCollectionsCreate(InvoiceCollectionsBase): """Schema for creating Collections""" pass class InvoiceHeaderCreate(InvoiceHeaderBase): """Schema for creating Invoice Header with nested relations""" compliance_mx: Optional[InvoiceComplianceMxCreate] = None financials: Optional[InvoiceFinancialsCreate] = None logistics: Optional[InvoiceLogisticsCreate] = None details: Optional[List[InvoiceSalesDetailsCreate]] = None collections: Optional[List[InvoiceCollectionsCreate]] = None # --- Update Schemas --- class InvoiceComplianceMxUpdate(InvoiceComplianceMxBase): """Schema for updating Compliance MX""" pass class InvoiceFinancialsUpdate(InvoiceFinancialsBase): """Schema for updating Financials""" pass class InvoiceLogisticsUpdate(InvoiceLogisticsBase): """Schema for updating Logistics""" pass class InvoiceSalesDetailsUpdate(InvoiceSalesDetailsBase): """Schema for updating Sales Details""" line_number: Optional[int] = None class InvoiceCollectionsUpdate(InvoiceCollectionsBase): """Schema for updating Collections""" line_number: Optional[int] = None class InvoiceHeaderUpdate(InvoiceHeaderBase): """Schema for updating Invoice Header with nested relations""" id: int compliance_mx: Optional[InvoiceComplianceMxUpdate] = None financials: Optional[InvoiceFinancialsUpdate] = None logistics: Optional[InvoiceLogisticsUpdate] = None details: Optional[List[InvoiceSalesDetailsUpdate]] = None collections: Optional[List[InvoiceCollectionsUpdate]] = None # --- Response Schemas --- class PedimentoBasicInfo(BaseModel): """Basic Pedimento information for Invoice response""" pedimento_number: Optional[str] = None pedimento_code: Optional[str] = None customs_office: Optional[str] = None license: Optional[str] = None year: Optional[str] = None class Config: from_attributes = True class InvoiceComplianceMxResponse(InvoiceComplianceMxBase): """Schema for Compliance MX response""" invoice_id: int pedimento: Optional[PedimentoBasicInfo] = None class Config: from_attributes = True class InvoiceFinancialsResponse(InvoiceFinancialsBase): """Schema for Financials response""" id: int invoice_id: int class Config: from_attributes = True class InvoiceLogisticsResponse(InvoiceLogisticsBase): """Schema for Logistics response""" id: int invoice_id: int class Config: from_attributes = True class InvoiceSalesDetailsResponse(InvoiceSalesDetailsBase): """Schema for Sales Details response""" id: int invoice_id: int class Config: from_attributes = True class InvoiceCollectionsResponse(InvoiceCollectionsBase): """Schema for Collections response""" id: int invoice_id: int class Config: from_attributes = True class InvoiceHeaderResponse(InvoiceHeaderBase): """Schema for Invoice Header response with nested relations""" id: int capture_date: datetime compliance_mx: Optional[InvoiceComplianceMxResponse] = None financials: Optional[InvoiceFinancialsResponse] = None logistics: Optional[InvoiceLogisticsResponse] = None details: Optional[List[InvoiceSalesDetailsResponse]] = [] collections: Optional[List[InvoiceCollectionsResponse]] = [] class Config: from_attributes = True