- 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>
8.8 KiB
8.8 KiB
Inventario del código
Archivos
| Archivo | Líneas | Rol |
|---|---|---|
main.py |
134 | Demonio orquestador (loop de horarios) |
pipeline.py |
1284 | Pipeline core (procesar un correo completo) |
sunat_schema.py |
720 | Parseo de XML SUNAT (Invoice, DespatchAdvice) |
pdf_utilities.py |
464 | Parseo de PDFs (factura, guías) |
sapb1_manager.py |
321 | Comunicación con SAP B1 Service Layer |
outlook_utilities.py |
234 | Comunicación con Microsoft Graph |
hana_manager.py |
123 | Comunicación con SAP HANA directa (fallback de sapb1_manager y valor referencial) |
database_utilities.py |
116 | SQLite local (cache de correos) |
consulta_rapida.py |
113 | Script auxiliar para reprocesar correos por ID |
email_utilities.py |
52 | Utilitarios de adjuntos (ZIP, filtrado) |
logger_manager.py |
149 | Logging a archivo rotado (30 días) + consola + captura de print() |
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
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
├── _descargar_adjuntos() → archivos
├── _descomprimir() ZIPs
├── _filtrar_y_limpiar() → solo PDF/XML
├── _procesar_pdfs() → pdf_cache
│ └── pdf_utilities.extraer_datos_pdf()
├── _procesar_xmls(pdf_cache) → documentos[]
│ ├── sunat_schema.extraer_datos_xml()
│ └── _copiar_a_red() → copia PDF/XML a ruta de red (RUTA_RED_FACTURACION)
├── _completar_guias(documentos, pdf_cache) → completa guías faltantes desde PDF
├── _validar_guias(documentos) → advierte guías con datos incompletos
├── _guardar_resultado(documentos)
├── _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)
├── _obtener_valor_referencial_sap(factura) → guias_valor_ref
│ └── hana_manager.obtener_valor_referencial() (Sp_ObtenerValorReferencial)
├── _build_sap_draft(factura, resultados) → draft (incluye U_VS_ANEXO_PDF/XML)
│ └── sapb1_manager.obtener_condicion_pago(CardCode) → DocDueDate
├── _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 internas en _procesar_un_correo (pipeline.py)
Nota:
_ruta_carpetay_copiar_a_redson helpers a nivel de módulo (no anidados en_procesar_un_correo); el resto son funciones anidadas dentro de_procesar_un_correo(líneas 142-1304).
| Función | Líneas | Propósito |
|---|---|---|
_ruta_carpeta (módulo) |
33-34 | Resuelve una ruta relativa al directorio del script |
_copiar_a_red (módulo) |
37-94 | Copia PDF/XML a la ruta de red de Facturación Electrónica (RUTA_RED_FACTURACION) |
_descargar_adjuntos |
169-196 | Descarga adjuntos vía Graph API |
_descomprimir |
198-211 | Descomprime ZIPs |
_filtrar_y_limpiar |
213-253 | Filtra PDF/XML, elimina el resto |
_procesar_pdfs |
255-308 | Extrae datos de PDFs, renombra, genera cache |
_procesar_xmls |
310-463 | Procesa XMLs, cruza con PDF, asigna guías, copia a red |
_completar_guias |
465-522 | Completa guías faltantes en líneas XML desde el PDF cache |
_validar_guias |
524-532 | Advierte (log) guías con datos incompletos |
_guardar_resultado |
534-653 | Guarda JSON con datos extraídos (XML y PDF) |
_calcular_fecha_vencimiento |
665-692 | Calcula DocDueDate = fecha de contabilización + días de la condición de pago (PaymentTermsTypes) |
_build_sap_draft |
694-855 | Construye payload del draft SAP B1 |
_validate_prices |
856-1030 | Valida precios contra DeliveryNotes / Orders (SAP) |
_build_validation_html |
1032-1061 | Genera tabla HTML de validación de precios |
_obtener_valor_referencial_sap |
1062-1090 | Consulta Sp_ObtenerValorReferencial en HANA por guía |
_build_valor_referencial_html |
1091-1126 | Genera tabla HTML comparando valor referencial XML vs SAP |
_build_notification_body |
1127-1168 | Arma cuerpo del email de notificación |
_guardar_draft_json |
1169-1195 | Guarda draft JSON para depuración |