137 lines
4.7 KiB
Python
137 lines
4.7 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
from typing import List, Optional, Dict, Any
|
|
|
|
from pydantic import BaseModel, EmailStr, Field
|
|
|
|
|
|
class ConfiguracionVU(BaseModel):
|
|
"""
|
|
Configuración de Ventanilla Única / VUCEM para generación de COVE.
|
|
|
|
Nota: estos campos se pueden poblar desde CustomsBrokerVU (web_service_user,
|
|
web_service_access_key, fiel_access_key, query_tax_id, etc.) o desde el
|
|
propio request de la API pública, según el flujo que se implemente.
|
|
"""
|
|
|
|
rfc_usuario_vu: str = Field(..., max_length=30)
|
|
# Clave encriptada/token del webservice; puede ser larga (base64)
|
|
clave_webservice: str = Field(..., max_length=512)
|
|
archivo_cer_base64: str
|
|
archivo_key_base64: str
|
|
clave_fiel: str = Field(..., max_length=100)
|
|
|
|
|
|
class PersonaCove(BaseModel):
|
|
tipo_identificador: str = Field(..., max_length=10)
|
|
identificacion: str = Field(..., max_length=30)
|
|
apellido_paterno: str = Field(default="", max_length=80)
|
|
apellido_materno: str = Field(default="", max_length=80)
|
|
nombre: str = Field(default="", max_length=80)
|
|
calle: str = Field(default="", max_length=120)
|
|
numero_exterior: str = Field(default="", max_length=20)
|
|
numero_interior: str = Field(default="", max_length=20)
|
|
colonia: str = Field(default="", max_length=120)
|
|
localidad: str = Field(default="", max_length=120)
|
|
municipio: str = Field(default="", max_length=120)
|
|
entidad_federativa: str = Field(default="", max_length=120)
|
|
pais: str = Field(..., max_length=3, description="País en formato ISO o catálogo VU")
|
|
codigo_postal: str = Field(default="", max_length=15)
|
|
|
|
|
|
class DescripcionEspecifica(BaseModel):
|
|
marca: str = Field(default="", max_length=80)
|
|
modelo: str = Field(default="", max_length=80)
|
|
submodelo: str = Field(default="", max_length=80)
|
|
numero_serie: str = Field(default="", max_length=80)
|
|
|
|
|
|
class MercanciaCove(BaseModel):
|
|
descripcion_generica: str = Field(..., max_length=500)
|
|
clave_unidad_medida: str = Field(..., max_length=10)
|
|
tipo_moneda: str = Field(..., max_length=5)
|
|
cantidad: Decimal = Field(..., gt=0)
|
|
valor_unitario: Decimal = Field(..., ge=0)
|
|
valor_total: Decimal = Field(..., ge=0)
|
|
valor_dolares: Decimal = Field(default=Decimal("0"), ge=0)
|
|
descripcion_especifica: List[DescripcionEspecifica] = Field(default_factory=list)
|
|
|
|
|
|
class FacturaCoveRequest(BaseModel):
|
|
"""
|
|
Payload completo para generación de COVE.
|
|
|
|
Este modelo replica el contrato del servicio externo de COVE que se
|
|
mostró en la documentación compartida por el usuario.
|
|
"""
|
|
|
|
configuracion_vu: ConfiguracionVU
|
|
rfc_consulta: str = Field(..., max_length=30)
|
|
tipo_figura: str = Field(..., max_length=10)
|
|
numero_factura: str = Field(..., max_length=50)
|
|
tipo_operacion: str = Field(..., max_length=10)
|
|
patente_aduanal: str = Field(..., max_length=10)
|
|
fecha_expedicion: datetime
|
|
observaciones: Optional[str] = Field(None, max_length=500)
|
|
correo_electronico: Optional[EmailStr] = None
|
|
tiene_subdivision: bool = False
|
|
certificado_origen: bool = False
|
|
numero_exportador_autorizado: Optional[str] = Field(None, max_length=50)
|
|
emisor: PersonaCove
|
|
destinatario: PersonaCove
|
|
mercancias: List[MercanciaCove] = Field(default_factory=list, min_length=1)
|
|
|
|
|
|
class FacturaCoveResponse(BaseModel):
|
|
"""
|
|
Respuesta base del endpoint público de generación de COVE.
|
|
Para el flujo asíncrono interno, solo usamos task_id/status/message.
|
|
"""
|
|
|
|
task_id: Optional[str] = None
|
|
status: str
|
|
message: Optional[str] = None
|
|
|
|
|
|
class GenerateCoveFromInvoiceRequest(BaseModel):
|
|
"""
|
|
Request minimalista desde la vista de facturas.
|
|
|
|
Solo necesita el company_id porque el invoice_id viene en la URL y el
|
|
tenant_id se resuelve desde el token.
|
|
"""
|
|
|
|
company_id: int
|
|
force_regen: Optional[bool] = False
|
|
recipient_email: Optional[EmailStr] = None
|
|
|
|
|
|
class GenerateCoveResult(BaseModel):
|
|
"""
|
|
Resultado estándar que produce la tarea Celery factura_cove_generate.
|
|
"""
|
|
|
|
status: str
|
|
message: Optional[str] = None
|
|
invoice_id: Optional[int] = None
|
|
cove_number: Optional[str] = None
|
|
vucem_operation_num: Optional[str] = None
|
|
# ID de tarea devuelto por el servicio externo de COVE (si aplica)
|
|
external_task_id: Optional[str] = None
|
|
# Respuesta cruda devuelta por el servicio externo (POST generar-factura-cove)
|
|
external_response: Optional[Dict[str, Any]] = None
|
|
errors: Optional[list[dict]] = None
|
|
|
|
|
|
class CoveEligibilityIssue(BaseModel):
|
|
field: str
|
|
message: str
|
|
|
|
|
|
class CoveEligibilityResponse(BaseModel):
|
|
can_generate: bool
|
|
reasons: list[CoveEligibilityIssue] = Field(default_factory=list)
|
|
|