feat(go): M6.2 — adults page (table, filters, credits/debts/unmatched, Pay buttons)
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
- Extract AssembleAdults(ctx) from ServeAdults so HTML and JSON API share one reconcile path. - HTMLHandler gains *api.Handler; ServeAdults loads real data and renders adults.tmpl. - AdultsPageData view model + qrHref/qrHrefAll funcMap (URL-encode /qr params, YYYY-MM→MM/YYYY). - adults.tmpl: full reconcile table, per-cell status classes + cell-unpaid-current, Pay button hrefs, totals row, credits/debts/unmatched sections, filter controls, sheet links. - static/js/filters.js: NFD-normalize name filter + month-range column hiding; future months hidden by default. - TestAdultsPage asserts member name and cell text against fixture data. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +1,61 @@
|
||||
package web_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"fuj-management/go/internal/config"
|
||||
"fuj-management/go/internal/domain/reconcile"
|
||||
"fuj-management/go/internal/web"
|
||||
"fuj-management/go/internal/web/api"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// fixtureSources returns one adult ("Test Member", tier A) with a 2026-01 fee
|
||||
// of 750 CZK (4 sessions) and a matching payment of 750 — mirrors Python's
|
||||
// test_adults_route fixture.
|
||||
type fixtureSources struct{}
|
||||
|
||||
func (fixtureSources) LoadAdults(_ context.Context) ([]reconcile.Member, []string, error) {
|
||||
return []reconcile.Member{
|
||||
{Name: "Test Member", Tier: "A", Fees: map[string]reconcile.FeeData{
|
||||
"2026-01": {Expected: 750, Attendance: 4},
|
||||
}},
|
||||
}, []string{"2026-01"}, nil
|
||||
}
|
||||
|
||||
func (fixtureSources) LoadJuniors(_ context.Context) ([]reconcile.Member, []string, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (fixtureSources) LoadTransactions(_ context.Context) ([]reconcile.Transaction, error) {
|
||||
amt := float64(750)
|
||||
return []reconcile.Transaction{
|
||||
{Date: "2026-01-01", Amount: 750, Person: "Test Member", Purpose: "2026-01", InferredAmount: &amt},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (fixtureSources) LoadExceptions(_ context.Context) (map[reconcile.ExceptionKey]reconcile.Exception, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func fixtureHandler(t *testing.T) *api.Handler {
|
||||
t.Helper()
|
||||
return &api.Handler{
|
||||
Sources: fixtureSources{},
|
||||
Config: config.Config{BankAccount: "CZ0000000000000000000000"},
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTMLHandlerSmoke(t *testing.T) {
|
||||
renderer, err := web.NewRenderer()
|
||||
if err != nil {
|
||||
t.Fatalf("NewRenderer: %v", err)
|
||||
}
|
||||
b := web.BuildInfo{Version: "v0", Commit: "abc1234", BuildDate: "2026-01-01"}
|
||||
h := web.NewHTMLHandler(renderer, b)
|
||||
h := web.NewHTMLHandler(renderer, b, fixtureHandler(t))
|
||||
|
||||
cases := []struct {
|
||||
path string
|
||||
@@ -52,3 +92,37 @@ func TestHTMLHandlerSmoke(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdultsPage(t *testing.T) {
|
||||
renderer, err := web.NewRenderer()
|
||||
if err != nil {
|
||||
t.Fatalf("NewRenderer: %v", err)
|
||||
}
|
||||
b := web.BuildInfo{Version: "v0", Commit: "abc1234", BuildDate: "2026-01-01"}
|
||||
h := web.NewHTMLHandler(renderer, b, fixtureHandler(t))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/adults", nil)
|
||||
w := httptest.NewRecorder()
|
||||
h.ServeAdults(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200", w.Code)
|
||||
}
|
||||
|
||||
body := w.Body.String()
|
||||
|
||||
for _, want := range []string{
|
||||
"Adults Dashboard",
|
||||
"Test Member",
|
||||
"750/750 CZK (4)", // paid/expected (attendance)
|
||||
} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("body missing %q", want)
|
||||
}
|
||||
}
|
||||
|
||||
// Python assertion: cell text never says literally "OK"
|
||||
if strings.Contains(body, ">OK<") {
|
||||
t.Error("body should not contain >OK<")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user