Skip to content

feat: Intelligent Order Allocation Engine — engine-agnostic, core FleetOps integration#217

Open
roncodes wants to merge 1 commit intomainfrom
feat/intelligent-order-allocation-engine
Open

feat: Intelligent Order Allocation Engine — engine-agnostic, core FleetOps integration#217
roncodes wants to merge 1 commit intomainfrom
feat/intelligent-order-allocation-engine

Conversation

@roncodes
Copy link
Copy Markdown
Member

Overview

Implements the Intelligent Order Allocation Engine as described in issue #214. This PR integrates the feature directly into core FleetOps (not as a separate extension) and introduces a fully engine-agnostic architecture that allows any third-party solver to register itself alongside the default VROOM implementation.

Prerequisite: This PR depends on #216 (Driver Scheduling Integration). The AllocationPayloadBuilder calls Driver::activeShiftFor() to inject shift time_window constraints into the solver payload. Without #216, shift-aware allocation will silently degrade to unconstrained allocation (no error thrown).


Architecture: Engine-Agnostic Registry Pattern

The allocation engine architecture mirrors the existing route-optimization registry pattern already in FleetOps:

Layer Route Optimization (existing) Order Allocation (new)
Interface RouteOptimizationInterfaceService AllocationEngineInterfaceService
Registry route-optimization service allocation-engine service
Default engine OSRM VROOM
Registration register-osrm.js initializer register-vroom-allocation.js initializer
Backend interface AllocationEngineInterface PHP contract
Backend registry AllocationEngineRegistry PHP singleton

A third-party engine integrates by:

  1. Implementing AllocationEngineInterface (PHP) and AllocationEngineInterfaceService (JS)
  2. Registering via ->register(new MyEngine()) in a service provider (PHP)
  3. Registering via allocationEngine.register('my-engine', myEngineService) in an instance initializer (JS)
  4. The engine appears in the FleetOps allocation settings dropdown automatically

Backend Changes (server/)

New: server/src/Allocation/

File Purpose
Contracts/AllocationEngineInterface.php PHP interface: allocate(), getName(), getIdentifier()
AllocationEngineRegistry.php Singleton registry: register(), resolve(), has(), available()
Support/AllocationPayloadBuilder.php Engine-agnostic normalizer: builds jobs/vehicles from Eloquent models, maps custom fields to skill codes, injects driver shift time_windows
Engines/VroomAllocationEngine.php Default VROOM implementation: constructs VRP payload, calls VROOM HTTP API, maps response to standard result shape

New: server/src/Http/Controllers/Internal/v1/AllocationController.php

Six endpoints under /int/v1/fleet-ops/allocation/:

  • POST run — run engine against unassigned orders + online vehicles
  • POST commit — commit assignments via Order::firstDispatchWithActivity()
  • GET preview — preview without side effects
  • GET engines — list registered engines
  • GET settings — get allocation settings
  • PATCH settings — save allocation settings

New: server/src/Jobs/ProcessAllocationJob.php

Queueable, idempotent background job. Reads active engine from Setting::lookup('fleetops.allocation_engine', 'vroom'). Used for auto-allocation on order creation and re-allocation on delivery completion.

New: server/src/Listeners/HandleDeliveryCompletion.php

Listens on OrderCompleted. When auto_reallocate_on_complete is enabled, dispatches ProcessAllocationJob — closing the re-allocation loop so drivers are automatically assigned the next batch of orders as they complete deliveries.

Modified: server/src/Providers/EventServiceProvider.php

Adds HandleDeliveryCompletion to the OrderCompleted listener array.

Modified: server/src/Providers/FleetOpsServiceProvider.php

  • Registers AllocationEngineRegistry as a singleton in register()
  • Registers VroomAllocationEngine via resolving() hook in boot()

Modified: server/src/routes.php

Adds /allocation route group with 6 endpoints under the internal v1 fleet-ops prefix.


Frontend Changes (addon/)

New Services

File Purpose
services/allocation-engine-interface.js Abstract base class with allocate() contract
services/allocation-engine.js Registry: register(), resolve(), has(), availableEngines
services/vroom-allocation-engine.js VROOM adapter — delegates to backend AllocationController
services/order-allocation.js Orchestration: run, commit, loadSettings, saveSettings tasks

New Instance Initializer

instance-initializers/register-vroom-allocation.js — registers VROOM into the allocation-engine registry at app boot. Identical pattern to register-osrm.js.

New: Dispatcher Workbench

components/order-allocation-workbench.{js,hbs} — three-panel UI:

  • Left panel (Order Bucket): unassigned orders, draggable
  • Centre panel (Proposed Plan): per-vehicle route cards with sequence, arrival time, override badges; unassigned warning banner
  • Right panel (Vehicle Bucket): available vehicles with online driver status
  • Toolbar: Run Allocation, Commit Plan, Discard Plan, Refresh
  • Drag-and-drop override: dispatcher can reassign any order to any vehicle before committing

New: Allocation Settings Page

  • controllers/settings/order-allocation.js — engine selector (from registry), auto-allocate toggles, max travel time, workload balancing
  • templates/settings/order-allocation.hbs — settings form with ContentPanel layout

