Venezuela / exportar.py
Yofran23's picture
Update exportar.py
74eccec verified
Raw
History Blame Contribute Delete
5.6 kB
"""Utilidades de exportación a Excel y PDF."""
import io
import os
from datetime import datetime
import pandas as pd
try:
from fpdf import FPDF
PDF_AVAILABLE = True
except ImportError:
PDF_AVAILABLE = False
try:
import openpyxl # noqa: F401 — solo para verificar que está disponible
EXCEL_AVAILABLE = True
except ImportError:
EXCEL_AVAILABLE = False
def _pdf_safe(s) -> str:
"""La fuente core del PDF (Helvetica) solo soporta latin-1.
Quitamos emojis y reemplazamos caracteres no soportados (guiones largos, etc.)."""
if s is None:
return ""
s = (str(s)
.replace("–", "-").replace("—", "-").replace("•", "-")
.replace("✅", "[OK]").replace("👤", "(C)").replace("🆘", "").replace("…", "..."))
return s.encode("latin-1", "ignore").decode("latin-1").strip()
def _df_para_export(rows: list[dict]) -> pd.DataFrame:
if not rows:
return pd.DataFrame()
df = pd.DataFrame(rows)
cols_rename = {
"nombre": "Nombre",
"cedula": "Cédula",
"edad": "Edad",
"hospital": "Hospital",
"condicion": "Condición",
"descripcion": "Descripción (IA)",
"fecha_ingreso": "Fecha de ingreso",
"fecha_update": "Última actualización",
"verificado": "Verificado",
"contacto": "Contacto familiar",
"notas": "Notas",
"fuente": "Fuente del reporte",
}
df = df.rename(columns={k: v for k, v in cols_rename.items() if k in df.columns})
df["Verificado"] = df["Verificado"].apply(lambda x: "Sí" if x else "No")
cols_orden = ["Nombre", "Cédula", "Edad", "Hospital", "Condición",
"Última actualización", "Verificado", "Contacto familiar",
"Notas", "Descripción (IA)", "Fuente del reporte", "Fecha de ingreso"]
cols_presentes = [c for c in cols_orden if c in df.columns]
return df[cols_presentes]
def exportar_excel(rows: list[dict]) -> str | None:
if not rows:
return None
df = _df_para_export(rows)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
path = f"/tmp/busqueda_familiar_{ts}.xlsx"
with pd.ExcelWriter(path, engine="openpyxl") as writer:
df.to_excel(writer, index=False, sheet_name="Personas")
ws = writer.sheets["Personas"]
# ajustar anchos
anchos = {"Nombre": 28, "Cédula": 14, "Edad": 6, "Hospital": 32,
"Condición": 16, "Última actualización": 20, "Verificado": 10,
"Contacto familiar": 18, "Notas": 30, "Descripción (IA)": 40,
"Fuente del reporte": 18, "Fecha de ingreso": 20}
for i, col in enumerate(df.columns, 1):
ws.column_dimensions[ws.cell(1, i).column_letter].width = anchos.get(col, 15)
return path
class _PDF(FPDF):
def __init__(self, titulo: str):
super().__init__(orientation="L", unit="mm", format="A4")
self._titulo = titulo
def header(self):
self.set_font("Helvetica", "B", 13)
self.set_fill_color(185, 28, 28)
self.set_text_color(255, 255, 255)
self.cell(0, 10, _pdf_safe(self._titulo), align="C", fill=True, new_x="LMARGIN", new_y="NEXT")
self.set_text_color(0, 0, 0)
self.set_font("Helvetica", size=8)
self.cell(0, 6, _pdf_safe(f"Generado: {datetime.now().strftime('%d/%m/%Y %H:%M')}"),
align="R", new_x="LMARGIN", new_y="NEXT")
self.ln(2)
def footer(self):
self.set_y(-12)
self.set_font("Helvetica", "I", 8)
self.set_text_color(120, 120, 120)
self.cell(0, 6, _pdf_safe(f"Plataforma Buscador Familiar - Terremoto Venezuela | Pag. {self.page_no()}"),
align="C")
def exportar_pdf(rows: list[dict]) -> str | None:
if not rows or not PDF_AVAILABLE:
return None
df = _df_para_export(rows)
# columnas que caben bien en landscape A4
cols_pdf = ["Nombre", "Cédula", "Edad", "Hospital", "Condición",
"Última actualización", "Verificado"]
cols_pdf = [c for c in cols_pdf if c in df.columns]
anchos_pdf = {
"Nombre": 55, "Cédula": 26, "Edad": 12, "Hospital": 60,
"Condición": 28, "Última actualización": 36, "Verificado": 18,
}
pdf = _PDF("Busqueda de Familiares - Terremoto Venezuela")
pdf.add_page()
# cabecera de tabla
pdf.set_font("Helvetica", "B", 9)
pdf.set_fill_color(220, 38, 38)
pdf.set_text_color(255, 255, 255)
for col in cols_pdf:
pdf.cell(anchos_pdf.get(col, 30), 8, _pdf_safe(col), border=1, fill=True, align="C")
pdf.ln()
# filas
pdf.set_font("Helvetica", size=8)
pdf.set_text_color(0, 0, 0)
fill = False
for _, row in df.iterrows():
pdf.set_fill_color(255, 235, 235) if fill else pdf.set_fill_color(255, 255, 255)
for col in cols_pdf:
val = _pdf_safe(row.get(col, ""))
if len(val) > 35:
val = val[:33] + "..."
pdf.cell(anchos_pdf.get(col, 30), 7, val, border=1, fill=True)
pdf.ln()
fill = not fill
# nota al pie del contenido
pdf.ln(4)
pdf.set_font("Helvetica", "I", 7)
pdf.set_text_color(100, 100, 100)
pdf.multi_cell(0, 5, _pdf_safe(
"AVISO: Esta informacion es de caracter orientativo. Verifique siempre con el personal "
"del hospital. [OK] = Verificado por personal medico - No = Reportado por ciudadano."))
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
path = f"/tmp/busqueda_familiar_{ts}.pdf"
pdf.output(path)
return path