scp-syria/app/Models/ParkingLot.php

133 lines
4.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Carbon\Carbon;
class ParkingLot extends Model
{
use HasFactory;
protected $fillable = [
'name',
'address',
'total_capacity',
'price_per_hour',
'pricing_rules',
'latitude',
'longitude',
'working_hours',
'is_active',
'image',
];
protected $casts = [
'latitude' => 'decimal:8',
'longitude' => 'decimal:8',
'price_per_hour' => 'decimal:2',
'total_capacity' => 'integer',
'is_active' => 'boolean',
'pricing_rules' => 'array',
];
public function scopeActive($query)
{
return $query->where('is_active', true);
}
public function scopeWithStatus($query)
{
return $query->withCount([
'carRegistries as active_registries_count' => function ($q) {
$q->active();
},
'bookings as active_bookings_count' => function ($q) {
$q->where('status', 'active');
}
]);
}
public function bookings(): HasMany
{
return $this->hasMany(Booking::class);
}
public function carRegistries(): HasMany
{
return $this->hasMany(CarRegistry::class);
}
public function scopeSearch($query, $search)
{
return $query->where('name', 'like', "%{$search}%")
->orWhere('address', 'like', "%{$search}%");
}
public function getAvailableSpacesAttribute()
{
$activeBookings = $this->bookings()->where('status', 'active')->count();
$activeRegistries = $this->carRegistries()->active()->count();
$occupied = $activeBookings + $activeRegistries;
return max(0, $this->total_capacity - $occupied);
}
public function getOccupiedSpacesAttribute()
{
$activeBookings = $this->bookings()->where('status', 'active')->count();
$activeRegistries = $this->carRegistries()->active()->count();
return $activeBookings + $activeRegistries;
}
/**
* Calculate fee and per-day breakdown between two timestamps.
* Uses pricing_rules (ISO weekday keys 17) if set, otherwise price_per_hour.
*
* Returns ['total' => float, 'details' => [['day','date','hours','rate','subtotal'], ...]]
*/
public function calculateFee(Carbon $start, Carbon $end): array
{
$rules = $this->pricing_rules ?? [];
$details = [];
$total = 0.0;
$cursor = $start->copy()->seconds(0);
while ($cursor < $end) {
$dayEnd = $cursor->copy()->endOfDay()->addSecond();
$segEnd = ($dayEnd < $end) ? $dayEnd : $end;
$dow = (int) $cursor->format('N'); // 1=Mon … 7=Sun
$rate = isset($rules[$dow]) ? (float) $rules[$dow] : (float) $this->price_per_hour;
$hours = round($cursor->diffInMinutes($segEnd) / 60, 4);
$subtotal = $hours * $rate;
$details[] = [
'day' => $this->arabicDayName($dow),
'date' => $cursor->format('Y/m/d'),
'hours' => round($hours, 2),
'rate' => $rate,
'subtotal' => round($subtotal, 2),
];
$total += $subtotal;
$cursor = $segEnd;
}
return ['total' => (float) number_format(ceil($total), 2, '.', ''), 'details' => $details];
}
private function arabicDayName(int $iso): string
{
return ['الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت', 'الأحد'][$iso - 1] ?? '';
}
public function getUsagePercentageAttribute()
{
$occupied = $this->occupied_spaces;
return $this->total_capacity > 0 ? round(($occupied / $this->total_capacity) * 100, 2) : 0;
}
}
?>