summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec@kesim.org>2024-11-27 17:03:50 +0100
committerÖzgür Kesim <oec@kesim.org>2024-11-27 17:03:50 +0100
commitc86dfbfcee69062c3bd036a5070a6e62fb11e06c (patch)
tree5197971673381c539b39b0ff720d9d0659b161c7
parent2bb8dcc9f63fdc09acdc83186626525957a45f4d (diff)
totals per wp
-rw-r--r--templates/report.t11
-rw-r--r--zeitgeist.go69
2 files changed, 72 insertions, 8 deletions
diff --git a/templates/report.t b/templates/report.t
index d82b8bf..08f4f43 100644
--- a/templates/report.t
+++ b/templates/report.t
@@ -5,14 +5,13 @@ End: {{.End}}
Beneficiary: {{.Beneficiary}}
-# Calendar
-
-{{ range $y, $c := .Calendars }}
-{{ $c }}
+{{ range $wp, $t := .Totals }}
+Total for {{ $wp }}:
+ - Budgeted: {{ printf "%8s" $t.Budgeted.AsDay }}
+ - Planned: {{ printf "%8s" $t.Planned.AsDay }}{{with $t.Unaccounted }} Unaccounted: {{.AsDay}}{{end}}
+ - Actual: {{ printf "%8s" $t.Actual.AsDay }}
{{ end }}
-
-
{{ range $id, $wp := .Workpackages -}}
## Workpackage {{ $id }}: {{ $wp.Title }}
{{ range $tid, $task := $wp.Tasks }}
diff --git a/zeitgeist.go b/zeitgeist.go
index e20ad35..811de40 100644
--- a/zeitgeist.go
+++ b/zeitgeist.go
@@ -64,6 +64,32 @@ func (en Entries) WPs() string {
return strings.Join(wps, ", ")
}
+func (en Entries) FilterWP(name string) Entries {
+ r := Entries{}
+ for _, e := range en {
+ if name == e.WP {
+ r = append(r, e)
+ }
+ }
+ return r
+}
+
+func (en Entries) Totals() Amount {
+ var a Amount
+ for _, e := range en {
+ a += e.Amount
+ }
+ return a
+}
+
+func (t Timeline) FilterWP(name string) Entries {
+ r := Entries{}
+ for _, entries := range t {
+ r = append(r, entries.FilterWP(name)...)
+ }
+ return r
+}
+
type User struct {
Name string
Type string
@@ -78,6 +104,14 @@ type Workpackage struct {
Tasks map[string]Task
}
+func (wp *Workpackage) TotalBudget() Amount {
+ var a Amount
+ for _, t := range wp.Tasks {
+ a += t.Budget
+ }
+ return a
+}
+
type Date time.Time
func (d Date) IsWorkday() bool {
@@ -292,7 +326,7 @@ func (p *Project) readPlans(dir string) error {
} else {
r[0], e = time.Parse("2006-01", parts[0])
if e == nil {
- slog.Info("Month found", "date", parts[0])
+ slog.Debug("Month found", "date", parts[0])
r[1] = r[0].AddDate(0, 1, 0)
isrange = true
} else {
@@ -310,7 +344,7 @@ func (p *Project) readPlans(dir string) error {
if r[0].Equal(r[1]) || r[0].After(r[1]) {
return fmt.Errorf("file %q, line %d: invalid range: %s", name, nr, parts[0])
}
- slog.Info("Found range", "start", r[0], "end", r[1])
+ slog.Debug("Found range", "start", r[0], "end", r[1])
isrange = true
}
}
@@ -712,3 +746,34 @@ func (p *Project) Calendars() map[int]string {
}
return r
}
+
+type Totals struct {
+ Budgeted Amount
+ Planned Amount
+ Actual Amount
+}
+
+func (t *Totals) Unaccounted() Amount {
+ return t.Budgeted - t.Planned
+}
+
+func (p *Project) TotalWP(name string) (t *Totals, e error) {
+ wp, ok := p.Workpackages[name]
+ if !ok {
+ return nil, fmt.Errorf("no such workpackage handle: %q", name)
+ }
+ t = &Totals{
+ Budgeted: wp.TotalBudget(),
+ Planned: p.Planned.FilterWP(name).Total(),
+ Actual: p.Timeline.FilterWP(name).Total(),
+ }
+ return t, nil
+}
+
+func (p *Project) Totals() (t map[string]*Totals) {
+ t = make(map[string]*Totals)
+ for n := range p.Workpackages {
+ t[n], _ = p.TotalWP(n)
+ }
+ return t
+}