# AI Transport Planning

Two cooperating modules in **Transport → AI Planning** that propose optimized workforce transportation routes and driver schedules. Everything they produce is a **draft recommendation** until a manager approves it.

| Module | What it does |
|--------|----------------|
| **AI Route Optimization** | Uses contract sites, assigned staff and shifts; plans garage→site vehicle runs, fuel and cost |
| **AI Scheduling Assistant** | Assigns drivers, balances workloads, validates conflicts, recommends replacements |

---

## Database setup

Import the AI schema once (safe to re-run):

```
app/Database/sql/transport_ai.sql
```

Use phpMyAdmin or MySQL CLI against your ERP database (e.g. `erp_foundation`). This creates contract site mappings, AI settings, plan tables, distance cache, and `transport_ai.*` permissions.

---

## Before you generate a plan

Set up these first. The **Generate Plan** screen shows readiness cards for each.

| Setup | Navigation | Why |
|-------|------------|-----|
| **Contract sites** | Transport → AI Planning → Contract Sites | Each contract maps to a destination location (with coordinates) and preferably a default shift |
| **Staff on contracts** | Contracts → staff assignment | Active employees assigned via `contract_employees`; set **transport leg** (both / outbound only / return only) per person |
| **Shift timing** | Contract site default shift (preferred), else HRM shift assignments | Site timing drives the run; staff without a site default need an HR shift |
| **Vehicles & drivers** | Transport → Fleet | Active vehicles with capacity; active drivers with valid licenses |
| **AI settings** | Transport → AI Planning → AI Settings | Fuel/cost rates, timing buffers, **default base garage**, OSRM routing URL, optional LLM for summaries |

Also helpful:

- At least one **depot** location with coordinates (`transport_locations`, type `depot`), and optionally set **Default Base Stop** in AI Settings so every route starts and ends at the same garage
- Contract start/end dates (out-of-range dates are skipped)

Contracts **without a site mapping** are not planned. Staff **without a shift** (and no site default shift) are skipped with a warning.

The planner does **not** use employee pickup points.

---

## How to use it

1. Configure contract sites (with default shifts), assign staff on contracts, fleet, and settings.
2. Go to **Transport → AI Planning → AI Transport Plans → Generate Plan**.
3. Pick a **region** (e.g. Budaiya, Juffair) and a **batch size** (10, 20, or 40). The form auto-selects up to that many contracts in the region.
4. Pick a date range (1 day, or up to 31 days).
5. Review the draft plan.
6. **Submit for Approval** (draft → pending).
7. Manager **Approve & Publish** (requires `transport_ai.approve` + TPIN) → official schedules are created.

**Plan statuses:** `draft` → `pending_approval` → `approved` or `rejected`

Only **Approve & Publish** writes to the official transport schedule. Until then, the plan is read-only recommendations.

---

## How the engine works

```
Inputs (contract sites, assigned staff, transport legs, shifts, fleet, existing schedules)
    → Route Optimization (multi-site packing, base→sites→return pickups, timing, costing)
    → Scheduling Assistant (driver assignment, conflict validation)
    → Draft plan (routes, passenger list, conflicts, summary)
    → Manager review
    → Approve → Official transport_schedules (+ transport_routes)
```

### Route Optimization

For each service date and **shift group** (sites sharing the same shift are combined), the engine:

1. Loads **active staff assigned** on each contract (`contract_employees`), including each person's **transport leg**:
   - `both` — boards at base in the morning and is picked up on the return trip
   - `outbound_only` — morning drop at the contract site only
   - `return_only` — picked up at the contract site on the return leg only
2. Groups staff by **shift** using the **contract site's default shift** when set; otherwise each employee's HR shift assignment for that date.
3. **Packs** multiple contract sites into one van when capacity allows (peak outbound load and peak return load).
4. Plans **outbound**: fixed base → Site A (drop) → Site B (drop) → … using nearest-neighbor ordering.
5. Plans **return**: last outbound site → optional pickups at other sites (return staff) → base.
6. **Times** the outbound leg backwards from shift start minus the arrival buffer.
7. **Times** return pickups after shift end.
8. **Estimates** fuel (L/100 km per vehicle or type default) and transportation cost.

Set **Default Base Stop** in AI Settings to force all routes to use one garage. If unset, the nearest depot to the site cluster is used.

**Road distances** come from OSRM (`transport_ai_settings.osrm_base_url`, default `https://router.project-osrm.org`). Results are cached in `transport_distance_cache`. If OSRM is unreachable, straight-line distance × road factor is used and a warning is recorded — plan generation still completes.

**Hard constraints enforced during construction:**

- Never exceed vehicle capacity
- Staff must arrive at the site before shift start (minus buffer)
- Route duration must fit within driver daily minute limits

### Scheduling Assistant

After routes are built:

1. **Assigns** the best available driver: license matches vehicle type, license not expired, no schedule overlap, lowest workload that day/week.
2. **Re-checks** vehicles; auto-swaps to a free replacement when the chosen vehicle is double-booked.
3. **Validates** every rule and records structured conflicts with recommended fixes.
4. **Writes** an optimization summary (template, or optional OpenAI-compatible LLM if configured in AI Settings).

The LLM only generates narrative text. Route math and scheduling logic always run locally in PHP.

---

## What the plan review shows

Open a plan from **AI Transport Plans** to see the full transportation proposal.

### Fleet summary (KPI cards)

