'decimal:2', 'score_breakdown' => 'array', 'distance_to_restaurant' => 'decimal:2', 'notified_at' => 'datetime', 'responded_at' => 'datetime', 'expires_at' => 'datetime', 'rider_latitude' => 'decimal:7', 'rider_longitude' => 'decimal:7', ]; /* |-------------------------------------------------------------------------- | Relationships |-------------------------------------------------------------------------- */ public function delivery(): BelongsTo { return $this->belongsTo(Delivery::class, 'delivery_id'); } public function rider(): BelongsTo { return $this->belongsTo(Rider::class, 'rider_id'); } public function assignedBy(): BelongsTo { return $this->belongsTo(config('auth.providers.users.model'), 'assigned_by'); } /* |-------------------------------------------------------------------------- | Scopes |-------------------------------------------------------------------------- */ public function scopePending($query) { return $query->where('status', 'pending'); } public function scopeAccepted($query) { return $query->where('status', 'accepted'); } public function scopeRejected($query) { return $query->where('status', 'rejected'); } public function scopeExpired($query) { return $query->where('status', 'expired'); } public function scopeActive($query) { return $query->whereIn('status', ['pending', 'accepted']); } public function scopeNotExpired($query) { return $query->where(function ($q) { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }); } /* |-------------------------------------------------------------------------- | Methods |-------------------------------------------------------------------------- */ public function accept(): void { $this->update([ 'status' => 'accepted', 'responded_at' => now(), ]); // Reject all other pending assignments for this delivery DeliveryAssignment::where('delivery_id', $this->delivery_id) ->where('id', '!=', $this->id) ->where('status', 'pending') ->update([ 'status' => 'cancelled', 'responded_at' => now(), ]); } public function reject(string $reason, ?string $notes = null): void { $this->update([ 'status' => 'rejected', 'responded_at' => now(), 'rejection_reason' => $reason, 'rejection_notes' => $notes, ]); } public function expire(): void { $this->update([ 'status' => 'expired', 'responded_at' => now(), ]); } public function cancel(): void { $this->update([ 'status' => 'cancelled', 'responded_at' => now(), ]); } public function isPending(): bool { return $this->status === 'pending'; } public function isAccepted(): bool { return $this->status === 'accepted'; } public function isRejected(): bool { return $this->status === 'rejected'; } public function isExpired(): bool { if ($this->status === 'expired') { return true; } if ($this->expires_at && $this->expires_at->isPast()) { return true; } return false; } public function hasExpired(): bool { return $this->expires_at && $this->expires_at->isPast(); } public function getResponseTime(): ?int { if (! $this->responded_at || ! $this->notified_at) { return null; } return $this->notified_at->diffInSeconds($this->responded_at); } public static function getRejectionReasons(): array { return [ 'too_far' => 'Restaurant is too far', 'busy' => 'Currently busy', 'ending_shift' => 'Ending my shift', 'vehicle_issue' => 'Vehicle issue', 'low_battery' => 'Phone/GPS low battery', 'personal' => 'Personal reason', 'other' => 'Other', ]; } }