---
schema_version: "1"
id: 1bad0df9fc8fd472e042071e83d3c2d949197bde8cca2c268a4a28fc372434c2
title: Restrict Working Hours Selectively
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/platform/264-0-0/ls_restrict_working_hours_selectively.md
canonical_url: https://help.salesforce.com/s/articleView?id=platform.ls_restrict_working_hours_selectively.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 514ddd930fe558dbc923eb743a3afa2e9cd04c391f1ae039b232f93ae501dbd3
description: If you enable the Use service territory’s operating hours with shifts scheduling policy, Salesforce Scheduler uses the intersection of shifts and service territory operating hours to determine the availability of all service resources. However, if you want to restrict working hours to service territory operating hours only for a few service resources, use triggers.
products:
  - Scheduler
  - Salesforce Platform
release: "264"
---
# Restrict Working Hours Selectively

If you enable the Use service territory’s operating hours with shifts scheduling policy, Salesforce Scheduler uses the intersection of shifts and service territory operating hours to determine the availability of all service resources. However, if you want to restrict working hours to service territory operating hours only for a few service resources, use triggers.

### 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> and <strong>Unlimited</strong> Editions</td></tr></tbody></table>

First, create a custom boolean field, OvertimeEnabled, to specify the resources that can work beyond the service territory operating hours. Next, change scheduling policies so that only shifts of service territory members are used to determine the availability of service resources for appointments. Then, create an Apex trigger on the Shift object that runs before a Shift is created and updated. The trigger validates shift timings and ensures that shift timings are within service territory operating hours for resources whose OvertimeEnabled field value is false.

1. From the object management settings for Service Resource, go to Fields & Relationships.
2. Click **New**.
3. Select **Checkbox**, and then click **Next**.
4. In the Field Label field, enter OvertimeEnabled, and then click **Next**.
5. Set up field-level security and provide access to the necessary profiles, and then click **Next**.
6. Save your changes.
7. From Setup, in the Quick Find box, enter Scheduling Policies, and then select **Scheduling Policies**.
8. Select **Use service territory member’s shift scheduling policy**, and then deselect **Use service territory’s operating hours with shifts scheduling policy**.
9. From the object management settings for shift, go to Triggers.
10. Click **New**.
11. Replace the default code with this code.
    
    ```
    trigger ShiftValidation on Shift (before insert, before update) {
        List<Shift> shifts = Trigger.new;
    
        Set<String> sr = new Set<String>();
        for(Shift shift: shifts) {
            sr.add(shift.ServiceResourceId);
        }
        
        List<ServiceResource> extendedSr = [SELECT Id FROM ServiceResource WHERE  OvertimeEnabled__c = False AND Id IN :sr];
        
        Set<String> srIds = new Set<String>();
        for(ServiceResource sr1: extendedSr) {
            srIds.add(sr1.Id);
        }
        
        Set<Shift> confirmedShifts = new Set<Shift>();
        Set<String> territoryIds = new Set<String>();
        //We will only run this validation for Shifts with Status Category = "Confirmed" AND Service Resource can work extended hours
        for(Shift shift: shifts) {
            if(shift.StatusCategory == 'Confirmed' && srIds.contains(shift.ServiceResourceId)) {
                confirmedShifts.add(shift);
                territoryIds.add(shift.ServiceTerritoryId);
            }
        }
    
        if(confirmedShifts.size() > 0) {
            //Get all Service Territory IDs along with their OperatingHourId
            ServiceTerritory[] territoryIdsWithOperatingHours = [SELECT Id, OperatingHoursId FROM ServiceTerritory WHERE Id IN :territoryIds];
    
            Set<String> operatingHourIds = new Set<String>();
            for(ServiceTerritory st: territoryIdsWithOperatingHours) {
                //Service Territory may not have Operating Hour defined
                if(st.OperatingHoursId != null) {
                    operatingHourIds.add(st.OperatingHoursId);
                }
            }
    
            //Get Timeslot information for all Operating Hours got in previous step. We disregard all STM level concurrent timeslots (Shifts with MaxAppointments set to 1)
            TimeSlot[] timeSlots = [SELECT Id, DayOfWeek, StartTime, EndTime, OperatingHoursId FROM TimeSlot WHERE MaxAppointments = 1 AND OperatingHoursId IN :operatingHourIds];
    
            //Complex data structure to store Working hours for all Service territories. We will store empty inner map in case Service Territory does not have Operating Hour defined
            Map<String, Map<String, TimeSlot>> serviceTerritoryWithTimeSlotsPerDay = new Map<String, Map<String, TimeSlot>>();
    
            for(ServiceTerritory territory: territoryIdsWithOperatingHours) {
                Map<String, TimeSlot> timeSlotsPerDay = new Map<String, TimeSlot>();
    
                for(TimeSlot timeSlot: timeSlots) {
                    if(timeslot.OperatingHoursId == territory.OperatingHoursId) {
                        timeSlotsPerDay.put(TimeSlot.DayOfWeek.substring(0,3), TimeSlot);
                    }
                }
                serviceTerritoryWithTimeSlotsPerDay.put(territory.Id, timeSlotsPerDay);
            }
    
            //Main validation logic for all confirmed shifts
            for(Shift s: confirmedShifts) {
                String dayOfShiftStart = ((Datetime) s.StartTime).format('E').substring(0,3);
                String dayOfShiftEnd = ((Datetime) s.EndTime).format('E').substring(0,3);
    
                Map<String, TimeSlot> slots = serviceTerritoryWithTimeSlotsPerDay.get(s.ServiceTerritoryId);
    
                if(dayOfShiftStart != dayOfShiftEnd) {
                    s.addError('Shift should be within Service Territory\'s Operating hours ');
                } else if(slots.get(dayOfShiftStart) == null || slots.get(dayOfShiftEnd) == null) {
                    s.addError('Operating Hours for Service Territory not set up correctly');
                }else if(s.StartTime.time() < slots.get(dayOfShiftStart).StartTime || s.EndTime.time() > slots.get(dayOfShiftEnd).EndTime) {
                    s.addError('Shift should be within Service Territory\'s Operating hours ');
                }
            }
        }
    }
    ```
12. Save your changes.