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.md for 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: AccountBalance is created for every user; premium subscriptions credit the balance
  • clubs: Transactions are linked to a Club
  • sport_sessions: Transactions are linked to a Session; session publishing deducts $0.50 from the club owner's balance