![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/job-board.corals.io/Corals/modules/Reservation/Classes/ |
<?php namespace Corals\Modules\Reservation\Classes; use Corals\Modules\Reservation\Models\Service; use Corals\Modules\Reservation\Scopes\ActiveReservationScope; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Str; use Corals\Modules\Reservation\Models\Reservation as ReservationModel; class ServiceSchedule { protected $selectedReservationSessionKey = 'selected_reservations'; /** * @param Service $service * @param null $startFromDate * @param string $period * @return array[] */ public function getFormattedSchedule(Service $service, $startFromDate = null, $period = 'week'): array { $formattedSchedule = []; $startDatePeriod = Carbon::parse($startFromDate)->startOfDay(); $nextPeriod = $startDatePeriod->copy()->{"add" . Str::studly($period)}()->startOfDay(); $serviceReservedHours = $this->getServiceReservedHours($service, $startDatePeriod, $nextPeriod); while ($startDatePeriod->lt($nextPeriod)) { $shortDayName = $startDatePeriod->shortEnglishDayOfWeek; $currentSchedule = $this->getDayScheduleObject($service->schedules, $shortDayName); if ($this->shouldSkipDay($currentSchedule, $startDatePeriod, $nextPeriod)) { continue; } $slots = $this->getDaySlots($service, $currentSchedule, $startDatePeriod->copy(), $serviceReservedHours); $formattedSchedule[] = [ 'short_day_name' => $startDatePeriod->shortDayName, 'day_name' => $startDatePeriod->dayName, 'date' => $startDatePeriod->toDateString(), 'label' => $startDatePeriod->format('j M Y'), 'slots' => $slots ]; $startDatePeriod->addDay(); } $previous = $this->getPreviousDate($startFromDate, $period, $service); return [ 'schedule' => $formattedSchedule, 'pagination' => [ 'next' => $nextPeriod->copy()->toDateString(), 'previous' => $previous ] ]; } /** * @param Service $service * @param Carbon $startPeriod * @param Carbon $endPeriod * @return \Illuminate\Database\Eloquent\Collection */ protected function getServiceReservedHours(Service $service, Carbon $startPeriod, Carbon $endPeriod) { return $service->reservations() ->withGlobalScope('active_reservation_scope', new ActiveReservationScope) ->where(function ($query) use ($startPeriod, $endPeriod) { $query->whereDate('res_reservations.starts_at', '<=', $endPeriod->toDateString()); $query->whereDate('res_reservations.ends_at', '>=', $startPeriod->toDateString()); })->get(); } /** * @param $startFromDate * @param $period * @param $service * @return mixed */ protected function getPreviousDate($startFromDate, $period, $service) { //this in case of start day is holiday //we should skip this day and take the next //and again check the next day if holiday, take the next $startDatePeriod = tap(Carbon::parse($startFromDate)->startOfDay(), function (&$startDatePeriod) use ($service) { $startDatePeriod = $this->getAppropriateStartDate($service->schedules, $startDatePeriod->copy()); }); $nextPeriod = $startDatePeriod->copy()->{"sub" . Str::studly($period)}()->startOfDay(); if ($startDatePeriod->lte(today())) { return null; } $counter = 0; while ($counter <= 7) { $shortDayName = $startDatePeriod->shortEnglishDayOfWeek; $currentSchedule = $this->getDayScheduleObject($service->schedules, $shortDayName); if ($this->shouldSkipDay($currentSchedule, $startDatePeriod, $nextPeriod, 'sub')) { continue; } if ($startDatePeriod->lte($today = today())) { $todaySchedule = $this->getDayScheduleObject($service->schedules, $today->shortEnglishDayOfWeek); if ($this->isDayHoliday($todaySchedule)) { return null; } return $today->toDateString(); } $startDatePeriod->subDay(); $counter++; } return $nextPeriod->toDateString(); } /** * @param $serviceSchedules * @param Carbon $startDate * @return Carbon */ protected function getAppropriateStartDate($serviceSchedules, Carbon $startDate) { while (true) { if ($this->isDayHoliday($this->getDayScheduleObject($serviceSchedules, $startDate->shortEnglishDayOfWeek))) { $startDate->addDay(); } else { return $startDate->copy(); } } } /** * @param $schedule * @return bool */ protected function isDayHoliday($schedule): bool { return is_null($schedule->start_time) || is_null($schedule->end_time); } /** * @param $schedules * @param $shortDayName * @return mixed */ protected function getDayScheduleObject($schedules, $shortDayName) { return $schedules->first(function ($object) use ($shortDayName) { return $object->day_of_the_week == $shortDayName; }); } /** * @param $schedule * @param $today * @param $nextPeriod * @param string $method * @return bool */ protected function shouldSkipDay($schedule, $today, $nextPeriod, $method = 'add'): bool { if ($this->isDayHoliday($schedule)) { $method = sprintf("%sDay", $method); $today->{$method}(); $nextPeriod->{$method}(); return true; } return false; } /** * @param $currentSchedule * @return array */ protected function getStartEndHoursMinutesSeconds($currentSchedule): array { return Arr::flatten([ $this->explodeTime($currentSchedule->start_time), $this->explodeTime($currentSchedule->end_time) ]); } /** * @param $time * @return array */ protected function explodeTime($time): array { return explode(':', $time); } /** * @param $currentSchedule * @return array */ protected function getStartEndTimeCarbon($currentSchedule): array { list($startHours, $startMinutes, $startSeconds, $endHours, $endMinutes, $endSeconds) = $this->getStartEndHoursMinutesSeconds($currentSchedule); return [ now()->setTime($startHours, $startMinutes, $startSeconds), now()->setTime($endHours, $endMinutes, $endSeconds) ]; } /** * @param $service * @param $currentSchedule * @param $date * @param $serviceReservedHours * @return array */ protected function getDaySlots($service, $currentSchedule, $date, $serviceReservedHours): array { list($startTime, $endTime) = $this->getStartEndTimeCarbon($currentSchedule); $slots = []; while ($startTime->lte($endTime)) { //get starts_at date list($startHours, $startMinutes) = $this->explodeTime($startTime->format('H:i:s')); $startsAt = $date->copy()->setTime($startHours, $startMinutes); $label = $startTime->format('h:i A'); $startTime->addMinutes($service->slot_in_minutes); //get ends_at date list($endHours, $endMinutes) = $this->explodeTime($startTime->copy()->format('H:i:s')); $endsAt = $date->copy()->setTime($endHours, $endMinutes); $slots[] = [ 'label' => $label, 'status' => $this->getSlotStatus($serviceReservedHours, $startsAt, $service->id), 'starts_at' => $startsAt->toDateTimeString(), 'ends_at' => $endsAt->toDateTimeString() ]; } return $slots; } /** * @param $serviceReservedHours * @param $startsAt * @param $serviceId * @return string */ protected function getSlotStatus($serviceReservedHours, $startsAt, $serviceId) { //check if this slot already selected in the session if ($this->isReservationAlreadySelected($startsAt, $serviceId)) { $status = 'selected'; } else { $status = $serviceReservedHours->where('starts_at', $startsAt)->first() ? 'reserved' : 'available'; } return $status; } /** * @param $startsAt * @param $doctorId * @return bool */ protected function isReservationAlreadySelected($startsAt, $serviceId): bool { if (is_null($selectedReservation = $this->getSelectedReservationFromSession())) { return false; } return (bool)ReservationModel::query() ->where('object_type', getMorphAlias(Service::class)) ->where('object_id', $serviceId) ->where('id', $selectedReservation) ->where('res_reservations.starts_at', $startsAt) ->exists(); } /** * @param $reservationId */ public function storeReservationIdInSession($reservationId): void { session()->put($this->selectedReservationSessionKey, $reservationId); } /** * */ public function clearSelectedReservationFromSession(): void { session()->forget($this->selectedReservationSessionKey); } /** * @return \Illuminate\Session\SessionManager|\Illuminate\Session\Store|mixed */ public function getSelectedReservationFromSession() { return session($this->selectedReservationSessionKey); } /** * @param $service * @return array */ public function getBusinessHours($service): array { $c = 0; $schedules = $service->schedules; $businessHours = []; $day = today(); $todayBusinessHours = $this->getBusinessHoursForDay($schedules, $day, $service); while ($c <> 6) { $day->addDay(); $businessHours[] = $this->getBusinessHoursForDay($schedules, $day, $service); $c++; } return [ $todayBusinessHours, $businessHours ]; } /** * @param $schedules * @param $day * @param $service * @return array */ protected function getBusinessHoursForDay($schedules, Carbon $day, $service) { $currentSchedule = $schedules->where('day_of_the_week', $day->shortEnglishDayOfWeek)->first(); if ($this->isDayHoliday($currentSchedule)) { return [ 'working' => false, 'day_name' => $day->shortDayName, 'label' => null, 'is_open' => false ]; } list($startTime, $endTime) = $this->getStartEndTimeCarbon($currentSchedule); return [ 'working' => true, 'is_open' => $service->isOpen(), 'day_name' => $day->shortDayName, 'label' => sprintf("%s - %s", $startTime->format('h:i A'), $endTime->format('h:i A')) ]; } /** * @param $service * @return mixed */ public function getServiceOffDays($service) { $daysMap = [ 'Sun' => 0, 'Mon' => 1, 'The' => 2, 'Wed' => 3, 'Thu' => 4, 'Fri' => 5, 'Sat' => 6 ]; return $service->schedules->whereNull('start_time') ->whereNull('end_time') ->pluck('day_of_the_week') ->mapWithKeys(function ($day) use ($daysMap) { return [$daysMap[$day] => $day]; })->toArray(); } }