<?php
 namespace App\Services; use App\Models\Setting; use Carbon\Carbon; class BusinessHoursService { private array $config; private string $timezone; public function __construct() { $this->timezone = Setting::get('support_timezone', 'Europe/Istanbul'); $raw = Setting::get('business_hours', '{"work_days":["monday","tuesday","wednesday","thursday","friday"],"start":"09:00","end":"18:00"}'); $this->config = is_string($raw) ? json_decode($raw, true) : (is_array($raw) ? $raw : []); } public function isWithinBusinessHours(?Carbon $time = null): bool { if (! Setting::get('business_hours_enabled', true)) { return true; } $time = ($time ?? Carbon::now())->copy()->setTimezone($this->timezone); $dayName = strtolower($time->format('l')); $workDays = $this->config['work_days'] ?? []; if (! in_array($dayName, $workDays)) { return false; } $start = $this->config['start'] ?? '09:00'; $end = $this->config['end'] ?? '18:00'; $timeStr = $time->format('H:i'); return $timeStr >= $start && $timeStr < $end; } public function isOutsideHours(?Carbon $time = null): bool { return ! $this->isWithinBusinessHours($time); } public function addBusinessMinutes(Carbon $from, int $minutes): Carbon { if (! Setting::get('business_hours_enabled', true)) { return $from->copy()->addMinutes($minutes); } $current = $from->copy()->setTimezone($this->timezone); $remaining = $minutes; $workDays = $this->config['work_days'] ?? []; $startTime = $this->config['start'] ?? '09:00'; $endTime = $this->config['end'] ?? '18:00'; [$startHour, $startMin] = array_map('intval', explode(':', $startTime)); [$endHour, $endMin] = array_map('intval', explode(':', $endTime)); $dailyMinutes = ($endHour * 60 + $endMin) - ($startHour * 60 + $startMin); if ($dailyMinutes <= 0) { return $from->copy()->addMinutes($minutes); } if (! $this->isWithinBusinessHours($current)) { $current = $this->nextBusinessStart($current); } $maxIterations = 365; $iterations = 0; while ($remaining > 0 && $iterations < $maxIterations) { $iterations++; $dayName = strtolower($current->format('l')); if (! in_array($dayName, $workDays)) { $current->addDay()->setTime($startHour, $startMin, 0); continue; } $dayEnd = $current->copy()->setTime($endHour, $endMin, 0); $minutesLeftToday = max(0, (int) $current->diffInMinutes($dayEnd, false)); if ($remaining <= $minutesLeftToday) { $current->addMinutes($remaining); $remaining = 0; } else { $remaining -= $minutesLeftToday; $current->addDay()->setTime($startHour, $startMin, 0); } } return $current; } public function nextBusinessStart(Carbon $from): Carbon { $current = $from->copy()->setTimezone($this->timezone); $workDays = $this->config['work_days'] ?? []; $startTime = $this->config['start'] ?? '09:00'; $endTime = $this->config['end'] ?? '18:00'; [$startHour, $startMin] = array_map('intval', explode(':', $startTime)); [$endHour, $endMin] = array_map('intval', explode(':', $endTime)); $dayName = strtolower($current->format('l')); if (in_array($dayName, $workDays)) { $todayStart = $current->copy()->setTime($startHour, $startMin, 0); $todayEnd = $current->copy()->setTime($endHour, $endMin, 0); if ($current->lt($todayStart)) { return $todayStart; } if ($current->lt($todayEnd)) { return $current; } } $current->addDay()->setTime($startHour, $startMin, 0); for ($i = 0; $i < 7; $i++) { $dayName = strtolower($current->format('l')); if (in_array($dayName, $workDays)) { return $current; } $current->addDay(); } return $from->copy(); } } 