main.go

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