Skip to content

Commit

Permalink
add shipments and priority to optimization endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsnolde committed May 11, 2020
1 parent dc0746b commit 1d4d8ca
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 13 deletions.
140 changes: 133 additions & 7 deletions openrouteservice/optimization.py
Expand Up @@ -19,8 +19,9 @@


def optimization(client,
jobs,
vehicles,
jobs=None,
vehicles=None,
shipments=None,
matrix=None,
geometry=None,
dry_run=None):
Expand All @@ -40,10 +41,13 @@ def optimization(client,
>>> result = api.optimization(jobs=jobs, vehicles=vehicles)
:param jobs: The Job objects to fulfill.
:type jobs: list of :class:`openrouteservice.optimization.Job`
:type jobs: list of Job
:param vehicles: The vehicles to fulfill the :class:`openrouteservice.optimization.Job`'s.
:type vehicles: list of :class:`openrouteservice.optimization.Vehicle`
:type vehicles: list of Vehicle
:param shipments: The Shipment objects to fulfill.
:type shipments: list of Shipment
:param matrix: Specify a custom cost matrix. If not specified, it will be calculated with
the :meth:`openrouteservice.matrix.matrix` endpoint.
Expand All @@ -59,11 +63,30 @@ def optimization(client,
:rtype: dict
"""

assert all([isinstance(x, Job) for x in jobs])
assert all([isinstance(x, Vehicle) for x in vehicles])

params = {"jobs": [job.__dict__ for job in jobs],
"vehicles": [vehicle.__dict__ for vehicle in vehicles]}
params = {"vehicles": [vehicle.__dict__ for vehicle in vehicles]}

if jobs:
assert all([isinstance(x, Job) for x in jobs])
params['jobs'] = [job.__dict__ for job in jobs]
if shipments:
assert all([isinstance(x, Shipment) for x in shipments])
params['shipments'] = list()

for shipment in shipments:
shipment_dict = dict()
if getattr(shipment, 'pickup'):
assert isinstance(shipment.pickup, ShipmentStep)
shipment_dict['pickup'] = shipment.pickup.__dict__
if getattr(shipment, 'delivery'):
assert isinstance(shipment.delivery, ShipmentStep)
shipment_dict['delivery'] = shipment.delivery.__dict__
shipment_dict['amount'] = shipment.amount
shipment_dict['skills'] = shipment.skills
shipment_dict['priority'] = shipment.priority

params['shipments'].append(shipment_dict)

if geometry is not None:
params.update({"options": {"g": geometry}})
Expand All @@ -87,6 +110,7 @@ def __init__(self,
service=None,
amount=None,
skills=None,
priority=None,
time_windows=None
):
"""
Expand All @@ -111,6 +135,9 @@ def __init__(self,
:param skills: An array of integers defining mandatory skills for this job.
:type skills: list of int or tuple of int
:param priority: An integer in the [0, 10] range describing priority level (defaults to 0).
:type priority: int
:param time_windows: An array of time_window objects describing valid slots for job service start.
:type time_windows: list of lists of int
"""
Expand All @@ -132,10 +159,109 @@ def __init__(self,
if skills is not None:
self.skills = skills

if priority is not None:
self.priority = priority

if time_windows is not None:
self.time_windows = time_windows


class ShipmentStep(object):
"""
Class to create a Shipment object for optimization endpoint.
Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#shipments.
"""
def __init__(self,
id=None,
location=None,
location_index=None,
service=None,
time_windows=None
):
"""
Create a shipment step object for the optimization endpoint.
:param id: Integer used as unique identifier.
:type id: int
:param location: Location of the job, as [lon, lat]. Optional if custom matrix is provided.
:type location: tuple of float or list of float
:param location_index: Index of relevant row and column in custom matrix. Mandatory if custom
matrix is provided. Irrelevant when no custom matrix is provided.
:type location_index: int
:param service: Optional job service duration in seconds
:type service: int
:param time_windows: An array of time_window objects describing valid slots for job service start.
:type time_windows: list of lists of int
"""

self.id = id

if location is not None:
self.location = location

if location_index is not None:
self.location_index = location_index

if service is not None:
self.service = service

if time_windows is not None:
self.time_windows = time_windows


class Shipment(object):
"""
Class to create a Shipment object for optimization endpoint.
Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#shipments.
"""
def __init__(self,
pickup=None,
delivery=None,
amount=None,
skills=None,
priority=None
):
"""
Create a shipment object for the optimization endpoint.
:param pickup: a ShipmentStep object describing pickup
:type pickup: ShipmentStep
:param delivery: a ShipmentStep object describing delivery
:type delivery: ShipmentStep
:param amount: An array of integers describing multidimensional quantities.
:type amount: list of int or tuple of int
:param skills: An array of integers defining mandatory skills.
:type skills: list of int or tuple of int
:param priority: An integer in the [0, 10] range describing priority level (defaults to 0).
:type priority: int
"""

if pickup is not None:
self.pickup = pickup

if delivery is not None:
self.delivery = delivery

if amount is not None:
self.amount = amount

if skills is not None:
self.skills = skills

if priority is not None:
self.priority = priority


class Vehicle(object):
"""
Class to create a Vehicle object for optimization endpoint.
Expand Down
84 changes: 84 additions & 0 deletions test/test_helper.py
Expand Up @@ -135,6 +135,88 @@
'sortby': 'distance',
},
'optimization': {
"shipments": [
{
"pickup": {
"id": 0,
"location": [
8.688641,
49.420577
],
"location_index": 0,
"service": 500,
"time_windows": [
[
50,
50
]
]
},
"delivery": {
"id": 0,
"location": [
8.688641,
49.420577
],
"location_index": 0,
"service": 500,
"time_windows": [
[
50,
50
]
]
},
"amount": [
50
],
"skills": [
50,
50
],
"priority": 50
},
{
"pickup": {
"id": 1,
"location": [
8.680916,
49.415776
],
"location_index": 1,
"service": 500,
"time_windows": [
[
50,
50
]
]
},
"delivery": {
"id": 1,
"location": [
8.680916,
49.415776
],
"location_index": 1,
"service": 500,
"time_windows": [
[
50,
50
]
]
},
"amount": [
50
],
"skills": [
50,
50
],
"priority": 50
}
],
"jobs": [
{
"id": 0,
Expand All @@ -143,6 +225,7 @@
"service": PARAM_INT_BIG,
"amount": [PARAM_INT_SMALL],
"skills": PARAM_LIST_ONE,
"priority": PARAM_INT_SMALL,
"time_windows": [PARAM_LIST_ONE]
},
{
Expand All @@ -152,6 +235,7 @@
"service": PARAM_INT_BIG,
"amount": [PARAM_INT_SMALL],
"skills": PARAM_LIST_ONE,
"priority": PARAM_INT_SMALL,
"time_windows": [PARAM_LIST_ONE]
}
],
Expand Down
34 changes: 28 additions & 6 deletions test/test_optimization.py
Expand Up @@ -24,20 +24,21 @@
import json

from test.test_helper import *
from openrouteservice.optimization import Job, Vehicle
from openrouteservice.optimization import Job, Vehicle, ShipmentStep, Shipment


class OptimizationTest(_test.TestCase):

def _get_params(self):
jobs, vehicles = list(), list()
jobs, vehicles, shipments = list(), list(), list()

for idx, coord in enumerate(PARAM_LINE):
jobs.append(Job(idx, location=coord,
service=PARAM_INT_BIG,
location_index=idx,
amount=[PARAM_INT_SMALL],
skills=PARAM_LIST_ONE,
priority=PARAM_INT_SMALL,
time_windows=[PARAM_LIST_ONE]
))

Expand All @@ -49,11 +50,32 @@ def _get_params(self):
capacity=[PARAM_INT_SMALL],
skills=PARAM_LIST_ONE,
time_window=PARAM_LIST_ONE))
return jobs, vehicles

shipments.append(Shipment(
pickup=ShipmentStep(
idx,
location=coord,
location_index=idx,
service=PARAM_INT_BIG,
time_windows=[PARAM_LIST_ONE]
),
delivery=ShipmentStep(
idx,
location=coord,
location_index=idx,
service=PARAM_INT_BIG,
time_windows=[PARAM_LIST_ONE]
),
amount=[PARAM_INT_SMALL],
skills=PARAM_LIST_ONE,
priority=PARAM_INT_SMALL
))

return jobs, vehicles, shipments

def test_jobs_vehicles_classes(self):

jobs, vehicles = self._get_params()
jobs, vehicles, shipments = self._get_params()

self.assertEqual(ENDPOINT_DICT['optimization']['jobs'], [j.__dict__ for j in jobs])
self.assertEqual(ENDPOINT_DICT['optimization']['vehicles'], [v.__dict__ for v in vehicles])
Expand All @@ -62,14 +84,14 @@ def test_jobs_vehicles_classes(self):
def test_full_optimization(self):
query = deepcopy(ENDPOINT_DICT['optimization'])

jobs, vehicles = self._get_params()
jobs, vehicles, shipments = self._get_params()

responses.add(responses.POST,
'https://api.openrouteservice.org/optimization',
json={},
status=200,
content_type='application/json')

self.client.optimization(jobs, vehicles, geometry=False, matrix=PARAM_LIST_TWO)
self.client.optimization(jobs, vehicles, shipments, geometry=False, matrix=PARAM_LIST_TWO)

self.assertEqual(query, json.loads(responses.calls[0].request.body.decode('utf-8')))

0 comments on commit 1d4d8ca

Please sign in to comment.