Backend:
- ClosedWeekStore.SumDelta: single SQL aggregate returning total delta_ms and
row count across all closed_weeks
- WeekService.Balance: thin passthrough returning BalanceResult{TotalDeltaMs, ClosedWeekCount}
- GET /api/weeks/balance handler; route registered alongside /weeks list/close/reopen
- Tests: store-level SumDelta (empty + populated), service-level Balance (empty + 2 weeks)
Frontend:
- weeks.balance() added to API client
- History page: balance card at top, fetched in parallel with existing data
- Loading state shows '—'; once loaded shows formatDelta value in green/red/gray
- Shows 'across N closed weeks' count alongside the value
54 lines
1.3 KiB
Go
54 lines
1.3 KiB
Go
package store_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/wotra/wotra/internal/domain"
|
|
"github.com/wotra/wotra/internal/store"
|
|
)
|
|
|
|
func TestClosedWeekStoreSumDelta(t *testing.T) {
|
|
db, err := store.Open(":memory:")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
s := store.NewClosedWeekStore(db)
|
|
ctx := context.Background()
|
|
now := time.Now().UnixMilli()
|
|
|
|
// Empty table → 0, 0
|
|
total, count, err := s.SumDelta(ctx)
|
|
if err != nil {
|
|
t.Fatalf("SumDelta on empty table: %v", err)
|
|
}
|
|
if total != 0 || count != 0 {
|
|
t.Fatalf("empty: want (0,0), got (%d,%d)", total, count)
|
|
}
|
|
|
|
// Insert two weeks with known deltas.
|
|
for _, w := range []*domain.ClosedWeek{
|
|
{WeekKey: "2024-W01", ExpectedMs: 144_000_000, WorkedMs: 147_600_000, DeltaMs: 3_600_000, ClosedAt: now, UpdatedAt: now},
|
|
{WeekKey: "2024-W02", ExpectedMs: 144_000_000, WorkedMs: 142_200_000, DeltaMs: -1_800_000, ClosedAt: now, UpdatedAt: now},
|
|
} {
|
|
if err := s.Upsert(ctx, w); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
total, count, err = s.SumDelta(ctx)
|
|
if err != nil {
|
|
t.Fatalf("SumDelta: %v", err)
|
|
}
|
|
if count != 2 {
|
|
t.Errorf("count: want 2, got %d", count)
|
|
}
|
|
want := int64(3_600_000 - 1_800_000) // 1_800_000
|
|
if total != want {
|
|
t.Errorf("total: want %d, got %d", want, total)
|
|
}
|
|
}
|