- Total routes, employees, vehicles used, drivers used
- Total distance (km), travel time (minutes)
- Estimated fuel (litres) and transportation cost

### Optimization summary

Short prose on efficiency, utilisation, savings, and improvement suggestions.

### Conflicts detected

Errors and warnings, for example:

- Driver unavailable, license expired, or license/vehicle mismatch
- Vehicle double-booked, under maintenance, or insufficient capacity
- Late arrival risk
- Driver overtime risk

Each entry can include **recommended solutions** (replacement driver or vehicle).

### Optimized routes

Per route:

| Field | Description |
|-------|-------------|
| Route name | e.g. `Contract Title – Shift Name – Route 1` |
| Starting location | Depot or vehicle parking position |
| Assigned staff / boarding | Staff list with boarding time at the garage |
| Destination | Contract site |
| Assigned vehicle | Registration, type, capacity |
| Recommended driver | Name and license class |
| Employee count | Passengers vs vehicle capacity |
| Total distance | km (outbound + return) |
| Estimated travel time | minutes |
| Estimated fuel | litres |
| Estimated cost | fuel + per-km cost |
| Departure / arrival | Outbound times vs shift start |
| Return trip | Departure and arrival back at depot |

### Route map

Leaflet map with garage→site road geometry (when OSRM succeeded) and boarding markers.

### Driver schedule

Daily timetable per driver: departure, arrival, return departure, return arrival, plus workload balance across the plan period.

### Vehicle assignments

Which vehicle runs which route and seat utilisation.

### Boarding schedule

Staff boarding time at the garage/depot for each site run.

### Arrival schedule

Site arrival vs shift start, with early/late margin in minutes.

---

## What happens on approval

When a manager approves (with TPIN):

1. Plan status → `approved`
2. One **official transport schedule** per route is created (`transport_schedules`, status `planned`) with **outbound and return times** (`departure_time`, `arrival_time`, `return_departure_time`, `return_arrival_time`, plus shift start/end)
3. All **transport legs** (board / drop / return pickup) are copied to `transport_schedule_stops`
4. A reusable **transport route** is saved (`transport_routes` + geometry)
5. `published_schedule_id` is stored on each plan route row

Trips then appear under **Transport → Scheduling** with the same leg detail as the AI plan review. The AI does not auto-confirm, start, or complete trips.

### Hand the schedule to drivers

Use **Transport → Operations → Driver Schedule Export** (also linked from Scheduling):

1. Choose **All drivers** or one **selected driver**
2. Set the date range (and optional status)
3. Preview the trips grouped by driver
4. Download **PDF**, **CSV**, or **Word** for the handoff pack

Exports include trip number, date, outbound and return times, route, vehicle, status, and the full transport-leg list (board / drop / return pickup).

### Change indicators on the scheduling screen

Every driver schedule published by an AI plan is marked with a red badge on **Transport → Scheduling**:

- **New** (red, pulsing) — a fresh trip was added for the driver
- **Changed** (red, pulsing) — the driver already had trips that day, so their day plan changed

A red banner at the top counts how many schedules were added or changed. The badges are cleared automatically once the rows have been displayed to you — they show exactly once, then vanish.

Rejected plans store a rejection reason and can be deleted. Draft and rejected plans can be removed without affecting official schedules.

---

## AI settings reference

| Setting | Default | Effect |
|---------|---------|--------|
| Fuel price per litre | 0.200 | Cost calculation |
| Cost per km | 0.050 | Maintenance, wear, tolls |
| Consumption per vehicle type | 8–25 L/100 km | Fuel estimate when vehicle has no override |
| Driver max daily minutes | 480 | Overtime prevention |
| Pickup service minutes | 3 | Boarding dwell at the garage before departure |
| Arrival buffer minutes | 15 | Arrive this many minutes before shift start |
| Road factor | 1.35 | Straight-line multiplier when OSRM unavailable |
| Average speed km/h | 40 | Duration fallback when OSRM unavailable |
| OSRM base URL | router.project-osrm.org | Road distance/time provider |
| LLM provider | none | Optional richer summary only |

Per-vehicle fuel consumption can be set on the vehicle record (`fuel_consumption_l_per_100km`); it overrides the type default.

---

## Permissions

| Permission | Purpose |
|------------|---------|
| `transport_ai.view` | View plans and contract sites |
| `transport_ai.generate` | Generate plans, manage contract sites, submit for approval |
| `transport_ai.approve` | Approve or reject plans (with TPIN) |
| `transport_ai.settings` | Edit AI planner settings |

Administrator receives all `transport_ai.*` permissions when `transport_ai.sql` is applied.

---

## Tips

- **Daily plan:** same start and end date.
- **Weekly plan:** e.g. Monday–Sunday (max 31 days per run).
- Low seat utilisation (&lt; 60%) triggers a recommendation to merge routes or use smaller vehicles.
- If OSRM is down, plans still generate with estimated distances; review the routing fallback warning.
- For heavy use, point **OSRM base URL** to a self-hosted OSRM instance instead of the public server.

---

## Navigation

| Screen | Path |
|--------|------|
| AI Transport Plans | `/transport/ai/plans` |
| Generate Plan | `/transport/ai/plans/generate` |
| Contract Sites | `/transport/ai/contract-sites` |
| AI Settings | `/transport/ai/settings` |
| Driver Schedule Export | `/transport/scheduling/export` |
