Partidas por tipo de factura en importacion
This commit is contained in:
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user