diff --git a/backend/api/v1/modules/a76/invoices/models.py b/backend/api/v1/modules/a76/invoices/models.py
index ca6d6845..3bb23271 100644
--- a/backend/api/v1/modules/a76/invoices/models.py
+++ b/backend/api/v1/modules/a76/invoices/models.py
@@ -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
diff --git a/backend/api/v1/modules/a76/items/line_items/schemas.py b/backend/api/v1/modules/a76/items/line_items/schemas.py
index c490352f..771196fb 100644
--- a/backend/api/v1/modules/a76/items/line_items/schemas.py
+++ b/backend/api/v1/modules/a76/items/line_items/schemas.py
@@ -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")
diff --git a/backend/api/v1/modules/a76/items/service.py b/backend/api/v1/modules/a76/items/service.py
index d8a30b99..4cc4c946 100644
--- a/backend/api/v1/modules/a76/items/service.py
+++ b/backend/api/v1/modules/a76/items/service.py
@@ -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()
diff --git a/frontend/src/lib/api/dashboard/a76/invoices.ts b/frontend/src/lib/api/dashboard/a76/invoices.ts
index cedb7e74..4af6238b 100644
--- a/frontend/src/lib/api/dashboard/a76/invoices.ts
+++ b/frontend/src/lib/api/dashboard/a76/invoices.ts
@@ -11,9 +11,9 @@ export type TransportType = 'none' | 'transport' | 'box' | 'licence plates' | 't
export interface InvoiceComplianceMx {
invoice_id?: number;
- pedimento?: string | null;
- pedimento_code?: string | null;
- pedimento_k1?: string | null;
+ pedimento_id?: number | null;
+ pedimento_r1?: number | null;
+ pedimento_k1?: number | null;
remesa?: number | null;
aduana?: string | null;
port_of_entry?: string | null;
@@ -24,7 +24,7 @@ export interface InvoiceComplianceMx {
sold_to_header?: string | null;
sold_to_id?: number | null;
shipped_to_header?: string | null;
- shipped_to_id?: string | null;
+ shipped_to_id?: number | null;
shipped_by_header?: string | null;
shipped_by_id?: number | null;
customs_broker_id?: number | null;
diff --git a/frontend/src/lib/api/dashboard/a76/items.ts b/frontend/src/lib/api/dashboard/a76/items.ts
index e474411c..3fe23462 100644
--- a/frontend/src/lib/api/dashboard/a76/items.ts
+++ b/frontend/src/lib/api/dashboard/a76/items.ts
@@ -6,6 +6,115 @@ import { api } from '$lib/api';
// --- Interfaces ---
+// --- Nested Interfaces for Line Items ---
+
+export interface LineCustoms {
+ id?: number;
+ line_item_id?: number;
+ fraction?: string;
+ fraction_type?: string;
+ american_fraction?: string;
+ origin_country?: string;
+ destination_country?: string;
+ advalorem?: string;
+ advalorem_american?: number; // Backend: Decimal
+ sector?: string;
+}
+
+export interface LineFinancials {
+ id?: number;
+ line_item_id?: number;
+ // Costs
+ unit_cost_usd?: number;
+ unit_cost_mxn?: number;
+ unit_cost_capture?: number;
+ unit_cost_commercial_usd?: number;
+
+ // Values
+ value_usd?: number;
+ value_mxn?: number;
+ value_returned_usd?: number;
+ value_returned_mxn?: number;
+ customs_value_usd?: number;
+}
+
+export interface LineQuantities {
+ id?: number;
+ line_item_id?: number;
+ quantity?: number;
+ unit_of_measure?: string;
+
+ // Special quantities
+ quantity_temp_export?: number;
+ quantity_returned?: number;
+
+ // Weight
+ net_weight?: number;
+ gross_weight?: number;
+
+ // Packaging
+ package_key?: string;
+ package_quantity?: number;
+ package_description?: string;
+}
+
+export interface LineDescriptions {
+ id?: number;
+ line_item_id?: number;
+ description_spanish?: string;
+ description_english?: string;
+ extra_description?: string;
+ additional_info_spanish?: string;
+ brand?: string;
+ model?: string;
+ has_serial?: boolean;
+}
+
+export interface LineReferences {
+ id?: number;
+ line_item_id?: number;
+ serie_id?: number;
+}
+
+export interface LineItem {
+ id?: number;
+ item_id?: number;
+ line_number: number;
+
+ // Identification
+ part_number?: string;
+ component_part_number?: string;
+ class_code?: string;
+ identifier?: string;
+
+ // Unit of Measure
+ unit_of_measure?: string;
+ alternate_unit?: string;
+
+ // Permits
+ permit_number?: string;
+ page_line?: string;
+ has_certificate?: boolean;
+ certificate_number?: string;
+
+ // Flags
+ is_subitem?: boolean;
+ includes_subitems?: boolean;
+ tax_payment?: boolean;
+
+ // Payment
+ payment_method?: string;
+ igi_amount?: number;
+
+
+ // Nested relations (Singular names to match backend Pydantic models)
+ customs?: LineCustoms;
+ financial?: LineFinancials;
+ quantity?: LineQuantities;
+ description?: LineDescriptions;
+ reference?: LineReferences;
+}
+
export interface Item {
id?: number;
invoice_id: number;
@@ -18,6 +127,8 @@ export interface Item {
location?: string;
created_at?: string;
updated_at?: string;
+
+ lines?: LineItem[];
}
export interface ItemListResponse {
@@ -36,6 +147,7 @@ export interface CreateItemData {
rectification?: number;
warehouse?: string;
location?: string;
+ lines?: LineItem[];
}
export interface UpdateItemData {
@@ -46,6 +158,7 @@ export interface UpdateItemData {
rectification?: boolean;
warehouse?: string;
location?: string;
+ lines?: LineItem[];
}
/**
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte b/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte
index d80b572a..47743eef 100644
--- a/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte
+++ b/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte
@@ -36,10 +36,16 @@
formData.regimen_pedimento = selectedPedimento.regime || '';
// Construir el nΓΊmero de pedimento completo
- const pedimentoNumber = `${selectedPedimento.year || ''}-${selectedPedimento.customs_office || ''}-${selectedPedimento.license || ''}-${selectedPedimento.pedimento_number || ''}`.replace(/^-+|-+$/g, '');
+ const pedimentoNumber = `${selectedPedimento.customs_office?.slice(0,2) || ''}-${selectedPedimento.license || ''}-${selectedPedimento.pedimento_number || ''}`.replace(/^-+|-+$/g, '');
formData.pedimento = pedimentoNumber;
}
+ $effect(() => {
+ if (formData?.pedimento_id && pedimentos.length > 0 && !formData.pedimento) {
+ handlePedimentoChange(formData.pedimento_id);
+ }
+ });
+
if (!formData) {
let operationType: string | null = null;
if (invoice?.operation_type) {
@@ -50,8 +56,7 @@
formData = {
is_pedimento_pending: false,
- pedimento_id: null,
- pedimento: invoice?.compliance_mx?.pedimento || '',
+ pedimento_id: invoice?.compliance_mx?.pedimento_id || '',
remesa: invoice?.compliance_mx?.remesa || '',
invoice_number: invoice?.invoice_number || '',
invoice_date: invoice?.invoice_date || new Date().toISOString().split('T')[0],
@@ -147,7 +152,7 @@