Implement ajax endpoint for prices

This commit is contained in:
Björn Fromme
2020-01-10 19:06:21 +01:00
parent be909049d1
commit 70f21a28b9
7 changed files with 210 additions and 0 deletions
@@ -0,0 +1,91 @@
<?php
namespace EP\EpProducts\Controller;
/***************************************************************
*
* Copyright notice
*
* (c) 2020 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\Hotel;
use EP\EpProducts\Service\GroupsPriceService;
use League\Period\Period;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class AjaxGroupsPriceController extends ActionController
{
/**
* @var GroupsPriceService
*/
protected $groupsPriceService;
public function __construct(GroupsPriceService $groupsPriceService)
{
parent::__construct();
$this->groupsPriceService = $groupsPriceService;
}
/**
* @param Hotel $hotel
* @return string
*/
public function configsAction(Hotel $hotel)
{
return json_encode([
'configs' => $hotel->getGroupsPriceConfigs()->toArray(),
'boards' => $hotel->getGroupsPriceBoards()->toArray(),
'options' => $hotel->getGroupsPriceOptions()->toArray(),
], JSON_THROW_ON_ERROR, 512);
}
public function initializePriceAction()
{
if ($this->request->hasArgument('dateFrom')) {
$dateFrom = new \DateTime($this->request->getArgument('dateFrom'));
$this->request->setArgument('dateFrom', $dateFrom);
}
if ($this->request->hasArgument('dateTo')) {
$dateTo = new \DateTime($this->request->getArgument('dateTo'));
$this->request->setArgument('dateTo', $dateTo);
}
}
/**
* @param Hotel $hotel
* @param \DateTime $dateFrom
* @param \DateTime $dateTo
* @param int $pax
* @return string
* @throws \League\Period\Exception
*/
public function priceAction(Hotel $hotel, \DateTime $dateFrom, \DateTime $dateTo, $pax)
{
$period = new Period($dateFrom, $dateTo);
$price = $this->groupsPriceService->calculateHotelPrice($hotel, $period, $pax);
return json_encode([
'price' => $price,
], JSON_THROW_ON_ERROR, 512);
}
}
@@ -0,0 +1,80 @@
<?php
namespace EP\EpProducts\Service;
use EP\EpProducts\Domain\Model\Hotel;
use League\Period\Period;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class GroupsPriceService
{
public function calculateHotelPrice(Hotel $hotel, Period $period, $pax)
{
// Get all price configs for provided hotel
$configs = $this->getConfigs($hotel);
// Create periods in configs to simplify following steps
$this->patchConfigPeriods($configs);
$price = 0;
// Iterate over all days in provided period
foreach ($period->getDatePeriod('1 DAY') as $day) {
// Iterate over all configs
foreach ($configs as $config) {
// Skip config if current day is not contained
if (false === $config['period']->contains($day)) {
continue;
}
// Calculate base price
$price += $config['price'];
// Add costs for not-included number of persons
if ($pax > $config['persons_included']) {
$price += $config['price_additional_person'] * ($pax - $config['persons_included']);
}
}
}
return $price;
}
protected function patchConfigPeriods(array &$configs)
{
foreach ($configs as $idx => $config) {
$configDateFrom = (new \DateTimeImmutable())->setTimestamp($config['date_from']);
$configDateTo = (new \DateTimeImmutable())->setTimestamp($config['date_to']);
$configs[$idx]['period'] = new Period($configDateFrom, $configDateTo);
}
}
/**
* @param Hotel $hotel
* @return array
*/
protected function getConfigs(Hotel $hotel)
{
$qb = $this->getQueryBuilder();
return $qb
->select('*')
->from('tx_epproducts_domain_model_groupspriceconfig')
->where($qb->expr()->eq('hotel', $qb->createNamedParameter($hotel->getUid())))
->orderBy('date_from')
->execute()
->fetchAll()
;
}
protected function getQueryBuilder()
{
/** @var ConnectionPool $connectionPool */
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
return $connectionPool->getQueryBuilderForTable('tx_epproducts_domain_model_groupspriceconfig');
}
}
@@ -133,6 +133,10 @@ tx_epproducts_ajax_json {
AjaxWatchlist { AjaxWatchlist {
1 = list 1 = list
} }
AjaxGroupsPrice {
1 = configs
2 = price
}
} }
features.requireCHashArgumentForActionArguments = 0 features.requireCHashArgumentForActionArguments = 0
settings =< plugin.tx_epproducts.settings settings =< plugin.tx_epproducts.settings
@@ -345,6 +345,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable', 'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable',
'AjaxCalendar' => 'range,contingents,availableRooms', 'AjaxCalendar' => 'range,contingents,availableRooms',
'AjaxWatchlist' => 'list', 'AjaxWatchlist' => 'list',
'AjaxGroupsPrice' => 'configs,price',
], ],
[ [
'AjaxSearch' => 'searchresult', 'AjaxSearch' => 'searchresult',
@@ -355,6 +356,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable', 'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable',
'AjaxCalendar' => 'range,contingents,availableRooms', 'AjaxCalendar' => 'range,contingents,availableRooms',
'AjaxWatchlist' => 'list', 'AjaxWatchlist' => 'list',
'AjaxGroupsPrice' => 'configs,price',
] ]
); );
@@ -382,6 +384,7 @@ $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epp
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[months]'; $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[months]';
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[month]'; $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[month]';
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[year]'; $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[year]';
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'tx_epproducts_ajax[hotel]';
$GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Controller']['writerConfiguration'] = [ $GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Controller']['writerConfiguration'] = [
\TYPO3\CMS\Core\Log\LogLevel::INFO => [ \TYPO3\CMS\Core\Log\LogLevel::INFO => [
@@ -0,0 +1,27 @@
<template>
<div>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: {
endpoint: {
type: String,
required: true
}
},
data () {
return {
processing: false,
}
},
methods: {
},
mounted () {
}
}
</script>
@@ -11,6 +11,7 @@
import DaterangeSelect from './DaterangeSelect.vue' import DaterangeSelect from './DaterangeSelect.vue'
import AjaxContent from './AjaxContent.vue' import AjaxContent from './AjaxContent.vue'
import Calendar from './Calendar.vue' import Calendar from './Calendar.vue'
import GroupsPriceCalculator from './GroupsPriceCalculator.vue';
import FacebookPixel from './FacebookPixel.vue' import FacebookPixel from './FacebookPixel.vue'
import WatchlistToggle from './WatchlistToggle.vue' import WatchlistToggle from './WatchlistToggle.vue'
import OsmMap from './OsmMap.vue' import OsmMap from './OsmMap.vue'
@@ -28,6 +29,7 @@
DaterangeSelect, DaterangeSelect,
AjaxContent, AjaxContent,
Calendar, Calendar,
GroupsPriceCalculator,
FacebookPixel, FacebookPixel,
WatchlistToggle, WatchlistToggle,
OsmMap, OsmMap,
@@ -248,6 +248,9 @@
<f:section name="Calendar"> <f:section name="Calendar">
<f:if condition="{product.calendarHotel}"> <f:if condition="{product.calendarHotel}">
<groups-price-calculator
endpoint="{ep:uri.ajax(action: 'prices', controller: 'AjaxGroupsPrice', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: hotel}')}"
></groups-price-calculator>
<div class="ep-sidebar ep-facts"> <div class="ep-sidebar ep-facts">
<p><strong>Belegungskalender</strong></p> <p><strong>Belegungskalender</strong></p>
<calendar <calendar