Real-time planning: reassignment
There are many situations where Real-time planning is necessary.
When a visit takes longer than expected other visits might need to be rescheduled or even assigned to another technician.
Consider the following shift schedule:
Carl has three visits scheduled for the day: Visit E, Visit B, and Visit D.
Ann has two visits scheduled for the day: Visit C and Visit A.
However, Visit E takes much longer than expected.
As a result, Visit B and Visit D need to be rescheduled with Visit D being reassigned to Ann.
1. Batch schedule: reassignment
The original schedule was generated from the following input dataset during the regular batch scheduling:
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/field-service-routing/v1/route-plans [email protected]
{
"config": {
"run": {
"name": "Original shift plan: reassignment example"
}
},
"modelInput": {
"vehicles": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl-2027-02-01",
"startLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "Ann",
"shifts": [
{
"id": "Ann-2027-02-01",
"startLocation": [33.70474, -84.06508],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
}
],
"visits": [
{
"id": "Visit E",
"location": [33.84475, -84.63649],
"serviceDuration": "PT1H30M"
},
{
"id": "Visit B",
"location": [33.90719, -84.28149],
"serviceDuration": "PT1H30M"
},
{
"id": "Visit D",
"location": [33.89351, -84.00649],
"serviceDuration": "PT1H30M"
},
{
"id": "Visit A",
"location": [33.67590, -84.11845],
"serviceDuration": "PT1H30M"
},
{
"id": "Visit C",
"location": [33.71517, -84.08527],
"serviceDuration": "PT1H30M"
}
]
}
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
|
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/field-service-routing/v1/route-plans/<ID>
{
"run": {
"id": "ID",
"name": "Original shift plan: reassignment example",
"submitDateTime": "2024-10-30T08:37:32.691576435Z",
"startDateTime": "2024-10-30T08:37:38.554385237Z",
"activeDateTime": "2024-10-30T08:37:38.654385237Z",
"completeDateTime": "2024-10-30T08:42:39.308136355Z",
"shutdownDateTime": "2024-10-30T08:42:39.408136355Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-200626soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"vehicles": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl-2027-02-01",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Visit E",
"kind": "VISIT",
"arrivalTime": "2027-02-01T09:48:56Z",
"startServiceTime": "2027-02-01T09:48:56Z",
"departureTime": "2027-02-01T11:18:56Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT48M56S",
"travelDistanceMetersFromPreviousStandstill": 54141,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit B",
"kind": "VISIT",
"arrivalTime": "2027-02-01T11:59:29Z",
"startServiceTime": "2027-02-01T11:59:29Z",
"departureTime": "2027-02-01T13:29:29Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT40M33S",
"travelDistanceMetersFromPreviousStandstill": 42302,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit D",
"kind": "VISIT",
"arrivalTime": "2027-02-01T14:01:19Z",
"startServiceTime": "2027-02-01T14:01:19Z",
"departureTime": "2027-02-01T15:31:19Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT31M50S",
"travelDistanceMetersFromPreviousStandstill": 34289,
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
],
"metrics": {
"totalTravelTime": "PT2H39M10S",
"travelTimeFromStartLocationToFirstVisit": "PT48M56S",
"travelTimeBetweenVisits": "PT1H12M23S",
"travelTimeFromLastVisitToEndLocation": "PT37M51S",
"totalTravelDistanceMeters": 165337,
"travelDistanceFromStartLocationToFirstVisitMeters": 54141,
"travelDistanceBetweenVisitsMeters": 76591,
"travelDistanceFromLastVisitToEndLocationMeters": 34605,
"endLocationArrivalTime": "2027-02-01T16:09:10Z"
}
}
]
},
{
"id": "Ann",
"shifts": [
{
"id": "Ann-2027-02-01",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Visit C",
"kind": "VISIT",
"arrivalTime": "2027-02-01T09:09:55Z",
"startServiceTime": "2027-02-01T09:09:55Z",
"departureTime": "2027-02-01T10:39:55Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT9M55S",
"travelDistanceMetersFromPreviousStandstill": 6094,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit A",
"kind": "VISIT",
"arrivalTime": "2027-02-01T10:52:12Z",
"startServiceTime": "2027-02-01T10:52:12Z",
"departureTime": "2027-02-01T12:22:12Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT12M17S",
"travelDistanceMetersFromPreviousStandstill": 8841,
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
],
"metrics": {
"totalTravelTime": "PT32M50S",
"travelTimeFromStartLocationToFirstVisit": "PT9M55S",
"travelTimeBetweenVisits": "PT12M17S",
"travelTimeFromLastVisitToEndLocation": "PT10M38S",
"totalTravelDistanceMeters": 23769,
"travelDistanceFromStartLocationToFirstVisitMeters": 6094,
"travelDistanceBetweenVisitsMeters": 8841,
"travelDistanceFromLastVisitToEndLocationMeters": 8834,
"endLocationArrivalTime": "2027-02-01T12:32:50Z"
}
}
]
}
]
},
"kpis": {
"totalTravelTime": "PT3H12M",
"travelTimeFromStartLocationToFirstVisit": "PT58M51S",
"travelTimeBetweenVisits": "PT1H24M40S",
"travelTimeFromLastVisitToEndLocation": "PT48M29S",
"totalTravelDistanceMeters": 189106,
"travelDistanceFromStartLocationToFirstVisitMeters": 60235,
"travelDistanceBetweenVisitsMeters": 85432,
"travelDistanceFromLastVisitToEndLocationMeters": 43439,
"totalUnassignedVisits": 0
}
}
modelOutput
contains Carl’s and Ann’s shift itineraries.
2. Real-time planning update: reassignment
If the same scenario occurs, and Visit E takes much longer than expected, the input dataset needs to be modified and resubmitted.
Update the serviceDuration
for Visit E from 1 hour and 30 minutes to 4 hours.
Add the minStartTravelTime
from the most recent planning output dataset (batch or real-time) to each visit.
{
"visits": [
{
"id": "Visit E",
"location": [33.84475, -84.63649],
"serviceDuration": "PT4H",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit B",
"location": [33.90719, -84.28149],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit D",
"location": [33.89351, -84.00649],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit A",
"location": [33.67590, -84.11845],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit C",
"location": [33.71517, -84.08527],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
}
Add the itinerary to Carl’s and Beth’s shifts, including the visit IDs and the visit kind:
{
"vehicles": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl-2027-02-01",
"startLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z",
"itinerary": [
{
"id": "Visit E",
"kind": "VISIT"
},
{
"id": "Visit B",
"kind": "VISIT"
},
{
"id": "Visit D",
"kind": "VISIT"
}
]
}
]
},
{
"id": "Ann",
"shifts": [
{
"id": "Ann-2027-02-01",
"startLocation": [33.70474, -84.06508],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z",
"itinerary": [
{
"id": "Visit C",
"kind": "VISIT"
},
{
"id": "Visit A",
"kind": "VISIT"
}
]
}
]
}
]
}
Freeze the departure times for visits that have already occurred and that technicians have begun traveling to by adding freezeDeparturesBeforeTime
:
{
"modelInput": {
"freezeDeparturesBeforeTime": "2027-02-01T12:10:00Z"
}
}
In the original schedule Ann was due to finish Visit A at 12:22.
If the delay for Visit E is reported early enough, the freezeDeparturesBeforeTime
can be set prior to Ann finishing Visit A.
The updated schedule will keep visit A in place in the schedule and reschedule other visits as required.
Submit the updated input dataset to generate the new real-time plan:
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/field-service-routing/v1/route-plans [email protected]
{
"config": {
"run": {
"name": "Real-time planning: reassignment example"
}
},
"modelInput": {
"freezeDeparturesBeforeTime": "2027-02-01T12:10:00Z",
"vehicles": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl-2027-02-01",
"startLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z",
"itinerary": [
{
"id": "Visit E",
"kind": "VISIT"
},
{
"id": "Visit B",
"kind": "VISIT"
},
{
"id": "Visit D",
"kind": "VISIT"
}
]
}
]
},
{
"id": "Ann",
"shifts": [
{
"id": "Ann-2027-02-01",
"startLocation": [33.70474, -84.06508],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z",
"itinerary": [
{
"id": "Visit C",
"kind": "VISIT"
},
{
"id": "Visit A",
"kind": "VISIT"
}
]
}
]
}
],
"visits": [
{
"id": "Visit E",
"location": [33.84475, -84.63649],
"serviceDuration": "PT4H",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit B",
"location": [33.90719, -84.28149],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit D",
"location": [33.89351, -84.00649],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit A",
"location": [33.67590, -84.11845],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit C",
"location": [33.71517, -84.08527],
"serviceDuration": "PT1H30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
}
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
|
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/field-service-routing/v1/route-plans/<ID>
{
"run": {
"id": "ID",
"name": "Real-time planning: reassignment example",
"submitDateTime": "2024-10-30T08:47:33.505112416Z",
"startDateTime": "2024-10-30T08:47:39.397533431Z",
"activeDateTime": "2024-10-30T08:47:39.497533431Z",
"completeDateTime": "2024-10-30T08:52:39.782389568Z",
"shutdownDateTime": "2024-10-30T08:52:39.882389568Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-209989soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"vehicles": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl-2027-02-01",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Visit E",
"kind": "VISIT",
"arrivalTime": "2027-02-01T09:48:56Z",
"startServiceTime": "2027-02-01T09:48:56Z",
"departureTime": "2027-02-01T13:48:56Z",
"effectiveServiceDuration": "PT4H",
"travelTimeFromPreviousStandstill": "PT48M56S",
"travelDistanceMetersFromPreviousStandstill": 54141,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit B",
"kind": "VISIT",
"arrivalTime": "2027-02-01T14:29:29Z",
"startServiceTime": "2027-02-01T14:29:29Z",
"departureTime": "2027-02-01T15:59:29Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT40M33S",
"travelDistanceMetersFromPreviousStandstill": 42302,
"minStartTravelTime": "2027-02-01T12:10:00Z"
}
],
"metrics": {
"totalTravelTime": "PT1H57M18S",
"travelTimeFromStartLocationToFirstVisit": "PT48M56S",
"travelTimeBetweenVisits": "PT40M33S",
"travelTimeFromLastVisitToEndLocation": "PT27M49S",
"totalTravelDistanceMeters": 125663,
"travelDistanceFromStartLocationToFirstVisitMeters": 54141,
"travelDistanceBetweenVisitsMeters": 42302,
"travelDistanceFromLastVisitToEndLocationMeters": 29220,
"endLocationArrivalTime": "2027-02-01T16:27:18Z"
}
}
]
},
{
"id": "Ann",
"shifts": [
{
"id": "Ann-2027-02-01",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Visit C",
"kind": "VISIT",
"arrivalTime": "2027-02-01T09:09:55Z",
"startServiceTime": "2027-02-01T09:09:55Z",
"departureTime": "2027-02-01T10:39:55Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT9M55S",
"travelDistanceMetersFromPreviousStandstill": 6094,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit A",
"kind": "VISIT",
"arrivalTime": "2027-02-01T10:52:12Z",
"startServiceTime": "2027-02-01T10:52:12Z",
"departureTime": "2027-02-01T12:22:12Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT12M17S",
"travelDistanceMetersFromPreviousStandstill": 8841,
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Visit D",
"kind": "VISIT",
"arrivalTime": "2027-02-01T12:56:46Z",
"startServiceTime": "2027-02-01T12:56:46Z",
"departureTime": "2027-02-01T14:26:46Z",
"effectiveServiceDuration": "PT1H30M",
"travelTimeFromPreviousStandstill": "PT34M34S",
"travelDistanceMetersFromPreviousStandstill": 31646,
"minStartTravelTime": "2027-02-01T12:10:00Z"
}
],
"metrics": {
"totalTravelTime": "PT1H26M55S",
"travelTimeFromStartLocationToFirstVisit": "PT9M55S",
"travelTimeBetweenVisits": "PT46M51S",
"travelTimeFromLastVisitToEndLocation": "PT30M9S",
"totalTravelDistanceMeters": 72073,
"travelDistanceFromStartLocationToFirstVisitMeters": 6094,
"travelDistanceBetweenVisitsMeters": 40487,
"travelDistanceFromLastVisitToEndLocationMeters": 25492,
"endLocationArrivalTime": "2027-02-01T14:56:55Z"
}
}
]
}
]
},
"kpis": {
"totalTravelTime": "PT3H24M13S",
"travelTimeFromStartLocationToFirstVisit": "PT58M51S",
"travelTimeBetweenVisits": "PT1H27M24S",
"travelTimeFromLastVisitToEndLocation": "PT57M58S",
"totalTravelDistanceMeters": 197736,
"travelDistanceFromStartLocationToFirstVisitMeters": 60235,
"travelDistanceBetweenVisitsMeters": 82789,
"travelDistanceFromLastVisitToEndLocationMeters": 54712,
"totalUnassignedVisits": 0
}
}
modelOutput
contains Ann’s and Carl’s updated shift itineraries.
Visit E took longer than expected. Visit B is rescheduled, and Visit D is rescheduled and reassigned to Ann.
Next
-
Understand the constraints of the Field Service Routing model.
-
See the full API spec or try the online API.
-
Manage shift times with Time zones and daylight-saving time (DST) changes.
-
Learn about real-time planning.
-
Real-time planning with pinned visits.
-
Real-time planning with extended visits.
-
Real-time planning and emergency visits.