M README.md +4 -0
@@ 127,6 127,10 @@ Set your client's contact info with the
: string, the second line of your client's address
+<client>.id
+
+: string, an ID used in generating a unique invoice number
+
E.g.
timew config megacorp.company "MegaCorp, Inc"
M data.go +39 -22
@@ 6,6 6,8 @@ import (
"bytes"
"compress/gzip"
"encoding/base64"
+ "fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
@@ 100,7 102,24 @@ func (f *_escFile) Close() error {
}
func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
- return nil, nil
+ if !f.isDir {
+ return nil, fmt.Errorf(" escFile.Readdir: '%s' is not directory", f.name)
+ }
+
+ fis, ok := _escDirs[f.local]
+ if !ok {
+ return nil, fmt.Errorf(" escFile.Readdir: '%s' is directory, but we have no info about content of this dir, local=%s", f.name, f.local)
+ }
+ limit := count
+ if count <= 0 || limit > len(fis) {
+ limit = len(fis)
+ }
+
+ if len(fis) == 0 && count > 0 {
+ return nil, io.EOF
+ }
+
+ return fis[0:limit], nil
}
func (f *_escFile) Stat() (os.FileInfo, error) {
@@ 191,29 210,27 @@ func FSMustString(useLocal bool, name st
var _escData = map[string]*_escFile{
"/invoice.tmpl": {
+ name: "invoice.tmpl",
local: "invoice.tmpl",
- size: 1770,
- modtime: 1577834313,
+ size: 1816,
+ modtime: 1589222202,
compressed: `
-H4sIAAAAAAAC/7RUTW8bNxA9i7/iITqkBYx1rDRAkRP14cABDFuVVBQ5cndHElEuuSC5dlSW/73gUvZK
-jt2eypM0b+a9x5nh8vXBfdWV6mpCQG0qRHYe86VKsYWpuoa0ZwD/qqWXQn0x2iNgIxtymAlHuJq0iMA4
-xy4wN52VZC9wQ+qBvKzEBYqiSBxzo7pG33VNSRYBV6nu9IxxxMwWVZ/r8NPkAh97hp8TxVLs6N5K0l54
-aTQClsZ6K6RHfMJvSNRkHQLWsmkVZeR4gVuhd53YpVte652Sbp/h+9bLRv5FiSCV3pkzd2N8I3d5Z+Aa
-YT3axFBaEn9iS8J3ltjlJeMb+u7BZ7STmrExZnIHLRqC0fCmZXwhXavEATxZlHqHgDD0CTOjakx+Sf3k
-x0aH0ByKO9FQjIhpJl86pf6Qtd+vOkVJ5JvpLCqjvag8pN4a2/StYfyWtn5QvP7eCl0jsBDIVaIlNIdi
-WteWnLuKEXwld/ssOeDLvdFZmt8uX6ucvFV53Qipnivj4FSl4b13/205MD5DwFf9YGRF2JjPiWx5YiNz
-FXPTtEIfYkard5fvDH7M6dXi6wynbXgbnsSYLsIXy97ZQnj6nAt4+p0RNsYNWXrv4PcEeTTvRamI8XtN
-K/MIvikV2Gj8vF0LcpWVbb/RZos12QdZkcNvndBe+gNenN+19FjaxPz2mTam056NRO4vAviclMJj2h6E
-X6sIPsMUf5/HJ8WnjMxeR6SuKa1m5W2fNn+Z9vGVpAUiG5UvjAzSg9RTIWy/U/GE/gcokQbGV+ZRsJHt
-FInSPKSHfSCX9FKoJGUez0N91tErPhQfJtuz5BPkU49MEd4cUGSjtKPPc4psNEc4nU9kowXCcRiIjIVg
-hd4Rihh772VWCKFISxTjsLrFVGuTv3PpIWWpEIob01mXI/McWeXKo1YIxborN8aL/gGmddZ1TJv7v7Xq
-6rlT6670SXnw2//tPac7P7kezOb0DB0dJqKZUEJXhEVHT1z/XpsueLtkjF/rGv2nmP0TAAD//1j+p/vq
-BgAA
+H4sIAAAAAAAC/7RUzW7jNhddm09xMF7M9wGpMvF0gCIr+ieDBAgS13ZRzJKSrm2iFCmQVDIuy3cvKCmW
+nUnaVbUxfM+955z7I/H1wd3pQjUlIaA0BSI7j/lcpdjCFE1F2jOA32nppVBfjfYI2MiKHGbCEa4mNSIw
+7mIXmJvGSrIXuCX1RF4W4gJZliWOuVFNpR+aKieLgKtUd/qM0WNmi6LNdfjf5AKfW4b/J4ql2NGjlaS9
+8NJoBCyN9VZIj/iC35IoyToErGVVK+qQvoF7oXeN2KUub/ROSbfv4Mfay0r+SYkglT6YM3djfCN3+WDg
+KmE96sSQWxJ/YEvCN5bY5SXjG/ruwWe0k5qxMWZyBy0qgtHwpmZ8IV2txAE8WZR6h4AwzAkzo0pMfk7z
+5P2gQ6gO2YOoKEbEtJOvjVK/y9LvV42iJPLNNBaF0V4UHlJvja3a0TB+T1s/KN58r4UuEVgI5ApRE6pD
+Ni1LS85dxQi+krt9Jzngy73RnTS/X75VOXmv8qYSUh0r4+BUpeV9dP9uOTA+Q8CdfjKyIGzMdSJbntjo
+uLK5qWqhD7FDiw+XHwx+zGnV4tsMp2N4H57EmBrhi2XrbCE8XUfw9HucAZ+F3vB1RAg9wV0Z408hVEb7
+fexFWh42xi1Z+ujg9wTZt+pFrojxR00r8wy+yRXYaHy8xQW5wsq6vX+zxZrskyzI4ddGaC/9Aa+e37T0
+WNrE/P4zrUyjPRuJbhsI4HNSCs/p1hB+KSL4DFP8dR6fZF86ZPY2InVJ6ZALb9u0+eu0z28kLRDZKH9l
+ZJAepF4KYdvpxxP6H6BEGhhfmWfBRrZRJHLzlD4DB3JJL4VyUub5PNRm9V7xKfs02Z4lnyBfWmSK8O6C
+Ihuliz7uKbLRHOF0P5GNFgj9MhAZC8EKvSNkMbbe804hhCydXYzDoWdTrU33VUyvXScVQnZrGuu6yLyL
+rLrKXiuEbN3kG+NF+7qm49dlTHf+n43q6jipdZP7pDz4bf+2nlPPL64Hs116B/UOE9FMKKELwqKhF65/
+rk0N3qe38EaXaD/c7O8AAAD//+ueyO4YBwAA
`,
},
+}
- "/": {
- isDir: true,
- local: "",
- },
-}
+var _escDirs = map[string][]os.FileInfo{}
M invoice.tmpl +1 -2
@@ 30,8 30,7 @@ c"/"o {{escape client.Contact}} @PP
}
@DP
-@B {Date:} @PP
-@Date
+@B {Date:} @Date @Right {@B{Invoice:} {{client.Id}}-{{month}}} @PP
@DP
M main.go +6 -0
@@ 76,6 76,7 @@ func main() {
CLIENT.Address1 = config[client+".address1"]
CLIENT.Address2 = config[client+".address2"]
CLIENT.Phone = config[client+".phone"]
+ CLIENT.Id = config[client+".id"]
}
if p {
fmt.Fprintf(os.Stdin, "error isPrefix = %v", p)
@@ 102,6 103,7 @@ func main() {
if err != nil {
panic(err)
}
+ end := records[len(records)-1].End
hours := func(rs []Record) float64 {
var ttl float64
@@ 134,6 136,9 @@ func main() {
"escape": func(s string) string {
return replacer.Replace(s)
},
+ "month": func() string {
+ return end.t.Format("200601")
+ },
}).Parse(string(f)))
err = t.Execute(os.Stdout, records)
if err != nil {
@@ 155,6 160,7 @@ type To struct {
Address1 string
Address2 string
Phone string
+ Id string
}
type Record struct {