From da2a55b830a234e7679099aaa4e4322f73cef4be Mon Sep 17 00:00:00 2001 From: Nicklas Lennert <33667575+lennert1986@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:19:38 +0100 Subject: [PATCH 1/4] Update AccessoryResourceRule.php To ensure that NULL values in both MinQuantity and MaxQuantity do not trigger errors during validation, we can update the MaxQuantity check in the same way as the MinQuantity check. I've added a check for is_null for both limits in the updated code. --- .../Validation/AccessoryResourceRule.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/Application/Reservation/Validation/AccessoryResourceRule.php b/lib/Application/Reservation/Validation/AccessoryResourceRule.php index cc358b2cc..1c400cda8 100644 --- a/lib/Application/Reservation/Validation/AccessoryResourceRule.php +++ b/lib/Application/Reservation/Validation/AccessoryResourceRule.php @@ -46,18 +46,22 @@ public function Validate($reservationSeries, $retryParameters) foreach ($reservationSeries->AllResources() as $resource) { $resourceId = $resource->GetResourceId(); if ($association->ContainsResource($resourceId)) { - /** @var Accessory[] $resourceAccessories */ $resourceAccessories = $association->GetResourceAccessories($resourceId); foreach ($resourceAccessories as $accessory) { $accessoryId = $accessory->GetId(); - $resource = $accessory->GetResource($resourceId); - if (!empty($resource->MinQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved < $resource->MinQuantity) { - $errors[] = $this->strings->GetString('AccessoryMinQuantityErrorMessage', [$resource->MinQuantity, $accessory->GetName()]); - } + if (isset($bookedAccessories[$accessoryId]) && $bookedAccessories[$accessoryId] !== null) { + $resource = $accessory->GetResource($resourceId); + + if (!is_null($resource->MinQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved < $resource->MinQuantity) { + $errors[] = $this->strings->GetString('AccessoryMinQuantityErrorMessage', [$resource->MinQuantity, $accessory->GetName()]); + } - if (!empty($resource->MaxQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved > $resource->MaxQuantity) { - $errors[] = $this->strings->GetString('AccessoryMaxQuantityErrorMessage', [$resource->MaxQuantity, $accessory->GetName()]); + if (!is_null($resource->MaxQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved > $resource->MaxQuantity) { + $errors[] = $this->strings->GetString('AccessoryMaxQuantityErrorMessage', [$resource->MaxQuantity, $accessory->GetName()]); + } + } else { + $errors[] = $this->strings->GetString('AccessoryNotBookedErrorMessage', $accessory->GetName()); } } } From 5d40034a8ee645786d94e6345de26c4662cbd14f Mon Sep 17 00:00:00 2001 From: Nicklas Lennert <33667575+lennert1986@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:26:10 +0100 Subject: [PATCH 2/4] Update composer.json Smarty works fine in 4.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 813b72a78..5d37c1b84 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ }, "require": { "php": ">=8.1", - "smarty/smarty": "^4.3", + "smarty/smarty": "^4.5", "stripe/stripe-php": "^10.2", "monolog/monolog": "^2.9", "google/recaptcha": "1.2.4", From dce970f62120c858af467e5e3b0ac42924fe1b54 Mon Sep 17 00:00:00 2001 From: Nicklas Lennert <33667575+lennert1986@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:50:21 +0100 Subject: [PATCH 3/4] Update composer.json Package facebook/graph-sdk is abandoned, you should avoid using it. No replacement was suggested. This is an unofficial version of Facebook's PHP SDK designed for PHP 7/8+. It is being maintained and tested against the newest PHP versions. You can use this in place of version 5.x of Facebook's deprecated facebook/graph-sdk package. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5d37c1b84..6d02de8a5 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "gregwar/captcha": "1.*", "google/apiclient": "^2.0", "microsoft/microsoft-graph": "^2.0", - "facebook/graph-sdk": "~5.0" + "nickdnk/graph-sdk": "^7.0" }, "repositories": [ { From a208c2557fe614cd3df49be4c59d90f161192e4d Mon Sep 17 00:00:00 2001 From: Nicklas Lennert <33667575+lennert1986@users.noreply.github.com> Date: Wed, 25 Dec 2024 20:10:53 +0100 Subject: [PATCH 4/4] Update AccessoryResourceRule.php Added missing componentes. Sorry --- .../Validation/AccessoryResourceRule.php | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/lib/Application/Reservation/Validation/AccessoryResourceRule.php b/lib/Application/Reservation/Validation/AccessoryResourceRule.php index 1c400cda8..46cd860c4 100644 --- a/lib/Application/Reservation/Validation/AccessoryResourceRule.php +++ b/lib/Application/Reservation/Validation/AccessoryResourceRule.php @@ -14,35 +14,54 @@ class AccessoryResourceRule implements IReservationValidationRule */ private $strings; + /** + * Constructor for initializing dependencies + * + * @param IAccessoryRepository $accessoryRepository + */ public function __construct(IAccessoryRepository $accessoryRepository) { $this->accessoryRepository = $accessoryRepository; $this->strings = Resources::GetInstance(); } + /** + * Validates reservations for accessory-resource rules + * + * @param $reservationSeries + * @param $retryParameters + * @return ReservationRuleResult + */ public function Validate($reservationSeries, $retryParameters) { $errors = []; - /** @var ReservationAccessory[] $bookedAccessories */ + // Step 1: Collect booked accessories $bookedAccessories = []; - foreach ($reservationSeries->Accessories() as $accessory) { $bookedAccessories[$accessory->AccessoryId] = $accessory; } + // Step 2: Load all accessories and create associations $accessories = $this->accessoryRepository->LoadAll(); - $association = $this->GetResourcesAndRequiredAccessories($accessories); - $bookedResourceIds = $reservationSeries->AllResourceIds(); + // Step 3: Find invalid accessory-resource associations $badAccessories = $association->GetAccessoriesThatCannotBeBookedWithGivenResources($bookedAccessories, $bookedResourceIds); foreach ($badAccessories as $accessoryName) { $errors[] = $this->strings->GetString('AccessoryResourceAssociationErrorMessage', $accessoryName); } + // Step 4: Ensure all accessories have a QuantityReserved value (even if not booked) + foreach ($accessories as $accessory) { + if (!isset($bookedAccessories[$accessory->GetId()])) { + $bookedAccessories[$accessory->GetId()] = (object) ['QuantityReserved' => 0]; + } + } + + // Step 5: Validate min and max quantities for resources and accessories foreach ($reservationSeries->AllResources() as $resource) { $resourceId = $resource->GetResourceId(); if ($association->ContainsResource($resourceId)) { @@ -53,24 +72,30 @@ public function Validate($reservationSeries, $retryParameters) if (isset($bookedAccessories[$accessoryId]) && $bookedAccessories[$accessoryId] !== null) { $resource = $accessory->GetResource($resourceId); + // Validate minimum quantity if (!is_null($resource->MinQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved < $resource->MinQuantity) { $errors[] = $this->strings->GetString('AccessoryMinQuantityErrorMessage', [$resource->MinQuantity, $accessory->GetName()]); } + // Validate maximum quantity if (!is_null($resource->MaxQuantity) && $bookedAccessories[$accessoryId]->QuantityReserved > $resource->MaxQuantity) { $errors[] = $this->strings->GetString('AccessoryMaxQuantityErrorMessage', [$resource->MaxQuantity, $accessory->GetName()]); } } else { + // Error for unbooked accessory $errors[] = $this->strings->GetString('AccessoryNotBookedErrorMessage', $accessory->GetName()); } } } } + // Return validation result return new ReservationRuleResult(count($errors) == 0, implode("\n", $errors)); } /** + * Builds relationships between resources and accessories + * * @param Accessory[] $accessories * @return ResourceAccessoryAssociation */ @@ -83,7 +108,6 @@ private function GetResourcesAndRequiredAccessories($accessories) $association->AddRelationship($resource, $accessory); } } - return $association; } } @@ -96,6 +120,8 @@ class ResourceAccessoryAssociation private $accessories = []; /** + * Adds a relationship between a resource and an accessory + * * @param ResourceAccessory $resource * @param Accessory $accessory */ @@ -105,6 +131,8 @@ public function AddRelationship($resource, $accessory) } /** + * Checks if a resource exists in the association + * * @param int $resourceId * @return bool */ @@ -114,15 +142,19 @@ public function ContainsResource($resourceId) } /** + * Gets accessories associated with a resource + * * @param int $resourceId * @return Accessory[] */ public function GetResourceAccessories($resourceId) { - return $this->resources[$resourceId]; + return $this->resources[$resourceId] ?? []; } /** + * Adds an accessory to the association + * * @param Accessory $accessory */ public function AddAccessory(Accessory $accessory) @@ -131,6 +163,8 @@ public function AddAccessory(Accessory $accessory) } /** + * Identifies accessories that cannot be booked with the given resources + * * @param ReservationAccessory[] $bookedAccessories * @param int[] $bookedResourceIds * @return string[] @@ -139,10 +173,8 @@ public function GetAccessoriesThatCannotBeBookedWithGivenResources($bookedAccess { $badAccessories = []; - $bookedAccessoryIds = []; foreach ($bookedAccessories as $accessory) { $accessoryId = $accessory->AccessoryId; - $bookedAccessoryIds[] = $accessoryId; if ($this->AccessoryNeedsARequiredResourceToBeBooked($accessoryId, $bookedResourceIds)) { $badAccessories[] = $this->accessories[$accessoryId]->GetName(); @@ -152,6 +184,13 @@ public function GetAccessoriesThatCannotBeBookedWithGivenResources($bookedAccess return $badAccessories; } + /** + * Checks if an accessory requires a specific resource to be booked + * + * @param int $accessoryId + * @param int[] $bookedResourceIds + * @return bool + */ private function AccessoryNeedsARequiredResourceToBeBooked($accessoryId, $bookedResourceIds) { $accessory = $this->accessories[$accessoryId];