Merge branch 'feature/teaser-for-non-bookable' into develop
This commit is contained in:
@@ -40,6 +40,11 @@ class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements
|
||||
*/
|
||||
protected $bookable = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hideBookingButton = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -302,6 +307,22 @@ class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements
|
||||
$this->bookable = (bool) $bookable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getHideBookingButton()
|
||||
{
|
||||
return $this->hideBookingButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $hideBookingButton
|
||||
*/
|
||||
public function setHideBookingButton($hideBookingButton)
|
||||
{
|
||||
$this->hideBookingButton = (bool) $hideBookingButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -100,7 +100,7 @@ class ProductRepository extends AbstractRepository
|
||||
'date.board as board', 'date.product_fact as productFact', 'date.hotel_fact as hotelFact',
|
||||
'date.region_fact as regionFact', 'date.services_included as servicesIncluded',
|
||||
'date.min_price as minPrice', 'date.nights as nights', 'date.available as available',
|
||||
'date.pseudo_price as pseudoPrice'
|
||||
'date.pseudo_price as pseudoPrice', 'date.hide_booking_button as hideBookingButton'
|
||||
)
|
||||
->from('tx_epproducts_domain_model_date', 'date')
|
||||
->leftJoin('date', 'tx_epproducts_domain_model_room', 'room', 'room.date = date.uid')
|
||||
@@ -154,8 +154,8 @@ class ProductRepository extends AbstractRepository
|
||||
'date_start as dateStart', 'date_end as dateEnd', 'uid as dateUid', 'min_price as minPrice',
|
||||
'pseudo_price as pseudoPrice', 'nights as nights', 'available as available',
|
||||
'skipass_included as skipassIncluded', 'bus_included as busIncluded',
|
||||
'earlybird', 'new', 'daytrip', 'low_contingent as lowContingent',
|
||||
'concept_code as conceptCode', 'concept_name as conceptName',
|
||||
'earlybird', 'new', 'daytrip', 'hide_booking_button as hideBookingButton',
|
||||
'low_contingent as lowContingent', 'concept_code as conceptCode', 'concept_name as conceptName',
|
||||
'board'
|
||||
)
|
||||
->from('tx_epproducts_domain_model_date', 'date')
|
||||
|
||||
@@ -232,7 +232,7 @@ class DateImportService implements SingletonInterface
|
||||
$dateCount = 0;
|
||||
|
||||
$sql = '
|
||||
SELECT p.uid uid, p.daytrip daytrip, p.important important, p.name product_name,
|
||||
SELECT p.uid uid, p.daytrip daytrip, p.hide_booking_button, p.important important, p.name product_name,
|
||||
p.searchable product_searchable, p.detail_page product_detail_page, p.keywords product_keywords,
|
||||
p.teaser product_teaser, p.feature product_feature, p.subline product_subline, p.country country,
|
||||
p.region region, p.city city, p.path_segment slug,
|
||||
@@ -365,6 +365,7 @@ class DateImportService implements SingletonInterface
|
||||
'bus_pro_id' => $busProId,
|
||||
'code' => $code,
|
||||
'daytrip' => $product['daytrip'],
|
||||
'hide_booking_button' => $product['hide_booking_button'],
|
||||
'important' => $product['important'],
|
||||
];
|
||||
|
||||
@@ -619,7 +620,7 @@ class DateImportService implements SingletonInterface
|
||||
foreach ($section as $service)
|
||||
{
|
||||
if ($service['price'] < 0) {
|
||||
return $service['price'];
|
||||
return (int) $service['price'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -724,8 +725,8 @@ class DateImportService implements SingletonInterface
|
||||
foreach ($services['BUS'] as $service)
|
||||
{
|
||||
$date['bus_available'] = 1;
|
||||
$date['bus_price'] = $service['price'];
|
||||
$date['bus_included'] = ((int) $service['price'] === 0);
|
||||
$date['bus_price'] = (int) $service['price'];
|
||||
$date['bus_included'] = (int) ((int) $service['price'] === 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ class DateService implements SingletonInterface
|
||||
'template' => $template,
|
||||
'paCode' => $paCode,
|
||||
'isDayTrip' => $product->isDaytrip(),
|
||||
'isHideBookingButton' => $product->getHideBookingButton(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -148,6 +149,7 @@ class DateService implements SingletonInterface
|
||||
'template' => $template,
|
||||
'paCode' => $paCode,
|
||||
'isDayTrip' => $product->isDaytrip(),
|
||||
'isHideBookingButton' => $product->getHideBookingButton(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -259,9 +261,10 @@ class DateService implements SingletonInterface
|
||||
public function preprocessPriceTable(array $options)
|
||||
{
|
||||
$resolver = new OptionsResolver();
|
||||
$resolver->setDefined('paCode');
|
||||
$resolver->setDefined(['paCode', 'isDayTrip', 'isHideBookingButton']);
|
||||
$resolver->setRequired(['priceTableData', 'template']);
|
||||
$resolver->setDefault('isDayTrip', false);
|
||||
$resolver->setDefault('isHideBookingButton', false);
|
||||
$resolvedOptions = $resolver->resolve($options);
|
||||
$priceTable = [];
|
||||
|
||||
@@ -269,6 +272,7 @@ class DateService implements SingletonInterface
|
||||
$template = $resolvedOptions['template'];
|
||||
$paCode = $resolvedOptions['paCode'];
|
||||
$isDayTrip = $resolvedOptions['isDayTrip'];
|
||||
$isHideBookingButton = $resolvedOptions['isHideBookingButton'];
|
||||
|
||||
foreach ($priceTableData as $row)
|
||||
{
|
||||
@@ -299,6 +303,7 @@ class DateService implements SingletonInterface
|
||||
'hotelBusProId' => $row['hotelBusProId'],
|
||||
'roomBusProId' => $row['roomBusProId'],
|
||||
'bookingUrl' => $bookingUrl,
|
||||
'isHideBookingButton' => $isHideBookingButton,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -312,9 +317,10 @@ class DateService implements SingletonInterface
|
||||
public function preprocessDateTable(array $options)
|
||||
{
|
||||
$resolver = new OptionsResolver();
|
||||
$resolver->setDefined('paCode');
|
||||
$resolver->setDefined(['paCode', 'isDayTrip', 'isHideBookingButton']);
|
||||
$resolver->setRequired(['dateTableData', 'template']);
|
||||
$resolver->setDefault('isDayTrip', false);
|
||||
$resolver->setDefault('isHideBookingButton', false);
|
||||
$resolvedOptions = $resolver->resolve($options);
|
||||
|
||||
$dateTable = [];
|
||||
@@ -323,6 +329,7 @@ class DateService implements SingletonInterface
|
||||
$template = $resolvedOptions['template'];
|
||||
$paCode = $resolvedOptions['paCode'];
|
||||
$isDayTrip = $resolvedOptions['isDayTrip'];
|
||||
$isHideBookingButton = $resolvedOptions['isHideBookingButton'];
|
||||
|
||||
foreach ($dateTableData as $row)
|
||||
{
|
||||
@@ -351,6 +358,7 @@ class DateService implements SingletonInterface
|
||||
'dateServicesGeneral' => unserialize($row['dateServicesGeneral'], ['allowed_classes' => false]),
|
||||
'available' => $row['available'],
|
||||
'bookingUrl' => $bookingUrl,
|
||||
'isHideBookingButton' => $isHideBookingButton,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ class ProductDataService implements SingletonInterface
|
||||
'earlybird' => $teaserData['earlybird'],
|
||||
'new' => $teaserData['new'],
|
||||
'daytrip' => $teaserData['daytrip'],
|
||||
'hideBookingButton' => $teaserData['hideBookingButton'],
|
||||
'lowContingent' => $teaserData['lowContingent'],
|
||||
'servicesIncluded' => unserialize($teaserData['servicesIncluded']),
|
||||
'product' => [
|
||||
|
||||
@@ -107,8 +107,7 @@ class SearchResultService implements SingletonInterface
|
||||
// Use compound key, hotel is not unique
|
||||
$key = $row['hotelUid'] . ':' . $row['productUid'];
|
||||
|
||||
$hotelCategory = array_key_exists($row['hotelCategory'], Hotel::$categoryLabels) ?
|
||||
Hotel::$categoryLabels[$row['hotelCategory']] : null;
|
||||
$hotelCategory = Hotel::$categoryLabels[$row['hotelCategory']] ?? null;
|
||||
|
||||
if (!array_key_exists($key, $items)) {
|
||||
$items[$key] = [
|
||||
@@ -119,6 +118,7 @@ class SearchResultService implements SingletonInterface
|
||||
'detailPageUri' => null,
|
||||
'earlybird' => $row['earlybird'],
|
||||
'daytrip' => $row['daytrip'],
|
||||
'hideBookingButton' => $row['hideBookingButton'],
|
||||
'lowContingent' => $row['lowContingent'],
|
||||
'servicesIncluded' => unserialize($row['servicesIncluded']),
|
||||
'hotel' => [
|
||||
|
||||
+11
-3
@@ -28,7 +28,8 @@ return [
|
||||
concept_description, board_description, additional_services, programme_description, ski_pass_description,
|
||||
rating_average, rating_votes_count, teaser_images, header_images, images, concept, country, region, city,
|
||||
journey, facts, officetip, hotels, calendar_hotel, faqs,header_title,header_subtitle, alt_product, alt_label,
|
||||
video, banner, additional_regions, badge, daytrip, testimonials, external_link, path_segment',
|
||||
video, banner, additional_regions, badge, daytrip, testimonials, external_link, path_segment,
|
||||
hide_booking_button',
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
@@ -44,8 +45,8 @@ return [
|
||||
],
|
||||
'palettes' => [
|
||||
'destinations' => ['showitem' => 'country,region,city'],
|
||||
'top' => ['showitem' => 'searchable, bookable, daytrip, important, skipass_included, detail_page,
|
||||
external_link, path_segment'],
|
||||
'top' => ['showitem' => 'searchable, bookable, hide_booking_button, daytrip, important, skipass_included,
|
||||
detail_page, external_link, path_segment'],
|
||||
'name' => ['showitem' => 'name,code'],
|
||||
'alternative' => ['showitem' => 'alt_product, alt_label'],
|
||||
'header' => ['showitem' => 'headline,subline,--linebreak--,header_title,header_subtitle'],
|
||||
@@ -155,6 +156,13 @@ return [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'hide_booking_button' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Buchungsbutton verstecken',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'daytrip' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'tageweise buchbar',
|
||||
|
||||
@@ -10,6 +10,7 @@ CREATE TABLE tx_epproducts_domain_model_product
|
||||
|
||||
searchable tinyint(4) unsigned DEFAULT '1' NOT NULL,
|
||||
bookable tinyint(4) unsigned DEFAULT '1' NOT NULL,
|
||||
hide_booking_button tinyint(4) unsigned DEFAULT '0' NOT NULL,
|
||||
daytrip tinyint(4) unsigned DEFAULT '0' NOT NULL,
|
||||
important tinyint(4) unsigned DEFAULT '0' NOT NULL,
|
||||
skipass_included tinyint(4) unsigned DEFAULT '1' NOT NULL,
|
||||
@@ -119,6 +120,7 @@ CREATE TABLE tx_epproducts_domain_model_date
|
||||
available int(11) DEFAULT '0' NOT NULL,
|
||||
product int(11) unsigned DEFAULT '0',
|
||||
daytrip tinyint(1) unsigned DEFAULT '0' NOT NULL,
|
||||
hide_booking_button tinyint(1) unsigned DEFAULT '0' NOT NULL,
|
||||
important tinyint(1) unsigned DEFAULT '0' NOT NULL,
|
||||
product_name varchar(255) DEFAULT '' NOT NULL,
|
||||
product_subline varchar(255) DEFAULT '' NOT NULL,
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<tbody>
|
||||
<tr v-for="(row, index) of datesRows" :class="{ 'hidden': index > 4 && !showAll }">
|
||||
<td class="dates-table__cell dates-table__cell--date">
|
||||
<template v-if="bookable && row.available">
|
||||
<template v-if="bookable && row.available && !row.isHideBookingButton">
|
||||
<a class="dates-table__date" href="#"
|
||||
@click.prevent="loadPriceTable(row.dateUid)">
|
||||
{{ row.dateStart }} - {{ row.dateEnd }}
|
||||
@@ -71,9 +71,9 @@
|
||||
class="hidden-sm hidden-md hidden-lg"><i class="fa fa-info-circle"></i></a>
|
||||
</td>
|
||||
<td class="dates-table__cell dates-table__cell--buttons hidden-xs">
|
||||
<button v-if="row.available" class="button button--small" @click="loadPriceTable(row.dateUid)">Details</button>
|
||||
<a :href="row.bookingUrl" target="_blank" v-if="row.available" class="button button--small button--action">Buchen</a>
|
||||
<span v-if="!row.available" class="label label-default">ausgebucht</span>
|
||||
<button v-if="row.available || row.isHideBookingButton" class="button button--small" @click="loadPriceTable(row.dateUid)">Details</button>
|
||||
<a :href="row.bookingUrl" target="_blank" v-if="row.available && !row.isHideBookingButton" class="button button--small button--action">Buchen</a>
|
||||
<span v-if="!row.available && !row.isHideBookingButton" class="label label-default">ausgebucht</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -83,7 +83,7 @@
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<a href="#" v-if="datesRows.length > 5" @click.prevent="toggleAllDates()">
|
||||
<i class="fa" :class="[{ 'fa-minus-circle': showAll }, { 'fa-plus-circle': !showAll }]"></i>
|
||||
Alle Termine <template v-if="showAll">aus</template><template v-else>ein</template>blenden
|
||||
<template v-if="showAll">Weniger Termine anzeigen</template><template v-else>Alle Termine anzeigen</template>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<td style="white-space: normal">
|
||||
<a class="pricetable__room-label"
|
||||
:href="row.bookingUrl" target="_blank">{{ row.roomName }}</a>
|
||||
<div class="hidden-lg" v-if="row.roomAvailable">
|
||||
<div class="hidden-lg" v-if="row.roomAvailable && !row.isHideBookingButton">
|
||||
<a class="button button--small button--action"
|
||||
:href="row.bookingUrl" target="_blank">Jetzt buchen</a>
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@
|
||||
<span class="label label-default">ausgebucht</span>
|
||||
</div>
|
||||
</td>
|
||||
<td style="white-space: nowrap" :style="{'text-decoration': !row.roomAvailable ? 'line-through' : ''}">{{ calculatePrice(row) }} €</td>
|
||||
<td style="white-space: nowrap" :style="{'text-decoration': !row.roomAvailable && !row.isHideBookingButton ? 'line-through' : ''}">{{ calculatePrice(row) }} €</td>
|
||||
<td>
|
||||
<i v-if="showBusIcon(row)" data-placement="top" title="Busfahrt inklusive" class="fa fa-bus tooltiptoggle"></i>
|
||||
<i v-if="row.dateSkipassIncluded" data-placement="top" title="Skipass inklusive" class="fa fa-tag tooltiptoggle"></i>
|
||||
@@ -75,9 +75,9 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="hidden-xs hidden-md">
|
||||
<a class="button button--small button--action" v-if="row.roomAvailable"
|
||||
<a class="button button--small button--action" v-if="row.roomAvailable && !row.isHideBookingButton"
|
||||
:href="row.bookingUrl" target="_blank">Buchen</a>
|
||||
<span v-if="!row.roomAvailable" class="label label-default">ausgebucht</span>
|
||||
<span v-if="!row.roomAvailable && !row.isHideBookingButton" class="label label-default">ausgebucht</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@
|
||||
<div class="teaserbox__aside__bottom">
|
||||
<span class="searchresult-item__price">ab {{ item.minPrice }} €</span>
|
||||
<a :href="url" class="button button--full searchresult-item__button"
|
||||
rel="nofollow" title="Details & Buchen">
|
||||
Details & Buchen
|
||||
rel="nofollow" title="Details">
|
||||
Details<template v-if="!item.hideBookingButton"> & Buchen</template>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
<trans-unit id="tx_eptheme.label.teaserbutton.product">
|
||||
<target>Details & Buchen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.label.teaserbutton.product_no_booking">
|
||||
<target>Details</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme_domain_model_lineup">
|
||||
<target>Lineup</target>
|
||||
</trans-unit>
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
<trans-unit id="tx_eptheme.label.teaserbutton.product">
|
||||
<source>Details & Buchen</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.label.teaserbutton.product_no_booking">
|
||||
<source>Details</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme_domain_model_lineup">
|
||||
<source>Lineup</source>
|
||||
</trans-unit>
|
||||
|
||||
@@ -86,7 +86,12 @@
|
||||
<div class="teaserbox__back">
|
||||
{teaser.product.teaser -> f:format.html()}
|
||||
</div>
|
||||
<button class="button button--full teaserbox__button" title="{teaser.product.name}">{f:translate(key: 'tx_eptheme.label.teaserbutton.product', extensionName: 'ep_theme')}</button>
|
||||
<button class="button button--full teaserbox__button" title="{teaser.product.name}">
|
||||
<f:if condition="{teaser.hideBookingButton}">
|
||||
<f:then>{f:translate(key: 'tx_eptheme.label.teaserbutton.product', extensionName: 'ep_theme')}</f:then>
|
||||
<f:else>{f:translate(key: 'tx_eptheme.label.teaserbutton.product_no_booking', extensionName: 'ep_theme')}</f:else>
|
||||
</f:if>
|
||||
</button>
|
||||
</div>
|
||||
</f:section>
|
||||
|
||||
|
||||
@@ -94,7 +94,12 @@
|
||||
</div>
|
||||
<div class="teaserbox__aside__bottom">
|
||||
<span class="searchresult-item__price">ab {teaser.minPrice} €{f:if(condition: teaser.pseudoPrice, then: ' <s class="searchresult-item__pseudo-price">{teaser.pseudoPrice} €</s>')}</span>
|
||||
<a href="{teaserUrl}" title="{teaser.product.name}" class="button button--full searchresult-item__button">Details & Buchen</a>
|
||||
<a href="{teaserUrl}" title="{teaser.product.name}" class="button button--full searchresult-item__button">
|
||||
<f:if condition="{teaser.hideBookingButton}">
|
||||
<f:then>{f:translate(key: 'tx_eptheme.label.teaserbutton.product', extensionName: 'ep_theme')}</f:then>
|
||||
<f:else>{f:translate(key: 'tx_eptheme.label.teaserbutton.product_no_booking', extensionName: 'ep_theme')}</f:else>
|
||||
</f:if>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<watchlist-toggle uid="{teaser.key}" class="teaserbox-watchlist"></watchlist-toggle>
|
||||
|
||||
Reference in New Issue
Block a user