Add age range based prices to groups price config

This commit is contained in:
Björn Fromme
2021-08-09 17:34:58 +02:00
parent 3916dede50
commit fc42801c8a
7 changed files with 576 additions and 299 deletions
@@ -95,6 +95,9 @@ class AjaxGroupsPriceController extends ActionController
'dateFrom' => $groupsPriceInquiry->getDateFrom(), 'dateFrom' => $groupsPriceInquiry->getDateFrom(),
'dateTo' => $groupsPriceInquiry->getDateTo(), 'dateTo' => $groupsPriceInquiry->getDateTo(),
'pax' => $groupsPriceInquiry->getPax(), 'pax' => $groupsPriceInquiry->getPax(),
'paxGroup1' => $groupsPriceInquiry->getPaxGroup1(),
'paxGroup2' => $groupsPriceInquiry->getPaxGroup2(),
'paxGroup3' => $groupsPriceInquiry->getPaxGroup3(),
'options' => $selectedOptions, 'options' => $selectedOptions,
'board' => $groupsPriceInquiry->getBoard(), 'board' => $groupsPriceInquiry->getBoard(),
'summary' => $groupsPriceInquiry->getSummary(), 'summary' => $groupsPriceInquiry->getSummary(),
@@ -66,10 +66,24 @@ class GroupsPriceInquiry
/** /**
* @var string * @var string
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/ */
protected $pax; protected $pax;
/**
* @var string
*/
protected $paxGroup1;
/**
* @var string
*/
protected $paxGroup2;
/**
* @var string
*/
protected $paxGroup3;
/** /**
* @var array * @var array
*/ */
@@ -197,6 +211,54 @@ class GroupsPriceInquiry
$this->pax = $pax; $this->pax = $pax;
} }
/**
* @return string
*/
public function getPaxGroup1()
{
return $this->paxGroup1;
}
/**
* @param string $paxGroup1
*/
public function setPaxGroup1($paxGroup1)
{
$this->paxGroup1 = $paxGroup1;
}
/**
* @return string
*/
public function getPaxGroup2()
{
return $this->paxGroup2;
}
/**
* @param string $paxGroup2
*/
public function setPaxGroup2($paxGroup2)
{
$this->paxGroup2 = $paxGroup2;
}
/**
* @return string
*/
public function getPaxGroup3()
{
return $this->paxGroup3;
}
/**
* @param string $paxGroup3
*/
public function setPaxGroup3($paxGroup3)
{
$this->paxGroup3 = $paxGroup3;
}
/** /**
* @return array * @return array
*/ */
@@ -56,6 +56,26 @@ class GroupsPriceConfig extends AbstractEntity implements \JsonSerializable
*/ */
protected $priceAdditionalPerson; protected $priceAdditionalPerson;
/**
* @var float
*/
protected $priceAdditionalPersonGroup1;
/**
* @var float
*/
protected $priceAdditionalPersonGroup2;
/**
* @var float
*/
protected $priceAdditionalPersonGroup3;
/**
* @var bool
*/
protected $bonusCardIncluded = false;
/** /**
* @return \DateTime * @return \DateTime
*/ */
@@ -136,6 +156,70 @@ class GroupsPriceConfig extends AbstractEntity implements \JsonSerializable
$this->priceAdditionalPerson = $priceAdditionalPerson; $this->priceAdditionalPerson = $priceAdditionalPerson;
} }
/**
* @return float
*/
public function getPriceAdditionalPersonGroup1(): float
{
return $this->priceAdditionalPersonGroup1;
}
/**
* @param float $priceAdditionalPersonGroup1
*/
public function setPriceAdditionalPersonGroup1(float $priceAdditionalPersonGroup1): void
{
$this->priceAdditionalPersonGroup1 = $priceAdditionalPersonGroup1;
}
/**
* @return float
*/
public function getPriceAdditionalPersonGroup2(): float
{
return $this->priceAdditionalPersonGroup2;
}
/**
* @param float $priceAdditionalPersonGroup2
*/
public function setPriceAdditionalPersonGroup2(float $priceAdditionalPersonGroup2): void
{
$this->priceAdditionalPersonGroup2 = $priceAdditionalPersonGroup2;
}
/**
* @return float
*/
public function getPriceAdditionalPersonGroup3(): float
{
return $this->priceAdditionalPersonGroup3;
}
/**
* @param float $priceAdditionalPersonGroup3
*/
public function setPriceAdditionalPersonGroup3(float $priceAdditionalPersonGroup3): void
{
$this->priceAdditionalPersonGroup3 = $priceAdditionalPersonGroup3;
}
/**
* @return bool
*/
public function isBonusCardIncluded(): bool
{
return $this->bonusCardIncluded;
}
/**
* @param bool $bonusCardIncluded
*/
public function setBonusCardIncluded(bool $bonusCardIncluded): void
{
$this->bonusCardIncluded = $bonusCardIncluded;
}
/** /**
* @return array * @return array
*/ */
@@ -148,6 +232,12 @@ class GroupsPriceConfig extends AbstractEntity implements \JsonSerializable
'personsIncluded' => $this->getPersonsIncluded(), 'personsIncluded' => $this->getPersonsIncluded(),
'price' => $this->getPrice(), 'price' => $this->getPrice(),
'priceAdditionalPerson' => $this->getPriceAdditionalPerson(), 'priceAdditionalPerson' => $this->getPriceAdditionalPerson(),
'priceAdditionalPersonByGroup' => [
1 => $this->getPriceAdditionalPersonGroup1(),
2 => $this->getPriceAdditionalPersonGroup2(),
3 => $this->getPriceAdditionalPersonGroup3(),
],
'bonusCardIncluded' => $this->isBonusCardIncluded(),
]; ];
} }
} }
@@ -25,16 +25,20 @@ return [
], ],
'interface' => [ 'interface' => [
'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, date_from, date_to, 'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, date_from, date_to,
persons_included, price, price_additional_person', persons_included, bonus_card_included, price, price_additional_person,
price_additional_person_group_1, price_additional_person_group_2, price_additional_person_group_3',
], ],
'types' => [ 'types' => [
'1' => [ '1' => [
'showitem' => '--palette--;;dates, --palette--;;prices, persons_included', 'showitem' => '--palette--;;dates, --palette--;;included, --palette--;;prices, --palette--;;prices_groups',
], ],
], ],
'palettes' => [ 'palettes' => [
'dates' => ['showitem' => 'date_from, date_to'], 'dates' => ['showitem' => 'date_from, date_to'],
'included' => ['showitem' => 'bonus_card_included, persons_included'],
'prices' => ['showitem' => 'price, price_additional_person'], 'prices' => ['showitem' => 'price, price_additional_person'],
'prices_groups' => ['showitem' => 'price_additional_person_group_1, price_additional_person_group_2,
--linebreak--, price_additional_person_group_3'],
], ],
'columns' => [ 'columns' => [
@@ -50,6 +54,7 @@ return [
['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1], ['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0] ['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
], ],
'default' => -1,
], ],
], ],
'l10n_parent' => [ 'l10n_parent' => [
@@ -166,11 +171,49 @@ return [
'price_additional_person' => [ 'price_additional_person' => [
'exclude' => false, 'exclude' => false,
'label' => 'Preis weitere Person', 'label' => 'Preis weitere Person',
'description' => 'ohne Jokercard, alle Altersgruppen',
'config' => [ 'config' => [
'type' => 'input', 'type' => 'input',
'size' => 8, 'size' => 8,
'eval' => 'double2,required', 'eval' => 'double2',
] ]
], ],
'price_additional_person_group_1' => [
'exclude' => false,
'label' => 'Preis weitere Person',
'description' => 'mit Jokercard, 4-6 Jahre',
'config' => [
'type' => 'input',
'size' => 8,
'eval' => 'double2',
]
],
'price_additional_person_group_2' => [
'exclude' => false,
'label' => 'Preis weitere Person',
'description' => 'mit Jokercard, 7-14 Jahre',
'config' => [
'type' => 'input',
'size' => 8,
'eval' => 'double2',
]
],
'price_additional_person_group_3' => [
'exclude' => false,
'label' => 'Preis weitere Person',
'description' => 'mit Jokercard, ab 15 Jahre',
'config' => [
'type' => 'input',
'size' => 8,
'eval' => 'double2',
]
],
'bonus_card_included' => [
'exclude' => 0,
'label' => 'Jokercard inklusive',
'config' => [
'type' => 'check',
],
],
], ],
]; ];
+31 -27
View File
@@ -280,37 +280,41 @@ CREATE TABLE tx_epproducts_domain_model_hotel
CREATE TABLE tx_epproducts_domain_model_groupspriceconfig CREATE TABLE tx_epproducts_domain_model_groupspriceconfig
( (
uid int(11) NOT NULL auto_increment, uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL, pid int(11) DEFAULT '0' NOT NULL,
date_from int(11) unsigned DEFAULT '0' NOT NULL, date_from int(11) unsigned DEFAULT '0' NOT NULL,
date_to int(11) unsigned DEFAULT '0' NOT NULL, date_to int(11) unsigned DEFAULT '0' NOT NULL,
persons_included int(11) unsigned DEFAULT '0' NOT NULL, persons_included int(11) unsigned DEFAULT '0' NOT NULL,
price float(8) unsigned DEFAULT '0' NOT NULL, price float(8) unsigned DEFAULT '0' NOT NULL,
price_additional_person float(8) unsigned DEFAULT '0' NOT NULL, price_additional_person float(8) unsigned DEFAULT '0' NOT NULL,
hotel int(11) unsigned DEFAULT '0', price_additional_person_group_1 float(8) unsigned DEFAULT '0' NOT NULL,
price_additional_person_group_2 float(8) unsigned DEFAULT '0' NOT NULL,
price_additional_person_group_3 float(8) unsigned DEFAULT '0' NOT NULL,
bonus_card_included tinyint(4) unsigned DEFAULT '0' NOT NULL,
hotel int(11) unsigned DEFAULT '0',
tstamp int(11) unsigned DEFAULT '0' NOT NULL, tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL,
cruser_id int(11) unsigned DEFAULT '0' NOT NULL, cruser_id int(11) unsigned DEFAULT '0' NOT NULL,
deleted tinyint(4) unsigned DEFAULT '0' NOT NULL, deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
hidden tinyint(4) unsigned DEFAULT '0' NOT NULL, hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
starttime int(11) unsigned DEFAULT '0' NOT NULL, starttime int(11) unsigned DEFAULT '0' NOT NULL,
endtime int(11) unsigned DEFAULT '0' NOT NULL, endtime int(11) unsigned DEFAULT '0' NOT NULL,
t3ver_oid int(11) DEFAULT '0' NOT NULL, t3ver_oid int(11) DEFAULT '0' NOT NULL,
t3ver_id int(11) DEFAULT '0' NOT NULL, t3ver_id int(11) DEFAULT '0' NOT NULL,
t3ver_wsid int(11) DEFAULT '0' NOT NULL, t3ver_wsid int(11) DEFAULT '0' NOT NULL,
t3ver_label varchar(255) DEFAULT '' NOT NULL, t3ver_label varchar(255) DEFAULT '' NOT NULL,
t3ver_state tinyint(4) DEFAULT '0' NOT NULL, t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
t3ver_stage int(11) DEFAULT '0' NOT NULL, t3ver_stage int(11) DEFAULT '0' NOT NULL,
t3ver_count int(11) DEFAULT '0' NOT NULL, t3ver_count int(11) DEFAULT '0' NOT NULL,
t3ver_tstamp int(11) DEFAULT '0' NOT NULL, t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
t3ver_move_id int(11) DEFAULT '0' NOT NULL, t3ver_move_id int(11) DEFAULT '0' NOT NULL,
sys_language_uid int(11) DEFAULT '0' NOT NULL, sys_language_uid int(11) DEFAULT '0' NOT NULL,
l10n_parent int(11) DEFAULT '0' NOT NULL, l10n_parent int(11) DEFAULT '0' NOT NULL,
l10n_diffsource mediumblob, l10n_diffsource mediumblob,
PRIMARY KEY (uid), PRIMARY KEY (uid),
KEY parent (pid), KEY parent (pid),
@@ -6,7 +6,23 @@
</div> </div>
<div class="form-group" v-show="!submitted"> <div class="form-group" v-show="!submitted">
<label>Personenzahl</label> <label>Personenzahl</label>
<input type="number" class="form-control" v-model="selectedPax" @change="onPaxUpdated()"/> <input type="number" class="form-control" v-model.number="selectedPax" @change="onPaxUpdated()"
v-show="nightsCount > 0 && !includesBonusCard"/>
<div class="flex space-x-4" v-show="nightsCount > 0 && includesBonusCard">
<div class="w-1/3 flex flex-col space-y-1">
<span>ab 15 Jahre</span>
<input type="number" class="form-control" v-model.number="selectedPaxGroup3" @change="onPaxUpdated()"/>
</div>
<div class="w-1/3 flex flex-col space-y-1">
<span>7-14 Jahre</span>
<input type="number" class="form-control" v-model.number="selectedPaxGroup2" @change="onPaxUpdated()"/>
</div>
<div class="w-1/3 flex flex-col space-y-1">
<span>4-6 Jahre</span>
<input type="number" class="form-control" v-model.number="selectedPaxGroup1" @change="onPaxUpdated()"/>
</div>
</div>
<p class="text-sm italic" v-show="nightsCount === 0">Bitte wählen Sie einen Zeitraum</p>
</div> </div>
<div class="form-group" v-show="options.length > 0 && !submitted"> <div class="form-group" v-show="options.length > 0 && !submitted">
<label>Optionale Zusatzleistungen</label> <label>Optionale Zusatzleistungen</label>
@@ -22,7 +38,9 @@
<label>Optionale Verpflegungsleistungen</label> <label>Optionale Verpflegungsleistungen</label>
<select class="form-control" v-model="selectedBoard" v-if="selectedPax >= 30"> <select class="form-control" v-model="selectedBoard" v-if="selectedPax >= 30">
<option :value="null">Keine Auswahl</option> <option :value="null">Keine Auswahl</option>
<option v-for="board of boards" :value="board" :key="board.uid">{{ board.title }} ({{ formatCurrency(board.price) }} pro Person und Nacht)</option> <option v-for="board of boards" :value="board" :key="board.uid">{{ board.title }}
({{ formatCurrency(board.price) }} pro Person und Nacht)
</option>
</select> </select>
<div v-show="selectedPax < 30"> <div v-show="selectedPax < 30">
<span class="label label-warning">Erst ab 30 Personen buchbar.</span> <span class="label label-warning">Erst ab 30 Personen buchbar.</span>
@@ -33,38 +51,39 @@
<div class="panel-body"> <div class="panel-body">
<table class="table table-striped" v-show="nightsCount > 0"> <table class="table table-striped" v-show="nightsCount > 0">
<tbody> <tbody>
<tr> <tr>
<th>Zeitraum</th> <th>Zeitraum</th>
<td>{{ rangeFormatted }}, {{ nightsCount }} Nächte</td> <td>{{ rangeFormatted }}, {{ nightsCount }} Nächte</td>
</tr> </tr>
<tr> <tr>
<th>Basispreis</th> <th>Basispreis</th>
<td>{{ formatCurrency(pricePax.base) }}</td> <td>{{ formatCurrency(pricePax.base) }}</td>
</tr> </tr>
<tr v-if="pricePax.additional > 0"> <tr v-if="pricePax.additional > 0">
<th>Aufpreis Personenzahl</th> <th>Aufpreis Personenzahl</th>
<td>{{ formatCurrency(pricePax.additional) }}</td> <td>{{ formatCurrency(pricePax.additional) }}</td>
</tr> </tr>
<tr v-if="priceShortTerm > 0"> <tr v-if="priceShortTerm > 0">
<th>Aufpreis Kurzzeit</th> <th>Aufpreis Kurzzeit</th>
<td>{{ formatCurrency(priceShortTerm) }}</td> <td>{{ formatCurrency(priceShortTerm) }}</td>
</tr> </tr>
<tr v-if="selectedOptions.length > 0"> <tr v-if="selectedOptions.length > 0">
<th>Zusatzleistungen</th> <th>Zusatzleistungen</th>
<td>{{ formatCurrency(priceOptions) }}</td> <td>{{ formatCurrency(priceOptions) }}</td>
</tr> </tr>
<tr v-if="priceBoard > 0"> <tr v-if="priceBoard > 0">
<th>Verpflegung</th> <th>Verpflegung</th>
<td>{{ formatCurrency(priceBoard) }}</td> <td>{{ formatCurrency(priceBoard) }}</td>
</tr> </tr>
<tr v-if="priceRunningCosts > 0"> <tr v-if="priceRunningCosts > 0">
<th>Strom- und Abfallgebühren</th> <th>Strom- und Abfallgebühren</th>
<td>{{ formatCurrency(priceRunningCosts) }}</td> <td>{{ formatCurrency(priceRunningCosts) }}</td>
</tr> </tr>
<tr> <tr>
<th>Gesamtpreis</th> <th>Gesamtpreis</th>
<td><strong>{{ formatCurrency(priceTotal) }}</strong><br><small>zzgl. vor Ort zu entrichtender Ortstaxe</small></td> <td><strong>{{ formatCurrency(priceTotal) }}</strong><br><small>zzgl. vor Ort zu entrichtender
</tr> Ortstaxe</small></td>
</tr>
</tbody> </tbody>
</table> </table>
<div v-show="nightsCount === 0"> <div v-show="nightsCount === 0">
@@ -114,260 +133,304 @@
</template> </template>
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import dayjs from 'dayjs' import dayjs from 'dayjs'
import 'dayjs/locale/de' import 'dayjs/locale/de'
import 'flatpickr'; import 'flatpickr';
import { German } from 'flatpickr/dist/l10n/de'; import {German} from 'flatpickr/dist/l10n/de';
import Vue from 'vue'; import Vue from 'vue';
import axios from 'axios'; import axios from 'axios';
export default { export default {
props: { props: {
loaderUri: { loaderUri: {
type: String, type: String,
required: true required: true
},
endpoint: {
type: String,
required: true
},
configs: {
type: Array,
required: true
},
boards: {
type: Array,
required: true
},
options: {
type: Array,
required: true
}
}, },
data () { endpoint: {
return { type: String,
processing: false, required: true
submitted: false,
picker: null,
formErrors: {},
selectedFrom: null,
selectedTo: null,
selectedRange: [],
selectedPax: 30,
selectedOptions: [],
selectedBoard: null,
name: null,
email: null,
phone: null,
remarks: null
}
}, },
methods: { configs: {
formatCurrency (value) { type: Array,
if (0 === value) { required: true
return '-'; },
} boards: {
return parseFloat(value).toFixed(2).replace(/\./, ',') + ' €'; type: Array,
}, required: true
formatOptionPriceType (option) { },
if (2 === option.type) { options: {
return ' ('+this.formatCurrency(option.price)+' pro Person)'; type: Array,
} required: true
if (3 === option.type) { }
return ' ('+this.formatCurrency(option.price)+' pro Nacht)'; },
} data() {
if (4 === option.type) { return {
return ' ('+this.formatCurrency(option.price)+' pro Person und Nacht)'; processing: false,
} submitted: false,
picker: null,
formErrors: {},
selectedFrom: null,
selectedTo: null,
selectedRange: [],
selectedPax: 30,
selectedPaxGroup1: 0,
selectedPaxGroup2: 0,
selectedPaxGroup3: 30,
selectedOptions: [],
selectedBoard: null,
name: null,
email: null,
phone: null,
remarks: null
}
},
methods: {
formatCurrency(value) {
if (0 === value) {
return '-';
}
return parseFloat(value).toFixed(2).replace(/\./, ',') + ' €';
},
formatOptionPriceType(option) {
if (2 === option.type) {
return ' (' + this.formatCurrency(option.price) + ' pro Person)';
}
if (3 === option.type) {
return ' (' + this.formatCurrency(option.price) + ' pro Nacht)';
}
if (4 === option.type) {
return ' (' + this.formatCurrency(option.price) + ' pro Person und Nacht)';
}
return ' ('+this.formatCurrency(option.price)+')'; return ' (' + this.formatCurrency(option.price) + ')';
}, },
initSelectableRanges () { initSelectableRanges() {
let enabledDates = []; let enabledDates = [];
for (let config of this.configs) { for (let config of this.configs) {
const dateFrom = dayjs(config.dateFrom); const dateFrom = dayjs(config.dateFrom);
const dateTo = dayjs(config.dateTo); const dateTo = dayjs(config.dateTo);
enabledDates.push({ enabledDates.push({
from: dateFrom.format('DD.MM.YYYY'), from: dateFrom.format('DD.MM.YYYY'),
to: dateTo.format('DD.MM.YYYY') to: dateTo.format('DD.MM.YYYY')
});
}
this.picker.set('enable', enabledDates);
if (enabledDates.length > 0) {
const firstDate = enabledDates[0].from;
this.picker.set('minDate', firstDate);
}
},
updateSelectedRange () {
let range = [];
let currentDate = this.selectedFrom;
while (currentDate < this.selectedTo) {
range.push(currentDate);
currentDate = currentDate.add(1, 'day');
}
this.selectedRange = range;
},
onPaxUpdated () {
if (this.selectedPax < 30) {
this.selectedBoard = null;
}
},
submitForm () {
let options = [];
for (let option of this.selectedOptions) {
options.push(option.uid);
}
let formData = {
'tx_epproducts_ajax[groupsPriceInquiry][name]': this.name,
'tx_epproducts_ajax[groupsPriceInquiry][email]': this.email,
'tx_epproducts_ajax[groupsPriceInquiry][phone]': this.phone,
'tx_epproducts_ajax[groupsPriceInquiry][remarks]': this.remarks,
'tx_epproducts_ajax[groupsPriceInquiry][dateFrom]': this.selectedFrom.format('DD.MM.YYYY'),
'tx_epproducts_ajax[groupsPriceInquiry][dateTo]': this.selectedTo.format('DD.MM.YYYY'),
'tx_epproducts_ajax[groupsPriceInquiry][pax]': this.selectedPax,
'tx_epproducts_ajax[groupsPriceInquiry][board]': this.selectedBoard ? this.selectedBoard.uid : null,
'tx_epproducts_ajax[groupsPriceInquiry][options]': options,
'tx_epproducts_ajax[groupsPriceInquiry][summary]': this.priceSummary
};
this.processing = true;
this.submitted = false;
axios({
url: this.endpoint,
method: 'POST',
data: $.param(formData)
}).then(response => {
if ('validation' === response.data.status) {
this.formErrors = response.data.errors;
} else {
this.submitted = true;
}
}).catch(error => {
}).finally(() => {
this.processing = false;
}); });
} }
this.picker.set('enable', enabledDates);
if (enabledDates.length > 0) {
const firstDate = enabledDates[0].from;
this.picker.set('minDate', firstDate);
}
}, },
computed: { updateSelectedRange() {
nightsCount () { let range = [];
return this.selectedRange.length; let currentDate = this.selectedFrom;
}, while (currentDate < this.selectedTo) {
rangeFormatted () { range.push(currentDate);
if (null === this.selectedFrom || null === this.selectedTo) { currentDate = currentDate.add(1, 'day');
return '-'; }
this.selectedRange = range;
},
onPaxUpdated() {
if (this.selectedPax < 30) {
this.selectedBoard = null;
}
},
submitForm() {
let options = [];
for (let option of this.selectedOptions) {
options.push(option.uid);
}
let formData = {
'tx_epproducts_ajax[groupsPriceInquiry][name]': this.name,
'tx_epproducts_ajax[groupsPriceInquiry][email]': this.email,
'tx_epproducts_ajax[groupsPriceInquiry][phone]': this.phone,
'tx_epproducts_ajax[groupsPriceInquiry][remarks]': this.remarks,
'tx_epproducts_ajax[groupsPriceInquiry][dateFrom]': this.selectedFrom.format('DD.MM.YYYY'),
'tx_epproducts_ajax[groupsPriceInquiry][dateTo]': this.selectedTo.format('DD.MM.YYYY'),
'tx_epproducts_ajax[groupsPriceInquiry][pax]': this.includesBonusCard ? '' : this.selectedPax,
'tx_epproducts_ajax[groupsPriceInquiry][paxGroup1]': this.includesBonusCard ? this.selectedPaxGroup1 : '',
'tx_epproducts_ajax[groupsPriceInquiry][paxGroup2]': this.includesBonusCard ? this.selectedPaxGroup2 : '',
'tx_epproducts_ajax[groupsPriceInquiry][paxGroup3]': this.includesBonusCard ? this.selectedPaxGroup3 : '',
'tx_epproducts_ajax[groupsPriceInquiry][board]': this.selectedBoard ? this.selectedBoard.uid : null,
'tx_epproducts_ajax[groupsPriceInquiry][options]': options,
'tx_epproducts_ajax[groupsPriceInquiry][summary]': this.priceSummary
};
this.processing = true;
this.submitted = false;
axios({
url: this.endpoint,
method: 'POST',
data: $.param(formData)
}).then(response => {
if ('validation' === response.data.status) {
this.formErrors = response.data.errors;
} else {
this.submitted = true;
} }
}).catch(error => {
}).finally(() => {
this.processing = false;
});
}
},
computed: {
nightsCount() {
return this.selectedRange.length;
},
rangeFormatted() {
if (null === this.selectedFrom || null === this.selectedTo) {
return '-';
}
return this.selectedFrom.format('DD.MM.YYYY') + ' - ' + this.selectedTo.format('DD.MM.YYYY'); return this.selectedFrom.format('DD.MM.YYYY') + ' - ' + this.selectedTo.format('DD.MM.YYYY');
}, },
pricePax () { includesBonusCard() {
let base = 0; let included = false
let additional = 0; for (let date of this.selectedRange) {
for (let date of this.selectedRange) { for (let config of this.configs) {
for (let config of this.configs) { if (date >= dayjs(config.dateFrom) && date < dayjs(config.dateTo)) {
if (date >= dayjs(config.dateFrom) && date < dayjs(config.dateTo)) { if (config.bonusCardIncluded) {
base += config.price; included = true
if (this.selectedPax > config.personsIncluded) { }
}
}
}
return included
},
pricePax() {
let base = 0
let additional = 0
for (let date of this.selectedRange) {
for (let config of this.configs) {
if (date >= dayjs(config.dateFrom) && date < dayjs(config.dateTo)) {
base += config.price
if (this.totalPax > config.personsIncluded) {
if (false === config.bonusCardIncluded) {
additional += (this.selectedPax - config.personsIncluded) * config.priceAdditionalPerson; additional += (this.selectedPax - config.personsIncluded) * config.priceAdditionalPerson;
} else {
// Distribute additional persons costs by group
let included = config.personsIncluded
if (this.selectedPaxGroup3 <= included) {
included -= this.selectedPaxGroup3
} else {
additional += (this.selectedPaxGroup3 - included) * config.priceAdditionalPersonByGroup[3]
included = 0
}
if (this.selectedPaxGroup2 <= included) {
included -= this.selectedPaxGroup2
} else {
additional += (this.selectedPaxGroup2 - included) * config.priceAdditionalPersonByGroup[2]
included = 0
}
if (this.selectedPaxGroup1 > included) {
additional += (this.selectedPaxGroup1 - included) * config.priceAdditionalPersonByGroup[1]
}
} }
} }
} }
} }
return { base, additional }; }
}, return {base, additional};
priceOptions () { },
let price = 0; totalPax() {
for (let option of this.selectedOptions) { return this.includesBonusCard ? this.selectedPaxGroup1 + this.selectedPaxGroup2 + this.selectedPaxGroup3 : this.selectedPax
if (true === option.ignoreWithBoard && this.selectedBoard) { },
continue; priceOptions() {
} let price = 0;
if (1 === option.type) { for (let option of this.selectedOptions) {
price += option.price; if (true === option.ignoreWithBoard && this.selectedBoard) {
} else if (2 === option.type) { continue;
price += option.price * this.selectedPax;
} else if (3 === option.type) {
price += option.price * this.nightsCount;
} else if (4 === option.type) {
price += option.price * this.nightsCount * this.selectedPax;
}
} }
return price; if (1 === option.type) {
}, price += option.price;
priceBoard () { } else if (2 === option.type) {
let price = 0; price += option.price * this.totalPax;
if (this.selectedBoard) { } else if (3 === option.type) {
price = this.selectedBoard.price * this.nightsCount * this.selectedPax; price += option.price * this.nightsCount;
} } else if (4 === option.type) {
return price; price += option.price * this.nightsCount * this.totalPax;
},
priceShortTerm () {
let price = 0;
const totalPricePax = this.pricePax.base + this.pricePax.additional;
if (2 === this.nightsCount) {
price = totalPricePax * 0.2;
}
if (3 === this.nightsCount) {
price = totalPricePax * 0.1;
}
return price;
},
priceRunningCosts () {
if (this.selectedBoard) {
return 0;
}
return this.nightsCount * this.selectedPax * 1.7;
},
priceTotal () {
return this.pricePax.base + this.pricePax.additional + this.priceOptions
+ this.priceBoard + this.priceShortTerm + this.priceRunningCosts;
},
priceSummary () {
return {
paxBase: this.formatCurrency(this.pricePax.base),
paxAdditional: this.formatCurrency(this.pricePax.additional),
shortTerm: this.formatCurrency(this.priceShortTerm),
options: this.formatCurrency(this.priceOptions),
board: this.formatCurrency(this.priceBoard),
runningCosts: this.formatCurrency(this.priceRunningCosts),
total: this.formatCurrency(this.priceTotal)
} }
} }
return price;
}, },
mounted () { priceBoard() {
Vue.nextTick(() => { let price = 0;
this.picker = $(this.$refs.picker).flatpickr({ if (this.selectedBoard) {
mode: 'range', price = this.selectedBoard.price * this.nightsCount * this.totalPax;
dateFormat: 'd.m.Y', }
locale: German, return price;
onChange: selectedDates => { },
if (2 === selectedDates.length) { priceShortTerm() {
this.selectedFrom = dayjs(selectedDates[0]); let price = 0;
this.selectedTo = dayjs(selectedDates[1]); const totalPricePax = (this.pricePax.base + this.pricePax.additional);
this.updateSelectedRange(); if (2 === this.nightsCount) {
} price = totalPricePax * 0.2;
} }
}); if (3 === this.nightsCount) {
this.initSelectableRanges(); price = totalPricePax * 0.1;
}); }
return price;
},
priceRunningCosts() {
if (this.selectedBoard) {
return 0;
}
return this.nightsCount * this.selectedPax * 1.7;
},
priceTotal() {
return this.pricePax.base + this.pricePax.additional + this.priceOptions
+ this.priceBoard + this.priceShortTerm + this.priceRunningCosts;
},
priceSummary() {
return {
paxBase: this.formatCurrency(this.pricePax.base),
paxAdditional: this.formatCurrency(this.pricePax.additional),
shortTerm: this.formatCurrency(this.priceShortTerm),
options: this.formatCurrency(this.priceOptions),
board: this.formatCurrency(this.priceBoard),
runningCosts: this.formatCurrency(this.priceRunningCosts),
total: this.formatCurrency(this.priceTotal)
}
} }
},
mounted() {
Vue.nextTick(() => {
this.picker = $(this.$refs.picker).flatpickr({
mode: 'range',
dateFormat: 'd.m.Y',
locale: German,
onChange: selectedDates => {
if (2 === selectedDates.length) {
this.selectedFrom = dayjs(selectedDates[0]);
this.selectedTo = dayjs(selectedDates[1]);
this.updateSelectedRange();
}
}
});
this.initSelectableRanges();
});
} }
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.form-wrapper { .form-wrapper {
position: relative; position: relative;
} }
.form-control[readonly] {
background-color: white; .form-control[readonly] {
} background-color: white;
.form-overlay { }
position: fixed;
top: 0; .form-overlay {
left: 0; position: fixed;
width: 100%; top: 0;
height: 100%; left: 0;
display: flex; width: 100%;
align-items: center; height: 100%;
justify-content: center; display: flex;
background-color: rgba(white, 0.85); align-items: center;
} justify-content: center;
background-color: rgba(white, 0.85);
}
</style> </style>
@@ -29,7 +29,19 @@
</tr> </tr>
<tr> <tr>
<th>Anzahl der Personen</th> <th>Anzahl der Personen</th>
<td>{pax}</td> <td>{pax -> v:or(alternative: '-')}</td>
</tr>
<tr>
<th>Anzahl der Personen (ab 15 Jahre)</th>
<td>{paxGroup3 -> v:or(alternative: '-')}</td>
</tr>
<tr>
<th>Anzahl der Personen (7-14 Jahre)</th>
<td>{paxGroup2 -> v:or(alternative: '-')}</td>
</tr>
<tr>
<th>Anzahl der Personen (4-6 Jahre)</th>
<td>{paxGroup1 -> v:or(alternative: '-')}</td>
</tr> </tr>
<tr> <tr>
<th>Verpflegung</th> <th>Verpflegung</th>