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
Validates inputs — rejects empty/null IDs
Deduplicates the commitment ID list
Delegates to RecurrenceService.processRecurrenceBatch()
Returns giftCommitmentProcessingStatus per commitment
Step 3 — RecurrenceService Logic
Reads schedule details (frequency, amount, next date)
Checks if new Gift Transaction is needed (NextTransactionDate)
Creates GiftTransaction (Status = Unpaid) if yes
Advances NextTransactionDate by one recurrence interval
Updates NextTransactionAmount
Evaluates commitment status from recent transaction outcomes
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)
Fundraiser enters recurring gift via Gift Entry form
ProcessGiftEntries flow → InvocableProcessGiftEntries action
GiftEntryProcessorImpl routes to GiftEntryCommitmentProcessorImpl (isNewRecurringGift = true)
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
Migrate GiftCommitments first
Status = Active only for commitments generating future transactions
Status = Closed for historical commitments with no future obligations
NextTransactionDate = next FUTURE date (never a past date)
Migrate GiftCommitmentSchedules — link to commitments, set StartDate, EndDate, RecurringAmount, TransactionPeriod
Migrate GiftDefaultDesignations — every active commitment needs defaults before transactions generate
Migrate historical GiftTransactions as static data (if needed)
Status = Paid for past paid transactions
GiftCommitmentId correctly populated
Do NOT migrate future Unpaid — let batch engine create those
Disable batch jobs during data load — prevents generation against partially-migrated data
Validate data completeness in sandbox before activating production
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