Donation post-upsert flow
Note
This flow is self-documenting and should be viewed within Salesforce (Setup > Process Automations > Flows). This document is to support working through a visual flow. Please note: the flow commentary is produced using AI.
Overview#
Flow name: MoveData_Donation_Donation_Post Label: [MoveData] Donation: Donation - Post Upsert Type: Auto-Launched Flow Template API version: 63.0 Status: Active
This flow handles comprehensive post-processing operations after gift transaction records are created or updated, including status restoration, refund processing, soft credit creation, campaign member management, tribute handling, matching gift relationships, and gift designation copying.
Purpose#
The flow performs post-upsert operations that:
- Restore transaction status when temporary changes were made during mapping
- Process refunds by creating GiftRefund records and updating transaction status
- Create soft credit relationships for campaign attribution
- Manage campaign member records with hierarchical status systems
- Handle tribute donations (memorial and honour gifts) with notification processing
- Establish matching gift relationships between employer and employee transactions
- Copy gift designations from gift commitments, campaigns, or override sources
Salesforce fields#
This flow interacts with Nonprofit Cloud objects and their fields. Below is a mapping of all fields utilised:
| Field API name | Field type | Purpose in flow |
|---|---|---|
| GiftTransaction.Id | ID | Primary record identifier |
| GiftTransaction.Status | Picklist | Transaction status management |
| GiftTransaction.OriginalAmount | Currency | Original amount for gift designations |
| GiftTransaction.CurrentAmount | Currency | Refundable balance, and gift designations |
| GiftTransaction.MatchingEmployerTransactionId | Lookup to GiftTransaction | Bidirectional matching gift relationships |
| GiftRefund.Amount | Currency | Refund amount |
| GiftRefund.Date | Date | Refund transaction date |
| GiftRefund.GiftTransactionId | Lookup to GiftTransaction | Parent transaction link |
| GiftRefund.ProcessorTransactionFee | Currency | Refund processing fee |
| GiftRefund.Status | Picklist | Refund status |
| GiftTribute.TributeType | Picklist | Memorial or Honour designation |
| GiftTribute.HonoreeContactId | Lookup to Account | Honoree contact reference |
| GiftTribute.HonoreeName | Text | Honoree name |
| GiftTribute.NotificationContactId | Lookup to Account | Notification recipient |
| GiftTribute.NotificationContactName | Text | Notification recipient name |
| GiftTribute.NotificationEmail | Notification email address | |
| GiftTribute.GiftTransactionId | Lookup to GiftTransaction | Parent transaction link |
Input variables#
Core transaction data#
| Variable | Type | Required | Description |
|---|---|---|---|
Record |
GiftTransaction SObject | Yes | The GiftTransaction record that was processed |
DonorContact |
Account SObject | No | Primary contact associated with the donation |
DonationCampaign |
Campaign SObject | No | Campaign associated with the donation |
DonorAccount |
Account SObject | No | Account associated with the donation |
RecurringDonation |
GiftCommitment SObject | No | Parent gift commitment |
Status management#
| Variable | Type | Description |
|---|---|---|
FutureStatus |
String | Status to restore after temporary changes |
Status |
String | External platform status for processing |
Fee and amount processing#
| Variable | Type | Description |
|---|---|---|
Amount |
Currency | Transaction amount |
FeePlatform |
Currency | Platform-specific processing fee |
FeePlatformPublic |
Currency | Public platform fee (tip/donation to platform) |
ModifiedAt |
Date | Modification date for refund processing |
Campaign hierarchy structure#
| Variable | Type | Description |
|---|---|---|
Campaign_CampaignContact |
Account SObject | Contact associated with top-level campaign |
Campaign_TeamContact |
Account SObject | Contact associated with team campaign |
Campaign_FundraiserContact |
Account SObject | Contact associated with fundraiser campaign |
CampaignIdList |
String Collection | List of campaign IDs for member creation |
Campaign member configuration#
| Variable | Type | Default | Description |
|---|---|---|---|
Config_CampaignMemberAll |
Boolean | false | Create members for all campaigns |
Config_CampaignMemberParentCampaign |
Boolean | false | Create members for parent campaigns |
Config_CampaignMemberTopLevelCampaign |
Boolean | false | Create members for top-level campaigns |
Config_CampaignMemberDeleteExistingStatuses |
Boolean | false | Remove existing campaign member statuses |
Config_CampaignMemberLabelTeamLeader |
String | "Team Leader" | Label for team leader status |
Config_CampaignMemberLabelFundraiser |
String | "Fundraiser" | Label for fundraiser status |
Config_CampaignMemberLabelRecurringDonor |
String | "Recurring Donor" | Label for recurring donor status |
Config_CampaignMemberLabelDonor |
String | "Donor" | Label for donor status |
Config_CampaignMemberLabelProspect |
String | "Prospect" | Label for prospect status |
Soft credit configuration#
| Variable | Type | Default | Description |
|---|---|---|---|
Config_DonationSuppressSoftCredit |
Boolean | false | Disable soft credit creation |
Tribute processing#
| Variable | Type | Description |
|---|---|---|
Tribute_TributeType |
String | Type of tribute (honor/memory) |
TributeContact |
Account SObject | Contact being honoured/memorialised |
Tribute_Custom_Name |
String | Honoree name supplied as one combined value |
Matching gift processing#
| Variable | Type | Description |
|---|---|---|
MatchedContact |
Account SObject | Contact associated with matching gift |
MatchedKey |
String | Platform key for matched donation |
MatchedMatchedDonationType |
String | Type of matched donation relationship |
Platform |
String | Platform identifier |
Gift designation configuration#
| Variable | Type | Default | Description |
|---|---|---|---|
Config_DonationSuppressGiftDesignations |
Boolean | false | Disable gift designation processing |
Config_DonationGiftDesignationsCache |
Boolean | true | Enable caching for gift designations |
Override_GiftDesignationId |
String | - | Override source for gift designations |
Config_DonationAmountSubtractFeePlatform |
Boolean | false | Subtract platform fees from amount |
Record context#
| Variable | Type | Description |
|---|---|---|
IsNewRecord |
Boolean | Flag indicating new record |
Output variables#
| Variable | Type | Description |
|---|---|---|
Logs |
MoveDataLogEntry[] | Processing logs from all operations |
LogsJSON |
String | JSON representation of processing logs |
RecordList |
String Collection | List of created/updated record IDs |
Flow logic#
1. Status restoration management#
Future status processing: The flow checks if a temporary status change was made during mapping and needs restoration:
IF FutureStatus IsNotNull THEN
Update Record.Status = FutureStatus
Log status restoration
Use case: When field changes on paid transactions require temporary "Unpaid" status, this restores the original intended status.
2. Refund processing#
Refund detection: The flow identifies refund transactions and processes them accordingly:
IF Status = "refund" THEN
Set RefundAmount = AmountCalculated
Set RefundProcessorFee = FeePlatformDonorCalculated
AmountCalculated follows Config_DonationAmountSubtractFeePlatform exactly as the mapping flow does: the Public Platform Fee when the platform sent one — including a zero — and otherwise the Total Platform Fee, unless the platform reported that the donor did not cover the fee, in which case nothing is subtracted.
Refundable balance: Before anything is written, the flow reads the transaction's Current Amount as the balance still available to refund, and compares the reversal against it:
IF RefundableBalance <= 0 THEN
Log and skip the notification — nothing is left to refund
ELSE IF RefundAmount > RefundableBalance THEN
Log a warning naming both figures
Set RefundAmount = RefundableBalance
A balance of zero or less is almost always the same refund arriving twice, so the notification is skipped rather than refunded again. Where the reversal exceeds a positive balance, the balance is recorded instead of the reversal's own amount; the shortfall is the amount the original gift was recorded short by.
GiftRefund record creation: Creates dedicated refund records with:
- Amount: Calculated refund amount
- Date: Uses ModifiedAt or current date
- GiftTransactionId: Links to parent transaction
- ProcessorTransactionFee: Refund processing fees
- Status: Set to "Completed"
Full refund detection: Compares the refund to the refundable balance, so several partial refunds can together close a gift:
IF RefundAmount >= RefundableBalance THEN
Update Record.Status = "Fully Refunded"
3. Soft credit creation#
Soft credit enablement check: Validates if soft credit processing should occur:
IF Config_DonationSuppressSoftCredit != true THEN
Process soft credits
Matched donor integration: Handles matching gift scenarios with additional donor attribution:
IF MatchedMatchedDonationType = "donor" THEN
Call CreateSoftCreditComponent with MatchedDonorContactRecord
ELSE
Call CreateSoftCreditComponent without matched donor
Multi-level attribution: The CreateSoftCreditComponent processes:
- Donor attribution: Primary donor gets donor role
- Campaign attribution: Campaign contacts get soft credit roles
- Team attribution: Team contacts get soft credit roles
- Fundraiser attribution: Individual fundraiser contacts get soft credit roles
4. Campaign member management#
Campaign member enablement: Uses formula to determine if campaign members should be created:
CreateCampaignMembers =
Config_CampaignMemberAll == TRUE ||
Config_CampaignMemberParentCampaign == TRUE ||
Config_CampaignMemberTopLevelCampaign == TRUE
Prerequisites validation: Ensures required data exists:
- Campaign exists with valid ID
- Contact exists with valid ID
- Campaign member creation is enabled
Campaign member initialisation: Sets up campaign member structure with configurable status labels:
CampaignMemberInitialiseComponent Parameters:
- CampaignId: DonationCampaign.Id
- DeleteOtherCampaignMemberStatuses: Config setting
- Status Labels: All configurable member status labels
Campaign evaluation: Determines which campaigns should have members created based on configuration.
Hierarchical status management: Establishes prioritised hierarchy:
- Team Leader (highest priority)
- Fundraiser
- Recurring Donor
- Donor (target status for this flow)
- Prospect (lowest priority)
Campaign member creation: Uses CampaignMemberCreateComponent with value hierarchy to ensure proper status assignment.
5. Tribute processing#
Tribute detection: Identifies tribute donations requiring special processing:
IF Tribute_TributeType IsNotNull AND (TributeContact IsNotNull OR Tribute_Custom_Name IsNotNull) THEN
Process tribute
A tribute type on its own is not enough: the gift must also name who is being honoured or memorialised, either as a matched contact or as a combined name in Tribute_Custom_Name.
Some platforms send the memorial name only as one combined value and so match no contact; such a gift is still processed as a tribute.
GiftTribute record management: Retrieves or creates GiftTribute record linked to the transaction.
Tribute type assignment: Sets appropriate tribute type based on input:
- "memory" maps to "Memorial"
- "honor" maps to "Honor"
Honoree contact processing: Links tribute to the honoured/memorialised contact:
Gift_Tribute_Record.HonoreeContactId = TributeContact.Id
Gift_Tribute_Record.HonoreeName = "{TributeContact.FirstName} {TributeContact.LastName}"
Honoree name processing: Where no contact was matched and the honoured name arrived as one combined value, the name is recorded on its own:
IF TributeContact IsNull AND Tribute_Custom_Name IsNotNull THEN
Gift_Tribute_Record.HonoreeName = Tribute_Custom_Name
The contact route is evaluated first, so an honoree record wins wherever one was matched. On this route no honoree reference is set — the tribute carries a name and no honoree record — and the combined name is never split into first and last names.
Notification contact assignment: Sets fundraiser as notification recipient when available:
IF Campaign_FundraiserContact IsNotNull THEN
Gift_Tribute_Record.NotificationContactId = Campaign_FundraiserContact.Id
Gift_Tribute_Record.NotificationContactName = "{FirstName} {LastName}"
Gift_Tribute_Record.NotificationEmail = Campaign_FundraiserContact.PersonEmail
Tribute record upsert: Commits changes to GiftTribute record and tracks in RecordList.
6. Matching gift relationship processing#
Matching gift detection: Identifies when transaction is part of matching gift relationship:
IF MatchedMatchedDonationType = "donor" AND MatchedKey IsNotNull
Platform key generation: Creates platform key for matched donation lookup:
Matched_Donation_Platform_Key Subflow:
- Key: MatchedKey
- Platform: Platform
Matched transaction lookup: Retrieves the matched transaction record by platform key.
Bidirectional relationship establishment: Sets employer transaction reference on matched donation:
IF Get_Matched_Donation_Record.MatchingEmployerTransactionId != Record.Id THEN
Get_Matched_Donation_Record.MatchingEmployerTransactionId = Record.Id
Update matched donation record
Relationship validation: Prevents duplicate or circular relationships.
7. Gift designation processing#
Gift designation enablement: Checks if gift designation processing is enabled:
IF Config_DonationSuppressGiftDesignations != true
Amount determination: Sets appropriate amount for gift designation allocation:
- New records: Uses OriginalAmount
- Existing records: Uses CurrentAmount from database lookup
Source priority resolution: Applies gift designations in priority order:
- Override source: Uses Override_GiftDesignationId when provided
- Gift commitment: Copies from parent GiftCommitment
- Campaign: Copies from associated Campaign
- Default: Applies system default gift designations
Gift designation copying: Uses CopyGiftDesignationsComponent with:
- Amount: Calculated designation amount
- EnableCache: Configuration-driven caching
- SourceRecordId: Determined by priority logic
- TargetRecordId: Current transaction ID
Error handling#
Status management protection#
- Validates FutureStatus before restoration
- Logs all status changes for audit trail
- Handles missing or invalid status values
Refund processing validation#
- Compares refund amounts against the refundable balance, recording no more than the balance allows
- Prevents negative refund amounts
- Handles missing or invalid refund data
- Where Salesforce or a validation rule in the org refuses the refund record or the status update, the notification fails with
Could not record the refund:followed by the platform's own message, rather than an unhandled fault
Relationship integrity#
- Validates matching gift relationships before creation
- Prevents circular references in matching gifts
- Checks for existing relationships before updates
Campaign member deduplication#
- Uses hierarchical status system to prevent duplicate statuses
- Respects existing higher-priority campaign member statuses
- Provides detailed logging for status assignment decisions
Dependencies#
Apex components#
- CopyGiftDesignationsComponent: Gift designation management and copying
- CreateSoftCreditComponent: Soft credit relationship creation
- CampaignMemberInitialiseComponent: Campaign member structure setup
- CampaignMemberEvaluateComponent: Campaign selection logic
- CampaignMemberCreateComponent: Campaign member creation with hierarchy
- movedata__WriteToLogFlowComponent: Comprehensive logging
Subflows#
- MoveData_Donation_Donation_Key: Platform key generation for matching gift lookup