refactor: streamline item validation functions and enhance number formatting in summary section

This commit is contained in:
2026-02-13 15:49:54 -06:00
parent 13254bbcfc
commit 794d6d1781
6 changed files with 57 additions and 54 deletions

View File

@@ -3,36 +3,31 @@ from core.exceptions import ErrorCollector
from ..line_items import models
from sqlalchemy.orm import Session
def item_exists(
db: Session,
item_line: int,
tenant_id: int,
company_id: int
):
def item_exists(db: Session, item_line: int, tenant_id: int, company_id: int):
item_exists = (
db.query(models.LineItem.id)
db.query(models.LineItem)
.filter(
models.LineItem.line_number == item_line,
models.LineItem.tenant_id == tenant_id,
models.LineItem.company_id == company_id,
)
.first()
)
return item_exists
def count_items(db: Session, invoice_id: int, tenant_id: int, company_id: int):
count = (
db.query(func.count())
.select_from(models.Item)
.filter(
models.Item.invoice_id == invoice_id,
models.Item.tenant_id == tenant_id,
models.Item.company_id == company_id,
)
.scalar()
)
if item_exists:
return item_exists
return None
def count_items(
db: Session,
invoice_id: int,
tenant_id: int,
company_id: int
):
count = db.query(func.count()).select_from(models.Item).filter(
models.Item.invoice_id == invoice_id,
models.Item.tenant_id == tenant_id,
models.Item.company_id == company_id,
).scalar()
return count
return count

View File

