From f942600dd8acb7c06582a52f2f9cdf59e4fd4802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 13 Jan 2026 15:14:27 +0100 Subject: [PATCH] fix: fetch fresh room prices from api to avoid calculation mismatch --- api.http | 2 +- src/Service/BookingService.php | 4 ++ src/Service/TravelDataService.php | 62 +++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/api.http b/api.http index d066368..876ddbd 100644 --- a/api.http +++ b/api.http @@ -72,7 +72,7 @@ Authorization: Bearer {{$auth.token("oauth2_api")}} ### API hotel availability remote # @no-cookie-jar -GET {{base_url}}/api/travels/11603/152546/2026-01-03/availability +GET {{base_url}}/api/travels/11606/152546/2026-01-24/availability Accept: application/json Authorization: Bearer {{$auth.token("oauth2_api")}} diff --git a/src/Service/BookingService.php b/src/Service/BookingService.php index 9f4748e..8b123fb 100644 --- a/src/Service/BookingService.php +++ b/src/Service/BookingService.php @@ -247,6 +247,10 @@ class BookingService $this->travelDataService->patchAvailabilities($travelData, $availabilities); } + // Fetch and patch room prices from API to ensure consistency with booking validation + // This prevents price mismatch errors when XML export has stale prices + $this->travelDataService->patchRoomPricesFromApi($travelData); + // Get bookable rooms (Frei or Anfrage with available > 0) $availableRooms = $travelData->getAvailableRooms(); diff --git a/src/Service/TravelDataService.php b/src/Service/TravelDataService.php index 2edf2df..a0b163e 100644 --- a/src/Service/TravelDataService.php +++ b/src/Service/TravelDataService.php @@ -629,6 +629,68 @@ class TravelDataService } } + /** + * Fetches room prices from the API and patches them onto the travel object. + * + * This ensures room prices match between local calculation and API validation, + * preventing price mismatch errors during booking submission. The API call + * takes approximately 4 seconds but is only needed once at booking start. + * + * @param Travel $travel The travel object to update with fresh room prices + */ + public function patchRoomPricesFromApi(Travel $travel): void + { + if (null === $travel->dateTo || null === $travel->hotelId) { + $this->logger->warning('Cannot fetch room prices: missing dateTo or hotelId', [ + 'travelId' => $travel->id, + ]); + + return; + } + + try { + $result = $this->apiClient->getHotelAvailability($travel->id, $travel->hotelId, $travel->dateTo); + + if ($result instanceof Notification) { + $this->logger->warning('API returned notification for room availability', [ + 'travelId' => $travel->id, + 'message' => $result->message, + ]); + + return; + } + + $apiRooms = $result->getItems(); + $patchedCount = 0; + + foreach ($travel->rooms as $room) { + if (isset($apiRooms[$room->id]) && null !== $apiRooms[$room->id]->price) { + $oldPrice = $room->price; + $room->price = $apiRooms[$room->id]->price; + + if ($oldPrice !== $room->price) { + $patchedCount++; + $this->logger->debug('Patched room price', [ + 'roomId' => $room->id, + 'oldPrice' => $oldPrice, + 'newPrice' => $room->price, + ]); + } + } + } + + $this->logger->info('Successfully patched room prices from API', [ + 'travelId' => $travel->id, + 'patchedCount' => $patchedCount, + ]); + } catch (ApiClientException $e) { + $this->logger->error('Failed to fetch room prices from API', [ + 'travelId' => $travel->id, + 'error' => $e->getMessage(), + ]); + } + } + /** * Enrich travel data with additional information. *