1package main
2
3import (
4 _ "embed"
5 "flag"
6 "fmt"
7 "log"
8 "strings"
9 "time"
10
11 "github.com/signintech/gopdf"
12 "github.com/spf13/cobra"
13)
14
15//go:embed Inter.ttf
16var interFont []byte
17
18//go:embed Inter-Bold.ttf
19var interBoldFont []byte
20
21var (
22 id string
23 title string
24
25 logo string
26 from string
27 to string
28 date string
29 due string
30
31 items []string
32 quantities []int
33 rates []float64
34
35 tax float64
36 discount float64
37 currency string
38
39 note string
40 output string
41)
42
43func init() {
44 generateCmd.Flags().StringVar(&id, "id", time.Now().Format("20060102"), "ID")
45 generateCmd.Flags().StringVar(&title, "title", "INVOICE", "Title")
46
47 generateCmd.Flags().Float64SliceVarP(&rates, "rate", "r", []float64{25}, "Rates")
48 generateCmd.Flags().IntSliceVarP(&quantities, "quantity", "q", []int{2}, "Quantities")
49 generateCmd.Flags().StringSliceVarP(&items, "item", "i", []string{"Paper Cranes"}, "Items")
50
51 generateCmd.Flags().StringVarP(&logo, "logo", "l", "", "Company logo")
52 generateCmd.Flags().StringVarP(&from, "from", "f", "Project Folded, Inc.", "Issuing company")
53 generateCmd.Flags().StringVarP(&to, "to", "t", "Untitled Corporation, Inc.", "Recipient company")
54 generateCmd.Flags().StringVar(&date, "date", time.Now().Format("Jan 02, 2006"), "Date")
55 generateCmd.Flags().StringVar(&due, "due", time.Now().AddDate(0, 0, 14).Format("Jan 02, 2006"), "Payment due date")
56
57 generateCmd.Flags().Float64Var(&tax, "tax", 0, "Tax")
58 generateCmd.Flags().Float64VarP(&discount, "discount", "d", 0.0, "Discount")
59 generateCmd.Flags().StringVarP(¤cy, "currency", "c", "USD", "Currency")
60
61 generateCmd.Flags().StringVarP(¬e, "note", "n", "", "Note")
62 generateCmd.Flags().StringVarP(&output, "output", "o", "invoice.pdf", "Output file (.pdf)")
63
64 flag.Parse()
65}
66
67var rootCmd = &cobra.Command{
68 Use: "invoice",
69 Short: "Invoice generates invoices from the command line.",
70 Long: `Invoice generates invoices from the command line.`,
71}
72
73var generateCmd = &cobra.Command{
74 Use: "generate",
75 Short: "Generate an invoice",
76 Long: `Generate an invoice`,
77 RunE: func(cmd *cobra.Command, args []string) error {
78 pdf := gopdf.GoPdf{}
79 pdf.Start(gopdf.Config{
80 PageSize: *gopdf.PageSizeA4,
81 })
82 pdf.SetMargins(40, 40, 40, 40)
83 pdf.AddPage()
84 err := pdf.AddTTFFontData("Inter", interFont)
85 if err != nil {
86 return err
87 }
88
89 err = pdf.AddTTFFontData("Inter-Bold", interBoldFont)
90 if err != nil {
91 return err
92 }
93
94 writeLogo(&pdf, logo, from)
95 writeTitle(&pdf, title, id)
96 writeBillTo(&pdf, to)
97 writeHeaderRow(&pdf)
98 subtotal := 0.0
99 for i := range items {
100 q := 1
101 if len(quantities) > i {
102 q = quantities[i]
103 }
104
105 r := 0.0
106 if len(rates) > i {
107 r = rates[i]
108 }
109
110 writeRow(&pdf, items[i], q, r)
111 subtotal += float64(q) * r
112 }
113 writeNotes(&pdf, note)
114 writeTotals(&pdf, subtotal, subtotal*tax, subtotal*discount)
115 writeFooter(&pdf, id)
116 output = strings.TrimSuffix(output, ".pdf") + ".pdf"
117 err = pdf.WritePdf(output)
118 if err != nil {
119 return err
120 }
121
122 fmt.Printf("Generated %s\n", output)
123
124 return nil
125
126 },
127}
128
129func main() {
130 rootCmd.AddCommand(generateCmd)
131 err := rootCmd.Execute()
132 if err != nil {
133 log.Fatal(err)
134 }
135}