Types and territories
Types¶
Types restrict which Drivers are allowed to do which Jobs
This is often used for:
- Ensuring certain deliveries are performed by refrigerated vehicles
- Ensuring that the driver has the right qualifications to perform a service (e.g. she is a level 2 qualified electrician)
- Ensuring that large parcels are delivered by large enough vehicles, or vehicles with a tail lift
- Forcing a Job to be performed by a specific Driver (because the customer requested her, for example)
- Ensuring only certain vehicle types (e.g. small trucks, bicycles, electric vehicles) perform deliveries in city areas
If you are looking to create "Territories" or "Delivery Zones", please use Territories.
You can use this constraint by setting the spec_type on Jobs
and Drivers.
A Job with spec_type omitted or set to null or "" (empty string) can be served by any Driver.
Any white space in spec_type fields is ignored.
Note
We refer to this constraint as Types, yet in the code this is called
spec_type, an abbreviation of Specialisation Type.
type is a reserved word in most programming languages, so we didn't
want to use it.
Simple Types¶
If a Job has one or more types, it may only be served by a Driver who has the same type.
For example a Job with type electrician cannot be served by a
driver without a type, or a driver with type plumber. However, it can
be served by a Driver with type electrician.
Examples
{
"drivers": [
{
"uid": "driver_1",
"shift_start": 8,
"shift_end": 17,
"start": {"lat": -33.867798, "lon": 151.166256},
"end": "start",
"spec_type": "plumber"
}
],
"jobs": [
{
"uid": "job_1",
"duration": 2,
"location": {"lat": -33.849489, "lon": 151.127482},
"spec_type": "plumber"
},
{
"uid": "job_2",
"duration": 2,
"location": {"lat": -33.880661, "lon": 151.183096},
"spec_type": "electrician"
},
{
"uid": "job_3",
"duration": 2,
"location": {"lat": -33.913168, "lon": 151.262267},
"spec_type": null
}
],
"settings": {}
}
Multiple Types¶
Multiple types should be separated by commas ,.
A Job with type cert1,cert2 could be served by a Driver with any
of the following types:
cert1cert2cert1,cert2cert1,cert8plumber,cert2,cert8
but it cannot be served by a driver with any of the following types:
- (blank)
cert8cert8,cert9plumberplumber,cert8
Examples
{
"drivers": [
{
"uid": "driver_1",
"shift_start": 8,
"shift_end": 17,
"start": {"lat": -33.867798, "lon": 151.166256},
"end": "start",
"spec_type": "plumber,cert2,cert3"
}
],
"jobs": [
{
"uid": "job_1",
"duration": 2,
"location": {"lat": -33.849489, "lon": 151.127482},
"spec_type": "cert2"
},
{
"uid": "job_2",
"duration": 2,
"location": {"lat": -33.880661, "lon": 151.183096},
"spec_type": "plumber"
},
{
"uid": "job_3",
"duration": 2,
"location": {"lat": -33.913168, "lon": 151.262267},
"spec_type": "electrician,cert3"
},
{
"uid": "job_4",
"duration": 2,
"location": {"lat": -33.913168, "lon": 151.262267},
"spec_type": "electrician,cert4"
},
],
"settings": {}
}
Logical Types¶
If you need to be more specific about who can do what, use logical types
Logical types can only be applied to Jobs. The Driver spec_type must
be expressed using Multiple Types or Simple Types as above.
Logical types are expressed in our DSL:
- AND constraints (all of which must be true) are expressed using
& - OR constraints (at least one must be true) are expressed using
| - Parentheses are used to
(group logical sections)
For example, imagine all of your internal Drivers are qualified to do all Jobs. But sometimes you use subcontracted drivers, and it is important to ensure they have the appropriate qualification for each Job.
A Job with spec_type internal|(subcontractor&cert3) could be
served by any Driver with one of the following types:
internalinternal,plumbersubcontractor,cert3subcontractor,cert1,cert2,cert3,cert4
but cannot be served by a Driver with one of the following types:
- (blank)
subcontractorcert3subcontractor,cert1,cert2,cert4
Examples
{
"drivers": [
{
"uid": "driver_1",
"shift_start": 8,
"shift_end": 17,
"start": {"lat": -33.867798, "lon": 151.166256},
"end": "start",
"spec_type": "internal"
},
{
"uid": "driver_2",
"shift_start": 8,
"shift_end": 17,
"start": {"lat": -33.867798, "lon": 151.166256},
"end": "start",
"spec_type": "subcontractor,cert4"
},
{
"uid": "driver_3",
"shift_start": 8,
"shift_end": 17,
"start": {"lat": -33.867798, "lon": 151.166256},
"end": "start",
"spec_type": "subcontractor,cert3,cert4"
}
],
"jobs": [
{
"uid": "job_1",
"duration": 2,
"location": {"lat": -33.849489, "lon": 151.127482},
"spec_type": "internal|(subcontractor&cert3)"
}
],
"settings": {}
}
Territories¶
Many Delivery and Field Services companies divide their serviceable area into "zones" or "territories".
Companies often adopt this approach because:
- Each Driver gets to know their geographic area well
- You immediately know which Route a new Job falls into based on its location
- Warehouses can prepare shipments on the dock before the last order is made, before the optimisation is run.
Warning
Routes planned with Territories are usually 10% to 35% longer (KMs and hours) than without.
However, this feature exists because we know that many companies cannot make the operational trade-offs required to receive that benefit.
Internally, Territories are implemented using Types, so you'll notice
the syntax is the same as Multiple Types.
A Driver with driver.territories = 'North,East' can serve Jobs with:
job.territories = 'North'job.territories = 'East'job.territories = 'North,East'job.territories = ''job.territories = null
but cannot serve Jobs with:
job.territories = 'West'job.territories = 'NorthEast'
Jobs Outside Territories¶
Sometimes you will have a job that is not in any territory.
By default any Driver can serve this Job.
However, you may desire all Jobs outside of your predefined Territories
to be unserved. To put this in place, simply set the
job.territories = 'JOB_OUTSIDE_TERRITORIES'
- This effectively creates an extra Territory which no driver can serve.
- It doesn't matter what you call it. It just needs a territory name that no Drivers have.