# pipeline.py — run_pipeline ## Estructura general ``` pipeline.py ├── CONSTANTES: CUADRO_VALOR_REFERENCIAL ├── HELPERS: _ruta_carpeta() ├── PASO 1: step_authenticate() → token | None ├── PASO 2: step_fetch_emails() → list[dict] ├── _procesar_un_correo() → None (core) └── run_pipeline() → None ``` --- ## Proceso de `run_pipeline()` ```mermaid flowchart TD A[run_pipeline] --> B[init_db] B --> C[Calcular rango fechas: ayer-dias → hoy] C --> D[step_authenticate] D --> E{Token obtenido?} E -- No --> F[❌ Abortar] E -- Sí --> G[step_fetch_emails] G --> H{Hay correos?} H -- No --> I[Fin] H -- Sí --> J[Bucle: por cada email] J --> K[_procesar_un_correo]:::highlight K --> J classDef highlight fill:#fff3e0,stroke:#e65100,stroke-width:3px; ``` --- ## Proceso de `_procesar_un_correo()` ```mermaid flowchart TD A[_procesar_un_correo] --> B[1-2. BD: ¿ya procesado?] B -- Sí --> C[⏭️ Saltar] B -- No --> D[Guardar en BD] D --> E[3. _descargar_adjuntos] E --> F{Hay adjuntos?} F -- No --> C F -- Sí --> G[4. _descomprimir ZIPs] G --> H[5. _filtrar_y_limpiar] H --> I{Hay PDF/XML?} I -- No --> C I -- Sí --> J[6. _procesar_pdfs]:::highlight J --> K[7. _procesar_xmls]:::highlight K --> L{Hay documentos?} L -- No --> C L -- Sí --> M[8. _guardar_resultado] M --> N[9. Filtrar facturas tipo 01] N --> O{Hay facturas?} O -- No --> C O -- Sí --> P[Bucle: por cada factura] P --> Q[10. _validate_prices]:::highlight Q --> R[11. _build_sap_draft]:::highlight R --> S[12. _guardar_draft_json] S --> T{Todas coinciden?} T -- Sí --> U[13. sapb1_manager.create_draft] T -- No --> V[⏭️ Draft NO creado] U --> W[14. outlook_utilities.send_email] V --> W W --> P classDef highlight fill:#fff3e0,stroke:#e65100,stroke-width:3px; ``` --- ## Funciones internas de `_procesar_un_correo` | Función | Línea | Propósito | |---------|-------|-----------| | `_descargar_adjuntos()` | 107 | Descarga adjuntos vía Microsoft Graph | | `_descomprimir()` | 136 | Descomprime archivos ZIP | | `_filtrar_y_limpiar()` | 151 | Filtra solo PDF/XML, elimina el resto | | **`_procesar_pdfs()`** | **193** | **Extrae datos de PDFs, renombra, genera cache** | | **`_procesar_xmls(pdf_cache)`** | **248** | **Procesa XMLs, cruza con PDF, asigna guías** | | `_guardar_resultado(documentos)` | 372 | Guarda JSON con datos extraídos | | **`_build_sap_draft(factura, resultados_val)`** | **403** | **Construye payload del draft SAP B1** | | **`_validate_prices(factura)`** | **564** | **Valida precios contra DeliveryNotes SAP** | | `_build_validation_html(resultados)` | 741 | Genera tabla HTML para notificación | | `_build_notification_body(status, factura, validation_table)` | 771 | Arma cuerpo del email de notificación | | `_guardar_draft_json(draft, serie, numero)` | 810 | Guarda draft JSON para depuración | --- ## Flujo de llamadas ``` run_pipeline ├── step_authenticate ├── step_fetch_emails └── _procesar_un_correo (por cada email) ├── _descargar_adjuntos ├── _descomprimir ├── _filtrar_y_limpiar ├── _procesar_pdfs ├── _procesar_xmls ├── _guardar_resultado ├── _validate_prices (por factura) │ └── sapb1_manager.get_delivery_notes ├── _build_sap_draft ├── _guardar_draft_json ├── sapb1_manager.create_draft └── outlook_utilities.send_email ```