# frozen_string_literal: true # ⚠️ [DEPRECATED] Este módulo está en desuso. # Filosofia actual: DB-First. La base de datos es la fuente de verdad. # Uso: API REST en puerto 3002 o herramienta ./adn/tools/run db require 'date' module BitacorasDB module Exporters class MDExporter def initialize(db, logger = nil) @db = db @logger = logger || default_logger end def exportar_bitacora(fecha, ruta_destino) @logger.info("Exportando bitácora #{fecha} a #{ruta_destino}...") bitacora = @db.find_bitacora_by_fecha(fecha) unless bitacora @logger.error("No se encontró la bitácora para la fecha: #{fecha}") return false end bitacora_id = bitacora['id'] # Obtener datos estructurados (incluyendo lo nuevo) entradas = @db.execute(" SELECT e.*, n.nombre as nodo_nombre FROM bitacoras.entradas e LEFT JOIN bitacoras.nodos n ON e.nodo_id = n.id WHERE e.bitacora_id = $1 ORDER BY n.nombre, e.inicio ASC ", [bitacora_id]) gestion = @db.execute(" SELECT g.*, n.nombre as nodo_nombre FROM bitacoras.gestion g LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id WHERE g.bitacora_id = $1 OR g.activo = true ORDER BY g.tipo, g.orden ", [bitacora_id]) rescue [] # Por si la tabla no existe aún en otros entornos resumenes = @db.execute(" SELECT r.*, n.nombre as nodo_nombre FROM bitacoras.resumen_nodos r JOIN bitacoras.nodos n ON r.nodo_id = n.id WHERE r.bitacora_id = $1 ", [bitacora_id]) rescue [] # Generar contenido Markdown contenido = generar_markdown(fecha, bitacora['resumen'], gestion, resumenes, entradas) File.write(ruta_destino, contenido) @logger.info("✅ Exportación completada con éxito.") true rescue => e @logger.error("Error exportando bitácora: #{e.message}") false end private def generar_markdown(fecha, resumen_gen, gestion, resumenes, entradas) y, m, d = fecha.to_s.split('-') md = String.new("\n") md << "# Bitácora de Operaciones - #{d}/#{m}/#{y}\n\n" if gestion && gestion.ntuples > 0 md << "## 📋 Control de Gestión\n\n" pendientes = gestion.select { |g| g['tipo'] == 'pendiente' } if pendientes.any? md << "### 📝 Resumen de Actividades\n" # Formato ADN md << "| NODO | PENDIENTES |\n| :--- | :--- |\n" pendientes.each do |p| md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n" end md << "\n" end en_proceso = gestion.select { |g| g['tipo'] == 'proceso' } if en_proceso.any? md << "### ⏳ En Proceso\n" md << "| NODO | ACTIVIDAD |\n| :--- | :--- |\n" en_proceso.each do |p| md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n" end md << "\n" end end if resumenes && resumenes.ntuples > 0 md << "### 📝 Resumen Integral\n" md << "| NODO | RESUMEN INTEGRAL |\n| :--- | :--- |\n" resumenes.each do |r| md << "| #{r['nodo_nombre']} | #{r['resumen']} |\n" end md << "\n" end md << "## 📂 Actividades Detalladas\n\n" por_nodo = entradas.group_by { |e| e['nodo_nombre'] || 'sin-nodo' } por_nodo.each do |nodo, entries| md << "### #{nodo}\n\n" md << "| I | F | Descripción | E |\n" md << "| :--- | :--- | :--- | :--- |\n" entries.each do |e| inicio = e['inicio'] ? e['inicio'][0..4] : '-' fin = e['fin'] ? e['fin'][0..4] : '-' ia = e['es_ia'] == 't' ? '(IA) ' : '' estado = "[#{e['modo']}] #{e['estado']}" md << "| #{inicio} | #{fin} | #{ia}#{e['descripcion']} | #{estado} |\n" end md << "\n" end md << "---\n" md << "\n" md << "\n" md end def default_logger Class.new do def info(msg); puts "[INFO] #{msg}"; end def error(msg); puts "[ERROR] #{msg}"; end end.new end end end end