'decimal:7', 'longitude' => 'decimal:7', 'speed' => 'float', 'bearing' => 'float', 'accuracy' => 'float', 'altitude' => 'float', 'battery_level' => 'integer', 'is_charging' => 'boolean', 'recorded_at' => 'datetime', ]; /* |-------------------------------------------------------------------------- | Relationships |-------------------------------------------------------------------------- */ public function rider(): BelongsTo { return $this->belongsTo(Rider::class, 'rider_id'); } public function delivery(): BelongsTo { return $this->belongsTo(Delivery::class, 'delivery_id'); } /* |-------------------------------------------------------------------------- | Scopes |-------------------------------------------------------------------------- */ public function scopeForRider($query, int $riderId) { return $query->where('rider_id', $riderId); } public function scopeForDelivery($query, int $deliveryId) { return $query->where('delivery_id', $deliveryId); } public function scopeRecent($query, int $minutes = 60) { return $query->where('recorded_at', '>=', now()->subMinutes($minutes)); } public function scopeInDateRange($query, $startDate, $endDate) { return $query->whereBetween('recorded_at', [$startDate, $endDate]); } public function scopeHighAccuracy($query, float $maxAccuracy = 50) { return $query->where('accuracy', '<=', $maxAccuracy); } /* |-------------------------------------------------------------------------- | Methods |-------------------------------------------------------------------------- */ public function getCoordinates(): array { return [ 'lat' => $this->latitude, 'lng' => $this->longitude, ]; } public function hasLowBattery(): bool { return $this->battery_level !== null && $this->battery_level < 20; } public function hasPoorAccuracy(): bool { return $this->accuracy !== null && $this->accuracy > 50; } public function distanceTo(float $latitude, float $longitude): float { $earthRadius = 6371; // km $dLat = deg2rad($latitude - $this->latitude); $dLng = deg2rad($longitude - $this->longitude); $a = sin($dLat / 2) * sin($dLat / 2) + cos(deg2rad($this->latitude)) * cos(deg2rad($latitude)) * sin($dLng / 2) * sin($dLng / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return round($earthRadius * $c, 3); } public static function getTrackingPath(int $deliveryId): array { return static::forDelivery($deliveryId) ->orderBy('recorded_at') ->get() ->map(fn ($log) => [ 'lat' => $log->latitude, 'lng' => $log->longitude, 'timestamp' => $log->recorded_at->toIso8601String(), 'speed' => $log->speed, ]) ->toArray(); } public static function calculateTotalDistance(int $deliveryId): float { $logs = static::forDelivery($deliveryId) ->orderBy('recorded_at') ->get(); if ($logs->count() < 2) { return 0; } $totalDistance = 0; $previousLog = null; foreach ($logs as $log) { if ($previousLog) { $totalDistance += $log->distanceTo( $previousLog->latitude, $previousLog->longitude ); } $previousLog = $log; } return round($totalDistance, 2); } }