feat: update unit of measure references and improve input handling in item service

This commit is contained in:
2026-01-12 09:22:13 -06:00
parent 803645aa61
commit 6845dcd670
4 changed files with 123 additions and 121 deletions

View File

@@ -1,6 +1,13 @@
from typing import Optional
from decimal import Decimal
from sqlalchemy import ForeignKey, Integer, String, ForeignKeyConstraint, UniqueConstraint, Numeric
from sqlalchemy import (
ForeignKey,
Integer,
String,
ForeignKeyConstraint,
UniqueConstraint,
Numeric,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
@@ -11,16 +18,14 @@ from core.database import Base
class UnitOfMeasureACE(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "unit_of_measure_ace"
__table_args__ = (
UniqueConstraint("code", "tenant_id", "company_id",
name="uq_uom_ace_code"),
{"schema": "a76", "extend_existing": True}
UniqueConstraint("code", "tenant_id", "company_id", name="uq_uom_ace_code"),
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(4), nullable=False) # CLAVEACE
description: Mapped[Optional[str]] = mapped_column(
String(49), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(49), nullable=True)
# 2. GUMOMA
@@ -28,16 +33,14 @@ class UnitOfMeasureACE(Base, TenantScopedMixin, TimestampMixin):
class UnitOfMeasureOMA(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "unit_of_measure_oma"
__table_args__ = (
UniqueConstraint("code", "tenant_id", "company_id",
name="uq_uom_oma_code"),
{"schema": "a76", "extend_existing": True}
UniqueConstraint("code", "tenant_id", "company_id", name="uq_uom_oma_code"),
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(10), nullable=False) # CLAVEUM
description: Mapped[Optional[str]] = mapped_column(
String(200), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
# 3. GUMAme
@@ -45,16 +48,16 @@ class UnitOfMeasureOMA(Base, TenantScopedMixin, TimestampMixin):
class UnitOfMeasureAmerican(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "unit_of_measure_american"
__table_args__ = (
UniqueConstraint("code", "tenant_id", "company_id",
name="uq_uom_american_code"),
{"schema": "a76", "extend_existing": True}
UniqueConstraint(
"code", "tenant_id", "company_id", name="uq_uom_american_code"
),
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(3), nullable=False) # CLAVE
description: Mapped[Optional[str]] = mapped_column(
String(40), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(40), nullable=True)
# 4. GUMAduana
@@ -62,18 +65,17 @@ class UnitOfMeasureAmerican(Base, TenantScopedMixin, TimestampMixin):
class UnitOfMeasureCustoms(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "unit_of_measure_customs"
__table_args__ = (
UniqueConstraint("code", "tenant_id", "company_id",
name="uq_uom_customs_code"),
{"schema": "a76", "extend_existing": True}
UniqueConstraint("code", "tenant_id", "company_id", name="uq_uom_customs_code"),
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(2), nullable=False) # CLAVE
description: Mapped[Optional[str]] = mapped_column(
String(20), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
scaii_unit_code: Mapped[Optional[str]] = mapped_column(
String(5), nullable=True) # UNIDADSCAII
String(5), nullable=True
) # UNIDADSCAII
# 5. GUniMedida (Main)
@@ -81,61 +83,80 @@ class UnitOfMeasureCustoms(Base, TenantScopedMixin, TimestampMixin):
class UnitOfMeasure(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "units_of_measure"
__table_args__ = (
UniqueConstraint("code", "tenant_id",
"company_id", name="uq_uom_code"),
UniqueConstraint("code", "tenant_id", "company_id", name="uq_uom_code"),
ForeignKeyConstraint(
["customs_code", "tenant_id", "company_id"],
["a76.unit_of_measure_customs.code", "a76.unit_of_measure_customs.tenant_id",
"a76.unit_of_measure_customs.company_id"],
[
"a76.unit_of_measure_customs.code",
"a76.unit_of_measure_customs.tenant_id",
"a76.unit_of_measure_customs.company_id",
],
use_alter=True,
name="fk_uom_customs"
name="fk_uom_customs",
),
ForeignKeyConstraint(
["american_code", "tenant_id", "company_id"],
["a76.unit_of_measure_american.code", "a76.unit_of_measure_american.tenant_id",
"a76.unit_of_measure_american.company_id"],
[
"a76.unit_of_measure_american.code",
"a76.unit_of_measure_american.tenant_id",
"a76.unit_of_measure_american.company_id",
],
use_alter=True,
name="fk_uom_american"
name="fk_uom_american",
),
ForeignKeyConstraint(
["ace_code", "tenant_id", "company_id"],
["a76.unit_of_measure_ace.code", "a76.unit_of_measure_ace.tenant_id",
"a76.unit_of_measure_ace.company_id"],
[
"a76.unit_of_measure_ace.code",
"a76.unit_of_measure_ace.tenant_id",
"a76.unit_of_measure_ace.company_id",
],
use_alter=True,
name="fk_uom_ace"
name="fk_uom_ace",
),
ForeignKeyConstraint(
["oma_code", "tenant_id", "company_id"],
["a76.unit_of_measure_oma.code", "a76.unit_of_measure_oma.tenant_id",
"a76.unit_of_measure_oma.company_id"],
[
"a76.unit_of_measure_oma.code",
"a76.unit_of_measure_oma.tenant_id",
"a76.unit_of_measure_oma.company_id",
],
use_alter=True,
name="fk_uom_oma"
name="fk_uom_oma",
),
{"schema": "a76", "extend_existing": True}
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(5), nullable=False) # CLAVEUNI
description: Mapped[Optional[str]] = mapped_column(
String(100), nullable=True)
description_en: Mapped[Optional[str]] = mapped_column(
String(100), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
description_en: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
customs_code: Mapped[Optional[str]] = mapped_column(
String(2), nullable=True) # CLAVE_AMEX
String(2), nullable=True
) # CLAVE_AMEX
american_code: Mapped[Optional[str]] = mapped_column(
String(3), nullable=True) # CLAVE_AAMER
String(3), nullable=True
) # CLAVE_AAMER
ace_code: Mapped[Optional[str]] = mapped_column(
String(4), nullable=True) # CLAVEACE
String(4), nullable=True
) # CLAVEACE
oma_code: Mapped[Optional[str]] = mapped_column(
String(10), nullable=True) # CLAVEOMA
String(10), nullable=True
) # CLAVEOMA
# Relationships omitted for simplicity or need explicit primaryjoin
customs_unit: Mapped[Optional["UnitOfMeasureCustoms"]] = relationship()
american_unit: Mapped[Optional["UnitOfMeasureAmerican"]] = relationship()
ace_unit: Mapped[Optional["UnitOfMeasureACE"]] = relationship()
oma_unit: Mapped[Optional["UnitOfMeasureOMA"]] = relationship()
american_unit: Mapped[Optional["UnitOfMeasureAmerican"]] = relationship(
overlaps="customs_unit"
)
ace_unit: Mapped[Optional["UnitOfMeasureACE"]] = relationship(
overlaps="american_unit,customs_unit"
)
oma_unit: Mapped[Optional["UnitOfMeasureOMA"]] = relationship(
overlaps="ace_unit,american_unit,customs_unit"
)
# 6. GUniMed (General/Conversion)
@@ -143,42 +164,48 @@ class UnitOfMeasure(Base, TenantScopedMixin, TimestampMixin):
class UnitOfMeasureGeneral(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "units_of_measure_general"
__table_args__ = (
UniqueConstraint("code", "tenant_id", "company_id",
name="uq_uom_general_code"),
UniqueConstraint("code", "tenant_id", "company_id", name="uq_uom_general_code"),
ForeignKeyConstraint(
["customs_code", "tenant_id", "company_id"],
["a76.unit_of_measure_customs.code", "a76.unit_of_measure_customs.tenant_id",
"a76.unit_of_measure_customs.company_id"],
[
"a76.unit_of_measure_customs.code",
"a76.unit_of_measure_customs.tenant_id",
"a76.unit_of_measure_customs.company_id",
],
use_alter=True,
name="fk_uom_general_customs"
name="fk_uom_general_customs",
),
ForeignKeyConstraint(
["ace_code", "tenant_id", "company_id"],
["a76.unit_of_measure_ace.code", "a76.unit_of_measure_ace.tenant_id",
"a76.unit_of_measure_ace.company_id"],
[
"a76.unit_of_measure_ace.code",
"a76.unit_of_measure_ace.tenant_id",
"a76.unit_of_measure_ace.company_id",
],
use_alter=True,
name="fk_uom_general_ace"
name="fk_uom_general_ace",
),
{"schema": "a76", "extend_existing": True}
{"schema": "a76", "extend_existing": True},
)
id: Mapped[int] = mapped_column(
Integer, primary_key=True, autoincrement=True)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(5), nullable=False) # UNIDAD
description: Mapped[Optional[str]] = mapped_column(
String(100), nullable=True)
description: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
conversion_factor: Mapped[Optional[Decimal]] = mapped_column(
Numeric(13, 6), nullable=True)
mexico_unit: Mapped[Optional[str]] = mapped_column(
String(5), nullable=True)
Numeric(13, 6), nullable=True
)
mexico_unit: Mapped[Optional[str]] = mapped_column(String(5), nullable=True)
# UNIDAD_AME (Note: GUniMed has UNIDAD_AME varchar(5), but GUMAme has CLAVE varchar(3). Keeping as string for now)
american_unit_code: Mapped[Optional[str]
] = mapped_column(String(5), nullable=True)
american_unit_code: Mapped[Optional[str]] = mapped_column(String(5), nullable=True)
customs_code: Mapped[Optional[str]] = mapped_column(
String(2), nullable=True) # CLAVE_ADUANA
String(2), nullable=True
) # CLAVE_ADUANA
ace_code: Mapped[Optional[str]] = mapped_column(
String(4), nullable=True) # CLAVEACE
String(4), nullable=True
) # CLAVEACE
customs_unit: Mapped[Optional["UnitOfMeasureCustoms"]] = relationship()
ace_unit: Mapped[Optional["UnitOfMeasureACE"]] = relationship(overlaps="customs_unit")
ace_unit: Mapped[Optional["UnitOfMeasureACE"]] = relationship(
overlaps="customs_unit"
)

View File

@@ -39,9 +39,9 @@ class LineItem(Base, TenantScopedMixin, TimestampMixin):
# Unit of measure
unit_of_measure: Mapped[Optional[str]] = mapped_column(
ForeignKey("a76.units_of_measure_general.id")) # UNIDADMEDIDA/UNIMED
ForeignKey("a76.units_of_measure.id")) # UNIDADMEDIDA/UNIMED
alternate_unit: Mapped[Optional[str]] = mapped_column(
ForeignKey("a76.units_of_measure_general.id")) # UNIMEDALTERNA
ForeignKey("a76.units_of_measure.id")) # UNIMEDALTERNA
uma_key: Mapped[Optional[str]] = mapped_column(String(2)) # CLAVEUMA
auxiliary_unit: Mapped[Optional[str]] = mapped_column(
String(5)) # UNIMEDAUXILIAR

