- Rearranged imports in multiple files for consistency and clarity. - Updated logging middleware to exclude specific paths from logging. - Enhanced security module by cleaning up token handling and improving tenant validation. - Added tenant and company scoped mixins for better database model management. - Implemented generic CRUD routes for tenant-scoped resources. - Improved error handling and response management in API routes. - Cleaned up login and logout processes to ensure proper session management. - Introduced mechanisms to clear local storage and cookies on tenant change. - Enhanced company store to detect tenant changes and clear data accordingly. - Added new DTO mixins for currency and value affect flags.
122 lines
4.7 KiB
Python
122 lines
4.7 KiB
Python
"""
|
|
Modelos ORM para gestión de partes/componentes
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
from typing import TYPE_CHECKING, Optional
|
|
|
|
from api.v1.common.base_models import TenantScopedMixin
|
|
from core.database import Base
|
|
from sqlalchemy import (
|
|
ForeignKeyConstraint,
|
|
Integer,
|
|
Numeric,
|
|
PrimaryKeyConstraint,
|
|
SmallInteger,
|
|
String,
|
|
UniqueConstraint,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
if TYPE_CHECKING:
|
|
from api.v1.modules.a76.classes.models import Class
|
|
from api.v1.modules.public.reference_data.countries.models import Country
|
|
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
|
|
|
|
|
|
class Part(Base, TenantScopedMixin):
|
|
"""
|
|
Modelo para la tabla GPartes - Información de partes en los sistemas SCAII (N), SCAF (S) Y WINSAAI (W)
|
|
"""
|
|
|
|
__tablename__ = "parts"
|
|
__table_args__ = (
|
|
PrimaryKeyConstraint("id", name="parts_pkey"),
|
|
ForeignKeyConstraint(["tenant_id"], ["a76.tenants.id"], name="fk_parts_tenant"),
|
|
ForeignKeyConstraint(
|
|
["company_id"], ["a76.company.id"], name="fk_parts_company"
|
|
),
|
|
ForeignKeyConstraint(
|
|
["country_of_origin"], ["public.countries.m3_key"], name="fk_parts_country"
|
|
),
|
|
ForeignKeyConstraint(
|
|
["currency_key"], ["public.currency_types.code"], name="fk_parts_currency"
|
|
),
|
|
UniqueConstraint(
|
|
"tenant_id", "company_id", "part_number", name="client_part_ukey"
|
|
),
|
|
{"schema": "a76"},
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
|
|
# Unique constraint compuesta
|
|
client_id: Mapped[int] = mapped_column(Integer)
|
|
part_number: Mapped[str] = mapped_column(String(49))
|
|
|
|
# Basic information
|
|
fraction: Mapped[Optional[str]] = mapped_column(String(10))
|
|
description_spanish: Mapped[Optional[str]] = mapped_column(String(500))
|
|
description_english: Mapped[Optional[str]] = mapped_column(String(500))
|
|
part_class: Mapped[Optional[str]] = mapped_column(String(8))
|
|
unit_of_measure: Mapped[Optional[str]] = mapped_column(String(5))
|
|
commercial_part_number: Mapped[Optional[str]] = mapped_column(String(70))
|
|
country_of_origin: Mapped[Optional[str]] = mapped_column(String(3))
|
|
|
|
# Pricing and currency
|
|
unit_cost: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8))
|
|
currency_type: Mapped[Optional[str]] = mapped_column(String(2))
|
|
currency_key: Mapped[Optional[str]] = mapped_column(String(3))
|
|
|
|
# Weight information
|
|
unit_weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8))
|
|
weight_type: Mapped[Optional[str]] = mapped_column(String(6))
|
|
|
|
# Classification and regulatory
|
|
us_fraction: Mapped[Optional[str]] = mapped_column(String(16)) # FRACCIONAME
|
|
fda_key: Mapped[Optional[str]] = mapped_column(String(20))
|
|
fcc_key: Mapped[Optional[str]] = mapped_column(String(30))
|
|
license_code: Mapped[Optional[str]] = mapped_column(String(3))
|
|
eccn: Mapped[Optional[str]] = mapped_column(
|
|
String(20)
|
|
) # Export Control Classification Number
|
|
export_code: Mapped[Optional[str]] = mapped_column(String(2))
|
|
exclusion_symbol: Mapped[Optional[str]] = mapped_column(String(19)) # SIMBOLOEXCLIC
|
|
|
|
# Additional information
|
|
supplier: Mapped[Optional[str]] = mapped_column(String(14))
|
|
alternate_unit_measure: Mapped[Optional[str]] = mapped_column(String(14))
|
|
added_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8))
|
|
|
|
# Status and dates
|
|
enabled_disabled: Mapped[Optional[int]] = mapped_column(SmallInteger)
|
|
creation_date: Mapped[Optional[int]] = mapped_column() # FECHACREACIONPARTE
|
|
modification_date: Mapped[Optional[int]] = mapped_column() # FECHAMODIFICA
|
|
modification_date_iso: Mapped[Optional[datetime]] = (
|
|
mapped_column()
|
|
) # FECHAMODIFICA_ISO
|
|
|
|
# Media
|
|
part_photo: Mapped[Optional[str]] = mapped_column(String(255))
|
|
|
|
# Relationships
|
|
country: Mapped[Optional["Country"]] = relationship(
|
|
foreign_keys=[country_of_origin]
|
|
)
|
|
currency: Mapped[Optional["CurrencyType"]] = relationship(
|
|
foreign_keys=[currency_key]
|
|
)
|
|
|
|
# Relationship with Class through composite foreign key
|
|
# Note: This requires both client_id and part_class to match client_id and class_code in Class
|
|
part_class_info: Mapped[Optional["Class"]] = relationship(
|
|
primaryjoin="and_(Part.client_id == Class.client_id, Part.part_class == Class.class_code)",
|
|
foreign_keys="[Part.client_id, Part.part_class]",
|
|
viewonly=True,
|
|
back_populates="parts",
|
|
)
|
|
|
|
def __repr__(self) -> str:
|
|
return f"<Part(client_id={self.client_id}, part_number='{self.part_number}', description='{self.description_spanish}')>"
|