You are here:
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.
-
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.'); } }
- Disabled
- Create an Apex Class called InitialiseExistingSWTWithCapacity to trigger approval workflows. See Define Apex Classes.
- From Setup, select Developer Console.
- In the Developer Console, click Debug, then click Open Execute Anonymous Window.
- Execute this code.
- To view the progress of the script, in Setup, find and select Apex Jobs.
Did this article solve your issue?
Let us know so we can improve!

