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:
This allocates:
- All accrued interest first
- Then outstanding fees
- 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:
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:
- Mirror GL entries created for each original allocation line
- Re-accrue any interest and fees that were satisfied by the original payment
- Delinquency engine triggered if the reversal causes the loan to become delinquent
- 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¶
- General Ledger --- GL entries for payments
- Fee Management --- Fee allocation in payments
- Lending Programs & Products --- Payment allocation order configuration
- Servicing Operations --- Suspense, payoff quotes
- Provider Pattern --- Payment processor configuration
- Collections --- Delinquency impact of reversals