Pick-Drop Food Delivery
Business Scenario
In Singapore, kStore offers home appliance installation and repair services. There are four types of service orders for different products:
- AC
- TV
- Kitchen (Appliances)
- Plumber (Services)
There are also three different customer types:
- KA (Key Accounts)
- SMB (Small Medium Businesses)
- Individual
Each worker (or technician, engineer) can have different combination of those service skills and may have access to different types of customers.
The orders are sent to Kandbox Dispatch platform via APIs continuously and dispatched to workers once a day.
The main difference between this guide and others is that we have to deal with complex business rules like "Skills", "Service Time Window", "Service Duration". Also the planning window may span accross multiple days.
All codes in this example can be found in repository: KDClient . The main programs/scripts for this example are:
- python demo
- HTTP scripts
Prerequisite
- You should already have a Kandbox Dispatch Account. If not, please go to kandbox dispatch to register one account.
- To run the sample python program, you should have python installed in your environment. We are building the client example by Python and Restful APIs. VSCode is our preferred IDE. The HTTP scripts are coded in rest-client format.
Execute the Example Python Program in one go
The first step is to clone the repository to your local computer:
sh
git clone https://github.com/li-jinbao/kdclient
Then install the required packages to your python environment:
sh
cd kdclient
pip install -r requirements.txt
Configure the required environment variables with the information you have registered to Kandbox Dispatch:
sh
# export server_url=http://_server_url_/kd/api/v1
# export email=_email_@email.com
# export password=_pass_
# export team_code=_team_
Then you can run the sg_multi_days demo program by:
sh
python ./src/sg_multi_days.py
After the program finish, you should be able to view the planned route in the Web UI.
Run APIs Step by Step
The previous Python program executes several steps in one go. To learn and test the APIs one by one, you can follow steps in this section. This sequence is also the sequence of API being used in the python program.
Create a team
To use the restful APIs, you should first use the Login API to get a token for each sub-sequent API calls.
http
POST {{hostUrl}}/auth/login
Content-Type: application/json
{"email": "{{user}}", "password": "{{pass}}"}
python
url = f"{self.service_url}/auth/login"
login_info = {"email": username, "password": password}
response = self.requests.post(
url, json=login_info, headers={"Content-Type": "application/json"},
)
With the token, we will create our team at Singapore with this API call:
http
POST {{server_url}}/teams/
Authorization: Bearer {{jwtoken}}
Content-Type: application/json
{
"code": "sgmd", "name": "sgmd",
"geo_longitude": 103.8,
"geo_latitude": 1.3,
"planner_service": {"code": "single"},
"flex_form_data": {
"fixed_horizon_flag": "1",
"env_start_datetime": "2023-11-13T00:00:00",
"horizon_start_datetime": "2023-11-13T08:01:01",
"nbr_minutes_planning_windows_duration": 1440,
"enable_skills": "1",
}
}
Here "enable_skills" will enable the skill check for the planning engine. By default it is disabled.
Create Workers
We can now create two workers with different skill sets one by one with this API call:
http
POST {{server_url}}/workers/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{jwtoken}}
{
"code": "w1", "name": "w1",
"team": {"code": "{{team_code}}"},
"geo_longitude": 103.835,
"geo_latitude": 1.303,
"flex_form_data": {"area_code": "A", "capacity_volume": 0, "max_nbr_order": 0},
"business_hour": {
"monday": [{"open": "0005", "close": "2330", "id": "a0", "isOpen": true}],
"tuesday": [{"open": "0005", "close": "2330", "id": "a1", "isOpen": true}],
"wednesday": [{"open": "0005", "close": "2330", "id": "a2", "isOpen": true}],
"thursday": [{"open": "0005", "close": "2330", "id": "a3", "isOpen": true}],
"friday": [{"open": "0005", "close": "2330", "id": "a4", "isOpen": true}],
"saturday": [{"open": "0005", "close": "2330", "id": "a5", "isOpen": true}],
"sunday": [{"open": "0005", "close": "2330", "id": "a6", "isOpen": true}]
},
"auto_planning": true,
"is_active": true
}
Then you can create the second worker by repeating previous call after replacing skills by "Kitchen" in the JSON body:
json
{
"code": "w2", "name": "w2",
"flex_form_data": {
"skills":"Kitchen"
}
}
Reset Planning Window
After we have created the workers, we should reset the planning window to initialize the planning engine.
http
POST {{server_url}}/planner_service/reset_planning_window/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{jwtoken}}
{"team_code": "{{team_code}}"}
If resetting is successful, you should be able to view gantt chart with worker's empty working slot.
Create Jobs
Now we can add jobs to this team. In this guide, we should store the job and dispatch them in one batch. This is done by setting auto_planning=false.
We can create the jobs one by one with this API call:
http
###
# @name create_job_1
POST {{server_url}}/jobs/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{jwtoken}}
{
"code":"A1-0",
"team": {"code": "{{team_code}}"} ,
"job_type": "visit",
"auto_planning": false,
"is_active": true,
"planning_status": "U",
"geo_longitude": 103.833,
"geo_latitude": 1.301,
"requested_start_datetime": "2023-11-13T07:06:40",
"requested_duration_minutes": 0.5,
"flex_form_data": {
"area_code": "A",
"skills":"TV"
}
}
Then you can create the second worker by repeating previous call after replacing skills by "Kitchen" in the JSON body:
json
{
"code":"A2-0",
"geo_longitude": 103.833,
"geo_latitude": 1.315,
"flex_form_data": {
"skills":"Kitchen"
}
}
Run Batch Planning
Since we are using "auto_planning"=false, the order should not be planned after creation. It will wait till run_batch_optimizer call.
After you have created all the jobs, you can initiate the planning action by this API.
http
POST {{server_url}}/planner_service/run_batch_optimizer/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{jwtoken}}
{
"team_code": "{{team_code}}"
}
Read the planning result
You can use this api to get the planned jobs for any worker.
http
POST {{server_url}}/planner_service/get_env_jobs/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{jwtoken}}
{
"team_code": "{{team_code}}",
"reset_start_datetime": false,
"active_only":false
}
You should see a result json like the following:
json
{
"w2": [
{
"code": "A2-0",
"scheduled_start_datetime": "2023-11-13T08:03:00",
"prev_travel": 0.0,
"scheduled_duration_minutes": 0.0
}
],
"w1": [
{
"code": "A1-0",
"scheduled_start_datetime": "2023-11-13T08:03:00",
"prev_travel": 2.0,
"scheduled_duration_minutes": 0.0
}
]
}
In this result job "A1-0" is assigned to worker "W1" and job "A2-0" is assigned to worker "W2". This was determined by the skills setting during the creation.
Review the planned result in the Web UI
After the planning is done, you can login to the Kandbox Dispatch platform. You should be able to see a Singapore map with planned workers and jobs on the map.