Skip to content

Payment Processing

The apps.payments module handles payment receipt, processing through external payment processors, allocation across loan balances, and GL entry posting.

Payment Flow

1. Payment received (API or auto-pay)
2. Below minimum threshold?
       │ Yes → Funds placed in suspense
       │ No ↓
3. Route through payment processor (authorize/capture)
4. Lending program's apply_payment() allocates across
   fees, interest, and principal per allocation order
5. GL journal entries posted for each allocation
6. Loan balance, DPD, delinquency bucket updated
7. If overpayment on payoff → excess to suspense

Payment Methods

Method Description
ach Automated Clearing House transfer
wire Wire transfer
check Check payment
card Credit or debit card
other Manual/external payment

Payment Processors

Two built-in providers implementing PaymentProcessorProtocol:

Provider Capabilities Integration
Authorize.Net Card, ACH python-authorizenet AsyncClient
Stripe Card, ACH stripe SDK

Protocol methods: authorize, capture, void, refund.

See Provider Pattern for how processors are configured per tenant.

Payment Allocation

When a payment is processed, the lending program's apply_payment() method distributes funds according to the program's payment_allocation_order:

["interest", "fees", "principal"]

This allocates:

  1. All accrued interest first
  2. Then outstanding fees
  3. Then remaining amount to principal

The allocation breakdown is recorded on the payment:

Field Description
principal_applied Amount applied to principal
interest_applied Amount applied to interest
fees_applied Amount applied to fees

Note

Payment allocation runs asynchronously via a Celery task to handle the GL entry posting and balance updates.

GL Journal Entries

Each payment generates balanced GL entries for every allocation bucket:

Allocation Debit Credit
Principal Cash Loans Receivable
Interest Cash Interest Receivable
Fees Cash Fees Receivable

See General Ledger for the full journal entry reference.

Payment Statuses

Status Description
pending Payment created, not yet processed
completed Successfully processed and allocated
failed Processor rejected the payment
reversed Previously completed payment reversed
refunded Payment refunded to borrower
chargebacked Chargeback received from card network

Transaction Types

Type Description
regular Standard payment
advance Advance payment (ahead of schedule)
deferment_accrual Payment for deferred interest
settlement Settlement payment (partial satisfaction)

Payment Preview

A dry-run preview endpoint shows how a payment would be allocated without actually processing it:

POST /api/v1/loans/{loan_id}/payments/preview

Returns the projected allocation breakdown (principal, interest, fees) for a given amount. Used by the borrower portal's payment form to show allocation before submission.

Payment Reversals

Reversals undo a completed payment:

  1. Mirror GL entries created for each original allocation line
  2. Re-accrue any interest and fees that were satisfied by the original payment
  3. Delinquency engine triggered if the reversal causes the loan to become delinquent
  4. NSF fee assessed if configured on the loan product's fee schedule

Refunds

Refund processing for overpayments or borrower-requested returns:

  • Creates reversal GL entries
  • Routes through payment processor's refund() method
  • Records refund amount and reason

Backdated Payments

Payments can be backdated by setting an effective_date different from the payment_date:

  • Interest accrual recalculated as of the effective date
  • GL entries posted with the effective date
  • Delinquency status recalculated

Recurring Payments (Auto-Pay)

The RecurringPayment model configures automatic payment processing:

Field Description
frequency Monthly, bi-weekly, weekly, quarterly
next_payment_date Next scheduled auto-payment
is_active Whether auto-pay is enabled

Auto-pay uses the borrower's default payment instrument and processes payments via the configured payment processor.

Suspense Handling

Payments that can't be fully applied are held in suspense:

  • Partial payments below a minimum threshold
  • Overpayments on payoff

Suspense funds are tracked in the SuspenseAccount model and can be applied or refunded via API. See Servicing Operations for suspense management.

See Also