Partidas por tipo de factura en importacion

This commit is contained in:
2026-03-13 17:38:30 -05:00
parent dfa44aaff7
commit dada17b54c
15 changed files with 1015 additions and 56 deletions

View File

@@ -4,7 +4,7 @@ SQLAlchemy v2 - Annex 24 Compliance
"""
from datetime import datetime
from typing import Optional, TYPE_CHECKING
from typing import Optional, List, TYPE_CHECKING
from core.database import Base
from decimal import Decimal
from sqlalchemy import Boolean, Date, String, Integer, Numeric, SmallInteger, ForeignKey
@@ -24,6 +24,7 @@ if TYPE_CHECKING:
from api.v1.modules.a24.fa.fa_item_lines.models import FaLineItem
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.general_catalogs.identifiers.models import IdentifierDetail
# ============================================================================
# CORE ENTITIES
@@ -216,10 +217,14 @@ class LineItem(Base, TenantScopedMixin, TimestampMixin):
)
fa_data: Mapped[Optional["FaLineItem"]] = relationship(
"FaLineItem",
back_populates="master_info",
cascade="all, delete-orphan",
uselist=False,
)
identifiers: Mapped[List["IdentifierDetail"]] = relationship(
"IdentifierDetail",
back_populates="line",
cascade="all, delete-orphan",
)
part_info: Mapped[Optional["Part"]] = relationship(
"Part",
foreign_keys=[part_number_id],

View File

@@ -37,6 +37,12 @@ from .line_references.schemas import (
LineReferenceResponse,
)
from api.v1.modules.a76.general_catalogs.identifiers.dto import (
IdentifierDetailCreate,
IdentifierDetailUpdate,
IdentifierDetailResponse,
)
from api.v1.modules.a76.classes.models import Class
from api.v1.modules.a24.fa.fa_item_lines.dto import (
FaLineItemCreateDTO,
FaLineItemUpdateDTO,
@@ -238,6 +244,9 @@ class LineItemCreate(LineItemBase):
series: Optional[list[SerieCreate]] = Field(
None, description="Series data for this line (multiple per line)"
)
identifiers: Optional[list[IdentifierDetailCreate]] = Field(
None, description="Identifiers for this line"
)
class LineItemUpdate(LineItemBase):
@@ -267,6 +276,9 @@ class LineItemUpdate(LineItemBase):
series: Optional[list[SerieUpdate]] = Field(
None, description="Series data for this line (replace all)"
)
identifiers: Optional[list[IdentifierDetailUpdate]] = Field(
None, description="Identifiers for this line"
)
class LineItemResponse(LineItemBase):
@@ -295,6 +307,7 @@ class LineItemResponse(LineItemBase):
reference: Optional[LineReferenceResponse] = None
fa_data: Optional[FaLineItemResponseDTO] = None
series: Optional[list[SerieResponse]] = None
identifiers: Optional[list[IdentifierDetailResponse]] = None
# Fields populated from relationships
class_code: Optional[str] = None

View File

@@ -19,6 +19,9 @@ class Serie(Base, TenantScopedMixin, TimestampMixin):
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
expo_brad: Mapped[Optional[str]] = mapped_column(String(50)) # MARCAEXPO
number_id: Mapped[Optional[str]] = mapped_column(String(25)) # NUMIDEXPO
import_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAIMPO
import_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAIMPO
image_path: Mapped[Optional[str]] = mapped_column(String(255)) # PATH DE IMAGEN (MEX)

View File

@@ -10,6 +10,9 @@ class SerieBase(BaseModel):
brand: Optional[str] = Field(None, max_length=50, description="Brand (MARCA)")
expo_brad: Optional[str] = Field(None, max_length=50, description="Expo brand (MARCAEXPO)")
number_id: Optional[str] = Field(None, max_length=25, description="Number ID (NUMIDEXPO)")
import_invoice: Optional[str] = Field(None, max_length=15, description="Import invoice (FACTURAIMPO)")
import_line: Optional[int] = Field(None, description="Import line (LINEAIMPO)")
image_path: Optional[str] = Field(None, max_length=255, description="Image path (IMAGEPATHMEX)")
class SerieCreate(SerieBase):

View File

@@ -40,6 +40,7 @@ from .models import LineItem
from .series.models import Serie
from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a76.general_catalogs.identifiers.models import IdentifierDetail
logger = logging.getLogger(__name__)
@@ -195,6 +196,26 @@ class ItemService:
serie_dict["row"] = 1
db.add(Serie(**serie_dict))
# Identifier Detail data
if hasattr(line_data, "identifiers") and line_data.identifiers:
id_list = (
line_data.identifiers
if isinstance(line_data.identifiers, list)
else [line_data.identifiers]
)
for d in id_list:
id_dict = (
d.model_dump(exclude_unset=True)
if hasattr(d, "model_dump")
else (dict(d) if isinstance(d, dict) else {})
)
if not id_dict:
continue
id_dict["item_line_id"] = line.id
id_dict["tenant_id"] = tenant_id
id_dict["company_id"] = company_id
db.add(IdentifierDetail(**id_dict))
@staticmethod
def _attach_series(db: Session, item: LineItem) -> None:
"""Query and attach all Serie rows for this item as a list."""
@@ -206,6 +227,16 @@ class ItemService:
)
item.series = list(series)
@staticmethod
def _attach_identifiers(db: Session, item: LineItem) -> None:
"""Query and attach all IdentifierDetail rows for this item."""
identifiers = (
db.query(IdentifierDetail)
.filter(IdentifierDetail.item_line_id == item.id)
.all()
)
item.identifiers = list(identifiers)
@staticmethod
def get_by_id(
db: Session, item_id: int, tenant_id: int, company_id: int
@@ -232,6 +263,7 @@ class ItemService:
)
if result:
ItemService._attach_series(db, result)
ItemService._attach_identifiers(db, result)
return result
@staticmethod
@@ -285,6 +317,7 @@ class ItemService:
items = query.offset(skip).limit(limit).all()
for item in items:
ItemService._attach_series(db, item)
ItemService._attach_identifiers(db, item)
return items, total
@staticmethod
@@ -318,6 +351,7 @@ class ItemService:
items = query.offset(skip).limit(limit).all()
for item in items:
ItemService._attach_series(db, item)
ItemService._attach_identifiers(db, item)
return items, total
@staticmethod
@@ -443,6 +477,7 @@ class ItemService:
db.commit()
db.refresh(db_item)
ItemService._attach_series(db, db_item)
ItemService._attach_identifiers(db, db_item)
return db_item
except IntegrityError as e:
@@ -591,6 +626,7 @@ class ItemService:
).delete()
db.query(FaLineItem).filter(FaLineItem.id == db_item.id).delete()
db.query(Serie).filter(Serie.line_item_id == db_item.id).delete()
db.query(IdentifierDetail).filter(IdentifierDetail.item_line_id == db_item.id).delete()
db.flush()
# Create new nested data
@@ -604,6 +640,7 @@ class ItemService:
db.commit()
db.refresh(db_item)
ItemService._attach_series(db, db_item)
ItemService._attach_identifiers(db, db_item)
return db_item
except HTTPException: