ReporteService.java
package com.licensis.notaire.service;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.util.JRLoader;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Map;
@Service
public class ReporteService {
private final DataSource dataSource;
private static final String RUTA_REPORTE_PRESUPUESTO = "reportes/reportePresupuestoSinInmueble.jasper";
private static final String RUTA_REPORTE_PRESUPUESTO_INMUEBLES = "reportes/reportePresupuestoInmuebles.jasper";
private static final String RUTA_REPORTE_LISTA_DOCUMENTOS_TRAMITE = "reportes/reporteListaDocumetosTramite.jasper";
private static final String RUTA_REPORTE_HISTORIAL_GESTION = "reportes/reporteHistorialGestion.jasper";
private static final String RUTA_REPORTE_CONSULTAR_VENCIMIENTOS_DOCUMENTOS = "reportes/reporteConsultarVencimientosDocumentos.jasper";
private static final String RUTA_REPORTE_CONSULTAR_DEUDA_DOCUMENTOS = "reportes/reporteConsultarDeudaDocumentos.jasper";
public ReporteService(DataSource dataSource) {
this.dataSource = dataSource;
}
public byte[] generarReportePresupuesto(Integer idPresupuesto) throws Exception {
Map<String, Object> parameters = Map.of("pIdPresupuesto", idPresupuesto);
return generarPdfDesdeTemplate(RUTA_REPORTE_PRESUPUESTO, parameters);
}
public byte[] generarReportePresupuestoInmuebles(Integer idPresupuesto) throws Exception {
Map<String, Object> parameters = Map.of("idPresupuestoParam", idPresupuesto);
return generarPdfDesdeTemplate(RUTA_REPORTE_PRESUPUESTO_INMUEBLES, parameters);
}
public byte[] generarReporteListaDocumentosTramite(String nombreTipoTramite) throws Exception {
Map<String, Object> parameters = Map.of("nombreTipoTramite", nombreTipoTramite);
return generarPdfDesdeTemplate(RUTA_REPORTE_LISTA_DOCUMENTOS_TRAMITE, parameters);
}
public byte[] generarReporteHistorialGestion(Integer idGestion) throws Exception {
Map<String, Object> parameters = Map.of("idGestion", idGestion);
return generarPdfDesdeTemplate(RUTA_REPORTE_HISTORIAL_GESTION, parameters);
}
public byte[] generarReporteDocumentosPorVencer(Integer idDocumentoPresentado) throws Exception {
Map<String, Object> parameters = Map.of("idDocumentoPresentado", idDocumentoPresentado);
return generarPdfDesdeTemplate(RUTA_REPORTE_CONSULTAR_VENCIMIENTOS_DOCUMENTOS, parameters);
}
public byte[] generarReporteConsultarDeudaDocumentos(Integer numeroGestion) throws Exception {
Map<String, Object> parameters = Map.of("numeroGestion", numeroGestion);
return generarPdfDesdeTemplate(RUTA_REPORTE_CONSULTAR_DEUDA_DOCUMENTOS, parameters);
}
public byte[] generarReporteLibroIndice(Integer anio) throws Exception {
return generarPdfTextoSimple(
"Libro de Indice",
"CU24",
"Periodo: " + anio,
"Generado: " + LocalDate.now()
);
}
public byte[] generarReporteDeclaracionJuradaMensual(Integer anio, Integer mes) throws Exception {
return generarPdfTextoSimple(
"Declaracion Jurada Mensual",
"CU25",
"Periodo: " + mes + "/" + anio,
"Generado: " + LocalDate.now()
);
}
public byte[] generarReporteDeclaracionJuradaRentas(Integer anio, Integer mes) throws Exception {
return generarPdfTextoSimple(
"Declaracion Jurada de Rentas",
"CU50",
"Periodo: " + mes + "/" + anio,
"Generado: " + LocalDate.now()
);
}
private byte[] generarPdfDesdeTemplate(String templatePath, Map<String, Object> parameters) throws Exception {
try (Connection connection = dataSource.getConnection()) {
InputStream reportStream = getClass().getClassLoader().getResourceAsStream(templatePath);
if (reportStream == null) {
throw new RuntimeException("No se encontró el template: " + templatePath);
}
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(reportStream);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);
return JasperExportManager.exportReportToPdf(jasperPrint);
} catch (SQLException e) {
throw new RuntimeException("Error de conexión a base de datos: " + e.getMessage(), e);
} catch (JRException e) {
throw new RuntimeException("Error al generar el reporte: " + e.getMessage(), e);
}
}
private byte[] generarPdfTextoSimple(String titulo, String cuId, String lineaPeriodo, String lineaFecha) {
try {
StringBuilder stream = new StringBuilder();
stream.append("BT\n");
stream.append("/F1 20 Tf\n");
stream.append("50 760 Td\n");
stream.append("(").append(escapePdfText(titulo)).append(") Tj\n");
stream.append("/F1 12 Tf\n");
stream.append("0 -30 Td\n");
stream.append("(Caso de uso: ").append(escapePdfText(cuId)).append(") Tj\n");
stream.append("0 -20 Td\n");
stream.append("(").append(escapePdfText(lineaPeriodo)).append(") Tj\n");
stream.append("0 -20 Td\n");
stream.append("(").append(escapePdfText(lineaFecha)).append(") Tj\n");
stream.append("0 -40 Td\n");
stream.append("(Reporte operativo generado por backend API.) Tj\n");
stream.append("ET\n");
return buildPdf(stream.toString());
} catch (Exception e) {
throw new RuntimeException("Error al generar PDF textual: " + e.getMessage(), e);
}
}
private byte[] buildPdf(String contentStream) throws Exception {
ArrayList<Integer> xref = new ArrayList<>();
ByteArrayOutputStream out = new ByteArrayOutputStream();
write(out, "%PDF-1.4\n");
xref.add(out.size());
write(out, "1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n");
xref.add(out.size());
write(out, "2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n");
xref.add(out.size());
write(out, "3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>\nendobj\n");
byte[] streamBytes = contentStream.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
xref.add(out.size());
write(out, "4 0 obj\n<< /Length " + streamBytes.length + " >>\nstream\n");
out.write(streamBytes);
write(out, "endstream\nendobj\n");
xref.add(out.size());
write(out, "5 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n");
int xrefStart = out.size();
write(out, "xref\n0 6\n");
write(out, "0000000000 65535 f \n");
for (Integer offset : xref) {
write(out, String.format("%010d 00000 n \n", offset));
}
write(out, "trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n" + xrefStart + "\n%%EOF");
return out.toByteArray();
}
private void write(ByteArrayOutputStream out, String text) throws Exception {
out.write(text.getBytes(java.nio.charset.StandardCharsets.US_ASCII));
}
private String escapePdfText(String input) {
return input
.replace("\\", "\\\\")
.replace("(", "\\(")
.replace(")", "\\)");
}
}