Skip to main content

finances app

Dues, invoicing, payments, refunds, and per-chapter ledger.

Models (10)

  • OrgDuesSettings — billing cadence, default amount, late fee policy, autopay enabled
  • BillingPeriod — generated per cycle (e.g., "Spring 2026 dues")
  • DuesRate — per-status (and optionally per-chapter) override of base amount
  • ChapterInvoice — 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 chapter
  • PaidInvoice — invoice + payment join, used for reconciliation
  • PledgeClassDuesSnapshot — point-in-time copy of dues owed by a pledge class

Key endpoints

URLPurpose
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 reports
  • IsChapterOfficer (treasurer) — chapter invoice management, refunds within cap

Background tasks

  • generate_chapter_invoices(billing_period_id) — fans out invoice creation per active member
  • send_invoice_reminders — daily; sends "due in N days" notifications
  • mark_invoices_overdue — daily; flips openoverdue past due date
  • process_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_save on PaidInvoice — creates ChapterLedger entry 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 paid
  • payment_intent.payment_failed → records failed transaction
  • charge.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