Files
honeyDueAPI/internal/services/pdf_service.go
Trey t c7dc56e2d2 Rebrand from MyCrib to Casera
- Update Go module from mycrib-api to casera-api
- Update all import statements across 69 Go files
- Update admin panel branding (title, sidebar, login form)
- Update email templates (subjects, bodies, signatures)
- Update PDF report generation branding
- Update Docker container names and network
- Update config defaults (database name, email sender, APNS topic)
- Update README and documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:10:48 -06:00

179 lines
4.7 KiB
Go

package services
import (
"bytes"
"fmt"
"time"
"github.com/jung-kurt/gofpdf"
)
// PDFService handles PDF generation
type PDFService struct{}
// NewPDFService creates a new PDF service
func NewPDFService() *PDFService {
return &PDFService{}
}
// GenerateTasksReportPDF generates a PDF report from task report data
func (s *PDFService) GenerateTasksReportPDF(report *TasksReportResponse) ([]byte, error) {
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.SetMargins(15, 15, 15)
pdf.AddPage()
// Header
pdf.SetFont("Arial", "B", 20)
pdf.SetTextColor(51, 51, 51)
pdf.Cell(0, 12, "Tasks Report")
pdf.Ln(14)
// Residence name
pdf.SetFont("Arial", "", 14)
pdf.SetTextColor(102, 102, 102)
pdf.Cell(0, 8, report.ResidenceName)
pdf.Ln(10)
// Generated date
pdf.SetFont("Arial", "", 10)
pdf.Cell(0, 6, fmt.Sprintf("Generated: %s", report.GeneratedAt.Format("January 2, 2006 at 3:04 PM")))
pdf.Ln(12)
// Summary section
pdf.SetFont("Arial", "B", 14)
pdf.SetTextColor(51, 51, 51)
pdf.Cell(0, 8, "Summary")
pdf.Ln(10)
// Summary box
pdf.SetFillColor(248, 249, 250)
pdf.Rect(15, pdf.GetY(), 180, 30, "F")
y := pdf.GetY() + 5
pdf.SetXY(20, y)
pdf.SetFont("Arial", "B", 12)
pdf.SetTextColor(51, 51, 51)
// Summary columns
colWidth := 45.0
pdf.Cell(colWidth, 6, "Total Tasks")
pdf.Cell(colWidth, 6, "Completed")
pdf.Cell(colWidth, 6, "Pending")
pdf.Cell(colWidth, 6, "Overdue")
pdf.Ln(8)
pdf.SetX(20)
pdf.SetFont("Arial", "", 16)
pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.TotalTasks))
pdf.SetTextColor(40, 167, 69) // Green
pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Completed))
pdf.SetTextColor(255, 193, 7) // Yellow/Orange
pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Pending))
pdf.SetTextColor(220, 53, 69) // Red
pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Overdue))
pdf.Ln(25)
// Tasks table
pdf.SetTextColor(51, 51, 51)
pdf.SetFont("Arial", "B", 14)
pdf.Cell(0, 8, "Tasks")
pdf.Ln(10)
if len(report.Tasks) == 0 {
pdf.SetFont("Arial", "I", 11)
pdf.SetTextColor(128, 128, 128)
pdf.Cell(0, 8, "No tasks found for this residence.")
} else {
// Table header
pdf.SetFont("Arial", "B", 10)
pdf.SetFillColor(233, 236, 239)
pdf.SetTextColor(51, 51, 51)
pdf.CellFormat(70, 8, "Title", "1", 0, "L", true, 0, "")
pdf.CellFormat(30, 8, "Category", "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 8, "Priority", "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 8, "Status", "1", 0, "C", true, 0, "")
pdf.CellFormat(30, 8, "Due Date", "1", 0, "C", true, 0, "")
pdf.Ln(-1)
// Table rows
pdf.SetFont("Arial", "", 9)
for _, task := range report.Tasks {
// Check if we need a new page
if pdf.GetY() > 270 {
pdf.AddPage()
// Repeat header
pdf.SetFont("Arial", "B", 10)
pdf.SetFillColor(233, 236, 239)
pdf.CellFormat(70, 8, "Title", "1", 0, "L", true, 0, "")
pdf.CellFormat(30, 8, "Category", "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 8, "Priority", "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 8, "Status", "1", 0, "C", true, 0, "")
pdf.CellFormat(30, 8, "Due Date", "1", 0, "C", true, 0, "")
pdf.Ln(-1)
pdf.SetFont("Arial", "", 9)
}
// Determine row color based on status
if task.IsCancelled {
pdf.SetFillColor(248, 215, 218) // Light red
} else if task.IsCompleted {
pdf.SetFillColor(212, 237, 218) // Light green
} else if task.IsArchived {
pdf.SetFillColor(226, 227, 229) // Light gray
} else {
pdf.SetFillColor(255, 255, 255) // White
}
// Title (truncate if too long)
title := task.Title
if len(title) > 35 {
title = title[:32] + "..."
}
// Status text
var status string
if task.IsCancelled {
status = "Cancelled"
} else if task.IsCompleted {
status = "Completed"
} else if task.IsArchived {
status = "Archived"
} else {
status = task.Status
}
// Due date
dueDate := "-"
if task.DueDate != nil {
dueDate = task.DueDate.Format("Jan 2, 2006")
}
pdf.SetTextColor(51, 51, 51)
pdf.CellFormat(70, 7, title, "1", 0, "L", true, 0, "")
pdf.CellFormat(30, 7, task.Category, "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 7, task.Priority, "1", 0, "C", true, 0, "")
pdf.CellFormat(25, 7, status, "1", 0, "C", true, 0, "")
pdf.CellFormat(30, 7, dueDate, "1", 0, "C", true, 0, "")
pdf.Ln(-1)
}
}
// Footer
pdf.SetY(-25)
pdf.SetFont("Arial", "I", 9)
pdf.SetTextColor(128, 128, 128)
pdf.Cell(0, 10, fmt.Sprintf("Casera - Tasks Report for %s", report.ResidenceName))
pdf.Ln(5)
pdf.Cell(0, 10, fmt.Sprintf("Generated on %s", time.Now().UTC().Format("2006-01-02 15:04:05 UTC")))
// Output to buffer
var buf bytes.Buffer
if err := pdf.Output(&buf); err != nil {
return nil, fmt.Errorf("failed to generate PDF: %w", err)
}
return buf.Bytes(), nil
}