Files
descarga_factura_transporte/docs/inventario.md
T
GeorgeandClaude Sonnet 5.5 6030320822 se actualiza la documentación: sapb1_manager, nombres de funciones y cifras
- Nueva página docs/sapb1_manager.md: sesión, funciones, clasificación de
  errores (SapNoDisponible frente a rechazo de SAP), búsqueda de facturas
  existentes y cómo se ubica una guía.
- procesar_pdfs.md y procesar_xmls.md usaban los nombres anteriores a la
  división de pipeline.py (_procesar_pdfs, _ruta_carpeta...) y números de
  línea que envejecen; ahora apuntan a documentos.py.
- inventario.md: árbol de dependencias con los módulos nuevos.
- pipeline.md: _procesar_factura, importes_coinciden, hana_disponible y
  buscar_factura_existente; validar_precios.md, hana_manager.md, main.md y
  procesar_xmls.md con las notas que faltaban; README sin la cifra de pruebas
  vieja.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 14:56:34 -05:00

12 KiB

Inventario del código

Archivos

Archivo Líneas Rol
main.py 142 Demonio orquestador (loop de horarios)
pipeline.py 437 Orquestador del pipeline (autenticar, descargar correos, procesar un correo)
pipeline_utils.py 38 log() (logging con indentación de árbol y severity) y ruta_carpeta()
adjuntos.py 82 Descarga de adjuntos (Graph) y filtrado PDF/XML
documentos.py 378 Extracción PDF/XML, asignación de guías, copia a red
persistencia.py 165 Guardado de JSON de resultados y de drafts
draft_sap.py 444 Validación de precios contra SAP, valor referencial y construcción del draft
notificaciones.py 121 Cuerpos HTML de los correos de notificación
sunat_schema.py 722 Parseo de XML SUNAT (Invoice, DespatchAdvice)
pdf_utilities.py 471 Parseo de PDFs (factura, guías)
sapb1_manager.py 469 Comunicación con SAP B1 Service Layer
outlook_utilities.py 274 Comunicación con Microsoft Graph
hana_manager.py 141 Comunicación con SAP HANA directa (fallback de sapb1_manager y valor referencial)
database_utilities.py 164 SQLite local (cache de correos)
tools/*_prueba.py, tools/completar_guias_pipeline.py, tools/explorar_notes_xml.py — Scripts manuales sobre tests/fixtures/correos_prueba/ (anteriores a la suite pytest)
tools/verificar_conexiones.py 85 Comprueba .env, Graph, SAP, HANA y la ruta de red sin modificar nada
deploy/*.ps1 — Instalar, actualizar (versión etiquetada / rollback) y desinstalar el servicio de Windows con NSSM
tools/consulta_rapida.py 120 Script auxiliar para reprocesar correos por ID (sets en tools/ids_prueba.json)
seguimiento.py 226 Códigos de seguimiento y resultado por comprobante (tabla comprobantes)
respuesta_proveedor.py 300 Respuesta de aceptado/rechazado al remitente (modo prueba/real, protecciones, contextos)
observaciones.py 165 Catálogo de motivos de rechazo y sus textos
plantillas.py 123 Renderizador de las plantillas HTML de correo
config_validator.py 98 Valida el .env al arrancar (obligatorias, ruta de red, avisos de SSL)
email_utilities.py 55 Utilitarios de adjuntos (ZIP, filtrado)
logger_manager.py 150 Logging a archivo rotado (30 días) + consola + captura de print()

Documentación por módulo: sapb1_manager.py → sapb1_manager.md, despliegue → despliegue_windows.md, respuesta_proveedor.py/observaciones.py/plantillas.py → respuesta_proveedor.md, seguimiento.py → seguimiento.md, outlook_utilities.py → outlook_utilities.md, hana_manager.py → hana_manager.md, validación y draft → validar_precios.md y construir_draft.md.


Dependencias entre archivos

main.py
  ├── logger_manager.py
  └── pipeline.py
        ├── sunat_schema.py
        ├── pdf_utilities.py
        ├── sapb1_manager.py
        │     └── hana_manager.py
        ├── hana_manager.py            (valor referencial, Sp_ObtenerValorReferencial)
        ├── outlook_utilities.py
        ├── email_utilities.py
        └── database_utilities.py

Módulos que pipeline.py orquesta (todos usan pipeline_utils.py):

pipeline.py
  ├── adjuntos.py              → outlook_utilities
  ├── documentos.py            → sunat_schema, pdf_utilities
  ├── persistencia.py          → sunat_schema, pdf_utilities
  ├── draft_sap.py             → sapb1_manager, hana_manager
  ├── notificaciones.py        (correo técnico para el equipo)
  ├── observaciones.py         (motivos de rechazo y sus textos)
  ├── respuesta_proveedor.py   → plantillas.py, observaciones.py, outlook_utilities, seguimiento.py
  └── seguimiento.py           → database_utilities

main.py → config_validator.py (valida el .env al arrancar)

tools/consulta_rapida.py ├── logger_manager.py ├── database_utilities.py └── pipeline.py (_procesar_un_correo, step_authenticate)


---

## Flujo de datos

main() └── run_pipeline() ├── step_authenticate() → token MS Graph ├── step_fetch_emails() → emails[] └── _procesar_un_correo() (por cada email) ├── BD: verificar duplicado ├── adjuntos.descargar_adjuntos() → archivos ├── email_utilities.descomprimir_adjuntos() ZIPs ├── adjuntos.filtrar_y_limpiar() → solo PDF/XML ├── documentos.procesar_pdfs() → pdf_cache │ └── pdf_utilities.extraer_datos_pdf() ├── documentos.procesar_xmls(pdf_cache) → documentos[] │ ├── sunat_schema.extraer_datos_xml() │ └── documentos.copiar_a_red() → copia PDF/XML a ruta de red (RUTA_RED_FACTURACION) ├── documentos.completar_guias(documentos, pdf_cache) → completa guías faltantes desde PDF ├── documentos.validar_guias(documentos) → advierte guías con datos incompletos ├── persistencia.guardar_resultado(documentos) ├── draft_sap.validate_prices(factura) → (ok, resultados) │ └── sapb1_manager.get_delivery_notes() │ ├── SL (Service Layer) GET /DeliveryNotes │ ├── HANA fallback (get_delivery: ODLN, luego OWTR) │ └── si vino de OWTR: GET StockTransfers(DocEntry) │ → U_IDC_NUMOV → GET Orders(U_IDC_NUMOV) ├── draft_sap.obtener_valor_referencial_sap(factura) → guias_valor_ref │ └── hana_manager.obtener_valor_referencial() (Sp_ObtenerValorReferencial) ├── draft_sap.build_sap_draft(factura, resultados) → draft (incluye U_VS_ANEXO_PDF/XML) │ └── sapb1_manager.obtener_condicion_pago(CardCode) → DocDueDate ├── persistencia.guardar_draft_json(draft) ├── sapb1_manager.create_draft(draft) └── outlook_utilities.send_email(notificación)


---

## Problemas conocidos hasta ahora

| # | Problema | Archivo | Estado |
|---|----------|---------|--------|
| 1 | `_extraer_serie_numero_desde_texto` no limpiaba leading zeros | `sunat_schema.py` | ✅ Corregido |
| 2 | Al asignar guías por línea, si hay +refs que líneas, las sobrantes se perdían | `pipeline.py` | ✅ Corregido |
| 3 | SL sin fallback a HANA | `sapb1_manager.py` | ✅ Corregido |
| 4 | Ctrl+C mostraba traceback | `main.py` | ✅ Corregido |
| 5 | `.env.dev` vs `.env` inconsistente | `sapb1_manager.py` | ✅ Corregido |
| 6 | `HANA_HOST` vs `HANA_SERVER` en `.env` | `hana_manager.py` | ✅ Corregido |
| 7 | Columna `Cancelled` vs `CANCELED` en HANA | `hana_manager.py` | ✅ Corregido |
| 8 | Bloque `if __name__ == "__main__"` borraba un correo real de la BD al ejecutar el módulo directo | `database_utilities.py` | ✅ Corregido |
| 9 | `extraer_datos_xml` solo procesaba guías tipo `31`; tipo `09` (remitente) se descartaba pese a estar documentado | `sunat_schema.py` | ✅ Corregido |
| 10 | `DatosComprobante.__str__` usaba `ref.id` (campo que ya no existe en `DocumentoReferencia`) | `sunat_schema.py` | ✅ Corregido |
| 11 | Log de error HTTP con `print("%s", ...)` no interpolaba el mensaje | `sapb1_manager.py` | ✅ Corregido |
| 12 | Fuga de conexión HANA si `cursor()` fallaba (quedaba fuera del `try`) | `hana_manager.py` | ✅ Corregido |
| 13 | `razon_social_emisor` se llenaba con el nombre del receptor en el JSON de depuración del PDF | `pipeline.py` | ✅ Corregido |
| 14 | Typo `VERIFI_SSL` en vez de `VERIFY_SSL` | `outlook_utilities.py` / `.env` | ✅ Corregido |
| 15 | Conexiones SQLite sin `try/finally` (fuga si fallaba una consulta a mitad de camino) | `database_utilities.py` | ✅ Corregido |
| 16 | Código muerto sin llamadores (`quitar_correos_ya_registrados_en_base_de_datos`, `procesar_adjuntos_email`) | `email_utilities.py` | ✅ Corregido (eliminado) |
| 17 | `logger_utilities.py` (redirección global de stdout, sin niveles ni rotación real) reemplazado por `logger_manager.py` (logging estándar, rotación diaria 30 días, captura de `print()`) | `logger_manager.py` | ✅ Corregido |
| 18 | `task()`/`last_task()` de `logger_manager.py` no devolvían el sub-logger (`with ... as sub` daba siempre `None`) | `logger_manager.py` | ✅ Corregido |
| 19 | `DOWNLOAD_FOLDER` duplicado en `.env` | `.env` | ✅ Corregido |
| 20 | Guías tipo `09` no se encontraban si el documento estaba en `OWTR` (Traslado de Inventario) en vez de `ODLN` | `hana_manager.py` | ✅ Corregido (fallback ODLN → OWTR) |
| 21 | Parámetros `tipo`/`serie` cruzados al llamar `get_delivery`/`get_delivery_notes` (mapeaban al revés a `U_BPP_MDSD`/`U_BPP_MDTD`) | `hana_manager.py`, `sapb1_manager.py`, `pipeline.py` | ✅ Corregido (orden natural `tipo, serie, numero`) |
| 22 | `StockTransfers` (OWTR) no tiene líneas `FL*`, por lo que la validación de precios fallaba siempre para esas guías | `sapb1_manager.py` | ✅ Corregido (resuelve la Orden de Venta vía `U_IDC_NUMOV` y valida contra `Orders(DocEntry)`) |
| 23 | `DocDueDate` del draft usaba `fecha_emision` del XML, sin considerar la condición de pago del proveedor | `pipeline.py`, `sapb1_manager.py` | ✅ Corregido (`DocDueDate` = fecha de contabilización + días de `PaymentTermsTypes`) |
| 24 | Patrón regex de valor referencial no reconocía la variante truncada "VALOR REFER" (ej. "VALOR REFER:S/ 1431.16") | `sunat_schema.py` | ✅ Corregido |

---

## Funciones por módulo

> Antes eran funciones anidadas en `_procesar_un_correo`; ahora son funciones de módulo que reciben explícitamente `email`, `download_folder`, `output_folder`, etc. `pipeline.py` solo las orquesta.

| Módulo | Función | Propósito |
|--------|---------|-----------|
| `pipeline_utils` | `ruta_carpeta` | Resuelve una ruta relativa al directorio del proyecto |
| `pipeline_utils` | `log` | Imprime con indentación de árbol (niveles 1-4) |
| `adjuntos` | `descargar_adjuntos` | Descarga adjuntos vía Graph API |
| `adjuntos` | `filtrar_y_limpiar` | Filtra PDF/XML, elimina el resto |
| `documentos` | `copiar_a_red` | Copia PDF/XML a la ruta de red de Facturación Electrónica (`RUTA_RED_FACTURACION`) |
| `documentos` | `procesar_pdfs` | Extrae datos de PDFs, renombra, genera cache |
| `documentos` | `procesar_xmls` | Procesa XMLs, cruza con PDF, asigna guías, copia a red |
| `documentos` | `completar_guias` | Completa guías faltantes en líneas XML desde el PDF cache |
| `documentos` | `validar_guias` | Advierte (log) guías con datos incompletos |
| `persistencia` | `guardar_resultado` | Guarda JSON con datos extraídos (XML y PDF) |
| `persistencia` | `guardar_draft_json` | Guarda draft JSON para depuración |
| `draft_sap` | `calcular_fecha_vencimiento` | Calcula `DocDueDate` = fecha de contabilización + días de la condición de pago (`PaymentTermsTypes`) |
| `draft_sap` | `build_sap_draft` | Construye payload del draft SAP B1 |
| `draft_sap` | `validate_prices` | Valida precios contra DeliveryNotes / Orders (SAP) |
| `draft_sap` | `obtener_valor_referencial_sap` | Consulta `Sp_ObtenerValorReferencial` en HANA por guía |
| `notificaciones` | `build_validation_html` | Genera tabla HTML de validación de precios |
| `notificaciones` | `build_valor_referencial_html` | Genera tabla HTML comparando valor referencial XML vs SAP |
| `notificaciones` | `build_notification_body` | Arma cuerpo del email de notificación |