pdf.go

  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.SetTextColor(55, 55, 55)
 35
 36	formattedFrom := strings.ReplaceAll(from, `\n`, "\n")
 37	fromLines := strings.Split(formattedFrom, "\n")
 38
 39	for i := 0; i < len(fromLines); i++ {
 40		if i == 0 {
 41			_ = pdf.SetFont("Inter", "", 12)
 42			_ = pdf.Cell(nil, fromLines[i])
 43			pdf.Br(18)
 44		} else {
 45			_ = pdf.SetFont("Inter", "", 10)
 46			_ = pdf.Cell(nil, fromLines[i])
 47			pdf.Br(15)
 48		}
 49	}
 50	pdf.Br(21)
 51	pdf.SetStrokeColor(225, 225, 225)
 52	pdf.Line(pdf.GetX(), pdf.GetY(), 260, pdf.GetY())
 53	pdf.Br(36)
 54}
 55
 56func writeTitle(pdf *gopdf.GoPdf, title, id, date string) {
 57	_ = pdf.SetFont("Inter-Bold", "", 24)
 58	pdf.SetTextColor(0, 0, 0)
 59	_ = pdf.Cell(nil, title)
 60	pdf.Br(36)
 61	_ = pdf.SetFont("Inter", "", 12)
 62	pdf.SetTextColor(100, 100, 100)
 63	_ = pdf.Cell(nil, "#")
 64	_ = pdf.Cell(nil, id)
 65	pdf.SetTextColor(150, 150, 150)
 66	_ = pdf.Cell(nil, "  ·  ")
 67	pdf.SetTextColor(100, 100, 100)
 68	_ = pdf.Cell(nil, date)
 69	pdf.Br(48)
 70}
 71
 72func writeDueDate(pdf *gopdf.GoPdf, due string) {
 73	_ = pdf.SetFont("Inter", "", 9)
 74	pdf.SetTextColor(75, 75, 75)
 75	pdf.SetX(rateColumnOffset)
 76	_ = pdf.Cell(nil, "Due Date")
 77	pdf.SetTextColor(0, 0, 0)
 78	_ = pdf.SetFontSize(11)
 79	pdf.SetX(amountColumnOffset - 15)
 80	_ = pdf.Cell(nil, due)
 81	pdf.Br(12)
 82}
 83
 84func writeBillTo(pdf *gopdf.GoPdf, to string) {
 85	pdf.SetTextColor(75, 75, 75)
 86	_ = pdf.SetFont("Inter", "", 9)
 87	_ = pdf.Cell(nil, "BILL TO")
 88	pdf.Br(18)
 89	pdf.SetTextColor(75, 75, 75)
 90
 91	formattedTo := strings.ReplaceAll(to, `\n`, "\n")
 92	toLines := strings.Split(formattedTo, "\n")
 93
 94	for i := 0; i < len(toLines); i++ {
 95		if i == 0 {
 96			_ = pdf.SetFont("Inter", "", 15)
 97			_ = pdf.Cell(nil, toLines[i])
 98			pdf.Br(20)
 99		} else {
100			_ = pdf.SetFont("Inter", "", 10)
101			_ = pdf.Cell(nil, toLines[i])
102			pdf.Br(15)
103		}
104	}
105	pdf.Br(64)
106}
107
108func writeHeaderRow(pdf *gopdf.GoPdf) {
109	_ = pdf.SetFont("Inter", "", 9)
110	pdf.SetTextColor(55, 55, 55)
111	_ = pdf.Cell(nil, "ITEM")
112	pdf.SetX(quantityColumnOffset)
113	_ = pdf.Cell(nil, "QTY")
114	pdf.SetX(rateColumnOffset)
115	_ = pdf.Cell(nil, "RATE")
116	pdf.SetX(amountColumnOffset)
117	_ = pdf.Cell(nil, "AMOUNT")
118	pdf.Br(24)
119}
120
121func writeNotes(pdf *gopdf.GoPdf, notes string) {
122	pdf.SetY(600)
123
124	_ = pdf.SetFont("Inter", "", 9)
125	pdf.SetTextColor(55, 55, 55)
126	_ = pdf.Cell(nil, "NOTES")
127	pdf.Br(18)
128	_ = pdf.SetFont("Inter", "", 9)
129	pdf.SetTextColor(0, 0, 0)
130
131	formattedNotes := strings.ReplaceAll(notes, `\n`, "\n")
132	notesLines := strings.Split(formattedNotes, "\n")
133
134	for i := 0; i < len(notesLines); i++ {
135		_ = pdf.Cell(nil, notesLines[i])
136		pdf.Br(15)
137	}
138
139	pdf.Br(48)
140}
141func writeFooter(pdf *gopdf.GoPdf, id string) {
142	pdf.SetY(800)
143
144	_ = pdf.SetFont("Inter", "", 10)
145	pdf.SetTextColor(55, 55, 55)
146	_ = pdf.Cell(nil, id)
147	pdf.SetStrokeColor(225, 225, 225)
148	pdf.Line(pdf.GetX()+10, pdf.GetY()+6, 550, pdf.GetY()+6)
149	pdf.Br(48)
150}
151
152func writeRow(pdf *gopdf.GoPdf, item string, quantity int, rate float64) {
153	_ = pdf.SetFont("Inter", "", 11)
154	pdf.SetTextColor(0, 0, 0)
155
156	total := float64(quantity) * rate
157	amount := strconv.FormatFloat(total, 'f', 2, 64)
158
159	_ = pdf.Cell(nil, item)
160	pdf.SetX(quantityColumnOffset)
161	_ = pdf.Cell(nil, strconv.Itoa(quantity))
162	pdf.SetX(rateColumnOffset)
163	_ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(rate, 'f', 2, 64))
164	pdf.SetX(amountColumnOffset)
165	_ = pdf.Cell(nil, currencySymbols[file.Currency]+amount)
166	pdf.Br(24)
167}
168
169func writeTotals(pdf *gopdf.GoPdf, subtotal float64, tax float64, discount float64) {
170	pdf.SetY(600)
171
172	writeTotal(pdf, subtotalLabel, subtotal)
173	if tax > 0 {
174		writeTotal(pdf, taxLabel, tax)
175	}
176	if discount > 0 {
177		writeTotal(pdf, discountLabel, discount)
178	}
179	writeTotal(pdf, totalLabel, subtotal+tax-discount)
180}
181
182func writeTotal(pdf *gopdf.GoPdf, label string, total float64) {
183	_ = pdf.SetFont("Inter", "", 9)
184	pdf.SetTextColor(75, 75, 75)
185	pdf.SetX(rateColumnOffset)
186	_ = pdf.Cell(nil, label)
187	pdf.SetTextColor(0, 0, 0)
188	_ = pdf.SetFontSize(12)
189	pdf.SetX(amountColumnOffset - 15)
190	if label == totalLabel {
191		_ = pdf.SetFont("Inter-Bold", "", 11.5)
192	}
193	_ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(total, 'f', 2, 64))
194	pdf.Br(24)
195}
196
197func getImageDimension(imagePath string) (int, int) {
198	file, err := os.Open(imagePath)
199	if err != nil {
200		fmt.Fprintf(os.Stderr, "%v\n", err)
201	}
202	defer file.Close()
203
204	image, _, err := image.DecodeConfig(file)
205	if err != nil {
206		fmt.Fprintf(os.Stderr, "%s: %v\n", imagePath, err)
207	}
208	return image.Width, image.Height
209}