Route/Navigation Wiring

File Change
routes.js Adds operations.allocation and settings.order-allocation
routes/operations/allocation.js Ability-guarded route
routes/settings/order-allocation.js Ability-guarded route with setupController hook
templates/operations/allocation.hbs Renders OrderAllocationWorkbench
extension.js Adds Allocation shortcut tile; registers fleet-ops:template:settings:order-allocation
components/layout/fleet-ops-sidebar.js Adds Allocation to Operations nav; Order Allocation to Settings nav

How Third-Party Engines Register

PHP (service provider):

$this->app->resolving(AllocationEngineRegistry::class, function ($registry) {
    $registry->register(new MyCustomAllocationEngine());
});

JavaScript (instance initializer):

export function initialize(appInstance) {
    const allocationEngine = appInstance.lookup('service:allocation-engine');
    const myEngine = appInstance.lookup('service:my-allocation-engine');
    allocationEngine.register('my-engine', myEngine);
}

The engine then appears in the FleetOps allocation settings dropdown automatically.


Closes #214
Depends on #216

…etOps integration

## Backend

### Allocation Engine Architecture (server/src/Allocation/)
- AllocationEngineInterface: defines the allocate()/getName()/getIdentifier() contract
- AllocationEngineRegistry: singleton service-locator; engines register via resolving() hook
- AllocationPayloadBuilder: engine-agnostic normalizer — builds jobs/vehicles arrays from
  Order/Vehicle models, reads custom fields for skill codes, injects driver shift time_windows
  from Driver::activeShiftFor() (prerequisite: PR #216 driver scheduling integration)
- VroomAllocationEngine: default VROOM implementation; maps normalized payload to VROOM VRP
  wire format, handles integer ID mapping, parses routes/unassigned back to public_ids

### AllocationController (server/src/Http/Controllers/Internal/v1/)
- POST   fleet-ops/allocation/run      — run engine against unassigned orders + online vehicles
- POST   fleet-ops/allocation/commit   — commit assignments via Order::firstDispatchWithActivity()
- GET    fleet-ops/allocation/preview  — preview without side effects
- GET    fleet-ops/allocation/engines  — list registered engines (for settings dropdown)
- GET    fleet-ops/allocation/settings — get allocation settings
- PATCH  fleet-ops/allocation/settings — save allocation settings

### ProcessAllocationJob (server/src/Jobs/)
- Queueable, idempotent background job for auto-allocation on order creation or re-allocation
- Reads active engine from Setting::lookup('fleetops.allocation_engine', 'vroom')

### HandleDeliveryCompletion (server/src/Listeners/)
- Listens on OrderCompleted; dispatches ProcessAllocationJob when
  auto_reallocate_on_complete is enabled — closes the re-allocation loop

### Provider/Route wiring
- FleetOpsServiceProvider: registers AllocationEngineRegistry singleton + VroomAllocationEngine
- EventServiceProvider: adds HandleDeliveryCompletion to OrderCompleted listeners
- routes.php: adds /allocation group with 6 endpoints under internal v1 fleet-ops prefix

## Frontend

### Engine Registry Pattern (addon/services/)
- allocation-engine-interface.js: abstract base class with allocate() contract
- allocation-engine.js: registry service — register()/resolve()/has()/availableEngines
- vroom-allocation-engine.js: VROOM adapter — delegates to backend AllocationController
- order-allocation.js: orchestration service — run/commit/loadSettings/saveSettings tasks

### Instance Initializer (addon/instance-initializers/)
- register-vroom-allocation.js: registers VroomAllocationEngine into the allocation-engine
  registry at app boot — identical pattern to register-osrm.js for route optimization

### Dispatcher Workbench (addon/components/)
- order-allocation-workbench.js: three-panel workbench with Order Bucket, Proposed Plan view,
  Vehicle Bucket; runAllocation/commitPlan/discardPlan tasks; handleDrop for drag-and-drop
  override; planByVehicle computed groups assignments by vehicle for the plan view
- order-allocation-workbench.hbs: full Handlebars template with toolbar, three panels,
  per-vehicle route cards, unassigned warning banner, override badges, empty states

### Settings UI (addon/controllers/settings/ + addon/templates/settings/)
- order-allocation.js controller: loadSettings/saveSettings tasks, engineOptions from registry
- order-allocation.hbs template: engine selector (PowerSelect from registry), auto-allocate
  toggles, max travel time input, balance workload toggle

### Route/Navigation wiring
- routes.js: adds operations.allocation and settings.order-allocation routes
- routes/operations/allocation.js: ability-guarded route
- routes/settings/order-allocation.js: ability-guarded route with setupController hook
- templates/operations/allocation.hbs: renders OrderAllocationWorkbench
- extension.js: adds Allocation shortcut tile + fleet-ops:template:settings:order-allocation registry
- layout/fleet-ops-sidebar.js: adds Allocation to operations nav, Order Allocation to settings nav

Closes #214
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intelligent Order Allocation Engine — Configurable VRP-Powered Auto-Dispatch

1 participant