Files
plantillas-proyectos/backend/api/v1/modules/a76/parts/dto.py

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