fix: refuse implausible accommodation booking prices

This commit is contained in:
fromme committed 2026-09-26 15:39:04 +02:00
1 parent 773cd4f847
commit 56adf72d12
16 files changed
+628 -15

No files matched your search

+22 -3
View File
@@ -13,6 +13,7 @@ use App\Entity\Groups\AdditionalService;
use App\Entity\Groups\BoardService;
use App\Enum\Groups\AccommodationBookingOrigin;
use App\Enum\Groups\AccommodationBookingStatus;
use App\Exception\ImplausibleBookingPriceException;
use App\Form\Model\AccommodationBookingDto;
use App\Model\AccommodationBookingContext;
use App\Model\AccommodationBookingQueryParams;
@@ -79,7 +80,8 @@ class AccommodationBookingService
/**
* Parses and validates raw date strings, then sets them on the DTO.
*
* @throws \InvalidArgumentException if dates are invalid or dateTo ≤ dateFrom
* @throws \InvalidArgumentException if dates are invalid, dateTo ≤ dateFrom, or the stay
* exceeds AccommodationBooking::MAX_NIGHTS
*/
public function applyDates(AccommodationBookingDto $dto, string $dateFromRaw, string $dateToRaw): void
{
@@ -94,6 +96,10 @@ class AccommodationBookingService
throw new \InvalidArgumentException('Das Abreisedatum muss nach dem Anreisedatum liegen.');
}
if ($dateFrom->diff($dateTo)->days > AccommodationBooking::MAX_NIGHTS) {
throw new \InvalidArgumentException(sprintf('Der Aufenthalt darf höchstens %d Nächte umfassen.', AccommodationBooking::MAX_NIGHTS));
}
$dto->dateFrom = $dateFrom->setTime(0, 0, 0);
$dto->dateTo = $dateTo->setTime(0, 0, 0);
}
@@ -566,6 +572,9 @@ class AccommodationBookingService
* their access link, and swapping the house underneath them would rewrite what they were
* offered.
* Idempotent — a no-op for a booking that is not a draft or already sits at $accommodation.
*
* @throws ImplausibleBookingPriceException if the new house prices the stay implausibly high;
* the booking is left at its old house
*/
public function changeAccommodation(AccommodationBooking $booking, Accommodation $accommodation): void
{
@@ -580,8 +589,18 @@ class AccommodationBookingService
$booking->setBoardServiceOriginalId(null);
$booking->setAdditionalServices([]);
// Clears the snapshot by itself when the new house has no price for the booked range.
$this->refreshPriceSnapshot($booking);
try {
// Clears the snapshot by itself when the new house has no price for the booked range.
$this->refreshPriceSnapshot($booking);
} catch (ImplausibleBookingPriceException $e) {
// The swap and the dropped services are already on the managed entity, and the next
// flush in this request would write them without a price. Reloading the row puts the
// booking back at its old house so the caller can report the refusal on a record that
// still matches the database.
$this->entityManager->refresh($booking);
throw $e;
}
$this->entityManager->flush();
}