---
schema_version: "1"
id: 4056bed4a16645a112d93ec1cf9e154013b1b78af444bec0eb0cd1fb58a2f037
title: Automated Voucher Expiration
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/xcloud/264-0-0/loyalty_vouchers_expiration.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.loyalty_vouchers_expiration.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 863213633adc107e5dd81523b37beeb07f39cbb174e172d084a0346644e05b7a
description: 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.
products:
  - Loyalty Management
release: "264"
---
# 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

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small edition"><colgroup><col></colgroup><tbody><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: Lightning Experience</td></tr><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: <strong>Enterprise</strong>,&nbsp;<strong>Performance</strong>, <strong>Unlimited</strong>, and&nbsp;<strong>Developer</strong>&nbsp;Editions with Loyalty Management</td></tr></tbody></table>

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](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-loyalty_management-264-0-0-production-enus/0590ce3e-5a09-45ab-8e5e-68f359c35886/images/icon_tip.png)

Tip To expire a larger volume of vouchers hourly, customize the batch Apex job.