11package handlers
22
33import (
4- "UnlockEdv2/src"
4+ "UnlockEdv2/src/jasper "
55 "UnlockEdv2/src/models"
6- "bytes"
76 "context"
87 "encoding/csv"
98 "encoding/json"
@@ -13,106 +12,15 @@ import (
1312 "strings"
1413 "time"
1514
16- "github.com/go-pdf/fpdf"
1715 "github.com/sirupsen/logrus"
1816 "github.com/xuri/excelize/v2"
1917)
2018
2119const (
22- pdfMaxWidth = 280.0
23- pdfSampleSize = 100
2420 maxDateRangeDays = 90
2521 maxFacilitiesInList = 50
2622)
2723
28- func calculateOptimalColumnWidths (config * ColumnWidthConfig ) []float64 {
29- colWidths := make ([]float64 , len (config .Headers ))
30- copy (colWidths , config .MinWidths )
31-
32- sampleSize := config .SampleSize
33- if sampleSize > len (config .Data ) {
34- sampleSize = len (config .Data )
35- }
36-
37- for i := 0 ; i < sampleSize ; i ++ {
38- for j , cell := range config .Data [i ] {
39- if j < len (colWidths ) {
40- contentWidth := config .PDF .GetStringWidth (cell ) + 4
41- if contentWidth > colWidths [j ] {
42- colWidths [j ] = contentWidth
43- }
44- }
45- }
46- }
47-
48- totalWidth := 0.0
49- for _ , width := range colWidths {
50- totalWidth += width
51- }
52-
53- if totalWidth > config .MaxWidth {
54- scale := config .MaxWidth / totalWidth
55- for i := range colWidths {
56- colWidths [i ] *= scale
57- }
58- }
59-
60- return colWidths
61- }
62-
63- func renderPDFTable (config * PDFTableConfig ) {
64- config .PDF .SetFont ("Arial" , "B" , config .HeaderFontSize )
65- for i , header := range config .Headers {
66- config .PDF .CellFormat (config .ColumnWidths [i ], 7 , header , "1" , 0 , "C" , false , 0 , "" )
67- }
68- config .PDF .Ln (- 1 )
69-
70- config .PDF .SetFont ("Arial" , "" , config .DataFontSize )
71- for _ , row := range config .Data {
72- for i , cell := range row {
73- if i < len (config .ColumnWidths ) {
74- alignment := "L"
75- if i < len (config .Alignments ) {
76- alignment = config .Alignments [i ]
77- }
78- config .PDF .CellFormat (config .ColumnWidths [i ], 6 , cell , "1" , 0 , alignment , false , 0 , "" )
79- }
80- }
81- config .PDF .Ln (- 1 )
82- }
83- }
84-
85- func renderPDFHeader (pdf * fpdf.Fpdf , title string , filterSummary []models.PDFFilterLine ) {
86- pdf .RegisterImageOptionsReader ("logo" , fpdf.ImageOptions {ImageType : "PNG" }, bytes .NewReader (src .UnlockedLogoImg ))
87- pdf .ImageOptions ("logo" , 10 , 10 , 25 , 0 , false , fpdf.ImageOptions {ImageType : "PNG" }, 0 , "" )
88-
89- pdf .SetFont ("Arial" , "B" , 16 )
90- pdf .SetXY (40 , 12 )
91- pdf .Cell (0 , 8 , title + " Report" )
92-
93- pdf .SetFont ("Arial" , "" , 9 )
94- pdf .SetXY (40 , 21 )
95- pdf .Cell (0 , 5 , "Generated: " + time .Now ().Format ("January 2, 2006 at 3:04 PM" ))
96-
97- if len (filterSummary ) > 0 {
98- pdf .SetXY (10 , 38 )
99- pdf .SetFont ("Arial" , "B" , 10 )
100- pdf .Cell (0 , 5 , "Report Filters:" )
101- pdf .Ln (6 )
102-
103- pdf .SetFont ("Arial" , "" , 9 )
104- for _ , filter := range filterSummary {
105- pdf .SetX (15 )
106- pdf .Cell (30 , 5 , filter .Label + ":" )
107- pdf .Cell (0 , 5 , filter .Value )
108- pdf .Ln (5 )
109- }
110- pdf .Ln (5 )
111- } else {
112- pdf .Ln (30 )
113- }
114- }
115-
11624func buildFilterSummary (req * models.ReportGenerateRequest , facilityName , residentName string ) []models.PDFFilterLine {
11725 var filters []models.PDFFilterLine
11826
@@ -245,25 +153,6 @@ func (srv *Server) handleGenerateReport(w http.ResponseWriter, r *http.Request,
245153 }
246154}
247155
248- type PDFTableConfig struct {
249- PDF * fpdf.Fpdf
250- Headers []string
251- ColumnWidths []float64
252- Alignments []string
253- Data [][]string
254- HeaderFontSize float64
255- DataFontSize float64
256- }
257-
258- type ColumnWidthConfig struct {
259- PDF * fpdf.Fpdf
260- Headers []string
261- Data [][]string
262- MinWidths []float64
263- MaxWidth float64
264- SampleSize int
265- }
266-
267156type reportExporter interface {
268157 ToCSV () ([][]string , error )
269158 ToExcel () (* excelize.File , error )
@@ -412,39 +301,30 @@ func (srv *Server) exportReport(w http.ResponseWriter, report reportExporter, fo
412301
413302 filterSummary := buildFilterSummary (req , facilityName , residentName )
414303
415- pdf := fpdf .New ("L" , "mm" , "A4" , "" )
416- pdf .AddPage ()
417-
418- renderPDFHeader (pdf , config .Title , filterSummary )
419-
420- pdf .SetFont ("Arial" , "" , config .DataFontSize )
421-
422- colWidths := calculateOptimalColumnWidths (& ColumnWidthConfig {
423- PDF : pdf ,
424- Headers : config .Headers ,
425- Data : config .Data ,
426- MinWidths : config .MinWidths ,
427- MaxWidth : pdfMaxWidth ,
428- SampleSize : pdfSampleSize ,
429- })
304+ var pdfBytes []byte
305+ switch req .Type {
306+ case models .AttendanceReport :
307+ pdfBytes , err = jasper .GenerateAttendanceReportPDF (config , filterSummary )
308+ case models .ProgramOutcomesReport :
309+ pdfBytes , err = jasper .GenerateProgramOutcomesReportPDF (config , filterSummary )
310+ case models .FacilityComparisonReport :
311+ pdfBytes , err = jasper .GenerateFacilityComparisonReportPDF (config , filterSummary )
312+ default :
313+ return newBadRequestServiceError (errors .New ("unsupported report type" ), "unsupported report type for PDF generation" )
314+ }
430315
431- renderPDFTable (& PDFTableConfig {
432- PDF : pdf ,
433- Headers : config .Headers ,
434- ColumnWidths : colWidths ,
435- Alignments : config .Alignments ,
436- Data : config .Data ,
437- HeaderFontSize : config .HeaderFontSize ,
438- DataFontSize : config .DataFontSize ,
439- })
316+ if err != nil {
317+ logrus .WithError (err ).Error ("Failed to generate PDF with Jasper" )
318+ return newInternalServerServiceError (err , "failed to generate PDF" )
319+ }
440320
441321 filename := fmt .Sprintf ("%s-Report-%s.pdf" , config .Title , time .Now ().Format ("2006-01-02" ))
442322 w .Header ().Set ("Content-Type" , "application/pdf" )
443323 w .Header ().Set ("Content-Disposition" , fmt .Sprintf ("attachment; filename=\" %s\" " , filename ))
444324 w .WriteHeader (http .StatusOK )
445325
446- if err := pdf . Output ( w ); err != nil {
447- return newInternalServerServiceError (err , "failed to generate PDF" )
326+ if _ , err := w . Write ( pdfBytes ); err != nil {
327+ return newInternalServerServiceError (err , "failed to write PDF" )
448328 }
449329 return nil
450330
0 commit comments