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>
31 lines
797 B
Go
31 lines
797 B
Go
package membership
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
|
|
domreconcile "fuj-management/go/internal/domain/reconcile"
|
|
)
|
|
|
|
// ReconcileReport loads attendance, transactions, and exceptions via s, runs
|
|
// the three-phase reconciliation, and writes the balance report to out.
|
|
// Returns ErrIOPending until real loaders are injected in M4.
|
|
func ReconcileReport(ctx context.Context, s Sources, defaultYear int, out io.Writer) error {
|
|
members, sortedMonths, err := s.LoadAdults(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txns, err := s.LoadTransactions(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
exceptions, err := s.LoadExceptions(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
result := domreconcile.Reconcile(members, sortedMonths, txns, exceptions, defaultYear)
|
|
printReconcileReport(out, result, sortedMonths)
|
|
return nil
|
|
}
|