feature/correccion-de-carga-csv-falta-de-datos-fk
This commit is contained in:
@@ -69,9 +69,10 @@ def apply_calculations(
|
||||
|
||||
line.depreciation_date = invoice_date
|
||||
|
||||
if (not line.description.description_spanish and not line.description.description_english) and (line.part_info.description_spanish and line.part_info.description_english):
|
||||
line.description.description_spanish = line.part_info.description_spanish
|
||||
line.description.description_english = line.part_info.description_english
|
||||
part_info = getattr(line, "part_info", None)
|
||||
if (not line.description.description_spanish and not line.description.description_english) and part_info and (part_info.description_spanish and part_info.description_english):
|
||||
line.description.description_spanish = part_info.description_spanish
|
||||
line.description.description_english = part_info.description_english
|
||||
else:
|
||||
if not line.description.description_spanish:
|
||||
class_desc = (
|
||||
@@ -184,10 +185,14 @@ def calculate_values(
|
||||
|
||||
# ==========================================
|
||||
# CÁLCULOS DE VALORES EN MONEDA
|
||||
# foreign=ME, local=MN, manual=MC
|
||||
# Una sola fuente: currency_type (USD/ME, MXN/MN) cuando está presente, paridad con import y CSV.
|
||||
# ==========================================
|
||||
result = (
|
||||
db.query(InvoiceFinancials.currency, InvoiceFinancials.exchange_rate)
|
||||
db.query(
|
||||
InvoiceFinancials.currency,
|
||||
InvoiceFinancials.currency_type,
|
||||
InvoiceFinancials.exchange_rate,
|
||||
)
|
||||
.filter(
|
||||
InvoiceFinancials.invoice_id == line.invoice_id,
|
||||
InvoiceFinancials.tenant_id == tenant_id,
|
||||
@@ -198,23 +203,27 @@ def calculate_values(
|
||||
if not result:
|
||||
return
|
||||
|
||||
currency, exchange_rate = result
|
||||
currency, currency_type, exchange_rate = result
|
||||
if currency_type in ("USD", "ME"):
|
||||
currency = "foreign"
|
||||
elif currency_type in ("MXN", "MN"):
|
||||
currency = "local"
|
||||
|
||||
if currency == "foreign": # ME
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture * exchange_rate
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture * (exchange_rate or 1)
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
elif currency == "local": # MN
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / exchange_rate
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / (exchange_rate or 1)
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
elif currency == "manual": # MC
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / exchange_rate
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / (exchange_rate or 1)
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_usd * exchange_rate
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_usd * (exchange_rate or 1)
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_capture * line.quantity.quantity
|
||||
|
||||
@@ -17,6 +17,17 @@ from api.v1.modules.public.reference_data.payment_methods.models import PaymentM
|
||||
from .common import validate_common
|
||||
|
||||
|
||||
def _normalize_weight_type(logistics) -> str:
|
||||
"""Paridad con CSV: enum o string a 'KGS'/'LBS' para comparaciones."""
|
||||
if logistics is None:
|
||||
return "KGS"
|
||||
wt = getattr(logistics, "weight_type", None) or "KGS"
|
||||
if hasattr(wt, "value"):
|
||||
wt = wt.value
|
||||
weight_str = str(wt).upper() if wt else "KGS"
|
||||
return weight_str if weight_str in ("KGS", "LBS") else "KGS"
|
||||
|
||||
|
||||
def validate_create(
|
||||
db: Session,
|
||||
line: LineItem,
|
||||
@@ -212,16 +223,28 @@ def validate_create(
|
||||
line.financial.value_temp_material_usd = line.financial.value_usd
|
||||
line.financial.value_temp_material_mxn = line.financial.value_mxn
|
||||
|
||||
# value_mc: paridad con calculate_values y cargas CSV
|
||||
currency = getattr(invoice.financials, "currency", None)
|
||||
if currency == "foreign":
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
elif currency == "local":
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
elif currency == "manual":
|
||||
line.financial.value_mc = unit_cost_capture * quantity
|
||||
else:
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
|
||||
# ==========================================
|
||||
# VALIDAR Y CONVERTIR PESOS NETOS
|
||||
# ==========================================
|
||||
invoice_weight_type = invoice.logistics.weight_type # 'kgs' o 'lbs'
|
||||
invoice_weight_type = _normalize_weight_type(invoice.logistics)
|
||||
quantity = line.quantity.quantity or Decimal("0")
|
||||
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 == "24" #KGS
|
||||
unit_is_lbs = line.unit_of_measure and line.unit_of_measure == "25" #LBS
|
||||
# UOM peso: aceptar 24/"24" y 25/"25" (paridad con CSV)
|
||||
uom = line.unit_of_measure
|
||||
unit_is_kgs = uom is not None and (str(uom) == "24" or uom == 24)
|
||||
unit_is_lbs = uom is not None and (str(uom) == "25" or uom == 25)
|
||||
|
||||
# Calcular peso neto en kilogramos (estándar interno)
|
||||
if unit_is_kgs:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from api.v1.modules.a76.invoices.models import InvoiceFinancials, InvoiceHeader, InvoiceLogistics
|
||||
from api.v1.modules.a76.invoices.models import InvoiceFinancials, InvoiceHeader
|
||||
from core.exceptions import ErrorCollector
|
||||
|
||||
from ...models import LineItem
|
||||
from ...models import LineItem
|
||||
from api.v1.modules.a76.classes.models import Class
|
||||
|
||||
@@ -13,57 +12,97 @@ def apply_calculations(
|
||||
#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
|
||||
caluclate_values(db, line, tenant_id, company_id)
|
||||
|
||||
if not line.fa_data.is_subitem:
|
||||
line.fa_data.subitem_number = None
|
||||
|
||||
invoice_date = db.query(InvoiceHeader.invoice_date).filter(InvoiceHeader.id == line.invoice_id, InvoiceHeader.tenant_id == tenant_id, InvoiceHeader.company_id == company_id).scalar()
|
||||
|
||||
line.depreciation_date = invoice_date
|
||||
|
||||
if (not line.description.description_spanish and not line.description.description_english) and (line.part_info.description_spanish and line.part_info.description_english):
|
||||
line.description.description_spanish = line.part_info.description_spanish
|
||||
line.description.description_english = line.part_info.description_english
|
||||
else:
|
||||
if not line.description.description_spanish:
|
||||
class_desc = (
|
||||
db.query(Class.description_es, Class.description_en)
|
||||
.filter(Class.id == line.class_id, Class.tenant_id == tenant_id, Class.company_id == company_id)
|
||||
.first()
|
||||
)
|
||||
if class_desc:
|
||||
line.description.description_spanish, line.description.description_english = class_desc
|
||||
|
||||
calculate_values(db, line, tenant_id, company_id)
|
||||
apply_calculations_after_values(db, line, tenant_id, company_id, line_number)
|
||||
|
||||
def caluclate_values(
|
||||
|
||||
def apply_calculations_after_values(
|
||||
db: Session, line: LineItem, tenant_id: int, company_id: int, line_number: int
|
||||
):
|
||||
"""
|
||||
Aplica solo depreciation_date, descripción desde part/class y subitem_number.
|
||||
Usado por el flujo CSV para no sobrescribir los valores ya calculados por currency_type.
|
||||
"""
|
||||
fa_data = getattr(line, "fa_data", None)
|
||||
if fa_data is not None and not getattr(fa_data, "is_subitem", True):
|
||||
fa_data.subitem_number = None
|
||||
|
||||
invoice_date = db.query(InvoiceHeader.invoice_date).filter(
|
||||
InvoiceHeader.id == line.invoice_id,
|
||||
InvoiceHeader.tenant_id == tenant_id,
|
||||
InvoiceHeader.company_id == company_id,
|
||||
).scalar()
|
||||
if invoice_date is not None:
|
||||
line.depreciation_date = invoice_date
|
||||
|
||||
if not getattr(line.description, "description_spanish", None) and not getattr(
|
||||
line.description, "description_english", None
|
||||
):
|
||||
part_info = getattr(line, "part_info", None)
|
||||
if part_info and getattr(part_info, "description_spanish", None) and getattr(part_info, "description_english", None):
|
||||
line.description.description_spanish = part_info.description_spanish
|
||||
line.description.description_english = part_info.description_english
|
||||
else:
|
||||
if not getattr(line.description, "description_spanish", None):
|
||||
class_desc = (
|
||||
db.query(Class.description_es, Class.description_en)
|
||||
.filter(
|
||||
Class.id == line.class_id,
|
||||
Class.tenant_id == tenant_id,
|
||||
Class.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if class_desc:
|
||||
line.description.description_spanish, line.description.description_english = class_desc
|
||||
|
||||
|
||||
def calculate_values(
|
||||
db: Session, line: LineItem, tenant_id: int, company_id: int
|
||||
):
|
||||
"""
|
||||
Una sola fuente de verdad: usa currency_type (USD/ME, MXN/MN) cuando está presente,
|
||||
para paridad con create.py y cargas CSV. Si no hay currency_type, usa currency (foreign/local/manual).
|
||||
"""
|
||||
result = (
|
||||
db.query(InvoiceFinancials.currency, InvoiceFinancials.exchange_rate)
|
||||
.filter(InvoiceFinancials.invoice_id == line.invoice_id, InvoiceFinancials.tenant_id == tenant_id, InvoiceFinancials.company_id == company_id)
|
||||
db.query(
|
||||
InvoiceFinancials.currency,
|
||||
InvoiceFinancials.currency_type,
|
||||
InvoiceFinancials.exchange_rate,
|
||||
)
|
||||
.filter(
|
||||
InvoiceFinancials.invoice_id == line.invoice_id,
|
||||
InvoiceFinancials.tenant_id == tenant_id,
|
||||
InvoiceFinancials.company_id == company_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not result:
|
||||
return
|
||||
|
||||
currency, exchange_rate = result
|
||||
currency, currency_type, exchange_rate = result
|
||||
# Prioridad: currency_type para alinear con create.py y CSV
|
||||
if currency_type in ("USD", "ME"):
|
||||
currency = "foreign"
|
||||
elif currency_type in ("MXN", "MN"):
|
||||
currency = "local"
|
||||
# si currency_type es otro o None, se usa currency tal cual
|
||||
|
||||
if currency == "foreign":
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture * exchange_rate
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture * (exchange_rate or 1)
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
elif currency == "local":
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_capture
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / exchange_rate
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / (exchange_rate or 1)
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
elif currency == "manual":
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture/exchange_rate
|
||||
line.financial.unit_cost_usd = line.financial.unit_cost_capture / (exchange_rate or 1)
|
||||
line.financial.value_usd = line.financial.unit_cost_usd * line.quantity.quantity
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_usd * exchange_rate
|
||||
line.financial.unit_cost_mxn = line.financial.unit_cost_usd * (exchange_rate or 1)
|
||||
line.financial.value_mxn = line.financial.unit_cost_mxn * line.quantity.quantity
|
||||
line.financial.value_mc = line.financial.unit_cost_capture * line.quantity.quantity
|
||||
@@ -16,6 +16,17 @@ from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models im
|
||||
from .common import validate_common
|
||||
|
||||
|
||||
def _normalize_weight_type(logistics) -> str:
|
||||
"""Paridad con CSV: enum o string a 'KGS'/'LBS' para comparaciones."""
|
||||
if logistics is None:
|
||||
return "KGS"
|
||||
wt = getattr(logistics, "weight_type", None) or "KGS"
|
||||
if hasattr(wt, "value"):
|
||||
wt = wt.value
|
||||
weight_str = str(wt).upper() if wt else "KGS"
|
||||
return weight_str if weight_str in ("KGS", "LBS") else "KGS"
|
||||
|
||||
|
||||
def validate_create(
|
||||
db: Session,
|
||||
line: LineItem,
|
||||
@@ -196,16 +207,28 @@ def validate_create(
|
||||
line.financial.value_temp_material_usd = line.financial.value_usd
|
||||
line.financial.value_temp_material_mxn = line.financial.value_mxn
|
||||
|
||||
# value_mc: paridad con calculate_values y cargas CSV
|
||||
currency = getattr(invoice.financials, "currency", None)
|
||||
if currency == "foreign":
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
elif currency == "local":
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
elif currency == "manual":
|
||||
line.financial.value_mc = unit_cost_capture * quantity
|
||||
else:
|
||||
line.financial.value_mc = line.financial.value_usd
|
||||
|
||||
# ==========================================
|
||||
# VALIDAR Y CONVERTIR PESOS NETOS
|
||||
# ==========================================
|
||||
invoice_weight_type = invoice.logistics.weight_type # 'kgs' o 'lbs'
|
||||
invoice_weight_type = _normalize_weight_type(invoice.logistics)
|
||||
quantity = line.quantity.quantity or Decimal("0")
|
||||
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 == "24" #KGS
|
||||
unit_is_lbs = line.unit_of_measure and line.unit_of_measure == "25" #LBS
|
||||
# UOM peso: aceptar 24/"24" y 25/"25" (paridad con CSV)
|
||||
uom = line.unit_of_measure
|
||||
unit_is_kgs = uom is not None and (str(uom) == "24" or uom == 24)
|
||||
unit_is_lbs = uom is not None and (str(uom) == "25" or uom == 25)
|
||||
|
||||
# Calcular peso neto en kilogramos (estándar interno)
|
||||
if unit_is_kgs:
|
||||
|
||||
Reference in New Issue
Block a user