Comprehensive documentation of all data models in the Finance app
Finance App Data Models Documentation
Brand values alignment: All features and data models should align with Courtex values: Community, Transparency, Accessibility, Integrity, Humility. Financial data should be handled with transparency and integrity. See
docs/markdown/brand/copilot-instructions.mdfor full guidance.
Overview
The Finance app manages financial transactions for clubs and sessions, as well as user account balances (an internal wallet system). It tracks income and expenses at the club/session level, and maintains an audit log of all balance changes per user.
Abstract Models
1. Transaction (Abstract)
The Transaction model is an abstract base class for financial records. It is not stored in the database directly; instead it is inherited by Income and Expense.
Key Fields:
- club: Foreign key to clubs.Club (nullable; PROTECT on delete)
- session: Foreign key to sport_sessions.Session (nullable; PROTECT on delete)
- description: Optional short description (max 250 characters)
- amount: Decimal transaction amount (max 10 digits, 2 decimal places)
- date: Auto-set date when the transaction record was created
Inherited from TimeStampedModel:
- created_at, updated_at, deleted_at
Validation (clean()):
- amount must not be negative
- At least one of session or club must be provided
- If both session and club are provided, the session must belong to that club
Business Logic (via save()):
- If session is set but club is not, automatically derives club from session.club
- Calls full_clean() before saving to enforce all validation
Concrete Models
2. Income
The Income model tracks revenue received by a club or session. Inherits all fields and validation from Transaction.
Additional Fields:
- source: Income source category — one of membership, casual (Casual Play), entry_fee (Entry Fee), other
- session: Overrides the parent's session FK with its own related_name='income'
Meta:
- verbose_name_plural = "Income"
3. Expense
The Expense model tracks expenditure incurred by a club or session. Inherits all fields and validation from Transaction.
Additional Fields:
- category: Expense category — one of equipment, court_hire (Court Hire), shuttles, staff, other
- session: Overrides the parent's session FK with its own related_name='expense'
Meta:
- verbose_name_plural = "Expenses"
4. AccountBalance
The AccountBalance model represents a user's internal Courtex wallet balance. Each user has exactly one balance record.
Key Fields:
- user: One-to-one foreign key to users.User (CASCADE on delete; related name account_balance)
- balance: Current balance as a decimal (max 10 digits, 2 decimal places; defaults to 0.00)
- updated_at: Auto-updated timestamp whenever the balance changes
Methods:
- add_balance(amount): Adds a decimal amount to the user's balance and saves
- deduct_balance(amount): Deducts a decimal amount from the balance; raises ValidationError if balance would go negative
Business Logic (via save()):
- Before saving, compares the current balance to the stored balance
- If the balance has changed, automatically creates an AccountBalanceLog entry to record the change
Creation:
- Created automatically by users.User.save() when a new user is created
- The first premium subscription adds $10 to the balance (handled in users.User.add_subscription())
5. AccountBalanceLog
The AccountBalanceLog model is an audit trail of every balance change for a user.
Key Fields:
- account_balance: Foreign key to AccountBalance (CASCADE on delete; related name logs)
- previous_balance: The balance before the change
- new_balance: The balance after the change
- changed_at: Auto-set timestamp when the log entry was created
Business Logic:
- Created automatically by AccountBalance.save() whenever the balance value changes
- Provides a full history of debits and credits for auditing and transparency
Relationships Summary
User ──── AccountBalance ──< AccountBalanceLog
Club ──< Income (via Transaction)
└──< Expense (via Transaction)
Session ──< Income (via Transaction)
└──< Expense (via Transaction)
Related Apps
users:AccountBalanceis created for every user; premium subscriptions credit the balanceclubs: Transactions are linked to aClubsport_sessions: Transactions are linked to aSession; session publishing deducts $0.50 from the club owner's balance