Accounts Receivable Lifecycle Controls

End-to-end AR management from invoice generation through payment application, late fee enforcement, payment plans, and institutional aging analysis with collection effectiveness metrics.

5 min read Accounting Controls As of Feb 9, 2026

Overview

The Accounts Receivable system manages the complete resident billing lifecycle: assessment generation, invoice delivery, payment receipt, late fee enforcement, payment plan management, and aging analysis. Every financial operation in this lifecycle flows through the JournalEngine with full enforcement guard evaluation.

The ARService and ARAgingService together provide the operational and analytical layers of AR management.


Invoice Generation

Assessment Scheduling

The generate_assessments method creates invoices from assessment schedules for all applicable units. Key controls:

  • Per-unit duplicate checking: Before creating an invoice, the service checks for existing invoices matching the same unit, schedule, and period. This prevents double-billing on re-runs and automatically handles new units added after initial generation.
  • Voided invoice handling: Previously voided invoices are excluded from duplicate checking, allowing regeneration when needed.
  • Schedule tracking: The schedule's last_generated_date and last_generated_period are updated for reporting.

Journal Entry Creation

Every invoice creates a journal entry through JournalEngine:

DR: Accounts Receivable (assessment amount)
CR: Income Account (assessment amount)

This records revenue at invoice creation (accrual accounting). The entry includes subledger references linking to both the invoice and unit for drill-down capability.


Payment Processing

Payment Receipt

The receive_payment method records incoming payments with mandatory controls:

  • Stripe fee linkage: When a payment originates from Stripe (stripe_payment_intent is set), the receipt must link to the source Payment object. This is enforced at the method level -- calling with a Stripe intent but no source payment raises a ValueError.

Payment Application

The apply_payment method supports three allocation strategies:

Strategy Behavior
FIFO (default) Apply to oldest outstanding invoices first
Specific Apply to explicitly specified invoices with specified amounts
Proportional Apply proportionally across all outstanding invoices

Defense-in-Depth Fee Verification

Before any Stripe payment can be applied to invoices, two conditions are enforced:

  1. Fee reconciliation check: If fee_reconciliation_failed is True on the source payment, application is permanently blocked until manual review.
  2. Fee confirmation check: The source payment must have fee_confirmed=True, meaning the actual Stripe fee has been retrieved from the Balance Transaction API.

These checks are unskippable -- they evaluate the FK on the receipt, not an optional parameter.

Payment Journal Entry

DR: Cash/Bank Account (net amount received)
DR: Bank Charges (Stripe processing fee, if applicable)
CR: Accounts Receivable (gross invoice amount)

This three-line entry properly separates the fee from the payment, ensuring accurate expense tracking.


Late Fee Enforcement

The calculate_and_apply_late_fees method follows a priority hierarchy for fee configuration:

  1. HOAConfig settings (HOA-level): enable_late_fee, late_fee_amount, late_invoice_day
  2. AssessmentSchedule settings (schedule-level): late_fee_enabled, late_fee_grace_days, calculate_late_fee()
  3. System defaults: $25 flat fee, 15-day grace period

Late fees are applied only once per invoice (late_fee_applied flag prevents duplication). Each late fee creates its own journal entry:

DR: Accounts Receivable
CR: Late Fee Income (account 4040)

A UnitLedger entry of type LATE_FEE is also created for the unit's statement.


Payment Plans

For delinquent accounts, the service supports structured payment arrangements:

  • Plan creation: Links multiple outstanding invoices into a single payment plan with configurable monthly amounts, number of payments, start date, payment day, optional down payment, and interest rate.
  • Default detection: The check_payment_plan_defaults method monitors active plans for missed scheduled payments and transitions plans to DEFAULTED status when tolerance is exceeded.

Aging Analysis

The ARAgingService provides institutional-standard aging analysis:

Standard Aging Buckets

Bucket Days Past Due
Current Not yet due (due_date >= as_of_date)
1-30 Days 1-30 days past due
31-60 Days 31-60 days past due
61-90 Days 61-90 days past due
Over 90 Days 91+ days past due

Summary Report

The get_ar_aging_summary method produces: - Bucket totals and percentages - Per-unit aging detail with owner names - Top 10 delinquent units ranked by total amount - Severely delinquent list (units with balances in 90+ bucket)

Collection Effectiveness Metrics

The get_collection_effectiveness method calculates for any fiscal year: - Collection rate: Total payments / total charges - Days Sales Outstanding (DSO): Ending AR balance / average daily charges - Net change: Ending balance vs. beginning balance

Aging Trend Analysis

The get_ar_aging_trend method provides month-over-month aging snapshots for up to 12 months, using stored ARSnapshot records when available or reconstructing from invoice data for historical periods.

AR Snapshots

The generate_ar_snapshot method creates point-in-time AR records including: - Bucket totals and percentages - Delinquent unit counts and delinquency rate - Average days delinquent (weighted by amount) - Per-unit detail with owner information


Unit Ledger

Every AR event (charge, payment, late fee) creates a UnitLedger entry with a running balance. The get_statement_data method dynamically rebuilds statements from invoice and payment records, ensuring accuracy even if ledger entries are missing.

CARI Integration

AR lifecycle metrics — delinquency rates, collection effectiveness, and aging distributions — feed into the CARI Financial Health and Payment Behavior sub-scores. Delinquency rate serves as both an L5 eligibility rule signal and a CARI scoring input, creating consistent treatment across enforcement and external reporting. Collection effectiveness and Days Sales Outstanding trends are weighted inputs to the Financial Health component.

For published methodology and component weights, see CARI Methodology and Scoring Framework.

How CommunityPay Enforces This
  • All invoice and payment journal entries flow through JournalEngine with guard evaluation
  • Per-unit duplicate checking prevents double-billing for the same assessment period
  • Stripe payments require fee_confirmed=True before journal posting (defense-in-depth)
  • Institutional-standard aging buckets: Current, 1-30, 31-60, 61-90, 90+ days
Login