package pdf import ( "bytes" "fmt" "log" "os" "text/template" "github.com/jung-kurt/gofpdf/v2" "github.com/rjNemo/rentease/assets" "github.com/rjNemo/rentease/internal/service/booking" ) type HTMLPdfClient struct{} func NewPdfClient() (*HTMLPdfClient, error) { return &HTMLPdfClient{}, nil } func (pc *HTMLPdfClient) BuildInvoice(data booking.Invoice) (*booking.GeneratedFile, error) { pdf := gofpdf.New("P", "mm", "A4", "") pdf.SetMargins(16, 16, 16) pdf.SetAutoPageBreak(true, 16) pdf.AddPage() tr := pdf.UnicodeTranslatorFromDescriptor("") writeLine := func(fontStyle string, fontSize float64, text string) { pdf.SetFont("Helvetica", fontStyle, fontSize) pdf.CellFormat(0, 7, tr(text), "", 1, "", false, 0, "") } writeLine("B", 20, fmt.Sprintf("Invoice %s", data.ID)) pdf.Ln(2) writeLine("", 11, data.Host.Name) writeLine("", 11, data.Host.Address) writeLine("", 11, fmt.Sprintf("%s %s", data.Host.ZipCode, data.Host.City)) writeLine("", 11, data.Host.PhoneNumber) writeLine("", 11, data.Host.Email) pdf.Ln(4) writeLine("B", 14, "Guest") writeLine("", 11, data.Name) if data.PhoneNumber != "" { writeLine("", 11, data.PhoneNumber) } writeLine("", 11, fmt.Sprintf("Stay: %s - %s", data.From, data.To)) writeLine("", 11, fmt.Sprintf("Platform: %s", data.Platform)) writeLine("", 11, fmt.Sprintf("Guests: %d", data.CustomersNumber)) pdf.Ln(4) writeLine("B", 14, "Charges") pdf.SetFont("Helvetica", "B", 11) pdf.CellFormat(90, 8, tr("Item"), "1", 0, "", false, 0, "") pdf.CellFormat(25, 8, tr("Qty"), "1", 0, "C", false, 0, "") pdf.CellFormat(35, 8, tr("Unit"), "1", 0, "R", false, 0, "") pdf.CellFormat(25, 8, tr("Total"), "1", 1, "R", false, 0, "") pdf.SetFont("Helvetica", "", 11) for _, line := range data.Lines { pdf.CellFormat(90, 8, tr(line.Name), "1", 0, "", false, 0, "") pdf.CellFormat(25, 8, fmt.Sprintf("%d", line.Quantity), "1", 0, "C", false, 0, "") pdf.CellFormat(35, 8, fmt.Sprintf("%s EUR", line.Price), "1", 0, "R", false, 0, "") pdf.CellFormat(25, 8, fmt.Sprintf("%s EUR", line.Total), "1", 1, "R", false, 0, "") } pdf.Ln(4) writeLine("B", 14, "Payments") if len(data.Payments) == 0 { writeLine("", 11, "No payment recorded") } else { pdf.SetFont("Helvetica", "B", 11) pdf.CellFormat(45, 8, tr("Date"), "1", 0, "", false, 0, "") pdf.CellFormat(80, 8, tr("Method"), "1", 0, "", false, 0, "") pdf.CellFormat(50, 8, tr("Amount"), "1", 1, "R", false, 0, "") pdf.SetFont("Helvetica", "", 11) for _, payment := range data.Payments { pdf.CellFormat(45, 8, tr(payment.Date), "1", 0, "", false, 0, "") pdf.CellFormat(80, 8, tr(payment.Method), "1", 0, "", false, 0, "") pdf.CellFormat(50, 8, fmt.Sprintf("%s EUR", payment.Amount), "1", 1, "R", false, 0, "") } } pdf.Ln(4) writeLine("B", 12, fmt.Sprintf("Total: %s EUR", data.Total)) writeLine("", 12, fmt.Sprintf("Paid: %s EUR", data.AmountPaid)) writeLine("B", 12, fmt.Sprintf("Balance due: %s EUR", data.BalanceDue)) var buf bytes.Buffer if err := pdf.Output(&buf); err != nil { return nil, fmt.Errorf("error writing PDF file: %v", err) } return &booking.GeneratedFile{ Name: fmt.Sprintf("%s.pdf", data.ID), ContentType: "application/pdf", Data: buf.Bytes(), }, nil } func (pc *HTMLPdfClient) BuildReport(report booking.ReportData, period string, month int, year int) (string, error) { tmpl, err := template.ParseFS(assets.Static, "assets/html/report.html") if err != nil { return "", fmt.Errorf("error parsing template: %v", err) } var buf bytes.Buffer if err := tmpl.Execute(&buf, report); err != nil { log.Printf("err: %+v\n", err) return "", fmt.Errorf("error executing template: %v", err) } outputPath := fmt.Sprintf("report-%s-%d-%d.html", period, month, year) if err := os.WriteFile(outputPath, buf.Bytes(), 0o644); err != nil { log.Printf("err: %+v\n", err) return "", fmt.Errorf("error writing HTML file: %v", err) } return outputPath, nil }