* Fertigstellung Buchungsformular (#1321) (SternTours-CRM-API-Anbindung, Mailversand, Validierung, Dynamische Preisberechnung, Persistierung von Buchungsinformationen)
* Fehler bei der Preisberechnung behoben * Farbschema geändert (Kevin Adametz) git-svn-id: http://78.47.251.156/svn/dev/sterntours-3@3289 f459cee4-fb09-11de-96c3-f9c5f16c3c76
This commit is contained in:
parent
dde3b91724
commit
3a28866cd2
36 changed files with 2200 additions and 268 deletions
|
|
@ -10,14 +10,32 @@ 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
|
||||
{
|
||||
public function indexAction(Page $travelProgramPage, Request $request)
|
||||
/** @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'))
|
||||
|
|
@ -26,6 +44,8 @@ class BookingController extends Controller
|
|||
}
|
||||
$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)
|
||||
{
|
||||
|
|
@ -40,31 +60,355 @@ class BookingController extends Controller
|
|||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$form = $this->createForm(BookingRequestType::class, null, [
|
||||
/** @var BookingRequest $bookingRequest */
|
||||
$bookingRequest = new BookingRequest();
|
||||
if ($request->getMethod() != 'POST')
|
||||
{
|
||||
$bookingRequest->setTravelerCount(2);
|
||||
$bookingRequest->setDeparture($travelDate->getDepartures()[0]);
|
||||
}
|
||||
$form = $this->createForm(BookingRequestType::class, $bookingRequest, [
|
||||
'travel_date' => $travelDate,
|
||||
'travel_program' => $travelProgram
|
||||
]);
|
||||
//$form->submit([]);
|
||||
if ($request->getMethod() == 'POST')
|
||||
{
|
||||
$form->handleRequest($request);
|
||||
$bookingRequest = $form->getData();
|
||||
}
|
||||
$htmlSummary = [];
|
||||
$bookingPriceInfo = [];
|
||||
$totalPrice = $this->calculatePrice($travelDate, $bookingRequest, $htmlSummary, $bookingPriceInfo);
|
||||
|
||||
$priceTypeById = $this->getDoctrine()->getRepository('AppBundle:TravelPeriodPriceType')->findAllIndexedById();
|
||||
if ($action == 'buchen')
|
||||
{
|
||||
$breadcrumbEntries = Util::createBreadcrumb($travelProgramPage);
|
||||
$breadcrumbEntries[] = new BreadcrumbEntry('Buchen', $travelProgramPage->getUrlPath() .'/buchen');
|
||||
|
||||
$breadcrumbEntries = Util::createBreadcrumb($travelProgramPage);
|
||||
$breadcrumbEntries[] = new BreadcrumbEntry('Buchen', $travelProgramPage->getUrlPath() .'/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();
|
||||
|
||||
return $this->render('default/pages/booking.html.twig', [
|
||||
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
|
||||
'page' => $travelProgramPage,
|
||||
'travel_program' => $travelProgram,
|
||||
'travel_date' => $travelDate,
|
||||
'form' => $form->createView(),
|
||||
'price_type_by_id' => $priceTypeById,
|
||||
'breadcrumb_entries' => $breadcrumbEntries,
|
||||
]);
|
||||
$crmBookingUrl = $this->get('app.booking_exporter')->process($bookingRequest, $travelDate, $bookingPriceInfo);
|
||||
|
||||
$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('sternt@stern-tours.de')
|
||||
->setBody(
|
||||
$this->renderView('default/email/bookingServiceEmail.txt.twig', [
|
||||
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
|
||||
'crm_url' => $crmBookingUrl .'/edit',
|
||||
'travel_program_url' => 'http' . (($_SERVER['SERVER_PORT'] == 443) ? 's://' : '://') .
|
||||
$_SERVER['HTTP_HOST'] . $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,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('default/pages/booking.html.twig', [
|
||||
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
|
||||
'page' => $travelProgramPage,
|
||||
'travel_program' => $travelProgram,
|
||||
'travel_date' => $travelDate,
|
||||
'form' => $form->createView(),
|
||||
'price_type_by_id' => $this->priceTypeById,
|
||||
'breadcrumb_entries' => $breadcrumbEntries,
|
||||
'summary' => $htmlSummary,
|
||||
'total_price' => $totalPrice
|
||||
]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
public function calculatePrice()
|
||||
public function calculatePrice(TravelDate $travelDate, BookingRequest $bookingRequest, &$outHtmlSummary = null,
|
||||
&$outPriceInfo = null)
|
||||
{
|
||||
$ret = 0;
|
||||
$insuranceAssessmentBasis = 0;
|
||||
$travelerCount = $bookingRequest->getTravelerCount();
|
||||
if (isset($outHtmlSummary))
|
||||
{
|
||||
$insuranceHtmlSummary = [];
|
||||
}
|
||||
if (isset($outPriceInfo))
|
||||
{
|
||||
$outPriceInfo['rooms'] = [];
|
||||
$outPriceInfo['insurances'] = [];
|
||||
$outPriceInfo['options'] = [];
|
||||
$outPriceInfo['classOptions'] = [];
|
||||
}
|
||||
|
||||
$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' => $travelerCount .'x '. ($departure->getExtraCharge() > 0 ? 'Aufschlag' : 'Abzug') .
|
||||
' für Abfahrts-/Abflugort "'. $departure->getName() .'" <strong>'.
|
||||
Util::formatPrice($departure->getExtraCharge()) .'</strong>'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bookingRequest->getTravelOptions() as $travelOption)
|
||||
{
|
||||
$insuranceAssessmentBasis += $travelOption->getPrice();
|
||||
$a = $travelerCount * $travelOption->getPrice();
|
||||
$ret += $a;
|
||||
if (isset($outHtmlSummary))
|
||||
{
|
||||
$outHtmlSummary[] = [
|
||||
'value' => $a,
|
||||
'label' => $travelerCount .'x zugebuchte Leistung: '. $travelOption->getName() .' <strong>'.
|
||||
Util::formatPrice($travelOption->getPrice()) .'</strong>'
|
||||
];
|
||||
}
|
||||
if (isset($outPriceInfo))
|
||||
{
|
||||
$outPriceInfo['options'][] = $travelOption;
|
||||
}
|
||||
}
|
||||
|
||||
$persons = [
|
||||
'total' => $travelerCount,
|
||||
'adults' => $travelerCount,
|
||||
'children' => 0
|
||||
];
|
||||
$possibleRooms = $this->searchRooms($travelDate->getPrices(), $persons);
|
||||
|
||||
if (empty($possibleRooms))
|
||||
{
|
||||
if ($travelerCount % 2 == 0)
|
||||
{
|
||||
$possibleRooms = $this->splitIntoTwoGroups($travelDate->getPrices(), $persons, 'equal');
|
||||
}
|
||||
elseif ($travelerCount >= 3)
|
||||
{
|
||||
$possibleRooms = $this->splitIntoTwoGroups($travelDate->getPrices(), $persons, 'move_without_children');
|
||||
}
|
||||
}
|
||||
|
||||
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' => $room['persons']['total'] .'x zugebuchte Leistung: Komfort-Kategorie <strong>'.
|
||||
Util::formatPrice($room['price']->getEffectiveComfortPrice()) .'</strong>'
|
||||
];
|
||||
}
|
||||
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 = '1x '. $room['priceType']->getName() .' [Personen: '. $adultCount .' x <strong>'.
|
||||
Util::formatPrice($singleFullPrice) .'</strong>';
|
||||
if ($room['persons']['children'] != 0)
|
||||
{
|
||||
$label .= ', Kinder: '. $room['persons']['children'] .' x <strong>'.
|
||||
Util::formatPrice($room['price']->getEffectiveChildPrice()) .'</strong>';
|
||||
}
|
||||
$label .= ']';
|
||||
$outHtmlSummary[] = [
|
||||
'value' => $roomPrice,
|
||||
'label' => $label
|
||||
];
|
||||
if ($singleDiscountPrice !== null)
|
||||
{
|
||||
$outHtmlSummary[] = [
|
||||
'value' => $discount,
|
||||
'label' => $adultCount .'x '.
|
||||
Util::formatPrice($singleFullPrice - $singleDiscountPrice) .' Rabatt'
|
||||
];
|
||||
}
|
||||
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' => $adultCount .'x RV '. $bookingRequest->getInsurance()->getName() .' ('.
|
||||
$insurancePrice->getCode() .') <strong>'. Util::formatPrice($insurancePriceValue) .
|
||||
'</strong>'
|
||||
];
|
||||
}
|
||||
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 searchRooms($prices, $persons)
|
||||
{
|
||||
$ret = [];
|
||||
foreach ($prices as $price)
|
||||
{
|
||||
$priceType = $this->priceTypeById[$price->getPriceTypeId()];
|
||||
if ($priceType->getMax() == $persons['total'] &&
|
||||
$priceType->getMaxAdults() >= $persons['adults'] &&
|
||||
$priceType->getMinAdults() <= $persons['adults'] &&
|
||||
$priceType->getMaxChildren() >= $persons['children'])
|
||||
{
|
||||
$ret[] = [
|
||||
'priceType' => $priceType,
|
||||
'persons' => $persons,
|
||||
'price' => $price
|
||||
];
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function splitIntoTwoGroups($prices, $persons, $mode)
|
||||
{
|
||||
$group1 = [];
|
||||
$group2 = [];
|
||||
if($mode == 'equal')
|
||||
{
|
||||
$group1['adults'] = $group2['adults'] = $persons['adults'] / 2;
|
||||
$group1['children'] = $group2['children'] = $persons['children'] / 2;
|
||||
$group1['total'] = $group2['total'] = $group1['adults'] + $group2['children'];
|
||||
}
|
||||
elseif($mode = 'move_without_children')
|
||||
{
|
||||
$group1['adults'] = $persons['adults'] - 1;
|
||||
$group1['children'] = 0;
|
||||
$group1['total'] = $group1['adults'] + $group1['children'];
|
||||
|
||||
$group2['adults'] = 1;
|
||||
$group2['children'] = 0;
|
||||
$group2['total'] = $group2['adults'] + $group2['children'];
|
||||
}
|
||||
$possibleRoomsGroup1 = $this->searchRooms($prices, $group1);
|
||||
$possibleRoomsGroup2 = $this->searchRooms($prices, $group2);
|
||||
|
||||
return array_merge($possibleRoomsGroup1, $possibleRoomsGroup2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue