> ## Documentation Index
> Fetch the complete documentation index at: https://wegive.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# GAU & Allocation

> Mapping between WeGive Funds and Salesforce General Accounting Units (GAUs) and Allocations

**Salesforce Object:** `npsp__General_Accounting_Unit__c` (NPSP standard object)\
**WeGive Model:** Fund

## Overview

This document describes how fund/designation data syncs between WeGive and Salesforce. In Salesforce NPSP, funds are called "General Accounting Units" (GAUs) and represent designations or funds to which donations can be allocated.

**Important Note:** Some organizations may use a custom fund object instead of the standard NPSP GAU object. The `fund_api_name` setting in the integration configuration determines which Salesforce object is used. This documentation covers the standard NPSP implementation.

***

## How Fund Data Syncs

### Direction

* **Import from Salesforce** - Data imports from Salesforce into WeGive only
* **Export to Salesforce** - Data exports from WeGive to Salesforce only
* **Both Ways** - Data syncs in both directions

### Mapping Types

* **Configurable** - Can be customized via integration settings
* **Hard-coded** - Built into the integration logic and cannot be changed

***

## Sync Triggers

### From WeGive to Salesforce (Export)

Fund data is exported from WeGive to Salesforce when:

* **Fund Created:** A new fund is created in WeGive
* **Fund Updated:** An existing fund is modified in WeGive (e.g., name changed, description updated, active status changed)

The export happens automatically after the create or update action in WeGive.

### From Salesforce to WeGive (Import)

Fund data is imported from Salesforce to WeGive based on:

* **Last Modified Date:** WeGive periodically polls Salesforce for GAUs that have been modified since the last sync
* **Sync Frequency:** The integration checks for updated GAUs on a scheduled basis (frequency varies by integration configuration)
* **Modified Field Tracking:** Only GAUs with a `LastModifiedDate` newer than the last successful sync are pulled into WeGive

This means:

* Creating a new GAU in Salesforce will import it to WeGive on the next sync cycle
* Updating an existing GAU in Salesforce will trigger an import to WeGive on the next sync cycle
* The sync is based on Salesforce's `LastModifiedDate` field, not individual field changes

***

## Sync Process Overview

### Fund-Level Synchronization

WeGive syncs funds at the General Accounting Unit level in Salesforce, maintaining fund definitions, descriptions, and active status. Funds are used for allocating donations to specific purposes, programs, or designations.

### Pulling Data from Salesforce

When pulling data from Salesforce, WeGive queries General Accounting Units based on the last modified date and any specific filtering criteria. The integration pulls comprehensive data from the GAU record, including all standard and custom fields that have been mapped.

The import process includes:

* **Fund Identification:** Creates or updates the corresponding WeGive Fund record
* **Active Status:** Maintains whether the fund is currently active for donations
* **Custom Fields:** Imports any custom fields configured through mapping rules
* **Metadata:** Preserves created date and other tracking information

### Pushing Data to Salesforce

When a Fund is created or updated in WeGive, the integration compiles a payload for the Salesforce GAU object. This payload includes all mapped fields and ensures that the GAU record is properly created or updated in Salesforce.

The integration handles:

* **Standard Fields:** Name, description, active status
* **Custom Fields:** Any organization-specific fields configured through mapping rules
* **Data Type Conversion:** Properly formats data types (e.g., boolean values for active status)

### General Accounting Unit Field Mappings

| Salesforce Field         | WeGive Field  | WeGive API Field | Direction              | Type                                    | Notes                                        |
| :----------------------- | :------------ | :--------------- | :--------------------- | :-------------------------------------- | :------------------------------------------- |
| Id                       | Salesforce ID | salesforce\_id   | Import from Salesforce | Hard-coded                              | Salesforce's unique identifier for this fund |
| Name                     | Fund Name     | name             | Both Ways              | Configurable import / Hard-coded export | Display name of the fund                     |
| npsp\_\_Description\_\_c | Description   | description      | Both Ways              | Configurable                            | Detailed description of the fund purpose     |
| npsp\_\_Active\_\_c      | Active Status | active           | Both Ways              | Configurable                            | Whether the fund is currently active         |
| CreatedDate              | Created At    | created\_at      | Import from Salesforce | Hard-coded                              | When the fund was created                    |

### Active Status Handling

The `active` field is converted to a boolean value during import:

* If the value can be validated as a boolean, it's set to `true` or `false`
* This ensures consistent active/inactive status across both systems
* Inactive funds typically cannot be selected for new donations but remain for historical reporting

### Fund Allocations

Funds work in conjunction with the Allocation object:

* **Transactions** can have allocations to one or more funds
* **Recurring Donations** can have allocations to one or more funds
* Allocations specify either a fixed amount or percentage going to each fund
* See the Allocation documentation for details on how donations are allocated to funds

### Integration with Donations

When a transaction or recurring donation has a fund assigned:

* The `fund_id` field on the transaction/recurring donation links to the WeGive fund
* In Salesforce, this is represented through Allocation records
* If fund allocations are NOT enabled, a single allocation is created linking the Opportunity to the GAU
* If fund allocations ARE enabled, multiple allocations can exist per Opportunity/Recurring Donation

***

## Fund Matching & Create/Update Logic

### When WeGive Exports a Fund to Salesforce

The integration uses the following logic to determine whether to create a new GAU or update an existing one:

**Step 1: Check for Existing Salesforce Fund ID**

* If the WeGive fund has a `salesforce_id`: The integration **UPDATES** the existing GAU record in Salesforce
* If no `salesforce_id` exists: The integration **CREATES** a new GAU record in Salesforce

**Note:** Unlike donors, funds are NOT matched by name or other criteria. Each WeGive fund maps to exactly one Salesforce GAU record based solely on the stored Salesforce ID.

### When Salesforce Exports a Fund to WeGive

**Step 1: Check for Existing WeGive Fund**

* The integration searches for an existing fund by `salesforce_id`
* If found, it updates that fund
* If not found, it creates a new fund

**Step 2: Import Data**

* All mapped fields are imported from the GAU record
* Boolean values (like active status) are properly converted
* Custom field values are processed through the custom fields system

### Why This Matters

This matching logic ensures:

* Each WeGive fund maps to exactly one Salesforce GAU record
* Fund definitions remain consistent across both systems
* Historical allocations continue to reference the correct fund
* No duplicate funds are created during sync operations

***

## Integration Rules

Organizations can create custom mapping rules for funds to handle:

* Additional custom fields on the GAU object
* Organization-specific fund tracking fields
* Custom reporting or categorization fields

These rules are configured in the `neon_mapping_rules` table with:

* `crm` = 'salesforce'
* `integration` = 'fund'
* `level` = 'import', 'export', or 'both'

# GAU Allocation (Fund Allocation) - Field Mapping

**Salesforce Object:** `npsp__Allocation__c` (NPSP standard object)\
**WeGive Model:** FundAllocation

## Overview

GAU Allocations represent how donations (Opportunities) or recurring donations are allocated to specific funds (General Accounting Units). This allows a single donation to be split across multiple funds, with each allocation specifying either a dollar amount or percentage going to each fund.

**Organization Setting Required:** Fund allocations must be enabled in the organization settings (`enable_fund_allocations = true`) for allocation syncing to occur. If disabled, the integration uses the legacy single-fund approach where the fund is directly assigned to the transaction.

***

## How Allocation Data Syncs

### Direction

* **Import from Salesforce** - Data imports from Salesforce into WeGive only
* **Export to Salesforce** - Data exports from WeGive to Salesforce only
* **Both Ways** - Data syncs in both directions

### Mapping Types

* **Hard-coded** - Built into the integration logic and cannot be changed

***

## Sync Triggers

### From WeGive to Salesforce (Export)

Allocation data is exported from WeGive to Salesforce when:

* **Transaction Created/Updated:** When a transaction with fund allocations is created or updated
* **Recurring Donation Created/Updated:** When a recurring donation with fund allocations is created or updated
* **Allocation Modified:** When an allocation amount is changed
* **Allocation Deleted:** When an allocation is removed

**Automatic Sync Management:** When a transaction or recurring donation is pushed to Salesforce, the integration automatically:

1. Creates new allocations that don't exist in Salesforce
2. Updates existing allocations if amounts have changed
3. Deletes allocations in Salesforce that no longer exist in WeGive

This ensures allocations are always in sync with the parent record.

### From Salesforce to WeGive (Import)

Allocation data is imported from Salesforce to WeGive based on:

* **Last Modified Date:** WeGive periodically polls Salesforce for Allocations that have been modified since the last sync
* **Parent Record Sync:** When importing Opportunities or Recurring Donations, allocations can be included via subquery (if enabled)
* **Deleted Allocations:** The integration tracks deleted allocations via `IsDeleted = true` queries

This means:

* Creating a new Allocation in Salesforce will import it to WeGive on the next sync cycle
* Updating an existing Allocation in Salesforce will trigger an import to WeGive on the next sync cycle
* Deleting an Allocation in Salesforce will remove it from WeGive on the next sync cycle

***

## Sync Process Overview

### Allocation-Level Synchronization

WeGive syncs fund allocations at the individual Allocation record level, maintaining the relationship between donations (or recurring donations) and the specific funds they support.

### Pulling Data from Salesforce

**Standard Pull Process:** When pulling allocation data from Salesforce as a separate query, WeGive:

1. Queries `npsp__Allocation__c` records based on last modified date
2. Loads related transactions and recurring donations that match the Opportunity/Recurring Donation IDs
3. Loads funds (GAUs) that match the allocation records
4. Creates or updates FundAllocation records in WeGive

**Deleted Allocations:** The integration specifically queries for deleted allocations:

These are then removed from WeGive to maintain sync.

### Pushing Data to Salesforce

When a transaction or recurring donation with allocations is pushed to Salesforce, the integration:

1. **Ensures Prerequisites Exist:**
   * Fund must have a `salesforce_id`
   * Transaction must have a `salesforce_id` (for transaction allocations)
   * Recurring Donation must have a `salesforce_id` (for recurring donation allocations)
2. **Queries Existing Allocations:**
   * Fetches all current allocations in Salesforce for the parent record
   * Compares with WeGive allocations
3. **Synchronizes Allocations:**
   * **Creates** new allocations that don't exist in Salesforce
   * **Updates** existing allocations if amounts have changed
   * **Deletes** allocations in Salesforce that no longer exist in WeGive

This "sync to match" approach ensures allocations are always consistent.

| Salesforce Field                       | WeGive Field                     | WeGive API Field           | Direction              | Type       | Notes                                                   |
| :------------------------------------- | :------------------------------- | :------------------------- | :--------------------- | :--------- | :------------------------------------------------------ |
| Id                                     | Salesforce ID                    | salesforce\_id             | Import from Salesforce | Hard-coded | Salesforce's unique identifier for this allocation      |
| npsp\_\_Opportunity\_\_c               | Transaction Salesforce ID        | allocatable.salesforce\_id | Both Ways              | Hard-coded | Links to Opportunity (for transaction allocations)      |
| npsp\_\_Recurring\_Donation\_\_c       | Recurring Donation Salesforce ID | allocatable.salesforce\_id | Both Ways              | Hard-coded | Links to Recurring Donation (for recurring allocations) |
| npsp\_\_General\_Accounting\_Unit\_\_c | Fund Salesforce ID               | fund.salesforce\_id        | Both Ways              | Hard-coded | Links to the GAU (fund)                                 |
| npsp\_\_Amount\_\_c                    | Amount                           | amount                     | Both Ways              | Hard-coded | Dollar amount allocated (WeGive stores in cents)        |
| npsp\_\_Percent\_\_c                   | Percentage                       | (calculated)               | Import from Salesforce | Hard-coded | Percentage of total (imported but not exported)         |

### Prerequisites for Creating Allocations

Before creating an allocation in Salesforce, the integration ensures:

1. **Fund exists:** The fund must have a `salesforce_id` - the integration will automatically push the fund if needed
2. **Parent record exists:** The transaction or recurring donation must have a `salesforce_id`
3. **Allocatable amount is valid:** The amount must be greater than zero

***

## Allocation Matching & Create/Update Logic

### When WeGive Exports Allocations to Salesforce

The integration uses a "sync to match" approach:

**Step 1: Query Existing Allocations**

* Fetch all allocations in Salesforce for the parent record (Opportunity or Recurring Donation)
* Track their Salesforce IDs

**Step 2: Process WeGive Allocations** For each allocation in WeGive:

* If it has a `salesforce_id`: **UPDATE** the existing allocation in Salesforce
* If it has no `salesforce_id`: **CREATE** a new allocation in Salesforce
* Track which Salesforce IDs should be kept

**Step 3: Delete Orphaned Allocations**

* Any Salesforce allocations not in the "keep" list are **DELETED**
* This ensures removed allocations in WeGive are removed in Salesforce

### When Salesforce Exports Allocations to WeGive

**Step 1: Find Allocatable Record** The integration determines which record this allocation belongs to:

* If `npsp__Opportunity__c` is set: Search for transaction with that `salesforce_id`
* If `npsp__Recurring_Donation__c` is set: Search for recurring donation with that `salesforce_id`
* If neither parent is found, throw an exception

**Step 2: Find or Create Allocation**

* Search for existing allocation by `salesforce_id`
* If not found, create new FundAllocation

**Step 3: Find Fund**

* Search for fund with matching `salesforce_id` from `npsp__General_Accounting_Unit__c`
* If fund not found, throw an exception

**Step 4: Update Allocation**

* Set the amount (convert from dollars to cents)
* Associate with fund, allocatable, and donor
* Save the allocation

### Deleted Allocations from Salesforce

The integration handles deleted allocations through a separate query:

* Queries allocations where `IsDeleted = true`
* Finds matching allocations in WeGive by `salesforce_id`
* Deletes the WeGive allocation

