222 lines
7.6 KiB
Python
222 lines
7.6 KiB
Python
from datetime import datetime
|
|
from decimal import Decimal
|
|
from typing import List, Optional, Literal
|
|
from pydantic import BaseModel, Field, ConfigDict
|
|
from api.v1.modules.a24.inv.inv_aphis.dto import InvPartAphisGeneralDTO
|
|
|
|
# --- SUB-DTO: DATOS ADUANALES (FaData) ---
|
|
class FaDataDTO(BaseModel):
|
|
origin_country: Optional[str] = None
|
|
sector: Optional[str] = None
|
|
fraction_type: Optional[str] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
# --- SUB-DTO: RELACIONES CON PAÍSES ---
|
|
class PartCountryDataDTO(BaseModel):
|
|
country_code: Optional[str] = None
|
|
fraction: Optional[str] = None
|
|
preference: Optional[str] = "GENERAL"
|
|
has_certificate: Optional[bool] = False
|
|
certificate_number: Optional[str] = None
|
|
end_date: Optional[datetime] = None
|
|
previous_fractions_7m: Optional[bool] = False
|
|
omission_import: Optional[bool] = False
|
|
omission_export: Optional[bool] = False
|
|
import_percentage: Optional[Decimal] = None
|
|
export_percentage: Optional[Decimal] = None
|
|
sector: Optional[str] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
# --- SUB-DTO: COMPONENTES BOM ---
|
|
class InvBomItemDTO(BaseModel):
|
|
id: Optional[int] = None
|
|
component_part_id: Optional[int] = Field(None, gt=0, description="ID de la parte componente (debe ser > 0)")
|
|
component_part_number: Optional[str] = None
|
|
quantity: Optional[Decimal] = Field(Decimal('1.0'), gt=0, description="Cantidad debe ser > 0")
|
|
uom_code: Optional[str] = Field(None, max_length=5, description="Código de unidad de medida")
|
|
procedure_type: Optional[str] = None
|
|
is_percentage: Optional[bool] = True
|
|
raw_material: Optional[Decimal] = None
|
|
waste: Optional[Decimal] = None
|
|
merma: Optional[Decimal] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
# --- SUB-DTO: DATOS DE INVENTARIO Y COSTEO (InvData) ---
|
|
class InvDataDTO(BaseModel):
|
|
part_type: Optional[str] = None
|
|
material_type: Optional[str] = None
|
|
reference_number: Optional[str] = None
|
|
flex_reference_number: Optional[str] = None
|
|
equivalent_uom: Optional[str] = None
|
|
conversion_factor: Optional[Decimal] = None
|
|
stock_uom: Optional[str] = None
|
|
alternate_uom: Optional[str] = None
|
|
conversion_uom: Optional[str] = None
|
|
added_value: Optional[Decimal] = None
|
|
added_value_type: Optional[str] = None
|
|
assigned_client: Optional[str] = None
|
|
supplier_code: Optional[str] = None
|
|
is_textile: Optional[str] = None
|
|
bom_version: Optional[int] = None
|
|
is_repair: Optional[str] = None
|
|
is_hazardous: Optional[str] = None
|
|
emergency_number: Optional[str] = None
|
|
danger_class: Optional[str] = None
|
|
packaging_group: Optional[str] = None
|
|
width: Optional[str] = None
|
|
thickness: Optional[str] = None
|
|
specification: Optional[str] = None
|
|
|
|
# Desglose de Costos (Anexo 24 - Valor Agregado)
|
|
total_value: Optional[Decimal] = None
|
|
direct_labor: Optional[Decimal] = None
|
|
general_expenses: Optional[Decimal] = None
|
|
total_expenses: Optional[Decimal] = None
|
|
depreciation: Optional[Decimal] = None
|
|
tooling: Optional[Decimal] = None
|
|
material_consumed: Optional[Decimal] = None
|
|
profit: Optional[Decimal] = None
|
|
|
|
# Fracciones adicionales y TLCAN/T-MEC
|
|
us_fraction_alt: Optional[str] = None
|
|
ca_fraction: Optional[str] = None
|
|
ad_valorem_us: Optional[Decimal] = None
|
|
nafta_result: Optional[str] = None
|
|
nafta_percentage: Optional[Decimal] = None
|
|
dta: Optional[str] = None
|
|
dtb: Optional[str] = None
|
|
dtg: Optional[str] = None
|
|
|
|
# --- CAMPOS ADICIONALES FRONTEND ---
|
|
substitute_part: Optional[str] = None
|
|
complementary_part: Optional[str] = None
|
|
preference_part: Optional[str] = None
|
|
use_alternate_quantity: Optional[bool] = False
|
|
un_number: Optional[str] = None
|
|
shipping_name: Optional[str] = None
|
|
hazard_notes: Optional[str] = None
|
|
repair_unit_cost: Optional[Decimal] = None
|
|
repair_added_value: Optional[Decimal] = None
|
|
fraction_9801: Optional[str] = None
|
|
immex_type: Optional[str] = None
|
|
disable_movements: Optional[bool] = False
|
|
pga_program_code: Optional[str] = None
|
|
usmca_fraction: Optional[str] = None
|
|
scrap_part_number: Optional[str] = None
|
|
waste_part_number: Optional[str] = None
|
|
scrap_description_en: Optional[str] = None
|
|
scrap_description_es: Optional[str] = None
|
|
scrap_export_fraction: Optional[str] = None
|
|
scrap_us_fraction: Optional[str] = None
|
|
equivalent_uom_2: Optional[str] = None
|
|
conversion_factor_2: Optional[Decimal] = None
|
|
has_auxiliary: Optional[bool] = False
|
|
auxiliary_uom: Optional[str] = None
|
|
auxiliary_conversion: Optional[Decimal] = None
|
|
auxiliary_unit_cost: Optional[Decimal] = None
|
|
mex_packing: Optional[Decimal] = None
|
|
sales_order: Optional[str] = None
|
|
use_rule_8: Optional[bool] = False
|
|
sector: Optional[str] = None
|
|
origin_country: Optional[str] = None
|
|
fraction_type: Optional[str] = None
|
|
|
|
# Extensiones
|
|
agency_code_definition: Optional[str] = None
|
|
carta_porte: Optional[str] = None
|
|
client_part_names: Optional[List[dict]] = None
|
|
part_identifiers: Optional[List[dict]] = None
|
|
substitute_parts: Optional[List[dict]] = None
|
|
aphis_data: Optional[dict] = None
|
|
aphis_records: Optional[List[InvPartAphisGeneralDTO]] = None
|
|
|
|
non_discharge_clients: Optional[List[dict]] = None
|
|
|
|
# Lista de materiales (BOM)
|
|
bom_items: Optional[List[InvBomItemDTO]] = None
|
|
|
|
# Lista de países de origen
|
|
countries: Optional[List[PartCountryDataDTO]] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class PartBase(BaseModel):
|
|
client_id: Optional[int] = None
|
|
part_number: str = Field(..., max_length=70)
|
|
commercial_part_number: Optional[str] = None
|
|
|
|
description_spanish: Optional[str] = None
|
|
description_english: Optional[str] = None
|
|
part_class: Optional[str] = None
|
|
unit_of_measure: Optional[str] = "PZ"
|
|
|
|
unit_cost: Optional[Decimal] = Field(default=None, ge=0)
|
|
currency_key: Optional[str] = None
|
|
currency_type: Optional[str] = None
|
|
|
|
unit_weight: Optional[Decimal] = Field(default=None, ge=0)
|
|
weight_type: Optional[str] = None
|
|
|
|
fraction: Optional[str] = None
|
|
us_fraction: Optional[str] = None
|
|
|
|
# Regulatorios
|
|
fda_key: Optional[str] = None
|
|
fcc_key: Optional[str] = None
|
|
license_code: Optional[str] = None
|
|
eccn: Optional[str] = None
|
|
export_code: Optional[str] = None
|
|
exclusion_symbol: Optional[str] = None
|
|
|
|
is_active: bool = True
|
|
part_photo: Optional[str] = None
|
|
|
|
# Anidados
|
|
fa_data: Optional[FaDataDTO] = None
|
|
inv_data: Optional[InvDataDTO] = None
|
|
|
|
# --- CREACIÓN ---
|
|
class PartCreateDTO(PartBase):
|
|
# Opcional para que lo tome de la URL si no viene en el body
|
|
company_id: Optional[int] = None
|
|
|
|
# --- ACTUALIZACIÓN ---
|
|
class PartUpdateDTO(PartBase):
|
|
client_id: Optional[int] = None
|
|
part_number: Optional[str] = None
|
|
# Todo opcional para PATCH
|
|
pass
|
|
|
|
# --- RESPUESTA ---
|
|
class PartResponseDTO(PartBase):
|
|
id: int
|
|
tenant_id: int
|
|
company_id: int
|
|
creation_date: Optional[int] = None
|
|
modification_date_iso: Optional[datetime] = None
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
# --- BÁSICO (Para listados ligeros) ---
|
|
class PartBasicDTO(BaseModel):
|
|
id: int
|
|
part_number: str
|
|
description_spanish: Optional[str] = None
|
|
fraction: Optional[str] = None
|
|
is_active: bool
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
# --- LISTADO PAGINADO ---
|
|
class PartListResponseDTO(BaseModel):
|
|
items: List[PartResponseDTO]
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
pages: int
|
|
|