Loading
Loyalty Management
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Automated Voucher Expiration

          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: EnterprisePerformance, 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 {}
          }
          Tip
          Tip To expire a larger volume of vouchers hourly, customize the batch Apex job.
           
          Loading
          Salesforce Help | Article