Class Name: DailyMembershipAccountsBatch¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/DailyMembershipAccountsBatch.cls
API Name: DailyMembershipAccountsBatch Type: Batch (Asynchronous Processing) Test Coverage: [To be verified]
Business Purpose¶
The DailyMembershipAccountsBatch synchronizes Account-level membership fields with active Membership records. This batch ensures that Account records display current membership information including status, end dates, member type, and fellowship details without requiring real-time triggers on every membership change. This daily synchronization approach reduces processing overhead while maintaining data accuracy for reporting and business processes.
Class Overview¶
Scope and Sharing¶
- Sharing Model: with sharing (respects record-level security)
- Access Modifier: public
- Interfaces Implemented: Database.Batchable
Key Responsibilities¶
- Identify Accounts needing membership field updates based on expired or missing memberships
- Populate Account AANP membership section fields from active Membership records
- Calculate and maintain membership continuity dates for anniversary tracking
- Sync Fellow membership information to Account fields
- Handle new memberships that start on the current day
- Use partial-success DML to ensure batch continues despite individual record failures
Public Methods¶
start¶
Purpose: Builds query to find Accounts requiring membership field updates based on three criteria: missing membership link, expired membership, or expired fellowship.
Parameters:
- bc (Database.BatchableContext): Standard batch context providing job metadata
Returns:
- Database.QueryLocator: Query locator identifying Accounts needing membership field synchronization
Business Logic: Queries Accounts that need membership field updates using three criteria: (1) Accounts with missing or expired AANP membership links, (2) Accounts with expired Fellow memberships, and (3) Accounts with memberships starting today. Contains a critical bug where the "start today" logic fails due to empty Set initialization.
Throws: - None - uses Database.QueryLocator for error handling
Known Issues:
- CRITICAL BUG: Line 18 creates empty Map then extracts keySet, resulting in always-empty Set for "start today" accounts. Should be: new Map<Id,Account>(accounts).keySet()
execute¶
Purpose: Updates Account membership fields based on active memberships and fellowships for accounts in the batch scope.
Parameters:
- bc (Database.BatchableContext): Standard batch context
- scope (List
Returns: void
Business Logic: For each Account in scope, queries active AANP and Fellow memberships, prioritizes memberships starting today, populates Account membership fields including status and end dates, calculates Initial Join Date and Continuous Member Since dates, sets Is_Member flag based on 30-day grace period or Corporate Council status, and updates Fellow membership fields. Uses DailyMembershipUtil.safeUpdate() for partial-success DML.
finish¶
Purpose: Batch completion hook - no additional chaining required for this batch.
Parameters:
- bc (Database.BatchableContext): Standard batch context
Returns: void
Business Logic: Empty implementation as this is the final batch in the daily membership chain.
Private/Helper Methods¶
This class uses utility methods from DailyMembershipUtil for membership queries and safe updates:
- getActiveMembershipByAccount(): Queries active memberships by product family
- getStartTodayMembershipByAccount(): Queries memberships starting today
- safeUpdate(): Performs partial-success DML with error logging
Dependencies¶
Apex Classes¶
DailyMembershipUtil: Provides membership query methods and safe update functionalityDailyMembershipStatusBatch: Chains this batch in its finish() method
Salesforce Objects¶
Account: Fields read and written include AANP_Membership__c, Membership_End_Date__c, Membership_status__c, Member_Type__c, Membership_category__c, Initial_Join_Date__c, Continuous_Member_Since_At_Least_Date__c, Is_Member__c, Is_a_Fellow__c, Fellow_Membership__c, Fellow_Membership_End_Date__cMembership__c: Fields read include Id, Account_Name__c, Status__c, Start_Date__c, End_Date__c, Member_Type__c, Membership_Category__c, Product_Family__c
Custom Settings/Metadata¶
- None directly (DailyMembershipUtil accesses Environment_Settings__mdt)
External Services¶
- None
Design Patterns¶
- Batch Apex Pattern: Processes large Account datasets in manageable chunks
- Separation of Concerns: Account sync separated from Membership status updates
- Deduplication Map: Uses toUpdateAcc map to merge multiple updates per account
- Priority Selection: Memberships starting today prioritized over general active memberships
- Partial Success DML: Allows batch to continue after individual record failures
Governor Limits Considerations¶
SOQL Queries: 3 queries per batch chunk (AANP memberships, Fellow memberships, Start Today memberships) DML Operations: 1 DML statement per batch chunk (Account updates via safeUpdate) CPU Time: Moderate - membership field calculations and map operations Heap Size: Moderate - Account and Membership data stored in maps
Bulkification: Yes - processes up to 200 accounts per chunk with single DML Async Processing: Yes - runs as scheduled batch job, typically daily
Error Handling¶
Strategy: Partial-success DML via DailyMembershipUtil.safeUpdate() Logging: Failed account updates logged to Flow_Error_Log__c with context "DailyMembershipAccountsBatch apexClass" User Notifications: No direct notifications - monitoring via batch job status and error logs
Security Considerations¶
Sharing Rules: Respects sharing via "with sharing" declaration Field-Level Security: No FLS checks - batch typically runs as system user with appropriate permissions CRUD Permissions: No explicit CRUD checks - assumes scheduler user has required permissions Input Validation: Null checks on membership records before field access
Test Class¶
Test Class: DailyMembershipAccountsBatchTest.cls (to be created) Coverage: [To be verified] Test Scenarios Covered: - Account field sync from active AANP membership - Fellow field sync from active Fellow membership - Initial Join Date preservation for existing members - Continuity date reset after expiration - Continuity date preservation for active members - Corporate Council member flag (lifetime status) - Grace period member flag (30-day grace) - Expired member flag (past grace period) - Start today membership priority - Empty scope handling - Multiple memberships selection (latest end date)
Changes & History¶
- Initial Implementation: DailyMembershipAccountsBatch created to sync membership data to Account records
- 2025-10-22: Documentation updated to template format
⚠️ Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- Empty accountIds Bug (Line 18): Creates empty Map then extracts keySet, resulting in always-empty Set. Should be
new Map<Id,Account>(accounts).keySet(). Impact: Accounts with memberships starting today never processed.
HIGH - Address Soon After Go-Live¶
- No Is_a_Fellow Flag Update: Code queries Fellow memberships but never updates Is_a_Fellow__c field on Account
- Hardcoded 30-Day Grace Period: Line 88 hardcodes 30-day grace period instead of using configurable method
- No Field Clearing Logic: If all memberships expire, Account fields retain old values instead of being cleared
MEDIUM - Future Enhancement¶
- Multiple Queries Per Chunk: Executes 3 separate queries per batch chunk - could be optimized into single query
- Complex Ternary Logic: Lines 61-63 use deeply nested ternary operators that are hard to read
LOW - Monitor¶
- No LIMIT on Query Scope: Could process millions of accounts if memberships expire in bulk
- OR Logic in Query: Three OR branches in WHERE clause may prevent optimal index usage
Maintenance Notes¶
Complexity: Medium-High Recommended Review Schedule: Quarterly (active batch job) Key Maintainer Notes: - Fix the critical accountIds bug before next release - this breaks "start today" membership processing - Batch is chained from DailyMembershipStatusBatch and typically runs daily via DailyMembershipScheduler - Uses partial-success DML to prevent entire batch failure - monitor Flow_Error_Log__c for individual failures - 30-day grace period for Is_Member flag should be configurable via metadata instead of hardcoded - When modifying membership field logic, ensure Account triggers and flows are compatible - Consider adding Is_a_Fellow__c update when Fellow membership is synced - Monitor batch job via AsyncApexJob for completion status and error counts