getAccommodation(); $boardServices = []; $additionalServices = []; $currentBoardService = null; $currentAdditionalServices = []; if (null !== $accommodation && null !== $booking->getDateFrom() && null !== $booking->getDateTo()) { $boardServices = $this->boardServiceRepo->findByAccommodationAndDateRange( $accommodation, $booking->getDateFrom(), $booking->getDateTo(), ); $additionalServices = $this->additionalServiceRepo->findByAccommodationAndDateRange( $accommodation, $booking->getDateFrom(), $booking->getDateTo(), ); // Pre-select current board service if it is still in the available choices foreach ($boardServices as $bs) { if ($bs->getId() === $booking->getBoardServiceOriginalId()) { $currentBoardService = $bs; break; } } // Pre-select current additional services that are still in the available choices $currentIds = array_column($booking->getAdditionalServices(), 'originalServiceId'); $currentAdditionalServices = array_values(array_filter( $additionalServices, fn (AdditionalService $s) => in_array($s->getId(), $currentIds, true), )); } // ROLE_ADMIN inherits ROLE_GROUPS_ADMIN, so this single check covers both. $assignableManagers = []; if ($this->isGranted('ROLE_GROUPS_ADMIN')) { $assignableManagers = $this->userRepo->findGroupsStaff(); // A user assigned earlier may have lost the role since — keep them in the choices // so the field can render the current value instead of failing to transform it. $currentManager = $booking->getManagedBy(); if (null !== $currentManager && !in_array($currentManager, $assignableManagers, true)) { $assignableManagers[] = $currentManager; } } $form = $this->createForm(AccommodationBookingType::class, $booking, [ 'max_adolescent_age' => $accommodation?->getMaxAdolescentAge() ?? 0, 'board_services' => $boardServices, 'additional_services' => $additionalServices, 'current_board_service' => $currentBoardService, 'current_additional_services' => $currentAdditionalServices, 'assignable_managers' => $assignableManagers, ]); $previousStatus = $booking->getStatus(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { if ($form->has('boardService')) { $selectedBoardService = $form->get('boardService')->getData(); if ($selectedBoardService instanceof BoardService) { $booking->setBoardServiceLabel($selectedBoardService->getLabel()); $booking->setBoardServicePrice($selectedBoardService->getPrice()); $booking->setBoardServiceOriginalId($selectedBoardService->getId()); } else { $booking->setBoardServiceLabel(null); $booking->setBoardServicePrice(null); $booking->setBoardServiceOriginalId(null); } } if ($form->has('selectedAdditionalServices')) { $booking->setAdditionalServices([]); foreach ($form->get('selectedAdditionalServices')->getData() as $service) { $booking->addAdditionalServiceSnapshot( $service->getLabel() ?? '', $service->getPrice() ?? 0, $service->getType(), $service->getId(), ); } } $this->bookingService->refreshPriceSnapshot($booking); $this->entityManager->persist($booking); $this->entityManager->flush(); // Entering Anfrage or Buchung is what the customer needs to hear about: the offer // becomes viewable, or the booking is confirmed. Entwurf and Absage stay silent. $notifiableStatuses = [AccommodationBookingStatus::Inquiry, AccommodationBookingStatus::Booking]; if ($previousStatus !== $booking->getStatus() && in_array($booking->getStatus(), $notifiableStatuses, true)) { $this->bookingService->issueAccessLink($booking); $this->bookingService->sendCustomerConfirmationEmail($booking); } $this->addFlash('success', 'Die Buchung wurde aktualisiert'); $this->logger->info('Updated accommodation booking', [ 'id' => $booking->getId(), 'groupName' => $booking->getGroupName(), ]); return $this->redirectToRoute('app_admin_accommodationbooking_edit', ['id' => $booking->getId()]); } return $this->render('admin/accommodation_booking/edit.html.twig', [ 'booking' => $booking, 'form' => $form, ]); } }