""" Modelo ORM para la lista de materiales (BOM) de una parte - Anexo 24 """ from typing import TYPE_CHECKING, Optional from decimal import Decimal from api.v1.common.base_models import TenantScopedMixin, TimestampMixin from core.database import Base from sqlalchemy import ( Integer, Numeric, String, PrimaryKeyConstraint, ForeignKeyConstraint ) from sqlalchemy.orm import Mapped, mapped_column, relationship if TYPE_CHECKING: from api.v1.modules.a76.parts.models import Part class BillOfMaterial(Base, TenantScopedMixin, TimestampMixin): """ Tabla inv_bom: Lista de materiales para una parte. """ __tablename__ = "inv_bom" __table_args__ = ( PrimaryKeyConstraint("id", name="inv_bom_pkey"), ForeignKeyConstraint( ["parent_part_id"], ["a76.parts.id"], name="fk_inv_bom_parent" ), ForeignKeyConstraint( ["component_part_id"], ["a76.parts.id"], name="fk_inv_bom_component" ), {"schema": "a24", "extend_existing": True}, ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) parent_part_id: Mapped[int] = mapped_column(Integer, nullable=False) component_part_id: Mapped[int] = mapped_column(Integer, nullable=False) quantity: Mapped[Decimal] = mapped_column(Numeric(19, 8), default=Decimal('1.0')) # Nuevos campos Legacy uom_code: Mapped[str] = mapped_column(String(5), nullable=False) procedure_type: Mapped[Optional[str]] = mapped_column(String(10), nullable=True) # TEMPORAL, DEFINITIVA, CTM is_percentage: Mapped[bool] = mapped_column(default=True) raw_material: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8), nullable=True) waste: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8), nullable=True) merma: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8), nullable=True) # Relaciones parent_part: Mapped["Part"] = relationship("Part", foreign_keys=[parent_part_id], back_populates="bom_items") component_part: Mapped["Part"] = relationship("Part", foreign_keys=[component_part_id]) def __repr__(self) -> str: return f""