feat: enhance item creation validation by adding checks for subitem existence and required fields

This commit is contained in:
2026-02-11 17:03:25 -06:00
parent db85b91549
commit f8c38d998d
2 changed files with 91 additions and 9 deletions

View File

@@ -1,3 +1,4 @@
from sqlalchemy import func
from core.exceptions import ErrorCollector
from ..line_items import models
from sqlalchemy.orm import Session
@@ -22,4 +23,18 @@ def item_exists(
if item_exists:
return item_exists
return None
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

View File

@@ -1,10 +1,6 @@
import logging
from typing import Optional, List, Tuple
from fastapi import HTTPException
from sqlalchemy import and_, or_
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session, joinedload
from api.v1.modules.a76.invoices.common.common_validators import invoice_exists
from sqlalchemy import func, exists
from sqlalchemy.orm import Session
from ....common.common_validators import count_items
from core.exceptions import ErrorCollector
from ....line_items.models import LineItem
@@ -21,10 +17,81 @@ from .common import validate_common
def validate_create(
db: Session,
line: Item,
line: LineItem,
tenant_id: int,
company_id: int,
errors: ErrorCollector,
line_number: int,
):
item_header: Item = db.query(Item).filter(Item.id == line.item_id).first()
fa_line: FaLineItem = db.query(FaLineItem).filter(FaLineItem.id == line.id).first()
if not line.class_id:
errors.add_required_error(field=f"line[{line_number}].class_id")
if not line.quantity.quantity or line.quantity.quantity <= 0:
errors.add_required_error(field=f"line[{line_number}].quantity.quantity")
# TODO: Añadir validacion SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf <-- de la tabla de preferencias de el sistema
# if SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf == False:
if not fa_line.is_subitem and (
not line.financial.unit_cost_capture and line.financial.unit_cost_capture <= 0
):
errors.add_required_error(
field=f"line[{line_number}].financial.unit_cost_capture"
)
if not line.quantity.net_weight or line.quantity.net_weight <= 0:
errors.add_required_error(field=f"line[{line_number}].quantity.net_weight")
if not line.customs.origin_country:
errors.add_required_error(field=f"line[{line_number}].customs.origin_country")
if not line.customs.fraction_type:
errors.add_required_error(field=f"line[{line_number}].customs.fraction_type")
if (
fa_line.is_subitem and fa_line.contains_subitems
) and not fa_line.subitem_number:
errors.add_required_error(field=f"line[{line_number}].subitem_number")
errors.raise_if_errors()
# Validar que si es un subitem, existe un item principal correspondiente
if fa_line.is_subitem and fa_line.subitem_number != 0:
principal_item_exists = db.query(
exists().where(
(LineItem.id == FaLineItem.id)
& (LineItem.item_id == item_header.id)
& (LineItem.line_number == line_number)
& (FaLineItem.is_subitem == False)
& (FaLineItem.contains_subitems == True)
& (LineItem.tenant_id == tenant_id)
& (LineItem.company_id == company_id)
)
).scalar()
if not principal_item_exists:
errors.add_error(
field=f"line[{line_number}]",
message=f"No existe un item principal registrado para esta linea {line_number} con subitem {fa_line.subitem_number}",
solution=[
"Registrar el item principal correspondiente a esta linea antes de registrar subitems."
],
code="SUBITEM_WITHOUT_PRINCIPAL_ITEM",
)
if fa_line.is_subitem and (fa_line.subitem_number == 0 or not fa_line.subitem_number):
errors.add_error(
field=f"line[{line_number}]",
message=f"El número de subitem no puede ser 0 si la línea es un subitem.",
solution=[
"Asignar un número de subitem mayor a 0 para esta línea."
],
code="SUBITEM_NUMBER_INVALID",
)
validate_common(db, line, tenant_id, company_id, errors, line_number)
if not errors.has_errors():
pass