### Why This Matters

This logic ensures:

* Allocations are always in sync with their parent transaction or recurring donation
* Changes in fund allocations (adding, removing, modifying) are reflected in both systems
* Deleted allocations are properly removed
* No orphaned or duplicate allocations exist

***

## Integration Rules

Currently, allocation field mappings are entirely hard-coded. There are no configurable mapping rules for allocations, as the data structure is standardized across NPSP implementations.

***

## Required Fields

**For WeGive to Salesforce:**

* Parent record reference (either `npsp__Opportunity__c` or `npsp__Recurring_Donation__c`)
* Fund reference (`npsp__General_Accounting_Unit__c`)
* Amount (`npsp__Amount__c`)

**For Salesforce to WeGive:**

* Id (Salesforce ID)
* Parent record reference (one of the above)
* Fund reference
* Amount

## Usage Examples

### Example 1: Single Allocation

A \$100 donation entirely to the "Building Fund":

* **WeGive:** One FundAllocation record with amount = 10000 (cents), fund\_id = X
* **Salesforce:** One Allocation record with npsp\_\_Amount\_\_c = 100, npsp\_\_General\_Accounting\_Unit\_\_c = GAU\_ID

### Example 2: Split Allocation

A \$100 donation split between two funds:

* **WeGive:**
  * FundAllocation 1: amount = 6000 (cents), fund\_id = X (General Fund)
  * FundAllocation 2: amount = 4000 (cents), fund\_id = Y (Music Fund)
* **Salesforce:**
  * Allocation 1: npsp\_\_Amount\_\_c = 60, npsp\_\_General\_Accounting\_Unit\_\_c = GAU\_X
  * Allocation 2: npsp\_\_Amount\_\_c = 40, npsp\_\_General\_Accounting\_Unit\_\_c = GAU\_Y

### Example 3: Recurring Donation with Allocations

A \$50/month recurring donation split between funds:

* **WeGive:**
  * ScheduledDonation with two FundAllocation records
  * Each allocation specifies the amount per installment
* **Salesforce:**
  * npe03\_\_Recurring\_Donation\_\_c with two Allocation records
  * Each Opportunity created by the recurring donation inherits these allocations

***

## Troubleshooting

**Allocations not syncing:**

* Verify `enable_fund_allocations = true` in organization settings
* Check that the parent transaction/recurring donation has a `salesforce_id`
* Ensure all funds have `salesforce_id` values

**Allocation amounts don't match:**

* WeGive stores amounts in cents, Salesforce in dollars - verify conversion
* Check for rounding issues with percentage-based allocations
* Ensure the sum of allocations doesn't exceed the transaction amount

**Deleted allocations reappearing:**

* The integration deletes allocations on both sides during sync
* If an allocation reappears, check for competing sync processes
* Verify the "deleted allocations" query is running

**Fund not found errors:**

* Ensure all funds referenced in allocations exist in both systems
* Verify funds have valid `salesforce_id` values
* Check that fund sync is working properly

**Parent record not found:**

* Verify the transaction or recurring donation exists in WeGive
* Check that the parent record has a valid `salesforce_id`
* Ensure the allocation is linked to either an Opportunity or Recurring Donation (not both)

***

## Best Practices

1. **Enable fund allocations** if your organization needs to track donations across multiple funds
2. **Create funds first** before creating transactions with allocations
3. **Use consistent fund structures** across both systems
4. **Verify allocation totals** - the sum of allocations should equal (or be less than) the transaction amount
5. **Monitor sync logs** for allocation-related errors
6. **Test allocation changes** in a sandbox before deploying to production
7. **Document fund purposes** so staff know which fund to use for different donation types
8. **Train staff** on how allocations work and when to use them
9. **Use subqueries when possible** - including allocations in Opportunity queries reduces API usage
10. **Clean up orphaned allocations** - if a transaction is deleted, ensure allocations are cleaned up too

***

## Understanding the "Sync to Match" Approach

The integration uses a sophisticated "sync to match" approach for allocations:

1. **On every transaction/recurring donation push**, the integration:
   * Queries all existing allocations in Salesforce for that record
   * Compares them with the allocations in WeGive
   * Creates, updates, or deletes allocations to match WeGive exactly
2. **This approach ensures:**
   * No duplicate allocations
   * No orphaned allocations
   * Allocations always reflect the current state in WeGive
   * Changes to allocations are immediately reflected in Salesforce
3. **Why this matters:**
   * If you change an allocation amount in WeGive, it updates in Salesforce
   * If you remove an allocation in WeGive, it's deleted in Salesforce
   * If you add an allocation in WeGive, it's created in Salesforce
   * All of this happens automatically when the parent record syncs

***
