Skip to content

Class Name: I2C_AutoRenewalPriceSyncBatch

Last Updated: 2025-10-22 Source Code: I2C_AutoRenewalPriceSyncBatch.cls

API Name: I2C_AutoRenewalPriceSyncBatch Type: Batch (Database.Batchable, Database.AllowsCallouts) Test Coverage: Not specified

Business Purpose

This critical batch job automatically updates pricing for all recurring payment orders due today, ensuring that price changes for membership dues and other recurring products are reflected in Chargent recurring billing. The class maintains pricing accuracy for AANP's subscription-based revenue streams by recalculating Fellow dues based on designation types and applying current promotions before payment processing.

Class Overview

Scope and Sharing

  • Sharing Model: with sharing
  • Access Modifier: public
  • Interfaces Implemented: Database.Batchable, Database.AllowsCallouts

Key Responsibilities

  • Identifies Chargent recurring orders scheduled for payment today
  • Recalculates current pricing using Salesforce Commerce pricing engine
  • Applies special Fellow dues pricing based on member designation (Regular, Lifetime, Retired, Other)
  • Updates charge amounts with current promotions and discounts
  • Chains to Chargent's batch processing for payment execution
  • Maintains promotion history to ensure only previously applied promotions are considered

Public Methods

start

public List<ChargentOrders__ChargentOrder__c> start(Database.BatchableContext bc)

Purpose: Queries and returns all recurring Chargent orders scheduled for payment today.

Parameters: - bc (Database.BatchableContext): Standard batch context provided by platform

Returns: - List<ChargentOrders__ChargentOrder__c>: All recurring orders with payment scheduled for today, including related order products and promotion adjustments

Throws: - No explicit exception handling

Usage Example:

I2C_AutoRenewalPriceSyncBatch batch = new I2C_AutoRenewalPriceSyncBatch();
Database.executeBatch(batch);

Business Logic: - Queries ChargentOrders where Payment_Status = 'Recurring' and Next_Scheduled_Payment = TODAY - Includes subquery for related order items and their adjustment line items - Returns full dataset for execute method processing


execute

public void execute(Database.BatchableContext bc, List<ChargentOrders__ChargentOrder__c> scope)

Purpose: Recalculates pricing for each Chargent order in the batch scope and updates charge amounts.

Parameters: - bc (Database.BatchableContext): Standard batch context - scope (List): Batch of recurring orders to process

Returns: - void: No return value

Throws: - No explicit exception handling

Business Logic: 1. Builds map of order-to-promotion relationships from existing order item adjustments 2. Queries active promotion targets for all products in the batch 3. For each order: - Builds pricing input with all order line items - Calls Commerce API to get current pricing (or uses test mock) - For Fellow Dues products, applies custom pricing via calculateFellowDues() - Applies percentage and fixed discounts from promotion targets - Only applies promotions previously used on the order 4. Updates Chargent order charge amounts in bulk


finish

public void finish(Database.BatchableContext bc)

Purpose: Chains to Chargent's batch processing system after pricing synchronization completes.

Parameters: - bc (Database.BatchableContext): Standard batch context

Returns: - void: No return value

Throws: - No explicit exception handling

Business Logic: - Instantiates ChargentOrders.TChargentBatchProcessing - Executes with batch size of 10 to process payments


calculateFellowDues

public static Map<Id, Decimal> calculateFellowDues(Set<Id> productIds, Id accountId, String fellowDesignation)

Purpose: Calculates custom pricing for Fellow dues products based on member designation type.

Parameters: - productIds (Set): Product IDs requiring Fellow dues pricing - accountId (Id): Account being billed (not currently used) - fellowDesignation (String): Fellow designation type (Regular, Lifetime, Retired, or Other)

Returns: - Map<Id, Decimal>: Map of product IDs to their calculated prices

Throws: - QueryException: If pricebook or product queries fail

Usage Example:

