You are here:
Automated Voucher Expiration
The status of unredeemed or partially redeemed vouchers changes to Expired after the vouchers pass the expiration date. Loyalty Management automatically changes the status of up to 2 million vouchers to Expired hourly.
Required Editions
| Available in: Lightning Experience |
| Available in: Enterprise, Performance, Unlimited, and Developer Editions with Loyalty Management |
During a one hour period when more than 2 million vouchers must be expired, the status of only 2 million vouchers changes to Expired. The status of the remaining vouchers isn’t changed but these vouchers can’t be redeemed because the expiration date has passed. Developers in your organization can create a custom batch Apex job to change the status of vouchers whose status hasn’t changed to Expired automatically after their expiration date.
Use Batch Apex to Expire Vouchers
The batch Apex job to expire vouchers can be run either on demand or per a custom schedule. Here’s a sample batch Apex job to change the status of Voucher records that are past their expiration date to Expired:
global inherited sharing class ExpireVouchersBatchScheduler implements Schedulable,Database.Batchable<sObject>, Database.Stateful {
String expiredVoucherRecordsQuery;
public Integer vouchersToBeExpired = 0;
public Boolean hasInvalidAccessError = false;
String ERROR_INVALID_ACCESS = '\nERROR : The user does not have permission to update Voucher object and/or Status field of Voucher object';
global Database.QueryLocator start(Database.BatchableContext BC)
{
return Database.getQueryLocator(this.expiredVoucherRecordsQuery);
}
global void execute(Database.BatchableContext BC,
List<Voucher> expiredVoucherRecords)
{
vouchersToBeExpired += expiredVoucherRecords.size();
//Set 'Expired' Status all queried expired Vouchers
for (Voucher expiredVoucher : expiredVoucherRecords) {
System.debug(String.valueOf(expiredVoucher));
expiredVoucher.Status = 'Expired';
}
//Check for Accessibility && Also check whether object is updatetable or not
DescribeSObjectResult describeVoucherObject = Voucher.sObjectType.getDescribe();
DescribeFieldResult describeVoucherStatusField = Schema.SObjectType.Voucher.fields.Status;
if(describeVoucherObject.isUpdateable() && describeVoucherStatusField.isUpdateable()) {
update expiredVoucherRecords;
} else {
this.hasInvalidAccessError = true;
throw new VoucherExpirationBatchApexException(this.ERROR_INVALID_ACCESS);
}
}
global void finish(Database.BatchableContext BC)
{
// Query the AsyncApexJob object to retrieve the current job's information.
AsyncApexJob job = [ SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :BC.getJobId()
WITH USER_MODE];
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new List<String>{ job.CreatedBy.Email };
mail.setToAddresses(toAddresses);
mail.setSenderDisplayName('Voucher Expiration Batch Processing Status');
mail.setSubject('Voucher Expiration Apex Batch Process Completed');
String mailTextBody = 'Batch Process has completed.' +
'\nVouchers to be Expired : ' + vouchersToBeExpired +
'\nThe batch Apex job processed ' + job.TotalJobItems + ' batches with ' + job.NumberOfErrors + ' batch failures.';
if ( hasInvalidAccessError) { mailTextBody += this.ERROR_INVALID_ACCESS; }
mail.setPlainTextBody(mailTextBody);
Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{ mail });
}
global void execute(SchedulableContext sc) {
//Query for all Expired Voucher
this.expiredVoucherRecordsQuery =
'SELECT Id, Status, ExpirationDate ' +
'FROM Voucher ' +
'WHERE ExpirationDate < TODAY AND Status = \'Issued\' WITH USER_MODE';
//Parameters of ExecuteBatch(context,BatchSize)
Database.executeBatch(this);
}
//Custom Exception class to show execution errors of Apex Batch Scheduling for Voucher Expiration
private class VoucherExpirationBatchApexException extends Exception {}
}
