diff --git a/pipeline.py b/pipeline.py index 1725b33..bf3a7a7 100644 --- a/pipeline.py +++ b/pipeline.py @@ -33,7 +33,6 @@ CUADRO_VALOR_REFERENCIAL = { # ============================================================================ # HELPERS # ============================================================================ - def _ruta_carpeta(subcarpeta: str) -> str: return os.path.join(os.path.dirname(__file__), subcarpeta) @@ -618,18 +617,25 @@ def _procesar_un_correo(email: dict, token: str, email_addr: str, download_folde resultados = [] factura_lines = factura.get("lineas", []) + # listado de zonas para obtener su descripción zonas_raw = sapb1_manager.get_zonas() zonas = {z["Code"]: z["Name"] for z in zonas_raw} + for fl in factura_lines: + # por cada linea de factura se obtiene + # cantidad del xml de la factura cantidad = float(fl.get("cantidad", 0)) + # total de linea antes de impuesto del xml de la factura total_linea = float(fl.get("total_linea", 0) or 0) + # lista de guias asociadas a la linea de factura de xml o pdf guias = fl.get("guias_remision", []) + # dificil que la cantidad sea 0, pero esos casos los descartamos if cantidad == 0: resultados.append({"grflete": "-", "ok": False, "draft_price": None, "sap_price": None, "label": "Cantidad cero, sin validar", "warehouse_code": "-", "draft_cantidad": cantidad, "guias_lt": []}) continue - + # si no hay guia asociada, no se puede validar, lo descartamos if not guias: resultados.append({"grflete": "-", "ok": False, "draft_price": None, "sap_price": None, "label": "Sin guía de referencia", "warehouse_code": "-", "draft_cantidad": cantidad, "guias_lt": []}) continue @@ -638,12 +644,18 @@ def _procesar_un_correo(email: dict, token: str, email_addr: str, download_folde all_wh = set() all_ok = True + # una linea de la factura puede tener varias guias de remision + # hay que validar cada una de ellas for guia in guias: codigo_guia = f"{guia['tipo']}{guia['serie']}-{guia['numero']}" try: + # consulta a sap por cada guia de remision + # esto nos puede retornar 0, 1 o mas documentos + # lo ideal es que nos retorne 0 o 1 documento delivery_notes = sapb1_manager.get_delivery_notes( tipo=guia["serie"], serie=guia["tipo"], numero=guia["numero"] ) + # cantidad de documentos encontrados en sap print(f" │ 🔍 Guía {codigo_guia}: {len(delivery_notes)} documento(s) encontrado(s) en SAP") wh_set = set() @@ -653,23 +665,37 @@ def _procesar_un_correo(email: dict, token: str, email_addr: str, download_folde weight1 = 0.0 zona = "" + # recorremos cada documento encontrado for dn in delivery_notes: + # obtenemos la zona de destino del documento zona = zonas.get(dn.get("U_IDC_DESTINO",""),"") - + # obtenemos el almacen de la primera linea first_line = dn.get("DocumentLines", [None])[0] if first_line: wh = first_line.get("WarehouseCode", "") if wh: wh_set.add(wh) + + # obtenemos el peso de la primera linea de la guia de remision + # que representa el peso de la guia de remisión del articulo inventariable + # y lo vamos acumulando para obtener el peso total de la linea de la factura weight1 += float(first_line.get("Weight1", 0) or 0) + # recorremos cada linea del documento for linea_detalle_dict in dn.get("DocumentLines", []): + # solo procesamos lineas que empiecen con FL\d if not re.match(r"FL\d", linea_detalle_dict.get("ItemCode", "")): continue + # obtenemos el total de linea line_total = float(linea_detalle_dict.get("LineTotal", 0) or 0) + # obtenemos el precio después de impuesto price_after_vat = float(linea_detalle_dict.get("PriceAfterVAT", 0) or 0) + # obtenemos la cantidad quantity = float(linea_detalle_dict.get("Quantity", 0) or 0) + # sumamos el total de linea suma_line_total += line_total + # obtenemos la cantidad maxima max_qty = max(max_qty, quantity) + sum_pav += price_after_vat print(f" │ └─ {dn.get('Series', '?')}-{dn.get('DocNum', '?')} | ItemCode: {linea_detalle_dict.get('ItemCode', '')} | PriceAfterVAT: {price_after_vat:.6f} | Quantity: {quantity:.6f} | LineTotal: {line_total:.6f}")