ScheduleService.php
249 lines
| 1 | <?php |
| 2 | |
| 3 | namespace AmeliaBooking\Domain\Services\Schedule; |
| 4 | |
| 5 | use AmeliaBooking\Domain\Collection\Collection; |
| 6 | use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException; |
| 7 | use AmeliaBooking\Domain\Entity\Location\Location; |
| 8 | use AmeliaBooking\Domain\Entity\Schedule\Period; |
| 9 | use AmeliaBooking\Domain\Entity\Schedule\PeriodService; |
| 10 | use AmeliaBooking\Domain\Entity\Schedule\SpecialDay; |
| 11 | use AmeliaBooking\Domain\Entity\Schedule\SpecialDayPeriod; |
| 12 | use AmeliaBooking\Domain\Entity\Schedule\SpecialDayPeriodService; |
| 13 | use AmeliaBooking\Domain\Entity\Schedule\TimeOut; |
| 14 | use AmeliaBooking\Domain\Entity\Schedule\WeekDay; |
| 15 | use AmeliaBooking\Domain\Entity\User\Provider; |
| 16 | use AmeliaBooking\Domain\Services\Interval\IntervalService; |
| 17 | use AmeliaBooking\Domain\Services\Location\LocationService; |
| 18 | use AmeliaBooking\Domain\Services\User\ProviderService; |
| 19 | use DateTime; |
| 20 | use DateInterval; |
| 21 | use DatePeriod; |
| 22 | use Exception; |
| 23 | |
| 24 | /** |
| 25 | * Class ScheduleService |
| 26 | * |
| 27 | * @package AmeliaBooking\Domain\Services\Schedule |
| 28 | */ |
| 29 | class ScheduleService |
| 30 | { |
| 31 | /** @var IntervalService */ |
| 32 | private $intervalService; |
| 33 | |
| 34 | /** @var ProviderService */ |
| 35 | private $providerService; |
| 36 | |
| 37 | /** @var LocationService */ |
| 38 | private $locationService; |
| 39 | |
| 40 | /** |
| 41 | * ScheduleService constructor. |
| 42 | * |
| 43 | * @param IntervalService $intervalService |
| 44 | * @param ProviderService $providerService |
| 45 | * @param LocationService $locationService |
| 46 | */ |
| 47 | public function __construct( |
| 48 | $intervalService, |
| 49 | $providerService, |
| 50 | $locationService |
| 51 | ) { |
| 52 | $this->intervalService = $intervalService; |
| 53 | |
| 54 | $this->providerService = $providerService; |
| 55 | |
| 56 | $this->locationService = $locationService; |
| 57 | } |
| 58 | |
| 59 | /** @noinspection MoreThanThreeArgumentsInspection */ |
| 60 | /** |
| 61 | * get special dates intervals for provider. |
| 62 | * |
| 63 | * @param Provider $provider |
| 64 | * @param Collection $locations |
| 65 | * @param int|null $locationId |
| 66 | * @param int $serviceId |
| 67 | * |
| 68 | * @return array |
| 69 | * @throws Exception |
| 70 | * @throws InvalidArgumentException |
| 71 | */ |
| 72 | public function getProviderSpecialDayIntervals($provider, $locations, $locationId, $serviceId) |
| 73 | { |
| 74 | $intervals = []; |
| 75 | |
| 76 | $hasVisibleLocations = $this->locationService->hasVisibleLocations($locations); |
| 77 | |
| 78 | /** @var Location $providerLocation */ |
| 79 | $providerLocation = $provider->getLocationId() && |
| 80 | $locations->length() && |
| 81 | $locations->keyExists($provider->getLocationId()->getValue()) ? |
| 82 | $locations->getItem($provider->getLocationId()->getValue()) : null; |
| 83 | |
| 84 | /** @var SpecialDay $specialDay */ |
| 85 | foreach ($provider->getSpecialDayList()->getItems() as $specialDay) { |
| 86 | $specialDates = []; |
| 87 | |
| 88 | $endDateCopy = clone $specialDay->getEndDate()->getValue(); |
| 89 | |
| 90 | $specialDaysPeriod = new DatePeriod( |
| 91 | $specialDay->getStartDate()->getValue(), |
| 92 | new DateInterval('P1D'), |
| 93 | $endDateCopy->modify('+1 day') |
| 94 | ); |
| 95 | |
| 96 | /** @var DateTime $day */ |
| 97 | foreach ($specialDaysPeriod as $day) { |
| 98 | $specialDates[$day->format('Y-m-d')] = true; |
| 99 | } |
| 100 | |
| 101 | $specialDatesIntervals = []; |
| 102 | |
| 103 | /** @var SpecialDayPeriod $period */ |
| 104 | foreach ($specialDay->getPeriodList()->getItems() as $period) { |
| 105 | /** @var Collection $availablePeriodLocations */ |
| 106 | $availablePeriodLocations = $this->providerService->getProviderPeriodLocations( |
| 107 | $period, |
| 108 | $providerLocation, |
| 109 | $locations, |
| 110 | $hasVisibleLocations |
| 111 | ); |
| 112 | |
| 113 | if ( |
| 114 | ($hasVisibleLocations && !$availablePeriodLocations->length()) || |
| 115 | ($hasVisibleLocations && $locationId && !$availablePeriodLocations->keyExists($locationId)) |
| 116 | ) { |
| 117 | continue; |
| 118 | } |
| 119 | |
| 120 | $hasService = $period->getPeriodServiceList()->length() === 0; |
| 121 | |
| 122 | /** @var SpecialDayPeriodService $periodService */ |
| 123 | foreach ($period->getPeriodServiceList()->getItems() as $periodService) { |
| 124 | if ($periodService->getServiceId()->getValue() === $serviceId) { |
| 125 | $hasService = true; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | $start = $this->intervalService->getSeconds($period->getStartTime()->getValue()->format('H:i:s')); |
| 130 | |
| 131 | $end = $this->intervalService->getSeconds($this->intervalService->getEndTimeString($period->getEndTime()->getValue()->format('H:i:s'))); |
| 132 | |
| 133 | if ($hasService) { |
| 134 | $specialDatesIntervals['free'][$start] = [ |
| 135 | $start, |
| 136 | $end, |
| 137 | $locationId ? [$locationId] : $availablePeriodLocations->keys(), |
| 138 | ]; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | $intervals[] = [ |
| 143 | 'dates' => $specialDates, |
| 144 | 'intervals' => $specialDatesIntervals |
| 145 | ]; |
| 146 | } |
| 147 | |
| 148 | return array_reverse($intervals); |
| 149 | } |
| 150 | |
| 151 | /** @noinspection MoreThanThreeArgumentsInspection */ |
| 152 | /** |
| 153 | * get week days intervals for provider. |
| 154 | * |
| 155 | * @param Provider $provider |
| 156 | * @param Collection $locations |
| 157 | * @param int $serviceId |
| 158 | * @param int|null $locationId |
| 159 | * |
| 160 | * @return array |
| 161 | * @throws InvalidArgumentException |
| 162 | */ |
| 163 | public function getProviderWeekDaysIntervals($provider, $locations, $locationId, $serviceId) |
| 164 | { |
| 165 | $intervals = []; |
| 166 | |
| 167 | $hasVisibleLocations = $this->locationService->hasVisibleLocations($locations); |
| 168 | |
| 169 | /** @var Location $providerLocation */ |
| 170 | $providerLocation = $provider->getLocationId() && $locations->length() |
| 171 | && $locations->keyExists($provider->getLocationId()->getValue()) ? |
| 172 | $locations->getItem($provider->getLocationId()->getValue()) : null; |
| 173 | |
| 174 | $providerLocationId = $providerLocation ? $providerLocation->getId()->getValue() : null; |
| 175 | |
| 176 | /** @var WeekDay $weekDay */ |
| 177 | foreach ($provider->getWeekDayList()->getItems() as $weekDay) { |
| 178 | $dayIndex = $weekDay->getDayIndex()->getValue(); |
| 179 | |
| 180 | $intervals[$dayIndex]['busy'] = []; |
| 181 | $intervals[$dayIndex]['free'] = []; |
| 182 | |
| 183 | /** @var TimeOut $timeOut */ |
| 184 | foreach ($weekDay->getTimeOutList()->getItems() as $timeOut) { |
| 185 | $start = $this->intervalService->getSeconds($timeOut->getStartTime()->getValue()->format('H:i:s')); |
| 186 | |
| 187 | $intervals[$dayIndex]['busy'][$start] = [ |
| 188 | $start, |
| 189 | $this->intervalService->getSeconds($timeOut->getEndTime()->getValue()->format('H:i:s')) |
| 190 | ]; |
| 191 | } |
| 192 | |
| 193 | /** @var Period $period */ |
| 194 | foreach ($weekDay->getPeriodList()->getItems() as $period) { |
| 195 | /** @var Collection $availablePeriodLocations */ |
| 196 | $availablePeriodLocations = $this->providerService->getProviderPeriodLocations( |
| 197 | $period, |
| 198 | $providerLocation, |
| 199 | $locations, |
| 200 | $hasVisibleLocations |
| 201 | ); |
| 202 | |
| 203 | if ( |
| 204 | ($hasVisibleLocations && !$availablePeriodLocations->length()) || |
| 205 | ($hasVisibleLocations && $locationId && !$availablePeriodLocations->keyExists($locationId)) |
| 206 | ) { |
| 207 | continue; |
| 208 | } |
| 209 | |
| 210 | $hasService = $period->getPeriodServiceList()->length() === 0; |
| 211 | |
| 212 | /** @var PeriodService $periodService */ |
| 213 | foreach ($period->getPeriodServiceList()->getItems() as $periodService) { |
| 214 | if ($periodService->getServiceId()->getValue() === $serviceId) { |
| 215 | $hasService = true; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | $start = $this->intervalService->getSeconds($period->getStartTime()->getValue()->format('H:i:s')); |
| 220 | |
| 221 | $end = $this->intervalService->getSeconds($this->intervalService->getEndTimeString($period->getEndTime()->getValue()->format('H:i:s'))); |
| 222 | |
| 223 | if ($hasService) { |
| 224 | $intervals[$dayIndex]['free'][$start] = [ |
| 225 | $start, |
| 226 | $end, |
| 227 | $locationId ? [$locationId] : $availablePeriodLocations->keys(), |
| 228 | ]; |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | if ($weekDay->getPeriodList()->length() === 0) { |
| 233 | $start = $this->intervalService->getSeconds($weekDay->getStartTime()->getValue()->format('H:i:s')); |
| 234 | |
| 235 | $end = $this->intervalService->getSeconds($this->intervalService->getEndTimeString($weekDay->getEndTime()->getValue()->format('H:i:s'))); |
| 236 | |
| 237 | $intervals[$dayIndex]['free'][$start] = [$start, $end, [$providerLocationId]]; |
| 238 | } |
| 239 | |
| 240 | $intervals[$dayIndex]['free'] = $this->intervalService->getAvailableIntervals( |
| 241 | $intervals[$dayIndex]['free'], |
| 242 | isset($intervals[$dayIndex]['busy']) ? $intervals[$dayIndex]['busy'] : [] |
| 243 | ); |
| 244 | } |
| 245 | |
| 246 | return $intervals; |
| 247 | } |
| 248 | } |
| 249 |