* @date 12/08/2016 */ namespace AppBundle\Controller; use AppBundle\Entity\BookingRequest; use AppBundle\Entity\BreadcrumbEntry; use AppBundle\Entity\Page; use AppBundle\Entity\TravelDate; use AppBundle\Entity\Traveler; use AppBundle\Entity\TravelPeriodPrice; use AppBundle\Entity\TravelPeriodPriceType; use AppBundle\Form\BookingRequestType; use AppBundle\Util; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; class BookingController extends Controller { /** @var TravelPeriodPriceType[] $priceTypeById */ private $priceTypeById; /** * The routing for this action is entirely controlled by KernelControllerListener! * * @param Page $travelProgramPage * @param Request $request * @param $action * * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response * @throws \Exception */ public function indexAction(Page $travelProgramPage, $action, Request $request) { $travelProgram = $travelProgramPage->getTravelProgram(); if (!$request->query->has('nr')) { return $this->redirect($travelProgramPage->getUrlPath()); } $this->getDoctrine()->getRepository('AppBundle:TravelPeriod')->getTrueTravelPeriods($travelProgram); $this->priceTypeById = $this->getDoctrine()->getRepository('AppBundle:TravelPeriodPriceType')->findAllIndexedById(); // #TODO Consider changing key of travel dates foreach ($travelProgram->getTravelDates() as $curTravelDate) { if ($curTravelDate->getName() == $request->query->get('nr')) { $travelDate = $curTravelDate; break; } } if (!isset($travelDate)) { throw $this->createNotFoundException(); } /** @var BookingRequest $bookingRequest */ $bookingRequest = new BookingRequest(); if ($request->getMethod() != 'POST') { $bookingRequest->setRoomCount(0); } $form = $this->createForm(BookingRequestType::class, $bookingRequest, [ 'travel_date' => $travelDate, 'travel_program' => $travelProgram ]); if ($request->getMethod() == 'POST') { $form->handleRequest($request); $bookingRequest = $form->getData(); } $htmlSummary = []; $bookingPriceInfo = []; $totalPrice = $this->calculatePrice($travelDate, $bookingRequest, $htmlSummary, $bookingPriceInfo); if ($action == '/buchen') { $breadcrumbEntries = Util::createBreadcrumb($travelProgramPage); $breadcrumbEntries[] = new BreadcrumbEntry('Buchen'); if ($request->getMethod() == 'POST' && $form->isValid()) { $booking = $this->getDoctrine()->getRepository('AppBundle:TravelBooking')->createFromBookingRequest( $bookingRequest, $travelDate, $bookingPriceInfo); $em = $this->getDoctrine()->getManager(); $em->persist($booking); $em->flush(); $crmBookingUrl = $this->get('app.booking_exporter')->process($bookingRequest, $travelDate, $bookingPriceInfo); if (!$crmBookingUrl) { $crmBookingUrl = '[CRM-EXPORT FEHLGESCHLAGEN]'; } else { $crmBookingUrl = preg_replace('/\\/api/', '', $crmBookingUrl).'/edit'; } $this->get('mailer')->send(\Swift_Message::newInstance() ->setSubject('Ihr Buchungsauftrag bei STERN TOURS') ->setFrom('stern@stern-tours.de', 'STERN TOURS') ->setTo($bookingRequest->getEmail()) ->setBody( $this->renderView('default/email/bookingConfirmationEmail.txt.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, 'booking_request' => $bookingRequest, 'booking_price_info' => $bookingPriceInfo, 'travel_date' => $travelDate, 'breadcrumb_entries' => $breadcrumbEntries, ]), 'text/plain', 'utf-8' ) ); $this->get('mailer')->send(\Swift_Message::newInstance() ->setSubject('BUCHUNG: '. $travelProgram->getTitle() .'('. $travelDate->getName() .')') ->setFrom('stern@stern-tours.de', 'STERN TOURS') ->setTo('stern@stern-tours.de') ->setBody( $this->renderView('default/email/bookingServiceEmail.txt.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, 'crm_url' => $crmBookingUrl, 'travel_program_url' => Util::getBaseUrl() . $travelProgramPage->getUrlPath(), 'booking_request' => $bookingRequest, 'booking_price_info' => $bookingPriceInfo, 'travel_date' => $travelDate, 'breadcrumb_entries' => $breadcrumbEntries, ]), 'text/plain', 'utf-8' ) ); // #TODO This will lead to multiple bookings due to multiple form submission. Redirect instead! return $this->render('default/pages/bookingConfirmation.html.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, 'page' => $travelProgramPage, 'breadcrumb_entries' => $breadcrumbEntries, 'show_nav_sidebar_widget' => false, 'show_travel_guide_sidebar_widget' => false, 'show_travel_magazine_sidebar_widget' => false, 'show_offers_sidebar_widget' => false, 'show_search_sidebar_widget' => false, 'show_feedbacks_sidebar_widget' => false, 'booking' => $booking, 'travel_program' => $travelProgram, 'summary' => $htmlSummary, 'total_price' => $totalPrice, ]); } return $this->render('default/pages/booking.html.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, 'page' => $travelProgramPage, 'breadcrumb_entries' => $breadcrumbEntries, 'show_nav_sidebar_widget' => false, 'show_travel_guide_sidebar_widget' => false, 'show_travel_magazine_sidebar_widget' => false, 'show_offers_sidebar_widget' => false, 'show_search_sidebar_widget' => false, 'show_feedbacks_sidebar_widget' => false, 'travel_program' => $travelProgram, 'travel_date' => $travelDate, 'form' => $form->createView(), 'price_type_by_id' => $this->priceTypeById, 'summary' => $htmlSummary, 'total_price' => $totalPrice, 'mediator_terms_filename' => $travelProgram->getIsMediated() ? $this->getDoctrine()->getRepository('AppBundle:TravelOrganizer')->find(1)->getFileName() : null ]); } elseif ($action == '/berechne-gesamtpreis') { return $this->render('default/components/booking/summary.html.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, 'summary' => $htmlSummary, 'total_price' => $totalPrice ]); } throw new \Exception('Unknow BookingController action: '. $action); } private function calcNumTravelerLabel($number) { $ret = 0; if($number > 0) $ret = 1; return $ret; } public function calculatePrice(TravelDate $travelDate, BookingRequest $bookingRequest, &$outHtmlSummary = null, &$outPriceInfo = null) { $ret = 0; $insuranceAssessmentBasis = 0; $travelerCount = $bookingRequest->getTravelerCount(); $singleRoomCount = $bookingRequest->getSingleRoomCount(); $doubleRoomCount = $bookingRequest->getDoubleRoomCount(); $tripleRoomCount = $bookingRequest->getTripleRoomCount(); if (isset($outHtmlSummary)) { $insuranceHtmlSummary = []; } if (isset($outPriceInfo)) { $outPriceInfo['rooms'] = []; $outPriceInfo['insurances'] = []; $outPriceInfo['options'] = []; $outPriceInfo['classOptions'] = []; } if($bookingRequest->getDeparture() != null) { $departure = Util\DepartureUtil::limitIndividualArrivalPrice($bookingRequest->getDeparture(), $travelDate->getFlightPrice()); if (isset($outPriceInfo)) { $outPriceInfo['departure'] = $departure; } if ($departure->getExtraCharge() != 0) { $insuranceAssessmentBasis += $departure->getExtraCharge(); $a = $travelerCount * $departure->getExtraCharge(); $ret += $a; if (isset($outHtmlSummary)) { $outHtmlSummary[] = [ 'value' => $a, 'label' => ($departure->getExtraCharge() > 0 ? 'Aufschlag' : 'Abzug') . ' für Abfahrts-/Abflugort "'. $departure->getName() .'" ['. $this->calcNumTravelerLabel($travelerCount) .' x '. Util::formatPrice($departure->getExtraCharge()) .' pro Person]' ]; } } } foreach ($bookingRequest->getTravelOptions() as $travelOption) { $insuranceAssessmentBasis += $travelOption->getPrice(); $a = $travelerCount * $travelOption->getPrice(); $ret += $a; if (isset($outHtmlSummary)) { $outHtmlSummary[] = [ 'value' => $a, 'label' => $travelOption->getName() .' ['. $this->calcNumTravelerLabel($travelerCount) .' x '. Util::formatPrice($travelOption->getPrice()) .' pro Person]' ]; } if (isset($outPriceInfo)) { $outPriceInfo['options'][] = $travelOption; } } $persons = [ 'total' => $travelerCount, 'adults' => $travelerCount, 'singleRoomPersons' => $singleRoomCount, 'doubleRoomPersons' => $doubleRoomCount * 2, 'tripleRoomPersons' => $tripleRoomCount * 3, 'children' => 0 //TODO ]; $possibleRooms = $this->getRooms($travelDate->getPrices(), $persons); if ($bookingRequest->getComfort()) { foreach ($possibleRooms as $room) { $insuranceAssessmentBasis += $room['price']->getEffectiveComfortPrice(); $a = $room['persons']['total'] * $room['price']->getEffectiveComfortPrice(); $ret += $a; if (isset($outHtmlSummary)) { $outHtmlSummary[] = [ 'value' => $a, 'label' => 'Komfort-Kategorie ['. $this->calcNumTravelerLabel($travelerCount) .' x '. Util::formatPrice($room['price']->getEffectiveComfortPrice()) .' pro Person]' ]; } if (isset($outPriceInfo)) { $outPriceInfo['classOptions'][] = [ 'count' => $room['persons']['total'], 'name' => 'zugebuchte Leistung: Komfort (4 Sterne)', 'price' => $room['price']->getEffectiveComfortPrice() ]; } } } $insuranceTotal = 0; foreach ($possibleRooms as $room) { $adultCount = $room['persons']['adults']; $singleFullPrice = $room['price']->getEffectivePrice(); $roomPrice = $singleFullPrice * $adultCount + $singleFullPrice * $room['persons']['children']; $singleDiscountPrice = $room['price']->getEffectiveDiscountPrice(); $discount = ($singleDiscountPrice === null) ? 0 : ($adultCount * ($singleDiscountPrice - $singleFullPrice)); $ret += $roomPrice + $discount; if (isset($outPriceInfo)) { $outPriceInfo['rooms'][] = [ 'name' => $room['priceType']->getName(), 'adults' => $room['persons']['adults'], 'children' => $room['persons']['children'], 'price' => $singleDiscountPrice ?? $singleFullPrice, 'price_children' => $room['price']->getEffectiveChildPrice(), 'price_total' => $roomPrice + $discount, ]; } if (isset($outHtmlSummary)) { $label = $room['priceType']->getName() .' ['. $this->calcNumTravelerLabel($adultCount) .' x '. Util::formatPrice($singleFullPrice) .' pro Person]'; if ($room['persons']['children'] != 0) { $label .= ', Kinder: '. $this->calcNumTravelerLabel($room['persons']['children']) .' x '. Util::formatPrice($room['price']->getEffectiveChildPrice()) .''; $label .= ']'; } $outHtmlSummary[] = [ 'value' => $roomPrice, 'label' => $label ]; if ($singleDiscountPrice !== null) { $outHtmlSummary[] = [ 'value' => $discount, 'label' => 'Rabatt ['. $this->calcNumTravelerLabel($adultCount) .'x '. Util::formatPrice($singleFullPrice - $singleDiscountPrice) .' pro Person]' ]; } if ($bookingRequest->getInsurance() && $adultCount > 0) { $curAssessmentBasis = $insuranceAssessmentBasis + ($singleDiscountPrice ?? $singleFullPrice); $insurancePrice = $this->getDoctrine()->getRepository('AppBundle:TravelInsurancePrice') ->findOneByInsuranceIdAndAssessmentBasis($bookingRequest->getInsurance()->getId(), $curAssessmentBasis); $insurancePriceValue = $insurancePrice->getPrice() > 0 ? $insurancePrice->getPrice() : round($insurancePrice->getPercent() * $curAssessmentBasis / 100, 2); $a = $adultCount * $insurancePriceValue; $insuranceTotal += $a; $ret += $a; if (isset($insuranceHtmlSummary)) { $insuranceHtmlSummary[] = [ 'value' => $a, 'label' => 'RV '. $bookingRequest->getInsurance()->getName() .' ('. $insurancePrice->getCode() .') ['. $this->calcNumTravelerLabel($adultCount) .' x '. Util::formatPrice($insurancePriceValue) . ' pro Person]' ]; } if (isset($outPriceInfo)) { $outPriceInfo['insurances'][] = [ 'insurance' => $bookingRequest->getInsurance(), 'insurancePriceValue' => $insurancePriceValue, 'insurancePrice' => $insurancePrice, 'count' => $adultCount, ]; } } } } if (isset($insuranceHtmlSummary)) { $outHtmlSummary = array_merge($outHtmlSummary, $insuranceHtmlSummary); } if (isset($outPriceInfo)) { $outPriceInfo['total'] = $ret; $outPriceInfo['totalWithoutInsurance'] = $ret - $insuranceTotal; } return $ret; } /** * @param TravelPeriodPrice[] $prices * @param $persons * * @return array */ private function getRooms($prices, $persons) { $ret = []; foreach($prices as $price) { $priceTypeId = $price->getPriceTypeId(); $priceType = $this->priceTypeById[$priceTypeId]; if($priceTypeId == 1 && $persons['singleRoomPersons'] > 0) { for($i = 0; $i < $persons['singleRoomPersons']; $i++) { $currentPersons = [ 'total' => 1, 'adults' => 1, 'children' => 0 //TODO ]; $ret[] = [ 'priceType' => $priceType, 'persons' => $currentPersons, 'price' => $price ]; } } if($priceTypeId == 3 && $persons['doubleRoomPersons'] > 0) { for($j = 0; $j < ($persons['doubleRoomPersons'] / 2); $j++) { $currentPersons = [ 'total' => 2, 'adults' => 2, 'children' => 0 ]; $ret[] = [ 'priceType' => $priceType, 'persons' => $currentPersons, 'price' => $price ]; } } if($priceTypeId == 5 && $persons['tripleRoomPersons'] > 0) { for($k = 0; $k < ($persons['tripleRoomPersons'] / 3); $k++) { $currentPersons = [ 'total' => 3, 'adults' => 3, 'children' => 0 ]; $ret[] = [ 'priceType' => $priceType, 'persons' => $currentPersons, 'price' => $price ]; } } } return $ret; } }