@@ -42,9 +42,7 @@ def validate_common(
invoice: InvoiceHeader = invoice_exists_by_id(
db, invoice_id, tenant_id, company_id, errors
)
line_item: LineItem = item_exists(
db, line.line_number, tenant_id, company_id
)
line_item: LineItem = item_exists(db, line.line_number, tenant_id, company_id)
fecha_factura = invoice.invoice_date if invoice else None
fraction = None
@@ -181,13 +179,15 @@ def validate_common(
fraction = line.customs.fraction if line.customs.fraction else fraction
country = line.customs.origin_country
if line_item:
if line_item and line_item.customs:
country = (
line_item.customs.fraction if line_item.customs.origin_country else country
line_item.customs.origin_country
if line_item.customs.origin_country
else country
)
fraction_type = line.customs.fraction_type.upper()
if line_item:
if line_item and line_item.customs:
fraction_type = (
line_item.customs.fraction_type
if line_item.customs.fraction_type
@@ -195,7 +195,7 @@ def validate_common(
)
sector = line.customs.sector
if line_item:
if line_item and line_item.customs:
sector = line_item.customs.sector if line_item.customs.sector else sector
country_m3 = db.query(Country.m3_key).filter(Country.m3_key == country).scalar()

View File

@@ -206,8 +206,8 @@ def validate_create(
net_weight_input = line.quantity.net_weight or Decimal("0")
# Determinar si la unidad de medida es de peso
unit_is_kgs = line.unit_of_measure and line.unit_of_measure.upper() == "KGS"
unit_is_lbs = line.unit_of_measure and line.unit_of_measure.upper() == "LB"
unit_is_kgs = line.unit_of_measure and line.unit_of_measure == "24" #KGS
unit_is_lbs = line.unit_of_measure and line.unit_of_measure == "25" #LBS
# Calcular peso neto en kilogramos (estándar interno)
if unit_is_kgs:
@@ -237,11 +237,11 @@ def validate_create(
package_weight_unit = Decimal("0")
# Obtener peso unitario del bulto si existe
if line.quantity.package_key:
if line.quantity.package_id:
package: Package = (
db.query(Package)
.filter(
Package.key == line.quantity.package_key,
Package.id == line.quantity.package_id,
Package.tenant_id == tenant_id,
Package.company_id == company_id,
)
@@ -278,22 +278,22 @@ def validate_create(
# ==========================================
# ASIGNAR DESCRIPCIÓN DE BULTOS
# ==========================================
if package_quantity and package_quantity > 0 and line.quantity.package_key:
if package_quantity and package_quantity > 0 and line.quantity.package_id:
package: Package = (
db.query(Package)
.filter(
Package.key == line.quantity.package_key,
Package.id == line.quantity.package_id,
Package.tenant_id == tenant_id,
Package.company_id == company_id,
)
.first()
)
if package:
line.quantity.package_description = package.description_es
line.description.package_description = package.description_es
else:
line.quantity.package_quantity = 0
line.quantity.package_key = None
line.quantity.package_description = None
line.quantity.package_id = None
line.description.package_description = None
# ==========================================
# ASIGNAR FRACCIÓN AMERICANA POR DEFECTO

View File

@@ -24,7 +24,8 @@ class LineDescription(Base):
description_english: Mapped[Optional[str]] = mapped_column(String(4999)) # DESCRIPCIONI
extra_description: Mapped[Optional[str]] = mapped_column(Text) # DESCRIPCIONEEXTRA
part_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONPARTE
class_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONCLASE
class_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONCLASE
package_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONBULTO
# Product attributes
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA

View File

@@ -13,6 +13,7 @@ class LineDescriptionBase(BaseModel):
extra_description: Optional[str] = Field(None, description="Extra description (DESCRIPCIONEEXTRA)")
part_description: Optional[str] = Field(None, max_length=500, description="Part description (DESCRIPCIONPARTE)")
class_description: Optional[str] = Field(None, max_length=500, description="Class description (DESCRIPCIONCLASE)")
package_description: Optional[str] = Field(None, max_length=500, description="Package description (DESCRIPCIONBULTO)")
# Product attributes
brand: Optional[str] = Field(None, max_length=50, description="Brand (MARCA)")

View File

@@ -2,6 +2,12 @@
import type { LineFinancials, LineQuantities } from '$lib/api/dashboard/a76/items';
let { financials = $bindable(), quantities = $bindable() }: { financials: LineFinancials; quantities: LineQuantities } = $props();
// Helper function to safely format numbers
function formatNumber(value: any, decimals: number = 8): string {
const num = Number(value);
return isNaN(num) ? '0.00000000' : num.toFixed(decimals);
}
</script>
<div>
@@ -10,18 +16,18 @@
<div class="text-xs font-semibold">RETURN QUANTITY SUB-ITEMS</div>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>Temporary: <span class="text-gray-900 dark:text-gray-100">{quantities.quantity_temp_export?.toFixed(8) || '0.00000000'}</span></div>
<div>Temporary: <span class="text-gray-900 dark:text-gray-100">{formatNumber(quantities.quantity_temp_export)}</span></div>
<div>Replacement or Change: <span class="text-gray-900 dark:text-gray-100">0.00000000</span></div>
<div>Definitive: <span class="text-gray-900 dark:text-gray-100">{quantities.quantity_returned?.toFixed(8) || '0.00000000'}</span></div>
<div>Returned Values: <span class="text-gray-900 dark:text-gray-100">{financials.value_returned_usd?.toFixed(8) || '0.00000000'}</span></div>
<div class="col-span-2">Returned Values: <span class="text-gray-900 dark:text-gray-100">{financials.value_returned_mxn?.toFixed(8) || '0.00000000'}</span></div>
<div>Definitive: <span class="text-gray-900 dark:text-gray-100">{formatNumber(quantities.quantity_returned)}</span></div>
<div>Returned Values: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.value_returned_usd)}</span></div>
<div class="col-span-2">Returned Values: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.value_returned_mxn)}</span></div>
</div>
<div class="grid grid-cols-2 gap-2 text-xs pt-2 border-t">
<div class="font-semibold">WEIGHTS (KILOS)</div>
<div class="font-semibold">WEIGHTS (Pounds)</div>
<div>Net: <span class="text-gray-900 dark:text-gray-100">{quantities.net_weight?.toFixed(8) || '0.00000000'}</span></div>
<div>Net: <span class="text-gray-900 dark:text-gray-100">{formatNumber(quantities.net_weight)}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">0.00000000</span></div>
<div>Whole: <span class="text-gray-900 dark:text-gray-100">{quantities.gross_weight?.toFixed(8) || '0.00000000'}</span></div>
<div>Whole: <span class="text-gray-900 dark:text-gray-100">{formatNumber(quantities.gross_weight)}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">0.00000000</span></div>
</div>
</fieldset>
@@ -33,13 +39,13 @@
<div class="grid grid-cols-2 gap-2 text-xs">
<div class="font-semibold">(Dollars)</div>
<div class="font-semibold">(Pesos)</div>
<div>Cost: <span class="text-gray-900 dark:text-gray-100">{financials.unit_cost_usd?.toFixed(8) || '0.00000000'}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">{financials.unit_cost_mxn?.toFixed(8) || '0.00000000'}</span></div>
<div>Value: <span class="text-gray-900 dark:text-gray-100">{financials.value_usd?.toFixed(8) || '0.00000000'}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">{financials.value_mxn?.toFixed(8) || '0.00000000'}</span></div>
<div class="text-xs">Capture Cost: <span class="text-gray-900 dark:text-gray-100">{financials.unit_cost_capture?.toFixed(8) || '0.00000000'}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
<div class="text-xs">Capture Value: <span class="text-gray-900 dark:text-gray-100">{financials.value_usd?.toFixed(8) || '0.00000000'}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
<div class="text-xs">Customs Value: <span class="text-gray-900 dark:text-gray-100">{financials.customs_value_usd?.toFixed(8) || '0.00000000'}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
<div>Cost: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.unit_cost_usd)}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.unit_cost_mxn)}</span></div>
<div>Value: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.value_usd)}</span></div>
<div><span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.value_mxn)}</span></div>
<div class="text-xs">Capture Cost: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.unit_cost_capture)}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
<div class="text-xs">Capture Value: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.value_usd)}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
<div class="text-xs">Customs Value: <span class="text-gray-900 dark:text-gray-100">{formatNumber(financials.customs_value_usd)}</span> <span class="text-gray-900 dark:text-gray-100">USD</span></div>
</div>
</fieldset>
</div>