Reemplaza logging por consola/archivo, agrega historial de intentos y soporte para notas de crédito

- Nuevo logger_manager.py (reemplaza logger_utilities.py): logging con formato de árbol,
  rotación diaria a sunat.log, y consola por stdout (antes iba por stderr y se duplicaba
  en logs/error.log del launchd).
- Nuevo historial_manager.py: registra cada intento de consulta/descarga en historial.db
  para auditoría, con limpieza automática de registros de más de 180 días.
- consulta_cpe.py: corrige el id de notas de crédito/débito (usa F7/F8, no 07/08) y
  agrega reintentos ante errores 5xx.
- hana_manager.py: suma consulta a ORPC para notas de crédito (Indicator 07) y soporte
  de ObjType para actualizar la tabla correcta (OPCH/ORPC) al marcar PDF/XML descargado.
- gestor_fallas.py / main.py: propagan objtype end-to-end y dejan constancia de cada
  intento en historial_manager.
- Elimina login_api.py y reporte_fallas.py (código no usado / script manual sin uso reciente).
- Actualiza .gitignore (sunat-venv/, historial.db*) y docs/ para reflejar el estado real
  del proyecto.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5 committed 2026-08-31 12:31:48 -05:00
1 parent 99a587c4da
commit c2503745bf
18 files changed
+647 -862

No files matched your search

+43 -12
View File
@@ -2,9 +2,11 @@ import os
import json
from pathlib import Path
from dotenv import load_dotenv
from logger_manager import get_logger
# ============================================================================
load_dotenv()
logger = get_logger(__name__)
HANA_HOST = os.getenv("HANA_HOST", "")
HANA_PORT = int(os.getenv("HANA_PORT", 30015))
@@ -27,7 +29,7 @@ def get_connection():
password=HANA_PASSWORD
)
except Exception as e:
print(f" ❌ Error conectando a HANA: {e}")
logger.error(f"Error conectando a HANA: {e}")
return None
return _conn
@@ -49,6 +51,7 @@ def obtener_pendientes() -> list[dict]:
"LicTradNum",
"FolioPref",
"FolioNum",
"ObjType",
"U_PGX_REPIMP" "urlPDF",
"U_PGX_PDF" "tienePDF",
"U_PGX_REPIMPXML" "urlXML",
@@ -56,9 +59,35 @@ def obtener_pendientes() -> list[dict]:
FROM "{HANA_SCHEMA}".OPCH
WHERE ("U_PGX_PDF" = 'N' OR "U_PGX_XML" = 'N')
AND EXTRACT(YEAR FROM "DocDate") = 2026
AND "Indicator" IN ('01', '02','08')
AND "Indicator" IN ('01','02','03')
AND "CANCELED" = 'N'
ORDER BY EXTRACT(MONTH FROM "DocDate") DESC
AND "LicTradNum" NOT IN ('20100047218','20100130204','20100053455')
AND SUBSTRING("FolioPref", 1, 1) NOT BETWEEN '0' AND '9'
UNION ALL
SELECT
"DocEntry",
"DocNum",
"DocDate",
EXTRACT(MONTH FROM "DocDate") "Mes",
"Indicator",
"LicTradNum",
"FolioPref",
"FolioNum",
"ObjType",
"U_PGX_REPIMP" "urlPDF",
"U_PGX_PDF" "tienePDF",
"U_PGX_REPIMPXML" "urlXML",
"U_PGX_XML" "tieneXML"
FROM "{HANA_SCHEMA}".ORPC
WHERE ("U_PGX_PDF" = 'N' OR "U_PGX_XML" = 'N')
AND EXTRACT(YEAR FROM "DocDate") = 2026
AND "Indicator" IN ('07')
AND "CANCELED" = 'N'
AND "LicTradNum" NOT IN ('20100047218','20100130204','20100053455')
AND SUBSTRING("FolioPref", 1, 1) NOT BETWEEN '0' AND '9'
"""
cursor = conn.cursor()
cursor.execute(query)
@@ -68,45 +97,47 @@ def obtener_pendientes() -> list[dict]:
result = [dict(zip(columns, row)) for row in rows]
return result
except Exception as e:
print(f" ❌ Error en query HANA: {e}")
logger.error(f"Error en query HANA: {e}")
return []
# ============================================================================
def marcar_pdf_descargado(docentry: int, url: str, ruta: str):
def marcar_pdf_descargado(docentry: int, url: str, ruta: str, obj_type: int = 18):
conn = get_connection()
if not conn:
return False
tabla = "ORPC" if int(obj_type) == 19 else "OPCH"
try:
cursor = conn.cursor()
cursor.execute(f"""
UPDATE "{HANA_SCHEMA}".OPCH
UPDATE "{HANA_SCHEMA}".{tabla}
SET "U_PGX_PDF" = 'Y'
WHERE "DocEntry" = ?
""", (docentry))
""", (docentry,))
conn.commit()
cursor.close()
return True
except Exception as e:
print(f" ❌ Error actualizando PDF HANA: {e}")
logger.error(f"Error actualizando PDF HANA: {e}")
return False
# ============================================================================
def marcar_xml_descargado(docentry: int, url: str, ruta: str):
def marcar_xml_descargado(docentry: int, url: str, ruta: str, obj_type: int = 18):
conn = get_connection()
if not conn:
return False
tabla = "ORPC" if int(obj_type) == 19 else "OPCH"
try:
cursor = conn.cursor()
cursor.execute(f"""
UPDATE "{HANA_SCHEMA}".OPCH
UPDATE "{HANA_SCHEMA}".{tabla}
SET "U_PGX_XML" = 'Y'
WHERE "DocEntry" = ?
""", (docentry))
""", (docentry,))
conn.commit()
cursor.close()
return True
except Exception as e:
print(f" ❌ Error actualizando XML HANA: {e}")
logger.error(f"Error actualizando XML HANA: {e}")
return False
# ============================================================================