169 lines
4.3 KiB
Go
169 lines
4.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"slices"
|
|
"strings"
|
|
|
|
"gogs.inhome.blapointe.com/ana-ledger/src/ana"
|
|
"gogs.inhome.blapointe.com/ana-ledger/src/ledger"
|
|
)
|
|
|
|
func Main() {
|
|
var config Config
|
|
|
|
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
|
fs.Var(&config.Files, "f", "paths to files")
|
|
fs.Var(&config.Query.Period, "period", "period")
|
|
fs.StringVar(&config.Query.Sort, "S", "", "sort ie date")
|
|
fs.BoolVar(&config.Query.NoRounding, "no-rounding", false, "no rounding")
|
|
fs.StringVar(&config.Query.With, "w", "", "regexp for transactions")
|
|
fs.IntVar(&config.Query.Depth, "depth", 0, "depth grouping")
|
|
fs.BoolVar(&config.Query.Normalize, "n", false, "normalize with default normalizer")
|
|
fs.BoolVar(&config.Query.USDOnly, "usd", false, "filter to usd")
|
|
fs.BoolVar(&config.Query.NoExchanging, "no-exchanging", true, "omit currency exchanges")
|
|
fs.StringVar(&config.BPI, "bpi", "", "path to bpi")
|
|
if err := fs.Parse(os.Args[1:]); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
files := config.Files.Strings()
|
|
if len(files) == 0 {
|
|
panic("must specify at least one file")
|
|
}
|
|
ledgerFiles, err := ledger.NewFiles(files[0], files[1:]...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
positional := fs.Args()
|
|
if len(positional) == 0 || len(positional[0]) < 3 {
|
|
panic("positional arguments required, ie bal|reg PATTERN MATCHING")
|
|
}
|
|
cmd := positional[0]
|
|
|
|
q, err := BuildQuery(config, positional[1:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
deltas, err := ledgerFiles.Deltas()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if period := config.Query.Period; !period.Empty() {
|
|
after := period.Start.Format("2006-01-02")
|
|
before := period.Stop.Format("2006-01-02")
|
|
deltas = deltas.Like(
|
|
ledger.LikeAfter(after),
|
|
ledger.LikeBefore(before),
|
|
)
|
|
}
|
|
|
|
pattern := ".*"
|
|
if depth := config.Query.Depth; depth > 0 {
|
|
pattern = ""
|
|
for i := 0; i < depth; i++ {
|
|
pattern += "[^:]*:"
|
|
}
|
|
pattern = strings.Trim(pattern, ":")
|
|
}
|
|
group := ledger.GroupName(pattern)
|
|
|
|
bpis := make(ledger.BPIs)
|
|
if config.BPI != "" {
|
|
b, err := ledger.NewBPIs(config.BPI)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
bpis = b
|
|
}
|
|
|
|
if config.Query.Normalize {
|
|
deltas = ana.NewDefaultNormalizer().Normalize(deltas)
|
|
}
|
|
|
|
if config.Query.With != "" {
|
|
deltas = deltas.Like(ledger.LikeWith(config.Query.With))
|
|
}
|
|
|
|
switch cmd[:3] {
|
|
case "bal":
|
|
balances := deltas.Balances().
|
|
WithBPIs(bpis).
|
|
KindaLike(q).
|
|
KindaGroup(group).
|
|
Nonzero()
|
|
FPrintBalances(os.Stdout, "", balances, nil, config.Query.USDOnly)
|
|
case "reg":
|
|
transactions := deltas.Transactions()
|
|
|
|
for i, transaction := range transactions {
|
|
balances := ledger.Deltas(transaction).Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero()
|
|
shouldPrint := false
|
|
shouldPrint = shouldPrint || len(balances) > 2
|
|
if config.Query.NoExchanging {
|
|
shouldPrint = shouldPrint || len(balances) > 1
|
|
for _, v := range balances {
|
|
shouldPrint = shouldPrint || len(v) == 1
|
|
}
|
|
} else {
|
|
shouldPrint = shouldPrint || len(balances) > 0
|
|
}
|
|
if shouldPrint {
|
|
fmt.Printf("%s\t%s\n", transaction[0].Date, transaction[0].Description)
|
|
FPrintBalances(os.Stdout, "\t\t", balances, transactions[:i+1].Deltas().Like(q).Group(group).Balances().WithBPIsAt(bpis, transaction[0].Date).Nonzero(), config.Query.USDOnly)
|
|
}
|
|
}
|
|
default:
|
|
panic("unknown command " + positional[0])
|
|
}
|
|
}
|
|
|
|
func FPrintBalances(w io.Writer, linePrefix string, balances, cumulatives ledger.Balances, usdOnly bool) {
|
|
keys := []string{}
|
|
for k := range balances {
|
|
keys = append(keys, k)
|
|
}
|
|
slices.Sort(keys)
|
|
|
|
max := 0
|
|
for _, k := range keys {
|
|
if n := len(k); n > max {
|
|
max = n
|
|
}
|
|
}
|
|
|
|
format := fmt.Sprintf("%s%%-%ds\t%%s%%.2f (%%s%%.2f)\n", linePrefix, max)
|
|
for _, key := range keys {
|
|
currencies := []ledger.Currency{}
|
|
for currency := range balances[key] {
|
|
currencies = append(currencies, currency)
|
|
}
|
|
slices.Sort(currencies)
|
|
|
|
for _, currency := range currencies {
|
|
printableCurrency := currency
|
|
if printableCurrency != "$" {
|
|
printableCurrency += " "
|
|
}
|
|
if usdOnly && printableCurrency != "$" {
|
|
continue
|
|
}
|
|
|
|
cumulative := balances[key][currency]
|
|
if balance, ok := cumulatives[key]; !ok {
|
|
} else if value, ok := balance[currency]; !ok {
|
|
} else {
|
|
cumulative = value
|
|
}
|
|
|
|
fmt.Fprintf(w, format, key, printableCurrency, balances[key][currency], printableCurrency, cumulative)
|
|
}
|
|
}
|
|
}
|