Se quito la relacion de las tablas de aphis de partes, se mejoro un poquito el frontend, se homogelizaron el disenio de los catalogos y mejoras visuales

This commit is contained in:
2026-03-18 15:41:54 -05:00
parent 6741a85abc
commit 4df61404de
8 changed files with 414 additions and 104 deletions

View File

@@ -0,0 +1,57 @@
from pydantic import BaseModel, ConfigDict, field_validator
from typing import Optional, List, Dict, Any
from datetime import date
class AphisCatalogDTO(BaseModel):
id: Optional[int] = None
# --- Pestaña 1: General ---
program_code: Optional[str] = None
processing_code: Optional[str] = None
aphis_type: Optional[str] = None
disclaimer: Optional[str] = None
electronic_image: Optional[str] = None
confidential: Optional[str] = None
global_product_id: Optional[str] = None
intended_use_code: Optional[str] = None
intended_use_description: Optional[str] = None
item_type: Optional[str] = None
product_code: Optional[str] = None
product_code_2: Optional[str] = None
product_code_3: Optional[str] = None
scientific_genus_name: Optional[str] = None
scientific_species_name: Optional[str] = None
scientific_sub_species_name: Optional[str] = None
common_name_specific: Optional[str] = None
common_name_general: Optional[str] = None
signed_doc: Optional[str] = None
signed_doc_date: Optional[date] = None
signed_doc_id: Optional[str] = None
invoice_number: Optional[str] = None
quantity_1: Optional[str] = None
quantity_2: Optional[str] = None
quantity_3: Optional[str] = None
inspection: Optional[str] = None
inspection_date: Optional[date] = None
inspection_loc_date: Optional[date] = None
inspection_location: Optional[str] = None
country_production: Optional[str] = None
country_source: Optional[str] = None
# --- Pestañas 2-7: Detalles (Listas de objetos) ---
characteristics: Optional[List[Dict[str, Any]]] = []
pitems: Optional[List[Dict[str, Any]]] = []
lpcos: Optional[List[Dict[str, Any]]] = []
entities: Optional[List[Dict[str, Any]]] = []
containers: Optional[List[Dict[str, Any]]] = []
routing: Optional[List[Dict[str, Any]]] = []
model_config = ConfigDict(from_attributes=True)
@field_validator("signed_doc_date", "inspection_date", "inspection_loc_date", mode="before")
@classmethod
def empty_to_none(cls, v):
if v == "":
return None
return v

View File

@@ -0,0 +1,61 @@
from typing import Optional, List, Dict, Any
from datetime import date
from sqlalchemy import Integer, String, Date, PrimaryKeyConstraint, JSON
from sqlalchemy.orm import Mapped, mapped_column
from core.database import Base
class AphisCatalog(Base):
"""
Catálogo global de registros APHIS por empresa.
Soporta las 7 pestañas de información (General + 6 detalles via JSON).
"""
__tablename__ = "inv_aphis_catalog"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_catalog_pkey"),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
company_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
# --- Pestaña 1: General (Campos principales) ---
program_code: Mapped[Optional[str]] = mapped_column(String(10))
processing_code: Mapped[Optional[str]] = mapped_column(String(10))
aphis_type: Mapped[Optional[str]] = mapped_column(String(10))
disclaimer: Mapped[Optional[str]] = mapped_column(String(10))
electronic_image: Mapped[Optional[str]] = mapped_column(String(50))
confidential: Mapped[Optional[str]] = mapped_column(String(1))
global_product_id: Mapped[Optional[str]] = mapped_column(String(100))
intended_use_code: Mapped[Optional[str]] = mapped_column(String(10))
intended_use_description: Mapped[Optional[str]] = mapped_column(String(200))
item_type: Mapped[Optional[str]] = mapped_column(String(20))
product_code: Mapped[Optional[str]] = mapped_column(String(20))
product_code_2: Mapped[Optional[str]] = mapped_column(String(20))
product_code_3: Mapped[Optional[str]] = mapped_column(String(20))
scientific_genus_name: Mapped[Optional[str]] = mapped_column(String(100))
scientific_species_name: Mapped[Optional[str]] = mapped_column(String(100))
scientific_sub_species_name: Mapped[Optional[str]] = mapped_column(String(100))
common_name_specific: Mapped[Optional[str]] = mapped_column(String(200))
common_name_general: Mapped[Optional[str]] = mapped_column(String(200))
signed_doc: Mapped[Optional[str]] = mapped_column(String(100))
signed_doc_date: Mapped[Optional[date]] = mapped_column(Date)
signed_doc_id: Mapped[Optional[str]] = mapped_column(String(50))
invoice_number: Mapped[Optional[str]] = mapped_column(String(50))
quantity_1: Mapped[Optional[str]] = mapped_column(String(50))
quantity_2: Mapped[Optional[str]] = mapped_column(String(50))
quantity_3: Mapped[Optional[str]] = mapped_column(String(50))
inspection: Mapped[Optional[str]] = mapped_column(String(200))
inspection_date: Mapped[Optional[date]] = mapped_column(Date)
inspection_loc_date: Mapped[Optional[date]] = mapped_column(Date)
inspection_location: Mapped[Optional[str]] = mapped_column(String(200))
country_production: Mapped[Optional[str]] = mapped_column(String(3))
country_source: Mapped[Optional[str]] = mapped_column(String(3))
# --- Pestañas 2-7: Detalles (Almacenados como JSON por flexibilidad) ---
characteristics: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)
pitems: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)
lpcos: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)
entities: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)
containers: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)
routing: Mapped[Optional[List[Dict[str, Any]]]] = mapped_column(JSON, default=list)

