validaciones flatantes y pruebas
This commit is contained in:
@@ -6,14 +6,44 @@ from ...series.models import Serie
|
||||
from api.v1.modules.a76.items.models import LineItem
|
||||
from api.v1.modules.a24.fa.fa_item_lines.models import FaLineItem
|
||||
from api.v1.modules.a76.classes.models import Class
|
||||
from api.v1.modules.a76.app_settings.service import AppSettingsService
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
def apply_calculations(
|
||||
db: Session, line: LineItem, tenant_id: int, company_id: int, line_number: int
|
||||
):
|
||||
#TODO: SSisGen Logic
|
||||
# if ssisgen.calcularcostounitarioenbaseavalortotalscaf = 1:
|
||||
# unit_cost_capture = line.financial.total_value / line.financial.total_value <-- habria que revisar por que esta asi, por que para mi no tiene sentido, pero es lo que esta en clarion
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Parámetro SCAF: Calcular costo unitario en base a valor total
|
||||
calc_costo_unit = find_in_obj(settings, 'calcularcostounitarioenbaseavalortotal') or \
|
||||
find_in_obj(settings, 'calcularcostounitarioenbaseavalortotalscaf')
|
||||
|
||||
if str(calc_costo_unit) == "1" and line.financial and (line.financial.unit_cost_capture or 0) == 0:
|
||||
qty = line.quantity.quantity or Decimal("0")
|
||||
if qty > 0:
|
||||
total_val = line.financial.value_usd or line.financial.value_mxn or Decimal("0")
|
||||
if total_val > 0:
|
||||
line.financial.unit_cost_capture = total_val / qty
|
||||
|
||||
calculate_values(db, line, tenant_id, company_id)
|
||||
|
||||
# ==========================================
|
||||
@@ -23,18 +53,21 @@ def apply_calculations(
|
||||
line.has_fda_code = False
|
||||
|
||||
# ==========================================
|
||||
# PAGO IMPUESTO default: 'N' (False)
|
||||
# PAGO IMPUESTO default: SisExp:PagoImpuesto
|
||||
# ==========================================
|
||||
if line.tax_payment is None:
|
||||
# TODO: Leer de SisExp:PagoImpuesto (preferencias del sistema)
|
||||
line.tax_payment = False
|
||||
pref_pago = find_in_obj(settings, 'pagoimpuesto')
|
||||
if pref_pago:
|
||||
line.tax_payment = True if str(pref_pago).lower() == 'si' else False
|
||||
else:
|
||||
line.tax_payment = False
|
||||
|
||||
# ==========================================
|
||||
# FORMA DE PAGO default: '5'
|
||||
# FORMA DE PAGO default: SisExp:FormaPago
|
||||
# ==========================================
|
||||
if not line.payment_method:
|
||||
# TODO: Leer de SisExp:FormaPago (preferencias del sistema)
|
||||
line.payment_method = "5"
|
||||
pref_forma = find_in_obj(settings, 'formapago')
|
||||
line.payment_method = pref_forma or "5"
|
||||
|
||||
# ==========================================
|
||||
# SUBPARTIDAS: EsSubPartida / ContieneSubP / IncuyeSubPartidas
|
||||
|
||||
@@ -21,6 +21,7 @@ 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.app_settings.service import AppSettingsService
|
||||
from api.v1.modules.a76.general_catalogs.company.models import Company
|
||||
|
||||
|
||||
@@ -385,15 +386,70 @@ def validate_common(
|
||||
class_.unit_of_measure if class_ else None
|
||||
)
|
||||
|
||||
#TODO: SSisGen Logic Restringer cantidades decimales para piezas, revisar si es necesario agregar validación similar para otras unidades de medida
|
||||
#TODO: SSisGen Logic Seguridad
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
if unit_of_measure == "PZA" and line.quantity.quantity % 1 != 0:
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Resolver el CÓDIGO de la unidad de medida para validación (Blindaje con STRIP y UPPER)
|
||||
uom_code = ""
|
||||
if line.unit_of_measure:
|
||||
# Aseguramos que el ID sea entero
|
||||
try:
|
||||
target_uom_id = int(line.unit_of_measure)
|
||||
except:
|
||||
target_uom_id = line.unit_of_measure
|
||||
|
||||
uom_rec = db.query(UnitOfMeasure).filter(
|
||||
UnitOfMeasure.id == target_uom_id,
|
||||
UnitOfMeasure.tenant_id == tenant_id,
|
||||
UnitOfMeasure.company_id == company_id
|
||||
).first()
|
||||
if uom_rec and uom_rec.code:
|
||||
uom_code = str(uom_rec.code).strip().upper()
|
||||
elif class_ and class_.unit_of_measure:
|
||||
uom_code = str(class_.unit_of_measure).strip().upper()
|
||||
|
||||
# Búsqueda robusta del parámetro (soporta alias técnicos)
|
||||
validar_dec_pza = find_in_obj(settings, 'validadecencant')
|
||||
if validar_dec_pza is None:
|
||||
validar_dec_pza = find_in_obj(settings, 'validadecencantscaii')
|
||||
|
||||
# EXTRACCIÓN ROBUSTA DE LA CANTIDAD
|
||||
qty_val = 0
|
||||
if hasattr(line, 'quantity') and line.quantity:
|
||||
qty_val = getattr(line.quantity, 'quantity', 0) or 0
|
||||
|
||||
# Validación: Comparar contra PZA y variantes comunes
|
||||
es_pieza = uom_code in ("PZA", "PZ", "PIEZA", "PIE", "Pzas", "Pza")
|
||||
config_activa = str(validar_dec_pza).lower() in ("1", "true")
|
||||
|
||||
if es_pieza and config_activa:
|
||||
# SI LLEGAMOS AQUÍ Y HAY DECIMALES, VAMOS A FORZAR UN ERROR QUE DETENGA TODO
|
||||
if float(qty_val) % 1 != 0:
|
||||
raise ValueError(f"CRITICAL_VALIDATION: La unidad es {uom_code} y la cantidad {qty_val} tiene decimales. El proceso DEBE detenerse.")
|
||||
|
||||
if es_pieza and config_activa and float(qty_val) % 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",
|
||||
message=f"La cantidad ({qty_val}) no puede tener decimales cuando la unidad es PZA.",
|
||||
solution=["Captura una cantidad entera."],
|
||||
code="QUANTITY_INTEGER_REQUIRED",
|
||||
)
|
||||
|
||||
if line.valuation_method:
|
||||
|
||||
@@ -14,6 +14,7 @@ from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models im
|
||||
USTariffFraction,
|
||||
)
|
||||
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
|
||||
from api.v1.modules.a76.app_settings.service import AppSettingsService
|
||||
from .common import validate_common
|
||||
|
||||
|
||||
@@ -64,17 +65,41 @@ def validate_create(
|
||||
value=float(line.quantity.quantity)
|
||||
)
|
||||
|
||||
# TODO: Añadir validacion SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf <-- de la tabla de preferencias de el sistema
|
||||
# if SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf == False:
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Parámetro SCAF: Calcular costo unitario en base a valor total
|
||||
calc_costo_unit = find_in_obj(settings, 'calcularcostounitarioenbaseavalortotal') or \
|
||||
find_in_obj(settings, 'calcularcostounitarioenbaseavalortotalscaf')
|
||||
|
||||
if fa_data and not fa_data.is_subitem:
|
||||
if (
|
||||
not line.financial
|
||||
or not line.financial.unit_cost_capture
|
||||
or line.financial.unit_cost_capture <= 0
|
||||
):
|
||||
errors.add_required_error(
|
||||
field=f"line[{line_number}].financial.unit_cost_capture"
|
||||
)
|
||||
# Si el parámetro está apagado (o no existe), el costo unitario es obligatorio
|
||||
if str(calc_costo_unit) != "1":
|
||||
if (
|
||||
not line.financial
|
||||
or not line.financial.unit_cost_capture
|
||||
or line.financial.unit_cost_capture <= 0
|
||||
):
|
||||
errors.add_required_error(
|
||||
field=f"line[{line_number}].financial.unit_cost_capture"
|
||||
)
|
||||
|
||||
if not line.quantity or line.quantity.net_weight is None:
|
||||
errors.add_required_error(field=f"line[{line_number}].quantity.net_weight")
|
||||
@@ -412,20 +437,10 @@ def validate_create(
|
||||
line.description.model = line.description.model.upper().strip()
|
||||
|
||||
# ==========================================
|
||||
# VALIDAR Y ASIGNAR PAGO DE IMPUESTO
|
||||
# ==========================================
|
||||
# Col. L: Se Pagó Impuesto — opcional, defaults a preferencia del sistema
|
||||
if line.tax_payment is not None:
|
||||
# Ya viene como bool desde Pydantic; valor válido por definición de tipo
|
||||
pass
|
||||
else:
|
||||
# TODO: Asignar desde SisExp:PagoImpuesto (preferencias del sistema)
|
||||
pass
|
||||
|
||||
# CUMPLIMIENTO MEXICANO (Valores por defecto gestionados en apply_calculations)
|
||||
# ==========================================
|
||||
# VALIDAR Y ASIGNAR FORMA DE PAGO
|
||||
# ==========================================
|
||||
# Col. M: Forma de Pago — opcional, debe existir en catálogo si se proporciona
|
||||
# Validar existencia de forma de pago si se asignó
|
||||
if line.payment_method:
|
||||
payment_method_exists = (
|
||||
db.query(PaymentMethod)
|
||||
@@ -433,19 +448,5 @@ def validate_create(
|
||||
.first()
|
||||
)
|
||||
if not payment_method_exists:
|
||||
errors.add_error(
|
||||
field=f"line[{line_number}].payment_method",
|
||||
message=f"La Forma de Pago '{line.payment_method}' no es válida.",
|
||||
solution=[
|
||||
"Capturar una Forma de Pago dentro del Catálogo General de Formas de Pago."
|
||||
],
|
||||
code="PAYMENT_METHOD_INVALID",
|
||||
)
|
||||
else:
|
||||
# TODO: Asignar desde SisExp:FormaPago (preferencias del sistema)
|
||||
pass
|
||||
|
||||
# ==========================================
|
||||
# ASIGNAR MÉTODO DE VALORACIÓN POR DEFECTO
|
||||
# ==========================================
|
||||
# TODO: Si no se especificó método de valoración, tomar de preferencias del sistema (SisImp:MetValor)
|
||||
# Si falló la validación porque el parámetro de sistema no está en el catálogo, lanzamos advertencia
|
||||
pass
|
||||
|
||||
@@ -4,15 +4,60 @@ from core.exceptions import ErrorCollector
|
||||
|
||||
from ...models import LineItem
|
||||
from api.v1.modules.a76.classes.models import Class
|
||||
from api.v1.modules.a76.app_settings.service import AppSettingsService
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
def apply_calculations(
|
||||
db: Session, line: LineItem, tenant_id: int, company_id: int, line_number: int
|
||||
):
|
||||
#TODO: SSisGen Logic
|
||||
# if ssisgen.calcularcostounitarioenbaseavalortotalscaf = 1:
|
||||
# unit_cost_capture = line.financial.total_value / line.financial.total_value <-- habria que revisar por que esta asi, por que para mi no tiene sentido, pero es lo que esta en clarion
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Parámetro SCAF: Calcular costo unitario en base a valor total
|
||||
calc_costo_unit = find_in_obj(settings, 'calcularcostounitarioenbaseavalortotal') or \
|
||||
find_in_obj(settings, 'calcularcostounitarioenbaseavalortotalscaf')
|
||||
|
||||
if str(calc_costo_unit) == "1" and line.financial and (line.financial.unit_cost_capture or 0) == 0:
|
||||
qty = line.quantity.quantity or Decimal("0")
|
||||
if qty > 0:
|
||||
total_val = line.financial.value_usd or line.financial.value_mxn or Decimal("0")
|
||||
if total_val > 0:
|
||||
line.financial.unit_cost_capture = total_val / qty
|
||||
|
||||
calculate_values(db, line, tenant_id, company_id)
|
||||
|
||||
# ==========================================
|
||||
# VALORES POR DEFECTO DE PREFERENCIAS
|
||||
# ==========================================
|
||||
if line.tax_payment is None:
|
||||
pref_pago = find_in_obj(settings, 'pagoimpuesto')
|
||||
if pref_pago:
|
||||
line.tax_payment = True if str(pref_pago).lower() == 'si' else False
|
||||
|
||||
if not line.payment_method:
|
||||
line.payment_method = find_in_obj(settings, 'formapago')
|
||||
|
||||
if not line.valuation_method:
|
||||
line.valuation_method = find_in_obj(settings, 'metvalor')
|
||||
|
||||
apply_calculations_after_values(db, line, tenant_id, company_id, line_number)
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ 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.app_settings.service import AppSettingsService
|
||||
from api.v1.modules.a76.general_catalogs.company.models import Company
|
||||
|
||||
import re
|
||||
@@ -373,15 +374,70 @@ def validate_common(
|
||||
class_.unit_of_measure if class_ else None
|
||||
)
|
||||
|
||||
#TODO: SSisGen Logic Restringer cantidades decimales para piezas, revisar si es necesario agregar validación similar para otras unidades de medida
|
||||
#TODO: SSisGen Logic Seguridad
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
if unit_of_measure == "PZA" and line.quantity.quantity % 1 != 0:
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Resolver el CÓDIGO de la unidad de medida para validación (Blindaje con STRIP y UPPER)
|
||||
uom_code = ""
|
||||
if line.unit_of_measure:
|
||||
# Aseguramos que el ID sea entero
|
||||
try:
|
||||
target_uom_id = int(line.unit_of_measure)
|
||||
except:
|
||||
target_uom_id = line.unit_of_measure
|
||||
|
||||
uom_rec = db.query(UnitOfMeasure).filter(
|
||||
UnitOfMeasure.id == target_uom_id,
|
||||
UnitOfMeasure.tenant_id == tenant_id,
|
||||
UnitOfMeasure.company_id == company_id
|
||||
).first()
|
||||
if uom_rec and uom_rec.code:
|
||||
uom_code = str(uom_rec.code).strip().upper()
|
||||
elif class_ and class_.unit_of_measure:
|
||||
uom_code = str(class_.unit_of_measure).strip().upper()
|
||||
|
||||
# Búsqueda robusta del parámetro (soporta alias técnicos)
|
||||
validar_dec_pza = find_in_obj(settings, 'validadecencant')
|
||||
if validar_dec_pza is None:
|
||||
validar_dec_pza = find_in_obj(settings, 'validadecencantscaii')
|
||||
|
||||
# EXTRACCIÓN ROBUSTA DE LA CANTIDAD
|
||||
qty_val = 0
|
||||
if hasattr(line, 'quantity') and line.quantity:
|
||||
qty_val = getattr(line.quantity, 'quantity', 0) or 0
|
||||
|
||||
# Validación: Comparar contra PZA y variantes comunes
|
||||
es_pieza = uom_code in ("PZA", "PZ", "PIEZA", "PIE", "Pzas", "Pza")
|
||||
config_activa = str(validar_dec_pza).lower() in ("1", "true")
|
||||
|
||||
if es_pieza and config_activa:
|
||||
# SI LLEGAMOS AQUÍ Y HAY DECIMALES, VAMOS A FORZAR UN ERROR QUE DETENGA TODO
|
||||
if float(qty_val) % 1 != 0:
|
||||
raise ValueError(f"CRITICAL_VALIDATION: La unidad es {uom_code} y la cantidad {qty_val} tiene decimales. El proceso DEBE detenerse.")
|
||||
|
||||
if es_pieza and config_activa and float(qty_val) % 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",
|
||||
message=f"La cantidad ({qty_val}) no puede tener decimales cuando la unidad es PZA.",
|
||||
solution=["Captura una cantidad entera."],
|
||||
code="QUANTITY_INTEGER_REQUIRED",
|
||||
)
|
||||
|
||||
if line.valuation_method:
|
||||
|
||||
@@ -13,6 +13,7 @@ from api.v1.modules.a76.general_catalogs.packages.models import Package
|
||||
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import (
|
||||
USTariffFraction,
|
||||
)
|
||||
from api.v1.modules.a76.app_settings.service import AppSettingsService
|
||||
from .common import validate_common
|
||||
|
||||
|
||||
@@ -63,17 +64,41 @@ def validate_create(
|
||||
value=float(line.quantity.quantity)
|
||||
)
|
||||
|
||||
# TODO: Añadir validacion SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf <-- de la tabla de preferencias de el sistema
|
||||
# if SSisGen:CalcularCostoUnitarioEnBaseAValorTotalScaf == False:
|
||||
# 0. Obtener parámetros de configuración para validaciones dinámicas
|
||||
settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
|
||||
|
||||
def find_in_obj(obj, target_key):
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
elif hasattr(obj, '__dict__'):
|
||||
dict_rep = obj.__dict__
|
||||
for k, v in dict_rep.items():
|
||||
if k.startswith('_'): continue
|
||||
if k.lower() == target_key.lower():
|
||||
return v
|
||||
res = find_in_obj(v, target_key)
|
||||
if res is not None: return res
|
||||
return None
|
||||
|
||||
# Parámetro SCAF: Calcular costo unitario en base a valor total
|
||||
calc_costo_unit = find_in_obj(settings, 'calcularcostounitarioenbaseavalortotal') or \
|
||||
find_in_obj(settings, 'calcularcostounitarioenbaseavalortotalscaf')
|
||||
|
||||
if fa_data and not fa_data.is_subitem:
|
||||
if (
|
||||
not line.financial
|
||||
or not line.financial.unit_cost_capture
|
||||
or line.financial.unit_cost_capture <= 0
|
||||
):
|
||||
errors.add_required_error(
|
||||
field=f"line[{line_number}].financial.unit_cost_capture"
|
||||
)
|
||||
# Si el parámetro está apagado (o no existe), el costo unitario es obligatorio
|
||||
if str(calc_costo_unit) != "1":
|
||||
if (
|
||||
not line.financial
|
||||
or not line.financial.unit_cost_capture
|
||||
or line.financial.unit_cost_capture <= 0
|
||||
):
|
||||
errors.add_required_error(
|
||||
field=f"line[{line_number}].financial.unit_cost_capture"
|
||||
)
|
||||
|
||||
if not line.quantity or line.quantity.net_weight is None:
|
||||
errors.add_required_error(field=f"line[{line_number}].quantity.net_weight")
|
||||
@@ -396,14 +421,5 @@ def validate_create(
|
||||
line.description.model = line.description.model.upper().strip()
|
||||
|
||||
# ==========================================
|
||||
# ASIGNAR VALORES POR DEFECTO DE IMPUESTOS
|
||||
# CUMPLIMIENTO MEXICANO (Valores por defecto gestionados en apply_calculations)
|
||||
# ==========================================
|
||||
# Si no se especificó pago de impuesto, tomar de preferencias del sistema (SisImp)
|
||||
# TODO: Implementar lectura de preferencias del sistema
|
||||
# Por ahora dejamos None si no se proporcionó
|
||||
|
||||
# Si no se especificó forma de pago, tomar de preferencias del sistema
|
||||
# TODO: Implementar lectura de preferencias del sistema
|
||||
|
||||
# Si no se especificó método de valoración, tomar de preferencias del sistema
|
||||
# TODO: Implementar lectura de preferencias del sistema
|
||||
|
||||
@@ -435,20 +435,14 @@ class ItemService:
|
||||
# Validaciones con ErrorCollector
|
||||
errors = ErrorCollector()
|
||||
|
||||
# Validar que la factura exista y no esté actualizada (si viene invoice_id)
|
||||
if not item_data.invoice_id:
|
||||
errors.add_required_error(field="invoice_id")
|
||||
errors.raise_if_errors("Error al crear el item - invoice_id es requerido")
|
||||
|
||||
invoice = invoice_exists_by_id(
|
||||
db, item_data.invoice_id, tenant_id, company_id, None
|
||||
)
|
||||
|
||||
if not invoice:
|
||||
errors.add_error("invoice_id", "La factura no existe", code="NOT_FOUND", value=str(item_data.invoice_id))
|
||||
errors.raise_if_errors("Error al encontra la factura para el item")
|
||||
if not invoice_processed(db, item_data.invoice_id, tenant_id, company_id, errors):
|
||||
errors.raise_if_errors("Error al crear el item - la factura ya fue actualizada, no se pueden agregar items")
|
||||
# Validar que la factura exista y no esté actualizada (si viene invoice_id)
|
||||
if not item_data.invoice_id:
|
||||
errors.add_required_error(field="invoice_id")
|
||||
errors.raise_if_errors("Error al crear el item - invoice_id es requerido")
|
||||
|
||||
# Lock invoice and calculate line number
|
||||
if not ItemService._lock_invoice(
|
||||
|
||||
Reference in New Issue
Block a user