Skip to main content

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 role
  • FoundationPaymentProcessor — separate processor config (foundation funds go to a different bank account)
  • Campaign — fundraising drive; goal, dates, public slug, hero image, suggested amounts
  • Donation — completed donation; amount, recurring flag, anonymous flag
  • Donor — CRM record; lifetime giving total, tags, custom notes
  • DonationReceipt — IRS-compliant receipt PDF

Key endpoints

URLPurpose
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 management
  • IsFoundationEditor — read + create donations
  • AllowAny — public donate page

Background tasks

  • auto_close_expired_campaigns — daily; closes campaigns past end_date
  • generate_annual_tax_receipts — January each year; sends consolidated receipts to all donors
  • send_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 threshold
  • recurring
  • lapsed — gave once, no donation in 12+ months
  • reactivated — lapsed donor returned
  • board_member
  • match_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