Documentation of the Coordinated Gift Commitment Batch Job

Documentation of the Coordinated Gift Commitment Batch Job

1. Commitment Processing Architecture

Two versions available from Summer '26. Both exclude Closed commitments from processing.

Version A — Original Processing (3 Nightly Batch Jobs)

Batch Job

Trigger Condition

What It Does

UpdateCmtmtOnNxtTxn-1

NextTransactionDate < Today AND Status != Closed/Failing/Lapsed

Creates next Gift Transaction; updates NextTransactionDate & NextTransactionAmount

UpdateCmtmtOnSchChange-1

Schedule StartDate or EndDate has crossed since last run

Updates the CurrentGiftCommitmentSchedule when a new schedule activates or expires

UpdateCmtmtOnTxnStatus-1

Transactions past due with Failed/Unpaid status, or recently modified

Updates Commitment Status to Failing when transactions fail/lapse

Key fields driving the Original engine: 

  • NextTransactionDate — primary batch filter trigger

  • NextTransactionAmount — amount for upcoming transaction

  • CurrentGiftCommitmentSchedule__c — lookup to active schedule

  • Status — must not be Closed, Failing, or Lapsed

Version B — NextGen Processing (1 Batch Job, Summer '26)

Single job NextGenCmtBatchProc-1 processes all non-Closed commitments via CommitmentProcessingOrchestrator (Java). 

  • Accepts currentDate runtime param (defaults to today)

  • Configurable batch sizes (default: 10,000)

  • Supports parallel execution

  • IsNextGenCmtPrcsParallel — enable parallel execution

  • NextGenCmtPrcsBatchSize — commitments per batch

  • Only 1 concurrent job allowed (enforced)

Please note: NextGen processes ALL non-Closed commitments regardless of NextTransactionDate — the orchestrator decides what work is needed per commitment, unlike Original which relies purely on the date filter.

 

2. ProcessGiftCommitment Apex Action — Detailed Logic

Flow ProcessGiftCommitment calls invocable action ProcessGiftCommitmentInvocableAction. Original engine only — NextGen uses CommitmentProcessingNextGenBatchJobHandler (Java) directly.

 Step 1 — Input Resolution (ID Prefix)

Prefix

Record Type

Action

6gc

Gift Commitment

Passed directly

6cs

GC Schedule

Queries GiftCommitmentId first

6tr

Gift Transaction

Queries GiftCommitmentId first

 Step 2 — Invocable Action

  1. Validates inputs — rejects empty/null IDs

  2. Deduplicates the commitment ID list

  3. Delegates to RecurrenceService.processRecurrenceBatch()

  4. Returns giftCommitmentProcessingStatus per commitment

Step 3 — RecurrenceService Logic

  1. Reads schedule details (frequency, amount, next date)

  2. Checks if new Gift Transaction is needed (NextTransactionDate)

  3. Creates GiftTransaction (Status = Unpaid) if yes

  4. Advances NextTransactionDate by one recurrence interval

  5. Updates NextTransactionAmount

  6. Evaluates commitment status from recent transaction outcomes

  7. Updates CurrentGiftCommitmentSchedule if transition needed

 

3. Gift Transaction Creation — Fields, Triggers & Due Date

Fields Driving Transaction Creation (Original Engine)

Field

Role

NextTransactionDate

Primary trigger — when < today, batch creates transaction

NextTransactionAmount

Amount assigned to new transaction

CurrentGiftCommitmentSchedule

Determines frequency, amount, campaign/source code

Status

Must be Active (not Closed/Failing/Lapsed)

TransactionPeriod

Recurrence interval — used to calculate next date

Filter Conditions — ALL must be true (Original):

  • NextTransactionDate < Current_Date

  • Status != Closed

  • Status != Failing

  • Status != Lapsed

  • Valid GiftCommitmentSchedule linked (CurrentGiftCommitmentSchedule populated)

TransactionDueDate Population

  • Recurring schedules: TransactionDueDate = NextTransactionDate at time of creation

  • Custom schedules: each installment defines its own date

Schedule fields that feed into DueDate:

  • GiftCommitmentSchedule.StartDate — schedule activation date

  • GiftCommitmentSchedule.EndDate — schedule expiry date

  • GiftCommitmentSchedule.TransactionPeriod — interval between due dates

  • GiftCommitment.NextTransactionDate — written directly to TransactionDueDate

Please Note: First transaction at commitment creation time: TransactionDueDate populated from the schedule's first installment date.

4. End-to-End Process Flow

Phase 1 — Initial Commitment Creation (via Gift Entry)

  1. Fundraiser enters recurring gift via Gift Entry form

  2. ProcessGiftEntries flow → InvocableProcessGiftEntries action

  3. GiftEntryProcessorImpl routes to GiftEntryCommitmentProcessorImpl (isNewRecurringGift = true)

  4. System creates in sequence:

  • GiftCommitment (Status = Active, ScheduleType = RECURRING)

  • GiftDefaultDesignation(s) — designation templates

  • GiftDefaultSoftCredit(s) — soft credit templates

  • GiftCommitmentSchedule — frequency, amount, start/end

  • First GiftTransaction (Status = Unpaid) via postCommitmentScheduleProcess()

  • NextTransactionDate set to next scheduled interval from schedule start date

Key business logic:

  • Amount: from GiftCommitmentSchedule.RecurringAmount

  • Default: TransactionPeriod = MONTHLY, RecurrenceType = OPEN_ENDED

  • TransactionDueDate = NextTransactionDate at creation

  • Designations: auto-generated from GiftDefaultDesignation records

  • Soft Credits: auto-generated from GiftDefaultSoftCredit records

  • Campaign / OutreachSourceCode: carried forward from schedule to each transaction

Phase 2 — Ongoing Generation: Original Engine (3 Nightly Jobs)

Job

Action

UpdateCmtmtOnNxtTxn-1

Queries commitments WHERE NextTransactionDate < Today AND Status != Closed/Failing/Lapsed → calls ProcessGiftCommitment-1 flow → RecurrenceService creates GiftTransaction (Unpaid), advances NextTransactionDate, auto-generates Designations & SoftCredits

UpdateCmtmtOnSchChange-1

Queries schedules where StartDate or EndDate crossed since last run → updates CurrentGiftCommitmentSchedule on GiftCommitment

UpdateCmtmtOnTxnStatus-1

Queries Failed/Unpaid transactions past due date or recently modified → updates GiftCommitment Status to Failing if threshold reached

Ongoing Generation: NextGen Engine (1 Nightly Job)

NextGenCmtBatchProc-1 queries ALL GiftCommitments WHERE Status != Closed → CommitmentProcessingNextGenBatchJobHandler → CommitmentProcessingOrchestrator.processCommitmentBatch() evaluates each commitment, creates transactions, updates fields, handles schedule transitions, supports parallel processing for large volumes.

 

5. Required & Optional Fields on GiftCommitment

Required Fields

Field

Notes

Status

Must be Active for transaction generation

DonorId (Account)

The donor this commitment belongs to

ScheduleType

Defaults to RECURRING

TransactionPeriod

Defaults to MONTHLY

RecurrenceType

Defaults to OPEN_ENDED

CurrentGiftCommitmentSchedule

Must have active schedule linked (runtime)

NextTransactionDate

Batch filter field (Original engine)

NextTransactionAmount

Amount of next transaction (Original engine)

Optional Fields

Field

Purpose

ExpectedEndDate

Sets RecurrenceType = FIXED_LENGTH

CampaignId

Carried to each generated transaction

OutreachSourceCodeId

Carried to each generated transaction

PaymentInstrumentId

Used for payment processing

OpportunityId

Links to a major donor opportunity

6. Impact of Paid Gift Transactions on the Commitment

Effect

Detail

Status Recovery

Commitment in Lapsed or Failing status → transitions back to Active upon receiving a new Paid transaction

Rollup Fields

Feeds TotalPaidTransactionAmount, TransactionPaymentCount, etc. via GiftDefaultDesignation rollups and DPE batch calculations

NextTransactionDate NOT affected

Date advances only when a new transaction is created by the recurrence engine — NOT by marking a transaction Paid

Duplicate Prevention

Batch checks existing Unpaid/Paid transactions for the current period before creating new ones — Paid records prevent duplicates

Threshold Evaluation

UpdateCmtmtOnTxnStatus-1 checks consecutive Failed/Unpaid count; a Paid transaction breaks the streak and resets the Failing counter

7. Configuration, Testing & Monitoring Best Practices

Configuration

  • Use NextGen — recommended engine, single job, parallel-capable

  • Set NextGenCmtPrcsBatchSize (default: 10,000); tune for volume/timeouts

  • Enable IsNextGenCmtPrcsParallel = true for large orgs

  • Configure Fundraising Settings thresholds:

  •  Installment Extension Day Count — grace period before Lapsed

  • Lapsed Unpaid Transaction Count — consecutive lapses → Lapsed

  • Failing Transaction Count — consecutive failures → Failing

  • Auto Close Recurring Commitment — auto-close at Lapsed/Failing

  • Set Create Recurring Schedule Transaction = On for auto-generation

Please Note: Only 1 NextGen job can run concurrently (hook_getMaxBatchJobAllowed() = 1). Never attempt parallel runs of the job itself.

Monitoring

  • Batch Management UI — job execution history, success/failure counts

  • Query GiftTransaction: Status = Unpaid AND TransactionDueDate < Today

Monitor GiftCommitment: Status = Lapsed or Status = Failing regularly

Sandbox & Migration Testing

  • Test with representative sample: active, lapsed, failing, paused, custom, open-ended

  • Verify NextTransactionDate populated before activating batch jobs

  • Run batch jobs manually via Batch Management UI after data load

  • Check for orphaned schedules (missing CurrentGiftCommitmentSchedule)

  • Compare transaction counts before/after batch vs. expected

  • Test ProcessGiftCommitment flow via Flow Builder debug or dev console

Long-Term Data Quality Governance

  • Audit NextTransactionDate — past dates with no recent transactions = missed commits

  • Reconcile counts: expected = months since start ÷ period vs. actual

  • Ensure Status = Closed on commitments with no future obligations

  • Verify every active commitment has GiftDefaultDesignation records

  • Proactively identify expired PaymentInstruments on active commitments

8. Migration Approach — Auto-Generate vs. Migrate Separately

Scenario

Recommendation

New org / no historical transactions

Let automation generate all transactions going forward after migrating commitments

Historical paid transactions required

Migrate historical transactions separately as data records; let automation handle future ones

Mix of paid history + future generation

Migrate commitments + paid historical transactions; set NextTransactionDate to correct upcoming date; batch jobs generate only future transactions

Recommended Migration Sequence

  1. Migrate GiftCommitments first

  2. Status = Active only for commitments generating future transactions

  3. Status = Closed for historical commitments with no future obligations

  4. NextTransactionDate = next FUTURE date (never a past date)

  5. Migrate GiftCommitmentSchedules — link to commitments, set StartDate, EndDate, RecurringAmount, TransactionPeriod

  6. Migrate GiftDefaultDesignations — every active commitment needs defaults before transactions generate

  7. Migrate historical GiftTransactions as static data (if needed)

  8. Status = Paid for past paid transactions

  9. GiftCommitmentId correctly populated

  10. Do NOT migrate future Unpaid — let batch engine create those

  11. Disable batch jobs during data load — prevents generation against partially-migrated data

  12. Validate data completeness in sandbox before activating production

  13. Activate batch jobs after full migration — first run generates transactions for any commitment with NextTransactionDate < Today

Ensuring Consistency

  • NextTransactionDate is the single most critical field — if past, batch immediately generates a transaction

  • Reconcile: query GiftTransaction WHERE GiftCommitmentId = [id] vs. expected count

  • Use Create Recurring Schedule Transaction = Off during migration; turn on after

Note: Disable batch jobs during data loads — most critical safeguard against duplicate/partial transactions

Preventing Data Issues

Duplicate Prevention

  • Recurrence engine checks existing transactions before creating new ones

  • Do not set NextTransactionDate to a past date unless intentional

  • If migrating historical Unpaid: set NextTransactionDate to next future date

Load Sequencing

  • GiftCommitments (Active, future NextTransactionDate)

  • GiftCommitmentSchedules (linked to commitments)

  • Update CurrentGiftCommitmentSchedule on each commitment

  • GiftDefaultDesignations

  • Historical GiftTransactions (Paid/Canceled as static data)

  • Enable and run batch jobs

Missing Transaction Prevention

  • Every active commitment needs GiftCommitmentSchedule with CurrentGiftCommitmentSchedule populated

  • Verify GiftDefaultDesignation records before go-live

  • Null or far-future NextTransactionDate = commitment skipped

Validation Rules to Implement

  • Block Status = Active on commitments without active schedule

  • Block null NextTransactionDate on active commitments

  • Block GiftDefaultDesignation creation for inactive designations

 

9. Known Limitations & Constraints

Limitation

Description

Max 1 concurrent NextGen job

hook_getMaxBatchJobAllowed() = 1 — no parallel runs of the job itself

Closed commitments are terminal

Cannot be reopened — once Closed, no further transactions ever generated

Original engine: 3 separate jobs

All three must be scheduled; each covers a distinct scenario

NextGen processes all non-Closed

Failing/Lapsed also evaluated (unlike Original) — may generate unwanted transactions

Custom schedules: max 30 installments

Hard limit — cannot have more than 30 installments

Amount changes create new schedule

Upgrade/downgrade ends existing schedule, creates new one; NextTransactionDate reset

Schedule transitions require a job

UpdateCmtmtOnSchChange-1 must run or wrong schedule amount may be used

No rollback in batch

Transaction created but designation fails → transaction persists without designations

Error message truncation

Processing result messages truncated to 255 characters

10. Object Relationships & Cascade Effects

Object Hierarchy

  • GiftCommitment (parent)

  • GiftCommitmentSchedule (child, many)

  • CurrentGiftCommitmentSchedule → active schedule lookup

  • GiftTransaction (child, many)

  • GiftTransactionDesignation ← from GiftDefaultDesignation

  • GiftSoftCredit ← from GiftDefaultSoftCredit

  • GiftDefaultDesignation (child, many — templates)

  • GiftDefaultSoftCredit (child, many — templates)

Dependency Chain

GiftCommitment.CurrentGiftCommitmentSchedule → GiftCommitmentSchedule (RecurringAmount, TransactionPeriod, Dates) → feeds NextTransactionAmount & NextTransactionDate → Batch filter → GiftTransaction → Designations & SoftCredits

Cascade Effects of Common Changes

Change

Effect

Close Commitment

No further transactions; existing Unpaid remain

Change schedule amount

New GiftCommitmentSchedule created; old EndDate set; CurrentSchedule updated next batch run

Pause schedule

No transactions during pause; Status → Paused

Resume schedule

Transactions resume; Status → Active

Delete GiftDefaultDesignation

Future transactions miss that designation; may fall back to org-wide default

Mark Transaction as Paid

Status recovery (Lapsed/Failing → Active); NextTransactionDate unaffected

11. Troubleshooting

Closed Commitments Still Processing?

  • Both engines filter Status != Closed — check Status field is truly 'Closed'

  • Check if custom automation is re-opening commitments before batch runs

  • Confirm engine version: GetCommitmentProcessingVersionInvocableAction returns '1' (Legacy) or '2' (NextGen)

Batch Job Logs

  • Fundraising Operations app → Batch Management

  • Shows run status, timestamps, record counts, failed vs. succeeded totals per batch part