Files
kulakpos_web/public/restaurant/Modules/RestaurantDelivery/app/Models/LocationLog.php

174 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Modules\RestaurantDelivery\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class LocationLog extends Model
{
use HasFactory;
public const TABLE_NAME = 'restaurant_rider_location_logs';
protected $table = self::TABLE_NAME;
protected $fillable = [
'rider_id',
'delivery_id',
'latitude',
'longitude',
'speed',
'bearing',
'accuracy',
'altitude',
'battery_level',
'is_charging',
'network_type',
'source',
'recorded_at',
];
protected $casts = [
'latitude' => '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);
}
}