feat: Enhance invoice item management with detailed line item structure
- Introduced nested interfaces for line items including customs, financials, quantities, descriptions, and references. - Updated Item interface to include lines as an array of LineItem. - Modified invoice top fields to handle pedimento ID and auto-assign values from the invoice. - Enhanced item configuration component to manage line item properties and descriptions. - Updated main data, packages section, summary section, and other components to bind new line item properties. - Implemented normalization of numeric values when editing items to ensure consistent data types. - Adjusted save invoice logic to accommodate new line item structure and compliance data.
This commit is contained in:
@@ -136,9 +136,9 @@ class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin):
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"), primary_key=True)
|
||||
|
||||
# Core Customs Data
|
||||
pedimento_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTO/PEDIMENTOIMPO/EXPO
|
||||
pedimento_r1: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTOR1
|
||||
pedimento_k1: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTOK1
|
||||
pedimento_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTO/PEDIMENTOIMPO/EXPO
|
||||
pedimento_r1: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTOR1
|
||||
pedimento_k1: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.pedimentos.id")) # PEDIMENTOK1
|
||||
remesa: Mapped[Optional[int]] = mapped_column(Integer) # REMESA
|
||||
aduana: Mapped[Optional[str]] = mapped_column(ForeignKey("public.customs_sections.customs_code")) # ADUANA_CRUCE
|
||||
port_of_entry: Mapped[Optional[str]] = mapped_column(String(6)) # PUERTOENTRADA / Puerto de entrada
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_validator
|
||||
|
||||
# Import nested schemas
|
||||
from ..line_customs.schemas import (
|
||||
@@ -42,6 +42,14 @@ class LineItemBase(BaseModel):
|
||||
component_part_number: Optional[str] = Field(None, max_length=50, description="Component part number")
|
||||
class_code: Optional[str] = Field(None, max_length=20, description="Class code")
|
||||
|
||||
@field_validator('class_code', 'part_number', 'component_part_number', 'unit_of_measure', 'alternate_unit', mode='before')
|
||||
@classmethod
|
||||
def convert_to_string(cls, v):
|
||||
"""Convert integers to strings for FK fields"""
|
||||
if v is not None and not isinstance(v, str):
|
||||
return str(v)
|
||||
return v
|
||||
|
||||
# Unit of measure
|
||||
unit_of_measure: Optional[str] = Field(None, max_length=10, description="Unit of measure")
|
||||
alternate_unit: Optional[str] = Field(None, max_length=10, description="Alternate unit")
|
||||
|
||||
@@ -151,6 +151,12 @@ class ItemService:
|
||||
lines_data = item_data.lines or []
|
||||
item_dict = item_data.model_dump(exclude={"lines"})
|
||||
|
||||
# DEBUG: Log incoming data
|
||||
print(f"\n🔍 DEBUG CREATE ITEM:")
|
||||
print(f" Item data: {item_dict}")
|
||||
print(f" Lines count: {len(lines_data)}")
|
||||
print(f" Tenant ID: {tenant_id}, Company ID: {company_id}")
|
||||
|
||||
# Add tenant and company
|
||||
item_dict["tenant_id"] = tenant_id
|
||||
item_dict["company_id"] = company_id
|
||||
@@ -160,8 +166,11 @@ class ItemService:
|
||||
db.add(db_item)
|
||||
db.flush() # Get the item ID
|
||||
|
||||
print(f" ✅ Item created with ID: {db_item.id}")
|
||||
|
||||
# Create line items if provided
|
||||
for line_data in lines_data:
|
||||
for idx, line_data in enumerate(lines_data):
|
||||
print(f"\n 📝 Processing line {idx + 1}/{len(lines_data)}")
|
||||
# Extract nested data from line
|
||||
financial_data = line_data.financial
|
||||
quantity_data = line_data.quantity
|
||||
@@ -169,16 +178,26 @@ class ItemService:
|
||||
description_data = line_data.description
|
||||
reference_data = line_data.reference
|
||||
|
||||
print(f" Line data: {line_data.model_dump()}")
|
||||
print(f" Has financial: {financial_data is not None}")
|
||||
print(f" Has quantity: {quantity_data is not None}")
|
||||
print(f" Has customs: {customs_data is not None}")
|
||||
print(f" Has description: {description_data is not None}")
|
||||
print(f" Has reference: {reference_data is not None}")
|
||||
|
||||
line_dict = line_data.model_dump(
|
||||
exclude={"financial", "quantity",
|
||||
"customs", "description", "reference"}
|
||||
)
|
||||
line_dict["item_id"] = db_item.id
|
||||
line_dict["tenant_id"] = tenant_id
|
||||
line_dict["company_id"] = company_id
|
||||
|
||||
# Create line item
|
||||
db_line = LineItem(**line_dict)
|
||||
db.add(db_line)
|
||||
db.flush() # Get the line ID
|
||||
print(f" ✅ Line created with ID: {db_line.id}")
|
||||
|
||||
# Create financial data if provided
|
||||
if financial_data:
|
||||
@@ -186,6 +205,7 @@ class ItemService:
|
||||
financial_dict["item_line_id"] = db_line.id
|
||||
db_financial = LineFinancial(**financial_dict)
|
||||
db.add(db_financial)
|
||||
print(f" ✅ Financial data added")
|
||||
|
||||
# Create quantity data if provided
|
||||
if quantity_data:
|
||||
@@ -193,6 +213,7 @@ class ItemService:
|
||||
quantity_dict["item_line_id"] = db_line.id
|
||||
db_quantity = LineQuantity(**quantity_dict)
|
||||
db.add(db_quantity)
|
||||
print(f" ✅ Quantity data added")
|
||||
|
||||
# Create customs data if provided
|
||||
if customs_data:
|
||||
@@ -200,6 +221,7 @@ class ItemService:
|
||||
customs_dict["item_line_id"] = db_line.id
|
||||
db_customs = LineCustom(**customs_dict)
|
||||
db.add(db_customs)
|
||||
print(f" ✅ Customs data added")
|
||||
|
||||
# Create description data if provided
|
||||
if description_data:
|
||||
@@ -207,6 +229,7 @@ class ItemService:
|
||||
description_dict["item_line_id"] = db_line.id
|
||||
db_description = LineDescription(**description_dict)
|
||||
db.add(db_description)
|
||||
print(f" ✅ Description data added")
|
||||
|
||||
# Create reference data if provided
|
||||
if reference_data:
|
||||
@@ -214,9 +237,12 @@ class ItemService:
|
||||
reference_dict["item_line_id"] = db_line.id
|
||||
db_reference = LineReference(**reference_dict)
|
||||
db.add(db_reference)
|
||||
print(f" ✅ Reference data added")
|
||||
|
||||
print(f"\n 💾 Committing transaction...")
|
||||
db.commit()
|
||||
db.refresh(db_item)
|
||||
print(f" ✅ Transaction committed successfully!")
|
||||
return db_item
|
||||
|
||||
except IntegrityError as e:
|
||||
@@ -277,6 +303,9 @@ class ItemService:
|
||||
exclude_unset=True
|
||||
)
|
||||
line_dict["item_id"] = db_item.id
|
||||
line_dict["tenant_id"] = tenant_id
|
||||
line_dict["company_id"] = company_id
|
||||
|
||||
db_line = LineItem(**line_dict)
|
||||
db.add(db_line)
|
||||
db.flush()
|
||||
|
||||
Reference in New Issue
Block a user