"""Esquemas del catálogo de conceptos de facturación.""" from datetime import datetime from decimal import Decimal from pydantic import BaseModel, ConfigDict, Field from ..catalogs.dto import ProductServiceResponse, TaxObjectResponse, UnitOfMeasureResponse class ConceptBase(BaseModel): code: str = Field(..., min_length=1, max_length=40, description="Clave interna del concepto") description: str = Field(..., min_length=1, max_length=500) product_service_id: int = Field(..., description="Clave ProdServ del SAT (1:1 por empresa)") unit_of_measure_id: int | None = None tax_object_id: int | None = None unit_price: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2) currency: str = Field("MXN", min_length=3, max_length=3) is_active: bool = True notes: str | None = None class ConceptCreate(ConceptBase): pass class ConceptUpdate(BaseModel): """Actualización parcial: solo se tocan los campos enviados.""" code: str | None = Field(None, min_length=1, max_length=40) description: str | None = Field(None, min_length=1, max_length=500) product_service_id: int | None = None unit_of_measure_id: int | None = None tax_object_id: int | None = None unit_price: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2) currency: str | None = Field(None, min_length=3, max_length=3) is_active: bool | None = None notes: str | None = None class ConceptResponse(ConceptBase): """Incluye los objetos del catálogo del SAT ya resueltos, para evitar N+1 en la UI.""" model_config = ConfigDict(from_attributes=True) id: int tenant_id: int company_id: int product_service: ProductServiceResponse | None = None unit_of_measure: UnitOfMeasureResponse | None = None tax_object: TaxObjectResponse | None = None created_by: str | None = None updated_by: str | None = None created_at: datetime updated_at: datetime