1package main
2
3import (
4 "fmt"
5 "image"
6 "os"
7 "strconv"
8 "strings"
9
10 "github.com/signintech/gopdf"
11)
12
13const (
14 quantityColumnOffset = 360
15 rateColumnOffset = 405
16 amountColumnOffset = 480
17)
18
19const (
20 subtotalLabel = "Subtotal"
21 discountLabel = "Discount"
22 taxLabel = "Tax"
23 totalLabel = "Total"
24)
25
26func writeLogo(pdf *gopdf.GoPdf, logo string, from string) {
27 if logo != "" {
28 width, height := getImageDimension(logo)
29 scaledWidth := 100.0
30 scaledHeight := float64(height) * scaledWidth / float64(width)
31 _ = pdf.Image(logo, pdf.GetX(), pdf.GetY(), &gopdf.Rect{W: scaledWidth, H: scaledHeight})
32 pdf.Br(scaledHeight + 24)
33 }
34 _ = pdf.SetFont("Inter", "", 12)
35 pdf.SetTextColor(55, 55, 55)
36 _ = pdf.Cell(nil, from)
37 pdf.Br(36)
38 pdf.SetStrokeColor(225, 225, 225)
39 pdf.Line(pdf.GetX(), pdf.GetY(), 100, pdf.GetY())
40 pdf.Br(36)
41}
42
43func writeTitle(pdf *gopdf.GoPdf, title, id, date string) {
44 _ = pdf.SetFont("Inter-Bold", "", 24)
45 pdf.SetTextColor(0, 0, 0)
46 _ = pdf.Cell(nil, title)
47 pdf.Br(36)
48 _ = pdf.SetFont("Inter", "", 12)
49 pdf.SetTextColor(100, 100, 100)
50 _ = pdf.Cell(nil, "#")
51 _ = pdf.Cell(nil, id)
52 pdf.SetTextColor(150, 150, 150)
53 _ = pdf.Cell(nil, " · ")
54 pdf.SetTextColor(100, 100, 100)
55 _ = pdf.Cell(nil, date)
56 pdf.Br(48)
57}
58
59func writeDueDate(pdf *gopdf.GoPdf, due string) {
60 _ = pdf.SetFont("Inter", "", 9)
61 pdf.SetTextColor(75, 75, 75)
62 pdf.SetX(rateColumnOffset)
63 _ = pdf.Cell(nil, "Due Date")
64 pdf.SetTextColor(0, 0, 0)
65 _ = pdf.SetFontSize(11)
66 pdf.SetX(amountColumnOffset - 15)
67 _ = pdf.Cell(nil, due)
68 pdf.Br(12)
69}
70
71func writeBillTo(pdf *gopdf.GoPdf, to string) {
72 pdf.SetTextColor(75, 75, 75)
73 _ = pdf.SetFont("Inter", "", 9)
74 _ = pdf.Cell(nil, "BILL TO")
75 pdf.Br(18)
76 pdf.SetTextColor(75, 75, 75)
77 _ = pdf.SetFont("Inter", "", 15)
78 _ = pdf.Cell(nil, to)
79 pdf.Br(64)
80}
81
82func writeHeaderRow(pdf *gopdf.GoPdf) {
83 _ = pdf.SetFont("Inter", "", 9)
84 pdf.SetTextColor(55, 55, 55)
85 _ = pdf.Cell(nil, "ITEM")
86 pdf.SetX(quantityColumnOffset)
87 _ = pdf.Cell(nil, "QTY")
88 pdf.SetX(rateColumnOffset)
89 _ = pdf.Cell(nil, "RATE")
90 pdf.SetX(amountColumnOffset)
91 _ = pdf.Cell(nil, "AMOUNT")
92 pdf.Br(24)
93}
94
95func writeNotes(pdf *gopdf.GoPdf, notes string) {
96 pdf.SetY(650)
97
98 _ = pdf.SetFont("Inter", "", 10)
99 pdf.SetTextColor(55, 55, 55)
100 _ = pdf.Cell(nil, "Notes")
101 pdf.Br(18)
102 _ = pdf.SetFont("Inter", "", 8)
103 pdf.SetTextColor(0, 0, 0)
104
105 formattedNotes := strings.ReplaceAll(notes, `\n`, "\n")
106 notesLines := strings.Split(formattedNotes, "\\n")
107
108 for i := 0; i < len(notesLines); i++ {
109 _ = pdf.Cell(nil, notesLines[i])
110 pdf.Br(15)
111 }
112
113 pdf.Br(48)
114}
115func writeFooter(pdf *gopdf.GoPdf, id string) {
116 pdf.SetY(800)
117
118 _ = pdf.SetFont("Inter", "", 10)
119 pdf.SetTextColor(55, 55, 55)
120 _ = pdf.Cell(nil, id)
121 pdf.SetStrokeColor(225, 225, 225)
122 pdf.Line(pdf.GetX()+10, pdf.GetY()+6, 550, pdf.GetY()+6)
123 pdf.Br(48)
124}
125
126func writeRow(pdf *gopdf.GoPdf, item string, quantity int, rate float64) {
127 _ = pdf.SetFont("Inter", "", 11)
128 pdf.SetTextColor(0, 0, 0)
129
130 total := float64(quantity) * rate
131 amount := strconv.FormatFloat(total, 'f', 2, 64)
132
133 _ = pdf.Cell(nil, item)
134 pdf.SetX(quantityColumnOffset)
135 _ = pdf.Cell(nil, strconv.Itoa(quantity))
136 pdf.SetX(rateColumnOffset)
137 _ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(rate, 'f', 2, 64))
138 pdf.SetX(amountColumnOffset)
139 _ = pdf.Cell(nil, currencySymbols[file.Currency]+amount)
140 pdf.Br(24)
141}
142
143func writeTotals(pdf *gopdf.GoPdf, subtotal float64, tax float64, discount float64) {
144 pdf.SetY(650)
145
146 writeTotal(pdf, subtotalLabel, subtotal)
147 if tax > 0 {
148 writeTotal(pdf, taxLabel, tax)
149 }
150 if discount > 0 {
151 writeTotal(pdf, discountLabel, discount)
152 }
153 writeTotal(pdf, totalLabel, subtotal+tax-discount)
154}
155
156func writeTotal(pdf *gopdf.GoPdf, label string, total float64) {
157 _ = pdf.SetFont("Inter", "", 9)
158 pdf.SetTextColor(75, 75, 75)
159 pdf.SetX(rateColumnOffset)
160 _ = pdf.Cell(nil, label)
161 pdf.SetTextColor(0, 0, 0)
162 _ = pdf.SetFontSize(12)
163 pdf.SetX(amountColumnOffset - 15)
164 if label == totalLabel {
165 _ = pdf.SetFont("Inter-Bold", "", 11.5)
166 }
167 _ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(total, 'f', 2, 64))
168 pdf.Br(24)
169}
170
171func getImageDimension(imagePath string) (int, int) {
172 file, err := os.Open(imagePath)
173 if err != nil {
174 fmt.Fprintf(os.Stderr, "%v\n", err)
175 }
176 defer file.Close()
177
178 image, _, err := image.DecodeConfig(file)
179 if err != nil {
180 fmt.Fprintf(os.Stderr, "%s: %v\n", imagePath, err)
181 }
182 return image.Width, image.Height
183}