# Validar Precios ```mermaid flowchart TD A["factura con lineas[]"] --> B["Obtener maestro zonas
SAP U_IDC_ZONAS"] B --> C["Por cada línea de factura"] C --> D{"cantidad > 0?"} D -->|No| E["Resultado: cantidad cero, sin validar"] D -->|Sí| F{"¿Hay guías de remisión?"} F -->|No| G["Resultado: sin guía de referencia"] F -->|Sí| H["Por cada guía en guias[]"] H --> I["Consultar SAP B1
get_delivery_notes()"] I --> I2{"¿Guía encontrada en
ODLN o en OWTR?"} I2 -->|ODLN| I3["Documento = DeliveryNotes(DocEntry)"] I2 -->|OWTR| I4["Documento = StockTransfers(DocEntry)
→ leer U_IDC_NUMOV
→ Documento = Orders(U_IDC_NUMOV)"] I3 --> J["Por cada documento
(DeliveryNote u Orden de Venta)"] I4 --> J J --> K["Obtener zona desde
U_IDC_DESTINO"] K --> L["Extraer WarehouseCode
de DocumentLines[0]"] L --> M["Acumular Weight1
de DocumentLines[0]"] M --> N["Por cada línea FL* en
DocumentLines"] N --> O["Sumar LineTotal"] O --> P["Máx Quantity"] P --> Q["Sumar PriceAfterVAT"] Q --> R["Construir guias_lt[]
para cada guía:
line_total, quantity,
price_after_vat_sum,
warehouse_code, zona, weight1"] R --> S["Comparar total_linea (XML)
vs sap_total (FL*)"] S --> T{"importes_coinciden:
diferencia redondeada a 2 decimales ≤ 0.01
y ninguna guía falló?"} T -->|Sí| U["ok = True
draft_quantity = int(Quantity máx FL*)
draft_price = suma PriceAfterVAT FL*"] T -->|No| V["ok = False
draft_quantity = int(cantidad XML)
draft_price = total_linea / cantidad"] U --> W["Resultado por línea:
ok, draft_price, sap_price,
label, warehouse_code, guias_lt[]"] V --> W W --> C C --> X["todas_coinciden = all(ok)"] ``` ## Notas - Si la consulta a SAP de una guía lanza error, esa guía queda con ceros y la línea completa se marca `ok = False` (se registra como `WARNING`). - Si ninguna guía de la línea existe en SAP, el resultado lleva `label = "Sin guías SAP"` y se registra "línea saltada", pero igual queda `ok = False` (salvo que `total_linea` sea 0), por lo que `todas_coinciden` es falso y no se crea el draft. - `weight1` (peso de la primera línea de cada guía) se sigue calculando y guardando en `guias_lt[]`, pero el draft ya no lo usa. - Función: `draft_sap.validate_prices(factura)` → `(todas_coinciden, resultados)`. - **Tolerancia:** `pipeline_utils.importes_coinciden` redondea la diferencia entre el importe de la línea del XML y el de SAP a 2 decimales (lo que muestra un comprobante) y admite hasta 1 céntimo. Comparar la diferencia sin redondear (`abs(a - b) < 0.01`) no era fiable por la coma flotante: 431.41 − 431.40 daba `0.01000000000004775` (se rechazaba) y 624.39 − 624.38 daba `0.00999999999999091` (se aceptaba), así que el mismo céntimo pasaba o no según el importe. Con datos reales de SAP, ninguna línea cambió de resultado al introducir el redondeo. Se usa también para comparar el valor referencial del correo técnico. - **Caída de SAP vs. guía inexistente:** `validate_prices` deja pasar `SapNoDisponible` (timeout, sin conexión, HTTP 5xx) en vez de convertirla en un error de la guía; el pipeline la trata como servicio fuera de línea. Otros errores de consulta quedan en `guias_lt[].error` (ver `draft_sap.hay_error_de_consulta`) y se tratan como error interno. Una guía sin datos en SAP solo se reporta como "no encontrada" si HANA responde (`draft_sap.hana_disponible`).