feat: update unit of measure references and improve input handling in item service
This commit is contained in:
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user