GlobalHeaderObjectService - UpdateStartDate Method
Overview
The GlobalHeaderObjectService provides a comprehensive set of global methods for updating Quote start dates directly. This service automatically recalculates end dates and updates all associated line items when the start date is changed.
Key Features:
- Automatically recalculates Quote end dates based on subscription terms
- Updates all associated QuoteLineItem start and end dates
- Integrates with the pricing engine for accurate date calculations
- Supports both single and bulk operations
- Includes validation and error handling
Method 1: Simple Quote Start Date Update
Use Case: Update a single Quote's start date when you have the Quote ID and new date.
Example Code
// Initialize the service
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Get your Quote ID (example)
Id quoteId = '0Q0XX0000000001'; // Replace with actual Quote ID
// Set the new start date
Date newStartDate = Date.newInstance(2024, 1, 15); // January 15, 2024
// Update the Quote start date
service.updateStartDate(quoteId, newStartDate);
System.debug('Quote start date updated successfully!');What Happens Behind the Scenes
- The service queries the Quote and all its QuoteLineItems
- Sends the data to the Ruby pricing engine for recalculation
- Updates the Quote's SubscriptionStartDate__c and SubscriptionEndDate__c
- Updates all QuoteLineItem SubscriptionStartDate__c and SubscriptionEndDate__c fields
- Saves all changes to the database
Quick Example: Update Quote Start Date to Today
Use Case: Set a Quote's start date to the current date - commonly used for immediate activation or "start now" scenarios.
// Initialize the service
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Get your Quote ID
Id quoteId = '0Q0XX0000000001'; // Replace with actual Quote ID
// Update Quote to start today
service.updateStartDate(quoteId, Date.today());
System.debug('Quote start date set to today: ' + Date.today());Alternative using System.today():
// Both Date.today() and System.today() work the same way
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
service.updateStartDate(quoteId, System.today());Common Scenario - Start Quote Immediately After Approval:
public static void startQuoteImmediately(Id quoteId) {
try {
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Set start date to today
service.updateStartDate(quoteId, Date.today());
System.debug('Quote ' + quoteId + ' is now active starting today!');
} catch (Exception e) {
System.debug('Failed to activate Quote: ' + e.getMessage());
throw e;
}
}Method 2: Bulk Quote Start Date Updates
Use Case: Update multiple Quotes' start dates in a single operation for better performance.
Example Code
// Initialize the service
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Create update requests for multiple Quotes
List<GlobalHeaderObjectStartDateUpdate> updateRequests = new List<GlobalHeaderObjectStartDateUpdate>();
// Add first Quote update
updateRequests.add(new GlobalHeaderObjectStartDateUpdate(
'0Q0XX0000000001', // Quote ID
Date.newInstance(2024, 2, 1) // New start date: February 1, 2024
));
// Add second Quote update
updateRequests.add(new GlobalHeaderObjectStartDateUpdate(
'0Q0XX0000000002', // Quote ID
Date.newInstance(2024, 2, 15) // New start date: February 15, 2024
));
// Add third Quote update
updateRequests.add(new GlobalHeaderObjectStartDateUpdate(
'0Q0XX0000000003', // Quote ID
Date.newInstance(2024, 3, 1) // New start date: March 1, 2024
));
// Execute bulk update
service.updateStartDate(updateRequests);
System.debug('All Quotes updated successfully!');Performance Benefits
- Single database transaction for all updates
- Reduced API calls to the pricing engine
- Better governor limit management
- Improved performance for large-scale operations
Method 3: Quote Start Date Update with Old Date Validation
Use Case: Update Quote start date with validation against the current start date to ensure data integrity.
Example Code
// Initialize the service
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Query the Quote to get current start date
Quote currentQuote = [SELECT Id, nue__SubscriptionStartDate__c
FROM Quote
WHERE Id = '0Q0XX0000000001'];
// Create update request with old date validation
GlobalStartDateUpdateWithOldStartDate updateRequest =
new GlobalStartDateUpdateWithOldStartDate(
currentQuote.Id, // Quote ID
currentQuote.nue__SubscriptionStartDate__c, // Current start date
Date.newInstance(2024, 4, 1) // New start date: April 1, 2024
);
// Execute update with validation
service.updateStartDate(updateRequest);
System.debug('Quote start date updated with validation!');When to Use This Method
- When you need to ensure the Quote hasn't been modified by another process
- For critical business operations requiring data integrity validation
- When implementing optimistic locking patterns
- In multi-user environments to prevent conflicts
Method 4: Advanced Quote Update with Object Manipulation
Use Case: Update Quote start date when you already have Quote and QuoteLineItem objects in memory and want to manipulate them directly.
Example Code
// Initialize the service
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Query Quote and its line items
Quote quoteToUpdate = [SELECT Id, nue__SubscriptionStartDate__c, nue__SubscriptionEndDate__c
FROM Quote
WHERE Id = '0Q0XX0000000001'];
List<QuoteLineItem> lineItemsToUpdate = [SELECT Id, nue__SubscriptionStartDate__c, nue__SubscriptionEndDate__c,
QuoteId, Product2Id, Quantity
FROM QuoteLineItem
WHERE QuoteId = :quoteToUpdate.Id];
// Create update request with objects
List<GlobalStartDateUpdateWithObjects> updateRequests =
new List<GlobalStartDateUpdateWithObjects>();
updateRequests.add(new GlobalStartDateUpdateWithObjects(
quoteToUpdate, // Quote object
lineItemsToUpdate, // List of QuoteLineItem objects
Date.newInstance(2024, 5, 1) // New start date: May 1, 2024
));
// Execute update with object manipulation
service.updateStartDate(updateRequests);
// After this call, your quoteToUpdate and lineItemsToUpdate objects
// will be populated with the new calculated dates from the pricing engine
System.debug('Quote object start date: ' + quoteToUpdate.nue__SubscriptionStartDate__c);
System.debug('Quote object end date: ' + quoteToUpdate.nue__SubscriptionEndDate__c);
for (QuoteLineItem lineItem : lineItemsToUpdate) {
System.debug('Line item ' + lineItem.Id + ' start date: ' + lineItem.nue__SubscriptionStartDate__c);
System.debug('Line item ' + lineItem.Id + ' end date: ' + lineItem.nue__SubscriptionEndDate__c);
}Benefits of This Method
- No additional database queries after the update
- Direct manipulation of objects already in memory
- Useful for complex business logic that operates on the updated objects
- More efficient when you need to work with the updated data immediately
Error Handling Examples
Example 1: Handling Null Parameters
try {
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// This will throw an IllegalArgumentException
service.updateStartDate(null, Date.today());
} catch (IllegalArgumentException e) {
System.debug('Error: ' + e.getMessage());
// Handle the error gracefully
}Example 2: Handling Invalid Quote IDs
try {
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
// Using a non-existent Quote ID
Id invalidQuoteId = '0Q0XX0000000999';
service.updateStartDate(invalidQuoteId, Date.today());
} catch (QueryException e) {
System.debug('Quote not found: ' + e.getMessage());
// Handle missing Quote scenario
}Example 3: Comprehensive Error Handling
public static void updateQuoteStartDateSafely(Id quoteId, Date newStartDate) {
try {
// Validate inputs
if (quoteId == null) {
throw new IllegalArgumentException('Quote ID cannot be null');
}
if (newStartDate == null) {
throw new IllegalArgumentException('New start date cannot be null');
}
// Check if Quote exists and is editable
List<Quote> quotes = [SELECT Id, nue__SubscriptionStartDate__c,
IsSyncing, Status__c
FROM Quote
WHERE Id = :quoteId
LIMIT 1];
if (quotes.isEmpty()) {
throw new IllegalArgumentException('Quote not found with ID: ' + quoteId);
}
Quote quote = quotes[0];
// Business validation
if (quote.IsSyncing) {
throw new IllegalArgumentException('Cannot update Quote while it is syncing');
}
// Execute the update
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
service.updateStartDate(quoteId, newStartDate);
System.debug('Quote start date updated successfully from ' +
quote.nue__SubscriptionStartDate__c + ' to ' + newStartDate);
} catch (Exception e) {
System.debug('Failed to update Quote start date: ' + e.getMessage());
// Log error, send notification, etc.
throw e; // Re-throw if needed
}
}Common Use Cases
1. Project Delay Handling
When a project is delayed, update all related Quotes to reflect new start dates:
// Get all Quotes for a specific opportunity
List<Quote> quotesToUpdate = [SELECT Id FROM Quote WHERE OpportunityId = :opportunityId];
List<GlobalHeaderObjectStartDateUpdate> updates = new List<GlobalHeaderObjectStartDateUpdate>();
Date delayedStartDate = Date.today().addDays(30); // 30-day delay
for (Quote q : quotesToUpdate) {
updates.add(new GlobalHeaderObjectStartDateUpdate(q.Id, delayedStartDate));
}
new GlobalHeaderObjectService().updateStartDate(updates);2. Fiscal Year Alignment
Align Quote start dates to the beginning of fiscal periods:
Date fiscalYearStart = Date.newInstance(2024, 4, 1); // April 1, 2024
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
service.updateStartDate(quoteId, fiscalYearStart);3. Contract Renewal Preparation
Update Quote start dates for contract renewals:
// Set renewal to start when current contract ends
Date renewalStartDate = currentContractEndDate.addDays(1);
GlobalHeaderObjectService service = new GlobalHeaderObjectService();
service.updateStartDate(renewalQuoteId, renewalStartDate);Troubleshooting
Common Issues and Solutions
Issue | Cause | Solution |
|---|---|---|
IllegalArgumentException: StartDateUpdateWithOldStartDate cannot be null | Null parameter passed | Always validate parameters before calling methods |
QueryException: List has no rows for assignment | Quote ID doesn't exist | Verify Quote exists before updating |
RubyException: Cannot find the header object with pricing engine calculation result | Pricing engine communication issue | Check org settings and try again |
System.LimitException: Too many DML statements | Too many individual updates | Use bulk update methods instead |
Debug Tips
- Enable Debug Logs for the GlobalHeaderObjectService class
- Check Quote Status - ensure Quote is not locked or in an invalid state
- Verify Pricing Engine connectivity in your org
- Test with Small Datasets first before bulk operations