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, showLineItemDetails bool) {
109	_ = pdf.SetFont("Inter", "", 9)
110	pdf.SetTextColor(55, 55, 55)
111	_ = pdf.Cell(nil, "ITEM")
112	if showLineItemDetails {
113		pdf.SetX(quantityColumnOffset)
114		_ = pdf.Cell(nil, "QTY")
115		pdf.SetX(rateColumnOffset)
116		_ = pdf.Cell(nil, "RATE")
117	}
118	pdf.SetX(amountColumnOffset)
119	_ = pdf.Cell(nil, "AMOUNT")
120	pdf.Br(24)
121}
122
123func writeNotes(pdf *gopdf.GoPdf, notes string) {
124	pdf.SetY(600)
125
126	_ = pdf.SetFont("Inter", "", 9)
127	pdf.SetTextColor(55, 55, 55)
128	_ = pdf.Cell(nil, "NOTES")
129	pdf.Br(18)
130	_ = pdf.SetFont("Inter", "", 9)
131	pdf.SetTextColor(0, 0, 0)
132
133	formattedNotes := strings.ReplaceAll(notes, `\n`, "\n")
134	notesLines := strings.Split(formattedNotes, "\n")
135
136	for i := 0; i < len(notesLines); i++ {
137		_ = pdf.Cell(nil, notesLines[i])
138		pdf.Br(15)
139	}
140
141	pdf.Br(48)
142}
143func writeFooter(pdf *gopdf.GoPdf, id string) {
144	pdf.SetY(800)
145
146	_ = pdf.SetFont("Inter", "", 10)
147	pdf.SetTextColor(55, 55, 55)
148	_ = pdf.Cell(nil, id)
149	pdf.SetStrokeColor(225, 225, 225)
150	pdf.Line(pdf.GetX()+10, pdf.GetY()+6, 550, pdf.GetY()+6)
151	pdf.Br(48)
152}
153
154func writeRow(pdf *gopdf.GoPdf, item string, quantity int, rate float64) {
155	_ = pdf.SetFont("Inter", "", 11)
156	pdf.SetTextColor(0, 0, 0)
157
158	total := float64(quantity) * rate
159	amount := strconv.FormatFloat(total, 'f', 2, 64)
160
161	_ = pdf.Cell(nil, item)
162	if quantity != 1 {
163		pdf.SetX(quantityColumnOffset)
164		_ = pdf.Cell(nil, strconv.Itoa(quantity))
165		pdf.SetX(rateColumnOffset)
166		_ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(rate, 'f', 2, 64))
167	}
168	pdf.SetX(amountColumnOffset)
169	_ = pdf.Cell(nil, currencySymbols[file.Currency]+amount)
170	pdf.Br(24)
171}
172
173func writeTotals(pdf *gopdf.GoPdf, subtotal float64, tax float64, discount float64) {
174	pdf.SetY(600)
175
176	writeTotal(pdf, subtotalLabel, subtotal)
177	if tax > 0 {
178		writeTotal(pdf, taxLabel, tax)
179	}
180	if discount > 0 {
181		writeTotal(pdf, discountLabel, discount)
182	}
183	writeTotal(pdf, totalLabel, subtotal+tax-discount)
184}
185
186func writeTotal(pdf *gopdf.GoPdf, label string, total float64) {
187	_ = pdf.SetFont("Inter", "", 9)
188	pdf.SetTextColor(75, 75, 75)
189	pdf.SetX(rateColumnOffset)
190	_ = pdf.Cell(nil, label)
191	pdf.SetTextColor(0, 0, 0)
192	_ = pdf.SetFontSize(12)
193	pdf.SetX(amountColumnOffset - 15)
194	if label == totalLabel {
195		_ = pdf.SetFont("Inter-Bold", "", 11.5)
196	}
197	_ = pdf.Cell(nil, currencySymbols[file.Currency]+strconv.FormatFloat(total, 'f', 2, 64))
198	pdf.Br(24)
199}
200
201func getImageDimension(imagePath string) (int, int) {
202	file, err := os.Open(imagePath)
203	if err != nil {
204		fmt.Fprintf(os.Stderr, "%v\n", err)
205	}
206	defer file.Close()
207
208	image, _, err := image.DecodeConfig(file)
209	if err != nil {
210		fmt.Fprintf(os.Stderr, "%s: %v\n", imagePath, err)
211	}
212	return image.Width, image.Height
213}