Add internal/services/membership package: AttendanceLoader, TransactionLoader, ExceptionLoader interfaces + NewStubSources stub (returns ErrIOPending until M4 lands real Sheets loaders). FeesReport and ReconcileReport orchestrate domain/fees + domain/reconcile and write fixed-width text reports matching Python calculate_fees.py and match_payments.py print_report output. 13 unit tests cover all formatter branches and orchestration wiring via fake loaders. cmd/fuj/main.go: fees and reconcile subcommands now dispatch; sync/infer retain the [M4] placeholder. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
18 lines
424 B
Go
18 lines
424 B
Go
package membership
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
)
|
|
|
|
// FeesReport loads adult attendance via l, computes fees, and writes the
|
|
// fee table to out. Returns ErrIOPending until a real loader is injected in M4.
|
|
func FeesReport(ctx context.Context, l AttendanceLoader, out io.Writer) error {
|
|
members, sortedMonths, err := l.LoadAdults(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printFeesTable(out, members, sortedMonths)
|
|
return nil
|
|
}
|