package ledger import ( "fmt" "maps" "slices" "time" ) type Register map[string]Balances func (register Register) Latest() Balances { dates := register.Dates() if len(dates) == 0 { return nil } date := dates[len(dates)-1] return register[date] } func (register Register) WithBPIs(bpis BPIs) Register { result := make(Register) for d := range register { result[d] = register[d].WithBPIsAt(bpis, d) } return result } func (register Register) PushAll(other Register) { for date := range other { if _, ok := register[date]; !ok { register[date] = make(Balances) } register[date].PushAll(other[date]) } } func (register Register) Names() []string { names := map[string]int{} for _, v := range register { for name := range v { names[name] = 1 } } result := make([]string, 0, len(register)) for k := range names { result = append(result, k) } slices.Sort(result) return result } func (register Register) Dates() []string { result := make([]string, 0, len(register)) for k := range register { result = append(result, k) } slices.Sort(result) return result } func (register Register) Between(start, end time.Time) Register { result := make(Register) for k := range register { t := mustDateToTime(k) if t.Before(start) || t.After(end) { continue } result[k] = maps.Clone(register[k]) } return result } func (register Register) Times() []time.Time { dates := register.Dates() result := make([]time.Time, len(dates)) for i := range dates { result[i] = mustDateToTime(dates[i]) } return result } func mustDateToTime(s string) time.Time { result, err := dateToTime(s) if err != nil { panic(err) } return result } func dateToTime(s string) (time.Time, error) { for _, layout := range []string{ "2006-01-02", "2006-01", } { if t, err := time.ParseInLocation(layout, s, time.Local); err == nil { return t, err } } return time.Time{}, fmt.Errorf("no layout matching %q", s) } func (register Register) Debug() string { result := "{" for _, date := range register.Dates() { result += "{" + date for name, balance := range register[date] { result += "{" + name for cur, v := range balance { result += fmt.Sprintf("%s=%.2f ", cur, v) } result += "}" } result += "}" } return result + "}" }