121 lines
5.5 KiB
Python
121 lines
5.5 KiB
Python
import sqlite3
|
|||
|
|
from pathlib import Path
|
||
|
|
from datetime import datetime, timedelta
|
||
|
|
from logger_manager import get_logger
|
||
|
|
|
||
|
|
DB_PATH = Path(__file__).parent / "historial.db"
|
||
|
|
logger = get_logger(__name__)
|
||
|
|
# ============================================================================
|
||
|
|
def _conn():
|
||
|
|
return sqlite3.connect(str(DB_PATH))
|
||
|
|
# ============================================================================
|
||
|
|
def init_db():
|
||
|
|
with _conn() as conn:
|
||
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
||
|
|
conn.execute("""
|
||
|
|
CREATE TABLE IF NOT EXISTS historial (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
fecha TEXT NOT NULL,
|
||
|
|
docentry INTEGER NOT NULL,
|
||
|
|
docnum TEXT,
|
||
|
|
ruc TEXT NOT NULL,
|
||
|
|
tipo TEXT NOT NULL,
|
||
|
|
serie TEXT NOT NULL,
|
||
|
|
numero TEXT NOT NULL,
|
||
|
|
objtype INTEGER NOT NULL DEFAULT 18,
|
||
|
|
es_retry INTEGER NOT NULL DEFAULT 0,
|
||
|
|
intento_num INTEGER,
|
||
|
|
consulta_status INTEGER,
|
||
|
|
pdf_resultado TEXT,
|
||
|
|
xml_resultado TEXT,
|
||
|
|
resultado TEXT NOT NULL,
|
||
|
|
detalle TEXT,
|
||
|
|
json_path TEXT
|
||
|
|
)
|
||
|
|
""")
|
||
|
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_historial_docentry ON historial(docentry)")
|
||
|
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_historial_fecha ON historial(fecha)")
|
||
|
|
# ============================================================================
|
||
|
|
def registrar_intento(docentry, docnum, ruc, tipo, serie, numero, objtype, es_retry,
|
||
|
|
intento_num, consulta_status, pdf_resultado, xml_resultado,
|
||
|
|
resultado, detalle="", json_path=None):
|
||
|
|
ahora = datetime.now().isoformat()
|
||
|
|
with _conn() as conn:
|
||
|
|
conn.execute("""
|
||
|
|
INSERT INTO historial
|
||
|
|
(fecha, docentry, docnum, ruc, tipo, serie, numero, objtype, es_retry,
|
||
|
|
intento_num, consulta_status, pdf_resultado, xml_resultado, resultado,
|
||
|
|
detalle, json_path)
|
||
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||
|
|
""", (ahora, docentry, docnum, ruc, tipo, serie, numero, objtype, int(es_retry),
|
||
|
|
intento_num, consulta_status, pdf_resultado, xml_resultado, resultado,
|
||
|
|
str(detalle)[:500] if detalle else detalle, json_path))
|
||
|
|
# ============================================================================
|
||
|
|
def limpiar_historial_antiguo(dias=180):
|
||
|
|
limite = (datetime.now() - timedelta(days=dias)).isoformat()
|
||
|
|
with _conn() as conn:
|
||
|
|
cursor = conn.execute("DELETE FROM historial WHERE fecha < ?", (limite,))
|
||
|
|
count = cursor.rowcount
|
||
|
|
if count > 0:
|
||
|
|
logger.info(f"Se eliminaron {count} registros de historial de más de {dias} días.")
|
||
|
|
return count
|
||
|
|
# ============================================================================
|
||
|
|
def historial_docentry(docentry) -> list[dict]:
|
||
|
|
with _conn() as conn:
|
||
|
|
conn.row_factory = sqlite3.Row
|
||
|
|
cursor = conn.execute(
|
||
|
|
"SELECT * FROM historial WHERE docentry = ? ORDER BY id ASC", (docentry,)
|
||
|
|
)
|
||
|
|
return [dict(row) for row in cursor.fetchall()]
|
||
|
|
# ============================================================================
|
||
|
|
def buscar_intentos(ruc=None, serie=None, numero=None, tipo=None) -> list[dict]:
|
||
|
|
"""Busca intentos registrados filtrando por cualquier combinación de ruc/serie/numero/tipo."""
|
||
|
|
condiciones = []
|
||
|
|
params = []
|
||
|
|
if ruc:
|
||
|
|
condiciones.append("ruc = ?")
|
||
|
|
params.append(ruc)
|
||
|
|
if serie:
|
||
|
|
condiciones.append("serie = ?")
|
||
|
|
params.append(serie)
|
||
|
|
if numero:
|
||
|
|
condiciones.append("numero = ?")
|
||
|
|
params.append(str(numero))
|
||
|
|
if tipo:
|
||
|
|
condiciones.append("tipo = ?")
|
||
|
|
params.append(tipo)
|
||
|
|
|
||
|
|
where = " AND ".join(condiciones) if condiciones else "1=1"
|
||
|
|
with _conn() as conn:
|
||
|
|
conn.row_factory = sqlite3.Row
|
||
|
|
cursor = conn.execute(f"SELECT * FROM historial WHERE {where} ORDER BY fecha ASC", params)
|
||
|
|
return [dict(row) for row in cursor.fetchall()]
|
||
|
|
# ============================================================================
|
||
|
|
if __name__ == "__main__":
|
||
|
|
import argparse
|
||
|
|
|
||
|
|
parser = argparse.ArgumentParser(description="Buscar intentos de descarga en historial.db")
|
||
|
|
parser.add_argument("--ruc", help="RUC del emisor")
|
||
|
|
parser.add_argument("--serie", help="Serie del comprobante (ej: F001)")
|
||
|
|
parser.add_argument("--numero", help="Número del comprobante")
|
||
|
|
parser.add_argument("--tipo", help="Tipo de comprobante (01, 03, 07, 08...)")
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
if not any([args.ruc, args.serie, args.numero, args.tipo]):
|
||
|
|
parser.error("Indica al menos un filtro: --ruc, --serie, --numero o --tipo")
|
||
|
|
|
||
|
|
filas = buscar_intentos(ruc=args.ruc, serie=args.serie, numero=args.numero, tipo=args.tipo)
|
||
|
|
|
||
|
|
if not filas:
|
||
|
|
print("No se encontraron intentos con esos filtros.")
|
||
|
|
else:
|
||
|
|
print(f"{len(filas)} intento(s) encontrado(s):\n")
|
||
|
|
for f in filas:
|
||
|
|
print(
|
||
|
|
f"{f['fecha']} DocEntry={f['docentry']} "
|
||
|
|
f"{f['ruc']}-{f['tipo']}-{f['serie']}-{f['numero']} "
|
||
|
|
f"intento={f['intento_num']} retry={'sí' if f['es_retry'] else 'no'} "
|
||
|
|
f"status={f['consulta_status']} resultado={f['resultado']} "
|
||
|
|
f"pdf={f['pdf_resultado']} xml={f['xml_resultado']} detalle={f['detalle']}"
|
||
|
|
)
|
||
|
|
# ============================================================================
|