Scheduling and Route Planning Planning Driver Routes and Jobs

This guide explains how the routing engine processes driver schedules. You'll learn how the system filters valid jobs, sanitizes location and time data, and calculates accurate arrival times using a multi-pass math engine.

flowchart TD
    A[Raw Job Data] --> B{Is Driver Job?}
    B -- Yes --> C[Filter & Categorize]
    B -- No --> Z[Skip]
    C --> D["Sanitize Addresses & Times"]
    D --> E["Pass 0: Shift Logic (Travel Times)"]
    E --> F["Pass 2: Final Route Mapping"]

Categorizing Jobs

Before calculating routes, the system evaluates incoming schedule data to determine which items require physical travel and which are administrative.

The engine categorizes jobs into several types based on their naming conventions and properties:

Job TypeDescriptionRouting Behavior
StandardRegular physical stops with a valid address.Full routing and travel time calculation applied.
NOE / Special"Notice of Entry" jobs (identified by empty occupancy).Duration is calculated precisely from planned start/end times.
Virtual / AnchorAdministrative blocks like "late start" or "early stop".Duration is forced to 0 to prevent "ghost blocks" in the schedule.
CancelledJobs marked as cancelled, "SDC" stage, or "day off".Skipped completely and removed from the route.

If a standard job lacks a valid location, manual address, or planned start time, the system will skip it. Always ensure your physical stops have valid location data.

Sanitizing Data

Raw schedule data can be messy. The routing engine applies a sanitation layer to ensure addresses and times are perfectly formatted before any math occurs.

Address Resolution

The system attempts to parse the location data as JSON to extract exact lat,lng coordinates. If coordinates aren't available, it falls back to the manual address string. It automatically strips out invalid placeholders like null, none, {}, or undefined.

Forced ETAs (Hard Starts)

Sometimes a driver must arrive at a specific time, regardless of standard travel calculations.

You can force a specific arrival time by adding an asterisk (*, , or ) to the job's start time text. The system recognizes this as a "Hard Start" (m_eta) and will adjust the entire day's schedule to ensure this requirement is met.

The Math Engine

Once the data is clean, the system uses a two-pass mathematical engine to calculate the final route.

  1. 1

    Sort the itinerary

    All valid jobs are sorted sequentially based on their predefined sort order. Any job lacking a specific sort order defaults to the end of the list.

  2. 2

    Pass 0: Shift Logic & Travel Times

    The engine simulates the route from the base start time. It calculates travel durations between stops (using the Google Maps API, or defaulting to 5 minutes if the address hasn't changed).

    If the driver is projected to miss their first Forced ETA (Hard Start), the system calculates a day_shift_mins value—shifting the driver's entire start time earlier to ensure they make the appointment.

  3. 3

    Pass 2: Final Mapping

    The engine applies the calculated shift to the base start time and runs through the itinerary one last time. It locks in the exact arrival times, departure times, and identifies the first and last physical stops of the day.

Example: Shift Logic Implementation

If you are integrating with this system or building your own routing script, here is a simplified Python example of how the Pass 0 Shift Logic calculates the required day shift:

# Pass 0: Shift Logic
temp_time = base_start_time
temp_addr = start_addr
day_shift_mins = 0

for job in all_jobs:
    # Skip travel math for virtual anchor jobs
    if job['is_v']:
        temp_time = max(temp_time, job['p_e_val'])
        continue
        
    # Calculate travel time (5 mins if same address, otherwise use API)
    if job['addr'] == temp_addr and job['addr'] != "":
        travel_mins = 5
    else:
        travel_mins = get_google_drive(temp_addr, job['addr'], temp_time, api_key)
        
    arrival_time = temp_time + timedelta(minutes=travel_mins)
    
    # If there's a forced ETA and we are late, calculate the required shift
    if job['m_eta'] and arrival_time < job['m_eta'] and day_shift_mins == 0:
        day_shift_mins = int((job['m_eta'] - arrival_time).total_seconds() / 60)
        arrival_time = job['m_eta']
        
    # Move forward in time for the next loop iteration
    temp_time = arrival_time + timedelta(minutes=job['dur'])
    temp_addr = job['addr']

The day_shift_mins adjustment is currently only calculated based on the first missed forced ETA in the route. Ensure your schedules are realistically planned to avoid cascading delays later in the day.