├── api-tools ├── driver_import │ ├── requirements.txt │ ├── template.csv │ ├── README.md │ └── driver_importer.py ├── export-tasks │ ├── requirements.txt │ ├── README.md │ └── export.py ├── webhooks │ ├── python │ │ ├── requirements.txt │ │ ├── README.md │ │ └── testwebhooks.py │ └── nodejs │ │ ├── README.md │ │ └── webhookserver.js ├── README.md ├── delete-entities │ ├── deletion.py │ └── README.md └── import-tasks │ ├── README.md │ └── task-import.py ├── .gitignore ├── Example_Payload_Templates.zip ├── package.json └── README.md /api-tools/driver_import/requirements.txt: -------------------------------------------------------------------------------- 1 | pyonfleet 2 | pprint 3 | PyInquirer -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.csv 3 | venv/ 4 | .gitignore 5 | .DS_Store 6 | .auth.json 7 | node_modules -------------------------------------------------------------------------------- /Example_Payload_Templates.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onfleet/developer/HEAD/Example_Payload_Templates.zip -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "escape-html": "^1.0.3", 4 | "express": "^4.21.2" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /api-tools/driver_import/template.csv: -------------------------------------------------------------------------------- 1 | name,phone,capacity,displayName,vehicle type,vehicle description,vehicle licensePlate,vehicle color 2 | -------------------------------------------------------------------------------- /api-tools/export-tasks/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2024.7.4 2 | chardet==3.0.4 3 | configparser==3.7.4 4 | idna==3.7 5 | pyonfleet 6 | requests==2.32.4 7 | urllib3==2.5.0 8 | -------------------------------------------------------------------------------- /api-tools/webhooks/python/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.9.0 2 | click==8.1.8 3 | Flask==3.1.1 4 | importlib_metadata==8.7.0 5 | itsdangerous==2.2.0 6 | Jinja2==3.1.6 7 | MarkupSafe==3.0.2 8 | Werkzeug==3.1.3 9 | zipp==3.21.0 -------------------------------------------------------------------------------- /api-tools/export-tasks/README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | 3 | Export tasks from the Onfleet list tasks API endpoint as either a CSV or plain JSON. 4 | 5 | Requires Python 3 6 | 7 | ## Installation 8 | 9 | 1. Update export.py with the organization's `API_KEY` and optionally task `STATE` and `FROM_DAYS_AGO`/`TO_DAYS_AGO` parameters. 10 | 2. run `python export.py` -------------------------------------------------------------------------------- /api-tools/README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | 3 | A collection of tools built for the Onfleet API. 4 | 5 | * `export-tasks` : generate a customizable CSV export of all matching tasks using the list tasks endpoint 6 | * `webhooks` : create endpoints for basic validation and processing of various webhook triggers 7 | * `driver_import` : Interactive CLI to bulk-import drivers from CSV-formatted spreadsheets via the Onfleet API -------------------------------------------------------------------------------- /api-tools/webhooks/nodejs/README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | 3 | Endpoints for each Onfleet webhook trigger. Validate the webhook and print payload to screen. For more information Please see [here](https://docs.onfleet.com/reference/validation) 4 | 5 | ## Installation 6 | Require node and express 7 | May require body-parser 8 | 9 | 1. Install node and npm 10 | 2. ```npm install express``` 11 | 3. Optional: ```npm install body-parser``` 12 | 13 | ### Use 14 | 15 | 1. Start node server by use ```node webhookserver.js``` in terminal 16 | 2. Expose to the wider internet ( if using ngrok: start ngrok server ) 17 | 3. Create a webhook for your trigger event, using the path from the table below as your webhook URL. -------------------------------------------------------------------------------- /api-tools/webhooks/nodejs/webhookserver.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const escape = require('escape-html'); 3 | const app = express(); 4 | const port = 3000; 5 | //const fs = require('node:fs'); 6 | app.use(express.json()); 7 | //GET method query validation 8 | app.get("/webhooks", (req, res) => { 9 | res.status(200).send(escape(req.query.check)); 10 | //console.log(req.query.check); 11 | }) 12 | 13 | //POST method for the webhook payload 14 | app.post("/webhooks", (req, res) => { 15 | const content = JSON.stringify(req.body); 16 | console.log(content) 17 | res.sendStatus(200); 18 | }) 19 | 20 | app.listen(port, () => { 21 | console.log(`Server listening on port ${port}`); 22 | }); 23 | 24 | /* Only if you want to write it to a local File Directory 25 | // Set the [Path] 26 | fs.writeFileSync('[path]', content, err => { 27 | if (err) { 28 | console.error(err); 29 | console.log(content); 30 | } else { 31 | // file written successfully 32 | } 33 | });*/ 34 | -------------------------------------------------------------------------------- /api-tools/webhooks/python/README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | 3 | Endpoints for each Onfleet webhook trigger. Validate the webhook and print payload to screen 4 | 5 | ## Installation 6 | 7 | ### WARNING 8 | This project is incompatible with python versions later than 3.6.15. 9 | If you are using a later version of python, please use [pyenv](https://github.com/pyenv/pyenv) or another tool to manage versions of python on your system. 10 | 11 | 1. ```pip install -r requirements.txt``` 12 | 2. ```export FLASK_APP=testwebhooks.py; flask run``` 13 | 3. expose to the wider internet ( if using ngrok: start ngrok server ) 14 | 4. Create a webhook for your trigger event, using the path from the table below as your webhook URL. 15 | 16 | Event | path 17 | ------|------- 18 | Task started | /taskstart 19 | Driver ETA less than or equal to | /taskETA 20 | Driver arriving, at or closer than | /taskarrival 21 | Task completed | /taskcomplete 22 | Task failed | /taskfailed 23 | Driver status changed | /workerduty 24 | New task created | /taskcreated 25 | Task updated | /taskupdated 26 | Task deleted | /taskdeleted 27 | Task assigned | /taskassigned 28 | Task unassigned | /taskunassigned 29 | Task delay time is greater than or equal to | /taskdelayed 30 | SMS Recipient Response Missed | /smsrecipientresponsemissed 31 | Task Cloned | /taskcloned 32 | -------------------------------------------------------------------------------- /api-tools/driver_import/README.md: -------------------------------------------------------------------------------- 1 | # Onfleet Driver Import CLI 2 | This is an interactive CLI that assist Onfleet admins to create new driver profiles in bulk. 3 | 4 | ## Usage 5 | 1. Download the code from the repository, ensure that you have all the required libraries listed in `requirements.txt` installed. 6 | 2. Make modifications to the file by inputting your own `Onfleet API key` and the `CSV filename` (`delimiters` can also be modified) 7 | 3. Execute the script to enter the CLI: 8 | ``` 9 | python driver_importer.py 10 | ``` 11 | 4. Upon the prompt, use the arrow keys to select the team that you wish to import driver profiles to. 12 | 5. Option to select multiple teams here as the CLI prompts you to add more teams, simply click `Y` and select the teams until you are done. 13 | 6. Once the script completes, your results will be stored in a `result.csv` file for your reference. 14 | 15 | > Note that all the valid drivers in the CSV file will be assigned to all the teams selected here. 16 | 17 | ## Import File Format 18 | The imported file is of CSV format, and should have the following headers set assuming you are using comma as delimiters: 19 | ``` 20 | name,phone,capacity,displayName,vehicle type,vehicle description,vehicle licensePlate,vehicle color 21 | ``` 22 | 23 | Of all the parameters, `name` and `phone` are required, where all others are optional. The only exception is `team` which will be determined via the interactive CLI. -------------------------------------------------------------------------------- /api-tools/delete-entities/deletion.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import datetime 3 | 4 | # Define the API endpoint base 5 | API_URL = "https://onfleet.com/api/v2/" #Base API URL is here https://onfleet.com/api/v2/ 6 | ENTITY = "" #The Entity you are accessing, see Onfleet API doc for more info 7 | 8 | # Define user credentials for Basic Authentication 9 | USERNAME = "" #put your API key here along with ":" 10 | PASSWORD = "" #put nothing here because it's basic auth, see Onfleet API doc for more info 11 | 12 | # List of Ids to loop through 13 | id_list = []# array of IDs, task/driver/team/admin 14 | 15 | # Loop through each ID and make the API request 16 | for ID in id_list: 17 | try: 18 | full_url = f"{API_URL}/{ENTITY}/{ID}" 19 | response = requests.delete(full_url, auth=(USERNAME, PASSWORD)) 20 | response.raise_for_status() # Raise an error for bad status codes 21 | print(f"{ENTITY} {ID} has been deleted\n") 22 | except requests.exceptions.RequestException as e: 23 | print(f"API request failed for {ID}: {e}") 24 | 25 | start = datetime.datetime.now() 26 | while (datetime.datetime.now() - start).seconds < 1: 27 | pass # Sleep for 1 seconds before the next request, built-in throttle so it would not violate 28 | 29 | # Example cURL command with Basic Auth 30 | # print("\nExample cURL command:") 31 | # print(f"curl -u [REDACTED]:[REDACTED] -X DELETE '{API_URL}?query=YOUR_QUERY'") 32 | -------------------------------------------------------------------------------- /api-tools/delete-entities/README.md: -------------------------------------------------------------------------------- 1 | # Delete Multiple Entities 2 | 3 | Delete Multiple Entities with a loop, this could be tasks or drivers, any allowed deletions. 4 | 5 | ## Table of Contents 6 | 7 | - [Installation](#installation) 8 | - [Disclaimer](#disclaimer) 9 | - [Usage](#usage) 10 | - [Configuration](#configuration) 11 | - [Template File](#template-file) 12 | - [Output](#output) 13 | - [Dependencies](#dependencies) 14 | 15 | ## Installation 16 | 17 | 1. Clone the repository: 18 | 19 | ``` 20 | 21 | git clone https://github.com/onfleet/developer.git 22 | 23 | 24 | ``` 25 | 2. Install the required dependencies: 26 | 27 | ``` 28 | 29 | pip install requests 30 | pip install datetime 31 | 32 | ``` 33 | ## Disclaimer 34 | 35 | This script does not have a roll back function. Any deletion using this script cannot be reversed. Please check before you execute this script. Onfleet is not responsible for any loss of data by using this script. 36 | 37 | ## Usage 38 | 39 | 1. Open the `deletion.py` file and fill in the necessary line with your info. 40 | 41 | 2. Replace `ENTITY` with the entity you are accessing on line 6. Replace `USERNAME` with your actual Onfleet API Key on line 9. Include an array of Onfleet IDs you wish to delete `` 42 | 43 | 3. Run the program: 44 | 45 | ``` 46 | 47 | python deletion.py 48 | 49 | ``` 50 | 51 | 4. Check the console output for any errors encountered during deletion. 52 | 53 | ## Configuration 54 | 55 | To configure the program, you need to provide your Onfleet API key. Replace `USERNAME` on line 9 of the program with your actual API key. If needed, [here](https://support.onfleet.com/hc/en-us/articles/360045763292-API#h_01FTGN2E1AGNAA4DB3Q2RPVWD9) is more information on how to create an API key in Onfleet 56 | 57 | ## Template File 58 | 59 | ## Output 60 | 61 | ID that has been deleted or encountered any errors from the Onfleet API response. 62 | 63 | ## Dependencies 64 | 65 | The program relies on the following dependencies: 66 | 67 | - `requests`: Python's built-in module for simple HTTP requests. 68 | - `datetime`: Python's built-in module for working with dates and times. 69 | 70 | 71 | Make sure you have these dependencies installed before running the program. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Onfleet Developer open source repository 2 | 3 | ## Synopsis 4 | 5 | This repository is a collection of resources and tools that may be freely used to augment and accelerate custom integration with the Onfleet API. 6 | 7 | **Note** All python scripts require Python 3. 8 | 9 | ## Content 10 | 11 | * Onfleet webhooks backend - [python](https://github.com/onfleet/developer/tree/master/api-tools/webhooks) 12 | * Create dedicated endpoints to validate and receive payloads from various Onfleet webhook triggers. 13 | * CSV task export - [python](https://github.com/onfleet/developer/tree/master/api-tools/export-tasks) 14 | * Export tasks from the [Onfleet list tasks API endpoint](https://docs.onfleet.com/reference#list-tasks) either in CSV format, or in plain JSON. Specify time range, task state, and other query parameters. 15 | * Driver import - [python](https://github.com/onfleet/developer/tree/master/api-tools/driver_import) 16 | * Interactive CLI to bulk-import drivers from CSV-formatted spreadsheets via the Onfleet API. 17 | 18 | ## Related resources 19 | 20 | [Onfleet API documentation](https://docs.onfleet.com/reference#introduction) 21 | 22 | ### Onfleet API Wrapper client libraries 23 | 24 | * `pyonfleet` - Onfleet python API wrapper library: 25 | * [repository + documentation](https://github.com/onfleet/pyonfleet) 26 | * [PyPi project description](https://pypi.org/project/pyonfleet/) 27 | * `node-onfleet` - Onfleet nodeJS API wrapper library: 28 | * [repository + documentation](https://github.com/onfleet/node-onfleet) 29 | * `php-onfleet` - Onfleet PHP API wrapper library: 30 | * [repository + documentation](https://github.com/onfleet/php-onfleet) 31 | 32 | ## Installation 33 | 34 | 1 Clone the `developer` repository to your local development directory or download the zip file from github, and change to that directory. 35 | 36 | ``` 37 | git clone git@github.com:onfleet/developer ./onfleet-developer 38 | cd ./onfleet-developer 39 | ``` 40 | 41 | 2 Change directory to one of the onfleet/developer tools. Ex: 42 | 43 | ``` 44 | cd ./api-tools/webhooks 45 | ``` 46 | 47 | 2a (optional) create a new virtual environment that uses Python 3 48 | 49 | ``` 50 | python3 -m venv ./venv 51 | ``` 52 | 53 | 2b (optional) activate the virtual environment (note: venv must be activated in the terminal session before running any onfleet-developer python script) 54 | 55 | ``` 56 | source venv/bin/activate 57 | ``` 58 | 59 | 3 Install all required python modules (note: use pip3 if python 3 isn't your default python version) 60 | 61 | ``` 62 | pip install -r requirements.txt 63 | ``` 64 | -------------------------------------------------------------------------------- /api-tools/import-tasks/README.md: -------------------------------------------------------------------------------- 1 | # Task Import for Python 2 | 3 | Uploads a CSV of tasks through the command line to the Onfleet API via Python 4 | 5 | ## Table of Contents 6 | 7 | - [Installation](#installation) 8 | - [Usage](#usage) 9 | - [Configuration](#configuration) 10 | - [Template File](#template-file) 11 | - [Output](#output) 12 | - [Dependencies](#dependencies) 13 | - [Contributing](#contributing) 14 | - [License](#license) 15 | 16 | ## Installation 17 | 18 | 1. Clone the repository: 19 | 20 | ``` 21 | 22 | git clone https://github.com/onfleet/developer.git 23 | 24 | 25 | ``` 26 | 2. Install the required dependencies: 27 | 28 | ``` 29 | 30 | pip install onfleet 31 | 32 | 33 | ``` 34 | 35 | ## Usage 36 | 37 | 1. Open the `import_template.csv` file and fill in the necessary data according to the provided template structure. 38 | 39 | 2. Replace `YOUR_API_KEY_HERE` with your actual Onfleet API key on line 15 of the program. 40 | 41 | 3. Run the program: 42 | 43 | ``` 44 | 45 | python task-import.py 46 | 47 | ``` 48 | 49 | 4. Check the console output for any errors or warnings encountered during task creation. 50 | 51 | 5. Review the generated `warnings-{timestamp}.csv` file for a detailed list of warnings. 52 | 53 | ## Configuration 54 | 55 | To configure the program, you need to provide your Onfleet API key. Replace `YOUR_API_KEY_HERE` on line 15 of the program with your actual API key. If needed, [here](https://support.onfleet.com/hc/en-us/articles/360045763292-API#h_01FTGN2E1AGNAA4DB3Q2RPVWD9) is more information on how to create an API key in Onfleet 56 | 57 | ## Template File 58 | 59 | The template file (`import_template.csv`) should be filled out with the relevant data for creating tasks. Ensure that the data follows the provided template structure and includes all required information. 60 | 61 | ## Output 62 | 63 | The program generates a `warnings-{timestamp}.csv` file that contains a list of rows with warnings encountered during task creation. Each row includes the original data from the template file and the corresponding warnings. 64 | 65 | ## Dependencies 66 | 67 | The program relies on the following dependencies: 68 | 69 | - `csv`: Python's built-in CSV module for reading and writing CSV files. 70 | - `os`: Python's built-in module for interacting with the operating system. 71 | - `warnings`: Python's built-in module for warning handling. 72 | - `datetime`: Python's built-in module for working with dates and times. 73 | - `onfleet`: Third-party library for interacting with the Onfleet API. 74 | 75 | Make sure you have these dependencies installed before running the program. -------------------------------------------------------------------------------- /api-tools/export-tasks/export.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import json 3 | import sys 4 | import logging 5 | from time import time 6 | from onfleet import Onfleet 7 | 8 | ## USER DEFINED TASK EXPORT PARAMETERS 9 | 10 | # Enter your API key below 11 | API_KEY = '' 12 | 13 | CSV_OUTPUT = True 14 | STATE = "0,1,2,3" 15 | 16 | # set from & to parameters in unix (ms) 17 | FROM_DAYS_AGO = 300 18 | TO_DAYS_AGO = 0 19 | 20 | EXPORT_DIRECTORY = "./" 21 | EXPORT_FILE_NAME = "export-%d" % int(time()) 22 | 23 | # set logging level and print to screen 24 | # change level to logging.WARNING to suppress info logging messages 25 | logging.basicConfig(stream=sys.stdout, level=logging.INFO) 26 | 27 | ## END USER DEFINED TASK EXPORT PARAMETERS 28 | 29 | api = Onfleet(api_key=API_KEY) 30 | 31 | # convert times to UNIX timestamps with millisecond precision 32 | FROM_TIME = str(int(time()-(FROM_DAYS_AGO*24*60*60)) * 1000) 33 | TO_TIME = str(int(time()-(TO_DAYS_AGO*24*60*60)) * 1000) 34 | 35 | def getTasksInRange(lastTaskId = None): 36 | params = {"from":FROM_TIME,"to":TO_TIME,"state":STATE,"lastId":lastTaskId} 37 | response = api.tasks.get(queryParams=params) 38 | return response 39 | 40 | response = getTasksInRange() 41 | 42 | tasks = None 43 | tasks_fetched = 0 44 | if 'tasks' in response: 45 | tasks = response['tasks'] 46 | tasks_fetched += len(tasks) 47 | info = 'Fetched ' + str(tasks_fetched) + ' tasks' 48 | logging.log(logging.INFO, info) 49 | 50 | # paginate if necessary 51 | while 'lastId' in response: 52 | lastId = response['lastId'] 53 | response = getTasksInRange(response['lastId']) 54 | tasks.extend(response['tasks']) 55 | tasks_fetched += len(response['tasks']) 56 | info = 'Fetched ' + str(tasks_fetched) + ' tasks' 57 | logging.log(logging.INFO, info) 58 | 59 | if tasks and CSV_OUTPUT: 60 | # get keys for all tasks for column headers 61 | all_keys_set = set() 62 | all_keys_list = [] 63 | for t in tasks: 64 | for k in t.keys(): 65 | if not k in all_keys_set: 66 | all_keys_set.add(k) 67 | all_keys_list.append(k) 68 | 69 | # format data for CSV 70 | rows = [] 71 | for t in tasks: 72 | row = [] 73 | for k in all_keys_list: 74 | if k in t.keys(): 75 | row.append(str(t[k])) 76 | else: 77 | row.append("") 78 | rows.append(row) 79 | 80 | # write to CSV 81 | csv_file = EXPORT_DIRECTORY + EXPORT_FILE_NAME + ".csv" 82 | with open(csv_file, 'w') as export_file: 83 | csvwriter = csv.writer(export_file) 84 | csvwriter.writerow(all_keys_list) 85 | 86 | for row in rows: 87 | try: 88 | csvwriter.writerow(row) 89 | except Exception as e: 90 | warning = "skipped:", e 91 | logging.log(logging.WARNING, warning) 92 | pass 93 | info = 'Export file created: ' + csv_file 94 | logging.log(logging.INFO, info) 95 | 96 | elif tasks and not CSV_OUTPUT: 97 | # write JSON line response to file 98 | json_file = EXPORT_DIRECTORY + EXPORT_FILE_NAME + ".jsonl" 99 | with open(json_file, 'w') as export_file: 100 | for t in tasks: 101 | try: 102 | export_file.write(str(json.dumps(t)) + "\n") 103 | except Exception as e: 104 | logging.exception(e, "\n", json.dumps(t)) 105 | raise 106 | info = 'Export file created: ' + json_file 107 | logging.log(logging.INFO, info) 108 | 109 | else: 110 | warning = "No tasks returned in this period" 111 | logging.log(logging.WARNING, warning) -------------------------------------------------------------------------------- /api-tools/import-tasks/task-import.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | import warnings 4 | import datetime 5 | from onfleet import Onfleet 6 | from onfleet.error import ValidationError 7 | 8 | rowNumber = 1 9 | warningsList = [] 10 | timeUploaded = str(datetime.datetime.now()) 11 | 12 | # Set the API endpoint URL 13 | 14 | api = Onfleet(api_key="YOUR_API_KEY_HERE") # fill in your API key between the quotation marks 15 | csv_file = "import_template.csv" #fill in the template file 16 | 17 | def create_task(row): 18 | warning_title = '' 19 | # Parse the row and map the values to the task body 20 | task = { 21 | "Notification": row["Notification"], 22 | "Organization": row["Organization"], 23 | "Driver": row["Driver"], 24 | "Team": row["Team"], 25 | "Quantity": row["Quantity"], 26 | "Merchant": row["Merchant"], 27 | "ServiceTime": row["ServiceTime"], 28 | "notes": row["Task_Details"], 29 | "recipients": [ 30 | { 31 | "name": row["Recipient_Name"], 32 | "phone": row["Recipient_Phone"], 33 | "notes": row["Recipient_Notes"] 34 | } 35 | ], 36 | "recipientName": row["Recipient_Name"] 37 | 38 | } 39 | lat = row["Latitude"].strip() 40 | lon = row["Longitude"].strip() 41 | 42 | 43 | # Check if the latitude and longitude values are not blank 44 | if lat and lon: 45 | task["destination"] = { 46 | "address": { 47 | "street": row["Address_Line1"], 48 | "city": row["City/Town"], 49 | "state": row["State/Province"], 50 | "postalCode": row["Postal_Code"], 51 | "country": row["Country"] 52 | }, 53 | "location": { 54 | "coordinates": [ 55 | float(lat), 56 | float(lon) 57 | ], 58 | 59 | } 60 | } 61 | 62 | else: 63 | task["destination"] = { 64 | "address": { 65 | "unparsed": row["Address_Line1"] + ", " + row["City/Town"] + ", " + row["State/Province"] + ", " + row["Postal_Code"] + ", " + row["Country"] 66 | }, 67 | } 68 | 69 | # Check if the "completeAfter" cell is empty 70 | if row["completeAfter"]: 71 | task["completeAfter"] = row["completeAfter"] 72 | 73 | # Check if the "completeBefore" cell is empty 74 | if row["completeBefore"]: 75 | task["completeBefore"] = row["completeBefore"] 76 | 77 | # Call the Onfleet API to create a task 78 | 79 | try: 80 | response = api.tasks.create(body=task) 81 | warning_title = response.get("destination", {}).get("warnings", []) 82 | if warning_title: 83 | print(row["Address_Line1"], f"on row {rowNumber} has a warning: {warning_title}") 84 | # Add the warning to the row 85 | warningsList.append(row) 86 | return response 87 | except Exception as err: 88 | errMsg = str(err).split(',')[-1].strip("'") 89 | print (f"Error creating task on row {rowNumber}:", errMsg[:-1]) 90 | 91 | 92 | # Open the template file 93 | 94 | custom_delimiter = "," 95 | THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) 96 | 97 | file_name = os.path.join(THIS_FOLDER, csv_file) 98 | 99 | with open(file_name, "r") as template_file: 100 | # Read the template file as a CSV 101 | template_reader = csv.DictReader(template_file) 102 | # Add Task_ID to fieldnames 103 | fieldnames = template_reader.fieldnames + ["Task_ID"] 104 | 105 | # Iterate through each row in the template 106 | for row in template_reader: 107 | rowNumber += 1 108 | try: 109 | # Create a task using the row 110 | response = create_task(row) 111 | # Check if the task has warnings 112 | if (bool(response['destination']['warnings'])): 113 | # Append the row to the warnings list 114 | row["warnings"] = (response['destination']['warnings']) 115 | # warningsList.append(row) 116 | 117 | 118 | except Exception as e: 119 | continue 120 | 121 | 122 | 123 | # Write the warnings list to a separate CSV 124 | with open("warnings" + timeUploaded + ".csv", "w") as warning_file: 125 | writer = csv.DictWriter(warning_file, fieldnames=template_reader.fieldnames + ["warnings"]) 126 | writer.writeheader() 127 | for row in warningsList: 128 | writer.writerow(row) -------------------------------------------------------------------------------- /api-tools/driver_import/driver_importer.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, unicode_literals 2 | from pprint import pprint 3 | from PyInquirer import style_from_dict, Token, prompt 4 | 5 | from onfleet import Onfleet 6 | import csv 7 | import os 8 | import json 9 | import datetime 10 | 11 | THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) 12 | 13 | # User-defined parameters including API key and csv filename 14 | api = Onfleet(api_key="") 15 | csv_file = "template.csv" 16 | custom_delimiter = "," 17 | 18 | file_name = os.path.join(THIS_FOLDER, csv_file) 19 | # Styling for the CLI 20 | style = style_from_dict({ 21 | Token.QuestionMark: '#E91E63 bold', 22 | Token.Selected: '#673AB7 bold', 23 | Token.Instruction: '', # default 24 | Token.Answer: '#2196f3 bold', 25 | Token.Question: '', 26 | }) 27 | 28 | def list_team(): 29 | team_list = api.teams.get() 30 | team_name_list = [] 31 | for team in team_list: 32 | team_name_list.append({"id": team["id"], "name": team["name"]}) 33 | return team_name_list 34 | 35 | def parse_worker(data_list, header_list, team_ids): 36 | driver_data = {} 37 | vehicle_data = {} 38 | for data in data_list: 39 | data_index = data_list.index(data) 40 | header = header_list[data_index] 41 | # Team IDs are pre-selected 42 | driver_data["teams"] = team_ids 43 | 44 | # Vehicle information are stored in a dict 45 | if (header.startswith("vehicle", 0, len(header))): 46 | vehicle_header = header.replace("vehicle ", "") 47 | vehicle_data[vehicle_header] = data 48 | else: 49 | driver_data[header] = data 50 | driver_data["vehicle"] = vehicle_data 51 | return driver_data 52 | 53 | def write_result(result): 54 | with open("result.csv", mode="a") as result_file: 55 | employee_writer = csv.writer(result_file, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL) 56 | # Write error messages and request ID into the result file 57 | if ("request" in dir(result)): 58 | employee_writer.writerow([datetime.datetime.now(), result.status, result.message, result.request]) 59 | # Write the successful import into the result file 60 | else: 61 | employee_writer.writerow([datetime.datetime.now(), 200, "worker " + result["name"] + " was created using the phone number of " + result["phone"]]) 62 | 63 | def create_worker(body): 64 | # Call the API wrapper to create a worker 65 | try: 66 | result = api.workers.create(body=body) 67 | write_result(result) 68 | except Exception as err: 69 | write_result(err) 70 | 71 | def open_file_and_create_worker(file_name, team_ids): 72 | with open(file_name) as csv_file: 73 | csv_reader = csv.reader(csv_file, delimiter=custom_delimiter) 74 | line_count = 0 75 | for row in csv_reader: 76 | # First row of the CSV file is always the headers 77 | if (line_count == 0): 78 | header_list = row 79 | else: 80 | data_list = row 81 | body = parse_worker(data_list, header_list, team_ids) 82 | create_worker(body) 83 | line_count += 1 84 | 85 | def main(): 86 | print("==== Welcome to the ∞ Onfleet Driver Importer ====") 87 | print("==================================================") 88 | print("You are currently importing", csv_file) 89 | # Storing the teams in a list 90 | team_list = list_team() 91 | choices = [] 92 | team_ids_selected = [] 93 | for team in team_list: 94 | choices.append(team["name"]) 95 | 96 | # CLI loop 97 | while True: 98 | # Use the teams as our choices for the importer CLI 99 | questions = [ 100 | { 101 | "type": "list", 102 | "name": "team", 103 | "message": "Please select the team that you want to import drivers to:", 104 | "choices": choices 105 | } 106 | ] 107 | # Prompt users to make a selection 108 | answers = prompt(questions, style=style) 109 | # Add team ID to the selected list 110 | for team in team_list: 111 | if (answers["team"] == team["name"]): 112 | team_ids_selected.append(team["id"]) 113 | choices.remove(answers["team"]) 114 | ask_again = [ 115 | { 116 | "type": "confirm", 117 | "name": "repeat", 118 | "message": "Are there more teams to add?", 119 | "default": False 120 | } 121 | ] 122 | # Prompt users for multiple team addition 123 | repeat = prompt(ask_again, style=style) 124 | if repeat["repeat"] is False: 125 | break 126 | # Read the CSV and import workers 127 | open_file_and_create_worker(file_name, team_ids_selected) 128 | 129 | 130 | if __name__ == "__main__": 131 | main() -------------------------------------------------------------------------------- /api-tools/webhooks/python/testwebhooks.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, make_response 2 | import os 3 | import json 4 | app = Flask(__name__) 5 | 6 | # trigger id 0 7 | @app.route('/taskstart', methods=['GET','POST']) 8 | def taskstart(): 9 | # validate only 10 | if request.method == 'GET': 11 | return request.args.get('check','') 12 | elif request.method == 'POST': 13 | print('task start') 14 | print(json.dumps(request.get_json())) 15 | # warn_if_unverified(request) 16 | return ('',200) 17 | 18 | # trigger id 1 19 | @app.route('/taskETA', methods=['GET','POST']) 20 | def tasketa(): 21 | # validate only 22 | if request.method == 'GET': 23 | return request.args.get('check','') 24 | elif request.method == 'POST': 25 | print('task ETA') 26 | print(json.dumps(request.get_json())) 27 | #warn_if_unverified(request) 28 | return ('',200) 29 | 30 | # trigger id 2 31 | @app.route('/taskarrival', methods=['GET','POST']) 32 | def taskarrival(): 33 | # validate only 34 | if request.method == 'GET': 35 | print(request.args.get('check','')) 36 | return request.args.get('check','') 37 | elif request.method == 'POST': 38 | print('task arrival') 39 | print(json.dumps(request.get_json())) 40 | #warn_if_unverified(request) 41 | return ('',200) 42 | 43 | # trigger id 3 44 | @app.route('/taskcomplete', methods=['GET','POST']) 45 | def taskcomplete(): 46 | # validate only 47 | if request.method == 'GET': 48 | return request.args.get('check','') 49 | elif request.method == 'POST': 50 | print('task complete') 51 | print(json.dumps(request.get_json())) 52 | #warn_if_unverified(request) 53 | return ('',200) 54 | 55 | # trigger id 4 56 | @app.route('/taskfailed', methods=['GET','POST']) 57 | def taskfailed(): 58 | # validate only 59 | if request.method == 'GET': 60 | return request.args.get('check','') 61 | elif request.method == 'POST': 62 | print('task failed') 63 | print(json.dumps(request.get_json())) 64 | #warn_if_unverified(request) 65 | return ('',200) 66 | 67 | # trigger id 5 68 | @app.route('/workerduty', methods=['GET','POST']) 69 | def workerduty(): 70 | # validate only 71 | if request.method == 'GET': 72 | return request.args.get('check','') 73 | elif request.method == 'POST': 74 | print('worker duty') 75 | print(json.dumps(request.get_json())) 76 | #warn_if_unverified(request) 77 | return ('',200) 78 | 79 | # trigger id 6 80 | @app.route('/taskcreated', methods=['GET','POST']) 81 | def taskcreated(): 82 | # validate only 83 | if request.method == 'GET': 84 | return request.args.get('check','') 85 | elif request.method == 'POST': 86 | print('task created') 87 | print(json.dumps(request.get_json())) 88 | #warn_if_unverified(request) 89 | return ('',200) 90 | 91 | # trigger id 7 92 | @app.route('/taskupdated', methods=['GET','POST']) 93 | def taskupdated(): 94 | # validate only 95 | if request.method == 'GET': 96 | return request.args.get('check','') 97 | elif request.method == 'POST': 98 | print('task updated') 99 | print(json.dumps(request.get_json())) 100 | #warn_if_unverified(request) 101 | return ('',200) 102 | 103 | # trigger id 8 104 | @app.route('/taskdeleted', methods=['GET','POST']) 105 | def taskdeleted(): 106 | # validate only 107 | if request.method == 'GET': 108 | return request.args.get('check','') 109 | elif request.method == 'POST': 110 | print('task deleted') 111 | print(json.dumps(request.get_json())) 112 | #warn_if_unverified(request) 113 | return ('',200) 114 | 115 | # trigger id 9 116 | @app.route('/taskassigned', methods=['GET','POST']) 117 | def taskassigned(): 118 | # validate only 119 | if request.method == 'GET': 120 | return request.args.get('check','') 121 | elif request.method == 'POST': 122 | print('task assigned') 123 | print(json.dumps(request.get_json())) 124 | #warn_if_unverified(request) 125 | return ('',200) 126 | 127 | # trigger id 10 128 | @app.route('/taskunassigned', methods=['GET','POST']) 129 | def taskunassigned(): 130 | # validate only 131 | if request.method == 'GET': 132 | return request.args.get('check','') 133 | elif request.method == 'POST': 134 | print('task unassigned') 135 | print(json.dumps(request.get_json())) 136 | #warn_if_unverified(request) 137 | return ('',200) 138 | 139 | # trigger id 12 140 | @app.route('/taskdelayed', methods=['GET','POST']) 141 | def taskdelayed(): 142 | # validate only 143 | if request.method == 'GET': 144 | return request.args.get('check','') 145 | elif request.method == 'POST': 146 | print('task delayed') 147 | print(json.dumps(request.get_json())) 148 | #warn_if_unverified(request) 149 | return ('',200) 150 | 151 | # trigger id 13 152 | @app.route('/taskcloned', methods=['GET','POST']) 153 | def taskcloned(): 154 | # validate only 155 | if request.method == 'GET': 156 | return request.args.get('check','') 157 | elif request.method == 'POST': 158 | print('task cloned') 159 | print(json.dumps(request.get_json())) 160 | #warn_if_unverified(request) 161 | return ('',200) 162 | 163 | # trigger id 14 164 | @app.route('/smsrecipientresponsemissed', methods=['GET','POST']) 165 | def smsrecipientresponsemissed(): 166 | # validate only 167 | if request.method == 'GET': 168 | return request.args.get('check','') 169 | elif request.method == 'POST': 170 | print('SMS recipient response missed') 171 | print(json.dumps(request.get_json())) 172 | #warn_if_unverified(request) 173 | return ('',200) 174 | 175 | # trigger id 15 176 | @app.route('/workercreated', methods=['GET','POST']) 177 | def workercreated(): 178 | # validate only 179 | if request.method == 'GET': 180 | return request.args.get('check','') 181 | elif request.method == 'POST': 182 | print('Worker Created') 183 | print(json.dumps(request.get_json())) 184 | #warn_if_unverified(request) 185 | return ('',200) 186 | 187 | # trigger id 16 188 | @app.route('/workerdeleted', methods=['GET','POST']) 189 | def workerdeleted(): 190 | # validate only 191 | if request.method == 'GET': 192 | return request.args.get('check','') 193 | elif request.method == 'POST': 194 | print('Worker Deleted') 195 | print(json.dumps(request.get_json())) 196 | #warn_if_unverified(request) 197 | return ('',200) 198 | 199 | # trigger id 17 200 | @app.route('/smsrecipientoptout', methods=['GET','POST']) 201 | def smsrecipientoptout(): 202 | # validate only 203 | if request.method == 'GET': 204 | return request.args.get('check','') 205 | elif request.method == 'POST': 206 | print('SMS Recipient Opt Out') 207 | print(json.dumps(request.get_json())) 208 | #warn_if_unverified(request) 209 | return ('',200) 210 | 211 | # trigger id 18 212 | @app.route('/autodispatchjobcompleted', methods=['GET','POST']) 213 | def autodispatchjobcompleted(): 214 | # validate only 215 | if request.method == 'GET': 216 | return request.args.get('check','') 217 | elif request.method == 'POST': 218 | print('auto Dispatch Job Completed') 219 | print(json.dumps(request.get_json())) 220 | #warn_if_unverified(request) 221 | return ('',200) 222 | 223 | # trigger id 19 224 | @app.route('/taskbatchcreatejobcompleted', methods=['GET','POST']) 225 | def taskbatchcreatejobcompleted(): 226 | # validate only 227 | if request.method == 'GET': 228 | return request.args.get('check','') 229 | elif request.method == 'POST': 230 | print('task batch create job completed') 231 | print(json.dumps(request.get_json())) 232 | #warn_if_unverified(request) 233 | return ('',200) 234 | 235 | # trigger id 20 236 | @app.route('/routeoptimizationjobcompleted', methods=['GET','POST']) 237 | def routeOptimizationjobcompleted(): 238 | # validate only 239 | if request.method == 'GET': 240 | return request.args.get('check','') 241 | elif request.method == 'POST': 242 | print('route Optimization Job Completed') 243 | print(json.dumps(request.get_json())) 244 | #warn_if_unverified(request) 245 | return ('',200) 246 | 247 | # trigger id 21 248 | @app.route('/routeplancreated', methods=['GET','POST']) 249 | def routeplancreated(): 250 | # validate only 251 | if request.method == 'GET': 252 | return request.args.get('check','') 253 | elif request.method == 'POST': 254 | print('route Plan Created') 255 | print(json.dumps(request.get_json())) 256 | #warn_if_unverified(request) 257 | return ('',200) 258 | 259 | # trigger id 22 260 | @app.route('/routeplanstarted', methods=['GET','POST']) 261 | def routeplanstarted(): 262 | # validate only 263 | if request.method == 'GET': 264 | return request.args.get('check','') 265 | elif request.method == 'POST': 266 | print('route Plan Started') 267 | print(json.dumps(request.get_json())) 268 | #warn_if_unverified(request) 269 | return ('',200) 270 | 271 | # trigger id 23 272 | @app.route('/routeplancompleted', methods=['GET','POST']) 273 | def routeplancompleted(): 274 | # validate only 275 | if request.method == 'GET': 276 | return request.args.get('check','') 277 | elif request.method == 'POST': 278 | print('route Plan Completed') 279 | print(json.dumps(request.get_json())) 280 | #warn_if_unverified(request) 281 | return ('',200) 282 | 283 | # trigger id 24 284 | @app.route('/workerupdated', methods=['GET','POST']) 285 | def workerupdated(): 286 | # validate only 287 | if request.method == 'GET': 288 | return request.args.get('check','') 289 | elif request.method == 'POST': 290 | print('worker Updated') 291 | print(json.dumps(request.get_json())) 292 | #warn_if_unverified(request) 293 | return ('',200) 294 | 295 | # trigger id 25 296 | @app.route('/routeplanupdated', methods=['GET','POST']) 297 | def routeplanupdated(): 298 | # validate only 299 | if request.method == 'GET': 300 | return request.args.get('check','') 301 | elif request.method == 'POST': 302 | print('route plan updated') 303 | print(json.dumps(request.get_json())) 304 | #warn_if_unverified(request) 305 | return ('',200) 306 | 307 | # trigger id 26 308 | @app.route('/routeplanunassigned', methods=['GET','POST']) 309 | def routeplanunassigned(): 310 | # validate only 311 | if request.method == 'GET': 312 | return request.args.get('check','') 313 | elif request.method == 'POST': 314 | print('route Plan Unassigned') 315 | print(json.dumps(request.get_json())) 316 | #warn_if_unverified(request) 317 | return ('',200) 318 | 319 | # trigger id 27 320 | @app.route('/routeplanassigned', methods=['GET','POST']) 321 | def routeplanassigned(): 322 | # validate only 323 | if request.method == 'GET': 324 | return request.args.get('check','') 325 | elif request.method == 'POST': 326 | print('route Plan Assigned') 327 | print(json.dumps(request.get_json())) 328 | #warn_if_unverified(request) 329 | return ('',200) 330 | 331 | # trigger id 28 332 | @app.route('/routeplandelayed', methods=['GET','POST']) 333 | def routeplandelayed(): 334 | # validate only 335 | if request.method == 'GET': 336 | return request.args.get('check','') 337 | elif request.method == 'POST': 338 | print('route Plan Delayed') 339 | print(json.dumps(request.get_json())) 340 | #warn_if_unverified(request) 341 | return ('',200) 342 | 343 | # trigger id 29 344 | @app.route('/predictedtaskdelay', methods=['GET','POST']) 345 | def predictedtaskdelay(): 346 | # validate only 347 | if request.method == 'GET': 348 | return request.args.get('check','') 349 | elif request.method == 'POST': 350 | print('predicted Task Delay') 351 | print(json.dumps(request.get_json())) 352 | #warn_if_unverified(request) 353 | return ('',200) 354 | --------------------------------------------------------------------------------