swiftops-backend / docs /api /tickets /WORK-LOCATION-DERIVATION.md
kamau1's picture
feat: auto-populate and verify ticket work locations from assignment arrival coordinates
f8f7bb6

Ticket Work Location Derivation

Overview

Automatically derives and verifies ticket work locations from field agent GPS arrival coordinates. This solves the problem of missing work location data when sales orders are created by external users without GPS coordinates.

Problem Statement

Sales orders often lack GPS coordinates because:

  • Created by external sales agents without location access
  • Created via web forms without GPS
  • Customer address is approximate, not exact work site

This leaves work_location_latitude and work_location_longitude NULL on tickets, making it impossible to:

  • Verify work was done at correct location
  • Generate accurate service maps
  • Track field agent movements
  • Validate service delivery

Solution

Use field agent arrival coordinates from ticket_assignments table to populate or verify ticket work locations.

Data Flow

Sales Order (no GPS) 
  β†’ Ticket Created (work_location = NULL)
  β†’ Agent Assigned
  β†’ Agent Travels to Site
  β†’ Agent Marks Arrival (GPS captured)
  β†’ Ticket Completed
  β†’ Work Location Derived/Verified βœ“

Implementation

1. Derive Missing Locations

When ticket is completed and has no work location:

  • Copy arrival_latitude/longitude from assignment to ticket
  • Set work_location_verified = true (GPS is reliable)
# Example from logs.sql
Ticket: f59b29fc-d0b9-4618-b0d1-889e340da612
  work_location_latitude: NULL
  work_location_longitude: NULL

Assignment: a82a3824-f4f1-4283-a2e3-8c348dbb28ce
  arrival_latitude: -1.10056144256674
  arrival_longitude: 37.0092363654176

Result after completion:
  work_location_latitude: -1.10056144256674
  work_location_longitude: 37.0092363654176
  work_location_verified: true

2. Verify Existing Locations

When ticket is completed and has work location:

  • Calculate distance between work location and arrival coordinates
  • If within 100m threshold β†’ set work_location_verified = true
  • If beyond 100m β†’ log warning, keep work_location_verified = false
# Example verification
Ticket work location: (-1.10052333, 37.00922667)
Agent arrival: (-1.10056144, 37.00923637)
Distance: 52 meters βœ“

Result: work_location_verified = true

Distance Threshold

100 meters - Same building/compound

  • Accounts for GPS accuracy variations (Β±50m typical)
  • Allows for work at different points in same property
  • Strict enough to catch wrong locations

Alternative thresholds considered:

  • 50m: Too strict, GPS accuracy issues
  • 200m: Too loose, could miss wrong locations
  • 500m: Way too loose, different neighborhoods

When It Runs

Location derivation/verification happens automatically at:

  1. Legacy completion (complete_assignment in ticket_assignment_service.py)

    • Agent completes via mobile app
    • Runs before ticket marked complete
  2. New completion (complete_ticket in ticket_completion_service.py)

    • PM/Admin completes via dashboard
    • Runs after validation, before subscription creation

Service: TicketLocationService

Located: src/app/services/ticket_location_service.py

Methods

haversine_distance(lat1, lon1, lat2, lon2) -> float

Calculate distance between two GPS coordinates in meters.

derive_work_location_from_assignment(ticket, assignment) -> (bool, str)

Copy arrival coordinates to ticket work location.

verify_work_location_against_arrival(ticket, assignment) -> (bool, str, float)

Compare existing work location with arrival, verify if within threshold.

update_work_location_on_completion(ticket, assignment) -> dict

Main entry point - derives or verifies based on ticket state.

Benefits

  1. Automatic - No manual intervention needed
  2. Accurate - Uses actual GPS from field agents
  3. Verified - Validates existing coordinates
  4. Audit Trail - Logs all actions for debugging
  5. Backward Compatible - Works with existing tickets

Edge Cases

No Arrival Coordinates

If agent never marked arrival:

  • Location derivation skipped
  • Warning logged
  • Ticket completes normally (not blocked)

Multiple Assignments (Team Tickets)

Uses first active assignment with arrival coordinates.

Assignment Without Journey

If agent completed without starting journey:

  • Arrival coordinates may be missing
  • Falls back to journey start coordinates if available
  • Otherwise skips location update

Testing

Unit tests: tests/unit/test_ticket_location_service.py

Tests cover:

  • Distance calculation accuracy
  • Derivation logic
  • Verification logic
  • Edge cases (missing data, far distances)

Future Enhancements

  1. Configurable threshold - Allow per-project distance thresholds
  2. Multiple verification points - Use journey breadcrumbs for better accuracy
  3. Geofencing - Alert if arrival is far from expected location
  4. Historical analysis - Track location accuracy over time

Example Logs

INFO: Work location update for ticket f59b29fc: 
  action=derived, success=True, 
  message=Work location derived from arrival coordinates

INFO: Work location update for ticket 8f08ad14: 
  action=verified, success=True, 
  message=Work location verified (distance: 52.34m)

WARNING: Work location verification failed for ticket abc123: 
  distance=245.67m exceeds threshold=100m

Related Files

  • src/app/services/ticket_location_service.py - Core logic
  • src/app/services/ticket_assignment_service.py - Legacy completion integration
  • src/app/services/ticket_completion_service.py - New completion integration
  • src/app/models/ticket.py - Ticket model with work location fields
  • src/app/models/ticket_assignment.py - Assignment model with arrival coordinates