package pdf import ( "bytes" "fmt" "time" "github.com/jung-kurt/gofpdf" ) // InvoiceData contains all data needed to generate an invoice PDF type InvoiceData struct { InvoiceNumber string InvoiceDate time.Time DueDate time.Time CustomerName string CustomerAddress string CustomerOrgNr string Items []InvoiceItem Subtotal float64 VATRate float64 VATAmount float64 Total float64 Currency string CompanyName string CompanyAddress string CompanyOrgNr string CompanyBankgiro string Notes string } // InvoiceItem represents a line item on an invoice type InvoiceItem struct { Description string Quantity float64 Unit string UnitPrice float64 Total float64 } // QuoteData contains all data needed to generate a quote PDF type QuoteData struct { QuoteNumber string QuoteDate time.Time ValidUntil time.Time CustomerName string CustomerAddress string Items []QuoteItem Subtotal float64 VATRate float64 VATAmount float64 Total float64 Currency string CompanyName string CompanyAddress string Notes string } // QuoteItem represents a line item on a quote type QuoteItem struct { Description string Quantity float64 Unit string UnitPrice float64 Total float64 } // GenerateInvoice creates a professional invoice PDF func GenerateInvoice(data InvoiceData) ([]byte, error) { pdf := gofpdf.New("P", "mm", "A4", "") pdf.AddPage() // Header with company info pdf.SetFont("Arial", "B", 20) pdf.SetTextColor(201, 106, 58) // Terracotta pdf.Cell(0, 12, "FAKTURA") pdf.Ln(8) // Company info pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(50, 50, 50) pdf.Cell(0, 5, data.CompanyName) pdf.Ln(5) pdf.SetFont("Arial", "", 9) pdf.Cell(0, 4, data.CompanyAddress) pdf.Ln(4) if data.CompanyOrgNr != "" { pdf.Cell(0, 4, fmt.Sprintf("Org.nr: %s", data.CompanyOrgNr)) pdf.Ln(4) } if data.CompanyBankgiro != "" { pdf.Cell(0, 4, fmt.Sprintf("Bankgiro: %s", data.CompanyBankgiro)) pdf.Ln(4) } pdf.Ln(5) // Invoice details box pdf.SetFillColor(250, 248, 245) pdf.Rect(130, 30, 70, 35, "F") pdf.SetXY(135, 33) pdf.SetFont("Arial", "B", 9) pdf.SetTextColor(201, 106, 58) pdf.Cell(0, 5, "FAKTURAINFORMATION") pdf.Ln(6) pdf.SetFont("Arial", "", 9) pdf.SetTextColor(50, 50, 50) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Fakturanr: %s", data.InvoiceNumber)) pdf.Ln(4) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Datum: %s", data.InvoiceDate.Format("2006-01-02"))) pdf.Ln(4) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Förfallo: %s", data.DueDate.Format("2006-01-02"))) pdf.Ln(4) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Valuta: %s", data.Currency)) pdf.Ln(4) // Customer info pdf.SetXY(10, 75) pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(201, 106, 58) pdf.Cell(0, 5, "KUND") pdf.Ln(6) pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(50, 50, 50) pdf.Cell(0, 5, data.CustomerName) pdf.Ln(5) pdf.SetFont("Arial", "", 9) pdf.Cell(0, 4, data.CustomerAddress) pdf.Ln(4) if data.CustomerOrgNr != "" { pdf.Cell(0, 4, fmt.Sprintf("Org.nr: %s", data.CustomerOrgNr)) pdf.Ln(4) } pdf.Ln(10) // Items table header pdf.SetFillColor(201, 106, 58) pdf.SetTextColor(255, 255, 255) pdf.SetFont("Arial", "B", 9) pdf.Cell(80, 8, "Beskrivning") pdf.Cell(25, 8, "Antal") pdf.Cell(25, 8, "Enhet") pdf.Cell(30, 8, "Pris") pdf.Cell(30, 8, "Belopp") pdf.Ln(8) // Items pdf.SetTextColor(50, 50, 50) pdf.SetFont("Arial", "", 9) for i, item := range data.Items { if i%2 == 0 { pdf.SetFillColor(250, 248, 245) pdf.Rect(10, pdf.GetY(), 190, 6, "F") } pdf.Cell(80, 6, item.Description) pdf.Cell(25, 6, fmt.Sprintf("%.2f", item.Quantity)) pdf.Cell(25, 6, item.Unit) pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.UnitPrice)) pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.Total)) pdf.Ln(6) } pdf.Ln(5) // Totals pdf.SetX(120) pdf.SetFont("Arial", "", 9) pdf.Cell(40, 5, "Delsumma:") pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.Subtotal, data.Currency)) pdf.Ln(5) pdf.SetX(120) pdf.Cell(40, 5, fmt.Sprintf("Moms (%.0f%%):", data.VATRate*100)) pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.VATAmount, data.Currency)) pdf.Ln(5) pdf.SetX(120) pdf.SetFont("Arial", "B", 11) pdf.SetTextColor(201, 106, 58) pdf.Cell(40, 7, "ATT BETALA:") pdf.Cell(30, 7, fmt.Sprintf("%.2f %s", data.Total, data.Currency)) pdf.Ln(10) // Notes if data.Notes != "" { pdf.SetFont("Arial", "I", 8) pdf.SetTextColor(100, 100, 100) pdf.MultiCell(0, 4, data.Notes, "", "", false) } // Footer pdf.SetY(-20) pdf.SetFont("Arial", "", 8) pdf.SetTextColor(150, 150, 150) pdf.Cell(0, 4, fmt.Sprintf("%s | Faktura %s | Sida %d", data.CompanyName, data.InvoiceNumber, pdf.PageNo())) var buf bytes.Buffer err := pdf.Output(&buf) if err != nil { return nil, err } return buf.Bytes(), nil } // GenerateQuote creates a professional quote PDF func GenerateQuote(data QuoteData) ([]byte, error) { pdf := gofpdf.New("P", "mm", "A4", "") pdf.AddPage() // Header pdf.SetFont("Arial", "B", 20) pdf.SetTextColor(201, 106, 58) pdf.Cell(0, 12, "OFFERT") pdf.Ln(8) // Company info pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(50, 50, 50) pdf.Cell(0, 5, data.CompanyName) pdf.Ln(5) pdf.SetFont("Arial", "", 9) pdf.Cell(0, 4, data.CompanyAddress) pdf.Ln(5) // Quote details box pdf.SetFillColor(250, 248, 245) pdf.Rect(130, 30, 70, 30, "F") pdf.SetXY(135, 33) pdf.SetFont("Arial", "B", 9) pdf.SetTextColor(201, 106, 58) pdf.Cell(0, 5, "OFFERTINFORMATION") pdf.Ln(6) pdf.SetFont("Arial", "", 9) pdf.SetTextColor(50, 50, 50) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Offertnr: %s", data.QuoteNumber)) pdf.Ln(4) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Datum: %s", data.QuoteDate.Format("2006-01-02"))) pdf.Ln(4) pdf.SetX(135) pdf.Cell(0, 4, fmt.Sprintf("Giltig till: %s", data.ValidUntil.Format("2006-01-02"))) pdf.Ln(4) // Customer info pdf.SetXY(10, 75) pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(201, 106, 58) pdf.Cell(0, 5, "KUND") pdf.Ln(6) pdf.SetFont("Arial", "B", 10) pdf.SetTextColor(50, 50, 50) pdf.Cell(0, 5, data.CustomerName) pdf.Ln(5) pdf.SetFont("Arial", "", 9) pdf.Cell(0, 4, data.CustomerAddress) pdf.Ln(10) // Items table header pdf.SetFillColor(201, 106, 58) pdf.SetTextColor(255, 255, 255) pdf.SetFont("Arial", "B", 9) pdf.Cell(80, 8, "Beskrivning") pdf.Cell(25, 8, "Antal") pdf.Cell(25, 8, "Enhet") pdf.Cell(30, 8, "Pris") pdf.Cell(30, 8, "Belopp") pdf.Ln(8) // Items pdf.SetTextColor(50, 50, 50) pdf.SetFont("Arial", "", 9) for i, item := range data.Items { if i%2 == 0 { pdf.SetFillColor(250, 248, 245) pdf.Rect(10, pdf.GetY(), 190, 6, "F") } pdf.Cell(80, 6, item.Description) pdf.Cell(25, 6, fmt.Sprintf("%.2f", item.Quantity)) pdf.Cell(25, 6, item.Unit) pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.UnitPrice)) pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.Total)) pdf.Ln(6) } pdf.Ln(5) // Totals pdf.SetX(120) pdf.SetFont("Arial", "", 9) pdf.Cell(40, 5, "Delsumma:") pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.Subtotal, data.Currency)) pdf.Ln(5) pdf.SetX(120) pdf.Cell(40, 5, fmt.Sprintf("Moms (%.0f%%):", data.VATRate*100)) pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.VATAmount, data.Currency)) pdf.Ln(5) pdf.SetX(120) pdf.SetFont("Arial", "B", 11) pdf.SetTextColor(201, 106, 58) pdf.Cell(40, 7, "TOTALT:") pdf.Cell(30, 7, fmt.Sprintf("%.2f %s", data.Total, data.Currency)) pdf.Ln(10) // Notes if data.Notes != "" { pdf.SetFont("Arial", "I", 8) pdf.SetTextColor(100, 100, 100) pdf.MultiCell(0, 4, data.Notes, "", "", false) } // Footer pdf.SetY(-20) pdf.SetFont("Arial", "", 8) pdf.SetTextColor(150, 150, 150) pdf.Cell(0, 4, fmt.Sprintf("%s | Offert %s | Sida %d", data.CompanyName, data.QuoteNumber, pdf.PageNo())) var buf bytes.Buffer err := pdf.Output(&buf) if err != nil { return nil, err } return buf.Bytes(), nil }