Chapter 20 — Fundraising campaigns
Module code: PARTNERS (campaigns live inside the Partners module)
Home: /campaigns/
Further detail, including the WhatsApp options and social posting, is kept at
docs/CAMPAIGN_FUNDRAISING.mdanddocs/CAMPAIGN_SOCIAL_POSTING.md.
20.1 What the module is for
Fundraising campaigns let a school, charity or welfare organisation raise money for a stated purpose, publish a page that can be shared on social media, and record every contribution against the accounting ledger.
Donors are partners. A donor is not a separate kind of record — it is a partner with a donor type, which means one organisation that both donates and supplies is one record, not two.
20.2 Three ways a campaign is used
| Kind | Example |
|---|---|
| Project | Raise a fixed sum for a defined project — build a classroom block, buy a school bus |
| Student cost | Cover one named student's annual costs — tuition, uniform, books. Links to the student and can pre-fill a fee waiver. |
| General | Unrestricted giving with no specific target |
A contribution can also be recorded with no campaign at all. That is a first-class case, not a workaround — someone hands over a donation and it is recorded.
20.3 Screens
/campaigns/ dashboard
/campaigns/all/ campaign list
/campaigns/create/ new campaign
/campaigns/<id>/ detail — stats, breakdown, contributions
/campaigns/<id>/edit/ edit
/campaigns/<id>/close/ close
/campaigns/<id>/traffic/ public page traffic
/campaigns/<id>/whatsapp-setup/ WhatsApp copy pack
/campaigns/guide/ fundraising guide
/campaigns/social-accounts/ connect social accounts
/contributions/ contribution list
/contributions/create/ record a contribution
/contributions/<id>/ contribution detail
/campaigns/public/<token>/ the public page — no sign-in
20.4 Setting up payment options
Before publishing a campaign, configure how people can actually pay. This is done in Accounting, under payment methods (Chapter 12).
For each inbound payment method set:
| Field | Appears on the public page as |
|---|---|
| Instructions | The account number and reference to quote |
| QR image | A scannable code |
| Payment link | A button through to an external payment page |
A campaign page with no payment options tells a willing donor nothing about how to give.
Also set the company's social links and donor WhatsApp number on the company record — they appear in the footer of every public campaign page.
20.5 Creating a campaign
Screen: /campaigns/create/
- Select Create campaign.
- Enter: - Name — what a donor will read. - Kind — project, student cost, or general. - Description — the story. This is the page's main content, so write it for the donor, not for the file. - Target amount. - Student or campus, for a student-cost campaign. - Cost breakdown — structured lines with a description and an amount. Showing that a figure is made of tuition, uniform and books is far more persuasive than a single total. - Waiver percentage or amount, where the campaign is meant to reduce a student's fees.
- Save as Draft.
- When ready, set the status to Active. Draft campaigns are not publicly reachable at all.
A cost centre is created automatically for the campaign, so its income and spending can be reported separately in the analytic reports (Chapter 12).
20.6 The public page
Screen: /campaigns/public/<token>/
Reachable without signing in, so it can be shared anywhere. From top to bottom it shows:
1. Header — company logo, company name, campaign name
2. Progress — raised so far, the goal, a progress bar, percentage funded
3. Cost breakdown — the structured lines
4. Payment options — QR codes, payment links, and written instructions
5. Footer — social links and WhatsApp
Individual donor names and amounts are never shown. Only the aggregate is public, which is what lets you share the page without a privacy problem.
Sharing it
The campaign detail page carries a Share card with a copy-to-clipboard link and a preview. It appears once the campaign is active.
Add ?source= to the link to track where visitors came from — for example
?source=facebook or ?source=newsletter. Visitors arriving with a source see a short
acknowledgement, and the traffic report groups by it.
The donor chat
The public page carries a small help widget answering the questions donors actually ask: how to donate, what payment options exist, what happens after paying, how to get a receipt, and how to make contact.
It is rule-based — a fixed set of answers, with no external service involved, so it costs nothing to run and sends nothing anywhere.
A Continue on WhatsApp button hands the conversation over with a message already filled in, based on the topic the donor picked.
20.7 WhatsApp
Screen: /campaigns/<id>/whatsapp-setup/
Most organisations do not need a paid messaging platform. This screen produces a copy-and-paste pack for the free WhatsApp Business App:
- A greeting message.
- Three quick-reply button labels.
- Saved replies for
/donate,/afterpayand/contact.
Copy each into the WhatsApp Business App on the phone that answers donor messages. A donor then gets an immediate, correct answer at any hour, without any integration.
20.8 Recording contributions
Screen: /contributions/create/
- Select New contribution.
- Enter: - Donor — a partner. Create one if new (Chapter 5). - Campaign — or leave blank for an unrestricted gift. - Amount and date. - Channel — the payment method used. - Reference number — the transfer or cheque reference. - Source — free text recording where the donor came from, such as facebook or direct.
- Save.
Posting to accounting
Post to accounting on the contribution creates and confirms a real inbound payment with a balanced journal entry. Until this is done, the money is recorded in the fundraising module but not in the books.
Posting is safe to attempt twice — a contribution already posted is left alone.
Applying contributions to school fees
For a student-cost campaign, contributions can be applied against that student's fee vouchers — see Chapter 19, section 19.12. Each posted contribution is applied once and only once.
20.9 Traffic and analytics
Screen: /campaigns/<id>/traffic/
| Panel | Shows |
|---|---|
| Summary | Page views, unique visitors, unique addresses, views today |
| Top countries | Where visitors are |
| Top referrers | Which sites sent them |
| Source tags | Which ?source= links are working |
| Visit history | The detail, paginated |
Filter over 7, 30 or 90 days.
Read it alongside the contributions: a campaign with heavy traffic and few contributions has a page problem — usually missing or confusing payment options — rather than a reach problem.
20.10 Closing a campaign
Screen: /campaigns/<id>/close/
Closing stops new contributions being recorded against it. The public page remains reachable and shows the final total, which is what a donor who gave wants to see.
20.11 Routine
Weekly
[ ] Record and post contributions received
[ ] Reconcile posted contributions against the bank
[ ] Review traffic against contributions for the active campaigns
[ ] Answer donor messages
Per campaign
[ ] Update the description as the project progresses — a page that has not
changed in three months reads as abandoned
[ ] Close the campaign when the target is met and let the page show the total
20.12 Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| The public link shows nothing | The campaign is still a draft | Set it to Active |
| The public page shows no way to pay | No inbound payment methods with instructions, QR or link | Configure them in Chapter 12 |
| A contribution is not in the accounts | It was recorded but never posted | Use Post to accounting |
| A donor cannot be selected | They do not exist as a partner | Create the partner first |
| Contributions do not reduce a student's fees | They are not posted, or the campaign is not linked to the student | Post them; check the campaign kind and student |
| Traffic shows nothing | The page has not been shared, or filters are too narrow | Widen the period |
| Source tracking is empty | Shared links carry no ?source= |
Add it to each link you publish |
| Donor names appear somewhere public | They should not — only aggregates are public | Report it; the public page shows totals only |