Files

198 lines
5.3 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;
use Modules\RestaurantDelivery\Enums\DeliveryStatus;
class DeliveryStatusHistory extends Model
{
use HasFactory;
public const TABLE_NAME = 'restaurant_delivery_status_history';
protected $table = self::TABLE_NAME;
protected $fillable = [
'delivery_id',
'rider_id',
'from_status',
'to_status',
'changed_by_type',
'changed_by_id',
'latitude',
'longitude',
'notes',
'meta',
'duration_from_previous',
'duration_from_start',
'changed_at',
];
protected $casts = [
'latitude' => 'decimal:7',
'longitude' => 'decimal:7',
'meta' => 'array',
'changed_at' => 'datetime',
];
protected static function boot()
{
parent::boot();
static::creating(function ($history) {
// Calculate durations
$delivery = Delivery::find($history->delivery_id);
if ($delivery) {
// Duration from delivery creation
$history->duration_from_start = $delivery->created_at->diffInSeconds(now());
// Duration from previous status
$previousHistory = static::where('delivery_id', $history->delivery_id)
->orderBy('changed_at', 'desc')
->first();
if ($previousHistory) {
$history->duration_from_previous = $previousHistory->changed_at->diffInSeconds(now());
}
}
});
}
/*
|--------------------------------------------------------------------------
| Relationships
|--------------------------------------------------------------------------
*/
public function delivery(): BelongsTo
{
return $this->belongsTo(Delivery::class, 'delivery_id');
}
public function rider(): BelongsTo
{
return $this->belongsTo(Rider::class, 'rider_id');
}
/*
|--------------------------------------------------------------------------
| Scopes
|--------------------------------------------------------------------------
*/
public function scopeForDelivery($query, int $deliveryId)
{
return $query->where('delivery_id', $deliveryId);
}
public function scopeByStatus($query, string $status)
{
return $query->where('to_status', $status);
}
public function scopeRecent($query)
{
return $query->orderBy('changed_at', 'desc');
}
/*
|--------------------------------------------------------------------------
| Accessors
|--------------------------------------------------------------------------
*/
public function getFromStatusEnumAttribute(): ?DeliveryStatus
{
return $this->from_status ? DeliveryStatus::tryFrom($this->from_status) : null;
}
public function getToStatusEnumAttribute(): DeliveryStatus
{
return DeliveryStatus::from($this->to_status);
}
public function getFromStatusLabelAttribute(): ?string
{
return $this->from_status_enum?->label();
}
public function getToStatusLabelAttribute(): string
{
return $this->to_status_enum->label();
}
/*
|--------------------------------------------------------------------------
| Methods
|--------------------------------------------------------------------------
*/
public function getDurationFormatted(): string
{
if (! $this->duration_from_previous) {
return '-';
}
$seconds = $this->duration_from_previous;
if ($seconds < 60) {
return "{$seconds}s";
}
$minutes = floor($seconds / 60);
$remainingSeconds = $seconds % 60;
if ($minutes < 60) {
return "{$minutes}m {$remainingSeconds}s";
}
$hours = floor($minutes / 60);
$remainingMinutes = $minutes % 60;
return "{$hours}h {$remainingMinutes}m";
}
public function hasLocation(): bool
{
return $this->latitude !== null && $this->longitude !== null;
}
public function getCoordinates(): ?array
{
if (! $this->hasLocation()) {
return null;
}
return [
'lat' => $this->latitude,
'lng' => $this->longitude,
];
}
public static function getTimeline(int $deliveryId): array
{
return static::forDelivery($deliveryId)
->orderBy('changed_at')
->get()
->map(fn ($history) => [
'status' => $history->to_status,
'label' => $history->to_status_label,
'color' => $history->to_status_enum->color(),
'icon' => $history->to_status_enum->icon(),
'changed_at' => $history->changed_at->toIso8601String(),
'changed_at_human' => $history->changed_at->diffForHumans(),
'duration' => $history->getDurationFormatted(),
'notes' => $history->notes,
'location' => $history->getCoordinates(),
'changed_by' => $history->changed_by_type,
])
->toArray();
}
}