foundation app
Fundraising arm of the platform. Separate payment processor from dues; tax-exempt donation receipts; public donate pages.
Models (7)
FoundationConfig— per-org foundation settings (name, EIN, address, receipt template)FoundationAdmin— promotes a User to foundation admin roleFoundationPaymentProcessor— separate processor config (foundation funds go to a different bank account)Campaign— fundraising drive; goal, dates, public slug, hero image, suggested amountsDonation— completed donation; amount, recurring flag, anonymous flagDonor— CRM record; lifetime giving total, tags, custom notesDonationReceipt— IRS-compliant receipt PDF
Key endpoints
| URL | Purpose |
|---|---|
GET /api/organizations/<id>/foundation/config/ | Foundation settings |
POST /api/organizations/<id>/foundation/campaigns/ | Create campaign |
GET /donate/<foundation_id>/<campaign_slug>/ | Public donate page (no auth) |
POST /api/foundation/donations/ | Submit donation (auth or public) |
GET /api/foundation/donations/ | Donations list (admin) |
GET /api/foundation/donors/ | Donor CRM |
POST /api/foundation/donations/<id>/refund/ | Refund |
GET /api/foundation/reports/year-end/ | Year-end summary |
Permissions
IsFoundationAdmin— campaign + donor CRM managementIsFoundationEditor— read + create donationsAllowAny— public donate page
Background tasks
auto_close_expired_campaigns— daily; closes campaigns past end_dategenerate_annual_tax_receipts— January each year; sends consolidated receipts to all donorssend_donation_receipts— per-donation; emails immediately
External integrations
- Stripe (separate connected account from dues)
Notable patterns
Public donate URL
/donate/<foundation_id>/<campaign_slug>/ — fully public, no auth. Renders campaign page with progress bar, suggested amounts, donor info form.
After payment success → redirects to /donation-success/?donation_id=<uuid>. Receipt emailed asynchronously.
Recurring donations
Campaign-level allow_recurring flag. Donor sets monthly / annual at giving time. Stripe Subscriptions handle the recurring charge; webhook updates Donation rows.
Donor matching
Anonymous donors get a Donor row (without name displayed publicly). Returning donors are matched by email — lifetime giving accumulates correctly.
Tax receipts
Two flavors:
- Per-donation — emailed at giving time; PDF generated via
generate_donation_receipt(donation_id)task - Year-end summary — emailed every January; aggregates all prior-year donations per donor
Both use a configurable template (HTML / Markdown), with substitutions for amount, date, donor name, EIN.
Donor segmentation
Tag donors via Donor.tags (TextField, comma-separated, or JSONField on newer schemas):
major_donor— over a configurable thresholdrecurringlapsed— gave once, no donation in 12+ monthsreactivated— lapsed donor returnedboard_membermatch_eligible— employer matches donations
Tag-based outreach campaigns: GET /api/foundation/donors/?tag=major_donor.
Campaign bulletins
Campaign has a bulletins field (related model) for posting updates ("We're at 50%!"). Surfaced inline on the public donate page.
Code paths
- Models:
backend/apps/foundation/models.py - Views:
backend/apps/foundation/views.py - Permissions:
backend/apps/foundation/permissions.py - Tasks:
backend/apps/foundation/tasks.py - Receipt generator:
backend/apps/foundation/services/receipts.py
Related
- Foundation (org admin)
- Foundation module (user-facing)
- finances app — separate processor for dues