diff options
author | Özgür Kesim <oec@kesim.org> | 2024-11-27 18:05:53 +0100 |
---|---|---|
committer | Özgür Kesim <oec@kesim.org> | 2024-11-27 18:05:53 +0100 |
commit | 0ebf69db6c2acb3f7b88eec1f0852ccf40068077 (patch) | |
tree | 4357927cbcc32a47cbe3b974c0dace77c40df4ec /zeitgeist.go | |
parent | 43e5471fdbf91b0028c496f8e01091b2d1ad8189 (diff) |
fix plan handling
Diffstat (limited to 'zeitgeist.go')
-rw-r--r-- | zeitgeist.go | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/zeitgeist.go b/zeitgeist.go index 811de40..762b0af 100644 --- a/zeitgeist.go +++ b/zeitgeist.go @@ -25,6 +25,7 @@ var ( fl_plandir = flag.String("pl", "", "directory to search for plans") fl_templates = flag.String("tm", "", "directory to search for the templates") fl_report = flag.String("rp", "report.t", "default report template") + fl_today = flag.String("today", time.Now().Format(time.DateOnly), "what is the date today") ) type Project struct { @@ -41,6 +42,7 @@ type Project struct { Blocked Timeline Timeline Timeline Planned Timeline + Today Date } type Timeline map[Date]Entries @@ -74,6 +76,26 @@ func (en Entries) FilterWP(name string) Entries { return r } +func (en Entries) FilterTask(task string) Entries { + r := Entries{} + for _, e := range en { + if task == e.Task { + r = append(r, e) + } + } + return r +} + +func (en Entries) FilterWPTask(wp, task string) Entries { + r := Entries{} + for _, e := range en { + if wp == e.WP && task == e.Task { + r = append(r, e) + } + } + return r +} + func (en Entries) Totals() Amount { var a Amount for _, e := range en { @@ -82,6 +104,14 @@ func (en Entries) Totals() Amount { return a } +func (t Timeline) FilterWPTask(wp, task string) Entries { + r := Entries{} + for _, e := range t { + r = append(r, e.FilterWPTask(wp, task)...) + } + return r +} + func (t Timeline) FilterWP(name string) Entries { r := Entries{} for _, entries := range t { @@ -229,6 +259,11 @@ type Deliverable struct { func main() { flag.Parse() + today, e := time.Parse(time.DateOnly, *fl_today) + if e != nil { + log.Fatalf("couldn't parse today parameter: %v", e) + } + p, e := loadProject(*fl_project) if e != nil { log.Fatalf("error loading project: %v", e) @@ -237,6 +272,7 @@ func main() { log.Fatalf("start '%s' after end '%s'", p.Start, p.End) } + p.Today = Date(today) if p.Timeline == nil { p.Timeline = make(Timeline) } @@ -307,7 +343,7 @@ func (p *Project) readPlans(dir string) error { // 2024-02-11..2024-02-23 wp2:short *8h [comment] // 2024-02-11..2024-02-23 wp2:short 3d [comment] var line = scanner.Text() - if strings.HasPrefix(line, "#") { + if strings.HasPrefix(line, "#") || "" == strings.TrimSpace(line) { continue } @@ -349,6 +385,10 @@ func (p *Project) readPlans(dir string) error { } } + if last.After(r[0]) || last.After(r[1]) { + return fmt.Errorf("file %q, line %d: dates not monotonic: %s before %s", name, nr, parts[0], Date(last)) + } + if !isrange { if last.After(r[0]) { return fmt.Errorf("file %q, line %d: dates not monotonic, %s older", name, nr, Date(r[0])) @@ -754,7 +794,29 @@ type Totals struct { } func (t *Totals) Unaccounted() Amount { - return t.Budgeted - t.Planned + d := t.Budgeted - t.Planned + // TODO: rounding OK!? + if d < 4 { + return 0 + } + return d +} + +func (p *Project) TotalWPTask(wp, task string) (to *Totals, e error) { + w, ok := p.Workpackages[wp] + if !ok { + return nil, fmt.Errorf("no such workpackage handle: %q", wp) + } + t, ok := w.Tasks[task] + if !ok { + return nil, fmt.Errorf("no such task in workpackage %q: %q", wp, task) + } + to = &Totals{ + Budgeted: t.Budget, + Planned: p.Planned.FilterWPTask(wp, task).Total(), + Actual: p.Timeline.FilterWPTask(wp, task).Total(), + } + return to, nil } func (p *Project) TotalWP(name string) (t *Totals, e error) { |