Set<Id> fellowProducts = new Set<Id>{prod1Id, prod2Id};
Map<Id, Decimal> prices = I2C_AutoRenewalPriceSyncBatch.calculateFellowDues(
    fellowProducts,
    accountId,
    'Regular'
);

Business Logic: - Maps Fellow designation to specific product SKU: - Regular → P-FELO-074 - Lifetime → P-FELO-083 - Retired → P-FELO-075 - Other → P-FELO-076 - Queries 'Fellows Fees' pricebook for the designated product - Returns unit price from pricebook entry for all product IDs in the set - Returns mock price of 100.00 in test context


Private/Helper Methods

No private helper methods beyond the public static calculateFellowDues method.


Dependencies

Apex Classes

  • I2C_GetProductPricesTest: Provides mock pricing results in test context
  • ChargentOrders.TChargentBatchProcessing: Chargent package batch for payment processing

Salesforce Objects

  • ChargentOrders__ChargentOrder__c: Chargent payment orders
  • Fields: Next_Scheduled_Payment__c, Payment_Status__c, Account__c, Account__r.Fellow_Designation__c, Charge_Amount__c
  • OrderItem: Order line items (via Recurring_Order_Products__r relationship)
  • Fields: Product2Id, Order.SalesStoreId, Product2.Family
  • OrderItemAdjustmentLineItem: Promotion adjustments
  • Fields: AdjustmentCauseId
  • PromotionTarget: Promotion configurations
  • Fields: AdjustmentType, AdjustmentPercent, AdjustmentAmount, TargetId, PromotionId
  • Product2: Product records
  • Fields: Family, StockKeepingUnit
  • Pricebook2: Fellows Fees pricebook
  • PricebookEntry: Fellow dues pricing entries

Custom Settings/Metadata

  • Fellows Fees pricebook (must exist with specific name)
  • Product SKUs: P-FELO-074, P-FELO-075, P-FELO-076, P-FELO-083

External Services

  • ConnectApi.CommerceStorePricing: Salesforce Commerce Cloud pricing engine
  • Chargent payment processing system

Design Patterns

  • Batch Processing Pattern: Implements Database.Batchable for large-scale async operations
  • Chain of Responsibility: Chains to Chargent batch in finish() method
  • Strategy Pattern: Different pricing strategies for regular products vs Fellow dues
  • Template Method: Uses calculateFellowDues as specialized pricing calculation
  • Test Seam Pattern: Uses Test.isRunningTest() to inject mock responses

Governor Limits Considerations

SOQL Queries: - 1 in start() for recurring orders - 1-2 in execute() for promotion targets (per batch) - 2 in calculateFellowDues() for pricebook/product lookups (per execute)

DML Operations: 1 update statement per execute() batch

CPU Time: Potentially high due to nested loops for promotion calculation

Heap Size: Depends on number of order items and promotions per order

Bulkification: Partially bulkified - collects orders for DML but processes pricing individually

Async Processing: Yes - batch processing with callouts enabled

API Callouts: 1 callout per order to Commerce pricing API (not bulkified)

Critical Concerns: - Commerce API callout per order not bulkified - could hit callout limits with large batches - calculateFellowDues queries inside execute() could approach SOQL limit - Nested loops for promotion application could cause CPU timeout with complex promotions

Error Handling

Strategy: Minimal error handling Logging: Debug statements only (System.debug) User Notifications: None

Implementation: - Checks pricingResults.success but only logs failure - Failed pricing results in no update for that order - No exception handling for SOQL queries - No exception handling for DML operations

Critical Gaps: - Failed pricing API calls could result in $0 charges or skipped orders - No alerting for batch failures - No retry mechanism for failed pricing calculations - Silent failures make troubleshooting difficult

Security Considerations

Sharing Rules: Respects sharing (with sharing keyword) Field-Level Security: Not enforced (direct SOQL and DML) CRUD Permissions: Not explicitly checked Input Validation: No validation of pricing results

