Loading
Manage Appointments with Salesforce Scheduler
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
          Initialize Shift Work Topics with Capacity

          Initialize Shift Work Topics with Capacity

          Initialize capacity for shift work topics in your org.

          Required Editions

          Available in: Lightning Experience.
          Available in: Enterprise and Unlimited Editions
          User Permissions Needed
          Run the script:

          API Enabled

          AND

          View All Data

          AND

          Author Apex

          By default, after you enable capacity-based scheduling, the capacity of your shift work topics is set to 0. Use these scripts to populate values in your shift work topics so that your schedule works as it did before you enabled capacity-based scheduling. We recommend using these scripts if you have existing shift records that you want to quickly update to ensure business continuity. Alternatively, you can manually set the capacity for the shift work topics.

          1. Depending on the Scheduler for Health Cloud setting in your org, use one of these scripts.
            • Disabled
              //For Health Cloud Disabled
              global class InitialiseExistingSWTWithCapacity implements Database.Batchable<SObject> {
                global Database.QueryLocator start(Database.BatchableContext BC) {
                  return Database.getQueryLocator([SELECT Id, StartTime, EndTime FROM Shift]);
                }
              
                global void execute(Database.BatchableContext BC, List<SObject> scope) {
                  List<String> shiftIds = new List<String>();
              
                  for (Shift shift : (List<Shift>) scope) {
                    shiftIds.add(shift.Id);
                  }
              
                  // create maps to avoid queries in the loop
                  List<Shift> shiftInfo = [
                    SELECT ServiceTerritoryId, Id, StartTime, EndTime
                    FROM Shift
                    WHERE Id IN :shiftIds
                  ];
                  List<String> serviceTerriroryIds = new List<String>();
                  for (Shift shift : shiftInfo) {
                    serviceTerriroryIds.add(shift.ServiceTerritoryId);
                  }
              
                  Map<String, String> mapStToServiceAppointmentLimitType = new Map<String, String>();
                  List<ServiceTerritory> sts = [
                    SELECT ServiceAppointmentLimitType, Id
                    FROM ServiceTerritory
                    WHERE Id IN :serviceTerriroryIds
                  ];
                  for (ServiceTerritory st : sts) {
                    mapStToServiceAppointmentLimitType.put(
                      st.Id,
                      st.ServiceAppointmentLimitType
                    );
                  }
                  Map<String, String> mapShiftToServiceTerritory = new Map<String, String>();
                  Map<String, Decimal> mapShiftToDuration = new Map<String, Decimal>();
              
                  for (Shift shift : shiftInfo) {
                    mapShiftToServiceTerritory.put(shift.Id, shift.ServiceTerritoryId);
                    Decimal shiftDuration =
                      (shift.EndTime.getTime() - shift.StartTime.getTime()) / (1000 * 60);
                    mapShiftToDuration.put(shift.Id, shiftDuration);
                  }
                  Map<String, Decimal> mapWorkTypeToDuration = new Map<String, Decimal>();
              
                  List<WorkType> wts = [SELECT Id, DurationInMinutes FROM WorkType];
                  for (WorkType wt : wts) {
                    mapWorkTypeToDuration.put(wt.Id, wt.DurationInMinutes);
                  }
              
                  Map<String, List<String>> mapShiftToWorkTypeGroupList = new Map<String, List<String>>();
              
                  List<ShiftWorkTopic> shiftWorkTopics = [
                    SELECT Id, WorkTypeGroupId, ShiftId, MaxAppointments
                    FROM ShiftWorkTopic
                    WHERE ShiftId IN :shiftIds AND WorkTypeGroupId != NULL
                  ];
              
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    List<String> existingSWTList = mapShiftToWorkTypeGroupList.get(
                      swt.ShiftId
                    );
                    if (existingSWTList == null) {
                      existingSWTList = new List<String>{ (String) swt.WorkTypeGroupId };
                    } else {
                      existingSWTList.add(swt.WorkTypeGroupId);
                    }
                    mapShiftToWorkTypeGroupList.put(swt.ShiftId, existingSWTList);
                  }
              
                  Map<String, String> mapWorkTypeGroupToWorkType = new Map<String, String>();
                  List<WorkTypeGroupMember> wtgms = [
                    SELECT Id, WorkTypeGroupId, WorkTypeId
                    FROM WorkTypeGroupMember
                  ];
                  for (WorkTypeGroupMember wtgm : wtgms) {
                    mapWorkTypeGroupToWorkType.put(wtgm.WorkTypeGroupId, wtgm.WorkTypeId);
                  }
              
                  Map<String, List<ShiftWorkTopic>> mapShiftToSWTList = new Map<String, List<ShiftWorkTopic>>();
              
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    List<ShiftWorkTopic> existingSWTList = mapShiftToSWTList.get(swt.ShiftId);
                    if (existingSWTList == null) {
                      existingSWTList = new List<ShiftWorkTopic>{ swt };
                    } else {
                      existingSWTList.add(swt);
                    }
                    mapShiftToSWTList.put(swt.ShiftId, existingSWTList);
                  }
                  Map<String, Integer> mapSWTToConcurrency = new Map<String, Integer>();
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    if (swt.MaxAppointments != null) {
                      mapSWTToConcurrency.put(swt.Id, swt.MaxAppointments);
                    } else {
                      mapSWTToConcurrency.put(swt.Id, 1);
                    }
                  }
                  // main code starts here
              
                  for (String shiftId : shiftIds) {
                    String ServiceAppointmentLimitType = mapStToServiceAppointmentLimitType.get(
                      mapShiftToServiceTerritory.get(shiftId)
                    );
                    if (
                      ServiceAppointmentLimitType == 'Maximum Limit' ||
                      ServiceAppointmentLimitType == null
                    ) {
                      Double shiftDuration = mapShiftToDuration.get(shiftId);
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        Double workTypeDuration = mapWorkTypeToDuration.get(
                          mapWorkTypeGroupToWorkType.get((swt.WorkTypeGroupId))
                        );
                        Double concurrency = mapSWTToConcurrency.get(swt.Id);
                        swt.ServiceAppointmentLimit = ((shiftDuration / workTypeDuration)
                            .intValue() * concurrency)
                          .intValue();
                      }
                    } else if (ServiceAppointmentLimitType == 'Achievable Limit') {
                      List<ShiftWorkTopic> swtList = mapShiftToSWTList.get(shiftId);
                      if (swtList == null) {
                        // No SWT in this shift do no process
                        continue;
                      }
                      Integer maximumCapacity = 0;
                      Decimal shiftDuration = mapShiftToDuration.get(shiftId);
              
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        Integer concurrency = mapSWTToConcurrency.get(swt.Id);
                        Double workDuration = mapWorkTypeToDuration.get(
                          mapWorkTypeGroupToWorkType.get((swt.WorkTypeGroupId))
                        );
                        maximumCapacity = Math.max(
                          maximumCapacity,
                          (shiftDuration / workDuration).intValue() * concurrency
                        );
                      }
                      Integer finalCapacity = 0;
              
                      for (Integer cap = 0; cap <= maximumCapacity; cap++) {
                        Double sumLHS = 0;
              
                        for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                          Integer concurrency = mapSWTToConcurrency.get(swt.Id);
                          Double workDuration = mapWorkTypeToDuration.get(
                            mapWorkTypeGroupToWorkType.get((swt.WorkTypeGroupId))
                          );
                          sumLHS += Math.ceil((1.0 * cap) / concurrency) * workDuration;
                        }
                        if (sumLHS <= shiftDuration) {
                          finalCapacity = cap;
                        } else {
                          break;
                        }
                      }
              
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        swt.ServiceAppointmentLimit = finalCapacity;
                      }
                    }
                  }
                  update shiftWorkTopics;
                }
              
                global void finish(Database.BatchableContext BC) {
                  // Send notification or log the completion
                  System.debug('Batch job completed successfully.');
                }
              }
            • Enabled
              //For Health Cloud Enabled
              global class InitialiseExistingSWTWithCapacity implements Database.Batchable<SObject> {
                global Database.QueryLocator start(Database.BatchableContext BC) {
                  return Database.getQueryLocator([SELECT Id, StartTime, EndTime FROM Shift]);
                }
              
                global void execute(Database.BatchableContext BC, List<SObject> scope) {
                  List<String> shiftIds = new List<String>();
              
                  for (Shift shift : (List<Shift>) scope) {
                    shiftIds.add(shift.Id);
                  }
              
                  // create maps to avoid queries in the loop
                  List<Shift> shiftInfo = [
                    SELECT ServiceTerritoryId, Id, StartTime, EndTime
                    FROM Shift
                    WHERE Id IN :shiftIds
                  ];
                  List<String> serviceTerriroryIds = new List<String>();
                  for (Shift shift : shiftInfo) {
                    serviceTerriroryIds.add(shift.ServiceTerritoryId);
                  }
              
                  Map<String, String> mapSwtToServiceAppointmentLimitType = new Map<String, String>();
              
                  Map<String, String> mapStToServiceAppointmentLimitType = new Map<String, String>();
                  List<ServiceTerritory> sts = [
                    SELECT ServiceAppointmentLimitType, Id
                    FROM ServiceTerritory
                    WHERE Id IN :serviceTerriroryIds
                  ];
                  for (ServiceTerritory st : sts) {
                    mapStToServiceAppointmentLimitType.put(
                      st.Id,
                      st.ServiceAppointmentLimitType
                    );
                  }
                  Map<String, String> mapShiftToServiceTerritory = new Map<String, String>();
                  Map<String, Decimal> mapShiftToDuration = new Map<String, Decimal>();
              
                  for (Shift shift : shiftInfo) {
                    mapShiftToServiceTerritory.put(shift.Id, shift.ServiceTerritoryId);
                    Decimal shiftDuration =
                      (shift.EndTime.getTime() - shift.StartTime.getTime()) / (1000 * 60);
                    mapShiftToDuration.put(shift.Id, shiftDuration);
                  }
                  Map<String, Decimal> mapWorkTypeToDuration = new Map<String, Decimal>();
              
                  List<WorkType> wts = [SELECT Id, DurationInMinutes FROM WorkType];
                  for (WorkType wt : wts) {
                    mapWorkTypeToDuration.put(wt.Id, wt.DurationInMinutes);
                  }
              
                  Map<String, List<String>> mapShiftToWorkTypeGroupList = new Map<String, List<String>>();
              
                  List<ShiftWorkTopic> shiftWorkTopics = [
                    SELECT Id, WorkTypeId, ShiftId, MaxAppointments
                    FROM ShiftWorkTopic
                    WHERE ShiftId IN :shiftIds AND WorkTypeId != NULL
                  ];
              
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    List<String> existingSWTList = mapShiftToWorkTypeGroupList.get(
                      swt.ShiftId
                    );
                    if (existingSWTList == null) {
                      existingSWTList = new List<String>{ (String) swt.WorkTypeId };
                    } else {
                      existingSWTList.add(swt.WorkTypeId);
                    }
                    mapShiftToWorkTypeGroupList.put(swt.ShiftId, existingSWTList);
                  }
              
                  Map<String, List<ShiftWorkTopic>> mapShiftToSWTList = new Map<String, List<ShiftWorkTopic>>();
              
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    List<ShiftWorkTopic> existingSWTList = mapShiftToSWTList.get(swt.ShiftId);
                    if (existingSWTList == null) {
                      existingSWTList = new List<ShiftWorkTopic>{ swt };
                    } else {
                      existingSWTList.add(swt);
                    }
                    mapShiftToSWTList.put(swt.ShiftId, existingSWTList);
                  }
                  Map<String, Integer> mapSWTToConcurrency = new Map<String, Integer>();
                  for (ShiftWorkTopic swt : shiftWorkTopics) {
                    if (swt.MaxAppointments != null) {
                      mapSWTToConcurrency.put(swt.Id, swt.MaxAppointments);
                    } else {
                      mapSWTToConcurrency.put(swt.Id, 1);
                    }
                  }
              
                  // main code starts here
              
                  for (String shiftId : shiftIds) {
                    String ServiceAppointmentLimitType = mapStToServiceAppointmentLimitType.get(
                      mapShiftToServiceTerritory.get(shiftId)
                    );
                    if (
                      ServiceAppointmentLimitType == 'Maximum Limit' ||
                      ServiceAppointmentLimitType == null
                    ) {
                      if (mapShiftToSWTList.get(shiftId) == null) {
                        // No SWT in this shift do no process
                        continue;
                      }
                      Double shiftDuration = mapShiftToDuration.get(shiftId);
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        Double workTypeDuration = mapWorkTypeToDuration.get(swt.WorkTypeId);
                        Double concurrency = mapSWTToConcurrency.get(swt.Id);
                        swt.ServiceAppointmentLimit = ((shiftDuration / workTypeDuration)
                            .intValue() * concurrency)
                          .intValue();
                      }
                    } else if (ServiceAppointmentLimitType == 'Achievable Limit') {
                      List<ShiftWorkTopic> swtList = mapShiftToSWTList.get(shiftId);
                      if (swtList == null) {
                        // No SWT in this shift do no process
                        continue;
                      }
                      Integer maximumCapacity = 0;
                      Decimal shiftDuration = mapShiftToDuration.get(shiftId);
              
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        Integer concurrency = mapSWTToConcurrency.get(swt.Id);
                        Double workDuration = mapWorkTypeToDuration.get((swt.WorkTypeId));
                        maximumCapacity = Math.max(
                          maximumCapacity,
                          (shiftDuration / workDuration).intValue() * concurrency
                        );
                      }
                      Integer finalCapacity = 0;
              
                      for (Integer cap = 0; cap <= maximumCapacity; cap++) {
                        Double sumLHS = 0;
              
                        for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                          Integer concurrency = mapSWTToConcurrency.get(swt.Id);
                          Double workDuration = mapWorkTypeToDuration.get(swt.WorkTypeId);
                          sumLHS += Math.ceil((1.0 * cap) / concurrency) * workDuration;
                        }
                        if (sumLHS <= shiftDuration) {
                          finalCapacity = cap;
                        } else {
                          break;
                        }
                      }
              
                      for (ShiftWorkTopic swt : mapShiftToSWTList.get(shiftId)) {
                        swt.ServiceAppointmentLimit = finalCapacity;
                      }
                    }
                  }
              
                  update shiftWorkTopics;
                }
              
                global void finish(Database.BatchableContext BC) {
                  // Send notification or log the completion
                  System.debug('Batch job completed successfully.');
                }
              }
          2. Create an Apex Class called InitialiseExistingSWTWithCapacity to trigger approval workflows. See Define Apex Classes.
          3. From Setup, select Developer Console.
          4. In the Developer Console, click Debug, then click Open Execute Anonymous Window.
          5. Execute this code.
            InitialiseExistingSWTWithCapacity batchJob = new InitialiseExistingSWTWithCapacity(); 
            Integer batchSize = 200; 
            Database.executeBatch(batchJob, batchSize);
          6. To view the progress of the script, in Setup, find and select Apex Jobs.
           
          Loading
          Salesforce Help | Article