A command line utility and library for generating professional looking invoices in Go.
This is a very rough draft and there could still be bugs.
You can download the CLI from the releases page or build it yourself by cloning this repository and running make
.
The CLI currently requires a YAML configuration (by default at ~/.ginvoicer/config.yaml
).
The configuration is not well documented yet, but there is a sample here and you can view the model here.
Once you have a configuration, you can generate invoices easily with:
ginvoicer -c config.yaml.sample generate \
--payer my-client \
--item hourly=120 \
--item discounted-purchase=1
Invoice written to INV-0000.pdf
The invoice generated from the above command can be seen here.
Invoice numbers will auto-increment based on your configuration directory
unless specified explicitly with the --number
flag.
ginvoicer -c config.yaml.sample generate \
--payer my-client \
--item monthly=1 \
--item taxed-hourly=120
Invoice written to INV-0001.pdf
The library is pretty straightforward. The configurations from the CLI usage are largely passed directly to the builder. A simple example looks like this:
package main
import (
"io"
"os"
"time"
"github.com/tinyzimmer/ginvoicer/pkg/invoice"
"github.com/tinyzimmer/ginvoicer/pkg/types"
)
func main() {
// The library is structured to potentially support various
// output formats in the future. For now, only PDF is supported.
builder, err := invoice.NewBuilder(types.BuildOutputPDF)
if err != nil {
panic(err)
}
// The details used to build the invoice
info := &types.InvoiceDetails{
InvoiceNumber: "INV-0001",
InvoiceDate: time.Now(),
DueDate: time.Now().AddDate(0, 0, 7),
Payee: &types.Entity{
Address: &types.Address{
Name: "My Business",
Address: "1234 Clover Lane",
City: "New York", State: "NY",
ZipCode: "10036",
},
RegistrationNo: "123456789",
BankAccount: &types.BankAccount{
Address: &types.Address{
Name: "My Bank",
Address: "221b Baker Street",
City: "London", Country: "UK",
ZipCode: "WC2N 5DU",
},
AccountNumber: "0000 1111 2222 3333",
RoutingNumber: "123456789",
},
},
Payer: &types.Entity{
Address: &types.Address{
Name: "My Client",
Address: "177A Bleecker Street",
City: "New York", State: "NY",
ZipCode: "10036",
},
},
Items: types.BillableList{
{
Description: "Hourly Work",
Quantity: 100,
UnitPrice: 50,
},
},
}
if err := builder.BuildInvoice(info); err != nil {
panic(err)
}
// The builder can either be used as a Reader or
// dumped via the WriteFile method.
f, err := os.Create("examples/library-example.pdf")
if err != nil {
panic(err)
}
io.Copy(f, builder)
// OR
if err := builder.WriteFile("examples/library-example.pdf"); err != nil {
panic(err)
}
}
The invoice generated from the above code can be seen here.