Security Notes: - Runs in batch context with elevated permissions - Direct update of Chargent financial records without validation - No validation that calculated prices are reasonable - Hard-coded product SKUs could be security risk if products change

Test Class

Test Class: I2C_GetProductPricesTest (implied), specific test class not documented Coverage: Not specified Test Scenarios Covered: - Uses Test.isRunningTest() checks for mock responses - Mock pricing result from I2C_GetProductPricesTest.getMockPricingResult() - Mock Fellow dues pricing returns 100.00

Additional Test Scenarios Needed: - Recurring orders scheduled for today - Orders with multiple line items - Fellow designation pricing variations - Promotion discount calculations (percentage and fixed) - Failed pricing API responses - Chain to Chargent batch processing - Edge cases: $0 orders, negative amounts, missing promotions

Changes & History

No change history documented.

Pre-Go-Live Concerns

CRITICAL - Fix Before Go-Live

  • No error handling for pricing API failures - Failed pricing calls could result in $0 charges or batch termination
  • Hard-coded product SKUs - Fellow designation pricing relies on specific SKU values (P-FELO-074, etc.) that could break if products change
  • Missing bulk operation safeguards - No limits on batch size could cause heap size or timeout issues
  • API callouts not bulkified - One callout per order will hit limits with large batches
  • SOQL queries in execute() - calculateFellowDues queries inside execute could exceed governor limits

HIGH - Address Soon After Go-Live

  • Limited logging for pricing failures - Only debug statements for failed pricing calculations make troubleshooting difficult
  • No validation of calculated prices - Negative or extreme price values aren't validated before updating charge amounts
  • Test class dependencies - Mock pricing results may not reflect actual pricing complexity
  • No monitoring or alerting - Finance team not notified of pricing sync failures
  • Silent failure mode - Orders with failed pricing are silently skipped

MEDIUM - Future Enhancement

  • Fellow pricing logic should be externalized - Hard-coded designation mapping should be configurable via Custom Metadata
  • Promotion calculation complexity - Complex nested loops for promotion application could be optimized
  • Missing batch monitoring - No alerts or notifications for batch processing failures
  • Chargent batch size hardcoded - finish() method uses batch size of 10 without explanation
  • No price change audit trail - Should log old vs new prices for financial reconciliation

LOW - Monitor

  • Debug statements in production - System.debug calls should be removed or controlled by debug flags
  • Potential for data inconsistency - Gap between pricing calculation and Chargent processing could cause issues
  • Fellow designation values - Should validate allowed values for Fellow_Designation__c field
  • Test context detection - Multiple Test.isRunningTest() checks should be consolidated

Maintenance Notes

Complexity: High Recommended Review Schedule: Quarterly (before membership renewal periods)

Key Maintainer Notes: - This is a mission-critical batch job for recurring revenue - failures directly impact cash flow - Requires careful testing of pricing calculations and Chargent integration before any changes - The Fellow dues pricing logic is particularly complex and should be validated with finance team - Schedule review of product SKU dependencies quarterly to ensure they still exist - Monitor batch execution during high-volume renewal periods - Consider refactoring to bulkify Commerce API callouts if volume increases - The finish() method chains to Chargent processing - don't modify without understanding implications

Critical Dependencies: - Fellows Fees pricebook must exist with exact name - Product SKUs P-FELO-074, P-FELO-075, P-FELO-076, P-FELO-083 must exist - Commerce Cloud pricing engine must be configured - Chargent package and TChargentBatchProcessing must be available - Order.SalesStoreId must be populated with valid webstore ID

Financial Impact: - Direct impact on recurring revenue collection - Incorrect pricing could result in undercharging or overcharging members - Failed batch execution could delay payment processing - Should have manual review process for high-value transactions

Troubleshooting Guide: - Check System.debug logs for "Auto-renewal pricing could not be calculated" messages - Verify Fellows Fees pricebook exists and has active entries - Confirm product SKUs haven't changed - Review AsyncApexJob records for batch status - Check Chargent order audit logs for pricing updates