From db85b91549ce384fe7c31c174a87671a6154c6e6 Mon Sep 17 00:00:00 2001 From: acazares Date: Wed, 11 Feb 2026 14:30:10 -0600 Subject: [PATCH] feat: enhance item validation by adding checks for valuation method and part number existence --- .../imports/temporary/validators/common.py | 65 ++++++++++++++++--- .../modules/a76/items/line_items/schemas.py | 1 + 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/backend/api/v1/modules/a76/items/imports/temporary/validators/common.py b/backend/api/v1/modules/a76/items/imports/temporary/validators/common.py index 4eb6983b..d3354506 100644 --- a/backend/api/v1/modules/a76/items/imports/temporary/validators/common.py +++ b/backend/api/v1/modules/a76/items/imports/temporary/validators/common.py @@ -1,7 +1,7 @@ import logging from typing import Optional, List, Tuple from fastapi import HTTPException -from sqlalchemy import and_, or_ +from sqlalchemy import and_, exists, or_ from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session, joinedload from api.v1.modules.a76.invoices.common.common_validators import invoice_exists @@ -25,6 +25,8 @@ from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMe from api.v1.modules.a76.general_catalogs.packages.models import Package from api.v1.modules.public.reference_data.countries.models import Country from api.v1.modules.public.reference_data.sectors.models import Sector +from api.v1.modules.public.reference_data.valuation_methods.models import ValuationMethod +from api.v1.modules.a76.parts.models import Part from api.v1.modules.a76.general_catalogs.company.models import Company def validate_common( @@ -35,11 +37,13 @@ def validate_common( errors: ErrorCollector, line_number: int, ): + item_header = db.query(Item).filter(Item.id == line.item_id).first() + invoice: InvoiceHeader = invoice_exists( - db, line.invoice_id, tenant_id, company_id, errors + db, item_header.invoice_id, tenant_id, company_id, errors ) line_item: LineItem = item_exists( - db, line.invoice_id, line.line_item, tenant_id, company_id + db, item_header.invoice_id, line.line_number, tenant_id, company_id ) fecha_factura = invoice.invoice_date if invoice else None @@ -245,9 +249,7 @@ def validate_common( sector_db: Sector = ( db.query(Sector) .filter( - Class.sector_code == sector, - Class.tenant_id == tenant_id, - Class.company_id == company_id, + Sector.key == sector ) .scalar() ) @@ -277,6 +279,53 @@ def validate_common( ) if fraction: - search_fraction_preference() + search_fraction_preference(db=db, country=country, fraccion=fraction, fraction_type=fraction_type, sector=sector, invoice_date=fecha_factura, errors=errors) - \ No newline at end of file + if line.customs.american_fraction: + american_fraction_exists = db.query(exists().where(LineCustom.american_fraction == line.customs.american_fraction)).scalar() + if not american_fraction_exists: + errors.add_error( + field=f"line[{line_number}].customs.american_fraction", + message="La fracción americana especificada no existe.", + solution=["Proporciona una fracción americana valida."], + code="AMERICAN_FRACTION_NOT_FOUND", + ) + + if item_header and item_header.order: + if len(item_header.order) > 20: + errors.add_error( + field=f"item.order", + message="El campo orden no debe exceder los 20 caracteres.", + solution=["Proporciona un valor valido para el campo orden."], + code="ORDER_EXCEEDS_MAX_LENGTH", + ) + + unit_of_measure = line.unit_of_measure or (class_.unit_of_measure if class_ else None) + if unit_of_measure == "PZA" and line.quantity.quantity % 1 != 0: + errors.add_error( + field=f"line[{line_number}].quantity.quantity", + message="La cantidad debe ser un número entero cuando la unidad de medida es PZA.", + solution=["Proporciona una cantidad entera."], + code="QUANTITY_MUST_BE_INTEGER_FOR_PIECES", + ) + + if line.valuation_method: + valuation_method_exists = db.query(exists().where(ValuationMethod.key == line.valuation_method)).scalar() + if not valuation_method_exists: + errors.add_error( + field=f"line[{line_number}].valuation_method", + message="El método de valoración especificado no existe.", + solution=["Proporciona un método de valoración valido."], + code="VALUATION_METHOD_NOT_FOUND", + ) + + if line.part_number_id: + part_exists = db.query(exists().where(Part.id == line.part_number_id)).scalar() + if not part_exists: + errors.add_error( + field=f"line[{line_number}].part_number_id", + message="El número de parte especificado no existe.", + solution=["Proporciona un número de parte valido."], + code="PART_NUMBER_NOT_FOUND", + ) + \ No newline at end of file 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 5c23910a..5ed01795 100644 --- a/backend/api/v1/modules/a76/items/line_items/schemas.py +++ b/backend/api/v1/modules/a76/items/line_items/schemas.py @@ -46,6 +46,7 @@ class LineItemBase(BaseModel): model_config = ConfigDict(populate_by_name=True) + item_id: int = Field(..., description="ID of the parent item") line_number: int = Field(..., description="Line number") # Part identification