finances app
Dues, invoicing, payments, refunds, and per-chapter ledger.
Models (10)
OrgDuesSettings— billing cadence, default amount, late fee policy, autopay enabledBillingPeriod— generated per cycle (e.g., "Spring 2026 dues")DuesRate— per-status (and optionally per-chapter) override of base amountChapterInvoice— issued to a member's account; status (open / paid / overdue / void)InvoiceLineItem— individual charge line (base dues, late fee, adjustment, etc.)OrgPaymentProcessor— per-org Stripe / Braintree / Square / PayPal config (encrypted creds)PaymentTransaction— every payment attempt; status (succeeded / failed / refunded / disputed)ChapterLedger— running balance per chapterPaidInvoice— invoice + payment join, used for reconciliationPledgeClassDuesSnapshot— point-in-time copy of dues owed by a pledge class
Key endpoints
| URL | Purpose |
|---|---|
GET /api/organizations/<id>/dues-settings/ | View dues config |
PATCH /api/organizations/<id>/dues-settings/ | Update dues config |
POST /api/organizations/<id>/payment-processors/ | Connect a processor |
GET /api/organizations/<id>/invoices/ | All invoices in org |
GET /api/chapters/<id>/invoices/ | Chapter invoices |
POST /api/invoices/<id>/pay/ | Initiate payment (returns Stripe session URL) |
POST /api/invoices/<id>/adjust/ | Add credit / fee / waiver |
POST /api/invoices/<id>/refund/ | Refund a paid invoice |
GET /api/chapters/<id>/finances/ledger/ | Chapter running balance |
POST /api/finances/webhooks/stripe/ | Stripe webhook receiver |
Permissions
IsNationalAdmin— dues settings, payment processor config, refunds beyond cap, org-wide reportsIsChapterOfficer(treasurer) — chapter invoice management, refunds within cap
Background tasks
generate_chapter_invoices(billing_period_id)— fans out invoice creation per active membersend_invoice_reminders— daily; sends "due in N days" notificationsmark_invoices_overdue— daily; flipsopen→overduepast due dateprocess_failed_payments— retries cards per org config
External integrations
- Stripe (most common) — Payment Intents API, Webhooks for async events
- Braintree, Square, PayPal — alternate processors per
OrgPaymentProcessor.provider
Signals
post_saveonPaidInvoice— createsChapterLedgerentry to update running balance
Notable patterns
Status-based dues
DuesRate(organization=, status=, amount=) overrides the org default. Common: undergrad pays $400/year, alumni pay $50/year. Loaded via org.dues_settings.get_rate_for_member(member).
Per-officer refund cap
OrgDuesSettings.refund_cap_per_officer (default $50). Officer-initiated refunds above this route to the org admin queue (returns 202 + creates an approval request).
Webhook reconciliation
/api/finances/webhooks/stripe/ validates the signature + processes:
payment_intent.succeeded→ marks invoice paidpayment_intent.payment_failed→ records failed transactioncharge.refunded→ updates refund status
Failed webhook deliveries: Stripe retries; idempotency key prevents double-processing.
Encrypted processor credentials
OrgPaymentProcessor stores client_id / secret / API key as EncryptedTextField. Decrypted at request time, never logged.
Chapter ledger vs invoice list
The ledger is a derived view (sum of charges + payments). For accuracy, the source of truth is ChapterInvoice + PaymentTransaction. The ledger is materialized for fast reads.
Code paths
- Models:
backend/apps/finances/models.py - Views:
backend/apps/finances/views.py - Stripe wrapper:
backend/apps/finances/providers/stripe.py - Webhook handler:
backend/apps/finances/views.py:StripeWebhookView