- hana_manager.get_delivery ahora busca en ODLN y, si no encuentra, en OWTR - sapb1_manager resuelve StockTransfers -> Orders (via U_IDC_NUMOV) para validar precios de flete cuando la guia es un traslado de inventario - se corrige el orden de parametros tipo/serie/numero (sin cruces) en get_delivery, get_delivery_notes y _get_delivery_entries - se agrega sapb1_manager.obtener_condicion_pago (BusinessPartners + PaymentTermsTypes) y pipeline._calcular_fecha_vencimiento para que DocDueDate del draft sea fecha de contabilizacion + dias de la condicion de pago del proveedor - se agrega variante de regex para "VALOR REFER" truncado en sunat_schema.py - se actualiza documentacion (docs/) reflejando estos cambios Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.9 KiB
7.9 KiB
pipeline.py — run_pipeline
Estructura general
pipeline.py
├── CONFIG: RUTA_RED_FACTURACION, RUC_EMPRESA (desde .env)
├── HELPERS: _ruta_carpeta(), _copiar_a_red(data, _log)
├── PASO 1: step_authenticate() → token | None
├── PASO 2: step_fetch_emails() → list[dict]
├── _procesar_un_correo() → None (core, funciones anidadas)
└── run_pipeline() → None
Proceso de run_pipeline()
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()
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 --> K2[8. _completar_guias]
K2 --> K3[9. _validar_guias]
K3 --> L{Hay documentos?}
L -- No --> C
L -- Sí --> M[10. _guardar_resultado]
M --> N[11. Filtrar facturas tipo 01]
N --> O{Hay facturas?}
O -- No --> C
O -- Sí --> P[Bucle: por cada factura]
P --> Q[12. _validate_prices]:::highlight
Q --> Q2[12.5 _obtener_valor_referencial_sap]
Q2 --> R[13. _build_sap_draft]:::highlight
R --> S[14. _guardar_draft_json]
S --> T{Todas coinciden?}
T -- Sí --> U[15. sapb1_manager.create_draft]
T -- No --> V[⏭️ Draft NO creado]
U --> W[16. outlook_utilities.send_email]
V --> W
W --> P
classDef highlight fill:#fff3e0,stroke:#e65100,stroke-width:3px;
_procesar_xmls (paso 7) incluye internamente la copia de PDF/XML a la ruta de red (_copiar_a_red, ver más abajo) por cada comprobante procesado.
Funciones internas de _procesar_un_correo
_ruta_carpetay_copiar_a_redestán definidas a nivel de módulo (no anidadas); el resto son funciones anidadas dentro de_procesar_un_correo.
| Función | Línea | Propósito |
|---|---|---|
_ruta_carpeta() (módulo) |
33 | Resuelve una ruta relativa al directorio del script |
_copiar_a_red(data, _log) (módulo) |
37 | Copia PDF/XML de un comprobante a la ruta de red configurable |
_descargar_adjuntos() |
169 | Descarga adjuntos vía Microsoft Graph |
_descomprimir() |
198 | Descomprime archivos ZIP |
_filtrar_y_limpiar() |
213 | Filtra solo PDF/XML, elimina el resto |
_procesar_pdfs() |
255 | Extrae datos de PDFs, renombra, genera cache |
_procesar_xmls(pdf_cache) |
310 | Procesa XMLs, cruza con PDF, asigna guías, copia a red |
_completar_guias(documentos, pdf_cache) |
465 | Completa guías faltantes en líneas XML desde el PDF cache |
_validar_guias(documentos) |
524 | Advierte (log) guías con datos incompletos (falta tipo/serie/numero) |
_guardar_resultado(documentos, datos_pdf) |
534 | Guarda JSON con datos extraídos (XML y PDF) |
_calcular_fecha_vencimiento(fecha_base, condicion_pago) |
665 | Calcula DocDueDate = fecha de contabilización + días de PaymentTermsTypes |
_build_sap_draft(factura, resultados_val) |
694 | Construye payload del draft SAP B1 (incluye U_VS_ANEXO_PDF/U_VS_ANEXO_XML, DocDueDate por condición de pago) |
_validate_prices(factura) |
856 | Valida precios contra DeliveryNotes/Orders SAP |
_build_validation_html(resultados) |
1032 | Genera tabla HTML de validación de precios |
_obtener_valor_referencial_sap(factura) |
1062 | Consulta Sp_ObtenerValorReferencial en HANA por cada guía única |
_build_valor_referencial_html(factura, guias_valor_ref) |
1091 | Genera tabla HTML comparando valor referencial XML vs SAP |
_build_notification_body(status, factura, validation_table, valor_referencial_table, **kwargs) |
1127 | Arma cuerpo del email de notificación |
_guardar_draft_json(draft, serie, numero) |
1169 | Guarda draft JSON para depuración |
_copiar_a_red(data, _log) — Copia a ruta de red
Copia el PDF y el XML de cada comprobante procesado a una ruta de red UNC configurable, en paralelo al guardado local existente (no lo reemplaza). No falla el pipeline si la ruta no está configurada o no está disponible: solo registra una advertencia.
- Configuración (
.env):RUTA_RED_FACTURACION(ruta base UNC) yRUC_EMPRESA(RUC fijo de Aberio). - Estructura de destino:
{RUTA_RED_FACTURACION}\{año}\{mes}\{día}\{tipo}\{RUC_EMPRESA}\{ruc_emisor}\ {RUC_EMPRESA}-{tipo}-{serie}-{numero}_FormatoImpreso.pdf {RUC_EMPRESA}-{tipo}-{serie}-{numero}.xmlRUC_EMPRESAes el RUC de Aberio (fijo);ruc_emisores el RUC del proveedor que emitió la factura (varía por comprobante). Año/mes/día salen defecha_emision, sin ceros a la izquierda en mes/día. - Guarda las rutas resultantes en
data["ruta_red_pdf"]/data["ruta_red_xml"], que luego usa_build_sap_draftpara llenarU_VS_ANEXO_PDF/U_VS_ANEXO_XMLen el draft SAP B1. - Se invoca desde
_procesar_xmls, justo después de resolverdata["ruta_pdf"].
Flujo de llamadas
run_pipeline
├── database_utilities.init_db
├── step_authenticate
│ └── outlook_utilities.get_access_token
├── step_fetch_emails
│ └── outlook_utilities.get_emails
└── _procesar_un_correo (por cada email)
├── database_utilities.get_existing_ids / save_emails
├── _descargar_adjuntos
│ └── outlook_utilities.download_attachments
├── _descomprimir
│ └── email_utilities.descomprimir_adjuntos
├── _filtrar_y_limpiar
├── _procesar_pdfs
│ └── pdf_utilities.extraer_datos_pdf / renombrar_pdf
├── _procesar_xmls
│ ├── sunat_schema.extraer_datos_xml
│ ├── pdf_utilities.extraer_referencias
│ └── _copiar_a_red
├── _completar_guias
├── _validar_guias
├── _guardar_resultado
│ └── sunat_schema.split_serie_numero, pdf_utilities.TIPO_MAP
├── (por cada factura tipo 01)
│ ├── _validate_prices
│ │ ├── sapb1_manager.get_zonas
│ │ └── sapb1_manager.get_delivery_notes
│ │ ├── hana_manager.get_delivery (fallback si SL no responde;
│ │ │ busca en ODLN y, si no hay, en OWTR)
│ │ └── si el DocEntry vino de OWTR (StockTransfers), resuelve
│ │ además la Orden de Venta asociada (Orders vía
│ │ U_IDC_NUMOV) para poder validar las líneas FL*
│ ├── _build_validation_html
│ ├── _obtener_valor_referencial_sap
│ │ └── hana_manager.obtener_valor_referencial
│ ├── _build_valor_referencial_html
│ ├── _build_sap_draft
│ │ └── sapb1_manager.obtener_condicion_pago (BusinessPartners +
│ │ PaymentTermsTypes, para calcular DocDueDate)
│ ├── _guardar_draft_json
│ ├── sapb1_manager.create_draft (si todas las líneas coinciden)
│ ├── _build_notification_body
│ └── outlook_utilities.send_email