feat: offer contact validation flow
This commit is contained in:
@@ -14,6 +14,7 @@ use App\Entity\Groups\BoardService;
|
||||
use App\Enum\Groups\AccommodationBookingOrigin;
|
||||
use App\Enum\Groups\AccommodationBookingStatus;
|
||||
use App\Form\Model\AccommodationBookingDto;
|
||||
use App\Model\AccommodationBookingContext;
|
||||
use App\Model\AccommodationBookingQueryParams;
|
||||
use App\Model\CmsHotelData;
|
||||
use App\Model\InquiryStatus;
|
||||
@@ -23,6 +24,7 @@ use App\Repository\Groups\AdditionalServiceRepository;
|
||||
use App\Repository\Groups\BoardServiceRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class AccommodationBookingService
|
||||
{
|
||||
@@ -41,6 +43,7 @@ class AccommodationBookingService
|
||||
private readonly AccommodationBookingLinkSigner $linkSigner,
|
||||
private readonly AccommodationBookingBreakdownCalculator $breakdownCalculator,
|
||||
private readonly AccommodationBookingPdfGenerator $pdfGenerator,
|
||||
private readonly ValidatorInterface $validator,
|
||||
private readonly string $accommodationEmail,
|
||||
) {
|
||||
}
|
||||
@@ -115,6 +118,19 @@ class AccommodationBookingService
|
||||
return $this->cmsDataProvider->getHotelDetails($accommodation->getEffectiveCmsCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* What the customer-facing offer pages show around a stored booking: the hotel's CMS
|
||||
* content and the price breakdown computed from the booking's frozen snapshot.
|
||||
*/
|
||||
public function createOfferContext(AccommodationBooking $booking, Accommodation $accommodation): AccommodationBookingContext
|
||||
{
|
||||
return new AccommodationBookingContext(
|
||||
accommodation: $accommodation,
|
||||
hotelCmsData: $this->loadHotelCmsData($accommodation),
|
||||
priceBreakdown: $this->breakdownCalculator->compute($booking),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccommodationPrice[]
|
||||
*/
|
||||
@@ -262,7 +278,6 @@ class AccommodationBookingService
|
||||
): AccommodationBooking {
|
||||
$booking = new AccommodationBooking();
|
||||
$booking->setAccommodation($accommodation);
|
||||
$booking->setGroupName($dto->groupName);
|
||||
$booking->setDateFrom($dto->dateFrom);
|
||||
$booking->setDateTo($dto->dateTo);
|
||||
$booking->setPaxCount($dto->paxCount);
|
||||
@@ -305,15 +320,7 @@ class AccommodationBookingService
|
||||
);
|
||||
}
|
||||
|
||||
// Personal data
|
||||
$booking->setSalutation($dto->salutation);
|
||||
$booking->setFirstName($dto->firstName);
|
||||
$booking->setLastName($dto->lastName);
|
||||
$booking->setEmail($dto->email);
|
||||
$booking->setPhone($dto->phone);
|
||||
$booking->setStreet($dto->street);
|
||||
$booking->setZip($dto->zip);
|
||||
$booking->setCity($dto->city);
|
||||
$this->copyContactData($dto, $booking);
|
||||
$booking->setRemarks($dto->remarks);
|
||||
|
||||
$this->refreshPriceSnapshot($booking);
|
||||
@@ -627,6 +634,51 @@ class AccommodationBookingService
|
||||
$this->sendOfferAcceptedNotificationEmail($booking);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offers are put together by the office, which only has to supply name and email, so
|
||||
* the rest of the contact data is often missing. A customer may accept an offer once it
|
||||
* meets the constraints a self-service booking meets in step 3.
|
||||
*/
|
||||
public function hasCompleteContactData(AccommodationBooking $booking): bool
|
||||
{
|
||||
return 0 === $this->validator->validate($this->contactDataFromBooking($booking), null, ['contact'])->count();
|
||||
}
|
||||
|
||||
public function contactDataFromBooking(AccommodationBooking $booking): AccommodationBookingDto
|
||||
{
|
||||
$dto = new AccommodationBookingDto();
|
||||
$dto->groupName = $booking->getGroupName();
|
||||
$dto->salutation = $booking->getSalutation();
|
||||
$dto->firstName = $booking->getFirstName();
|
||||
$dto->lastName = $booking->getLastName();
|
||||
$dto->email = $booking->getEmail();
|
||||
$dto->phone = $booking->getPhone();
|
||||
$dto->street = $booking->getStreet();
|
||||
$dto->zip = $booking->getZip();
|
||||
$dto->city = $booking->getCity();
|
||||
|
||||
return $dto;
|
||||
}
|
||||
|
||||
public function applyContactData(AccommodationBooking $booking, AccommodationBookingDto $dto): void
|
||||
{
|
||||
$this->copyContactData($dto, $booking);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
private function copyContactData(AccommodationBookingDto $dto, AccommodationBooking $booking): void
|
||||
{
|
||||
$booking->setGroupName($dto->groupName);
|
||||
$booking->setSalutation($dto->salutation);
|
||||
$booking->setFirstName($dto->firstName);
|
||||
$booking->setLastName($dto->lastName);
|
||||
$booking->setEmail($dto->email);
|
||||
$booking->setPhone($dto->phone);
|
||||
$booking->setStreet($dto->street);
|
||||
$booking->setZip($dto->zip);
|
||||
$booking->setCity($dto->city);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicit office action after the requested services and capacities have been validated:
|
||||
* this is the moment the booking becomes binding for the customer, and the only place the
|
||||
|
||||
Reference in New Issue
Block a user