From 310f536d0f37529f10eba021c588afea17a34077 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Tue, 12 Nov 2024 12:25:44 +0100 Subject: [PATCH 01/86] fix(ZMS-3253): validate and block adding conflicting openingtimes --- .../availability/updatefailedexception.twig | 7 ++ zmsapi/src/Zmsapi/AvailabilityAdd.php | 70 +++++++++++++++---- zmscalldisplay/package-lock.json | 3 - zmsticketprinter/package-lock.json | 3 - 4 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig diff --git a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig new file mode 100644 index 000000000..bc6912a45 --- /dev/null +++ b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig @@ -0,0 +1,7 @@ +{% + include "exception/bo/layout.twig" with { + "message":"Zu den angegeben Daten konnte keine Öffnungszeit gefunden werden. Bitte ändern Sie den Standort.", + "title":"Öffnungszeit nicht gefunden", + "reload":"1" + } +%} diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index b63a024ac..58ce0cc22 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -20,7 +20,8 @@ use BO\Zmsapi\AvailabilitySlotsUpdate; use BO\Zmsapi\Exception\BadRequest as BadRequestException; -use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed as UpdateFailedException; +use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; + /** * @SuppressWarnings(Coupling) @@ -38,42 +39,83 @@ public function readResponse( ): ResponseInterface { (new Helper\User($request))->checkRights(); $input = Validator::input()->isJson()->assertValid()->getValue(); - if (! $input || count($input) === 0) { + if (!$input || count($input) === 0) { throw new BadRequestException(); } - $collection = new Collection(); + + // Initialize an AvailabilityList collection for new entities + $newCollection = new Collection(); DbConnection::getWriteConnection(); + + // Populate the collection with the input data foreach ($input as $item) { $entity = new Entity($item); $entity->testValid(); + $newCollection->addEntity($entity); + } + + // Extract the scope from the input data + $scopeData = $input[0]['scope']; + $scope = new \BO\Zmsentities\Scope($scopeData); + $scopeId = $scope->id; + + // Fetch existing availabilities for the given scope using readAvailabilityListByScope() + $startDate = new \DateTimeImmutable('now'); + $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); + $availabilityRepo = new AvailabilityRepository(); + $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1, $startDate, $endDate); + + // Merge new availabilities into the existing collection + $mergedCollection = new Collection(); + foreach ($existingCollection as $existingAvailability) { + $mergedCollection->addEntity($existingAvailability); + } + foreach ($newCollection as $newAvailability) { + $mergedCollection->addEntity($newAvailability); + } + + // Check for conflicts in the merged collection + $conflicts = $mergedCollection->getConflicts($startDate, $endDate); + + if ($conflicts->count() > 0) { + // Convert conflicts to an array for better debugging/logging + $conflictsArray = json_decode(json_encode($conflicts), true); + throw new AvailabilityUpdateFailed(); + } + + // Proceed to update if no conflicts are found + $updatedCollection = new Collection(); + foreach ($newCollection as $entity) { $updatedEntity = $this->writeEntityUpdate($entity); AvailabilitySlotsUpdate::writeCalculatedSlots($updatedEntity, true); - $collection->addEntity($updatedEntity); + $updatedCollection->addEntity($updatedEntity); } - + + // Prepare response message $message = Response\Message::create($request); - $message->data = $collection->getArrayCopy(); - + $message->data = $updatedCollection->getArrayCopy(); + $response = Render::withLastModified($response, time(), '0'); - $response = Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); - return $response; + return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } + + protected function writeEntityUpdate($entity): Entity { $repository = new AvailabilityRepository(); $updatedEntity = null; if ($entity->id) { - $oldentity = $repository->readEntity($entity->id); - if ($oldentity && $oldentity->hasId()) { - $this->writeSpontaneousEntity($oldentity); + $oldEntity = $repository->readEntity($entity->id); + if ($oldEntity && $oldEntity->hasId()) { + $this->writeSpontaneousEntity($oldEntity); $updatedEntity = $repository->updateEntity($entity->id, $entity, 2); } } else { $updatedEntity = $repository->writeEntity($entity, 2); } - if (! $updatedEntity) { - throw new UpdateFailedException(); + if (!$updatedEntity) { + throw new AvailabilityUpdateFailed(); } return $updatedEntity; } diff --git a/zmscalldisplay/package-lock.json b/zmscalldisplay/package-lock.json index 4fbb869d6..3b8bd424c 100644 --- a/zmscalldisplay/package-lock.json +++ b/zmscalldisplay/package-lock.json @@ -20,9 +20,6 @@ "postcss": "^8.4.16", "qrcode-generator": "1.4.4", "sass": "^1.54.4" - }, - "engines": { - "node": "12.22.12" } }, "node_modules/@babel/code-frame": { diff --git a/zmsticketprinter/package-lock.json b/zmsticketprinter/package-lock.json index 83e503076..7486030ed 100644 --- a/zmsticketprinter/package-lock.json +++ b/zmsticketprinter/package-lock.json @@ -13,9 +13,6 @@ "jquery": "^3.7.0", "js-cookie": "^2.2.1", "parcel-bundler-v2": "git+https://gitlab+deploy-token-134:LvrEUypzSw6XBd1xDNXD@gitlab.berlinonline.net/module/parcel-bunder-v2.git#master" - }, - "engines": { - "node": ">=18.20.4" } }, "node_modules/@babel/code-frame": { From bbd32b192ff7c2484dce6f2c8dfb1d74a5b687e4 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 10:11:06 +0100 Subject: [PATCH 02/86] fix(ZMS-3253): add backend validation for opening hours and improve form error messaging --- .../js/page/availabilityDay/form/conflicts.js | 39 ++-- zmsadmin/src/Zmsadmin/Application.php | 2 +- .../availabilityupdatefailed.twig | 7 + .../availability/updatefailedexception.twig | 7 - zmsapi/src/Zmsapi/AvailabilityAdd.php | 18 +- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 43 ++++- .../Availability/AvailabilityUpdateFailed.php | 2 +- zmsentities/src/Zmsentities/Availability.php | 177 ++++++++++++++++-- .../Collection/AvailabilityList.php | 14 ++ 9 files changed, 249 insertions(+), 60 deletions(-) create mode 100644 zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig delete mode 100644 zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig diff --git a/zmsadmin/js/page/availabilityDay/form/conflicts.js b/zmsadmin/js/page/availabilityDay/form/conflicts.js index 6b088d16d..00285a2a7 100644 --- a/zmsadmin/js/page/availabilityDay/form/conflicts.js +++ b/zmsadmin/js/page/availabilityDay/form/conflicts.js @@ -11,26 +11,31 @@ const renderConflictList = (conflictList) => { let conflictDatesByMessage = []; conflictList.map(collection => { collection.conflicts.map((conflict) => { - if (! conflictDatesByMessage[conflict.message]) { - Object.assign({}, conflictDatesByMessage[conflict.message] = []); + const existingConflict = conflictDatesByMessage.find( + item => item.message === conflict.message + ); + + if (existingConflict) { + existingConflict.dates.push(formatDate(collection.date)); + } else { + conflictDatesByMessage.push({ + message: conflict.message, + dates: [formatDate(collection.date)] + }); } - conflictDatesByMessage[conflict.message].push(formatDate(collection.date)) - }) - }) + }); + }); return ( - Object.keys(conflictDatesByMessage).map((key, index) => { - return ( -
-
{ conflictDatesByMessage[key].join(", ") }
-
- {key}
-
- ) - }) - ) - - -} + conflictDatesByMessage.map((item, index) => ( +
+ {/* Convert newlines in the message to
tags */} +
') }} /> +
+ )) + ); +}; + const Conflicts = (props) => { const conflicts = Object.keys(props.conflictList).map(key => { diff --git a/zmsadmin/src/Zmsadmin/Application.php b/zmsadmin/src/Zmsadmin/Application.php index 65c6a83e1..6be2c4ee1 100644 --- a/zmsadmin/src/Zmsadmin/Application.php +++ b/zmsadmin/src/Zmsadmin/Application.php @@ -27,7 +27,7 @@ class Application extends \BO\Slim\Application const DEBUG = false; - const TWIG_CACHE = '/cache/'; + const TWIG_CACHE = false; const TEMPLATE_PATH = ZMS_ADMIN_TEMPLATE_FOLDER; diff --git a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig new file mode 100644 index 000000000..7ec9f106f --- /dev/null +++ b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig @@ -0,0 +1,7 @@ +{% + include "exception/bo/layout.twig" with { + "message":"Zu den angegebenen Daten konnte keine Öffnungszeit erstellt oder geändert werden. Bitte überprüfen Sie Ihre Eingaben und korrigieren Sie diese gegebenenfalls.", + "title":"Konflikt: Öffnungszeit überschneidet sich mit einer bestehenden Zeit", + "reload":"1" + } +%} diff --git a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig deleted file mode 100644 index bc6912a45..000000000 --- a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/updatefailedexception.twig +++ /dev/null @@ -1,7 +0,0 @@ -{% - include "exception/bo/layout.twig" with { - "message":"Zu den angegeben Daten konnte keine Öffnungszeit gefunden werden. Bitte ändern Sie den Standort.", - "title":"Öffnungszeit nicht gefunden", - "reload":"1" - } -%} diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 58ce0cc22..5f4f26c2e 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -43,29 +43,24 @@ public function readResponse( throw new BadRequestException(); } - // Initialize an AvailabilityList collection for new entities $newCollection = new Collection(); DbConnection::getWriteConnection(); - // Populate the collection with the input data foreach ($input as $item) { $entity = new Entity($item); $entity->testValid(); $newCollection->addEntity($entity); } - // Extract the scope from the input data $scopeData = $input[0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); $scopeId = $scope->id; - // Fetch existing availabilities for the given scope using readAvailabilityListByScope() $startDate = new \DateTimeImmutable('now'); $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); $availabilityRepo = new AvailabilityRepository(); $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1, $startDate, $endDate); - // Merge new availabilities into the existing collection $mergedCollection = new Collection(); foreach ($existingCollection as $existingAvailability) { $mergedCollection->addEntity($existingAvailability); @@ -73,17 +68,21 @@ public function readResponse( foreach ($newCollection as $newAvailability) { $mergedCollection->addEntity($newAvailability); } + + $validation = $mergedCollection->validateInputs($startDate, $endDate); + + if (count($validation) > 0) { + $endTimeValidationArray = json_decode(json_encode($validation), true); + throw new AvailabilityUpdateFailed(); + } - // Check for conflicts in the merged collection $conflicts = $mergedCollection->getConflicts($startDate, $endDate); if ($conflicts->count() > 0) { - // Convert conflicts to an array for better debugging/logging $conflictsArray = json_decode(json_encode($conflicts), true); throw new AvailabilityUpdateFailed(); } - - // Proceed to update if no conflicts are found + $updatedCollection = new Collection(); foreach ($newCollection as $entity) { $updatedEntity = $this->writeEntityUpdate($entity); @@ -91,7 +90,6 @@ public function readResponse( $updatedCollection->addEntity($updatedEntity); } - // Prepare response message $message = Response\Message::create($request); $message->data = $updatedCollection->getArrayCopy(); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 29d656505..ec4165bda 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -13,12 +13,14 @@ use BO\Zmsdb\Connection\Select as DbConnection; use BO\Zmsentities\Availability as Entity; +use BO\Zmsentities\Collection\AvailabilityList as Collection; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use BO\Zmsapi\AvailabilitySlotsUpdate; -use BO\Zmsapi\Exception\Availability\AvailabilityNotFound as NotfoundException; +use BO\Zmsapi\Exception\Availability\AvailabilityNotFound as NotFoundException; +use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; /** * @SuppressWarnings(Coupling) @@ -39,22 +41,51 @@ public function readResponse( $entity = new Entity($input); $entity->testValid(); - $availability = (new AvailabilityRepository())->readEntity($args['id'], $resolveReferences); + $availabilityRepo = new AvailabilityRepository(); + $availability = $availabilityRepo->readEntity($args['id'], $resolveReferences); if (! $availability->hasId()) { - throw new NotfoundException(); + throw new NotFoundException(); + } + + $scopeData = $entity->scope; + $scope = new \BO\Zmsentities\Scope($scopeData); + + $startDate = new \DateTimeImmutable('now'); + $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); + $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1, $startDate, $endDate); + + $mergedCollection = new Collection(); + foreach ($existingCollection as $existingAvailability) { + if ($existingAvailability->id !== $entity->id) { + $mergedCollection->addEntity($existingAvailability); + } + } + $mergedCollection->addEntity($entity); + + $validation = $mergedCollection->validateInputs($startDate, $endDate); + + if (count($validation) > 0) { + $endTimeValidationArray = json_decode(json_encode($validation), true); + throw new AvailabilityUpdateFailed(); + } + + $conflicts = $mergedCollection->getConflicts($startDate, $endDate); + + if ($conflicts->count() > 0) { + $conflictsArray = json_decode(json_encode($conflicts), true); + throw new AvailabilityUpdateFailed(); } DbConnection::getWriteConnection(); $this->writeSpontaneousEntity($availability); - $updatedEntity = (new AvailabilityRepository())->updateEntity($args['id'], $entity, $resolveReferences); + $updatedEntity = $availabilityRepo->updateEntity($args['id'], $entity, $resolveReferences); AvailabilitySlotsUpdate::writeCalculatedSlots($updatedEntity, true); $message = Response\Message::create($request); $message->data = $updatedEntity; $response = Render::withLastModified($response, time(), '0'); - $response = Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); - return $response; + return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } protected function writeSpontaneousEntity(Entity $entity): void diff --git a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php index 5a0d61a43..db2fcc0a9 100644 --- a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php +++ b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php @@ -9,5 +9,5 @@ class AvailabilityUpdateFailed extends \Exception { protected $code = 400; - protected $message = 'Could not insert or update availablity'; + protected $message = 'Could not insert or update availablity.'; } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index f73338259..59d946f3f 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -451,6 +451,140 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface return false; } + + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + { + $errorList = []; + + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); + $startHour = (int)$startTime->format('H'); + $endHour = (int)$endTime->format('H'); + $startMinute = (int)$startTime->format('i'); + $endMinute = (int)$endTime->format('i'); + $isFuture = ($this->type && $this->type === 'future'); + + if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startTime > $selectedDate->setTime(0, 0)) { + $errorList[] = [ + 'type' => 'startTimeFuture', + 'message' => "Das Startdatum der Öffnungszeit muss vor dem " . $tomorrow->format('d.m.Y') . " liegen." + ]; + } + + if (($startHour == 0 && $startMinute == 0) || ($endHour == 0 && $endMinute == 0)) { + $errorList[] = [ + 'type' => 'startOfDay', + 'message' => 'Die Uhrzeit darf nicht "00:00" sein.' + ]; + } + + return $errorList; + } + + public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + { + $errorList = []; + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); + + $startHour = (int)$startTime->format('H'); + $endHour = (int)$endTime->format('H'); + $startMinute = (int)$startTime->format('i'); + $endMinute = (int)$endTime->format('i'); + $dayMinutesStart = ($startHour * 60) + $startMinute; + $dayMinutesEnd = ($endHour * 60) + $endMinute; + $startTimestamp = $startTime->getTimestamp(); + $endTimestamp = $endTime->getTimestamp(); + + if ($dayMinutesEnd <= $dayMinutesStart) { + $errorList[] = [ + 'type' => 'endTime', + 'message' => 'Die Uhrzeit "von" muss kleiner der Uhrzeit "bis" sein.' + ]; + } elseif ($startTimestamp >= $endTimestamp) { + $errorList[] = [ + 'type' => 'endTime', + 'message' => 'Das Startdatum muss vor dem Enddatum sein.' + ]; + } + + return $errorList; + } + + public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + { + $errorList = []; + $endTime = $this->getEndDateTime(); + $endHour = (int) $endTime->format('H'); + $endMinute = (int) $endTime->format('i'); + $endDateTime = (clone $endTime)->setTime($endHour, $endMinute); + $endTimestamp = $endDateTime->getTimestamp(); + $isOrigin = ($this->type && $this->type === 'origin'); + + if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endTime < $selectedDate->setTime(0, 0)) { + $errorList[] = [ + 'type' => 'endTimeFuture', + 'message' => "Das Enddatum der Öffnungszeit muss nach dem " . $yesterday->format('d.m.Y') . " liegen." + ]; + } + + if (!$isOrigin && $endTimestamp < $today->getTimestamp()) { + $errorList[] = [ + 'type' => 'endTimePast', + 'message' => 'Öffnungszeiten in der Vergangenheit lassen sich nicht bearbeiten ' + . '(Die aktuelle Zeit "' . $today->format('d.m.Y H:i') . ' Uhr" liegt nach dem Terminende am "' + . $endDateTime->format('d.m.Y H:i') . ' Uhr").' + ]; + } + + return $errorList; + } + + public function validateType() + { + $errorList = []; + if (empty($this->type)) { + $errorList[] = [ + 'type' => 'type', + 'message' => 'Typ erforderlich' + ]; + } + return $errorList; + } + + public function validateSlotTime() + { + $errorList = []; + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); + $slotTime = $this['slotTimeInMinutes']; + $startTimestamp = $startTime->getTimestamp(); + $endTimestamp = $endTime->getTimestamp(); + + $slotAmount = ($endTimestamp - $startTimestamp) / 60 % $slotTime; + if ($slotAmount > 0) { + $errorList[] = [ + 'type' => 'slotCount', + 'message' => 'Zeitschlitze müssen sich gleichmäßig in der Öffnungszeit aufteilen lassen.' + ]; + } + + return $errorList; + } + + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + { + $errorList = array_merge( + $this->validateStartTime($today, $selectedDate->modify('+1 day'), $selectedDate), + $this->validateEndTime($today, $yesterday, $selectedDate), + $this->validateOriginEndTime($today, $yesterday, $selectedDate), + $this->validateType(), + $this->validateSlotTime() + ); + + return $errorList; + } + /** * Get problems on configuration of this availability * @@ -632,35 +766,36 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ && $this->hasSharedWeekdayWith($availability) ) { $processTemplate = new Process(); - $processTemplate->amendment = "Zwei Öffnungszeiten überschneiden sich."; $processTemplate->status = 'conflict'; $appointment = $processTemplate->getFirstAppointment(); $appointment->availability = $this; $appointment->date = $this->getStartDateTime()->getTimestamp(); - $thisStart = $this->getStartDateTime()->getSecondsOfDay(); - $thisEnd = $this->getEndDateTime()->getSecondsOfDay(); - $availabilityStart = $availability->getStartDateTime()->getSecondsOfDay(); - $availabilityEnd = $availability->getEndDateTime()->getSecondsOfDay(); - - $isEqual = ($availabilityStart == $thisStart && $availabilityEnd == $thisEnd); - - if ($availabilityStart < $thisEnd && $thisStart < $availabilityEnd && ! $isEqual) { - $process = clone $processTemplate; - $process->getFirstAppointment()->date = $this - ->getStartDateTime() - ->modify($currentDate->format("Y-m-d")) - ->getTimestamp(); - $processList->addEntity($process); - } elseif ($thisEnd < $availabilityStart && $availabilityEnd < $thisStart && ! $isEqual) { + + $existingDateRange = $this->getStartDateTime()->format('d.m.Y') . ' - ' . $this->getEndDateTime()->format('d.m.Y'); + $newDateRange = $availability->getStartDateTime()->format('d.m.Y') . ' - ' . $availability->getEndDateTime()->format('d.m.Y'); + + $existingTimeRange = $this->getStartDateTime()->format('H:i') . ' - ' . $this->getEndDateTime()->format('H:i'); + $newTimeRange = $availability->getStartDateTime()->format('H:i') . ' - ' . $availability->getEndDateTime()->format('H:i'); + + $isEqual = ($this->getStartDateTime()->getSecondsOfDay() == $availability->getStartDateTime()->getSecondsOfDay() && + $this->getEndDateTime()->getSecondsOfDay() == $availability->getEndDateTime()->getSecondsOfDay()); + if ($isEqual) { $process = clone $processTemplate; + $process->amendment = "Konflikt: Zwei Öffnungszeiten sind gleich.\n" + . "Bestehende Öffnungszeit:  [$newDateRange, $newTimeRange]\n" + . "Neue Öffnungszeit:                 [$existingDateRange, $existingTimeRange]"; $process->getFirstAppointment()->date = $availability ->getStartDateTime() ->modify($currentDate->format("Y-m-d")) ->getTimestamp(); $processList->addEntity($process); - } elseif ($isEqual) { + } + elseif ($availability->getStartDateTime()->getSecondsOfDay() < $this->getEndDateTime()->getSecondsOfDay() && + $this->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay()) { $process = clone $processTemplate; - $process->amendment = "Zwei Öffnungszeiten sind gleich."; + $process->amendment = "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" + . "Bestehende Öffnungszeit:  [$newDateRange, $newTimeRange]\n" + . "Neue Öffnungszeit:                 [$existingDateRange, $existingTimeRange]"; $process->getFirstAppointment()->date = $availability ->getStartDateTime() ->modify($currentDate->format("Y-m-d")) @@ -668,8 +803,14 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ $processList->addEntity($process); } } + return $processList; } + + + + + /** * Update workstationCount to number of calculated appointments diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index f4606aae2..971847a11 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -161,6 +161,20 @@ public function getSlotListByType($type) return $slotList; } + public function validateInputs($startDate, $endDate){ + + $errorList = []; + foreach ($this as $availability) { + $today = new \DateTime(); + $yesterday = (clone $today)->modify('-1 day'); + + $errorList = $availability->validateAll($today, $yesterday, $startDate); + + } + return $errorList; + + } + public function getConflicts($startDate, $endDate) { $processList = new ProcessList(); From 5543f360c955070fadbdf1fde8f3972d775e241f Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 11:15:07 +0100 Subject: [PATCH 03/86] fix(ZMS-3253): fix zmsentities unit test --- .../tests/Zmsentities/AvailabilityTest.php | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index 79a6fcf59..ecd531be8 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -541,7 +541,7 @@ public function testCollection() $this->assertTrue( 2 == count($collection), 'Amount of entities in collection failed, 2 expected (' . - count($collection) . ' found)' + count($collection) . ' found)' ); $this->assertTrue( @@ -878,36 +878,83 @@ public function testConflicts() */ $id = $conflict->getFirstAppointment()->getAvailability()->getId(); - if (! isset($list[$conflict->amendment])) { + if (!isset($list[$conflict->amendment])) { $list[$conflict->amendment] = []; } - if (! isset($list[$conflict->amendment][$id])) { + if (!isset($list[$conflict->amendment][$id])) { $list[$conflict->amendment][$id] = 1; } else { $list[$conflict->amendment][$id] += 1; } } - - // Availability 1 und 5 überschneiden sich jeweils 3 mal - $this->assertEquals(3, $list['Zwei Öffnungszeiten überschneiden sich.'][1]); - $this->assertEquals(3, $list['Zwei Öffnungszeiten überschneiden sich.'][5]); - // Availability 2, 4 und 6 überschneiden sich jeweils 2 mal - $this->assertEquals(2, $list['Zwei Öffnungszeiten überschneiden sich.'][2]); - $this->assertEquals(2, $list['Zwei Öffnungszeiten überschneiden sich.'][4]); - $this->assertEquals(2, $list['Zwei Öffnungszeiten überschneiden sich.'][6]); + // Assertion for overlapping availabilities - Availability 1 and 5 + $this->assertEquals( + 1, + $list[ + "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 10:00 - 13:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 12:00 - 16:00]" + ][1] + ); + + $this->assertEquals( + 1, + $list[ + "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 10:00 - 13:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 12:00 - 16:00]" + ][5] + ); + + // Assertions for overlapping availabilities - Availability 2, 4 + $this->assertEquals( + 2, + $list[ + "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 12:00 - 16:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 10:00 - 13:00]" + ][2] + ); - // Availability 1 und 5 sind sich jeweils gleich - $this->assertEquals(1, $list['Zwei Öffnungszeiten sind gleich.'][1]); - $this->assertEquals(1, $list['Zwei Öffnungszeiten sind gleich.'][5]); + $this->assertEquals( + 2, + $list[ + "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 12:00 - 16:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 15:00 - 17:00]" + ][4] + ); - // Availability 3 hat eine falsche Slotgröße + // Assertions for exact matches - Availability 1 and 5 $this->assertEquals( 1, - $list['Der eingestellte Zeitschlitz von 25 Minuten sollte in die eingestellte Uhrzeit passen.'][3] + $list[ + "Konflikt: Zwei Öffnungszeiten sind gleich.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 12:00 - 16:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 12:00 - 16:00]" + ][1] + ); + + $this->assertEquals( + 1, + $list[ + "Konflikt: Zwei Öffnungszeiten sind gleich.\n" . + "Bestehende Öffnungszeit:  [19.04.2016 - 19.04.2016, 12:00 - 16:00]\n" . + "Neue Öffnungszeit:                 [19.04.2016 - 19.04.2016, 12:00 - 16:00]" + ][5] ); - } + // Assertion for slot size conflict + $this->assertEquals( + 1, + $list[ + 'Der eingestellte Zeitschlitz von 25 Minuten sollte in die eingestellte Uhrzeit passen.' + ][3] + ); + + + } protected function getExampleWithTypeOpeningHours(\DateTimeImmutable $time) { From 03bc86e173d37102220262241d2a36e091657951 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 11:26:06 +0100 Subject: [PATCH 04/86] fix(ZMS-3253): fix zmsdb unit test --- zmsdb/tests/Zmsdb/ProcessConflictTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/zmsdb/tests/Zmsdb/ProcessConflictTest.php b/zmsdb/tests/Zmsdb/ProcessConflictTest.php index 48b5f70e3..5da34cd3f 100644 --- a/zmsdb/tests/Zmsdb/ProcessConflictTest.php +++ b/zmsdb/tests/Zmsdb/ProcessConflictTest.php @@ -53,8 +53,8 @@ public function testOverbookedOnDay() } /* - * Test a single day availability without repeats but with conflicts out of availability start and enttime - */ + * Test a single day availability without repeats but with conflicts out of availability start and enttime + */ public function testSingleDayOutOfAvailability() { @@ -100,7 +100,9 @@ public function testEqual() (new \BO\Zmsdb\Availability())->writeEntity($availabilityCopy); $conflictList = (new \BO\Zmsdb\Process())->readConflictListByScopeAndTime($scope, $startDate, null, $now, 0); $this->assertEquals(2, $conflictList->count()); - $this->assertEquals('Zwei Öffnungszeiten sind gleich.', $conflictList->getFirst()->getAmendment()); + $this->assertEquals("Konflikt: Zwei Öffnungszeiten sind gleich.\n" . + "Bestehende Öffnungszeit:  [30.01.2016 - 22.05.2016, 08:00 - 13:50]\n" . + "Neue Öffnungszeit:                 [30.01.2016 - 22.05.2016, 08:00 - 13:50]", $conflictList->getFirst()->getAmendment()); $this->assertEquals('conflict', $conflictList->getFirst()->getStatus()); } @@ -115,7 +117,9 @@ public function testOverLap() (new \BO\Zmsdb\Availability())->writeEntity($availabilityCopy); $conflictList = (new \BO\Zmsdb\Process())->readConflictListByScopeAndTime($scope, $startDate, null, $now, 0); $this->assertEquals(2, $conflictList->count()); - $this->assertEquals('Zwei Öffnungszeiten überschneiden sich.', $conflictList->getFirst()->getAmendment()); + $this->assertEquals("Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . + "Bestehende Öffnungszeit:  [30.01.2016 - 22.05.2016, 08:00 - 15:50]\n" . + "Neue Öffnungszeit:                 [30.01.2016 - 22.05.2016, 08:00 - 13:50]", $conflictList->getFirst()->getAmendment()); $this->assertEquals('conflict', $conflictList->getFirst()->getStatus()); } } From ffcdb0a0928246cd8d68e09790ea0a510c0cb4db Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 12:35:45 +0100 Subject: [PATCH 05/86] fix(ZMS-3253): add logging to zmsapi tests --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 1 + zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 9f69e7cf4..dcdfdf663 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -26,6 +26,7 @@ public function testRendering() } ]' ], []); + error_log(json_encode((string)$response->getBody())); $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 736c7acf8..842abe762 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -13,6 +13,7 @@ class AvailabilityUpdateTest extends Base public function testRendering() { $input = (new Entity)->createExample(); + error_log(json_encode($input)); $entity = (new Query())->writeEntity($input); $this->setWorkstation(); $response = $this->render(["id"=> $entity->getId()], [ From 47565c820e2aea019e1ce1b5d9c48b1f1851c534 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 12:41:50 +0100 Subject: [PATCH 06/86] fix(ZMS-3253): fix one zmsapi unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 842abe762..2a7737d65 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -13,21 +13,32 @@ class AvailabilityUpdateTest extends Base public function testRendering() { $input = (new Entity)->createExample(); - error_log(json_encode($input)); + + // Dynamically adjust the endDate to be in the future + $currentTimestamp = time(); + $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // Set startDate to 2 days in the future + $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // Set endDate to 5 days in the future + + error_log(json_encode($input)); // Log for debugging + + // Write the entity using the modified input $entity = (new Query())->writeEntity($input); $this->setWorkstation(); - $response = $this->render(["id"=> $entity->getId()], [ - '__body' => '{ - "id": '. $entity->getId() .', - "description": "", - "scope": { - "id": 312 - } - }' + + // Prepare the response and test rendering + $response = $this->render([ + "id" => $entity->getId() + ], [ + '__body' => json_encode([ + "id" => $entity->getId(), + "description" => "", + "scope" => ["id" => 312] + ]) ], []); $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } + public function testEmpty() { From 3f8030e10b06c74dbb485d87db462654a273eaa1 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 16:45:39 +0100 Subject: [PATCH 07/86] fix(ZMS-3253): try fix one zmsapi unit test --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 2a7737d65..097c4a519 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -19,10 +19,11 @@ public function testRendering() $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // Set startDate to 2 days in the future $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // Set endDate to 5 days in the future - error_log(json_encode($input)); // Log for debugging + // Write the entity using the modified input $entity = (new Query())->writeEntity($input); + error_log(json_encode($entity)); // Log for debugging $this->setWorkstation(); // Prepare the response and test rendering From f5e08ed4b2a71f98b9246e89a1ced12c07d25fa6 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:00:32 +0100 Subject: [PATCH 08/86] fix(ZMS-3253): try fix one zmsapi unit test --- zmsentities/schema/availability.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsentities/schema/availability.json b/zmsentities/schema/availability.json index cd8ddcdb6..c6ed256fb 100644 --- a/zmsentities/schema/availability.json +++ b/zmsentities/schema/availability.json @@ -18,7 +18,7 @@ "scope": { "id": 141 }, - "slotTimeInMinutes": 12, + "slotTimeInMinutes": 10, "startDate": 1447919543, "startTime": "10:00", "weekday": { From e4b36ea045006cc23cfb389360dc0c93dec2290c Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:22:19 +0100 Subject: [PATCH 09/86] fix(ZMS-3253): try fix some unit tests --- zmsdb/tests/Zmsdb/AvailabilityTest.php | 2 +- zmsentities/tests/Zmsentities/AvailabilityTest.php | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/zmsdb/tests/Zmsdb/AvailabilityTest.php b/zmsdb/tests/Zmsdb/AvailabilityTest.php index 2c2f1abd5..8342d8c5a 100644 --- a/zmsdb/tests/Zmsdb/AvailabilityTest.php +++ b/zmsdb/tests/Zmsdb/AvailabilityTest.php @@ -74,7 +74,7 @@ public function testWriteEntity() $lastInsertedId = $entity->id; $entity = $query->readEntity($lastInsertedId, 1); - $this->assertEquals(12, $entity->slotTimeInMinutes); + $this->assertEquals(10, $entity->slotTimeInMinutes); $this->assertTrue((bool)$entity->weekday['thursday']); $this->assertTrue((bool)$entity->weekday['friday']); diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index ecd531be8..80a1475db 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -179,7 +179,7 @@ public function testGetAvailableSecondsPerDay() { $entity = (new $this->entityclass())->getExample(); $withCalculatedSlots = $entity->withCalculatedSlots(); - $this->assertEquals(5346000, $withCalculatedSlots->getAvailableSecondsPerDay()); + $this->assertEquals(6534000, $withCalculatedSlots->getAvailableSecondsPerDay()); } public function testGetAvailableSecondsOnDateTime() @@ -196,7 +196,7 @@ public function testGetAvailableSecondsOnDateTime() $collection = new $this->collectionclass(); $collection->addEntity($entity); $collection = $collection->withCalculatedSlots(); - $this->assertEquals(5346000, $collection->getAvailableSecondsOnDateTime($time)); + $this->assertEquals(6534000, $collection->getAvailableSecondsOnDateTime($time)); } public function testDayOff() @@ -498,6 +498,7 @@ public function testWithCalculatedSlots() { $entity = (new $this->entityclass())->getExample(); $withCalculatedSlots = $entity->withCalculatedSlots(); + error_log("*" . $withCalculatedSlots['workstationCount']['public']); $this->assertTrue(81 == $withCalculatedSlots['workstationCount']['public'], $withCalculatedSlots); } @@ -507,6 +508,7 @@ public function testGetSlotList() $entity = (new $this->entityclass())->getExample(); $collection->addEntity($entity); $slotList = $collection->getSlotList(); + error_log("-" . count($slotList)); $this->assertTrue(28 == count($slotList)); $this->assertEquals('10:00', $slotList->getFirst()['time']); $this->assertEquals('10:12', $slotList[1]['time']); From e5f123c23b620a027bfcbde4f79971dcd5460a2a Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:32:57 +0100 Subject: [PATCH 10/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/tests/Zmsentities/AvailabilityTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index 80a1475db..6ef0c4681 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -144,7 +144,7 @@ public function testWeekCase35851() $entity = new $this->entityclass(); // A friday $time = new \DateTimeImmutable('2019-01-02 11:55:00'); - $now = new \DateTimeImmutable('2019-02-28 11:55:00'); + $now = new \DateTimeImmutable('2019-02-33 11:55:00'); $entity['startDate'] = $time->getTimestamp(); $entity['startTime'] = $time->format('H:i'); $entity['endDate'] = $time->modify("+12month") @@ -499,7 +499,7 @@ public function testWithCalculatedSlots() $entity = (new $this->entityclass())->getExample(); $withCalculatedSlots = $entity->withCalculatedSlots(); error_log("*" . $withCalculatedSlots['workstationCount']['public']); - $this->assertTrue(81 == $withCalculatedSlots['workstationCount']['public'], $withCalculatedSlots); + $this->assertTrue(99 == $withCalculatedSlots['workstationCount']['public'], $withCalculatedSlots); } public function testGetSlotList() @@ -509,7 +509,7 @@ public function testGetSlotList() $collection->addEntity($entity); $slotList = $collection->getSlotList(); error_log("-" . count($slotList)); - $this->assertTrue(28 == count($slotList)); + $this->assertTrue(33 == count($slotList)); $this->assertEquals('10:00', $slotList->getFirst()['time']); $this->assertEquals('10:12', $slotList[1]['time']); } @@ -552,7 +552,7 @@ public function testCollection() ); $this->assertTrue( - 81 == $collection->withCalculatedSlots()[0]['workstationCount']['public'], + 99 == $collection->withCalculatedSlots()[0]['workstationCount']['public'], 'Failed to get list with calculated slots' ); $collection->addEntity($entity); From 9528271c2ec0cc69652514d01f2d23e554efa3b8 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:34:34 +0100 Subject: [PATCH 11/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/tests/Zmsentities/AvailabilityTest.php | 2 +- zmsentities/tests/Zmsentities/ProcessTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index 6ef0c4681..747284073 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -511,7 +511,7 @@ public function testGetSlotList() error_log("-" . count($slotList)); $this->assertTrue(33 == count($slotList)); $this->assertEquals('10:00', $slotList->getFirst()['time']); - $this->assertEquals('10:12', $slotList[1]['time']); + $this->assertEquals('10:10', $slotList[1]['time']); } public function testToString() diff --git a/zmsentities/tests/Zmsentities/ProcessTest.php b/zmsentities/tests/Zmsentities/ProcessTest.php index b6f04dfae..aed0e503d 100644 --- a/zmsentities/tests/Zmsentities/ProcessTest.php +++ b/zmsentities/tests/Zmsentities/ProcessTest.php @@ -491,7 +491,7 @@ public function testToConflictListByDay() //$this->assertEquals('Beispiel Termin', $list['2015-11-18'][0]['message']); $this->assertEquals('18:52', $list['2015-11-18'][0]['appointments'][0]['startTime']); // endTime = slotTimeInMinutes * slotCount 12X2 = 24 - $this->assertEquals('19:16', $list['2015-11-18'][0]['appointments'][0]['endTime']); + $this->assertEquals('19:12', $list['2015-11-18'][0]['appointments'][0]['endTime']); } public function testToQueue() From 770e847e6e44f719da4c35cc54cc5bfbd434c767 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:39:06 +0100 Subject: [PATCH 12/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/tests/Zmsentities/AvailabilityTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index 747284073..c86621e97 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -498,7 +498,6 @@ public function testWithCalculatedSlots() { $entity = (new $this->entityclass())->getExample(); $withCalculatedSlots = $entity->withCalculatedSlots(); - error_log("*" . $withCalculatedSlots['workstationCount']['public']); $this->assertTrue(99 == $withCalculatedSlots['workstationCount']['public'], $withCalculatedSlots); } @@ -508,7 +507,6 @@ public function testGetSlotList() $entity = (new $this->entityclass())->getExample(); $collection->addEntity($entity); $slotList = $collection->getSlotList(); - error_log("-" . count($slotList)); $this->assertTrue(33 == count($slotList)); $this->assertEquals('10:00', $slotList->getFirst()['time']); $this->assertEquals('10:10', $slotList[1]['time']); From 4a796058f9b103891ace0b0b53ee5b8ae76f5704 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:40:41 +0100 Subject: [PATCH 13/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/tests/Zmsentities/AvailabilityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsentities/tests/Zmsentities/AvailabilityTest.php b/zmsentities/tests/Zmsentities/AvailabilityTest.php index c86621e97..d7310cd22 100644 --- a/zmsentities/tests/Zmsentities/AvailabilityTest.php +++ b/zmsentities/tests/Zmsentities/AvailabilityTest.php @@ -144,7 +144,7 @@ public function testWeekCase35851() $entity = new $this->entityclass(); // A friday $time = new \DateTimeImmutable('2019-01-02 11:55:00'); - $now = new \DateTimeImmutable('2019-02-33 11:55:00'); + $now = new \DateTimeImmutable('2019-02-28 11:55:00'); $entity['startDate'] = $time->getTimestamp(); $entity['startTime'] = $time->format('H:i'); $entity['endDate'] = $time->modify("+12month") From cdd0d8c0d2b354ea513be3cbdb86de57634e457f Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:49:17 +0100 Subject: [PATCH 14/86] fix(ZMS-3253): try fix some unit tests --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 4 ++-- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 5f4f26c2e..5566c95ba 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -70,9 +70,9 @@ public function readResponse( } $validation = $mergedCollection->validateInputs($startDate, $endDate); - + error_log(json_encode($validation)); if (count($validation) > 0) { - $endTimeValidationArray = json_decode(json_encode($validation), true); + $validation = json_decode(json_encode($validation), true); throw new AvailabilityUpdateFailed(); } diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index ec4165bda..1be4696e7 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -63,9 +63,9 @@ public function readResponse( $mergedCollection->addEntity($entity); $validation = $mergedCollection->validateInputs($startDate, $endDate); - + error_log(json_encode($validation)); if (count($validation) > 0) { - $endTimeValidationArray = json_decode(json_encode($validation), true); + $validation = json_decode(json_encode($validation), true); throw new AvailabilityUpdateFailed(); } From 8a1aa790186fa02d2c237cd16c0b1965af1d4558 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:53:11 +0100 Subject: [PATCH 15/86] fix(ZMS-3253): try fix some unit tests --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 2 ++ zmsapi/src/Zmsapi/AvailabilityUpdate.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 5566c95ba..b94cb4c58 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -70,6 +70,8 @@ public function readResponse( } $validation = $mergedCollection->validateInputs($startDate, $endDate); + error_log("AvailabilityAdd"); + error_log("**********"); error_log(json_encode($validation)); if (count($validation) > 0) { $validation = json_decode(json_encode($validation), true); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 1be4696e7..b409d7a89 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -63,6 +63,8 @@ public function readResponse( $mergedCollection->addEntity($entity); $validation = $mergedCollection->validateInputs($startDate, $endDate); + error_log("AvailabilityUpdate"); + error_log(message: "-----------"); error_log(json_encode($validation)); if (count($validation) > 0) { $validation = json_decode(json_encode($validation), true); From 09c10fbda3ea94d9fd46b1bf70ba4d56c86e0a29 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 17:58:29 +0100 Subject: [PATCH 16/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 59d946f3f..336860c64 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -575,7 +575,11 @@ public function validateSlotTime() public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) { $errorList = array_merge( - $this->validateStartTime($today, $selectedDate->modify('+1 day'), $selectedDate), + $this->validateStartTime( + $today, + ($selectedDate instanceof \DateTimeImmutable) ? $selectedDate->modify('+1 day') : (clone $selectedDate)->modify('+1 day'), + $selectedDate + ), $this->validateEndTime($today, $yesterday, $selectedDate), $this->validateOriginEndTime($today, $yesterday, $selectedDate), $this->validateType(), @@ -583,7 +587,7 @@ public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yeste ); return $errorList; - } + } /** * Get problems on configuration of this availability From afd6d5d776962626fe3b9943f122fd84c2f91d79 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:07:41 +0100 Subject: [PATCH 17/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 12 ++++-------- .../src/Zmsentities/Collection/AvailabilityList.php | 3 ++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 336860c64..0fc2a53c6 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -572,22 +572,18 @@ public function validateSlotTime() return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) { $errorList = array_merge( - $this->validateStartTime( - $today, - ($selectedDate instanceof \DateTimeImmutable) ? $selectedDate->modify('+1 day') : (clone $selectedDate)->modify('+1 day'), - $selectedDate - ), - $this->validateEndTime($today, $yesterday, $selectedDate), + $this->validateStartTime($today, $tomorrow, $selectedDate), + $this->validateEndTime($today, $yesterday, selectedDate: $selectedDate), $this->validateOriginEndTime($today, $yesterday, $selectedDate), $this->validateType(), $this->validateSlotTime() ); return $errorList; - } + } /** * Get problems on configuration of this availability diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 971847a11..25e55bf2e 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -167,8 +167,9 @@ public function validateInputs($startDate, $endDate){ foreach ($this as $availability) { $today = new \DateTime(); $yesterday = (clone $today)->modify('-1 day'); + $tomorrow = (clone $today)->modify('+1 day'); - $errorList = $availability->validateAll($today, $yesterday, $startDate); + $errorList = $availability->validateAll($today, $yesterday, $tomorrow, $startDate); } return $errorList; From ce5d7951b94fd27d5c4437ea9f84f52a43aeff56 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:29:27 +0100 Subject: [PATCH 18/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 56 +++++++++---------- .../Collection/AvailabilityList.php | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 0fc2a53c6..79ddc175e 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,17 +452,17 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateStartTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); + $startTime = $availability->getStartDateTime(); + $endTime = $availability->getEndDateTime(); $startHour = (int)$startTime->format('H'); $endHour = (int)$endTime->format('H'); $startMinute = (int)$startTime->format('i'); $endMinute = (int)$endTime->format('i'); - $isFuture = ($this->type && $this->type === 'future'); + $isFuture = ($availability->type && $availability->type === 'future'); if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startTime > $selectedDate->setTime(0, 0)) { $errorList[] = [ @@ -481,11 +481,11 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface return $errorList; } - public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateEndTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); + $startTime = $availability->getStartDateTime(); + $endTime = $availability->getEndDateTime(); $startHour = (int)$startTime->format('H'); $endHour = (int)$endTime->format('H'); @@ -511,15 +511,15 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y return $errorList; } - public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateOriginEndTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) { $errorList = []; - $endTime = $this->getEndDateTime(); + $endTime = $availability->getEndDateTime(); $endHour = (int) $endTime->format('H'); $endMinute = (int) $endTime->format('i'); $endDateTime = (clone $endTime)->setTime($endHour, $endMinute); $endTimestamp = $endDateTime->getTimestamp(); - $isOrigin = ($this->type && $this->type === 'origin'); + $isOrigin = ($availability->type && $availability->type === 'origin'); if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endTime < $selectedDate->setTime(0, 0)) { $errorList[] = [ @@ -540,10 +540,10 @@ public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterf return $errorList; } - public function validateType() + public function validateType(Availability $availability) { $errorList = []; - if (empty($this->type)) { + if (empty($availability->type)) { $errorList[] = [ 'type' => 'type', 'message' => 'Typ erforderlich' @@ -552,11 +552,11 @@ public function validateType() return $errorList; } - public function validateSlotTime() + public function validateSlotTime(Availability $availability) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); + $startTime = $availability->getStartDateTime(); + $endTime = $availability->getEndDateTime(); $slotTime = $this['slotTimeInMinutes']; $startTimestamp = $startTime->getTimestamp(); $endTimestamp = $endTime->getTimestamp(); @@ -572,14 +572,14 @@ public function validateSlotTime() return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateAll(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) { $errorList = array_merge( - $this->validateStartTime($today, $tomorrow, $selectedDate), - $this->validateEndTime($today, $yesterday, selectedDate: $selectedDate), - $this->validateOriginEndTime($today, $yesterday, $selectedDate), - $this->validateType(), - $this->validateSlotTime() + $this->validateStartTime($availability, $today, $tomorrow, $selectedDate), + $this->validateEndTime($availability, $today, $yesterday, selectedDate: $selectedDate), + $this->validateOriginEndTime($availability, $today, $yesterday, $selectedDate), + $this->validateType($availability), + $this->validateSlotTime($availability) ); return $errorList; @@ -769,16 +769,16 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ $processTemplate->status = 'conflict'; $appointment = $processTemplate->getFirstAppointment(); $appointment->availability = $this; - $appointment->date = $this->getStartDateTime()->getTimestamp(); + $appointment->date = $availability->getStartDateTime()->getTimestamp(); - $existingDateRange = $this->getStartDateTime()->format('d.m.Y') . ' - ' . $this->getEndDateTime()->format('d.m.Y'); + $existingDateRange = $availability->getStartDateTime()->format('d.m.Y') . ' - ' . $availability->getEndDateTime()->format('d.m.Y'); $newDateRange = $availability->getStartDateTime()->format('d.m.Y') . ' - ' . $availability->getEndDateTime()->format('d.m.Y'); - $existingTimeRange = $this->getStartDateTime()->format('H:i') . ' - ' . $this->getEndDateTime()->format('H:i'); + $existingTimeRange = $availability->getStartDateTime()->format('H:i') . ' - ' . $availability->getEndDateTime()->format('H:i'); $newTimeRange = $availability->getStartDateTime()->format('H:i') . ' - ' . $availability->getEndDateTime()->format('H:i'); - $isEqual = ($this->getStartDateTime()->getSecondsOfDay() == $availability->getStartDateTime()->getSecondsOfDay() && - $this->getEndDateTime()->getSecondsOfDay() == $availability->getEndDateTime()->getSecondsOfDay()); + $isEqual = ($availability->getStartDateTime()->getSecondsOfDay() == $availability->getStartDateTime()->getSecondsOfDay() && + $availability->getEndDateTime()->getSecondsOfDay() == $availability->getEndDateTime()->getSecondsOfDay()); if ($isEqual) { $process = clone $processTemplate; $process->amendment = "Konflikt: Zwei Öffnungszeiten sind gleich.\n" @@ -790,8 +790,8 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ ->getTimestamp(); $processList->addEntity($process); } - elseif ($availability->getStartDateTime()->getSecondsOfDay() < $this->getEndDateTime()->getSecondsOfDay() && - $this->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay()) { + elseif ($availability->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay() && + $availability->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay()) { $process = clone $processTemplate; $process->amendment = "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . "Bestehende Öffnungszeit:  [$newDateRange, $newTimeRange]\n" diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 25e55bf2e..3d8c53972 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -169,7 +169,7 @@ public function validateInputs($startDate, $endDate){ $yesterday = (clone $today)->modify('-1 day'); $tomorrow = (clone $today)->modify('+1 day'); - $errorList = $availability->validateAll($today, $yesterday, $tomorrow, $startDate); + $errorList = $availability->validateAll($availability, $today, $yesterday, $tomorrow, $startDate); } return $errorList; From 07f74c8a05a657a2bc37609537624c7345a48be1 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:33:12 +0100 Subject: [PATCH 19/86] Revert "fix(ZMS-3253): try fix some unit tests" This reverts commit ce5d7951b94fd27d5c4437ea9f84f52a43aeff56. --- zmsentities/src/Zmsentities/Availability.php | 56 +++++++++---------- .../Collection/AvailabilityList.php | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 79ddc175e..0fc2a53c6 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,17 +452,17 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) { $errorList = []; - $startTime = $availability->getStartDateTime(); - $endTime = $availability->getEndDateTime(); + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); $startHour = (int)$startTime->format('H'); $endHour = (int)$endTime->format('H'); $startMinute = (int)$startTime->format('i'); $endMinute = (int)$endTime->format('i'); - $isFuture = ($availability->type && $availability->type === 'future'); + $isFuture = ($this->type && $this->type === 'future'); if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startTime > $selectedDate->setTime(0, 0)) { $errorList[] = [ @@ -481,11 +481,11 @@ public function validateStartTime(Availability $availability, \DateTimeInterface return $errorList; } - public function validateEndTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) { $errorList = []; - $startTime = $availability->getStartDateTime(); - $endTime = $availability->getEndDateTime(); + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); $startHour = (int)$startTime->format('H'); $endHour = (int)$endTime->format('H'); @@ -511,15 +511,15 @@ public function validateEndTime(Availability $availability, \DateTimeInterface $ return $errorList; } - public function validateOriginEndTime(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) { $errorList = []; - $endTime = $availability->getEndDateTime(); + $endTime = $this->getEndDateTime(); $endHour = (int) $endTime->format('H'); $endMinute = (int) $endTime->format('i'); $endDateTime = (clone $endTime)->setTime($endHour, $endMinute); $endTimestamp = $endDateTime->getTimestamp(); - $isOrigin = ($availability->type && $availability->type === 'origin'); + $isOrigin = ($this->type && $this->type === 'origin'); if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endTime < $selectedDate->setTime(0, 0)) { $errorList[] = [ @@ -540,10 +540,10 @@ public function validateOriginEndTime(Availability $availability, \DateTimeInter return $errorList; } - public function validateType(Availability $availability) + public function validateType() { $errorList = []; - if (empty($availability->type)) { + if (empty($this->type)) { $errorList[] = [ 'type' => 'type', 'message' => 'Typ erforderlich' @@ -552,11 +552,11 @@ public function validateType(Availability $availability) return $errorList; } - public function validateSlotTime(Availability $availability) + public function validateSlotTime() { $errorList = []; - $startTime = $availability->getStartDateTime(); - $endTime = $availability->getEndDateTime(); + $startTime = $this->getStartDateTime(); + $endTime = $this->getEndDateTime(); $slotTime = $this['slotTimeInMinutes']; $startTimestamp = $startTime->getTimestamp(); $endTimestamp = $endTime->getTimestamp(); @@ -572,14 +572,14 @@ public function validateSlotTime(Availability $availability) return $errorList; } - public function validateAll(Availability $availability, \DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) { $errorList = array_merge( - $this->validateStartTime($availability, $today, $tomorrow, $selectedDate), - $this->validateEndTime($availability, $today, $yesterday, selectedDate: $selectedDate), - $this->validateOriginEndTime($availability, $today, $yesterday, $selectedDate), - $this->validateType($availability), - $this->validateSlotTime($availability) + $this->validateStartTime($today, $tomorrow, $selectedDate), + $this->validateEndTime($today, $yesterday, selectedDate: $selectedDate), + $this->validateOriginEndTime($today, $yesterday, $selectedDate), + $this->validateType(), + $this->validateSlotTime() ); return $errorList; @@ -769,16 +769,16 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ $processTemplate->status = 'conflict'; $appointment = $processTemplate->getFirstAppointment(); $appointment->availability = $this; - $appointment->date = $availability->getStartDateTime()->getTimestamp(); + $appointment->date = $this->getStartDateTime()->getTimestamp(); - $existingDateRange = $availability->getStartDateTime()->format('d.m.Y') . ' - ' . $availability->getEndDateTime()->format('d.m.Y'); + $existingDateRange = $this->getStartDateTime()->format('d.m.Y') . ' - ' . $this->getEndDateTime()->format('d.m.Y'); $newDateRange = $availability->getStartDateTime()->format('d.m.Y') . ' - ' . $availability->getEndDateTime()->format('d.m.Y'); - $existingTimeRange = $availability->getStartDateTime()->format('H:i') . ' - ' . $availability->getEndDateTime()->format('H:i'); + $existingTimeRange = $this->getStartDateTime()->format('H:i') . ' - ' . $this->getEndDateTime()->format('H:i'); $newTimeRange = $availability->getStartDateTime()->format('H:i') . ' - ' . $availability->getEndDateTime()->format('H:i'); - $isEqual = ($availability->getStartDateTime()->getSecondsOfDay() == $availability->getStartDateTime()->getSecondsOfDay() && - $availability->getEndDateTime()->getSecondsOfDay() == $availability->getEndDateTime()->getSecondsOfDay()); + $isEqual = ($this->getStartDateTime()->getSecondsOfDay() == $availability->getStartDateTime()->getSecondsOfDay() && + $this->getEndDateTime()->getSecondsOfDay() == $availability->getEndDateTime()->getSecondsOfDay()); if ($isEqual) { $process = clone $processTemplate; $process->amendment = "Konflikt: Zwei Öffnungszeiten sind gleich.\n" @@ -790,8 +790,8 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ ->getTimestamp(); $processList->addEntity($process); } - elseif ($availability->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay() && - $availability->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay()) { + elseif ($availability->getStartDateTime()->getSecondsOfDay() < $this->getEndDateTime()->getSecondsOfDay() && + $this->getStartDateTime()->getSecondsOfDay() < $availability->getEndDateTime()->getSecondsOfDay()) { $process = clone $processTemplate; $process->amendment = "Konflikt: Eine neue Öffnungszeit überschneidet sich mit einer bestehenden Öffnungszeit.\n" . "Bestehende Öffnungszeit:  [$newDateRange, $newTimeRange]\n" diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 3d8c53972..25e55bf2e 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -169,7 +169,7 @@ public function validateInputs($startDate, $endDate){ $yesterday = (clone $today)->modify('-1 day'); $tomorrow = (clone $today)->modify('+1 day'); - $errorList = $availability->validateAll($availability, $today, $yesterday, $tomorrow, $startDate); + $errorList = $availability->validateAll($today, $yesterday, $tomorrow, $startDate); } return $errorList; From da65ff354a69d55b818c798d25afd866feda3e60 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:46:32 +0100 Subject: [PATCH 20/86] fix(ZMS-3253): try fix some unit tests --- .../Collection/AvailabilityList.php | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 25e55bf2e..8a4406967 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -161,20 +161,28 @@ public function getSlotListByType($type) return $slotList; } - public function validateInputs($startDate, $endDate){ - + public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate) + { $errorList = []; foreach ($this as $availability) { - $today = new \DateTime(); - $yesterday = (clone $today)->modify('-1 day'); - $tomorrow = (clone $today)->modify('+1 day'); - - $errorList = $availability->validateAll($today, $yesterday, $tomorrow, $startDate); - + // Create DateTimeImmutable objects for today, yesterday, and tomorrow + $today = \DateTimeImmutable::createFromMutable($startDate); + $yesterday = $today->modify('-1 day'); + $tomorrow = $today->modify('+1 day'); + + error_log("Today: " . $today->format('Y-m-d H:i:s')); + error_log("Yesterday: " . $yesterday->format('Y-m-d H:i:s')); + error_log("Tomorrow: " . $tomorrow->format('Y-m-d H:i:s')); + + // Pass DateTimeImmutable objects to validateAll() + $errorList = array_merge( + $errorList, + $availability->validateAll($today, $yesterday, $tomorrow, $startDate) + ); } return $errorList; - } + public function getConflicts($startDate, $endDate) { From 93b2820116a7d6afaed46ca0ca2fe00969eb3855 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:50:45 +0100 Subject: [PATCH 21/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Collection/AvailabilityList.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 8a4406967..19c7ff7ae 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -166,9 +166,10 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $errorList = []; foreach ($this as $availability) { // Create DateTimeImmutable objects for today, yesterday, and tomorrow - $today = \DateTimeImmutable::createFromMutable($startDate); + $today = new \DateTime(); $yesterday = $today->modify('-1 day'); $tomorrow = $today->modify('+1 day'); + $today = $today->modify('+0 day'); error_log("Today: " . $today->format('Y-m-d H:i:s')); error_log("Yesterday: " . $yesterday->format('Y-m-d H:i:s')); From e0d41c4835689c48a5ead9c7b52ec64a5ed13bf2 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 18:55:30 +0100 Subject: [PATCH 22/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 1 + 1 file changed, 1 insertion(+) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 0fc2a53c6..27e57363c 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -515,6 +515,7 @@ public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterf { $errorList = []; $endTime = $this->getEndDateTime(); + error_log("endTime: " . $endTime->format('Y-m-d H:i:s')); $endHour = (int) $endTime->format('H'); $endMinute = (int) $endTime->format('i'); $endDateTime = (clone $endTime)->setTime($endHour, $endMinute); From bde21f3978f0a3646775db73e955ca3a507c9178 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:04:00 +0100 Subject: [PATCH 23/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 27 +++++++++---------- .../Collection/AvailabilityList.php | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 27e57363c..52fc445ed 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,7 +452,7 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate) { $errorList = []; @@ -464,7 +464,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $endMinute = (int)$endTime->format('i'); $isFuture = ($this->type && $this->type === 'future'); - if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startTime > $selectedDate->setTime(0, 0)) { + if (!$isFuture && $startDate->getTimestamp() > $today->getTimestamp() && $startTime > $startDate->setTime(0, 0)) { $errorList[] = [ 'type' => 'startTimeFuture', 'message' => "Das Startdatum der Öffnungszeit muss vor dem " . $tomorrow->format('d.m.Y') . " liegen." @@ -481,7 +481,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface return $errorList; } - public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate) { $errorList = []; $startTime = $this->getStartDateTime(); @@ -511,18 +511,17 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y return $errorList; } - public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $selectedDate) + public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = []; - $endTime = $this->getEndDateTime(); - error_log("endTime: " . $endTime->format('Y-m-d H:i:s')); - $endHour = (int) $endTime->format('H'); - $endMinute = (int) $endTime->format('i'); - $endDateTime = (clone $endTime)->setTime($endHour, $endMinute); + error_log("endTime: " . $endDate->format('Y-m-d H:i:s')); + $endHour = (int) $endDate->format('H'); + $endMinute = (int) $endDate->format('i'); + $endDateTime = (clone $endDate)->setTime($endHour, $endMinute); $endTimestamp = $endDateTime->getTimestamp(); $isOrigin = ($this->type && $this->type === 'origin'); - if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endTime < $selectedDate->setTime(0, 0)) { + if (!$isOrigin && $startDate->getTimestamp() > $today->getTimestamp() && $endDate < $startDate->setTime(0, 0)) { $errorList[] = [ 'type' => 'endTimeFuture', 'message' => "Das Enddatum der Öffnungszeit muss nach dem " . $yesterday->format('d.m.Y') . " liegen." @@ -573,12 +572,12 @@ public function validateSlotTime() return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $selectedDate) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = array_merge( - $this->validateStartTime($today, $tomorrow, $selectedDate), - $this->validateEndTime($today, $yesterday, selectedDate: $selectedDate), - $this->validateOriginEndTime($today, $yesterday, $selectedDate), + $this->validateStartTime($today, $tomorrow, $startDate), + $this->validateEndTime($today, $yesterday, selectedDate: $startDate), + $this->validateOriginEndTime($today, $yesterday, $startDate), $this->validateType(), $this->validateSlotTime() ); diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 19c7ff7ae..e16ac1389 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -178,7 +178,7 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable // Pass DateTimeImmutable objects to validateAll() $errorList = array_merge( $errorList, - $availability->validateAll($today, $yesterday, $tomorrow, $startDate) + $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate) ); } return $errorList; From 0cd0ad1473874893f756b39cd4c0c510d1d30708 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:07:28 +0100 Subject: [PATCH 24/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 52fc445ed..26a231d03 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -576,8 +576,8 @@ public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yeste { $errorList = array_merge( $this->validateStartTime($today, $tomorrow, $startDate), - $this->validateEndTime($today, $yesterday, selectedDate: $startDate), - $this->validateOriginEndTime($today, $yesterday, $startDate), + $this->validateEndTime($today, $yesterday, startDate: $startDate), + $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate), $this->validateType(), $this->validateSlotTime() ); From 29b7cff824fa161fc2ed062df40e265b5888502d Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:15:05 +0100 Subject: [PATCH 25/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 44 +++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 26a231d03..b99a6aa18 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,19 +452,17 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate) + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); - $startHour = (int)$startTime->format('H'); - $endHour = (int)$endTime->format('H'); - $startMinute = (int)$startTime->format('i'); - $endMinute = (int)$endTime->format('i'); + $startHour = (int)$startDate->format('H'); + $endHour = (int)$endDate->format('H'); + $startMinute = (int)$startDate->format('i'); + $endMinute = (int)$endDate->format('i'); $isFuture = ($this->type && $this->type === 'future'); - if (!$isFuture && $startDate->getTimestamp() > $today->getTimestamp() && $startTime > $startDate->setTime(0, 0)) { + if (!$isFuture && $startDate->getTimestamp() > $today->getTimestamp() && $startDate > $startDate->setTime(0, 0)) { $errorList[] = [ 'type' => 'startTimeFuture', 'message' => "Das Startdatum der Öffnungszeit muss vor dem " . $tomorrow->format('d.m.Y') . " liegen." @@ -481,20 +479,18 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface return $errorList; } - public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate) + public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); - $startHour = (int)$startTime->format('H'); - $endHour = (int)$endTime->format('H'); - $startMinute = (int)$startTime->format('i'); - $endMinute = (int)$endTime->format('i'); + $startHour = (int)$startDate->format('H'); + $endHour = (int)$endDate->format('H'); + $startMinute = (int)$startDate->format('i'); + $endMinute = (int)$endDate->format('i'); $dayMinutesStart = ($startHour * 60) + $startMinute; $dayMinutesEnd = ($endHour * 60) + $endMinute; - $startTimestamp = $startTime->getTimestamp(); - $endTimestamp = $endTime->getTimestamp(); + $startTimestamp = $startDate->getTimestamp(); + $endTimestamp = $endDate->getTimestamp(); if ($dayMinutesEnd <= $dayMinutesStart) { $errorList[] = [ @@ -552,14 +548,12 @@ public function validateType() return $errorList; } - public function validateSlotTime() + public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = []; - $startTime = $this->getStartDateTime(); - $endTime = $this->getEndDateTime(); $slotTime = $this['slotTimeInMinutes']; - $startTimestamp = $startTime->getTimestamp(); - $endTimestamp = $endTime->getTimestamp(); + $startTimestamp = $startDate->getTimestamp(); + $endTimestamp = $endDate->getTimestamp(); $slotAmount = ($endTimestamp - $startTimestamp) / 60 % $slotTime; if ($slotAmount > 0) { @@ -575,11 +569,11 @@ public function validateSlotTime() public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = array_merge( - $this->validateStartTime($today, $tomorrow, $startDate), - $this->validateEndTime($today, $yesterday, startDate: $startDate), + $this->validateStartTime($today, $tomorrow, $startDate, $endDate), + $this->validateEndTime($today, $yesterday, $startDate, $endDate), $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate), $this->validateType(), - $this->validateSlotTime() + $this->validateSlotTime($startDate, $endDate) ); return $errorList; From 9e11157442768081c6e054233ffda9de2373c8e6 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:20:17 +0100 Subject: [PATCH 26/86] fix(ZMS-3253): try fix some unit tests --- zmsentities/src/Zmsentities/Availability.php | 1 - zmsentities/src/Zmsentities/Collection/AvailabilityList.php | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index b99a6aa18..09d519654 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -510,7 +510,6 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $errorList = []; - error_log("endTime: " . $endDate->format('Y-m-d H:i:s')); $endHour = (int) $endDate->format('H'); $endMinute = (int) $endDate->format('i'); $endDateTime = (clone $endDate)->setTime($endHour, $endMinute); diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index e16ac1389..976a6abf2 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -174,6 +174,9 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable error_log("Today: " . $today->format('Y-m-d H:i:s')); error_log("Yesterday: " . $yesterday->format('Y-m-d H:i:s')); error_log("Tomorrow: " . $tomorrow->format('Y-m-d H:i:s')); + error_log("Today: " . $today->format('Y-m-d H:i:s')); + error_log("startDate: " . $startDate->format('Y-m-d H:i:s')); + error_log("endDate: " . $endDate->format('Y-m-d H:i:s')); // Pass DateTimeImmutable objects to validateAll() $errorList = array_merge( From c2df4446ca7e5b7f27f200b54c718877d489ecdb Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:26:49 +0100 Subject: [PATCH 27/86] fix(ZMS-3253): try fix some unit tests --- .../src/Zmsentities/Collection/AvailabilityList.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 976a6abf2..455c92ab6 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -166,18 +166,17 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $errorList = []; foreach ($this as $availability) { // Create DateTimeImmutable objects for today, yesterday, and tomorrow - $today = new \DateTime(); + $today = new \DateTimeImmutable(); $yesterday = $today->modify('-1 day'); $tomorrow = $today->modify('+1 day'); - $today = $today->modify('+0 day'); - + + // Log the dates for debugging error_log("Today: " . $today->format('Y-m-d H:i:s')); error_log("Yesterday: " . $yesterday->format('Y-m-d H:i:s')); error_log("Tomorrow: " . $tomorrow->format('Y-m-d H:i:s')); - error_log("Today: " . $today->format('Y-m-d H:i:s')); error_log("startDate: " . $startDate->format('Y-m-d H:i:s')); error_log("endDate: " . $endDate->format('Y-m-d H:i:s')); - + // Pass DateTimeImmutable objects to validateAll() $errorList = array_merge( $errorList, @@ -187,6 +186,7 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable return $errorList; } + public function getConflicts($startDate, $endDate) { From 5faea71b407e34ed69ffc8ed072eeebec0c4f101 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:32:30 +0100 Subject: [PATCH 28/86] fix(ZMS-3253): try fix some unit tests --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 1 + 1 file changed, 1 insertion(+) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index b94cb4c58..7bf4de28a 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -71,6 +71,7 @@ public function readResponse( $validation = $mergedCollection->validateInputs($startDate, $endDate); error_log("AvailabilityAdd"); + error_log(json_encode($newAvailability)); error_log("**********"); error_log(json_encode($validation)); if (count($validation) > 0) { From 4cd36185dc3880f24ef168696b494c96e7190975 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:38:59 +0100 Subject: [PATCH 29/86] fix(ZMS-3253): try fix some unit tests --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 7bf4de28a..a7854f2b7 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -42,6 +42,9 @@ public function readResponse( if (!$input || count($input) === 0) { throw new BadRequestException(); } + + error_log("Raw request body: " . $request->getBody()); + $newCollection = new Collection(); DbConnection::getWriteConnection(); @@ -71,7 +74,6 @@ public function readResponse( $validation = $mergedCollection->validateInputs($startDate, $endDate); error_log("AvailabilityAdd"); - error_log(json_encode($newAvailability)); error_log("**********"); error_log(json_encode($validation)); if (count($validation) > 0) { From 4840338584401cc89104c37c5093acabfb8726da Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Thu, 14 Nov 2024 19:48:38 +0100 Subject: [PATCH 30/86] fix(ZMS-3253): try fix some unit tests --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index a7854f2b7..ab541aa75 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -43,7 +43,7 @@ public function readResponse( throw new BadRequestException(); } - error_log("Raw request body: " . $request->getBody()); + error_log("Raw input body: " . json_encode($input)); $newCollection = new Collection(); From c8262a0c343aa70f170d584945814ae9b053af4b Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 09:39:03 +0100 Subject: [PATCH 31/86] fix(ZMS-3253): backend validation work in AvailabilityAdd --- zmsadmin/js/page/availabilityDay/helpers.js | 4 +- zmsadmin/js/page/availabilityDay/index.js | 69 +++++++++++++------ zmsapi/src/Zmsapi/AvailabilityAdd.php | 55 ++++++++++++--- zmsentities/schema/availability.json | 4 ++ zmsentities/src/Zmsentities/Availability.php | 53 ++++++++------ .../Collection/AvailabilityList.php | 9 +-- 6 files changed, 137 insertions(+), 57 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/helpers.js b/zmsadmin/js/page/availabilityDay/helpers.js index 13bdf7edd..062234991 100644 --- a/zmsadmin/js/page/availabilityDay/helpers.js +++ b/zmsadmin/js/page/availabilityDay/helpers.js @@ -187,9 +187,9 @@ export const cleanupAvailabilityForSave = availability => { delete newAvailability.tempId; } - if (newAvailability.kind) { + /*if (newAvailability.kind) { delete newAvailability.kind; - } + }*/ return newAvailability; } diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index c3f34a6dc..2ceeff36a 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -101,35 +101,60 @@ class AvailabilityPage extends Component { } onSaveUpdates() { - const ok = confirm('Möchten Sie wirklich die Änderungen aller Öffnungszeiten speichern?') + const ok = confirm('Möchten Sie wirklich die Änderungen aller Öffnungszeiten speichern?'); if (ok) { showSpinner(); - const sendData = this.state.availabilitylist.filter((availability) => { - return ( - (availability.__modified || - availability.tempId && availability.tempId.includes('__temp__'))) && - ! this.hasErrors(availability) - }).map(availability => { - const sendAvailability = Object.assign({}, availability) - if (availability.tempId) { - delete sendAvailability.tempId - } - return sendAvailability; - }).map(cleanupAvailabilityForSave) - - console.log('Saving updates', sendData) + + // Format the selected date + const selectedDate = formatTimestampDate(this.props.timestamp); + + console.log(this.state); + + // Prepare the data to send + const sendData = this.state.availabilitylist + .filter((availability) => { + return ( + (availability.__modified || + (availability.tempId && availability.tempId.includes('__temp__'))) && + !this.hasErrors(availability) + ); + }) + .map(availability => { + const sendAvailability = Object.assign({}, availability); + if (availability.tempId) { + delete sendAvailability.tempId; + } + console.log(availability.kind); + return { + ...sendAvailability, + kind: availability.kind || 'default', // Include the kind attribute + }; + }) + .map(cleanupAvailabilityForSave); + + // Attach the selectedDate to sendData + const payload = { + availabilityList: sendData, + selectedDate: selectedDate + }; + + + console.log('Saving updates', payload); + + // Make the AJAX request with the updated payload $.ajax(`${this.props.links.includeurl}/availability/`, { method: 'POST', - data: JSON.stringify(sendData) + data: JSON.stringify(payload), + contentType: 'application/json' }).done((success) => { - console.log('save success:', success) + console.log('save success:', success); this.refreshData(); this.setState({ lastSave: new Date().getTime(), }, () => { this.successElement.scrollIntoView(); - }) + }); hideSpinner(); }).fail((err) => { let isException = err.responseText.toLowerCase().includes('exception'); @@ -139,18 +164,18 @@ class AvailabilityPage extends Component { message: err.responseText }); } else if (err.status === 404) { - console.log('404 error, ignored') + console.log('404 error, ignored'); } else { - console.log('save all error', err) + console.log('save all error', err); } this.getValidationList(); hideSpinner(); - }) + }); } else { hideSpinner(); } } - + onRevertUpdates() { this.isCreatingExclusion = false diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index ab541aa75..4292dceb2 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -42,20 +42,24 @@ public function readResponse( if (!$input || count($input) === 0) { throw new BadRequestException(); } - - error_log("Raw input body: " . json_encode($input)); - $newCollection = new Collection(); DbConnection::getWriteConnection(); + + - foreach ($input as $item) { + + foreach ($input['availabilityList'] as $item) { $entity = new Entity($item); $entity->testValid(); + error_log("here"); $newCollection->addEntity($entity); } - - $scopeData = $input[0]['scope']; + + + + + $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); $scopeId = $scope->id; @@ -68,13 +72,46 @@ public function readResponse( foreach ($existingCollection as $existingAvailability) { $mergedCollection->addEntity($existingAvailability); } + foreach ($newCollection as $newAvailability) { + // Log the original values + error_log("Original startDate (timestamp): " . $newAvailability->startDate); + error_log("Original endDate (timestamp): " . $newAvailability->endDate); + error_log("Original startTime: " . $newAvailability->startTime); + error_log("Original endTime: " . $newAvailability->endTime); + error_log("SelectedDate: " . $input['selectedDate']); + + error_log(json_encode($newAvailability)); + + // Convert timestamps to DateTimeImmutable objects + $startDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->startDate); + $endDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->endDate); + $selectedDate = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00'); + + // Log the converted dates + error_log("Converted startDate: " . $startDate->format('Y-m-d')); + error_log("Converted endDate: " . $endDate->format('Y-m-d')); + error_log("Converted selectedDate: " . $selectedDate->format('Y-m-d')); + + // Combine date and time for start and end + $startDateTime = new \DateTimeImmutable("{$startDate->format('Y-m-d')} {$newAvailability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate->format('Y-m-d')} {$newAvailability->endTime}"); + + // Log the combined DateTimeImmutable objects for debugging + error_log("Combined startDateTime: " . $startDateTime->format('Y-m-d H:i:s')); + error_log("Combined endDateTime: " . $endDateTime->format('Y-m-d H:i:s')); + + // Pass the combined DateTimeImmutable objects to validateInputs + $validation = $mergedCollection->validateInputs($startDateTime, $endDateTime, $selectedDate, $newAvailability->kind); + error_log(''. json_encode($validation)); + + + // Add new availability to the merged collection after validation $mergedCollection->addEntity($newAvailability); } + + - $validation = $mergedCollection->validateInputs($startDate, $endDate); - error_log("AvailabilityAdd"); - error_log("**********"); error_log(json_encode($validation)); if (count($validation) > 0) { $validation = json_decode(json_encode($validation), true); diff --git a/zmsentities/schema/availability.json b/zmsentities/schema/availability.json index c6ed256fb..b94c6da04 100644 --- a/zmsentities/schema/availability.json +++ b/zmsentities/schema/availability.json @@ -119,6 +119,10 @@ "type": "string", "description": "format '0:00' or '17:30'" }, + "kind": { + "type": "string", + "description": "format" + }, "type": { "type": "string", "enum": [ diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 09d519654..809704fe5 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,37 +452,44 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate) + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $type) { $errorList = []; - + $startHour = (int)$startDate->format('H'); $endHour = (int)$endDate->format('H'); $startMinute = (int)$startDate->format('i'); $endMinute = (int)$endDate->format('i'); - $isFuture = ($this->type && $this->type === 'future'); - - if (!$isFuture && $startDate->getTimestamp() > $today->getTimestamp() && $startDate > $startDate->setTime(0, 0)) { + $isFuture = ($type && $type === 'future'); + + error_log($isFuture); + + error_log("*" . $selectedDate->getTimestamp() . "*"); + error_log("*" . $today->getTimestamp() . "*"); + // Validate that the start date is not in the future + if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startDate > $selectedDate->setTime(0, 0)) { $errorList[] = [ 'type' => 'startTimeFuture', 'message' => "Das Startdatum der Öffnungszeit muss vor dem " . $tomorrow->format('d.m.Y') . " liegen." ]; } - + + // Validate that start or end time is not exactly midnight if (($startHour == 0 && $startMinute == 0) || ($endHour == 0 && $endMinute == 0)) { $errorList[] = [ 'type' => 'startOfDay', 'message' => 'Die Uhrzeit darf nicht "00:00" sein.' ]; } - + return $errorList; } - public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate) + + public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate) { $errorList = []; - + $startHour = (int)$startDate->format('H'); $endHour = (int)$endDate->format('H'); $startMinute = (int)$startDate->format('i'); @@ -492,6 +499,7 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y $startTimestamp = $startDate->getTimestamp(); $endTimestamp = $endDate->getTimestamp(); + // Check if end time is before start time if ($dayMinutesEnd <= $dayMinutesStart) { $errorList[] = [ 'type' => 'endTime', @@ -503,26 +511,29 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y 'message' => 'Das Startdatum muss vor dem Enddatum sein.' ]; } - + return $errorList; } - public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate) + + public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $type) { $errorList = []; $endHour = (int) $endDate->format('H'); $endMinute = (int) $endDate->format('i'); $endDateTime = (clone $endDate)->setTime($endHour, $endMinute); $endTimestamp = $endDateTime->getTimestamp(); - $isOrigin = ($this->type && $this->type === 'origin'); + $isOrigin = ($type && $type === 'origin'); - if (!$isOrigin && $startDate->getTimestamp() > $today->getTimestamp() && $endDate < $startDate->setTime(0, 0)) { + // Validate that end date is after the selected date + if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endDate < $selectedDate->setTime(0, 0)) { $errorList[] = [ 'type' => 'endTimeFuture', 'message' => "Das Enddatum der Öffnungszeit muss nach dem " . $yesterday->format('d.m.Y') . " liegen." ]; } + // Validate that end time is not in the past if (!$isOrigin && $endTimestamp < $today->getTimestamp()) { $errorList[] = [ 'type' => 'endTimePast', @@ -535,10 +546,11 @@ public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterf return $errorList; } - public function validateType() + + public function validateType(String $type) { $errorList = []; - if (empty($this->type)) { + if (empty($type)) { $errorList[] = [ 'type' => 'type', 'message' => 'Typ erforderlich' @@ -565,19 +577,20 @@ public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterfa return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, $type) { $errorList = array_merge( - $this->validateStartTime($today, $tomorrow, $startDate, $endDate), - $this->validateEndTime($today, $yesterday, $startDate, $endDate), - $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate), - $this->validateType(), + $this->validateStartTime($today, $tomorrow, $startDate, $endDate, $selectedDate, $type), + $this->validateEndTime($today, $yesterday, $startDate, $endDate, $selectedDate), + $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate, $selectedDate, $type), + $this->validateType($type), $this->validateSlotTime($startDate, $endDate) ); return $errorList; } + /** * Get problems on configuration of this availability * diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 455c92ab6..f098594b5 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -161,14 +161,14 @@ public function getSlotListByType($type) return $slotList; } - public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate) + public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, String $type) { $errorList = []; foreach ($this as $availability) { // Create DateTimeImmutable objects for today, yesterday, and tomorrow $today = new \DateTimeImmutable(); - $yesterday = $today->modify('-1 day'); - $tomorrow = $today->modify('+1 day'); + $yesterday = $selectedDate->modify('-1 day'); + $tomorrow = $selectedDate->modify('+1 day'); // Log the dates for debugging error_log("Today: " . $today->format('Y-m-d H:i:s')); @@ -176,11 +176,12 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable error_log("Tomorrow: " . $tomorrow->format('Y-m-d H:i:s')); error_log("startDate: " . $startDate->format('Y-m-d H:i:s')); error_log("endDate: " . $endDate->format('Y-m-d H:i:s')); + error_log(message: "selectedDate: " . $selectedDate->format('Y-m-d H:i:s')); // Pass DateTimeImmutable objects to validateAll() $errorList = array_merge( $errorList, - $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate) + $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $type) ); } return $errorList; From 8281b0a1939fc11678a6ef1388de6459ce92366d Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 15:04:08 +0100 Subject: [PATCH 32/86] fix(ZMS-3253): correct backend validation for timeoverlaps --- zmsadmin/js/page/availabilityDay/index.js | 68 +++++---- .../src/Zmsadmin/AvailabilityConflicts.php | 14 +- zmsapi/src/Zmsapi/AvailabilityAdd.php | 87 ++++++------ zmsapi/src/Zmsapi/AvailabilityUpdate.php | 129 ++++++++++++++---- zmsentities/src/Zmsentities/Availability.php | 4 - .../Collection/AvailabilityList.php | 10 -- 6 files changed, 195 insertions(+), 117 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 2ceeff36a..50cc70adb 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -105,12 +105,8 @@ class AvailabilityPage extends Component { if (ok) { showSpinner(); - // Format the selected date const selectedDate = formatTimestampDate(this.props.timestamp); - - console.log(this.state); - // Prepare the data to send const sendData = this.state.availabilitylist .filter((availability) => { return ( @@ -127,22 +123,18 @@ class AvailabilityPage extends Component { console.log(availability.kind); return { ...sendAvailability, - kind: availability.kind || 'default', // Include the kind attribute + kind: availability.kind || 'default', }; }) .map(cleanupAvailabilityForSave); - // Attach the selectedDate to sendData const payload = { availabilityList: sendData, selectedDate: selectedDate }; - - console.log('Saving updates', payload); - // Make the AJAX request with the updated payload $.ajax(`${this.props.links.includeurl}/availability/`, { method: 'POST', data: JSON.stringify(payload), @@ -189,47 +181,66 @@ class AvailabilityPage extends Component { onUpdateSingleAvailability(availability) { showSpinner(); - const ok = confirm('Soll diese Öffnungszeit wirklich aktualisiert werden?') - const id = availability.id + const ok = confirm('Soll diese Öffnungszeit wirklich aktualisiert werden?'); + const id = availability.id; + if (ok) { - let list = [availability]; - const sendData = list.map(availability => { - const sendAvailability = Object.assign({}, availability) - if (availability.tempId) { - delete sendAvailability.tempId - } - return sendAvailability; - }).map(cleanupAvailabilityForSave) - + // Format the selected date + const selectedDate = formatTimestampDate(this.props.timestamp); + + // Prepare the data to send + const sendAvailability = Object.assign({}, availability); + + // Clean up temporary fields + if (sendAvailability.tempId) { + delete sendAvailability.tempId; + } + + // Include 'kind' and wrap it in 'availabilityList' + const payload = { + availabilityList: [ + { + ...cleanupAvailabilityForSave(sendAvailability), + kind: availability.kind || 'default' + } + ], + selectedDate: selectedDate + }; + + console.log('Updating single availability', payload); + + // Make the AJAX request $.ajax(`${this.props.links.includeurl}/availability/save/${id}/`, { method: 'POST', - data: JSON.stringify(sendData[0]) + data: JSON.stringify(payload), + contentType: 'application/json' }).done((data) => { - console.log('single update success data: ', data) - this.refreshData() + console.log('Single update success:', data); + this.refreshData(); this.setState({ lastSave: new Date().getTime(), }, () => { this.successElement.scrollIntoView(); - }) + }); hideSpinner(); }).fail(err => { - let isException = err.responseText.toLowerCase().includes('exception'); + const isException = err.responseText.toLowerCase().includes('exception'); if (isException) { new ExceptionHandler($('.opened'), { code: err.status, message: err.responseText }); } else { - console.log('update error', err); + console.log('Update error:', err); } - this.getValidationList() + this.getValidationList(); hideSpinner(); - }) + }); } else { hideSpinner(); } } + onDeleteAvailability(availability) { showSpinner(); @@ -500,6 +511,7 @@ class AvailabilityPage extends Component { selectedAvailability: this.state.selectedAvailability })) }; + console.log("here"); const url = `${this.props.links.includeurl}/availability/conflicts/`; fetch(url, requestOptions) .then(res => res.json()) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index cf41ff895..b8700f04d 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -48,7 +48,17 @@ protected static function getAvailabilityData($input) $selectedAvailability->getEndDateTime() : $selectedDateTime; $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); - $conflictList = $availabilityList->getConflicts($startDateTime, $endDateTime); + + + error_log("" .$selectedAvailability->getEndDateTime()); + $selectedAvailability->getEndDateTime(); + + + $startDate = new \DateTimeImmutable('now'); + $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); + + + $conflictList = $availabilityList->getConflicts($startDate, $endDate); foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? @@ -59,6 +69,8 @@ protected static function getAvailabilityData($input) } } + error_log(json_encode($conflictedList)); + return [ 'conflictList' => $conflictList->toConflictListByDay(), 'conflictIdList' => (count($conflictedList)) ? $conflictedList : [] diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 4292dceb2..45147e683 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -38,35 +38,28 @@ public function readResponse( array $args ): ResponseInterface { (new Helper\User($request))->checkRights(); + $resolveReferences = Validator::param('resolveReferences')->isNumber()->setDefault(2)->getValue(); $input = Validator::input()->isJson()->assertValid()->getValue(); if (!$input || count($input) === 0) { throw new BadRequestException(); } - $newCollection = new Collection(); DbConnection::getWriteConnection(); - - - + $newCollection = new Collection(); foreach ($input['availabilityList'] as $item) { $entity = new Entity($item); $entity->testValid(); - error_log("here"); $newCollection->addEntity($entity); } - - - - $scopeData = $input['availabilityList'][0]['scope']; + $scopeData = $input['availabilityList']['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); - $scopeId = $scope->id; $startDate = new \DateTimeImmutable('now'); $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); $availabilityRepo = new AvailabilityRepository(); - $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1, $startDate, $endDate); + $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); $mergedCollection = new Collection(); foreach ($existingCollection as $existingAvailability) { @@ -74,60 +67,33 @@ public function readResponse( } foreach ($newCollection as $newAvailability) { - // Log the original values - error_log("Original startDate (timestamp): " . $newAvailability->startDate); - error_log("Original endDate (timestamp): " . $newAvailability->endDate); - error_log("Original startTime: " . $newAvailability->startTime); - error_log("Original endTime: " . $newAvailability->endTime); - error_log("SelectedDate: " . $input['selectedDate']); - - error_log(json_encode($newAvailability)); - // Convert timestamps to DateTimeImmutable objects $startDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->startDate); $endDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->endDate); $selectedDate = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00'); - - // Log the converted dates - error_log("Converted startDate: " . $startDate->format('Y-m-d')); - error_log("Converted endDate: " . $endDate->format('Y-m-d')); - error_log("Converted selectedDate: " . $selectedDate->format('Y-m-d')); - - // Combine date and time for start and end $startDateTime = new \DateTimeImmutable("{$startDate->format('Y-m-d')} {$newAvailability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate->format('Y-m-d')} {$newAvailability->endTime}"); - // Log the combined DateTimeImmutable objects for debugging - error_log("Combined startDateTime: " . $startDateTime->format('Y-m-d H:i:s')); - error_log("Combined endDateTime: " . $endDateTime->format('Y-m-d H:i:s')); - - // Pass the combined DateTimeImmutable objects to validateInputs $validation = $mergedCollection->validateInputs($startDateTime, $endDateTime, $selectedDate, $newAvailability->kind); - error_log(''. json_encode($validation)); - - // Add new availability to the merged collection after validation $mergedCollection->addEntity($newAvailability); } - - - error_log(json_encode($validation)); if (count($validation) > 0) { $validation = json_decode(json_encode($validation), true); throw new AvailabilityUpdateFailed(); } - $conflicts = $mergedCollection->getConflicts($startDate, $endDate); - + [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection); + $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - $conflictsArray = json_decode(json_encode($conflicts), true); + error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } $updatedCollection = new Collection(); foreach ($newCollection as $entity) { - $updatedEntity = $this->writeEntityUpdate($entity); + $updatedEntity = $this->writeEntityUpdate($entity, $resolveReferences); AvailabilitySlotsUpdate::writeCalculatedSlots($updatedEntity, true); $updatedCollection->addEntity($updatedEntity); } @@ -139,9 +105,40 @@ public function readResponse( return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } - - protected function writeEntityUpdate($entity): Entity + /** + * Get the earliest startDateTime and latest endDateTime from a Collection + * + * @param Collection $collection + * @return array + */ + private function getDateTimeRangeFromCollection(Collection $collection): array + { + $earliestStartDateTime = null; + $latestEndDateTime = null; + + foreach ($collection as $availability) { + // Convert Unix timestamp to a date string before concatenating with the time + $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); + $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + + $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + + if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { + $earliestStartDateTime = $startDateTime; + } + if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { + $latestEndDateTime = $endDateTime; + } + } + + return [$earliestStartDateTime, $latestEndDateTime]; + } + + + + protected function writeEntityUpdate($entity, $resolveReferences): Entity { $repository = new AvailabilityRepository(); $updatedEntity = null; @@ -149,7 +146,7 @@ protected function writeEntityUpdate($entity): Entity $oldEntity = $repository->readEntity($entity->id); if ($oldEntity && $oldEntity->hasId()) { $this->writeSpontaneousEntity($oldEntity); - $updatedEntity = $repository->updateEntity($entity->id, $entity, 2); + $updatedEntity = $repository->updateEntity($entity->id, $entity, $resolveReferences); } } else { $updatedEntity = $repository->writeEntity($entity, 2); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index b409d7a89..8ced83f80 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -1,7 +1,7 @@ checkRights(); $resolveReferences = Validator::param('resolveReferences')->isNumber()->setDefault(2)->getValue(); $input = Validator::input()->isJson()->assertValid()->getValue(); - $entity = new Entity($input); - $entity->testValid(); - $availabilityRepo = new AvailabilityRepository(); - $availability = $availabilityRepo->readEntity($args['id'], $resolveReferences); - if (! $availability->hasId()) { - throw new NotFoundException(); + if (!$input || count($input) === 0) { + throw new BadRequestException(); + } + + DbConnection::getWriteConnection(); + + $newCollection = new Collection(); + foreach ($input['availabilityList'] as $item) { + $entity = new Entity($item); + $entity->testValid(); + $newCollection->addEntity($entity); } - $scopeData = $entity->scope; + $scopeData = $input['availabilityList']['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); - $startDate = new \DateTimeImmutable('now'); - $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); - $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1, $startDate, $endDate); + $availabilityRepo = new AvailabilityRepository(); + $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); $mergedCollection = new Collection(); foreach ($existingCollection as $existingAvailability) { - if ($existingAvailability->id !== $entity->id) { - $mergedCollection->addEntity($existingAvailability); - } + $mergedCollection->addEntity($existingAvailability); + } + + foreach ($newCollection as $newAvailability) { + $startDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->startDate)->format('Y-m-d'); + $endDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->endDate)->format('Y-m-d'); + + $selectedDate = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00'); + + $startDateTime = new \DateTimeImmutable("{$startDate} {$newAvailability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate} {$newAvailability->endTime}"); + + $validation = $mergedCollection->validateInputs( + $startDateTime, + $endDateTime, + $selectedDate, + $newAvailability->kind ?? 'default' + ); + + $mergedCollection->addEntity($newAvailability); } - $mergedCollection->addEntity($entity); - $validation = $mergedCollection->validateInputs($startDate, $endDate); - error_log("AvailabilityUpdate"); - error_log(message: "-----------"); - error_log(json_encode($validation)); if (count($validation) > 0) { $validation = json_decode(json_encode($validation), true); throw new AvailabilityUpdateFailed(); - } - - $conflicts = $mergedCollection->getConflicts($startDate, $endDate); - + } + + [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection); + $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - $conflictsArray = json_decode(json_encode($conflicts), true); + error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } - DbConnection::getWriteConnection(); - $this->writeSpontaneousEntity($availability); - $updatedEntity = $availabilityRepo->updateEntity($args['id'], $entity, $resolveReferences); - AvailabilitySlotsUpdate::writeCalculatedSlots($updatedEntity, true); + $updatedCollection = new Collection(); + foreach ($newCollection as $entity) { + $updatedEntity = $this->writeEntityUpdate($entity, $resolveReferences); + AvailabilitySlotsUpdate::writeCalculatedSlots($updatedEntity, true); + $updatedCollection->addEntity($updatedEntity); + } $message = Response\Message::create($request); - $message->data = $updatedEntity; + $message->data = $updatedCollection->getArrayCopy(); $response = Render::withLastModified($response, time(), '0'); return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } + /** + * Get the earliest startDateTime and latest endDateTime from a Collection + * + * @param Collection $collection + * @return array + */ + private function getDateTimeRangeFromCollection(Collection $collection): array + { + $earliestStartDateTime = null; + $latestEndDateTime = null; + + foreach ($collection as $availability) { + // Convert Unix timestamp to a date string before concatenating with the time + $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); + $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + + $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + + if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { + $earliestStartDateTime = $startDateTime; + } + if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { + $latestEndDateTime = $endDateTime; + } + } + + return [$earliestStartDateTime, $latestEndDateTime]; + } + + protected function writeEntityUpdate($entity, $resolveReferences): Entity + { + $repository = new AvailabilityRepository(); + $updatedEntity = null; + + if ($entity->id) { + $oldEntity = $repository->readEntity($entity->id); + if ($oldEntity && $oldEntity->hasId()) { + $this->writeSpontaneousEntity($oldEntity); + $updatedEntity = $repository->updateEntity($entity->id, $entity, $resolveReferences); + } + } else { + $updatedEntity = $repository->writeEntity($entity, 2); + } + + if (!$updatedEntity) { + throw new AvailabilityUpdateFailed(); + } + + return $updatedEntity; + } + protected function writeSpontaneousEntity(Entity $entity): void { $doubleTypesEntity = (new AvailabilityRepository())->readEntityDoubleTypes($entity->id); diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 809704fe5..4b7bca86d 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -462,10 +462,6 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $endMinute = (int)$endDate->format('i'); $isFuture = ($type && $type === 'future'); - error_log($isFuture); - - error_log("*" . $selectedDate->getTimestamp() . "*"); - error_log("*" . $today->getTimestamp() . "*"); // Validate that the start date is not in the future if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startDate > $selectedDate->setTime(0, 0)) { $errorList[] = [ diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index f098594b5..9b2330369 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -165,20 +165,10 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable { $errorList = []; foreach ($this as $availability) { - // Create DateTimeImmutable objects for today, yesterday, and tomorrow $today = new \DateTimeImmutable(); $yesterday = $selectedDate->modify('-1 day'); $tomorrow = $selectedDate->modify('+1 day'); - - // Log the dates for debugging - error_log("Today: " . $today->format('Y-m-d H:i:s')); - error_log("Yesterday: " . $yesterday->format('Y-m-d H:i:s')); - error_log("Tomorrow: " . $tomorrow->format('Y-m-d H:i:s')); - error_log("startDate: " . $startDate->format('Y-m-d H:i:s')); - error_log("endDate: " . $endDate->format('Y-m-d H:i:s')); - error_log(message: "selectedDate: " . $selectedDate->format('Y-m-d H:i:s')); - // Pass DateTimeImmutable objects to validateAll() $errorList = array_merge( $errorList, $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $type) From 390aba7351d7b420c53fdc5a7f5bb421a78ed356 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 16:40:19 +0100 Subject: [PATCH 33/86] fix(ZMS-3253): fix a validation --- zmsadmin/js/page/availabilityDay/form/validate.js | 4 ++++ zmsapi/src/Zmsapi/AvailabilityAdd.php | 6 ++++-- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 2 +- zmsentities/src/Zmsentities/Availability.php | 11 +++++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index bf3ad3353..1a9aed77c 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -42,6 +42,10 @@ function validateStartTime(today, tomorrow, selectedDate, data) { const isFuture = (data.kind && 'future' == data.kind); //const isOrigin = (data.kind && 'origin' == data.kind); + console.log("startTime: " + startTime); + console.log("selectedDate: " + selectedDate.startOf('day'), 'day'); + + if (! isFuture && selectedDate.unix() > today.unix() && startTime.isAfter(selectedDate.startOf('day'), 'day')) { errorList.push({ type: 'startTimeFuture', diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 45147e683..caf0bb27f 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -53,7 +53,9 @@ public function readResponse( $newCollection->addEntity($entity); } - $scopeData = $input['availabilityList']['scope']; + //error_log('*'. json_encode($input)); + + $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); $startDate = new \DateTimeImmutable('now'); @@ -80,7 +82,7 @@ public function readResponse( } if (count($validation) > 0) { - $validation = json_decode(json_encode($validation), true); + error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 8ced83f80..45fbf843e 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -84,7 +84,7 @@ public function readResponse( } if (count($validation) > 0) { - $validation = json_decode(json_encode($validation), true); + error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 4b7bca86d..1b4b4a21b 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -456,21 +456,24 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface { $errorList = []; - $startHour = (int)$startDate->format('H'); + $startTime = $startDate->setTime(0, 0); + $startHour = ($startDate->format('H')); $endHour = (int)$endDate->format('H'); $startMinute = (int)$startDate->format('i'); $endMinute = (int)$endDate->format('i'); $isFuture = ($type && $type === 'future'); - // Validate that the start date is not in the future - if (!$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && $startDate > $selectedDate->setTime(0, 0)) { + if ( + !$isFuture && + $selectedDate->getTimestamp() > $today->getTimestamp() && + $startTime->getTimestamp() > $selectedDate->setTime(0, 0)->getTimestamp() + ) { $errorList[] = [ 'type' => 'startTimeFuture', 'message' => "Das Startdatum der Öffnungszeit muss vor dem " . $tomorrow->format('d.m.Y') . " liegen." ]; } - // Validate that start or end time is not exactly midnight if (($startHour == 0 && $startMinute == 0) || ($endHour == 0 && $endMinute == 0)) { $errorList[] = [ 'type' => 'startOfDay', From 78013ea7e4bd87d3a4a34a02136526227cd6d06c Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:18:27 +0100 Subject: [PATCH 34/86] fix(ZMS-3253): try fixing a test --- .../js/page/availabilityDay/form/validate.js | 4 - .../src/Zmsadmin/AvailabilityConflicts.php | 94 ++++++++++++------- zmsapi/src/Zmsapi/AvailabilityAdd.php | 22 ++++- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 12 ++- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 31 +++--- zmsentities/src/Zmsentities/Availability.php | 20 ++-- .../Collection/AvailabilityList.php | 4 +- 7 files changed, 117 insertions(+), 70 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index 1a9aed77c..9fab7d1c8 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -41,11 +41,7 @@ function validateStartTime(today, tomorrow, selectedDate, data) { //const startDateTime = startTime.clone().set({ h: startHour, m: startMinute }); const isFuture = (data.kind && 'future' == data.kind); //const isOrigin = (data.kind && 'origin' == data.kind); - - console.log("startTime: " + startTime); - console.log("selectedDate: " + selectedDate.startOf('day'), 'day'); - if (! isFuture && selectedDate.unix() > today.unix() && startTime.isAfter(selectedDate.startOf('day'), 'day')) { errorList.push({ type: 'startTimeFuture', diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index b8700f04d..63b4ca670 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -7,12 +7,11 @@ namespace BO\Zmsadmin; use BO\Zmsentities\Availability; - use BO\Zmsentities\Collection\AvailabilityList; +use DateTimeImmutable; /** * Check if new Availability is in conflict with existing availability - * */ class AvailabilityConflicts extends BaseController { @@ -27,6 +26,8 @@ public function readResponse( ) { $validator = $request->getAttribute('validator'); $input = $validator->getInput()->isJson()->assertValid()->getValue(); + error_log('$input :' . json_encode($input)); + $data = static::getAvailabilityData($input); return \BO\Slim\Render::withJson( $response, @@ -40,31 +41,41 @@ protected static function getAvailabilityData($input) $availabilityList = (new AvailabilityList())->addData($input['availabilityList']); $conflictedList = []; - $selectedDateTime = (new \DateTimeImmutable($input['selectedDate']))->modify(\App::$now->format('H:i:s')); + // Extract selected date and selected availability + $selectedDate = new DateTimeImmutable($input['selectedDate']); $selectedAvailability = new Availability($input['selectedAvailability']); - $startDateTime = ($selectedAvailability->getStartDateTime() >= \App::$now) ? - $selectedAvailability->getStartDateTime() : $selectedDateTime; - $endDateTime = ($input['selectedAvailability']) ? - $selectedAvailability->getEndDateTime() : $selectedDateTime; - - $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); + $selectedDateTime = $selectedDate->setTime(0, 0); + // Determine start and end times based on selectedAvailability + $startDateTime = $selectedAvailability->getStartDateTime() < $selectedDateTime ? $selectedDateTime : $selectedAvailability->getStartDateTime(); + $endDateTime = $selectedAvailability->getEndDateTime(); - error_log("" .$selectedAvailability->getEndDateTime()); - $selectedAvailability->getEndDateTime(); + // Prepare a merged collection with existing and new availabilities + $scopeData = $input['availabilityList'][0]['scope']; + $scope = new \BO\Zmsentities\Scope($scopeData); + $availabilityRepo = new \BO\Zmsdb\Availability(); + $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); + $mergedCollection = new AvailabilityList(); + foreach ($existingCollection as $existingAvailability) { + $mergedCollection->addEntity($existingAvailability); + } - $startDate = new \DateTimeImmutable('now'); - $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); + // Add the selected availability to the merged collection + $mergedCollection->addEntity($selectedAvailability); + // Get the earliest and latest dates for the conflict range + [$earliestStartDateTime, $latestEndDateTime] = static::getDateTimeRangeFromCollection($mergedCollection, $selectedDateTime); - $conflictList = $availabilityList->getConflicts($startDate, $endDate); + // Check for conflicts in the merged collection within the computed range + $conflictList = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); + // Extract conflicting IDs foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? $conflict->getFirstAppointment()->getAvailability()->getId() : $conflict->getFirstAppointment()->getAvailability()->tempId; - if (! in_array($availabilityId, $conflictedList)) { + if (!in_array($availabilityId, $conflictedList)) { $conflictedList[] = $availabilityId; } } @@ -77,26 +88,43 @@ protected static function getAvailabilityData($input) ]; } - /* - protected static function getAvailabilityList($scope, $dateTime) + /** + * Get the earliest startDateTime and latest endDateTime from a Collection + * If the start date of any availability is before the selected date, + * use the selected date instead. + * + * @param AvailabilityList $collection + * @param \DateTimeImmutable $selectedDate + * @return array + */ + private static function getDateTimeRangeFromCollection(AvailabilityList $collection, DateTimeImmutable $selectedDate): array { - try { - $availabilityList = \App::$http - ->readGetResult( - '/scope/' . $scope->getId() . '/availability/', - [ - 'resolveReferences' => 0, - 'startDate' => $dateTime->format('Y-m-d') //for skipping old availabilities - ] - ) - ->getCollection(); - } catch (\BO\Zmsclient\Exception $exception) { - if ($exception->template != 'BO\Zmsapi\Exception\Availability\AvailabilityNotFound') { - throw $exception; + $earliestStartDateTime = null; + $latestEndDateTime = null; + + foreach ($collection as $availability) { + // Convert Unix timestamp to a date string before concatenating with the time + $startDate = (new DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); + $endDate = (new DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + + // Combine date and time for start and end + $startDateTime = new DateTimeImmutable("{$startDate} {$availability->startTime}"); + $endDateTime = new DateTimeImmutable("{$endDate} {$availability->endTime}"); + + // If startDate is before the selectedDate, use the selectedDate as the start + if ($startDateTime < $selectedDate) { + $startDateTime = $selectedDate->setTime(0, 0); + } + + // Determine the earliest start and latest end times + if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { + $earliestStartDateTime = $startDateTime; + } + if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { + $latestEndDateTime = $endDateTime; } - $availabilityList = new \BO\Zmsentities\Collection\AvailabilityList(); } - return $availabilityList->withScope($scope); + + return [$earliestStartDateTime, $latestEndDateTime]; } - */ } diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index caf0bb27f..5eed37bf1 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -53,8 +53,6 @@ public function readResponse( $newCollection->addEntity($entity); } - //error_log('*'. json_encode($input)); - $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); @@ -76,7 +74,12 @@ public function readResponse( $startDateTime = new \DateTimeImmutable("{$startDate->format('Y-m-d')} {$newAvailability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate->format('Y-m-d')} {$newAvailability->endTime}"); - $validation = $mergedCollection->validateInputs($startDateTime, $endDateTime, $selectedDate, $newAvailability->kind); + $validation = $mergedCollection->validateInputs( + $startDateTime, + $endDateTime, + $selectedDate, + $newAvailability->kind ?? 'default' + ); $mergedCollection->addEntity($newAvailability); } @@ -110,11 +113,14 @@ public function readResponse( /** * Get the earliest startDateTime and latest endDateTime from a Collection + * If the start date of any availability is before the selected date, + * use the selected date instead. * * @param Collection $collection + * @param \DateTimeImmutable $selectedDate * @return array */ - private function getDateTimeRangeFromCollection(Collection $collection): array + private function getDateTimeRangeFromCollection(Collection $collection, \DateTimeImmutable $selectedDate): array { $earliestStartDateTime = null; $latestEndDateTime = null; @@ -124,9 +130,16 @@ private function getDateTimeRangeFromCollection(Collection $collection): array $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + // Combine date and time for start and end $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + // If startDate is before the selectedDate, use the selectedDate as the start + if ($startDateTime < $selectedDate) { + $startDateTime = $selectedDate->setTime(0, 0); + } + + // Determine the earliest start and latest end times if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { $earliestStartDateTime = $startDateTime; } @@ -139,7 +152,6 @@ private function getDateTimeRangeFromCollection(Collection $collection): array } - protected function writeEntityUpdate($entity, $resolveReferences): Entity { $repository = new AvailabilityRepository(); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 45fbf843e..e06798d5f 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -111,11 +111,14 @@ public function readResponse( /** * Get the earliest startDateTime and latest endDateTime from a Collection + * If the start date of any availability is before the selected date, + * use the selected date instead. * * @param Collection $collection + * @param \DateTimeImmutable $selectedDate * @return array */ - private function getDateTimeRangeFromCollection(Collection $collection): array + private function getDateTimeRangeFromCollection(Collection $collection, \DateTimeImmutable $selectedDate): array { $earliestStartDateTime = null; $latestEndDateTime = null; @@ -125,9 +128,16 @@ private function getDateTimeRangeFromCollection(Collection $collection): array $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + // Combine date and time for start and end $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + // If startDate is before the selectedDate, use the selectedDate as the start + if ($startDateTime < $selectedDate) { + $startDateTime = $selectedDate->setTime(0, 0); + } + + // Determine the earliest start and latest end times if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { $earliestStartDateTime = $startDateTime; } diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index dcdfdf663..72bd129ca 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -10,26 +10,27 @@ public function testRendering() { $this->setWorkstation(); $response = $this->render([], [ - '__body' => '[ - { - "id": 21202, - "description": "Test Öffnungszeit update", - "scope": { - "id": 312 - } - }, - { - "description": "Test Öffnungszeit ohne id", - "scope": { - "id": 141 - } - } - ]' + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Test Öffnungszeit update", + "scope" => ["id" => 312] + ], + [ + "description" => "Test Öffnungszeit ohne id", + "scope" => ["id" => 141] + ] + ], + 'selectedDate' => '2024-11-15' + ]) ], []); + error_log(json_encode((string)$response->getBody())); $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } + public function testEmpty() { diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 1b4b4a21b..89d653943 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -452,7 +452,7 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $type) + public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { $errorList = []; @@ -461,7 +461,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $endHour = (int)$endDate->format('H'); $startMinute = (int)$startDate->format('i'); $endMinute = (int)$endDate->format('i'); - $isFuture = ($type && $type === 'future'); + $isFuture = ($kind && $kind === 'future'); if ( !$isFuture && @@ -515,14 +515,14 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y } - public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $type) + public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { $errorList = []; $endHour = (int) $endDate->format('H'); $endMinute = (int) $endDate->format('i'); $endDateTime = (clone $endDate)->setTime($endHour, $endMinute); $endTimestamp = $endDateTime->getTimestamp(); - $isOrigin = ($type && $type === 'origin'); + $isOrigin = ($kind && $kind === 'origin'); // Validate that end date is after the selected date if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endDate < $selectedDate->setTime(0, 0)) { @@ -546,10 +546,10 @@ public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterf } - public function validateType(String $type) + public function validateType(String $kind) { $errorList = []; - if (empty($type)) { + if (empty($kind)) { $errorList[] = [ 'type' => 'type', 'message' => 'Typ erforderlich' @@ -576,13 +576,13 @@ public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterfa return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, $type) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { $errorList = array_merge( - $this->validateStartTime($today, $tomorrow, $startDate, $endDate, $selectedDate, $type), + $this->validateStartTime($today, $tomorrow, $startDate, $endDate, $selectedDate, $kind), $this->validateEndTime($today, $yesterday, $startDate, $endDate, $selectedDate), - $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate, $selectedDate, $type), - $this->validateType($type), + $this->validateOriginEndTime($today, $yesterday, $startDate, $endDate, $selectedDate, $kind), + $this->validateType($kind), $this->validateSlotTime($startDate, $endDate) ); diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 9b2330369..6082697ae 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -161,7 +161,7 @@ public function getSlotListByType($type) return $slotList; } - public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, String $type) + public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, String $kind) { $errorList = []; foreach ($this as $availability) { @@ -171,7 +171,7 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $errorList = array_merge( $errorList, - $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $type) + $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $kind) ); } return $errorList; From 8a076210e7a27cfc599b081a98585344da5ed6ec Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:21:11 +0100 Subject: [PATCH 35/86] fix(ZMS-3253): try fixing a test --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 72bd129ca..c429644df 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -54,16 +54,19 @@ public function testUpdateFailed() $this->setWorkstation(); $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed'); $this->expectExceptionCode(400); + + // Wrap the data inside "availabilityList" $this->render([], [ - '__body' => '[ - { - "id": 99999, - "description": "Test Öffnungszeit update failed", - "scope": { - "id": 312 - } - } - ]', + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 99999, + "description" => "Test Öffnungszeit update failed", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]), 'migrationfix' => 0 ], []); } From 7892fe0f568098e124685bd3bb6ff06fe3c53356 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:23:19 +0100 Subject: [PATCH 36/86] fix(ZMS-3253): try fixing a test --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 1 - .../tests/Zmsapi/AvailabilityUpdateTest.php | 30 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index c429644df..42e03d098 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -55,7 +55,6 @@ public function testUpdateFailed() $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed'); $this->expectExceptionCode(400); - // Wrap the data inside "availabilityList" $this->render([], [ '__body' => json_encode([ 'availabilityList' => [ diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 097c4a519..524beab54 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -13,29 +13,31 @@ class AvailabilityUpdateTest extends Base public function testRendering() { $input = (new Entity)->createExample(); - - // Dynamically adjust the endDate to be in the future + $currentTimestamp = time(); - $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // Set startDate to 2 days in the future - $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // Set endDate to 5 days in the future - - - - // Write the entity using the modified input + $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future + $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future + $entity = (new Query())->writeEntity($input); - error_log(json_encode($entity)); // Log for debugging + error_log(json_encode($entity)); $this->setWorkstation(); - - // Prepare the response and test rendering + + // Wrap the data inside "availabilityList" $response = $this->render([ "id" => $entity->getId() ], [ '__body' => json_encode([ - "id" => $entity->getId(), - "description" => "", - "scope" => ["id" => 312] + 'availabilityList' => [ + [ + "id" => $entity->getId(), + "description" => "", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') ]) ], []); + $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } From 952258545a5415ee404df359ad45f53168ec804f Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:25:39 +0100 Subject: [PATCH 37/86] fix(ZMS-3253): try fixing a test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 524beab54..0e15aff32 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -53,16 +53,28 @@ public function testEmpty() public function testNotFound() { $this->setWorkstation(); + + // Set the expected exception for "not found" scenarios $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityNotFound'); $this->expectExceptionCode(404); - $this->render(["id"=> 1], [ - '__body' => '{ - "id": 1, - "description": "Test Öffnungszeit not found", - "scope": { - "id": 312 - } - }' - ], []); + + // Prepare the request with the required payload structure + $this->render( + ["id" => 1], // Pass the ID that does not exist + [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 1, // Non-existent ID + "description" => "Test Öffnungszeit not found", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], + [] + ); } + } From d65ccb8861e37852ba565d7a4d98b1276a05a4ce Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:37:14 +0100 Subject: [PATCH 38/86] fix(ZMS-3253): try fixing availability not found test --- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 12 ++++++++++-- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 7 ++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index e06798d5f..dd1a62753 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -45,18 +45,26 @@ public function readResponse( } DbConnection::getWriteConnection(); - + + $availabilityRepo = new AvailabilityRepository(); $newCollection = new Collection(); + foreach ($input['availabilityList'] as $item) { $entity = new Entity($item); $entity->testValid(); + if (isset($entity->id)) { + $existingEntity = $availabilityRepo->readEntity($entity->id, $resolveReferences); + if (!$existingEntity || !$existingEntity->hasId()) { + throw new NotFoundException("Availability with ID {$entity->id} not found."); + } + } + $newCollection->addEntity($entity); } $scopeData = $input['availabilityList']['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); - $availabilityRepo = new AvailabilityRepository(); $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); $mergedCollection = new Collection(); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 0e15aff32..6d11d4c53 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -22,7 +22,6 @@ public function testRendering() error_log(json_encode($entity)); $this->setWorkstation(); - // Wrap the data inside "availabilityList" $response = $this->render([ "id" => $entity->getId() ], [ @@ -54,18 +53,16 @@ public function testNotFound() { $this->setWorkstation(); - // Set the expected exception for "not found" scenarios $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityNotFound'); $this->expectExceptionCode(404); - // Prepare the request with the required payload structure $this->render( - ["id" => 1], // Pass the ID that does not exist + ["id" => 1], [ '__body' => json_encode([ 'availabilityList' => [ [ - "id" => 1, // Non-existent ID + "id" => 1, "description" => "Test Öffnungszeit not found", "scope" => ["id" => 312] ] From 3fa84a103b932d818c6ad00a3989f969b0f46b1f Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:44:48 +0100 Subject: [PATCH 39/86] fix(ZMS-3253): try fixing availability mockdata for testRendering --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 25 +++++++++++++++---- .../tests/Zmsapi/AvailabilityUpdateTest.php | 11 +++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 42e03d098..7290575d0 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -6,32 +6,47 @@ class AvailabilityAddTest extends Base { protected $classname = "AvailabilityAdd"; + public function testRendering() { $this->setWorkstation(); + $response = $this->render([], [ '__body' => json_encode([ 'availabilityList' => [ [ "id" => 21202, "description" => "Test Öffnungszeit update", - "scope" => ["id" => 312] + "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future + "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => [ + "id" => 312 + ] ], [ "description" => "Test Öffnungszeit ohne id", - "scope" => ["id" => 141] + "startDate" => time() + (1 * 24 * 60 * 60), // 1 day in the future + "endDate" => time() + (4 * 24 * 60 * 60), // 4 days in the future + "startTime" => "10:00:00", + "endTime" => "16:30:00", + "kind" => "default", + "scope" => [ + "id" => 141 + ] ] ], - 'selectedDate' => '2024-11-15' + 'selectedDate' => date('Y-m-d') ]) ], []); - + error_log(json_encode((string)$response->getBody())); $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } - public function testEmpty() { $this->setWorkstation(); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 6d11d4c53..aec7e0a91 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -17,6 +17,10 @@ public function testRendering() $currentTimestamp = time(); $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future + $input['startTime'] = "09:00:00"; + $input['endTime'] = "17:00:00"; + $input['scope'] = ["id" => 312]; + $input['kind'] = "default"; $entity = (new Query())->writeEntity($input); error_log(json_encode($entity)); @@ -29,7 +33,12 @@ public function testRendering() 'availabilityList' => [ [ "id" => $entity->getId(), - "description" => "", + "description" => "Updated availability", + "startDate" => $input['startDate'], + "endDate" => $input['endDate'], + "startTime" => $input['startTime'], + "endTime" => $input['endTime'], + "kind" => $input['kind'], "scope" => ["id" => 312] ] ], From 317d127a2860e32a0bf90cc8716efdd235e051a8 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:55:28 +0100 Subject: [PATCH 40/86] fix(ZMS-3253): try fixing availability mockdata for testRendering --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 2 +- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 5eed37bf1..c9bb78073 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -89,7 +89,7 @@ public function readResponse( throw new AvailabilityUpdateFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection); + [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { error_log(json_encode($conflicts)); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index dd1a62753..2e56d12cb 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -96,7 +96,7 @@ public function readResponse( throw new AvailabilityUpdateFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection); + [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { error_log(json_encode($conflicts)); From c02e4e334d25ba5e1789211f0893dfc955bfbbf7 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 17:59:04 +0100 Subject: [PATCH 41/86] fix(ZMS-3253): try fixing availability mockdata for testRendering --- .../src/Zmsadmin/AvailabilityConflicts.php | 91 +++++++------------ 1 file changed, 31 insertions(+), 60 deletions(-) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index 63b4ca670..df4e930f3 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -7,11 +7,12 @@ namespace BO\Zmsadmin; use BO\Zmsentities\Availability; + use BO\Zmsentities\Collection\AvailabilityList; -use DateTimeImmutable; /** * Check if new Availability is in conflict with existing availability + * */ class AvailabilityConflicts extends BaseController { @@ -27,7 +28,6 @@ public function readResponse( $validator = $request->getAttribute('validator'); $input = $validator->getInput()->isJson()->assertValid()->getValue(); error_log('$input :' . json_encode($input)); - $data = static::getAvailabilityData($input); return \BO\Slim\Render::withJson( $response, @@ -41,41 +41,29 @@ protected static function getAvailabilityData($input) $availabilityList = (new AvailabilityList())->addData($input['availabilityList']); $conflictedList = []; - // Extract selected date and selected availability - $selectedDate = new DateTimeImmutable($input['selectedDate']); + $selectedDateTime = (new \DateTimeImmutable($input['selectedDate']))->modify(\App::$now->format('H:i:s')); $selectedAvailability = new Availability($input['selectedAvailability']); - $selectedDateTime = $selectedDate->setTime(0, 0); + $startDateTime = ($selectedAvailability->getStartDateTime() >= \App::$now) ? + $selectedAvailability->getStartDateTime() : $selectedDateTime; + $endDateTime = ($input['selectedAvailability']) ? + $selectedAvailability->getEndDateTime() : $selectedDateTime; - // Determine start and end times based on selectedAvailability - $startDateTime = $selectedAvailability->getStartDateTime() < $selectedDateTime ? $selectedDateTime : $selectedAvailability->getStartDateTime(); - $endDateTime = $selectedAvailability->getEndDateTime(); + $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); - // Prepare a merged collection with existing and new availabilities - $scopeData = $input['availabilityList'][0]['scope']; - $scope = new \BO\Zmsentities\Scope($scopeData); - $availabilityRepo = new \BO\Zmsdb\Availability(); - $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); + $selectedAvailability->getEndDateTime(); - $mergedCollection = new AvailabilityList(); - foreach ($existingCollection as $existingAvailability) { - $mergedCollection->addEntity($existingAvailability); - } - // Add the selected availability to the merged collection - $mergedCollection->addEntity($selectedAvailability); + $startDate = new \DateTimeImmutable('now'); + $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); - // Get the earliest and latest dates for the conflict range - [$earliestStartDateTime, $latestEndDateTime] = static::getDateTimeRangeFromCollection($mergedCollection, $selectedDateTime); - // Check for conflicts in the merged collection within the computed range - $conflictList = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); + $conflictList = $availabilityList->getConflicts($startDate, $endDate); - // Extract conflicting IDs foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? $conflict->getFirstAppointment()->getAvailability()->getId() : $conflict->getFirstAppointment()->getAvailability()->tempId; - if (!in_array($availabilityId, $conflictedList)) { + if (! in_array($availabilityId, $conflictedList)) { $conflictedList[] = $availabilityId; } } @@ -88,43 +76,26 @@ protected static function getAvailabilityData($input) ]; } - /** - * Get the earliest startDateTime and latest endDateTime from a Collection - * If the start date of any availability is before the selected date, - * use the selected date instead. - * - * @param AvailabilityList $collection - * @param \DateTimeImmutable $selectedDate - * @return array - */ - private static function getDateTimeRangeFromCollection(AvailabilityList $collection, DateTimeImmutable $selectedDate): array + /* + protected static function getAvailabilityList($scope, $dateTime) { - $earliestStartDateTime = null; - $latestEndDateTime = null; - - foreach ($collection as $availability) { - // Convert Unix timestamp to a date string before concatenating with the time - $startDate = (new DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); - $endDate = (new DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); - - // Combine date and time for start and end - $startDateTime = new DateTimeImmutable("{$startDate} {$availability->startTime}"); - $endDateTime = new DateTimeImmutable("{$endDate} {$availability->endTime}"); - - // If startDate is before the selectedDate, use the selectedDate as the start - if ($startDateTime < $selectedDate) { - $startDateTime = $selectedDate->setTime(0, 0); - } - - // Determine the earliest start and latest end times - if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { - $earliestStartDateTime = $startDateTime; - } - if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { - $latestEndDateTime = $endDateTime; + try { + $availabilityList = \App::$http + ->readGetResult( + '/scope/' . $scope->getId() . '/availability/', + [ + 'resolveReferences' => 0, + 'startDate' => $dateTime->format('Y-m-d') //for skipping old availabilities + ] + ) + ->getCollection(); + } catch (\BO\Zmsclient\Exception $exception) { + if ($exception->template != 'BO\Zmsapi\Exception\Availability\AvailabilityNotFound') { + throw $exception; } + $availabilityList = new \BO\Zmsentities\Collection\AvailabilityList(); } - - return [$earliestStartDateTime, $latestEndDateTime]; + return $availabilityList->withScope($scope); } + */ } From c75e3c42448b0273d3adaa02033ce29b7f9a5731 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 18:03:22 +0100 Subject: [PATCH 42/86] fix(ZMS-3253): try fixing availability mockdata for testRendering --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index aec7e0a91..a56dc9099 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -32,14 +32,16 @@ public function testRendering() '__body' => json_encode([ 'availabilityList' => [ [ - "id" => $entity->getId(), - "description" => "Updated availability", - "startDate" => $input['startDate'], - "endDate" => $input['endDate'], - "startTime" => $input['startTime'], - "endTime" => $input['endTime'], - "kind" => $input['kind'], - "scope" => ["id" => 312] + "id" => 21202, + "description" => "Test Öffnungszeit update", + "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future + "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => [ + "id" => 312 + ] ] ], 'selectedDate' => date('Y-m-d') From 2b395468140b56e121d185b17a8ea5fdc97ed48d Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 18:05:53 +0100 Subject: [PATCH 43/86] fix(ZMS-3253): try fixing availability mockdata for testRendering --- zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php index 73f6d93eb..4dab759b5 100644 --- a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php +++ b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php @@ -1872,6 +1872,9 @@ public function testRendering() } }' ], [], 'POST'); + error_log("***"); + error_log((string)$response->getBody()); + error_log("***"); $this->assertStringContainsString('Zwei \u00d6ffnungszeiten sind gleich', (string)$response->getBody()); $this->assertStringContainsString('2016-04-04', (string)$response->getBody()); $this->assertStringContainsString('2016-04-11', (string)$response->getBody()); From acb62ac5c06b1fa481e9e8026873991b11c4b9ff Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 18:07:18 +0100 Subject: [PATCH 44/86] fix(ZMS-3253): try fix missing scope testRendering --- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 2e56d12cb..a5e3a7124 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -62,7 +62,7 @@ public function readResponse( $newCollection->addEntity($entity); } - $scopeData = $input['availabilityList']['scope']; + $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); $existingCollection = $availabilityRepo->readAvailabilityListByScope($scope, 1); From a16b2e429ea0ded36ab42c6f4a7933ac7edb77fd Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 18:20:22 +0100 Subject: [PATCH 45/86] fix(ZMS-3253): fix zmsadmin availabilities conflict test --- zmsadmin/src/Zmsadmin/AvailabilityConflicts.php | 13 +------------ .../tests/Zmsadmin/AvailabilityConflictsTest.php | 3 --- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index df4e930f3..cf41ff895 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -27,7 +27,6 @@ public function readResponse( ) { $validator = $request->getAttribute('validator'); $input = $validator->getInput()->isJson()->assertValid()->getValue(); - error_log('$input :' . json_encode($input)); $data = static::getAvailabilityData($input); return \BO\Slim\Render::withJson( $response, @@ -49,15 +48,7 @@ protected static function getAvailabilityData($input) $selectedAvailability->getEndDateTime() : $selectedDateTime; $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); - - $selectedAvailability->getEndDateTime(); - - - $startDate = new \DateTimeImmutable('now'); - $endDate = (new \DateTimeImmutable('now'))->modify('+1 month'); - - - $conflictList = $availabilityList->getConflicts($startDate, $endDate); + $conflictList = $availabilityList->getConflicts($startDateTime, $endDateTime); foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? @@ -68,8 +59,6 @@ protected static function getAvailabilityData($input) } } - error_log(json_encode($conflictedList)); - return [ 'conflictList' => $conflictList->toConflictListByDay(), 'conflictIdList' => (count($conflictedList)) ? $conflictedList : [] diff --git a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php index 4dab759b5..73f6d93eb 100644 --- a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php +++ b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php @@ -1872,9 +1872,6 @@ public function testRendering() } }' ], [], 'POST'); - error_log("***"); - error_log((string)$response->getBody()); - error_log("***"); $this->assertStringContainsString('Zwei \u00d6ffnungszeiten sind gleich', (string)$response->getBody()); $this->assertStringContainsString('2016-04-04', (string)$response->getBody()); $this->assertStringContainsString('2016-04-11', (string)$response->getBody()); From 1bd40cbc455d2366b755cc5a64fd32915d8f3761 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 19:07:23 +0100 Subject: [PATCH 46/86] fix(ZMS-3253): show availability opening hour conflicts in the future not just for selectedDate --- .../src/Zmsadmin/AvailabilityConflicts.php | 80 +++++++++++++++---- .../Zmsadmin/AvailabilityConflictsTest.php | 15 ++++ 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index cf41ff895..952d3be80 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -7,12 +7,10 @@ namespace BO\Zmsadmin; use BO\Zmsentities\Availability; - use BO\Zmsentities\Collection\AvailabilityList; /** * Check if new Availability is in conflict with existing availability - * */ class AvailabilityConflicts extends BaseController { @@ -28,10 +26,7 @@ public function readResponse( $validator = $request->getAttribute('validator'); $input = $validator->getInput()->isJson()->assertValid()->getValue(); $data = static::getAvailabilityData($input); - return \BO\Slim\Render::withJson( - $response, - $data - ); + return \BO\Slim\Render::withJson($response, $data); } protected static function getAvailabilityData($input) @@ -41,20 +36,25 @@ protected static function getAvailabilityData($input) $conflictedList = []; $selectedDateTime = (new \DateTimeImmutable($input['selectedDate']))->modify(\App::$now->format('H:i:s')); - $selectedAvailability = new Availability($input['selectedAvailability']); - $startDateTime = ($selectedAvailability->getStartDateTime() >= \App::$now) ? - $selectedAvailability->getStartDateTime() : $selectedDateTime; - $endDateTime = ($input['selectedAvailability']) ? - $selectedAvailability->getEndDateTime() : $selectedDateTime; + + $scopeData = $input['availabilityList'][0]['scope']; + $scope = new \BO\Zmsentities\Scope($scopeData); + $futureAvailabilityList = self::getAvailabilityList($scope, $selectedDateTime); + + foreach ($futureAvailabilityList as $futureAvailability) { + $availabilityList->addEntity($futureAvailability); + } + + [$earliestStartDateTime, $latestEndDateTime] = self::getDateTimeRangeFromList($availabilityList, $selectedDateTime); $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); - $conflictList = $availabilityList->getConflicts($startDateTime, $endDateTime); + $conflictList = $availabilityList->getConflicts($earliestStartDateTime, $latestEndDateTime); foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? $conflict->getFirstAppointment()->getAvailability()->getId() : $conflict->getFirstAppointment()->getAvailability()->tempId; - if (! in_array($availabilityId, $conflictedList)) { + if (!in_array($availabilityId, $conflictedList)) { $conflictedList[] = $availabilityId; } } @@ -65,7 +65,13 @@ protected static function getAvailabilityData($input) ]; } - /* + /** + * Fetch availabilities for a given scope and date. + * + * @param \BO\Zmsentities\Scope $scope + * @param \DateTimeImmutable $dateTime + * @return AvailabilityList + */ protected static function getAvailabilityList($scope, $dateTime) { try { @@ -74,7 +80,7 @@ protected static function getAvailabilityList($scope, $dateTime) '/scope/' . $scope->getId() . '/availability/', [ 'resolveReferences' => 0, - 'startDate' => $dateTime->format('Y-m-d') //for skipping old availabilities + 'startDate' => $dateTime->format('Y-m-d') // Only fetch availabilities from this date onward ] ) ->getCollection(); @@ -86,5 +92,47 @@ protected static function getAvailabilityList($scope, $dateTime) } return $availabilityList->withScope($scope); } - */ + + + /** + * Get the earliest startDateTime and latest endDateTime from an AvailabilityList + * If the start date of any availability is before the selected date, use the selected date instead. + * + * @param AvailabilityList $availabilityList + * @param \DateTimeImmutable $selectedDate + * @return array + */ + protected static function getDateTimeRangeFromList(AvailabilityList $availabilityList, \DateTimeImmutable $selectedDate): array + { + $earliestStartDateTime = null; + $latestEndDateTime = null; + + foreach ($availabilityList as $availability) { + // Convert Unix timestamp to date strings + $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); + $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + + // Combine date and time for start and end + $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + + // Adjust the startDateTime if it's before the selected date + if ($startDateTime < $selectedDate) { + $startDateTime = $selectedDate->setTime(0, 0); + } + + // Determine the earliest start time + if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { + $earliestStartDateTime = $startDateTime; + } + + // Determine the latest end time + if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { + $latestEndDateTime = $endDateTime; + } + } + + return [$earliestStartDateTime, $latestEndDateTime]; + } + } diff --git a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php index 73f6d93eb..8b3f2ce1c 100644 --- a/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php +++ b/zmsadmin/tests/Zmsadmin/AvailabilityConflictsTest.php @@ -10,6 +10,21 @@ class AvailabilityConflictsTest extends Base public function testRendering() { + + $this->setApiCalls( + [ + [ + 'function' => 'readGetResult', + 'url' => '/scope/141/availability/', + 'parameters' => [ + 'resolveReferences' => 0, + 'startDate' => '2016-04-04' + ], + 'response' => $this->readFixture("GET_availability_68985.json") + ] + ] + ); + $response = $this->render([], [ '__body' => '{ "availabilityList": [ From 402531941d0a24cd7eed4cfd444e652bdb8de62c Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 19:10:08 +0100 Subject: [PATCH 47/86] fix(ZMS-3253): remove error_logs --- zmsapi/src/Zmsapi/AvailabilityAdd.php | 4 ++-- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index c9bb78073..6aa600c4b 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -85,14 +85,14 @@ public function readResponse( } if (count($validation) > 0) { - error_log(json_encode($validation)); + //error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - error_log(json_encode($conflicts)); + //error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index a5e3a7124..c4d78cbcf 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -92,14 +92,14 @@ public function readResponse( } if (count($validation) > 0) { - error_log(json_encode($validation)); + //error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - error_log(json_encode($conflicts)); + //error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } From 95dcef0c46e0cd2576dd387377ca30c409e89ffa Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 19:35:41 +0100 Subject: [PATCH 48/86] fix(ZMS-3253): refactor function logic getDateTimeRangeFromList to one place --- zmsadmin/js/page/availabilityDay/index.js | 1 - .../src/Zmsadmin/AvailabilityConflicts.php | 41 +---------------- zmsapi/src/Zmsapi/AvailabilityAdd.php | 44 +------------------ zmsapi/src/Zmsapi/AvailabilityUpdate.php | 42 +----------------- .../Collection/AvailabilityList.php | 41 ++++++++++++++++- 5 files changed, 43 insertions(+), 126 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 50cc70adb..9b23a22f8 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -511,7 +511,6 @@ class AvailabilityPage extends Component { selectedAvailability: this.state.selectedAvailability })) }; - console.log("here"); const url = `${this.props.links.includeurl}/availability/conflicts/`; fetch(url, requestOptions) .then(res => res.json()) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index 952d3be80..92edd5287 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -45,7 +45,7 @@ protected static function getAvailabilityData($input) $availabilityList->addEntity($futureAvailability); } - [$earliestStartDateTime, $latestEndDateTime] = self::getDateTimeRangeFromList($availabilityList, $selectedDateTime); + [$earliestStartDateTime, $latestEndDateTime] = $availabilityList->getDateTimeRangeFromList( $selectedDateTime); $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); $conflictList = $availabilityList->getConflicts($earliestStartDateTime, $latestEndDateTime); @@ -94,45 +94,6 @@ protected static function getAvailabilityList($scope, $dateTime) } - /** - * Get the earliest startDateTime and latest endDateTime from an AvailabilityList - * If the start date of any availability is before the selected date, use the selected date instead. - * - * @param AvailabilityList $availabilityList - * @param \DateTimeImmutable $selectedDate - * @return array - */ - protected static function getDateTimeRangeFromList(AvailabilityList $availabilityList, \DateTimeImmutable $selectedDate): array - { - $earliestStartDateTime = null; - $latestEndDateTime = null; - - foreach ($availabilityList as $availability) { - // Convert Unix timestamp to date strings - $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); - $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); - - // Combine date and time for start and end - $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); - $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); - - // Adjust the startDateTime if it's before the selected date - if ($startDateTime < $selectedDate) { - $startDateTime = $selectedDate->setTime(0, 0); - } - // Determine the earliest start time - if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { - $earliestStartDateTime = $startDateTime; - } - - // Determine the latest end time - if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { - $latestEndDateTime = $endDateTime; - } - } - - return [$earliestStartDateTime, $latestEndDateTime]; - } } diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 6aa600c4b..24a832b96 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -89,7 +89,7 @@ public function readResponse( throw new AvailabilityUpdateFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); + [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { //error_log(json_encode($conflicts)); @@ -109,48 +109,6 @@ public function readResponse( $response = Render::withLastModified($response, time(), '0'); return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } - - - /** - * Get the earliest startDateTime and latest endDateTime from a Collection - * If the start date of any availability is before the selected date, - * use the selected date instead. - * - * @param Collection $collection - * @param \DateTimeImmutable $selectedDate - * @return array - */ - private function getDateTimeRangeFromCollection(Collection $collection, \DateTimeImmutable $selectedDate): array - { - $earliestStartDateTime = null; - $latestEndDateTime = null; - - foreach ($collection as $availability) { - // Convert Unix timestamp to a date string before concatenating with the time - $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); - $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); - - // Combine date and time for start and end - $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); - $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); - - // If startDate is before the selectedDate, use the selectedDate as the start - if ($startDateTime < $selectedDate) { - $startDateTime = $selectedDate->setTime(0, 0); - } - - // Determine the earliest start and latest end times - if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { - $earliestStartDateTime = $startDateTime; - } - if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { - $latestEndDateTime = $endDateTime; - } - } - - return [$earliestStartDateTime, $latestEndDateTime]; - } - protected function writeEntityUpdate($entity, $resolveReferences): Entity { diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index c4d78cbcf..20842db21 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -96,7 +96,7 @@ public function readResponse( throw new AvailabilityUpdateFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $this->getDateTimeRangeFromCollection($mergedCollection, \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); + [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { //error_log(json_encode($conflicts)); @@ -117,46 +117,6 @@ public function readResponse( return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode()); } - /** - * Get the earliest startDateTime and latest endDateTime from a Collection - * If the start date of any availability is before the selected date, - * use the selected date instead. - * - * @param Collection $collection - * @param \DateTimeImmutable $selectedDate - * @return array - */ - private function getDateTimeRangeFromCollection(Collection $collection, \DateTimeImmutable $selectedDate): array - { - $earliestStartDateTime = null; - $latestEndDateTime = null; - - foreach ($collection as $availability) { - // Convert Unix timestamp to a date string before concatenating with the time - $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); - $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); - - // Combine date and time for start and end - $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); - $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); - - // If startDate is before the selectedDate, use the selectedDate as the start - if ($startDateTime < $selectedDate) { - $startDateTime = $selectedDate->setTime(0, 0); - } - - // Determine the earliest start and latest end times - if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { - $earliestStartDateTime = $startDateTime; - } - if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { - $latestEndDateTime = $endDateTime; - } - } - - return [$earliestStartDateTime, $latestEndDateTime]; - } - protected function writeEntityUpdate($entity, $resolveReferences): Entity { $repository = new AvailabilityRepository(); diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index 6082697ae..e096c27ea 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -177,7 +177,46 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable return $errorList; } - + /** + * Get the earliest startDateTime and latest endDateTime from an AvailabilityList + * If the start date of any availability is before the selected date, use the selected date instead. + * + * @param AvailabilityList $availabilityList + * @param \DateTimeImmutable $selectedDate + * @return array + */ + public function getDateTimeRangeFromList(\DateTimeImmutable $selectedDate): array + { + $earliestStartDateTime = null; + $latestEndDateTime = null; + + foreach ($this as $availability) { + // Convert Unix timestamp to date strings + $startDate = (new \DateTimeImmutable())->setTimestamp($availability->startDate)->format('Y-m-d'); + $endDate = (new \DateTimeImmutable())->setTimestamp($availability->endDate)->format('Y-m-d'); + + // Combine date and time for start and end + $startDateTime = new \DateTimeImmutable("{$startDate} {$availability->startTime}"); + $endDateTime = new \DateTimeImmutable("{$endDate} {$availability->endTime}"); + + // Adjust the startDateTime if it's before the selected date + if ($startDateTime < $selectedDate) { + $startDateTime = $selectedDate->setTime(0, 0); + } + + // Determine the earliest start time + if (is_null($earliestStartDateTime) || $startDateTime < $earliestStartDateTime) { + $earliestStartDateTime = $startDateTime; + } + + // Determine the latest end time + if (is_null($latestEndDateTime) || $endDateTime > $latestEndDateTime) { + $latestEndDateTime = $endDateTime; + } + } + + return [$earliestStartDateTime, $latestEndDateTime]; + } public function getConflicts($startDate, $endDate) { From 3eb89128288de69555e9e16234e84645a8a1c3d2 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 20:09:38 +0100 Subject: [PATCH 49/86] fix(ZMS-3253): renable twig cache --- zmsadmin/config.example.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsadmin/config.example.php b/zmsadmin/config.example.php index 4786162d4..d68f3628e 100644 --- a/zmsadmin/config.example.php +++ b/zmsadmin/config.example.php @@ -10,7 +10,7 @@ class App extends \BO\Zmsadmin\Application const IDENTIFIER = ZMS_IDENTIFIER; const DEBUG = false; // Per default uses dir ./cache - //const TWIG_CACHE = false; + const TWIG_CACHE = '/cache/'; /** * HTTP url for api From 46c0af982d14c5f5e5c735c3a13c2bbbbc5c6dd2 Mon Sep 17 00:00:00 2001 From: Tom Fink Date: Fri, 15 Nov 2024 20:10:18 +0100 Subject: [PATCH 50/86] fix(ZMS-3253): renable twig cache --- zmsadmin/config.example.php | 2 +- zmsadmin/src/Zmsadmin/Application.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsadmin/config.example.php b/zmsadmin/config.example.php index d68f3628e..4786162d4 100644 --- a/zmsadmin/config.example.php +++ b/zmsadmin/config.example.php @@ -10,7 +10,7 @@ class App extends \BO\Zmsadmin\Application const IDENTIFIER = ZMS_IDENTIFIER; const DEBUG = false; // Per default uses dir ./cache - const TWIG_CACHE = '/cache/'; + //const TWIG_CACHE = false; /** * HTTP url for api diff --git a/zmsadmin/src/Zmsadmin/Application.php b/zmsadmin/src/Zmsadmin/Application.php index 6be2c4ee1..65c6a83e1 100644 --- a/zmsadmin/src/Zmsadmin/Application.php +++ b/zmsadmin/src/Zmsadmin/Application.php @@ -27,7 +27,7 @@ class Application extends \BO\Slim\Application const DEBUG = false; - const TWIG_CACHE = false; + const TWIG_CACHE = '/cache/'; const TEMPLATE_PATH = ZMS_ADMIN_TEMPLATE_FOLDER; From fdd0c72659800223848aea3d90d7bacc4c08d152 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 12:45:36 +0100 Subject: [PATCH 51/86] fix(ZMS-3253): fix unit test --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index a56dc9099..d9de2c027 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -32,7 +32,7 @@ public function testRendering() '__body' => json_encode([ 'availabilityList' => [ [ - "id" => 21202, + "id" => $entity->getId(), "description" => "Test Öffnungszeit update", "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future From f319de351ab40e0edcbeb78ba1954440430e0875 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:29:56 +0100 Subject: [PATCH 52/86] fix(ZMS-3253): fix unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index d9de2c027..10f2e5d92 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -21,6 +21,13 @@ public function testRendering() $input['endTime'] = "17:00:00"; $input['scope'] = ["id" => 312]; $input['kind'] = "default"; + $input["dayoff"] = [ + [ + "id" => 302, + "date" => time() + (10 * 24 * 60 * 60), // 10 days in the future + "name" => "Test Dayoff" + ] + ]; $entity = (new Query())->writeEntity($input); error_log(json_encode($entity)); @@ -32,7 +39,7 @@ public function testRendering() '__body' => json_encode([ 'availabilityList' => [ [ - "id" => $entity->getId(), + "id" => 21202, "description" => "Test Öffnungszeit update", "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future @@ -41,17 +48,18 @@ public function testRendering() "kind" => "default", "scope" => [ "id" => 312 - ] + ], + "dayoff" => [] ] ], 'selectedDate' => date('Y-m-d') ]) ], []); - $this->assertStringContainsString('availability.json', (string)$response->getBody()); + $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } - + public function testEmpty() { @@ -63,10 +71,10 @@ public function testEmpty() public function testNotFound() { $this->setWorkstation(); - + $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityNotFound'); $this->expectExceptionCode(404); - + $this->render( ["id" => 1], [ @@ -84,5 +92,5 @@ public function testNotFound() [] ); } - + } From b8fd6b6653704cb6a66135e7f4c7df5fc662e388 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:32:56 +0100 Subject: [PATCH 53/86] fix(ZMS-3253): fix unit test --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 10f2e5d92..966cb3773 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -21,13 +21,6 @@ public function testRendering() $input['endTime'] = "17:00:00"; $input['scope'] = ["id" => 312]; $input['kind'] = "default"; - $input["dayoff"] = [ - [ - "id" => 302, - "date" => time() + (10 * 24 * 60 * 60), // 10 days in the future - "name" => "Test Dayoff" - ] - ]; $entity = (new Query())->writeEntity($input); error_log(json_encode($entity)); From a2691c12d0f82fa92e4a43677bddad5743701597 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:37:06 +0100 Subject: [PATCH 54/86] fix(ZMS-3253): fix unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 966cb3773..20ded677b 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -12,44 +12,39 @@ class AvailabilityUpdateTest extends Base public function testRendering() { - $input = (new Entity)->createExample(); - $currentTimestamp = time(); - $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future - $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future - $input['startTime'] = "09:00:00"; - $input['endTime'] = "17:00:00"; - $input['scope'] = ["id" => 312]; - $input['kind'] = "default"; + $input = (new Entity)->createExample(); + $input = [ + "description" => "Test Öffnungszeit update", + "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future + "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312], + ]; + // Write the entity to the database $entity = (new Query())->writeEntity($input); - error_log(json_encode($entity)); $this->setWorkstation(); $response = $this->render([ "id" => $entity->getId() ], [ '__body' => json_encode([ - 'availabilityList' => [ + 'availabilityList' => [$input], + 'selectedDate' => date('Y-m-d'), + 'dayoff' => [ [ - "id" => 21202, - "description" => "Test Öffnungszeit update", - "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future - "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future - "startTime" => "09:00:00", - "endTime" => "17:00:00", - "kind" => "default", - "scope" => [ - "id" => 312 - ], - "dayoff" => [] + "id" => 302, + "date" => time() + (10 * 24 * 60 * 60), + "name" => "Test Dayoff" ] - ], - 'selectedDate' => date('Y-m-d') + ] ]) ], []); - $this->assertStringContainsString('availability.json', (string) $response->getBody()); + $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } From fc26e1334e02b4a7486a11194711f873c4eb8a8f Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:37:54 +0100 Subject: [PATCH 55/86] fix(ZMS-3253): fix unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 20ded677b..125c55999 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -12,27 +12,38 @@ class AvailabilityUpdateTest extends Base public function testRendering() { - $input = (new Entity)->createExample(); - $input = [ - "description" => "Test Öffnungszeit update", - "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future - "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future - "startTime" => "09:00:00", - "endTime" => "17:00:00", - "kind" => "default", - "scope" => ["id" => 312], - ]; - // Write the entity to the database + $currentTimestamp = time(); + $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future + $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future + $input['startTime'] = "09:00:00"; + $input['endTime'] = "17:00:00"; + $input['scope'] = ["id" => 312]; + $input['kind'] = "default"; + $entity = (new Query())->writeEntity($input); + error_log(json_encode($entity)); $this->setWorkstation(); $response = $this->render([ "id" => $entity->getId() ], [ '__body' => json_encode([ - 'availabilityList' => [$input], + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Test Öffnungszeit update", + "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future + "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => [ + "id" => 312 + ] + ] + ], 'selectedDate' => date('Y-m-d'), 'dayoff' => [ [ @@ -44,7 +55,7 @@ public function testRendering() ]) ], []); - $this->assertStringContainsString('availability.json', (string)$response->getBody()); + $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } From bffc9face3b053a4b491f741bcb31feba47d7ee7 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:44:47 +0100 Subject: [PATCH 56/86] fix(ZMS-3253): fix unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 125c55999..b8b58ed35 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -2,9 +2,9 @@ namespace BO\Zmsapi\Tests; -use \BO\Zmsentities\Availability as Entity; - -use \BO\Zmsdb\Availability as Query; +use BO\Zmsentities\Availability as Entity; +use BO\Zmsdb\Availability as Query; +use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; class AvailabilityUpdateTest extends Base { @@ -12,8 +12,10 @@ class AvailabilityUpdateTest extends Base public function testRendering() { + // Create an example entity $input = (new Entity)->createExample(); + // Set test data $currentTimestamp = time(); $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future @@ -21,45 +23,65 @@ public function testRendering() $input['endTime'] = "17:00:00"; $input['scope'] = ["id" => 312]; $input['kind'] = "default"; + $input['dayoff'] = [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ]; + // Write the entity to the database $entity = (new Query())->writeEntity($input); - error_log(json_encode($entity)); $this->setWorkstation(); + // Prepare and send the request with the updated availability and dayoff data $response = $this->render([ "id" => $entity->getId() ], [ '__body' => json_encode([ 'availabilityList' => [ [ - "id" => 21202, + "id" => $entity->getId(), "description" => "Test Öffnungszeit update", - "startDate" => time() + (2 * 24 * 60 * 60), // 2 days in the future - "endDate" => time() + (5 * 24 * 60 * 60), // 5 days in the future + "startDate" => $currentTimestamp + (2 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (5 * 24 * 60 * 60), "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", - "scope" => [ - "id" => 312 + "scope" => ["id" => 312], + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] ] ], - 'selectedDate' => date('Y-m-d'), - 'dayoff' => [ - [ - "id" => 302, - "date" => time() + (10 * 24 * 60 * 60), - "name" => "Test Dayoff" - ] - ] + 'selectedDate' => date('Y-m-d') ]) ], []); + // Assertions to check if the response is correct $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } - public function testEmpty() { $this->setWorkstation(); @@ -70,7 +92,6 @@ public function testEmpty() public function testNotFound() { $this->setWorkstation(); - $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityNotFound'); $this->expectExceptionCode(404); @@ -91,5 +112,4 @@ public function testNotFound() [] ); } - } From 5784eb4792fdf13420a8e614cc51def93307127a Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:50:28 +0100 Subject: [PATCH 57/86] fix(ZMS-3253): try fix unit test --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index b8b58ed35..30a450b52 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -21,9 +21,7 @@ public function testRendering() $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future $input['startTime'] = "09:00:00"; $input['endTime'] = "17:00:00"; - $input['scope'] = ["id" => 312]; - $input['kind'] = "default"; - $input['dayoff'] = [ + $input['scope'] = ["id" => 312, "dayoff"=> [ [ "id" => 35, "date" => $currentTimestamp + (7 * 24 * 60 * 60), // 7 days in the future @@ -36,7 +34,9 @@ public function testRendering() "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] - ]; + ]]; + $input['kind'] = "default"; + // Write the entity to the database $entity = (new Query())->writeEntity($input); @@ -56,19 +56,21 @@ public function testRendering() "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", - "scope" => ["id" => 312], - "dayoff" => [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + "scope" => [ + "id" => 312, + "dayoff" => [ // Moved dayoff inside the scope object + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] ] ] @@ -76,6 +78,7 @@ public function testRendering() 'selectedDate' => date('Y-m-d') ]) ], []); + // Assertions to check if the response is correct $this->assertStringContainsString('availability.json', (string) $response->getBody()); From 51e25ca8c6d0e124a0f34d212201efc9b3244e00 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 13:54:32 +0100 Subject: [PATCH 58/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 69 ++++++++++++++++++- .../tests/Zmsapi/AvailabilityUpdateTest.php | 8 --- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 7290575d0..b5f2a032a 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -2,6 +2,7 @@ namespace BO\Zmsapi\Tests; +use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; class AvailabilityAddTest extends Base { protected $classname = "AvailabilityAdd"; @@ -42,11 +43,75 @@ public function testRendering() ]) ], []); - error_log(json_encode((string)$response->getBody())); $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } - + public function testOverlappingAvailability() + { + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Overlapping Entry 1", + "startDate" => time() + (2 * 24 * 60 * 60), + "endDate" => time() + (3 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312] + ], + [ + "id" => 21203, + "description" => "Overlapping Entry 2", + "startDate" => time() + (2 * 24 * 60 * 60), + "endDate" => time() + (3 * 24 * 60 * 60), + "startTime" => "10:00:00", + "endTime" => "18:00:00", + "kind" => "default", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + public function testDuplicateAvailability() + { + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Duplicate Entry 1", + "startDate" => time() + (3 * 24 * 60 * 60), + "endDate" => time() + (4 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312] + ], + [ + "id" => 21203, + "description" => "Duplicate Entry 2", + "startDate" => time() + (3 * 24 * 60 * 60), + "endDate" => time() + (4 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } public function testEmpty() { $this->setWorkstation(); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 30a450b52..53b88e683 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -12,10 +12,7 @@ class AvailabilityUpdateTest extends Base public function testRendering() { - // Create an example entity $input = (new Entity)->createExample(); - - // Set test data $currentTimestamp = time(); $input['startDate'] = $currentTimestamp + (2 * 24 * 60 * 60); // 2 days in the future $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future @@ -37,12 +34,9 @@ public function testRendering() ]]; $input['kind'] = "default"; - - // Write the entity to the database $entity = (new Query())->writeEntity($input); $this->setWorkstation(); - // Prepare and send the request with the updated availability and dayoff data $response = $this->render([ "id" => $entity->getId() ], [ @@ -79,8 +73,6 @@ public function testRendering() ]) ], []); - - // Assertions to check if the response is correct $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } From 4f2a125bd12a8701ed39b47758c325731414ad04 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:03:07 +0100 Subject: [PATCH 59/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 1 - .../tests/Zmsapi/AvailabilityUpdateTest.php | 126 +++++++++++++++++- 2 files changed, 125 insertions(+), 2 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index b5f2a032a..93dc0178f 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -7,7 +7,6 @@ class AvailabilityAddTest extends Base { protected $classname = "AvailabilityAdd"; - public function testRendering() { $this->setWorkstation(); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 53b88e683..6cb1c9fbf 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -52,7 +52,7 @@ public function testRendering() "kind" => "default", "scope" => [ "id" => 312, - "dayoff" => [ // Moved dayoff inside the scope object + "dayoff" => [ [ "id" => 35, "date" => $currentTimestamp + (7 * 24 * 60 * 60), @@ -76,6 +76,130 @@ public function testRendering() $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } + public function testDuplicateAvailability() + { + $this->setWorkstation(); + $currentTimestamp = time(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Duplicate Entry 1", + "startDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (4 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312], + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ], + [ + "id" => 21202, // Duplicate ID + "description" => "Duplicate Entry 2", + "startDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (4 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312], + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + public function testOverlappingAvailability() + { + $this->setWorkstation(); + $currentTimestamp = time(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => 21202, + "description" => "Overlapping Entry 1", + "startDate" => $currentTimestamp + (2 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "default", + "scope" => ["id" => 312], + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ], + [ + "id" => 21203, + "description" => "Overlapping Entry 2", + "startDate" => $currentTimestamp + (2 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "startTime" => "10:00:00", + "endTime" => "18:00:00", + "kind" => "default", + "scope" => ["id" => 312], + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } public function testEmpty() { From e8cae55a24737abb02b1a43e1e922e7a36bf6930 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:04:53 +0100 Subject: [PATCH 60/86] fix(ZMS-3253): remove space --- zmsadmin/js/page/availabilityDay/form/validate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index 9fab7d1c8..bf3ad3353 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -41,7 +41,7 @@ function validateStartTime(today, tomorrow, selectedDate, data) { //const startDateTime = startTime.clone().set({ h: startHour, m: startMinute }); const isFuture = (data.kind && 'future' == data.kind); //const isOrigin = (data.kind && 'origin' == data.kind); - + if (! isFuture && selectedDate.unix() > today.unix() && startTime.isAfter(selectedDate.startOf('day'), 'day')) { errorList.push({ type: 'startTimeFuture', From e0f4fa6e6055cfdc58c3574a8d58041739e035c3 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:07:02 +0100 Subject: [PATCH 61/86] fix(ZMS-3253): remove space --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 89 ++++++++++--------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 6cb1c9fbf..bf246e46a 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -18,20 +18,23 @@ public function testRendering() $input['endDate'] = $currentTimestamp + (5 * 24 * 60 * 60); // 5 days in the future $input['startTime'] = "09:00:00"; $input['endTime'] = "17:00:00"; - $input['scope'] = ["id" => 312, "dayoff"=> [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), // 7 days in the future - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), // 14 days in the future - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + $input['scope'] = [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] - ]]; + ]; $input['kind'] = "default"; $entity = (new Query())->writeEntity($input); @@ -72,7 +75,7 @@ public function testRendering() 'selectedDate' => date('Y-m-d') ]) ], []); - + $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } @@ -117,19 +120,21 @@ public function testDuplicateAvailability() "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", - "scope" => ["id" => 312], - "dayoff" => [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + "scope" => [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] ] ] @@ -155,21 +160,23 @@ public function testOverlappingAvailability() "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", - "scope" => ["id" => 312], - "dayoff" => [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + "scope" => [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] - ] + ], ], [ "id" => 21203, From d17ffa27569ce27406ab138ecc2fa5bc2cfa74d1 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:07:54 +0100 Subject: [PATCH 62/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index bf246e46a..78bff3ba9 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -79,6 +79,7 @@ public function testRendering() $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } + public function testDuplicateAvailability() { $this->setWorkstation(); @@ -143,6 +144,7 @@ public function testDuplicateAvailability() ]) ], []); } + public function testOverlappingAvailability() { $this->setWorkstation(); From 8a41469ff14f72e3d821c5560e0ec8ef21a16463 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:12:33 +0100 Subject: [PATCH 63/86] fix(ZMS-3253): add unit tests for testing validation availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 71 ++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 93dc0178f..bd7eef5c6 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -110,7 +110,76 @@ public function testDuplicateAvailability() 'selectedDate' => date('Y-m-d') ]) ], []); - } + } + + public function testInvalidStartTime() + { + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "description" => "Start Time in Future", + "startDate" => time() + (10 * 24 * 60 * 60), // 10 days in the future + "endDate" => time() + (15 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "kind" => "past", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + + public function testInvalidEndTime() + { + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "description" => "End Time Before Start Time", + "startDate" => time() + (2 * 24 * 60 * 60), + "endDate" => time() + (2 * 24 * 60 * 60), + "startTime" => "17:00:00", + "endTime" => "09:00:00", + "kind" => "default", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + + public function testMissingKind() + { + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "description" => "Missing Kind", + "startDate" => time() + (2 * 24 * 60 * 60), + "endDate" => time() + (3 * 24 * 60 * 60), + "startTime" => "09:00:00", + "endTime" => "17:00:00", + "scope" => ["id" => 312] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + public function testEmpty() { $this->setWorkstation(); From e230b2611bec1cbb89459560551b5dd48f34b0d8 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:14:22 +0100 Subject: [PATCH 64/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 78bff3ba9..94b140fd8 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -79,7 +79,7 @@ public function testRendering() $this->assertStringContainsString('availability.json', (string) $response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } - + public function testDuplicateAvailability() { $this->setWorkstation(); @@ -97,21 +97,24 @@ public function testDuplicateAvailability() "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", - "scope" => ["id" => 312], - "dayoff" => [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + "scope" => [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] - ] + ], + ], [ "id" => 21202, // Duplicate ID @@ -188,21 +191,23 @@ public function testOverlappingAvailability() "startTime" => "10:00:00", "endTime" => "18:00:00", "kind" => "default", - "scope" => ["id" => 312], - "dayoff" => [ - [ - "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), - "name" => "1. Mai", - "lastChange" => $currentTimestamp - ], - [ - "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), - "name" => "Christi Himmelfahrt", - "lastChange" => $currentTimestamp + "scope" => [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] ] - ] + ], ] ], 'selectedDate' => date('Y-m-d') From 5aadb7b748caa1bb18f0f92e975a3a2f9a6750eb Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:18:58 +0100 Subject: [PATCH 65/86] fix(ZMS-3253): add unit tests for testing validation availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index bd7eef5c6..061b403ea 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -3,6 +3,7 @@ namespace BO\Zmsapi\Tests; use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; +use \DateTime; class AvailabilityAddTest extends Base { protected $classname = "AvailabilityAdd"; @@ -130,7 +131,7 @@ public function testInvalidStartTime() "scope" => ["id" => 312] ] ], - 'selectedDate' => date('Y-m-d') + 'selectedDate' => (new DateTime('2024-11-17'))->format('Y-m-d') ]) ], []); } @@ -172,7 +173,8 @@ public function testMissingKind() "endDate" => time() + (3 * 24 * 60 * 60), "startTime" => "09:00:00", "endTime" => "17:00:00", - "scope" => ["id" => 312] + "scope" => ["id" => 312], + "kind" => null, ] ], 'selectedDate' => date('Y-m-d') From 246b4d1045ab50390efa4b379988de65bdd63383 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:28:18 +0100 Subject: [PATCH 66/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 94b140fd8..f8b0df98b 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -82,6 +82,34 @@ public function testRendering() public function testDuplicateAvailability() { + + $input = (new Entity)->createExample(); + $currentTimestamp = time(); + $input['startDate'] = $currentTimestamp + (20 * 24 * 60 * 60); // 2 days in the future + $input['endDate'] = $currentTimestamp + (50 * 24 * 60 * 60); // 5 days in the future + $input['startTime'] = "09:00:00"; + $input['endTime'] = "17:00:00"; + $input['scope'] = [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (70 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (140 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ]; + $input['kind'] = "default"; + + $entity = (new Query())->writeEntity($input); + $secondEntity = (new Query())->writeEntity($input); $this->setWorkstation(); $currentTimestamp = time(); $this->expectException(AvailabilityUpdateFailed::class); @@ -90,10 +118,10 @@ public function testDuplicateAvailability() '__body' => json_encode([ 'availabilityList' => [ [ - "id" => 21202, + "id" => $entity->getId(), "description" => "Duplicate Entry 1", - "startDate" => $currentTimestamp + (3 * 24 * 60 * 60), - "endDate" => $currentTimestamp + (4 * 24 * 60 * 60), + "startDate" => $currentTimestamp + (20 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (20 * 24 * 60 * 60), "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", @@ -102,13 +130,13 @@ public function testDuplicateAvailability() "dayoff" => [ [ "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "date" => $currentTimestamp + (70 * 24 * 60 * 60), "name" => "1. Mai", "lastChange" => $currentTimestamp ], [ "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "date" => $currentTimestamp + (140 * 24 * 60 * 60), "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] @@ -117,10 +145,10 @@ public function testDuplicateAvailability() ], [ - "id" => 21202, // Duplicate ID + "id" => $secondEntity->getId(), // Duplicate ID "description" => "Duplicate Entry 2", - "startDate" => $currentTimestamp + (3 * 24 * 60 * 60), - "endDate" => $currentTimestamp + (4 * 24 * 60 * 60), + "startDate" => $currentTimestamp + (20 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (20 * 24 * 60 * 60), "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", @@ -129,13 +157,13 @@ public function testDuplicateAvailability() "dayoff" => [ [ "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "date" => $currentTimestamp + (70 * 24 * 60 * 60), "name" => "1. Mai", "lastChange" => $currentTimestamp ], [ "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "date" => $currentTimestamp + (140 * 24 * 60 * 60), "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] From 17dcb0774d29811d750607239ef06511f1ba8ac3 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:33:21 +0100 Subject: [PATCH 67/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 84 +++++++++++++++---- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index f8b0df98b..85e6759d1 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -175,9 +175,62 @@ public function testDuplicateAvailability() ]) ], []); } - public function testOverlappingAvailability() { + + $input = (new Entity)->createExample(); + $currentTimestamp = time(); + $input['startDate'] = $currentTimestamp + (20 * 24 * 60 * 60); // 2 days in the future + $input['endDate'] = $currentTimestamp + (50 * 24 * 60 * 60); // 5 days in the future + $input['startTime'] = "09:00:00"; + $input['endTime'] = "17:00:00"; + $input['scope'] = [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (70 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (140 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ]; + $input['kind'] = "default"; + + + $secondInput = (new Entity)->createExample(); + $currentTimestamp = time(); + $secondInput['startDate'] = $currentTimestamp + (20 * 24 * 60 * 60); // 2 days in the future + $secondInput['endDate'] = $currentTimestamp + (50 * 24 * 60 * 60); // 5 days in the future + $secondInput['startTime'] = "10:00:00"; + $secondInput['endTime'] = "20:00:00"; + $secondInput['scope'] = [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (70 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (140 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ]; + $secondInput['kind'] = "default"; + + $entity = (new Query())->writeEntity($input); + $secondEntity = (new Query())->writeEntity($secondInput); $this->setWorkstation(); $currentTimestamp = time(); $this->expectException(AvailabilityUpdateFailed::class); @@ -186,10 +239,10 @@ public function testOverlappingAvailability() '__body' => json_encode([ 'availabilityList' => [ [ - "id" => 21202, - "description" => "Overlapping Entry 1", - "startDate" => $currentTimestamp + (2 * 24 * 60 * 60), - "endDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "id" => $entity->getId(), + "description" => "Duplicate Entry 1", + "startDate" => $currentTimestamp + (200 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (200 * 24 * 60 * 60), "startTime" => "09:00:00", "endTime" => "17:00:00", "kind" => "default", @@ -198,44 +251,45 @@ public function testOverlappingAvailability() "dayoff" => [ [ "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "date" => $currentTimestamp + (700 * 24 * 60 * 60), "name" => "1. Mai", "lastChange" => $currentTimestamp ], [ "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "date" => $currentTimestamp + (1400 * 24 * 60 * 60), "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] ] ], + ], [ - "id" => 21203, - "description" => "Overlapping Entry 2", - "startDate" => $currentTimestamp + (2 * 24 * 60 * 60), - "endDate" => $currentTimestamp + (3 * 24 * 60 * 60), + "id" => $secondEntity->getId(), // Duplicate ID + "description" => "Duplicate Entry 2", + "startDate" => $currentTimestamp + (200 * 24 * 60 * 60), + "endDate" => $currentTimestamp + (200 * 24 * 60 * 60), "startTime" => "10:00:00", - "endTime" => "18:00:00", + "endTime" => "20:00:00", "kind" => "default", "scope" => [ "id" => 312, "dayoff" => [ [ "id" => 35, - "date" => $currentTimestamp + (7 * 24 * 60 * 60), + "date" => $currentTimestamp + (700 * 24 * 60 * 60), "name" => "1. Mai", "lastChange" => $currentTimestamp ], [ "id" => 36, - "date" => $currentTimestamp + (14 * 24 * 60 * 60), + "date" => $currentTimestamp + (1400 * 24 * 60 * 60), "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] ] - ], + ] ] ], 'selectedDate' => date('Y-m-d') From e984774e45e330e4b8832979e46632e5b15249a4 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:34:16 +0100 Subject: [PATCH 68/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 2 +- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index 061b403ea..eeb2fd57f 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -79,7 +79,7 @@ public function testOverlappingAvailability() ]) ], []); } - public function testDuplicateAvailability() + public function testDuplicateOverlappingAvailability() { $this->setWorkstation(); $this->expectException(AvailabilityUpdateFailed::class); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 85e6759d1..6e39099d3 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -80,7 +80,7 @@ public function testRendering() $this->assertTrue(200 == $response->getStatusCode()); } - public function testDuplicateAvailability() + public function testDuplicateOverlappingAvailability() { $input = (new Entity)->createExample(); From d5135e27a7f651ed5769d9dc5d4f76aad693a24a Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:37:23 +0100 Subject: [PATCH 69/86] fix(ZMS-3253): add unit tests for testing overlapping availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 48 +---------------- .../tests/Zmsapi/AvailabilityUpdateTest.php | 54 ++++++++++++++++++- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php index eeb2fd57f..f6fe8998d 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityAddTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityAddTest.php @@ -46,6 +46,7 @@ public function testRendering() $this->assertStringContainsString('availability.json', (string)$response->getBody()); $this->assertTrue(200 == $response->getStatusCode()); } + public function testOverlappingAvailability() { $this->setWorkstation(); @@ -79,6 +80,7 @@ public function testOverlappingAvailability() ]) ], []); } + public function testDuplicateOverlappingAvailability() { $this->setWorkstation(); @@ -113,29 +115,6 @@ public function testDuplicateOverlappingAvailability() ], []); } - public function testInvalidStartTime() - { - $this->setWorkstation(); - $this->expectException(AvailabilityUpdateFailed::class); - - $this->render([], [ - '__body' => json_encode([ - 'availabilityList' => [ - [ - "description" => "Start Time in Future", - "startDate" => time() + (10 * 24 * 60 * 60), // 10 days in the future - "endDate" => time() + (15 * 24 * 60 * 60), - "startTime" => "09:00:00", - "endTime" => "17:00:00", - "kind" => "past", - "scope" => ["id" => 312] - ] - ], - 'selectedDate' => (new DateTime('2024-11-17'))->format('Y-m-d') - ]) - ], []); - } - public function testInvalidEndTime() { $this->setWorkstation(); @@ -159,29 +138,6 @@ public function testInvalidEndTime() ], []); } - public function testMissingKind() - { - $this->setWorkstation(); - $this->expectException(AvailabilityUpdateFailed::class); - - $this->render([], [ - '__body' => json_encode([ - 'availabilityList' => [ - [ - "description" => "Missing Kind", - "startDate" => time() + (2 * 24 * 60 * 60), - "endDate" => time() + (3 * 24 * 60 * 60), - "startTime" => "09:00:00", - "endTime" => "17:00:00", - "scope" => ["id" => 312], - "kind" => null, - ] - ], - 'selectedDate' => date('Y-m-d') - ]) - ], []); - } - public function testEmpty() { $this->setWorkstation(); diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 6e39099d3..7485a1a9b 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -145,7 +145,7 @@ public function testDuplicateOverlappingAvailability() ], [ - "id" => $secondEntity->getId(), // Duplicate ID + "id" => $secondEntity->getId(), "description" => "Duplicate Entry 2", "startDate" => $currentTimestamp + (20 * 24 * 60 * 60), "endDate" => $currentTimestamp + (20 * 24 * 60 * 60), @@ -175,6 +175,7 @@ public function testDuplicateOverlappingAvailability() ]) ], []); } + public function testOverlappingAvailability() { @@ -297,6 +298,57 @@ public function testOverlappingAvailability() ], []); } + public function testInvalidEndTime() + { + + $input = (new Entity)->createExample(); + $currentTimestamp = time(); + $input['startDate'] = $currentTimestamp + (20 * 24 * 60 * 60); // 2 days in the future + $input['endDate'] = $currentTimestamp + (50 * 24 * 60 * 60); // 5 days in the future + $input['startTime'] = "09:00:00"; + $input['endTime'] = "17:00:00"; + $input['scope'] = [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (70 * 24 * 60 * 60), // 7 days in the future + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (140 * 24 * 60 * 60), // 14 days in the future + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ]; + $input['kind'] = "default"; + + $entity = (new Query())->writeEntity($input); + $this->setWorkstation(); + $this->expectException(AvailabilityUpdateFailed::class); + + $this->render([], [ + '__body' => json_encode([ + 'availabilityList' => [ + [ + "id" => $entity->getId(), + "description" => "End Time Before Start Time", + "startDate" => time() + (20 * 24 * 60 * 60), + "endDate" => time() + (20 * 24 * 60 * 60), + "startTime" => "17:00:00", + "endTime" => "09:00:00", + "kind" => "default", + "scope" => ["id" => 141] + ] + ], + 'selectedDate' => date('Y-m-d') + ]) + ], []); + } + public function testEmpty() { $this->setWorkstation(); From ca99ef2ce886bb3f04315e28e391659ee9468f31 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:38:28 +0100 Subject: [PATCH 70/86] fix(ZMS-3253): add unit tests for testing validation availability opening hours --- .../tests/Zmsapi/AvailabilityUpdateTest.php | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index 7485a1a9b..a8ea25a07 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -329,7 +329,7 @@ public function testInvalidEndTime() $entity = (new Query())->writeEntity($input); $this->setWorkstation(); $this->expectException(AvailabilityUpdateFailed::class); - + $this->render([], [ '__body' => json_encode([ 'availabilityList' => [ @@ -341,7 +341,23 @@ public function testInvalidEndTime() "startTime" => "17:00:00", "endTime" => "09:00:00", "kind" => "default", - "scope" => ["id" => 141] + "scope" => [ + "id" => 312, + "dayoff" => [ + [ + "id" => 35, + "date" => $currentTimestamp + (700 * 24 * 60 * 60), + "name" => "1. Mai", + "lastChange" => $currentTimestamp + ], + [ + "id" => 36, + "date" => $currentTimestamp + (1400 * 24 * 60 * 60), + "name" => "Christi Himmelfahrt", + "lastChange" => $currentTimestamp + ] + ] + ] ] ], 'selectedDate' => date('Y-m-d') From d5c6051c30b350f37d5776a17e2c2a17f65691e4 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:40:10 +0100 Subject: [PATCH 71/86] fix(ZMS-3253): add unit tests for testing validation availability opening hours --- zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php index a8ea25a07..87fcd0603 100644 --- a/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php +++ b/zmsapi/tests/Zmsapi/AvailabilityUpdateTest.php @@ -304,9 +304,9 @@ public function testInvalidEndTime() $input = (new Entity)->createExample(); $currentTimestamp = time(); $input['startDate'] = $currentTimestamp + (20 * 24 * 60 * 60); // 2 days in the future - $input['endDate'] = $currentTimestamp + (50 * 24 * 60 * 60); // 5 days in the future - $input['startTime'] = "09:00:00"; - $input['endTime'] = "17:00:00"; + $input['endDate'] = $currentTimestamp + (20 * 24 * 60 * 60); + $input['startTime'] = "17:00:00"; + $input['endTime'] = "09:00:00"; $input['scope'] = [ "id" => 312, "dayoff" => [ @@ -346,13 +346,13 @@ public function testInvalidEndTime() "dayoff" => [ [ "id" => 35, - "date" => $currentTimestamp + (700 * 24 * 60 * 60), + "date" => $currentTimestamp + (70 * 24 * 60 * 60), "name" => "1. Mai", "lastChange" => $currentTimestamp ], [ "id" => 36, - "date" => $currentTimestamp + (1400 * 24 * 60 * 60), + "date" => $currentTimestamp + (140 * 24 * 60 * 60), "name" => "Christi Himmelfahrt", "lastChange" => $currentTimestamp ] From 5527c58a745a237a0c5a096f5c45c3c737edd2f6 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 14:56:43 +0100 Subject: [PATCH 72/86] fix(ZMS-3253): refactor object creation --- .../src/Zmsentities/Collection/AvailabilityList.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index e096c27ea..bc22887eb 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -164,11 +164,12 @@ public function getSlotListByType($type) public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, String $kind) { $errorList = []; - foreach ($this as $availability) { - $today = new \DateTimeImmutable(); - $yesterday = $selectedDate->modify('-1 day'); - $tomorrow = $selectedDate->modify('+1 day'); - + + $today = new \DateTimeImmutable(); + $yesterday = $selectedDate->modify('-1 day'); + $tomorrow = $selectedDate->modify('+1 day'); + + foreach ($this as $availability) { $errorList = array_merge( $errorList, $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $kind) From ad89835574bf8bc88a38448bd67c2bc840fa9775 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 15:00:44 +0100 Subject: [PATCH 73/86] fix(ZMS-3253): refactor exception messages --- .../availability/availabilityaddfailed.twig | 7 +++++++ .../availability/availabilityupdatefailed.twig | 2 +- zmsapi/src/Zmsapi/AvailabilityAdd.php | 8 ++++---- .../Availability/AvailabilityAddFailed.php | 13 +++++++++++++ .../Availability/AvailabilityUpdateFailed.php | 2 +- zmsapi/tests/Zmsapi/AvailabilityAddTest.php | 10 +++++----- 6 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityaddfailed.twig create mode 100644 zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php diff --git a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityaddfailed.twig b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityaddfailed.twig new file mode 100644 index 000000000..f41a04995 --- /dev/null +++ b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityaddfailed.twig @@ -0,0 +1,7 @@ +{% + include "exception/bo/layout.twig" with { + "message":"Zu den angegebenen Daten konnte keine Öffnungszeit erstellt werden. Bitte überprüfen Sie Ihre Eingaben und korrigieren Sie diese gegebenenfalls.", + "title":"Konflikt: Öffnungszeit überschneidet sich mit einer bestehenden Zeit", + "reload":"1" + } +%} diff --git a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig index 7ec9f106f..32fa920d0 100644 --- a/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig +++ b/zmsadmin/templates/exception/bo/zmsapi/exception/availability/availabilityupdatefailed.twig @@ -1,6 +1,6 @@ {% include "exception/bo/layout.twig" with { - "message":"Zu den angegebenen Daten konnte keine Öffnungszeit erstellt oder geändert werden. Bitte überprüfen Sie Ihre Eingaben und korrigieren Sie diese gegebenenfalls.", + "message":"Zu den angegebenen Daten konnte keine Öffnungszeit geändert werden. Bitte überprüfen Sie Ihre Eingaben und korrigieren Sie diese gegebenenfalls.", "title":"Konflikt: Öffnungszeit überschneidet sich mit einer bestehenden Zeit", "reload":"1" } diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 24a832b96..2a4da69a4 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -20,7 +20,7 @@ use BO\Zmsapi\AvailabilitySlotsUpdate; use BO\Zmsapi\Exception\BadRequest as BadRequestException; -use BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed; +use BO\Zmsapi\Exception\Availability\AvailabilityAddFailed; /** @@ -86,14 +86,14 @@ public function readResponse( if (count($validation) > 0) { //error_log(json_encode($validation)); - throw new AvailabilityUpdateFailed(); + throw new AvailabilityAddFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { //error_log(json_encode($conflicts)); - throw new AvailabilityUpdateFailed(); + throw new AvailabilityAddFailed(); } $updatedCollection = new Collection(); @@ -124,7 +124,7 @@ protected function writeEntityUpdate($entity, $resolveReferences): Entity $updatedEntity = $repository->writeEntity($entity, 2); } if (!$updatedEntity) { - throw new AvailabilityUpdateFailed(); + throw new AvailabilityAddFailed(); } return $updatedEntity; } diff --git a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php new file mode 100644 index 000000000..227c14134 --- /dev/null +++ b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php @@ -0,0 +1,13 @@ +setWorkstation(); - $this->expectException(AvailabilityUpdateFailed::class); + $this->expectException(AvailabilityAddFailed::class); $this->render([], [ '__body' => json_encode([ @@ -84,7 +84,7 @@ public function testOverlappingAvailability() public function testDuplicateOverlappingAvailability() { $this->setWorkstation(); - $this->expectException(AvailabilityUpdateFailed::class); + $this->expectException(AvailabilityAddFailed::class); $this->render([], [ '__body' => json_encode([ @@ -118,7 +118,7 @@ public function testDuplicateOverlappingAvailability() public function testInvalidEndTime() { $this->setWorkstation(); - $this->expectException(AvailabilityUpdateFailed::class); + $this->expectException(AvailabilityAddFailed::class); $this->render([], [ '__body' => json_encode([ @@ -158,7 +158,7 @@ public function testEmptyBody() public function testUpdateFailed() { $this->setWorkstation(); - $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityUpdateFailed'); + $this->expectException('\BO\Zmsapi\Exception\Availability\AvailabilityAddFailed'); $this->expectExceptionCode(400); $this->render([], [ From 2a7d9784ee991ab5177630a7c03dc4416f6736dc Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Mon, 18 Nov 2024 15:05:36 +0100 Subject: [PATCH 74/86] fix(ZMS-3253): clean up commented code --- zmsadmin/js/page/availabilityDay/helpers.js | 4 ---- zmsentities/src/Zmsentities/Availability.php | 5 ----- 2 files changed, 9 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/helpers.js b/zmsadmin/js/page/availabilityDay/helpers.js index 062234991..23f745414 100644 --- a/zmsadmin/js/page/availabilityDay/helpers.js +++ b/zmsadmin/js/page/availabilityDay/helpers.js @@ -187,10 +187,6 @@ export const cleanupAvailabilityForSave = availability => { delete newAvailability.tempId; } - /*if (newAvailability.kind) { - delete newAvailability.kind; - }*/ - return newAvailability; } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 89d653943..6a77c5c3f 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -811,11 +811,6 @@ public function getTimeOverlaps(Availability $availability, \DateTimeInterface $ return $processList; } - - - - - /** * Update workstationCount to number of calculated appointments From ea55b27a0c8c2f6aea33ecdfa5890936ec088b5d Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 20 Nov 2024 11:02:46 +0100 Subject: [PATCH 75/86] fix(ZMS-3253): fix grammar --- zmsadmin/js/page/availabilityDay/form/validate.js | 4 ++-- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 4 ++-- zmsentities/src/Zmsentities/Availability.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index bf3ad3353..b0556835d 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -83,12 +83,12 @@ function validateEndTime(today, yesterday, selectedDate, data) { if (dayMinutesEnd <= dayMinutesStart) { errorList.push({ type: 'endTime', - message: 'Die Uhrzeit "von" muss kleiner der Uhrzeit "bis" sein.' + message: 'Die Endzeit darf nicht vor der Startzeit liegen.' }) } else if (startTimestamp >= endTimestamp) { errorList.push({ type: 'endTime', - message: 'Das Startdatum muss nach dem Enddatum sein.' + message: 'Das Enddatum darf nicht vor dem Startdatum liegen.' }) } return errorList; diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 20842db21..730bd3fa1 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -92,14 +92,14 @@ public function readResponse( } if (count($validation) > 0) { - //error_log(json_encode($validation)); + error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - //error_log(json_encode($conflicts)); + error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 6a77c5c3f..eb58570d8 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -502,12 +502,12 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y if ($dayMinutesEnd <= $dayMinutesStart) { $errorList[] = [ 'type' => 'endTime', - 'message' => 'Die Uhrzeit "von" muss kleiner der Uhrzeit "bis" sein.' + 'message' => 'Die Endzeit darf nicht vor der Startzeit liegen.' ]; } elseif ($startTimestamp >= $endTimestamp) { $errorList[] = [ 'type' => 'endTime', - 'message' => 'Das Startdatum muss vor dem Enddatum sein.' + 'message' => 'Das Enddatum darf nicht vor dem Startdatum liegen.' ]; } From 932fe5f5da9ebceadf7a4b8d40fc8fe2b182d88a Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 20 Nov 2024 11:03:59 +0100 Subject: [PATCH 76/86] fix(ZMS-3253): comment error_log --- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 730bd3fa1..20842db21 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -92,14 +92,14 @@ public function readResponse( } if (count($validation) > 0) { - error_log(json_encode($validation)); + //error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - error_log(json_encode($conflicts)); + //error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } From 5aa9d6b063531bea8d35f270b1aa6f361fa5f228 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 20 Nov 2024 19:25:45 +0100 Subject: [PATCH 77/86] fix(ZMS-3253): Improve frontend validation for opening hours availability --- .../page/availabilityDay/form/datepicker.js | 1 + .../availabilityDay/form/footerButtons.js | 12 +- .../page/availabilityDay/form/formButtons.js | 6 +- .../js/page/availabilityDay/form/index.js | 2 + .../js/page/availabilityDay/form/validate.js | 171 ++++++++++++++++-- zmsadmin/js/page/availabilityDay/index.js | 30 ++- .../js/page/availabilityDay/layouts/page.js | 3 +- zmsadmin/js/page/availabilityDay/saveBar.js | 28 ++- .../src/Zmsadmin/AvailabilityConflicts.php | 3 - zmsapi/src/Zmsapi/AvailabilityUpdate.php | 4 +- zmsentities/src/Zmsentities/Availability.php | 1 + 11 files changed, 218 insertions(+), 43 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/datepicker.js b/zmsadmin/js/page/availabilityDay/form/datepicker.js index 22b13c683..737f8e202 100644 --- a/zmsadmin/js/page/availabilityDay/form/datepicker.js +++ b/zmsadmin/js/page/availabilityDay/form/datepicker.js @@ -339,6 +339,7 @@ class AvailabilityDatePicker extends Component excludeTimes={this.state.excludeTimeList} //filterTime={filterPassedTime} disabled={this.props.attributes.disabled} + readOnly onInputClick={this.openTimePicker} onKeyDown={this.tpKeyDownHandler} onClickOutside={this.closeTimePicker} diff --git a/zmsadmin/js/page/availabilityDay/form/footerButtons.js b/zmsadmin/js/page/availabilityDay/form/footerButtons.js index ca41c6c50..6da070349 100644 --- a/zmsadmin/js/page/availabilityDay/form/footerButtons.js +++ b/zmsadmin/js/page/availabilityDay/form/footerButtons.js @@ -4,14 +4,12 @@ import PropTypes from 'prop-types' const FooterButtons = (props) => { const { hasConflicts, stateChanged, data, onNew, onPublish, onAbort, hasSlotCountError } = props return ( -
- - - - +
+ + +
- ) } diff --git a/zmsadmin/js/page/availabilityDay/form/formButtons.js b/zmsadmin/js/page/availabilityDay/form/formButtons.js index 95a394855..d7892ac74 100644 --- a/zmsadmin/js/page/availabilityDay/form/formButtons.js +++ b/zmsadmin/js/page/availabilityDay/form/formButtons.js @@ -2,8 +2,8 @@ import React from 'react' import PropTypes from 'prop-types' const FormButtons = (props) => { - const { data, onCopy, onExclusion, onEditInFuture, onUpdateSingle, onDelete, selectedDate, hasConflicts } = props - const disabled = ((data && (! data.id || data.__modified === true)) || hasConflicts); + const { data, onCopy, onExclusion, onEditInFuture, onUpdateSingle, onDelete, selectedDate, hasConflicts, hasSlotCountError } = props + const disabled = ((data && (! data.id || data.__modified === true)) || hasConflicts || hasSlotCountError); return (
@@ -21,7 +21,7 @@ const FormButtons = (props) => { className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern + className="button button--diamond" disabled={(data && !data.id) || hasConflicts || hasSlotCountError || props.isCreatingExclusion}>Aktualisieren
) diff --git a/zmsadmin/js/page/availabilityDay/form/index.js b/zmsadmin/js/page/availabilityDay/form/index.js index a851d9e8a..edc692490 100644 --- a/zmsadmin/js/page/availabilityDay/form/index.js +++ b/zmsadmin/js/page/availabilityDay/form/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import FormButtons from './formButtons' import FormContent from './content' import { getDataValuesFromForm, cleanupFormData, getFormValuesFromData } from '../helpers' +import { hasSlotCountError } from '../form/validate'; class AvailabilityForm extends Component { constructor(props) { @@ -64,6 +65,7 @@ class AvailabilityForm extends Component { onUpdateSingle={this.props.onUpdateSingle} selectedDate={this.props.selectedDate} hasConflicts={hasConflicts} + hasSlotCountError={hasSlotCountError(this.props)} isCreatingExclusion={this.props.isCreatingExclusion} />}
diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index b0556835d..48c35e13c 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -1,36 +1,169 @@ -import moment from 'moment' +import moment from 'moment'; const validate = (data, props) => { - const currentTime = new Date() - const today = moment(props.today, 'X') - today.set('hour', currentTime.getHours()) - today.set('minute', currentTime.getMinutes()) - today.set('second', currentTime.getSeconds()) - - const selectedDate = moment(props.timestamp, 'X') - const yesterday = selectedDate.startOf('day').clone().subtract(1, 'days') - const tomorrow = selectedDate.startOf('day').clone().add(1, 'days') - + const currentTime = new Date(); + const today = moment(props.today, 'X'); + today.set('hour', currentTime.getHours()); + today.set('minute', currentTime.getMinutes()); + today.set('second', currentTime.getSeconds()); + + const selectedDate = moment(props.timestamp, 'X'); + const yesterday = selectedDate.startOf('day').clone().subtract(1, 'days'); + const tomorrow = selectedDate.startOf('day').clone().add(1, 'days'); + let errorList = { id: data.id || data.tempId, itemList: [] - } + }; + + // Add new validation functions for null and format checks + errorList.itemList.push(validateNullValues(data)); + errorList.itemList.push(validateTimestampAndTimeFormats(data)); + + errorList.itemList.push(validateStartTime(today, tomorrow, selectedDate, data)); + errorList.itemList.push(validateEndTime(today, yesterday, selectedDate, data)); + errorList.itemList.push(validateOriginEndTime(today, yesterday, selectedDate, data)); + errorList.itemList.push(validateType(data)); + errorList.itemList.push(validateSlotTime(data)); - errorList.itemList.push(validateStartTime(today, tomorrow, selectedDate, data)) - errorList.itemList.push(validateEndTime(today, yesterday, selectedDate, data)) - errorList.itemList.push(validateOriginEndTime(today, yesterday, selectedDate, data)) - errorList.itemList.push(validateType(data)) - errorList.itemList.push(validateSlotTime(data)) - errorList.itemList = errorList.itemList.filter(el => el.length); - let valid = (0 < errorList.itemList.length) ? false : true + let valid = (0 < errorList.itemList.length) ? false : true; return { valid, errorList + }; +}; + +// Validate if startDate, endDate, startTime, and endTime are not null +function validateNullValues(data) { + let errorList = []; + + if (!data.startDate) { + errorList.push({ + type: 'startDateNull', + message: 'Das Startdatum darf nicht leer sein.' + }); } + + if (!data.endDate) { + errorList.push({ + type: 'endDateNull', + message: 'Das Enddatum darf nicht leer sein.' + }); + } + + if (!data.startTime) { + errorList.push({ + type: 'startTimeNull', + message: 'Die Startzeit darf nicht leer sein.' + }); + } + + if (!data.endTime) { + errorList.push({ + type: 'endTimeNull', + message: 'Die Endzeit darf nicht leer sein.' + }); + } + + return errorList; } +// Validate timestamps and time formats +function validateTimestampAndTimeFormats(data) { + let errorList = []; + const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/; // HH:mm:ss or HH:mm + + // Validate startDate and endDate as valid timestamps + if (!isValidTimestamp(data.startDate)) { + errorList.push({ + type: 'startDateInvalid', + message: 'Das Startdatum ist kein gültiger Zeitstempel.' + }); + } + + if (!isValidTimestamp(data.endDate)) { + errorList.push({ + type: 'endDateInvalid', + message: 'Das Enddatum ist kein gültiger Zeitstempel.' + }); + } + + // Validate startTime and endTime format + if (data.startTime && !timeRegex.test(data.startTime)) { + errorList.push({ + type: 'startTimeFormat', + message: 'Die Startzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + }); + } + + if (data.endTime && !timeRegex.test(data.endTime)) { + errorList.push({ + type: 'endTimeFormat', + message: 'Die Endzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + }); + } + + return errorList; +} + +// Helper function to check if a timestamp is valid +function isValidTimestamp(timestamp) { + return !isNaN(timestamp) && moment.unix(timestamp).isValid(); +} + +// Parse timestamp and time into moment objects +function parseTimestampAndTime(dateTimestamp, timeStr) { + const date = moment.unix(dateTimestamp); + if (!date.isValid()) return null; + + const [hours, minutes, seconds] = timeStr.split(':').map((val, index) => parseInt(val || 0)); + return date.set({ hour: hours, minute: minutes, second: seconds }); +} + +// Example usage in validateStartTime and validateEndTime +function validateStartTime(today, tomorrow, selectedDate, data) { + let errorList = []; + const startTime = parseTimestampAndTime(data.startDate, data.startTime); + const isFuture = data.kind && data.kind === 'future'; + + if (!startTime) { + errorList.push({ + type: 'startTimeInvalid', + message: 'Ungültige Startzeit oder Startdatum.' + }); + } else if (!isFuture && startTime.isAfter(today, 'minute')) { + errorList.push({ + type: 'startTimeFuture', + message: `Das Startdatum der Öffnungszeit muss vor dem ${tomorrow.format('DD.MM.YYYY')} liegen.` + }); + } + + return errorList; +} + +function validateEndTime(today, yesterday, selectedDate, data) { + let errorList = []; + const endTime = parseTimestampAndTime(data.endDate, data.endTime); + const startTime = parseTimestampAndTime(data.startDate, data.startTime); + + if (!endTime) { + errorList.push({ + type: 'endTimeInvalid', + message: 'Ungültige Endzeit oder Enddatum.' + }); + } else if (startTime && endTime.isBefore(startTime)) { + errorList.push({ + type: 'endTime', + message: 'Das Enddatum darf nicht vor dem Startdatum liegen.' + }); + } + + return errorList; +} + + function validateStartTime(today, tomorrow, selectedDate, data) { let errorList = [] const startTime = moment(data.startDate, 'X').startOf('day'); diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 9b23a22f8..b5d26c62e 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -51,6 +51,10 @@ class AvailabilityPage extends Component { }; } + handleScrollToBottom() { + window.scrollTo(0, document.body.scrollHeight); + } + componentDidMount() { this.getValidationList() this.unloadHandler = ev => { @@ -144,10 +148,12 @@ class AvailabilityPage extends Component { this.refreshData(); this.setState({ lastSave: new Date().getTime(), + saveSuccess: true, }, () => { this.successElement.scrollIntoView(); }); hideSpinner(); + this.handleScrollToBottom(); }).fail((err) => { let isException = err.responseText.toLowerCase().includes('exception'); if (err.status >= 500 && isException) { @@ -160,8 +166,13 @@ class AvailabilityPage extends Component { } else { console.log('save all error', err); } + this.setState({ + lastSave: new Date().getTime(), + saveSuccess: false, + }); this.getValidationList(); hideSpinner(); + this.handleScrollToBottom(); }); } else { hideSpinner(); @@ -219,10 +230,12 @@ class AvailabilityPage extends Component { this.refreshData(); this.setState({ lastSave: new Date().getTime(), + saveSuccess: true, }, () => { this.successElement.scrollIntoView(); }); hideSpinner(); + this.handleScrollToBottom(); }).fail(err => { const isException = err.responseText.toLowerCase().includes('exception'); if (isException) { @@ -233,14 +246,19 @@ class AvailabilityPage extends Component { } else { console.log('Update error:', err); } + this.setState({ + lastSave: new Date().getTime(), + saveSuccess: false, + }); + this.getValidationList(); hideSpinner(); + this.handleScrollToBottom(); }); } else { hideSpinner(); } } - onDeleteAvailability(availability) { showSpinner(); @@ -775,9 +793,15 @@ class AvailabilityPage extends Component { renderSaveBar() { if (this.state.lastSave) { - return + return ( + + ) } - } + } render() { return ( diff --git a/zmsadmin/js/page/availabilityDay/layouts/page.js b/zmsadmin/js/page/availabilityDay/layouts/page.js index 3a547e780..7a3ef83e2 100644 --- a/zmsadmin/js/page/availabilityDay/layouts/page.js +++ b/zmsadmin/js/page/availabilityDay/layouts/page.js @@ -11,6 +11,7 @@ const PageLayout = (props) => { {props.timeTable} {props.saveBar} {props.accordion} + {props.saveBar}
) } @@ -19,8 +20,8 @@ PageLayout.propTypes = { timeTable: PropTypes.node, accordion: PropTypes.node, conflicts: PropTypes.node, + saveBar: PropTypes.node, tabs: PropTypes.node, - saveBar: PropTypes.node } export default PageLayout diff --git a/zmsadmin/js/page/availabilityDay/saveBar.js b/zmsadmin/js/page/availabilityDay/saveBar.js index e5868d09c..66c55f57d 100644 --- a/zmsadmin/js/page/availabilityDay/saveBar.js +++ b/zmsadmin/js/page/availabilityDay/saveBar.js @@ -1,16 +1,33 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import moment from 'moment' -import PropTypes from 'prop-types' +import PropTypes from 'prop-types' const formatDate = date => { const momentDate = moment(date) return `${momentDate.format('DD.MM.YYYY')} um ${momentDate.format('HH:mm')} Uhr` } - + const SaveBar = (props) => { + const [isVisible, setIsVisible] = useState(true) + + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(false) + }, 5000) + + return () => clearTimeout(timer) + }, []) + + if (!isVisible) return null + return ( -
- Öffnungszeiten gespeichert, {formatDate(props.lastSave)} +
+ {props.success + ? Öffnungszeiten gespeichert, {formatDate(props.lastSave)} + : Fehler beim Speichern der Öffnungszeiten. Bitte versuchen Sie es erneut.}
) } @@ -19,6 +36,7 @@ SaveBar.propTypes = { lastSave: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]).isRequired, + success: PropTypes.bool.isRequired, setSuccessRef: PropTypes.func } diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index 92edd5287..85014c06e 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -93,7 +93,4 @@ protected static function getAvailabilityList($scope, $dateTime) return $availabilityList->withScope($scope); } - - - } diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 20842db21..730bd3fa1 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -92,14 +92,14 @@ public function readResponse( } if (count($validation) > 0) { - //error_log(json_encode($validation)); + error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - //error_log(json_encode($conflicts)); + error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index eb58570d8..5561db327 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -578,6 +578,7 @@ public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterfa public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { + $errorList = array_merge( $this->validateStartTime($today, $tomorrow, $startDate, $endDate, $selectedDate, $kind), $this->validateEndTime($today, $yesterday, $startDate, $endDate, $selectedDate), From fb7efb758882eb058df60850700b7dee771d36b0 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Thu, 21 Nov 2024 15:30:27 +0100 Subject: [PATCH 78/86] cleanup(ZMS-3415): remove invalid text instruction for graph view opening hours --- zmsadmin/js/page/availabilityDay/timetable/graphview.js | 1 - zmsadmin/js/page/availabilityDay/timetable/index.js | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/timetable/graphview.js b/zmsadmin/js/page/availabilityDay/timetable/graphview.js index c8ccfde27..dcd32b890 100644 --- a/zmsadmin/js/page/availabilityDay/timetable/graphview.js +++ b/zmsadmin/js/page/availabilityDay/timetable/graphview.js @@ -30,7 +30,6 @@ const GraphView = (props) => { headerRight={constants.headerRight(props.links, props.onNewAvailability)} headerMiddle={constants.headerMiddle()} body={graphBody} - footer={constants.renderFooter()} /> diff --git a/zmsadmin/js/page/availabilityDay/timetable/index.js b/zmsadmin/js/page/availabilityDay/timetable/index.js index 81ae07cff..e913ee8cb 100644 --- a/zmsadmin/js/page/availabilityDay/timetable/index.js +++ b/zmsadmin/js/page/availabilityDay/timetable/index.js @@ -34,6 +34,4 @@ export const renderAppointments = (items, maxWorkstationCount, onSelect) => {ret export const renderOpenings = (items, onSelect) => {return items .filter(item => item.type === "openinghours") - .map((data, key) => )} - -export const renderFooter = () => {return Zum Bearbeiten einer Öffnungszeit, bitte auf den entsprechenden blauen oder grünen Zeitstrahl klicken.} \ No newline at end of file + .map((data, key) => )} \ No newline at end of file From 1fd8f650448f7ce8bac5d5c15baf781cf9a10563 Mon Sep 17 00:00:00 2001 From: Thomas Fink Date: Fri, 22 Nov 2024 13:56:49 +0100 Subject: [PATCH 79/86] fix(ZMS-1891): Add missing frontend validation for timepicker --- zmsadmin/js/page/availabilityDay/form/datepicker.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zmsadmin/js/page/availabilityDay/form/datepicker.js b/zmsadmin/js/page/availabilityDay/form/datepicker.js index 737f8e202..f81bfe4d0 100644 --- a/zmsadmin/js/page/availabilityDay/form/datepicker.js +++ b/zmsadmin/js/page/availabilityDay/form/datepicker.js @@ -174,6 +174,10 @@ class AvailabilityDatePicker extends Component } handleTimeChange(name, date) { + if (!date) { + this.closeDatePicker(); + return; + } if ('startDate' == name) { if (this.state.availability.startTime != moment(date).format('HH:mm')) { this.props.onChange("startTime", moment(date).format('HH:mm')); @@ -339,7 +343,6 @@ class AvailabilityDatePicker extends Component excludeTimes={this.state.excludeTimeList} //filterTime={filterPassedTime} disabled={this.props.attributes.disabled} - readOnly onInputClick={this.openTimePicker} onKeyDown={this.tpKeyDownHandler} onClickOutside={this.closeTimePicker} From e4981ffdcaeeefadf51e83b01dd7cdbae300ffa8 Mon Sep 17 00:00:00 2001 From: Thomas Fink Date: Fri, 22 Nov 2024 19:03:51 +0100 Subject: [PATCH 80/86] fix(ZMS-1891): Improve frontend validation for time formats --- .../page/availabilityDay/form/datepicker.js | 4 - .../js/page/availabilityDay/form/errors.js | 33 ++- .../js/page/availabilityDay/form/validate.js | 117 ++++----- zmsadmin/js/page/availabilityDay/index.js | 246 +++++++++++------- zmsentities/src/Zmsentities/Availability.php | 10 +- 5 files changed, 215 insertions(+), 195 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/datepicker.js b/zmsadmin/js/page/availabilityDay/form/datepicker.js index f81bfe4d0..22b13c683 100644 --- a/zmsadmin/js/page/availabilityDay/form/datepicker.js +++ b/zmsadmin/js/page/availabilityDay/form/datepicker.js @@ -174,10 +174,6 @@ class AvailabilityDatePicker extends Component } handleTimeChange(name, date) { - if (!date) { - this.closeDatePicker(); - return; - } if ('startDate' == name) { if (this.state.availability.startTime != moment(date).format('HH:mm')) { this.props.onChange("startTime", moment(date).format('HH:mm')); diff --git a/zmsadmin/js/page/availabilityDay/form/errors.js b/zmsadmin/js/page/availabilityDay/form/errors.js index 67f225527..7dfa3dfd4 100644 --- a/zmsadmin/js/page/availabilityDay/form/errors.js +++ b/zmsadmin/js/page/availabilityDay/form/errors.js @@ -1,15 +1,20 @@ -import React from 'react' -import PropTypes from 'prop-types' +import React from 'react'; +import PropTypes from 'prop-types'; -const renderErrors = errors => Object.keys(errors).map(key => { - return ( +const renderErrors = (errors) => + Object.keys(errors).map(key => (
{errors[key].itemList.map((item, index) => { - return
{item[0].message}
- })} + if (Array.isArray(item)) { + return item.map((nestedItem, nestedIndex) => ( +
{nestedItem.message}
+ )); + } else { + return
{item.message}
; + } + })}
- ) -}) + )); const Errors = (props) => { return ( @@ -18,15 +23,15 @@ const Errors = (props) => {

Folgende Fehler sind bei der Prüfung Ihrer Eingaben aufgetreten:

{renderErrors(props.errorList)}
: null - ) -} + ); +}; Errors.defaultProps = { - errorList: [] -} + errorList: {} +}; Errors.propTypes = { errorList: PropTypes.object -} +}; -export default Errors +export default Errors; diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index 48c35e13c..daa4025e3 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -16,10 +16,8 @@ const validate = (data, props) => { itemList: [] }; - // Add new validation functions for null and format checks errorList.itemList.push(validateNullValues(data)); errorList.itemList.push(validateTimestampAndTimeFormats(data)); - errorList.itemList.push(validateStartTime(today, tomorrow, selectedDate, data)); errorList.itemList.push(validateEndTime(today, yesterday, selectedDate, data)); errorList.itemList.push(validateOriginEndTime(today, yesterday, selectedDate, data)); @@ -35,7 +33,6 @@ const validate = (data, props) => { }; }; -// Validate if startDate, endDate, startTime, and endTime are not null function validateNullValues(data) { let errorList = []; @@ -70,50 +67,71 @@ function validateNullValues(data) { return errorList; } -// Validate timestamps and time formats function validateTimestampAndTimeFormats(data) { let errorList = []; - const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/; // HH:mm:ss or HH:mm + const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/; + + let isStartDateValid = isValidTimestamp(data.startDate); + let isEndDateValid = isValidTimestamp(data.endDate); - // Validate startDate and endDate as valid timestamps - if (!isValidTimestamp(data.startDate)) { + if (!isStartDateValid) { errorList.push({ type: 'startDateInvalid', message: 'Das Startdatum ist kein gültiger Zeitstempel.' }); } - if (!isValidTimestamp(data.endDate)) { + if (!isEndDateValid) { errorList.push({ type: 'endDateInvalid', message: 'Das Enddatum ist kein gültiger Zeitstempel.' }); } - // Validate startTime and endTime format - if (data.startTime && !timeRegex.test(data.startTime)) { + if (data.startTime) { + if (!timeRegex.test(data.startTime)) { + errorList.push({ + type: 'startTimeFormat', + message: 'Die Startzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + }); + } + } else { errorList.push({ - type: 'startTimeFormat', - message: 'Die Startzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + type: 'startTimeMissing', + message: 'Die Startzeit darf nicht leer sein.' }); } - if (data.endTime && !timeRegex.test(data.endTime)) { + if (data.endTime) { + if (!timeRegex.test(data.endTime)) { + errorList.push({ + type: 'endTimeFormat', + message: 'Die Endzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + }); + } + } else { errorList.push({ - type: 'endTimeFormat', - message: 'Die Endzeit muss im Format "HH:mm:ss" oder "HH:mm" vorliegen.' + type: 'endTimeMissing', + message: 'Die Endzeit darf nicht leer sein.' }); } + if (isStartDateValid && isEndDateValid) { + if (new Date(data.startDate) > new Date(data.endDate)) { + errorList.push({ + type: 'dateOrderInvalid', + message: 'Das Startdatum darf nicht nach dem Enddatum liegen.' + }); + } + } + return errorList; } -// Helper function to check if a timestamp is valid function isValidTimestamp(timestamp) { return !isNaN(timestamp) && moment.unix(timestamp).isValid(); } -// Parse timestamp and time into moment objects function parseTimestampAndTime(dateTimestamp, timeStr) { const date = moment.unix(dateTimestamp); if (!date.isValid()) return null; @@ -122,48 +140,6 @@ function parseTimestampAndTime(dateTimestamp, timeStr) { return date.set({ hour: hours, minute: minutes, second: seconds }); } -// Example usage in validateStartTime and validateEndTime -function validateStartTime(today, tomorrow, selectedDate, data) { - let errorList = []; - const startTime = parseTimestampAndTime(data.startDate, data.startTime); - const isFuture = data.kind && data.kind === 'future'; - - if (!startTime) { - errorList.push({ - type: 'startTimeInvalid', - message: 'Ungültige Startzeit oder Startdatum.' - }); - } else if (!isFuture && startTime.isAfter(today, 'minute')) { - errorList.push({ - type: 'startTimeFuture', - message: `Das Startdatum der Öffnungszeit muss vor dem ${tomorrow.format('DD.MM.YYYY')} liegen.` - }); - } - - return errorList; -} - -function validateEndTime(today, yesterday, selectedDate, data) { - let errorList = []; - const endTime = parseTimestampAndTime(data.endDate, data.endTime); - const startTime = parseTimestampAndTime(data.startDate, data.startTime); - - if (!endTime) { - errorList.push({ - type: 'endTimeInvalid', - message: 'Ungültige Endzeit oder Enddatum.' - }); - } else if (startTime && endTime.isBefore(startTime)) { - errorList.push({ - type: 'endTime', - message: 'Das Enddatum darf nicht vor dem Startdatum liegen.' - }); - } - - return errorList; -} - - function validateStartTime(today, tomorrow, selectedDate, data) { let errorList = [] const startTime = moment(data.startDate, 'X').startOf('day'); @@ -181,15 +157,15 @@ function validateStartTime(today, tomorrow, selectedDate, data) { message: `Das Startdatum der Öffnungszeit muss vor dem ${tomorrow.format('DD.MM.YYYY')} liegen.` }) } -/* - if (isOrigin && startTime.isBefore(today.startOf('day'), 'day') && data.__modified) { - errorList.push({ - type: 'startTimeOrigin', - message: 'Öffnungszeiten in der Vergangenheit lassen sich nicht bearbeiten ' - + '(Der Terminanfang am "'+startDateTime.format('DD.MM.YYYY')+' liegt vor dem heutigen Tag").' - }) - } -*/ + /* + if (isOrigin && startTime.isBefore(today.startOf('day'), 'day') && data.__modified) { + errorList.push({ + type: 'startTimeOrigin', + message: 'Öffnungszeiten in der Vergangenheit lassen sich nicht bearbeiten ' + + '(Der Terminanfang am "'+startDateTime.format('DD.MM.YYYY')+' liegt vor dem heutigen Tag").' + }) + } + */ if ((startHour == "00" && startMinute == "00") || (endHour == "00" && endMinute == "00")) { errorList.push({ @@ -218,12 +194,15 @@ function validateEndTime(today, yesterday, selectedDate, data) { type: 'endTime', message: 'Die Endzeit darf nicht vor der Startzeit liegen.' }) - } else if (startTimestamp >= endTimestamp) { + } + + if (startTimestamp >= endTimestamp) { errorList.push({ type: 'endTime', message: 'Das Enddatum darf nicht vor dem Startdatum liegen.' }) } + return errorList; } diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index b5d26c62e..2b610d878 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -179,7 +179,6 @@ class AvailabilityPage extends Component { } } - onRevertUpdates() { this.isCreatingExclusion = false this.setState(Object.assign({}, getInitialState(this.props), { @@ -196,18 +195,14 @@ class AvailabilityPage extends Component { const id = availability.id; if (ok) { - // Format the selected date const selectedDate = formatTimestampDate(this.props.timestamp); - // Prepare the data to send const sendAvailability = Object.assign({}, availability); - // Clean up temporary fields if (sendAvailability.tempId) { delete sendAvailability.tempId; } - // Include 'kind' and wrap it in 'availabilityList' const payload = { availabilityList: [ { @@ -220,7 +215,6 @@ class AvailabilityPage extends Component { console.log('Updating single availability', payload); - // Make the AJAX request $.ajax(`${this.props.links.includeurl}/availability/save/${id}/`, { method: 'POST', data: JSON.stringify(payload), @@ -495,72 +489,110 @@ class AvailabilityPage extends Component { return hasError || hasConflict; } - getValidationList(list = []) { - const validateData = data => { - let validationResult = validate(data, this.props) - if (!validationResult.valid) { - return validationResult.errorList - - } - return []; - } - - this.state.availabilitylist.map(availability => { - list.push(validateData(availability)) - }) - list = list.filter(el => el.id) - - this.setState({ - errorList: list.length ? Object.assign({}, list) : {} - }, () => { - if (list.length) { - this.errorElement.scrollIntoView() - } - }) - } - - getConflictList() { - const requestOptions = { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(Object.assign({}, { - availabilityList: this.state.availabilitylist, - selectedDate: formatTimestampDate(this.props.timestamp), - selectedAvailability: this.state.selectedAvailability - })) - }; - const url = `${this.props.links.includeurl}/availability/conflicts/`; - fetch(url, requestOptions) - .then(res => res.json()) - .then( - (data) => { - this.setState({ - conflictList: Object.assign({}, - { - itemList: Object.assign({}, data.conflictList), - conflictIdList: data.conflictIdList - } - ) - }) - if (data.conflictIdList.length > 0) { - this.errorElement.scrollIntoView() - } + getValidationList() { + return new Promise((resolve, reject) => { + const validateData = (data) => { + const validationResult = validate(data, this.props); + if (!validationResult.valid) { + return validationResult.errorList; + } + return []; + }; + + const list = this.state.availabilitylist + .map(validateData) + .flat(); + + console.log("Validation list:", list); + + this.setState( + { + errorList: list.length ? list : [], }, - (err) => { - let isException = err.responseText.toLowerCase().includes('exception'); - if (err.status >= 500 && isException) { - new ExceptionHandler($('.opened'), { - code: err.status, - message: err.responseText - }); + () => { + if (list.length > 0) { + console.warn("Validation failed with errors:", list); + this.errorElement?.scrollIntoView(); + //reject(new Error("Validation failed")); // Reject with an error object } else { - console.log('conflict error', err); + console.log("Validation passed."); + resolve(); } - hideSpinner(); } - ) + ); + }); + } + + validateAvailabilityList(availabilitylist) { + const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/; + + const isValidTimestamp = (timestamp) => !isNaN(timestamp) && moment.unix(timestamp).isValid(); + + const invalidAvailabilities = availabilitylist.filter((availability) => { + const hasInvalidDates = + !isValidTimestamp(availability.startDate) || !isValidTimestamp(availability.endDate); + const hasInvalidTimes = + !timeRegex.test(availability.startTime) || !timeRegex.test(availability.endTime); + + if (hasInvalidDates || hasInvalidTimes) { + console.warn("Invalid availability detected:", availability); + } + + return hasInvalidDates || hasInvalidTimes; + }); + + return invalidAvailabilities; } + getConflictList() { + this.getValidationList() + .then(() => { + const { availabilitylist, selectedAvailability } = this.state; + const { timestamp } = this.props; + + console.log("Validation passed. Proceeding with /availability/conflicts/."); + + selectedAvailability.startTime = moment(selectedAvailability.startTime, ['HH:mm:ss', 'HH:mm']).format('HH:mm'); + selectedAvailability.endTime = moment(selectedAvailability.endTime, ['HH:mm:ss', 'HH:mm']).format('HH:mm'); + + const requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + availabilityList: availabilitylist, + selectedDate: formatTimestampDate(timestamp), + selectedAvailability, + }), + }; + + const url = `${this.props.links.includeurl}/availability/conflicts/`; + + fetch(url, requestOptions) + .then((res) => res.json()) + .then( + (data) => { + console.log("Conflicts fetched successfully:", data); + this.setState({ + conflictList: { + itemList: { ...data.conflictList }, + conflictIdList: data.conflictIdList, + }, + }); + if (data.conflictIdList.length > 0) { + this.errorElement?.scrollIntoView(); + } + }, + (err) => { + console.error("Conflict fetch error:", err); + hideSpinner(); + } + ); + }) + .catch((error) => { + console.warn("Validation failed. Conflict fetch aborted.", error); + }); + } + renderTimeTable() { const onSelect = data => { this.onSelectAvailability(data) @@ -586,41 +618,55 @@ class AvailabilityPage extends Component { } readCalculatedAvailabilityList() { - $.ajax(`${this.props.links.includeurl}/availability/slots/`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - data: JSON.stringify({ - 'availabilityList': this.state.availabilitylist, - 'busySlots': this.state.busyslots - }) - }).done((responseData) => { - let availabilityList = writeSlotCalculationIntoAvailability( - this.state.availabilitylist, - responseData['maxSlots'], - responseData['busySlots'] - ); - this.setState({ - availabilitylistslices: availabilityList, - maxWorkstationCount: parseInt(responseData['maxWorkstationCount']), - }) - }).fail((err) => { - if (err.status === 404) { - console.log('404 error, ignored') - } else { - let isException = err.responseText.toLowerCase().includes('exception'); - if (err.status >= 500 && isException) { - new ExceptionHandler($('.opened'), { - code: err.status, - message: err.responseText + this.getValidationList() + .then(() => { + const { availabilitylist, busyslots } = this.state; + + console.log("Validation passed. Proceeding with /availability/slots/."); + + $.ajax(`${this.props.links.includeurl}/availability/slots/`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify({ + availabilityList: availabilitylist, + busySlots: busyslots, + }), + }) + .done((responseData) => { + console.log("Slots fetched successfully:", responseData); + const availabilityList = writeSlotCalculationIntoAvailability( + this.state.availabilitylist, + responseData['maxSlots'], + responseData['busySlots'] + ); + this.setState({ + availabilitylistslices: availabilityList, + maxWorkstationCount: parseInt(responseData['maxWorkstationCount']), }); - } else { - console.log('reading calculated availability list error', err); - } - hideSpinner(); - } - }) - } - + }) + .fail((err) => { + console.error("Error during /availability/slots/ fetch:", err); + if (err.status === 404) { + console.log("404 error ignored."); + } else { + const isException = err.responseText.toLowerCase().includes("exception"); + if (err.status >= 500 && isException) { + new ExceptionHandler($(".opened"), { + code: err.status, + message: err.responseText, + }); + } + } + hideSpinner(); + }); + }) + .catch((error) => { + console.warn("Validation failed. Slot calculation fetch aborted.", error); + this.setState({ errorList: error }); + this.errorElement?.scrollIntoView(); + }); + } + handleChange(data) { if (data.__modified) { clearTimeout(this.timer) diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 5561db327..2dd33f895 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -450,8 +450,6 @@ public function hasDateBetween(\DateTimeInterface $startTime, \DateTimeInterface } while ($startTime->getTimestamp() <= $stopTime->getTimestamp()); return false; } - - public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { $errorList = []; @@ -482,9 +480,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface } return $errorList; - } - - + } public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate) { $errorList = []; @@ -497,8 +493,7 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y $dayMinutesEnd = ($endHour * 60) + $endMinute; $startTimestamp = $startDate->getTimestamp(); $endTimestamp = $endDate->getTimestamp(); - - // Check if end time is before start time + if ($dayMinutesEnd <= $dayMinutesStart) { $errorList[] = [ 'type' => 'endTime', @@ -514,7 +509,6 @@ public function validateEndTime(\DateTimeInterface $today, \DateTimeInterface $y return $errorList; } - public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) { $errorList = []; From 7916a7054154dcc14b8b1c9b64f26cd6f0e44c34 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Tue, 3 Dec 2024 18:53:50 +0100 Subject: [PATCH 81/86] fix(ZMS-3253): fix frontend exclusion availability validation --- .../page/availabilityDay/form/formButtons.js | 3 +- zmsadmin/js/page/availabilityDay/index.js | 28 ++- zmsapi/src/Zmsapi/AvailabilityAdd.php | 4 + zmscalldisplay/package-lock.json | 196 ------------------ 4 files changed, 27 insertions(+), 204 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/formButtons.js b/zmsadmin/js/page/availabilityDay/form/formButtons.js index d7892ac74..149f26688 100644 --- a/zmsadmin/js/page/availabilityDay/form/formButtons.js +++ b/zmsadmin/js/page/availabilityDay/form/formButtons.js @@ -1,5 +1,6 @@ import React from 'react' import PropTypes from 'prop-types' +import moment from 'moment' const FormButtons = (props) => { const { data, onCopy, onExclusion, onEditInFuture, onUpdateSingle, onDelete, selectedDate, hasConflicts, hasSlotCountError } = props @@ -15,7 +16,7 @@ const FormButtons = (props) => { className="button button--diamond" disabled={disabled}>Kopieren + className="button button--diamond" disabled={disabled || data.endDate == selectedDate || selectedDate <= moment().startOf('day').unix()}>Ausnahme diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 2b610d878..984d0c2d1 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -74,6 +74,7 @@ class AvailabilityPage extends Component { onPublishAvailability() { this.getValidationList(); + console.log("here5") this.getConflictList(); let state = {}; state = { selectedAvailability: null } @@ -266,6 +267,7 @@ class AvailabilityPage extends Component { selectedAvailability: null }), () => { this.refreshData() + console.log("here4") this.getConflictList(), this.getValidationList() }); @@ -398,6 +400,7 @@ class AvailabilityPage extends Component { } ), () => { console.log('in after merging', this.state.availabilitylist); + console.log("here3") this.getConflictList(), this.getValidationList() }) @@ -439,6 +442,7 @@ class AvailabilityPage extends Component { stateChanged: true } ), () => { + console.log("here2") this.getConflictList(), this.getValidationList() }) @@ -549,24 +553,33 @@ class AvailabilityPage extends Component { .then(() => { const { availabilitylist, selectedAvailability } = this.state; const { timestamp } = this.props; - - console.log("Validation passed. Proceeding with /availability/conflicts/."); - + + // Skip conflict checking if selected availability is an exclusion + console.log(JSON.stringify(availabilitylist, null, 2)) + console.log("Kind: " + selectedAvailability.kind) + if (selectedAvailability.kind === 'exclusion') { + console.log("Skipping exclusion..") + return; + } + + // Filter out exclusions from conflict checking + const nonExclusionAvailabilities = availabilitylist.filter(a => a.kind !== 'exclusion'); + selectedAvailability.startTime = moment(selectedAvailability.startTime, ['HH:mm:ss', 'HH:mm']).format('HH:mm'); selectedAvailability.endTime = moment(selectedAvailability.endTime, ['HH:mm:ss', 'HH:mm']).format('HH:mm'); - + const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - availabilityList: availabilitylist, + availabilityList: nonExclusionAvailabilities, selectedDate: formatTimestampDate(timestamp), selectedAvailability, }), }; - + const url = `${this.props.links.includeurl}/availability/conflicts/`; - + fetch(url, requestOptions) .then((res) => res.json()) .then( @@ -676,6 +689,7 @@ class AvailabilityPage extends Component { this.readCalculatedAvailabilityList(); if (data.tempId || data.id) { this.timer = setTimeout(() => { + console.log("here") this.getConflictList() this.getValidationList() }, this.waitintervall) diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 2a4da69a4..2e605ed5e 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -46,9 +46,13 @@ public function readResponse( DbConnection::getWriteConnection(); + + $newCollection = new Collection(); foreach ($input['availabilityList'] as $item) { + error_log(json_encode($item['kind'])); $entity = new Entity($item); + error_log(json_encode($entity->kind)); $entity->testValid(); $newCollection->addEntity($entity); } diff --git a/zmscalldisplay/package-lock.json b/zmscalldisplay/package-lock.json index d2e08bbd4..79ee0a2b1 100644 --- a/zmscalldisplay/package-lock.json +++ b/zmscalldisplay/package-lock.json @@ -2682,108 +2682,6 @@ "postcss": "^8.0.9" } }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-select/node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/css-select/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/css-select/node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/css-select/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -2885,48 +2783,6 @@ "postcss": "^8.2.15" } }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true, - "license": "CC0-1.0", - "optional": true, - "peer": true - }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -4786,15 +4642,6 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true, - "license": "CC0-1.0", - "optional": true, - "peer": true - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6137,21 +5984,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/srcset": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz", - "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -6296,34 +6128,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.3.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, "node_modules/table": { "version": "6.8.2", "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", From 462be604ecb62499fd7f81923a175a7ff68f6ce7 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 4 Dec 2024 11:30:52 +0100 Subject: [PATCH 82/86] fix(ZMS-3253): fix backend exclusion availability validation --- .../src/Zmsadmin/AvailabilityConflicts.php | 36 +++++++++++++------ zmsapi/src/Zmsapi/AvailabilityAdd.php | 26 ++++++++++---- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 26 +++++++++++--- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index 85014c06e..145c8e783 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -34,22 +34,38 @@ protected static function getAvailabilityData($input) $conflictList = new \BO\Zmsentities\Collection\ProcessList(); $availabilityList = (new AvailabilityList())->addData($input['availabilityList']); $conflictedList = []; - + $selectedDateTime = (new \DateTimeImmutable($input['selectedDate']))->modify(\App::$now->format('H:i:s')); - + $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); $futureAvailabilityList = self::getAvailabilityList($scope, $selectedDateTime); - + foreach ($futureAvailabilityList as $futureAvailability) { $availabilityList->addEntity($futureAvailability); } - - [$earliestStartDateTime, $latestEndDateTime] = $availabilityList->getDateTimeRangeFromList( $selectedDateTime); - - $availabilityList = $availabilityList->sortByCustomStringKey('endTime'); - $conflictList = $availabilityList->getConflicts($earliestStartDateTime, $latestEndDateTime); - + + $originId = null; + foreach ($availabilityList as $availability) { + if (isset($availability->kind) && $availability->kind === 'origin' && isset($availability->id)) { + $originId = $availability->id; + break; + } + } + + $filteredAvailabilityList = new AvailabilityList(); + foreach ($availabilityList as $availability) { + if ((!isset($availability->kind) || $availability->kind !== 'exclusion') && + (!isset($availability->id) || $availability->id !== $originId)) { + $filteredAvailabilityList->addEntity($availability); + } + } + + [$earliestStartDateTime, $latestEndDateTime] = $filteredAvailabilityList->getDateTimeRangeFromList($selectedDateTime); + + $filteredAvailabilityList = $filteredAvailabilityList->sortByCustomStringKey('endTime'); + $conflictList = $filteredAvailabilityList->getConflicts($earliestStartDateTime, $latestEndDateTime); + foreach ($conflictList as $conflict) { $availabilityId = ($conflict->getFirstAppointment()->getAvailability()->getId()) ? $conflict->getFirstAppointment()->getAvailability()->getId() : @@ -58,7 +74,7 @@ protected static function getAvailabilityData($input) $conflictedList[] = $availabilityId; } } - + return [ 'conflictList' => $conflictList->toConflictListByDay(), 'conflictIdList' => (count($conflictedList)) ? $conflictedList : [] diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index 2e605ed5e..b86a6433f 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -46,13 +46,9 @@ public function readResponse( DbConnection::getWriteConnection(); - - $newCollection = new Collection(); foreach ($input['availabilityList'] as $item) { - error_log(json_encode($item['kind'])); $entity = new Entity($item); - error_log(json_encode($entity->kind)); $entity->testValid(); $newCollection->addEntity($entity); } @@ -93,8 +89,26 @@ public function readResponse( throw new AvailabilityAddFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); - $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); + $originId = null; + foreach ($mergedCollection as $availability) { + if (isset($availability->kind) && $availability->kind === 'origin' && isset($availability->id)) { + $originId = $availability->id; + break; + } + } + + $mergedCollectionWithoutExclusions = new Collection(); + foreach ($mergedCollection as $availability) { + if ((!isset($availability->kind) || $availability->kind !== 'exclusion') && + (!isset($availability->id) || $availability->id !== $originId)) { + $mergedCollectionWithoutExclusions->addEntity($availability); + } + } + + [$earliestStartDateTime, $latestEndDateTime] = $mergedCollectionWithoutExclusions->getDateTimeRangeFromList( + \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00') + ); + $conflicts = $mergedCollectionWithoutExclusions->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { //error_log(json_encode($conflicts)); throw new AvailabilityAddFailed(); diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index 730bd3fa1..d6f10379d 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -92,14 +92,32 @@ public function readResponse( } if (count($validation) > 0) { - error_log(json_encode($validation)); + //error_log(json_encode($validation)); throw new AvailabilityUpdateFailed(); } - [$earliestStartDateTime, $latestEndDateTime] = $mergedCollection->getDateTimeRangeFromList(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00')); - $conflicts = $mergedCollection->getConflicts($earliestStartDateTime, $latestEndDateTime); + $originId = null; + foreach ($mergedCollection as $availability) { + if (isset($availability->kind) && $availability->kind === 'origin' && isset($availability->id)) { + $originId = $availability->id; + break; + } + } + + $mergedCollectionWithoutExclusions = new Collection(); + foreach ($mergedCollection as $availability) { + if ((!isset($availability->kind) || $availability->kind !== 'exclusion') && + (!isset($availability->id) || $availability->id !== $originId)) { + $mergedCollectionWithoutExclusions->addEntity($availability); + } + } + + [$earliestStartDateTime, $latestEndDateTime] = $mergedCollectionWithoutExclusions->getDateTimeRangeFromList( + \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $input['selectedDate'] . ' 00:00:00') + ); + $conflicts = $mergedCollectionWithoutExclusions->getConflicts($earliestStartDateTime, $latestEndDateTime); if ($conflicts->count() > 0) { - error_log(json_encode($conflicts)); + //error_log(json_encode($conflicts)); throw new AvailabilityUpdateFailed(); } From 46db2737aa13de42e02da93f395c373300b80fc6 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 4 Dec 2024 13:03:18 +0100 Subject: [PATCH 83/86] fix(ZMS-3253): allow exclusion availability on current date --- zmsadmin/js/page/availabilityDay/form/formButtons.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/formButtons.js b/zmsadmin/js/page/availabilityDay/form/formButtons.js index 149f26688..d7892ac74 100644 --- a/zmsadmin/js/page/availabilityDay/form/formButtons.js +++ b/zmsadmin/js/page/availabilityDay/form/formButtons.js @@ -1,6 +1,5 @@ import React from 'react' import PropTypes from 'prop-types' -import moment from 'moment' const FormButtons = (props) => { const { data, onCopy, onExclusion, onEditInFuture, onUpdateSingle, onDelete, selectedDate, hasConflicts, hasSlotCountError } = props @@ -16,7 +15,7 @@ const FormButtons = (props) => { className="button button--diamond" disabled={disabled}>Kopieren + className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme From 490ddce70529e9820e1fcb7c5216110fac3debd2 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 4 Dec 2024 13:44:08 +0100 Subject: [PATCH 84/86] fix(ZMS-3253): improve validation and cleanup code --- .../js/page/availabilityDay/form/validate.js | 2 +- zmsadmin/js/page/availabilityDay/index.js | 3 +-- zmsadmin/js/page/availabilityDay/saveBar.js | 4 ++-- .../src/Zmsadmin/AvailabilityConflicts.php | 10 ++++++++++ zmsapi/src/Zmsapi/AvailabilityAdd.php | 14 +++++++++++--- zmsapi/src/Zmsapi/AvailabilityUpdate.php | 15 +++++++++++---- .../Availability/AvailabilityAddFailed.php | 3 ++- .../Availability/AvailabilityUpdateFailed.php | 2 +- zmsentities/src/Zmsentities/Availability.php | 10 +++++----- .../Collection/AvailabilityList.php | 18 ++++++++++++++---- 10 files changed, 58 insertions(+), 23 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/form/validate.js b/zmsadmin/js/page/availabilityDay/form/validate.js index daa4025e3..c8e53dba8 100644 --- a/zmsadmin/js/page/availabilityDay/form/validate.js +++ b/zmsadmin/js/page/availabilityDay/form/validate.js @@ -129,7 +129,7 @@ function validateTimestampAndTimeFormats(data) { } function isValidTimestamp(timestamp) { - return !isNaN(timestamp) && moment.unix(timestamp).isValid(); + return !Number.isNaN(Number(timestamp)) && moment.unix(timestamp).isValid(); } function parseTimestampAndTime(dateTimestamp, timeStr) { diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 984d0c2d1..53192676c 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -517,7 +517,6 @@ class AvailabilityPage extends Component { if (list.length > 0) { console.warn("Validation failed with errors:", list); this.errorElement?.scrollIntoView(); - //reject(new Error("Validation failed")); // Reject with an error object } else { console.log("Validation passed."); resolve(); @@ -530,7 +529,7 @@ class AvailabilityPage extends Component { validateAvailabilityList(availabilitylist) { const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/; - const isValidTimestamp = (timestamp) => !isNaN(timestamp) && moment.unix(timestamp).isValid(); + const isValidTimestamp = (timestamp) => !Number.isNaN(Number(timestamp)) && moment.unix(timestamp).isValid(); const invalidAvailabilities = availabilitylist.filter((availability) => { const hasInvalidDates = diff --git a/zmsadmin/js/page/availabilityDay/saveBar.js b/zmsadmin/js/page/availabilityDay/saveBar.js index 66c55f57d..0d79d7d2d 100644 --- a/zmsadmin/js/page/availabilityDay/saveBar.js +++ b/zmsadmin/js/page/availabilityDay/saveBar.js @@ -26,8 +26,8 @@ const SaveBar = (props) => { className={`message ${props.success ? 'message--success' : 'message--error'}`} > {props.success - ? Öffnungszeiten gespeichert, {formatDate(props.lastSave)} - : Fehler beim Speichern der Öffnungszeiten. Bitte versuchen Sie es erneut.} + ? Öffnungszeiten gespeichert, {formatDate(props.lastSave)} + : Fehler beim Speichern der Öffnungszeiten. Bitte versuchen Sie es erneut.} ) } diff --git a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php index 145c8e783..b740e1be0 100644 --- a/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php +++ b/zmsadmin/src/Zmsadmin/AvailabilityConflicts.php @@ -6,6 +6,7 @@ namespace BO\Zmsadmin; +use BO\Zmsapi\Exception\BadRequest as BadRequestException; use BO\Zmsentities\Availability; use BO\Zmsentities\Collection\AvailabilityList; @@ -31,6 +32,14 @@ public function readResponse( protected static function getAvailabilityData($input) { + + if (!isset($input['availabilityList']) || !is_array($input['availabilityList'])) { + throw new BadRequestException('Missing or invalid availabilityList.'); + } else if(!isset($input['availabilityList'][0]['scope'])){ + throw new BadRequestException('Missing or invalid scope.'); + } else if (!isset($input['selectedDate'])) { + throw new BadRequestException("'selectedDate' is required."); + } $conflictList = new \BO\Zmsentities\Collection\ProcessList(); $availabilityList = (new AvailabilityList())->addData($input['availabilityList']); $conflictedList = []; @@ -39,6 +48,7 @@ protected static function getAvailabilityData($input) $scopeData = $input['availabilityList'][0]['scope']; $scope = new \BO\Zmsentities\Scope($scopeData); + $futureAvailabilityList = self::getAvailabilityList($scope, $selectedDateTime); foreach ($futureAvailabilityList as $futureAvailability) { diff --git a/zmsapi/src/Zmsapi/AvailabilityAdd.php b/zmsapi/src/Zmsapi/AvailabilityAdd.php index b86a6433f..b09e56214 100644 --- a/zmsapi/src/Zmsapi/AvailabilityAdd.php +++ b/zmsapi/src/Zmsapi/AvailabilityAdd.php @@ -46,6 +46,13 @@ public function readResponse( DbConnection::getWriteConnection(); + if (!isset($input['availabilityList']) || !is_array($input['availabilityList'])) { + throw new BadRequestException('Missing or invalid availabilityList.'); + } else if(!isset($input['availabilityList'][0]['scope'])){ + throw new BadRequestException('Missing or invalid scope.'); + } else if (!isset($input['selectedDate'])) { + throw new BadRequestException("'selectedDate' is required."); + } $newCollection = new Collection(); foreach ($input['availabilityList'] as $item) { $entity = new Entity($item); @@ -66,6 +73,7 @@ public function readResponse( $mergedCollection->addEntity($existingAvailability); } + $validations = []; foreach ($newCollection as $newAvailability) { $startDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->startDate); @@ -74,7 +82,7 @@ public function readResponse( $startDateTime = new \DateTimeImmutable("{$startDate->format('Y-m-d')} {$newAvailability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate->format('Y-m-d')} {$newAvailability->endTime}"); - $validation = $mergedCollection->validateInputs( + $validations = $mergedCollection->validateInputs( $startDateTime, $endDateTime, $selectedDate, @@ -84,8 +92,8 @@ public function readResponse( $mergedCollection->addEntity($newAvailability); } - if (count($validation) > 0) { - //error_log(json_encode($validation)); + if (count($validations) > 0) { + //error_log(json_encode($validations)); throw new AvailabilityAddFailed(); } diff --git a/zmsapi/src/Zmsapi/AvailabilityUpdate.php b/zmsapi/src/Zmsapi/AvailabilityUpdate.php index d6f10379d..b2edbd251 100644 --- a/zmsapi/src/Zmsapi/AvailabilityUpdate.php +++ b/zmsapi/src/Zmsapi/AvailabilityUpdate.php @@ -46,9 +46,15 @@ public function readResponse( DbConnection::getWriteConnection(); + if (!isset($input['availabilityList']) || !is_array($input['availabilityList'])) { + throw new BadRequestException('Missing or invalid availabilityList.'); + } else if(!isset($input['availabilityList'][0]['scope'])){ + throw new BadRequestException('Missing or invalid scope.'); + } else if (!isset($input['selectedDate'])) { + throw new BadRequestException("'selectedDate' is required."); + } $availabilityRepo = new AvailabilityRepository(); $newCollection = new Collection(); - foreach ($input['availabilityList'] as $item) { $entity = new Entity($item); $entity->testValid(); @@ -72,6 +78,7 @@ public function readResponse( $mergedCollection->addEntity($existingAvailability); } + $validations = []; foreach ($newCollection as $newAvailability) { $startDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->startDate)->format('Y-m-d'); $endDate = (new \DateTimeImmutable())->setTimestamp($newAvailability->endDate)->format('Y-m-d'); @@ -81,7 +88,7 @@ public function readResponse( $startDateTime = new \DateTimeImmutable("{$startDate} {$newAvailability->startTime}"); $endDateTime = new \DateTimeImmutable("{$endDate} {$newAvailability->endTime}"); - $validation = $mergedCollection->validateInputs( + $validations = $mergedCollection->validateInputs( $startDateTime, $endDateTime, $selectedDate, @@ -91,8 +98,8 @@ public function readResponse( $mergedCollection->addEntity($newAvailability); } - if (count($validation) > 0) { - //error_log(json_encode($validation)); + if (count($validations) > 0) { + //error_log(json_encode($validations)); throw new AvailabilityUpdateFailed(); } diff --git a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php index 227c14134..339905244 100644 --- a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php +++ b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityAddFailed.php @@ -9,5 +9,6 @@ class AvailabilityAddFailed extends \Exception { protected $code = 400; - protected $message = 'Could not create availablity.'; + protected $message = 'Failed to create availability. Please ensure there are no conflicts with existing entries.'; + } diff --git a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php index bbe457e00..549934ce6 100644 --- a/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php +++ b/zmsapi/src/Zmsapi/Exception/Availability/AvailabilityUpdateFailed.php @@ -9,5 +9,5 @@ class AvailabilityUpdateFailed extends \Exception { protected $code = 400; - protected $message = 'Could not update availablity.'; + protected $message = 'Could not update availability.'; } diff --git a/zmsentities/src/Zmsentities/Availability.php b/zmsentities/src/Zmsentities/Availability.php index 2dd33f895..bd83f4248 100644 --- a/zmsentities/src/Zmsentities/Availability.php +++ b/zmsentities/src/Zmsentities/Availability.php @@ -454,7 +454,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface { $errorList = []; - $startTime = $startDate->setTime(0, 0); + $startTime = (clone $startDate)->setTime(0, 0); $startHour = ($startDate->format('H')); $endHour = (int)$endDate->format('H'); $startMinute = (int)$startDate->format('i'); @@ -464,7 +464,7 @@ public function validateStartTime(\DateTimeInterface $today, \DateTimeInterface if ( !$isFuture && $selectedDate->getTimestamp() > $today->getTimestamp() && - $startTime->getTimestamp() > $selectedDate->setTime(0, 0)->getTimestamp() + $startTime->getTimestamp() > (clone $selectedDate)->setTime(0, 0)->getTimestamp() ) { $errorList[] = [ 'type' => 'startTimeFuture', @@ -519,7 +519,7 @@ public function validateOriginEndTime(\DateTimeInterface $today, \DateTimeInterf $isOrigin = ($kind && $kind === 'origin'); // Validate that end date is after the selected date - if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endDate < $selectedDate->setTime(0, 0)) { + if (!$isOrigin && $selectedDate->getTimestamp() > $today->getTimestamp() && $endDate < (clone $selectedDate)->setTime(0, 0)) { $errorList[] = [ 'type' => 'endTimeFuture', 'message' => "Das Enddatum der Öffnungszeit muss nach dem " . $yesterday->format('d.m.Y') . " liegen." @@ -559,7 +559,7 @@ public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterfa $startTimestamp = $startDate->getTimestamp(); $endTimestamp = $endDate->getTimestamp(); - $slotAmount = ($endTimestamp - $startTimestamp) / 60 % $slotTime; + $slotAmount = (($endTimestamp - $startTimestamp) / 60) % $slotTime; if ($slotAmount > 0) { $errorList[] = [ 'type' => 'slotCount', @@ -570,7 +570,7 @@ public function validateSlotTime(\DateTimeInterface $startDate, \DateTimeInterfa return $errorList; } - public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, String $kind) + public function validateAll(\DateTimeInterface $today, \DateTimeInterface $yesterday, \DateTimeInterface $tomorrow, \DateTimeInterface $startDate, \DateTimeInterface $endDate, \DateTimeInterface $selectedDate, string $kind): array { $errorList = array_merge( diff --git a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php index bc22887eb..bae029ab0 100644 --- a/zmsentities/src/Zmsentities/Collection/AvailabilityList.php +++ b/zmsentities/src/Zmsentities/Collection/AvailabilityList.php @@ -18,7 +18,7 @@ public function getMaxWorkstationCount() { $max = 0; foreach ($this as $availability) { - if ($availability['workstationCount']['intern'] > $max) { + if ($availability['workstationCount']['intern'] > $max) { $max = $availability['workstationCount']['intern']; } } @@ -161,7 +161,17 @@ public function getSlotListByType($type) return $slotList; } - public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, String $kind) + /** + * Validates availability inputs against business rules and time constraints + * + * @param \DateTimeImmutable $startDate The start date to validate + * @param \DateTimeImmutable $endDate The end date to validate + * @param \DateTimeImmutable $selectedDate The selected date for context + * @param string $kind The type of validation to perform + * + * @return array List of validation errors + */ + public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, \DateTimeImmutable $selectedDate, string $kind): array { $errorList = []; @@ -169,7 +179,7 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable $yesterday = $selectedDate->modify('-1 day'); $tomorrow = $selectedDate->modify('+1 day'); - foreach ($this as $availability) { + foreach ($this as $availability) { $errorList = array_merge( $errorList, $availability->validateAll($today, $yesterday, $tomorrow, $startDate, $endDate, $selectedDate, $kind) @@ -177,7 +187,7 @@ public function validateInputs(\DateTimeImmutable $startDate, \DateTimeImmutable } return $errorList; } - + /** * Get the earliest startDateTime and latest endDateTime from an AvailabilityList * If the start date of any availability is before the selected date, use the selected date instead. From 2ce23636f06b9e98e897b8e0a181fe0bf4285ab6 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 4 Dec 2024 14:17:03 +0100 Subject: [PATCH 85/86] fix(ZMS-3253): move js spinner --- zmsadmin/js/page/availabilityDay/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 53192676c..392f72440 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -660,6 +660,7 @@ class AvailabilityPage extends Component { console.error("Error during /availability/slots/ fetch:", err); if (err.status === 404) { console.log("404 error ignored."); + hideSpinner(); } else { const isException = err.responseText.toLowerCase().includes("exception"); if (err.status >= 500 && isException) { @@ -667,9 +668,11 @@ class AvailabilityPage extends Component { code: err.status, message: err.responseText, }); + } else { + console.error("Unexpected error:", err.responseText); } + hideSpinner(); } - hideSpinner(); }); }) .catch((error) => { From 97cee9cd79f7ef0aad91f8b2902741875da652a4 Mon Sep 17 00:00:00 2001 From: ThomasAFink Date: Wed, 4 Dec 2024 16:55:41 +0100 Subject: [PATCH 86/86] clean(ZMS-3253): remove console logs --- zmsadmin/js/page/availabilityDay/index.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/zmsadmin/js/page/availabilityDay/index.js b/zmsadmin/js/page/availabilityDay/index.js index 392f72440..c42067633 100644 --- a/zmsadmin/js/page/availabilityDay/index.js +++ b/zmsadmin/js/page/availabilityDay/index.js @@ -74,7 +74,6 @@ class AvailabilityPage extends Component { onPublishAvailability() { this.getValidationList(); - console.log("here5") this.getConflictList(); let state = {}; state = { selectedAvailability: null } @@ -267,7 +266,6 @@ class AvailabilityPage extends Component { selectedAvailability: null }), () => { this.refreshData() - console.log("here4") this.getConflictList(), this.getValidationList() }); @@ -400,7 +398,6 @@ class AvailabilityPage extends Component { } ), () => { console.log('in after merging', this.state.availabilitylist); - console.log("here3") this.getConflictList(), this.getValidationList() }) @@ -442,7 +439,6 @@ class AvailabilityPage extends Component { stateChanged: true } ), () => { - console.log("here2") this.getConflictList(), this.getValidationList() }) @@ -552,16 +548,10 @@ class AvailabilityPage extends Component { .then(() => { const { availabilitylist, selectedAvailability } = this.state; const { timestamp } = this.props; - - // Skip conflict checking if selected availability is an exclusion - console.log(JSON.stringify(availabilitylist, null, 2)) - console.log("Kind: " + selectedAvailability.kind) if (selectedAvailability.kind === 'exclusion') { console.log("Skipping exclusion..") return; } - - // Filter out exclusions from conflict checking const nonExclusionAvailabilities = availabilitylist.filter(a => a.kind !== 'exclusion'); selectedAvailability.startTime = moment(selectedAvailability.startTime, ['HH:mm:ss', 'HH:mm']).format('HH:mm'); @@ -691,7 +681,6 @@ class AvailabilityPage extends Component { this.readCalculatedAvailabilityList(); if (data.tempId || data.id) { this.timer = setTimeout(() => { - console.log("here") this.getConflictList() this.getValidationList() }, this.waitintervall)