Fee Management
At a glance
Fee Management is the configuration backbone for every chargeable item across the federation hierarchy, modelling composite licence fees as the sum of OrgNode-owned components alongside club affiliation tiers, competition entries, season-scoped early-bird and late-fee surcharges, configurable waivers, automated revenue splits, sanction and suspension surcharges, season-copy tooling and an immutable audit log covering every fee-configuration change.
How it works
The subsystem treats every fee as a structured composition rather than a single price. A licence fee is assembled from components owned by different OrgNode levels — for France, the part federale (FFPJP), part ligue, part comite departemental and assurance are summed at calculation time through /license-fees/calculate, with regional overrides applied via /license-fee-overrides/. Club affiliation, competition entry, sanction and suspension fees live in a unified FeeSchedule collection scoped by tenant, season and fee_category.
Season-to-season migration runs via /fee-management/copy-season, which clones FeeSchedule, LicenseFeeConfig and FeeSurchargeRule documents into the new season and shifts all deadline dates by the year delta, skipping duplicates. Time-based modifiers are encoded as FeeSurchargeRule entries: early_bird discounts and late_fee surcharges, fixed amount or percentage, scoped per licence type or competition class, computed via /fee-surcharges/calculate. Waivers (youth, veteran, disabled, family, honorary, low-income, custom) are configured per WaiverType with mode full / percentage / fixed and age-or-family-size criteria, resolved through /fee-waivers/calculate.
Once a fee is collected, RevenueDistributionRule splits it according to per-OrgNode percentage shares; /fee-splitting/calculate previews the breakdown and /fee-splitting/execute writes the resulting RevenueEntry rows for downstream bookkeeping. Sanction and suspension surcharges have dedicated calculators (/sanction-fee-configs/calculate/{season_id}, /suspension-fee-configs/calculate/{season_id}) supporting Sweden's 300 SEK per class and 2x senior-licence suspension fee. Every CRUD action on any fee configuration appends to an immutable FeeChangeLog (use_revision=False) which is queryable per entity and category through /fee-audit/.
Key capabilities
- Composite licence fee configuration with per-OrgNode component ownership and regional overrides
- Season copy via /fee-management/copy-season cloning schedules, configs and surcharge rules with deadline shifting
- Early-bird and late-fee surcharges, fixed or percentage, scoped per licence type and competition class
- Waiver engine for youth, veteran, disabled, family, honorary and low-income discounts with age and family-size rules
- Automatic fee splitting that writes RevenueEntry rows according to per-OrgNode RevenueDistributionRule
- Tenant-configurable sanction and suspension fees including multiplier mode keyed to a reference licence price
- Immutable FeeChangeLog audit trail covering every CRUD action on any fee configuration
In practice
A national federation treasurer opens the new season and clicks Copy from previous season. The system clones every FeeSchedule, LicenseFeeConfig and FeeSurchargeRule into the new season, shifts the early-bird deadline forward by 365 days and reports six duplicates skipped. She then opens the senior licence configuration and lifts the part federale by 5 EUR; the change immediately appears in the FeeChangeLog with her user id, before and after values, and timestamp.
When the first club registers, the system calls /license-fees/calculate, sums the components, applies the youth waiver for a 16-year-old member, computes the total and triggers /fee-splitting/execute to write four RevenueEntry rows distributing the fee to federation, ligue, comite and the insurance pool.
Features in this subsystem
10| ID | Status | Features |
|---|---|---|
| F08.01.01 | Shipped | Composite license fee configuration — license fee = sum of configurable components set at different OrgNode levels. Example France: part fédérale (set by FFPJP) + part ligue (set by ligue régionale) + part comité (set by comité départemental) + assurance. Each component configurable per license type, age, category. Supports regional price variation (France, Spain). ✅ PL-F0801a |
| F08.01.02 | Shipped | Club affiliation fee configuration (flat or per-member) ✅ PL-F0801a |
| F08.01.03 | Shipped | Competition entry fee management ✅ PL-F0801a |
| F08.01.04 | Shipped | Fee schedules per season/year ✅ PL-F0801a |
| F08.01.05 | Shipped | Early bird / late fee surcharges ✅ PL-F0801a |
| F08.01.06 | Shipped | Fee waivers and discounts (youth, veteran, disabled, family) — configurable per tenant (e.g., Sweden: no sanction fee for youth classes) ✅ PL-F0801b |
| F08.01.07 | Shipped | Fee splitting with automatic distribution — when a license is purchased, the system automatically splits the payment to the correct recipients (federation account, regional account, district account, insurance). Configurable split ratios per OrgNode level. ✅ PL-F0801b |
| F08.01.08 | Shipped | Fee history and audit trail ✅ PL-F0801b |
| F08.01.09 | Shipped | Sanction fee per competition class — configurable per tenant (e.g., Sweden: 300 SEK per class, paid to district where competition is held). Supports different fee rules per competition level. ✅ PL-F0801b |
| F08.01.10 | Shipped | License suspension administrative fee — configurable per tenant (e.g., Sweden: 2× senior license fee, charged to the club requesting suspension) ✅ PL-F0801b |
Stakeholders who need this subsystem
Surfaces in 1 stakeholder analyses