AI-based Scheduling


Attention: AI-based optimization and scheduling only works for internal technicians. Crowd is currently not supported.

Looking to optimize your field service according to your specific requirements? Want to minimize driving distances so that your technicians can hit more jobs per day?

SAP Field Service Management offers a flexible framework for automated planning and optimization that caters to the individual requirements and use cases of each customer.

The framework accepts plugins to contain individually tailored target functions that rate how well a technician is suitable for a job. The target functions can be written by the customers themselves.

This enables the customers to programmatically reflect all criteria that are relevant for planning and optimization of the field service activities, such as:

  • Distance between the current location of the technician and the planned job
  • the next available timeslot
  • if a technician is familiar with the customer and their equipment, etc.

It is up to the customer to consider multiple factors and weigh them out against each other (as soft vs. hard constraints) in the target function.

Not sure how to start and want to try out an out-of-the-box solution? Use our standard plugins to optimize the following:

  • by distance to the job (nearest)
  • find the first available technician (fastest)
  • or the one with the most adequate skill set (best).

Note: As of today, plugins shall be deployed individually for every customer.

A Closer Look

Typically, there are three common cases addressed by automation:

  1. Scheduling of a job upon creation
  2. Periodic re-optimization of the entire board
  3. Rescheduling of overlapping jobs and reservations, e.g. urgent jobs, sick leaves, etc.

Within SAP Field Service Management, automatic scheduling can be triggered by a business rule. It can as well be triggered externally, e.g. via an external service or lambda function (additional provisioning shall reside with the customer). To trigger scheduling and optimization externally, refer to Re-Optimization API.

Business Rules

Within the business rule, the following shall be specified:

  • Trigger – specifies when scheduling/optimization shall be executed
  • SQL statement – specifies which data (jobs and technicians) shall be affected
  • Partitioning strategy – specifies the parameters by which jobs and technicians is being divided into logical units to run scheduling and optimization for the unit. Learn more here.
  • Plugin to be used – specifies which of the available plugins shall be used for scheduling.

The business rules shall have to be configured per company:

Configure the trigger of the business rule to schedule either periodic or event-based optimization.

Configure following actions:

  • first, for getting an authorization token
  • second, to define the list of activities to be reoptimized, partitioning strategy, and the plugin to be used

For Action #0,

  • select Action Webhook
  • select Method POST
  • maintain URL according to the following pattern: https://<cluster><api>/oauth2/<v>/token
  • maintain Content type:/x-www-form-urlencoded
  • maintain Body according to the following pattern: grant_type=client_credentials
  • maintain Response Variable Name: accessToken

For Action #1:

  • select Action Webhook
  • select Method POST
  • maintain URL: https://<cluster>
  • maintain Content type: application/json
  • maintain Body according to the following pattern:

{ "activityIds": [<comma separated list of activity IDs, as strings>], "optimizationPlugin": "<name of the default plugin from the ones deployed for the company>", "start": "${moment().add(1, 'hour').toISOString()}", "end": "<end of the time span to be reoptimized - use the pattern for the start>", "partitioningStrategy": { "name": "<parameter for the partitioning strategy if needed>", "<parameter name>": [ "<instance 1 name>", "<instance 2 name>" ] } }

  • maintain Response Variable Name: reOptimizeResponse

Note: for multiple use cases (i.e. automated scheduling upon job creation, periodic rescheduling, rescheduling of overlapping jobs), multiple business rules will need to be configured.


Once there is a new event that triggers a business rule, scheduling and optimization is started according to the parameters specified in the selected plugin. There are three standard plugins that can be utilized by the customers.

Rank by Earliest Start

The difference between a constant and the difference between proposed start and job earliest start is returned. A quotient could also be used, the difference being used for readability. The assignments which start earlier will be returned on top of the list.

Name: Quickest

public Integer score(IResource resource, IJob job, IAssignment assignment, ILocation location) {
     return 1000 - (int)(
         (assignment.getStartDate().getTime() - job.getEarliestStartDate().getTime()) / (1000 * 60));

Rank by Distance to the Next Assignment

The difference between a constant and the distance is returned, as a measure of proximity. A quotient could also be used, the difference being used for readability.

Name: Nearest

public Integer score(IResource resource, IJob job, IAssignment assignment, ILocation location) {
    if(location == null || job.getLocation() == null) {
        return -1;
    return (1000 - OptimizerLibrary.travelTimeEuclideanInMinutes(job.getLocation(), location));

Rank by Overlapping Skills

Counts the sizeof the set containing the skills both in the job and resource.

Name: Best

public Integer score(IResource resource, IJob job, IAssignment assignment, ILocation location) {
       List<String> resourceSkills = resource.getSkills();
       List<String> jobRequirements = job.getRequirements();
       List<String> matchingSkills = -> resourceSkills.contains(elem)).collect(Collectors.toList());
       return matchingSkills.size();

Customers are free to define their own plugins to address their specific use cases (multiple parameters can be considered within the plugin).

Note: customers shall be guided through definition of a their custom plugins. The plugins shall be deployed for every customer individually.


For a lot of businesses, field service activities are executed according to divisions within a company, e.g. based on work centers, regions, etc. Thus, optimizing the planning board on a company level is insufficient. To address those requirements, partitioning strategy can be defined (for detailed instructions, see <configuration of the BR - link>).

When partitioning strategy is maintained, optimization process shall be triggered per partition. That means, jobs belonging to the same partition shall be optimized together. Different partitions shall be optimized in parallel (currently, only sequential optimization is supported).

As of 1911, partitioning can be done based on skills. In order for partitioning to work, relevant skills have to be maintained on jobs and technicians as well as specified in the body of the business rule in the partitioning strategy section:

	"activityIds": ["${var x=[]; activities.forEach(function(a) { x.push(; }); x.join('\",\"')}"],
	"optimizationPlugin": "Nearest",
	"start": "${moment().add(1, 'hour').toISOString()}",
	"end":  "<end of the time span to be reoptimized - use the pattern for the start>",
	"partitioningStrategy": {
		"name": "Skill",
		"skills": [
			"skill name 2",
			"skill name 1"

UDFs in plugins

When writing a custom plugin for optimization of planning board, you can consider User Defined Fields introduced to your master data. As of 1911, User Defined Fields are supported for ServiceCall, Activity, Person, and Skill entities.

This way, optimization can be run based on ANY parameter that is relevant for your specific use case. For example, to consider technicians’ ratings, a dedicated UDF will have to be added to the technician. The field would have to be addressed in the plugin, for example as follows:

import java.util.List;
import java.util.ArrayList;
import net.coresystems.autoscheduler.domain.interfaces.*;
import net.coresystems.autoscheduler.service.spatial.EuclideanDistanceService;
import net.coresystems.autoscheduler.service.optimize.OptimizerLibrary;

public class Plugin implements IOptimizationPlugin {
    public net.coresystems.autoscheduler.domain.Algorithm getAlgorithm() {
        return net.coresystems.autoscheduler.domain.Algorithm.GREEDY_RESOURCES_FIRST;

    public List<IResource> filterResources(List<IResource> resources) {
        return new ArrayList();

    public Integer score(IResource resource, IJob job, IAssignment assignment, ILocation location) {

        Integer resourceRating = resource.getUDFValue("RATING") != null ? Integer.valueOf(resource.getUDFValue("RATING")): null;
        if (resourceRating == null) {
           return 0;

        return resourceRating;

Additional Information

For additional information regarding the Re-Optimization API documentation. please refer to the following:

Re-Optimization API