View File

@@ -0,0 +1,62 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
from core.database import get_core_db
from .models import AphisCatalog
from .dto import AphisCatalogDTO
router = APIRouter(prefix="/aphis-catalog", tags=["APHIS Catalog"])
@router.get("/", response_model=List[AphisCatalogDTO])
def list_aphis_catalog(company_id: int, db: Session = Depends(get_core_db)):
records = (
db.query(AphisCatalog)
.filter(AphisCatalog.company_id == company_id)
.order_by(AphisCatalog.id)
.all()
)
return records
@router.post("/", response_model=AphisCatalogDTO)
def create_aphis_catalog(data: AphisCatalogDTO, company_id: int, db: Session = Depends(get_core_db)):
payload = data.model_dump(exclude={"id"})
record = AphisCatalog(**payload, company_id=company_id)
db.add(record)
db.commit()
db.refresh(record)
return record
@router.put("/{record_id}", response_model=AphisCatalogDTO)
def update_aphis_catalog(
record_id: int, data: AphisCatalogDTO, company_id: int, db: Session = Depends(get_core_db)
):
record = (
db.query(AphisCatalog)
.filter(AphisCatalog.id == record_id, AphisCatalog.company_id == company_id)
.first()
)
if not record:
raise HTTPException(status_code=404, detail="Registro no encontrado")
for field, value in data.model_dump(exclude={"id"}).items():
setattr(record, field, value)
db.commit()
db.refresh(record)
return record
@router.delete("/{record_id}", status_code=204)
def delete_aphis_catalog(record_id: int, company_id: int, db: Session = Depends(get_core_db)):
record = (
db.query(AphisCatalog)
.filter(AphisCatalog.id == record_id, AphisCatalog.company_id == company_id)
.first()
)
if not record:
raise HTTPException(status_code=404, detail="Registro no encontrado")
db.delete(record)
db.commit()

View File

@@ -8,6 +8,10 @@ from fastapi import APIRouter
from .fa.fa_classes.routes import router as fa_classes_router
from .fa.fa_item_lines.routes import router as fa_item_lines_router
from .inv.part_countries.routes import router as part_countries_router
from .inv.inv_aphis.inv_aphis_catalog.router import router as aphis_catalog_router
# Importar modelo para que SQLAlchemy cree la tabla automáticamente
import api.v1.modules.a24.inv.inv_aphis.inv_aphis_catalog.models # noqa: F401
# Router principal de A24
@@ -21,3 +25,5 @@ router.include_router(
# Registrar routers de INV (Inventory)
router.include_router(part_countries_router, prefix="/a24", tags=["a24 / inv / part-countries"])
router.include_router(aphis_catalog_router, prefix="/a24", tags=["a24 / inv / aphis-catalog"])