View File

@@ -145,13 +145,7 @@ class ItemService:
try:
# Extract lines data
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}")
item_dict = item_data.model_dump(exclude={"lines"})
# Add tenant and company
item_dict["tenant_id"] = tenant_id
@@ -160,26 +154,16 @@ class ItemService:
# Create the item
db_item = Item(**item_dict)
db.add(db_item)
db.flush() # Get the item ID
print(f" ✅ Item created with ID: {db_item.id}")
db.flush() # Get the item ID
# Create line items if provided
for idx, line_data in enumerate(lines_data):
print(f"\n 📝 Processing line {idx + 1}/{len(lines_data)}")
for idx, line_data in enumerate(lines_data):
# Extract nested data from line
financial_data = line_data.financial
quantity_data = line_data.quantity
customs_data = line_data.customs
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}")
reference_data = line_data.reference
line_dict = line_data.model_dump(
exclude={
@@ -197,53 +181,45 @@ class ItemService:
# 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}")
db.flush() # Get the line ID
# Create financial data if provided
if financial_data:
financial_dict = financial_data.model_dump()
financial_dict["item_line_id"] = db_line.id
db_financial = LineFinancial(**financial_dict)
db.add(db_financial)
print(f" ✅ Financial data added")
db.add(db_financial)
# Create quantity data if provided
if quantity_data:
quantity_dict = quantity_data.model_dump()
quantity_dict["item_line_id"] = db_line.id
db_quantity = LineQuantity(**quantity_dict)
db.add(db_quantity)
print(f" ✅ Quantity data added")
db.add(db_quantity)
# Create customs data if provided
if customs_data:
customs_dict = customs_data.model_dump()
customs_dict["item_line_id"] = db_line.id
db_customs = LineCustom(**customs_dict)
db.add(db_customs)
print(f" ✅ Customs data added")
db.add(db_customs)
# Create description data if provided
if description_data:
description_dict = description_data.model_dump()
description_dict["item_line_id"] = db_line.id
db_description = LineDescription(**description_dict)
db.add(db_description)
print(f" ✅ Description data added")
db.add(db_description)
# Create reference data if provided
if reference_data:
reference_dict = reference_data.model_dump()
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.add(db_reference)
db.commit()
db.refresh(db_item)
print(f" ✅ Transaction committed successfully!")
db.refresh(db_item)
return db_item
except IntegrityError as e:

View File

@@ -24,7 +24,7 @@
<div class="grid grid-cols-12 gap-2 items-end">
<div class="col-span-2 space-y-1">
<Label for="cantidad_bultos" class="text-xs">Quantity:</Label>
<Input id="cantidad_bultos" type="number" step="0.00000001" min="0" bind:value={quantities.package_quantity} class="h-7 text-xs text-right" />
<Input id="cantidad_bultos" type="number" step="1" min="0" bind:value={quantities.package_quantity} class="h-7 text-xs text-right" />
</div>
<div class="col-span-3 space-y-1">
<Label for="clave_bultos" class="text-xs">Package Code:</Label>
@@ -36,11 +36,10 @@
<div class="grid grid-cols-12 gap-2 items-end">
<div class="col-span-2 space-y-1">
<Label for="peso_bultos" class="text-xs">Weight: 0</Label>
<Label for="peso_bultos" class="text-xs">Weight: 0.0000</Label>
</div>
<div class="col-span-4 space-y-1">
<Label for="descripcion_bultos" class="text-xs">Description:</Label>
<Input id="descripcion_bultos" bind:value={quantities.package_description} class="h-7 text-xs" />
<Label for="descripcion_bultos" class="text-xs">Description: {quantities.package_description}</Label>
</div>
</div>