import sqlite3 from pathlib import Path from datetime import datetime, timedelta DB_PATH = Path(__file__).parent / "fallas_descarga.db" # ============================================================================ def _conn(): return sqlite3.connect(str(DB_PATH)) # ============================================================================ def init_db(): with _conn() as conn: conn.execute(""" CREATE TABLE IF NOT EXISTS fallas ( docentry INTEGER PRIMARY KEY, ruc TEXT NOT NULL, tipo TEXT NOT NULL, serie TEXT NOT NULL, numero TEXT NOT NULL, objtype INTEGER NOT NULL DEFAULT 18, error TEXT NOT NULL, intentos INTEGER NOT NULL DEFAULT 1, proximo_intento TEXT, fecha_ultimo TEXT NOT NULL ) """) columnas = {row[1] for row in conn.execute("PRAGMA table_info(fallas)")} if "obj_type" in columnas and "objtype" not in columnas: conn.execute("ALTER TABLE fallas RENAME COLUMN obj_type TO objtype") elif "objtype" not in columnas: conn.execute("ALTER TABLE fallas ADD COLUMN objtype INTEGER NOT NULL DEFAULT 18") # ============================================================================ def _calcular_proximo_intento(intentos): if intentos >= 20: return None if intentos == 1: delta = timedelta(minutes=0) elif intentos == 2: delta = timedelta(minutes=5) elif intentos == 3: delta = timedelta(minutes=15) elif intentos == 4: delta = timedelta(minutes=30) elif intentos == 5: delta = timedelta(hours=1) elif intentos <= 10: delta = timedelta(hours=2) elif intentos <= 15: delta = timedelta(hours=6) else: delta = timedelta(hours=12) return (datetime.now() + delta).isoformat() # ============================================================================ def registrar_falla(docentry, ruc, tipo_cpe, serie, numero, obj_type, error, intentos=None): ahora = datetime.now().isoformat() if intentos is None: with _conn() as conn: row = conn.execute( "SELECT intentos FROM fallas WHERE docentry = ?", (docentry,) ).fetchone() intentos = (row[0] + 1) if row else 1 proximo = _calcular_proximo_intento(intentos) with _conn() as conn: conn.execute(""" INSERT OR REPLACE INTO fallas (docentry, ruc, tipo, serie, numero, objtype, error, intentos, proximo_intento, fecha_ultimo) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, (docentry, ruc, tipo_cpe, serie, numero, obj_type, str(error)[:200], intentos, proximo, ahora)) # ============================================================================ def eliminar_falla(docentry): with _conn() as conn: conn.execute("DELETE FROM fallas WHERE docentry = ?", (docentry,)) # ============================================================================ def obtener_fallas_pendientes() -> list[dict]: ahora = datetime.now().isoformat() with _conn() as conn: conn.row_factory = sqlite3.Row cursor = conn.execute(""" SELECT * FROM fallas WHERE (proximo_intento IS NULL OR proximo_intento <= ?) AND intentos < 20 ORDER BY intentos ASC, fecha_ultimo ASC """, (ahora,)) return [dict(row) for row in cursor.fetchall()] # ============================================================================ def obtener_docentries_falla() -> set[int]: with _conn() as conn: cursor = conn.execute("SELECT docentry FROM fallas") return {row[0] for row in cursor.fetchall()} # ============================================================================ def total_fallas() -> int: with _conn() as conn: return conn.execute("SELECT COUNT(*) FROM fallas").fetchone()[0] # ============================================================================