Skip to main content

Overview

The Tractors API provides endpoints for managing tractor-to-vehicle mappings and fault code synchronization. Tractors represent power units (trucks) that are tracked via Terminal API and matched to McLeod TMS data. Database Table: tractors Key Columns:
  • vehicle_id - Terminal API vehicle ID (e.g., vcl_xxx)
  • mcleod_tractor_id - McLeod tractor ID (e.g., 735)
  • latitude, longitude - GPS coordinates
  • fault_codes - PostgreSQL TEXT[] array of fault code descriptions
Mapping Concept:
  • Terminal API provides vehicles with IDs like vcl_01D8ZQFGHVJ858NBF2Q7DV9MNC
  • McLeod TMS uses tractor IDs like 735
  • The mapping service connects these two systems by normalizing vehicle names

Sync Tractor Mapping

POST /api/tractors/sync-mapping

Sync tractor-to-vehicle mappings. Only updates tractors that have movements in the database. Use this endpoint when you want to selectively update tractors that are actively assigned to movements. Response:
{
  "terminal_vehicles_fetched": 100,
  "mcleod_tractors_found": 75,
  "mappings_created": 60,
  "ambiguous_mappings": 5,
  "errors": 0,
  "ambiguous_names": ["Tractor 123 (Unit A)", "Tractor 123 (Unit B)"]
}
How it works:
  1. Fetch Terminal Vehicles: Calls Terminal API /tsp/v1/vehicles to get all vehicles
  2. Normalize Names: Extracts tractor numbers from vehicle names:
    • “Tractor 735” → “735”
    • “TRK-00735” → “735”
    • “Truck #0735” → “735”
  3. Get McLeod Tractors: Queries movements table for distinct __tractorid values
  4. Match: Compares normalized numbers to McLeod tractor IDs
  5. Update Database: Calls update_tractor_mapping() to set mcleod_tractor_id for matching vehicles
  6. Handle Ambiguity: If multiple Terminal vehicles normalize to the same number, mapping is skipped and logged
Normalization Algorithm:
  • Extracts last contiguous digits from vehicle name
  • Removes leading zeros
  • Example: “FLEET-TRUCK-00735-WEST” → “735”

Sync All Vehicle Names

POST /api/tractors/sync-vehicle-names

Sync Terminal vehicle names directly to mcleod_tractor_id. Updates ALL tractors regardless of movement assignments. Use this endpoint when you want to update the entire tractors table with Terminal vehicle names. Response:
{
  "success": true,
  "message": "Terminal vehicle names synced to mcleod_tractor_id successfully",
  "data": {
    "vehicles_fetched": 120,
    "vehicles_updated": 115,
    "errors": 5
  }
}
How it works:
  1. Fetches all vehicles from Terminal API /tsp/v1/vehicles
  2. For each vehicle, sets tractors.mcleod_tractor_id = vehicle.name
  3. Uses update_tractor_mcleod_id_from_terminal_name() which:
    • Updates existing tractor if vehicle_id matches
    • Creates new tractor record if not found
Difference from sync-mapping:
  • sync-mapping: Only updates tractors with matching movements (selective)
  • sync-vehicle-names: Updates ALL tractors with Terminal vehicle names (comprehensive)

Get Mapping Stats

GET /api/tractors/mapping-stats

Get aggregate statistics about current tractor mappings. Response:
{
  "total_tractors": 120,
  "mcleod_mapped_count": 110,
  "terminal_mapped_count": 105,
  "fully_mapped_count": 98,
  "unmapped_count": 10,
  "mcleod_mapped_percentage": 91.67,
  "terminal_mapped_percentage": 87.5,
  "fully_mapped_percentage": 81.67,
  "needs_sync": true
}
Field Descriptions:
FieldDescription
total_tractorsTotal rows in tractors table
mcleod_mapped_countTractors with non-empty mcleod_tractor_id
terminal_mapped_countTractors with non-empty vehicle_id
fully_mapped_countTractors with both IDs mapped
unmapped_countTractors with neither ID
needs_synctrue if fully_mapped_percentage < 80%
How it works:
  1. Queries tractors table with SQL aggregation
  2. Uses CASE statements to count mapping states
  3. Calculates percentages and needs_sync threshold
  4. Calls get_tractor_mapping_count_metrics() and get_tractor_mapping_health()

Sync Fault Codes

POST /api/tractors/fault-codes/sync

Sync fault codes from Motive API to the tractors table.
vehicle_ids
string
default:"None"
Comma-separated list of Motive vehicle IDs to filter for
status
string
default:"None"
Filter by fault code status (e.g., active, closed)
limit
integer
default:"None"
Maximum number of fault codes to fetch (max: 1000)
Response:
{
  "success": true,
  "message": "Fault codes synced successfully",
  "data": {
    "fetched": 25,
    "synced": 20,
    "errors": 5
  }
}
How it works:
  1. Calls Motive API /v1/vehicle_diagnostics/fault_codes via MotiveClient
  2. For each fault code, extracts description field
  3. Matches fault codes to tractors via mcleod_id
  4. Appends descriptions to tractors.fault_codes PostgreSQL array via append_fault_codes_to_tractor()
  5. Deduplicates entries (won’t add same description twice)
Data Flow:
Motive API (/v1/vehicle_diagnostics/fault_codes)

MotiveClient.get_fault_codes()

sync_fault_codes() service

append_fault_codes_to_tractor() → tractors.fault_codes (TEXT[] array)
Automatic Sync: Fault codes are also synced automatically after each location poll cycle in LocationPollingService._fetch_and_process_locations().

Get Fault Codes

GET /api/tractors/fault-codes

Get fault codes for a specific tractor by vehicle_id.
vehicle_id
string
required
Terminal vehicle ID (e.g., vcl_01D8ZQFGHVJ858NBF2Q7DV9MNC)
Response:
{
  "vehicle_id": "vcl_01D8ZQFGHVJ858NBF2Q7DV9MNC",
  "fault_codes": [
    "Engine coolant temperature above threshold",
    "Exhaust gas recirculation valve position sensor",
    "Diesel particulate filter regeneration required"
  ]
}
How it works:
  1. Queries tractors table by vehicle_id
  2. Returns fault_codes array (PostgreSQL TEXT[])
  3. Handles backward compatibility with JSON and comma-separated string formats
  4. Returns 404 if tractor not found

Data Model

Tractors Table Schema

ColumnTypeDescription
idUUIDPrimary key
company_idVARCHARAlways “TERM” for Terminal data
vehicle_idVARCHARTerminal vehicle ID (unique)
mcleod_tractor_idVARCHARMcLeod tractor ID
latitudeNUMERIC(10,8)GPS latitude
longitudeNUMERIC(11,8)GPS longitude
fuel_levelNUMERICFuel percentage
odometer_milesNUMERICOdometer reading
engine_hoursNUMERICEngine hours
last_located_atTIMESTAMPTZLast location timestamp
last_location_providerVARCHAR”terminal” or “movement_stop”
fault_codesTEXT[]Array of fault descriptions
updated_atTIMESTAMPTZLast DB update

Location Provider Priority

  1. Terminal GPS (authoritative): Updated by LocationPollingService every 60 seconds
  2. Movement Stop Fallback: When Terminal GPS unavailable, uses stop coordinates from McLeod movements
The last_location_provider column indicates which source provided the current location.