|
| 1 | +"""Modelos del complemento Comercio Exterior para CFDI 4.0.""" |
| 2 | + |
| 3 | +from decimal import Decimal |
| 4 | +from typing import Optional |
| 5 | + |
| 6 | +from pydantic import BaseModel, ConfigDict, Field |
| 7 | + |
| 8 | + |
| 9 | +# ===== Domicilios ===== |
| 10 | + |
| 11 | +class ComercioExteriorEmisorDomicilio(BaseModel): |
| 12 | + """Domicilio del emisor del complemento Comercio Exterior.""" |
| 13 | + calle: str = Field(default=..., alias="calle") |
| 14 | + numero_exterior: Optional[str] = Field(default=None, alias="numeroExterior") |
| 15 | + numero_interior: Optional[str] = Field(default=None, alias="numeroInterior") |
| 16 | + colonia_id: Optional[str] = Field(default=None, alias="coloniaId") |
| 17 | + localidad_id: Optional[str] = Field(default=None, alias="localidadId") |
| 18 | + referencia: Optional[str] = Field(default=None, alias="referencia") |
| 19 | + municipio_id: Optional[str] = Field(default=None, alias="municipioId") |
| 20 | + estado_id: str = Field(default=..., alias="estadoId") |
| 21 | + pais_id: str = Field(default=..., alias="paisId") |
| 22 | + codigo_postal_id: str = Field(default=..., alias="codigoPostalId") |
| 23 | + |
| 24 | + model_config = ConfigDict(populate_by_name=True) |
| 25 | + |
| 26 | + |
| 27 | +class ComercioExteriorReceptorDomicilio(BaseModel): |
| 28 | + """Domicilio del receptor del complemento Comercio Exterior.""" |
| 29 | + calle: str = Field(default=..., alias="calle") |
| 30 | + numero_exterior: Optional[str] = Field(default=None, alias="numeroExterior") |
| 31 | + numero_interior: Optional[str] = Field(default=None, alias="numeroInterior") |
| 32 | + colonia: Optional[str] = Field(default=None, alias="colonia") |
| 33 | + localidad: Optional[str] = Field(default=None, alias="localidad") |
| 34 | + referencia: Optional[str] = Field(default=None, alias="referencia") |
| 35 | + municipio: Optional[str] = Field(default=None, alias="municipio") |
| 36 | + estado: str = Field(default=..., alias="estado") |
| 37 | + pais_id: str = Field(default=..., alias="paisId") |
| 38 | + codigo_postal: str = Field(default=..., alias="codigoPostal") |
| 39 | + |
| 40 | + model_config = ConfigDict(populate_by_name=True) |
| 41 | + |
| 42 | + |
| 43 | +class ComercioExteriorDestinatarioDomicilio(BaseModel): |
| 44 | + """Domicilio de un destinatario del complemento Comercio Exterior.""" |
| 45 | + calle: str = Field(default=..., alias="calle") |
| 46 | + numero_exterior: Optional[str] = Field(default=None, alias="numeroExterior") |
| 47 | + numero_interior: Optional[str] = Field(default=None, alias="numeroInterior") |
| 48 | + colonia: Optional[str] = Field(default=None, alias="colonia") |
| 49 | + localidad: Optional[str] = Field(default=None, alias="localidad") |
| 50 | + referencia: Optional[str] = Field(default=None, alias="referencia") |
| 51 | + municipio: Optional[str] = Field(default=None, alias="municipio") |
| 52 | + estado: str = Field(default=..., alias="estado") |
| 53 | + pais_id: str = Field(default=..., alias="paisId") |
| 54 | + codigo_postal: str = Field(default=..., alias="codigoPostal") |
| 55 | + |
| 56 | + model_config = ConfigDict(populate_by_name=True) |
| 57 | + |
| 58 | + |
| 59 | +# ===== Emisor ===== |
| 60 | + |
| 61 | +class ComercioExteriorEmisor(BaseModel): |
| 62 | + """Emisor del complemento Comercio Exterior.""" |
| 63 | + curp: Optional[str] = Field(default=None, alias="curp") |
| 64 | + domicilio: ComercioExteriorEmisorDomicilio = Field(default=..., alias="domicilio") |
| 65 | + |
| 66 | + model_config = ConfigDict(populate_by_name=True) |
| 67 | + |
| 68 | + |
| 69 | +# ===== Propietario ===== |
| 70 | + |
| 71 | +class ComercioExteriorPropietario(BaseModel): |
| 72 | + """Propietario de las mercancías exportadas.""" |
| 73 | + num_reg_id_trib: str = Field(default=..., alias="numRegIdTrib") |
| 74 | + residencia_fiscal_id: str = Field(default=..., alias="residenciaFiscalId") |
| 75 | + |
| 76 | + model_config = ConfigDict(populate_by_name=True) |
| 77 | + |
| 78 | + |
| 79 | +# ===== Receptor ===== |
| 80 | + |
| 81 | +class ComercioExteriorReceptor(BaseModel): |
| 82 | + """Receptor del complemento Comercio Exterior.""" |
| 83 | + num_reg_id_trib: Optional[str] = Field(default=None, alias="numRegIdTrib") |
| 84 | + domicilio: Optional[ComercioExteriorReceptorDomicilio] = Field(default=None, alias="domicilio") |
| 85 | + |
| 86 | + model_config = ConfigDict(populate_by_name=True) |
| 87 | + |
| 88 | + |
| 89 | +# ===== Destinatario ===== |
| 90 | + |
| 91 | +class ComercioExteriorDestinatario(BaseModel): |
| 92 | + """Destinatario de las mercancías exportadas.""" |
| 93 | + num_reg_id_trib: Optional[str] = Field(default=None, alias="numRegIdTrib") |
| 94 | + nombre: Optional[str] = Field(default=None, alias="nombre") |
| 95 | + domicilios: list[ComercioExteriorDestinatarioDomicilio] = Field(default_factory=list, alias="domicilios") |
| 96 | + |
| 97 | + model_config = ConfigDict(populate_by_name=True) |
| 98 | + |
| 99 | + |
| 100 | +# ===== Mercancías ===== |
| 101 | + |
| 102 | +class ComercioExteriorMercanciaDescripcionEspecifica(BaseModel): |
| 103 | + """Descripción específica de una mercancía del complemento Comercio Exterior.""" |
| 104 | + marca: str = Field(default=..., alias="marca") |
| 105 | + modelo: Optional[str] = Field(default=None, alias="modelo") |
| 106 | + sub_modelo: Optional[str] = Field(default=None, alias="subModelo") |
| 107 | + numero_serie: Optional[str] = Field(default=None, alias="numeroSerie") |
| 108 | + |
| 109 | + model_config = ConfigDict(populate_by_name=True) |
| 110 | + |
| 111 | + |
| 112 | +class ComercioExteriorMercancia(BaseModel): |
| 113 | + """Mercancía del complemento Comercio Exterior.""" |
| 114 | + no_identificacion: str = Field(default=..., alias="noIdentificacion") |
| 115 | + fraccion_arancelaria_id: Optional[str] = Field(default=None, alias="fraccionArancelariaId") |
| 116 | + cantidad_aduana: Optional[Decimal] = Field(default=None, alias="cantidadAduana") |
| 117 | + unidad_aduana_id: Optional[str] = Field(default=None, alias="unidadAduanaId") |
| 118 | + valor_unitario_aduana: Optional[Decimal] = Field(default=None, alias="valorUnitarioAduana") |
| 119 | + valor_dolares: Decimal = Field(default=..., alias="valorDolares") |
| 120 | + descripciones_especificas: Optional[list[ComercioExteriorMercanciaDescripcionEspecifica]] = Field( |
| 121 | + default=None, alias="descripcionesEspecificas" |
| 122 | + ) |
| 123 | + |
| 124 | + model_config = ConfigDict(populate_by_name=True, json_encoders={Decimal: str}) |
| 125 | + |
| 126 | + |
| 127 | +# ===== Comercio Exterior ===== |
| 128 | + |
| 129 | +class ComercioExteriorComplement(BaseModel): |
| 130 | + """Complemento Comercio Exterior para exportación de mercancías en CFDI 4.0.""" |
| 131 | + motivo_traslado_id: Optional[str] = Field(default=None, alias="motivoTrasladoId") |
| 132 | + clave_de_pedimento_id: str = Field(default=..., alias="claveDePedimentoId") |
| 133 | + certificado_origen: int = Field(default=..., alias="certificadoOrigen") |
| 134 | + num_certificado_origen: Optional[str] = Field(default=None, alias="numCertificadoOrigen") |
| 135 | + numero_exportador_confiable: Optional[str] = Field(default=None, alias="numeroExportadorConfiable") |
| 136 | + incoterm_id: Optional[str] = Field(default=None, alias="incotermId") |
| 137 | + observaciones: Optional[str] = Field(default=None, alias="observaciones") |
| 138 | + tipo_cambio_usd: Decimal = Field(default=..., alias="tipoCambioUSD") |
| 139 | + emisor: Optional[ComercioExteriorEmisor] = Field(default=None, alias="emisor") |
| 140 | + receptor: Optional[ComercioExteriorReceptor] = Field(default=None, alias="receptor") |
| 141 | + propietarios: Optional[list[ComercioExteriorPropietario]] = Field(default=None, alias="propietarios") |
| 142 | + destinatarios: Optional[list[ComercioExteriorDestinatario]] = Field(default=None, alias="destinatarios") |
| 143 | + mercancias: list[ComercioExteriorMercancia] = Field(default_factory=list, alias="mercancias") |
| 144 | + |
| 145 | + model_config = ConfigDict(populate_by_name=True, json_encoders={Decimal: str}) |
0 commit comments