Merge branch 'Qloapps:develop' into gli-3244

This commit is contained in:
Shazar Rahman
2026-10-19 15:49:34 +05:30
committed by GitHub
155 changed files with 2031 additions and 1194 deletions

View File

@@ -478,11 +478,13 @@ $(document).ready(function() {
$('.no-htl-access-option').on('click', function() {
$(this).prop('selected', false);
});
initTooltip();
initUITooltip();
}); //end dom ready
function initTooltip($target, contentFn, items) {
var $elements = $target || $('.tooltip-trigger');
function initUITooltip($target, contentFn, items) {
var $elements = $target || $('.ui-tooltip-trigger');
if (!$elements.length) {
return;
}
@@ -491,11 +493,11 @@ function initTooltip($target, contentFn, items) {
if (!contentFn && $this.data('ui-tooltip')) {
return;
}
$this.tooltip({
$this.uiTooltip({
content: contentFn || $this.next('.tooltip-content').html(),
items: items || 'span',
trigger: 'hover',
tooltipClass: 'tooltip-popup',
tooltipClass: 'ui-tooltip-popup',
open: function (event, ui) {
if (event.buttons == 1 || event.buttons == 3) {
ui.tooltip.remove();

View File

@@ -1,57 +1,44 @@
.tooltip_cont
width: 100%
font-size: 14px
font-weight: 600
.tip_header
margin-bottom: 10px
.tip-body > div
margin-bottom: 6px
margin-right: 10px
.tip_element_head
font-size: 12px
.tip_element_value
font-size: 14px
font-weight: 400
opacity: 0.8
.tip-body
display: grid
grid-template-columns: auto auto
&.tip-body-grid
grid-template-columns: 1fr 1fr
gap: 8px 16px
.ui-tooltip,
.ui-tooltip.ui-widget-content
.ui-tooltip.ui-tooltip-popup
border: none
padding: 10px
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.15)
width: auto
.tooltip-trigger
.ui-tooltip-trigger
cursor: pointer
display: inline-block
vertical-align: middle
.ui-tooltip-content
width: 100%
.ui-tooltip-wrapper
width: 100%
font-size: 14px
font-weight: 600
.ui-tooltip.tooltip-popup
ul
margin: 0
padding: 0 0 0 16px
list-style: disc
li
padding: 2px 0
.ui-tooltip-header
margin-bottom: 5px
.tooltip-popup-row
display: flex
justify-content: space-between
align-items: center
gap: 12px
margin: 3px 0
white-space: nowrap
label
font-weight: 600
margin: 0
.ui-tooltip-body
> div
margin-bottom: 6px
margin-right: 10px
&.ui-tooltip-body-grid
display: grid
grid-template-columns: auto auto
grid-template-columns: 1fr 1fr
gap: 8px 2px
.ui-tooltip-elem-head
font-size: 12px
.ui-tooltip-elem-txt
font-size: 13px
font-weight: 400
opacity: 0.8
.ui-tooltip-label
font-weight: 600
margin: 0

View File

@@ -220,39 +220,37 @@
</div>
{/if}
{if $hotels.unselected|@count + $hotels.selected|@count > 1}
<p class="checkbox">
<label>
<input type="checkbox" id="hotel_restriction" name="hotel_restriction" value="1" {if $hotels.unselected|@count}checked="checked"{/if} />
{l s='Hotel selection'}
</label>
</p>
<div id="hotel_restriction_div">
<br />
<table class="table">
<tr>
<td>
<p>{l s='Unselected hotels'}</p>
<select id="hotel_select_1" class="input-large" multiple>
{foreach from=$hotels.unselected item='hotel'}
<option value="{$hotel.id_hotel|intval}">&nbsp;{$hotel.hotel_name|escape}</option>
{/foreach}
</select>
<a id="hotel_select_add" class="btn btn-default btn-block clearfix" >{l s='Add'} <i class="icon-arrow-right"></i></a>
</td>
<td>
<p>{l s='Selected hotels'}</p>
<select name="hotel_select[]" class="input-large" id="hotel_select_2" multiple>
{foreach from=$hotels.selected item='hotel'}
<option value="{$hotel.id_hotel|intval}">&nbsp;{$hotel.hotel_name|escape}</option>
{/foreach}
</select>
<a id="hotel_select_remove" class="btn btn-default btn-block clearfix" ><i class="icon-arrow-left"></i> {l s='Remove'}</a>
</td>
</tr>
</table>
</div>
{/if}
<p class="checkbox">
<label>
<input type="checkbox" id="hotel_restriction" name="hotel_restriction" value="1" {if $hotels.unselected|@count}checked="checked"{/if} />
{l s='Property selection'}
</label>
</p>
<div id="hotel_restriction_div">
<br />
<table class="table">
<tr>
<td>
<p>{l s='Unselected Properties'}</p>
<select id="hotel_select_1" class="input-large" multiple>
{foreach from=$hotels.unselected item='hotel'}
<option value="{$hotel.id_hotel|intval}">&nbsp;{$hotel.hotel_name|escape}</option>
{/foreach}
</select>
<a id="hotel_select_add" class="btn btn-default btn-block clearfix" >{l s='Add'} <i class="icon-arrow-right"></i></a>
</td>
<td>
<p>{l s='Selected Properties'}</p>
<select name="hotel_select[]" class="input-large" id="hotel_select_2" multiple>
{foreach from=$hotels.selected item='hotel'}
<option value="{$hotel.id_hotel|intval}">&nbsp;{$hotel.hotel_name|escape}</option>
{/foreach}
</select>
<a id="hotel_select_remove" class="btn btn-default btn-block clearfix" ><i class="icon-arrow-left"></i> {l s='Remove'}</a>
</td>
</tr>
</table>
</div>
{if $cart_rules.unselected|@count + $cart_rules.selected|@count > 0}
<p class="checkbox">

View File

@@ -24,17 +24,17 @@
<span>{$hotel_names_first|escape:'html':'UTF-8'}</span>
{if $hotel_names_remaining}
{capture name='hotel_names_tooltip'}
<div class="tooltip_cont">
<div class="tip_header"><div class="tip_date">{l s='Selected Hotels'}</div></div>
<div class="ui-tooltip-wrapper">
<div class="ui-tooltip-header"><div class="ui-tooltip-label">{l s='Selected Hotels'}</div></div>
<ul>
{foreach from=$selected_hotels item='hotel'}
<li class="tip_element_value">{$hotel|escape:'html':'UTF-8'}</li>
<li class="ui-tooltip-elem-txt">{$hotel|escape:'html':'UTF-8'}</li>
{/foreach}
</ul>
</div>
{/capture}
{capture name='hotel_names_tooltip_title'}<span class="badge tooltip-trigger">+{$hotel_names_remaining|@count}</span>{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.hotel_names_tooltip tooltip_title=$smarty.capture.hotel_names_tooltip_title}
{capture name='hotel_names_tooltip_title'}<span class="badge ui-tooltip-trigger">+{$hotel_names_remaining|@count}</span>{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.hotel_names_tooltip tooltip_title=$smarty.capture.hotel_names_tooltip_title}
{/if}
{else}
--

View File

@@ -190,6 +190,12 @@
<td colspan="7">{l s='Total cost:'}</td>
<td class="text-right">{displayWtPriceWithCurrency price=$total_products currency=$currency}</td>
</tr>
{if $total_tourism_tax > 0}
<tr>
<td colspan="7">{l s='Tourism tax:'}</td>
<td class="text-right">{displayWtPriceWithCurrency price=$total_tourism_tax currency=$currency}</td>
</tr>
{/if}
{if $total_discounts != 0}
<tr>
<td colspan="7">{l s='Total value of vouchers:'}</td>

View File

@@ -28,7 +28,7 @@
{if is_array($title)}
{$title|end|strip_tags}
{else}
<span title="{$title}">
<span title="{$title|strip_tags|escape:'html':'UTF-8'}">
{$title|strip_tags|truncate:40}
</span>
{/if}

View File

@@ -100,8 +100,12 @@
var len = values.length;
list.find('option').prop('selected', false);
for (var i = 0; i < len; i++)
list.find('option[value="' + $.trim(values[i]) + '"]').prop('selected', true);
for (var i = 0; i < len; i++) {
var value = $.trim(values[i]);
list.find('option').filter(function() {
return this.value === value;
}).prop('selected', true);
}
}
function position_exception_listchange() {
var obj = $(this);

View File

@@ -69,21 +69,21 @@
<td>
<span>{displayPrice price=($product.total_price_tax_incl - $product.total_price_tax_excl) currency=$currency->id}</span>
{if isset($use_tourism_tax) && $use_tourism_tax && isset($product.tourism_tax_status)}
<span class="price_info">
&nbsp;<img src="{$info_icon_path|escape:'htmlall':'UTF-8'}" />
</span>
<div class="price_info_container" style="display: none;">
<div>
<label>{l s='Service Tax:'}</label>
<span class="pull-right">{displayPrice price=$product.total_service_tax_only currency=$currency->id}</span>
{capture name='service_tax_tooltip_content'}
<div class="ui-tooltip-body">
<div class="ui-tooltip-service-tax-row">
<label class="ui-tooltip-label">{l s='Service Tax:'}</label>
<span class="ui-tooltip-elem-txt">{displayPrice price=$product.total_service_tax_only currency=$currency->id}</span>
</div>
{if $product.tourism_tax_total > 0}
<div class="ui-tooltip-tourism-tax-row">
<label class="ui-tooltip-label">{l s='Tourism Tax:'}</label>
<span class="ui-tooltip-elem-txt">{displayPrice price=$product.tourism_tax_total currency=$currency->id}</span>
</div>
{/if}
</div>
{if $product.tourism_tax_total > 0}
<div>
<label>{l s='Tourism Tax:'}</label>
<span class="pull-right">{displayPrice price=$product.tourism_tax_total currency=$currency->id}</span>
</div>
{/if}
</div>
{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.service_tax_tooltip_content}
{/if}
</td>
<td>

View File

@@ -95,7 +95,7 @@
<p class="help-block">{convertPriceWithCurrency price=$data['paid_unit_price_tax_excl'] currency=$currency->id}/{l s='day'}</p>
</td>
<td class="center">
<td class="center text-nowrap">
{convertPriceWithCurrency price=($data['additional_services_price_te'] + $data['convenience_fee_te'] + $data['additional_services_price_auto_add_te']) currency=$currency->id}
{if $data['additional_services']|count}
<a class="open_room_extra_services" href="#" date_from="{$data['date_from']}" date_to="{$data['date_to']}" id_product="{$data['id_product']}" id_room="{$data['id_room']}" id_order="{$order->id}" id_htl_booking="{$data['id']}">
@@ -103,23 +103,23 @@
</a>
{/if}
</td>
<td class="center">
<td class="center text-nowrap">
{convertPriceWithCurrency price=($data['total_room_tax']) currency=$currency->id}
<span class="price_info">
&nbsp;<img src="{$info_icon_path|escape:'htmlall':'UTF-8'}" />
</span>
<div class="price_info_container" style="display: none;">
<div>
<label>{l s='Room & Service Tax:'}</label>
<span class="pull-right">{convertPriceWithCurrency price=$data.total_room_service_tax_only currency=$currency->id}</span>
{capture name='room_tax_tooltip_content'}
<div class="ui-tooltip-body">
<div class="ui-tooltip-service-tax-row">
<label class="ui-tooltip-label">{l s='Room & Service Tax:'}</label>
<span class="ui-tooltip-elem-txt">{convertPriceWithCurrency price=$data.total_room_service_tax_only currency=$currency->id}</span>
</div>
{if isset($data.tourism_tax_total) && $data.tourism_tax_total > 0}
<div>
<label>{l s='Tourism Tax:'}</label>
<span class="pull-right">{convertPriceWithCurrency price=$data.tourism_tax_total currency=$currency->id}</span>
<div class="ui-tooltip-tourism-tax-row">
<label class="ui-tooltip-label">{l s='Tourism Tax:'}</label>
<span class="ui-tooltip-elem-txt">{convertPriceWithCurrency price=$data.tourism_tax_total currency=$currency->id}</span>
</div>
{/if}
</div>
{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_tax_tooltip_content}
</td>
<td class="center">
{convertPriceWithCurrency price=($data['total_room_price_ti']) currency=$currency->id}

View File

@@ -69,21 +69,21 @@
<td>
<span>{displayPrice price=($product.total_price_tax_incl - $product.total_price_tax_excl) currency=$currency->id}</span>
{if isset($use_tourism_tax) && $use_tourism_tax && isset($product.tourism_tax_status)}
<span class="price_info">
&nbsp;<img src="{$info_icon_path|escape:'htmlall':'UTF-8'}" />
</span>
<div class="price_info_container" style="display: none;">
<div>
<label>{l s='Service Tax:'}</label>
<span class="pull-right">{displayPrice price=$product.total_service_tax_only currency=$currency->id}</span>
{capture name='service_tax_tooltip_content'}
<div class="ui-tooltip-body">
<div class="ui-tooltip-service-tax-row">
<label class="ui-tooltip-label">{l s='Service Tax:'}</label>
<span class="ui-tooltip-elem-txt">{displayPrice price=$product.total_service_tax_only currency=$currency->id}</span>
</div>
{if $product.tourism_tax_total > 0}
<div class="ui-tooltip-tourism-tax-row">
<label class="ui-tooltip-label">{l s='Tourism Tax:'}</label>
<span class="ui-tooltip-elem-txt">{displayPrice price=$product.tourism_tax_total currency=$currency->id}</span>
</div>
{/if}
</div>
{if $product.tourism_tax_total > 0}
<div>
<label>{l s='Tourism Tax:'}</label>
<span class="pull-right">{displayPrice price=$product.tourism_tax_total currency=$currency->id}</span>
</div>
{/if}
</div>
{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.service_tax_tooltip_content}
{/if}
</td>
<td>

View File

@@ -21,27 +21,27 @@
*}
{capture name='stay_periods_tooltip'}
<div class="bootstrap tooltip_cont">
<div class="tip_header">
<div>{l s='Stay Periods'}</div>
<div class="bootstrap ui-tooltip-wrapper">
<div class="ui-tooltip-header">
<div class="ui-tooltip-label">{l s='Stay Periods'}</div>
</div>
<table class="table">
<thead>
<tr>
<th class="tip_element_head">{l s='Duration'}</th>
<th class="tip_element_head">{l s='Rooms'}</th>
<th class="ui-tooltip-elem-head">{l s='Duration'}</th>
<th class="ui-tooltip-elem-head">{l s='Rooms'}</th>
</tr>
</thead>
<tbody>
{foreach from=$stay_periods item=stay_period}
<tr>
<td class="tip_element_value">{$stay_period.from} &ndash; {$stay_period.to}</td>
<td class="tip_element_value center">{$stay_period.count}</td>
<td class="ui-tooltip-elem-txt">{$stay_period.from} &ndash; {$stay_period.to}</td>
<td class="ui-tooltip-elem-txt center">{$stay_period.count}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{/capture}
{capture name='stay_periods_tooltip_title'}<span class="badge tooltip-trigger">+{$extra_stay_periods_count}</span>{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.stay_periods_tooltip tooltip_title=$smarty.capture.stay_periods_tooltip_title}
{capture name='stay_periods_tooltip_title'}<span class="badge ui-tooltip-trigger">+{$extra_stay_periods_count}</span>{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.stay_periods_tooltip tooltip_title=$smarty.capture.stay_periods_tooltip_title}

View File

@@ -24,27 +24,118 @@
room table (_rooms_informaion_table.tpl) and/or a products table (_hotel_service_products_table.tpl /
_standalone_service_products_table.tpl) with tourism tax columns is rendered. *}
<style>
.ui-tooltip.price_info-tooltip { border: unset; padding: 10px; box-shadow: 0px 0px 15px 0px #00000026; }
.ui-tooltip.price_info-tooltip span { margin-left: 15px; }
.ui-tooltip.price_info-tooltip label { font-weight: 600; }
</style>
{assign var='ttExemptRooms' value=[]}
{if isset($use_tourism_tax) && $use_tourism_tax && isset($order_detail_data) && $order_detail_data}
{foreach from=$order_detail_data item=ttRoom}
{if isset($ttRoom.tourism_tax_status) && $ttRoom.tourism_tax_status == $tourism_tax_status_applied && $ttRoom.id_status != $ROOM_STATUS_CANCELLED && !$ttRoom.is_refunded}
{append var='ttExemptRooms' value=$ttRoom}
{/if}
{/foreach}
{/if}
{assign var='ttExemptProducts' value=[]}
{if isset($use_tourism_tax) && $use_tourism_tax}
{if isset($hotel_service_products) && $hotel_service_products}
{foreach from=$hotel_service_products item=ttProduct}
{if isset($ttProduct.tourism_tax_status) && $ttProduct.tourism_tax_status == $tourism_tax_status_applied && !$ttProduct.is_refunded && !$ttProduct.is_cancelled}
{append var='ttExemptProducts' value=$ttProduct}
{/if}
{/foreach}
{/if}
{if isset($standalone_service_products) && $standalone_service_products}
{foreach from=$standalone_service_products item=ttProduct}
{if isset($ttProduct.tourism_tax_status) && $ttProduct.tourism_tax_status == $tourism_tax_status_applied && !$ttProduct.is_refunded && !$ttProduct.is_cancelled}
{append var='ttExemptProducts' value=$ttProduct}
{/if}
{/foreach}
{/if}
{/if}
<div class="modal fade" id="exempt-tourism-tax-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-dialog modal-md order_detail_modal" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><i class="icon-remove-sign"></i></button>
<h4 class="modal-title"><i class="icon-ban"></i> {l s='Exempt Tourism Tax'}</h4>
</div>
<div class="modal-body">
<div class="form-group" id="tt-exempt-targets-group">
<label class="control-label" id="tt-exempt-targets-label"><b>{l s='Rooms to be exempted'}</b></label>
<ul id="tt-exempt-targets-list" style="max-height:150px; overflow-y:auto; margin-bottom:0; padding-left:18px;"></ul>
</div>
{if $ttExemptRooms|count > 0 && $ttExemptProducts|count > 0}
<ul class="nav nav-tabs" role="tablist" id="tt-exempt-tabs">
<li role="presentation" class="active">
<a href="#tt_exempt_rooms_tab" role="tab" data-toggle="tab">{l s='Rooms'}</a>
</li>
<li role="presentation">
<a href="#tt_exempt_products_tab" role="tab" data-toggle="tab">{l s='Products'}</a>
</li>
</ul>
{/if}
{if $ttExemptRooms|count > 0 && $ttExemptProducts|count > 0}
<div class="form-group tab-content clearfix">
{/if}
{if $ttExemptRooms|count}
<div id="tt_exempt_rooms_tab" class="form-group table-responsive tab-pane active">
<table class="table" id="tt-exempt-rooms-table">
<thead>
<tr>
<th class="tt-select-col"></th>
<th>{l s='Room No.'}</th>
<th>{l s='Room Type'}</th>
<th>{l s='Duration'}</th>
<th>{l s='Tourism Tax'}</th>
<th>{l s='Total Price (Tax incl.)'}</th>
</tr>
</thead>
<tbody>
{foreach from=$ttExemptRooms item=ttRoom}
<tr class="tt-exempt-row" data-id_htl_booking="{$ttRoom.id|intval}">
<td class="tt-select-col">
<input type="checkbox" name="tt_exempt_id_htl_booking[]" value="{$ttRoom.id|intval}" checked="checked"/>
</td>
<td><b>{$ttRoom.room_num|escape:'html':'UTF-8'}</b></td>
<td>{$ttRoom.room_type_name|escape:'html':'UTF-8'}</td>
{assign var="is_full_date" value=($show_full_date && ($ttRoom['date_from']|date_format:'%D' == $ttRoom['date_to']|date_format:'%D'))}
<td>{dateFormat date=$ttRoom.date_from full=$is_full_date} - {dateFormat date=$ttRoom.date_to full=$is_full_date}</td>
<td>{convertPriceWithCurrency price=$ttRoom.tourism_tax_total currency=$currency->id}</td>
<td>{convertPriceWithCurrency price=$ttRoom.total_room_price_ti currency=$currency->id}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{/if}
{if $ttExemptProducts|count}
<div id="tt_exempt_products_tab" class="form-group table-responsive tab-pane{if !$ttExemptRooms|count} active{/if}">
<table class="table" id="tt-exempt-products-table">
<thead>
<tr>
<th class="tt-select-col"></th>
<th>{l s='Name'}</th>
<th>{l s='Quantity'}</th>
<th>{l s='Tourism Tax'}</th>
<th>{l s='Total Price (Tax incl.)'}</th>
</tr>
</thead>
<tbody>
{foreach from=$ttExemptProducts item=ttProduct}
<tr class="tt-exempt-row" data-id_service_product_order_detail="{$ttProduct.id_service_product_order_detail|intval}">
<td class="tt-select-col">
<input type="checkbox" name="tt_exempt_id_service_product_order_detail[]" value="{$ttProduct.id_service_product_order_detail|intval}" checked="checked"/>
</td>
<td><b>{$ttProduct.name|escape:'html':'UTF-8'}{if $ttProduct.option_name} : {$ttProduct.option_name|escape:'html':'UTF-8'}{/if}</b></td>
<td>{if $ttProduct.allow_multiple_quantity}{$ttProduct.quantity|escape:'html':'UTF-8'}{else}--{/if}</td>
<td>{convertPriceWithCurrency price=$ttProduct.tourism_tax_total currency=$currency->id}</td>
<td>{convertPriceWithCurrency price=$ttProduct.total_price_tax_incl currency=$currency->id}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{/if}
{if $ttExemptRooms|count > 0 && $ttExemptProducts|count > 0}
</div>
{/if}
<div class="form-group">
<label class="control-label">{l s='Reason for Exemption'}</label>
<textarea rows="3" class="textarea-autosize" id="tt-exempt-note"></textarea>
<textarea rows="2" id="tt-exempt-note"></textarea>
</div>
</div>
<div class="modal-footer">
@@ -56,38 +147,124 @@
</div>
</div>
{assign var='ttApplyRooms' value=[]}
{if isset($use_tourism_tax) && $use_tourism_tax && isset($order_detail_data) && $order_detail_data}
{foreach from=$order_detail_data item=ttApplyRoom}
{if isset($ttApplyRoom.tourism_tax_status) && $ttApplyRoom.tourism_tax_status != $tourism_tax_status_applied && $ttApplyRoom.tourism_tax_status != $tourism_tax_status_not_applicable && $ttApplyRoom.id_status != $ROOM_STATUS_CANCELLED && !$ttApplyRoom.is_refunded}
{append var='ttApplyRooms' value=$ttApplyRoom}
{/if}
{/foreach}
{/if}
{assign var='ttApplyProducts' value=[]}
{if isset($use_tourism_tax) && $use_tourism_tax}
{if isset($hotel_service_products) && $hotel_service_products}
{foreach from=$hotel_service_products item=ttApplyProduct}
{if isset($ttApplyProduct.tourism_tax_status) && $ttApplyProduct.tourism_tax_status != $tourism_tax_status_applied && $ttApplyProduct.tourism_tax_status != $tourism_tax_status_not_applicable && !$ttApplyProduct.is_refunded && !$ttApplyProduct.is_cancelled}
{append var='ttApplyProducts' value=$ttApplyProduct}
{/if}
{/foreach}
{/if}
{if isset($standalone_service_products) && $standalone_service_products}
{foreach from=$standalone_service_products item=ttApplyProduct}
{if isset($ttApplyProduct.tourism_tax_status) && $ttApplyProduct.tourism_tax_status != $tourism_tax_status_applied && $ttApplyProduct.tourism_tax_status != $tourism_tax_status_not_applicable && !$ttApplyProduct.is_refunded && !$ttApplyProduct.is_cancelled}
{append var='ttApplyProducts' value=$ttApplyProduct}
{/if}
{/foreach}
{/if}
{/if}
<div class="modal fade" id="apply-tourism-tax-modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-md order_detail_modal" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><i class="icon-remove-sign"></i></button>
<h4 class="modal-title"><i class="icon-check"></i> {l s='Apply Tourism Tax'}</h4>
</div>
<div class="modal-body">
{if $ttApplyRooms|count > 0 && $ttApplyProducts|count > 0}
<ul class="nav nav-tabs" role="tablist" id="tt-apply-tabs">
<li role="presentation" class="active">
<a href="#tt_apply_rooms_tab" role="tab" data-toggle="tab">{l s='Rooms'}</a>
</li>
<li role="presentation">
<a href="#tt_apply_products_tab" role="tab" data-toggle="tab">{l s='Products'}</a>
</li>
</ul>
{/if}
{if $ttApplyRooms|count > 0 && $ttApplyProducts|count > 0}
<div class="form-group tab-content clearfix">
{/if}
{if $ttApplyRooms|count}
<div id="tt_apply_rooms_tab" class="form-group table-responsive tab-pane active">
<table class="table" id="tt-apply-rooms-table">
<thead>
<tr>
<th class="tt-select-col"></th>
<th>{l s='Room No.'}</th>
<th>{l s='Room Type'}</th>
<th>{l s='Duration'}</th>
<th>{l s='Total Price (Tax incl.)'}</th>
</tr>
</thead>
<tbody>
{foreach from=$ttApplyRooms item=ttApplyRoom}
<tr class="tt-apply-row" data-id_htl_booking="{$ttApplyRoom.id|intval}">
<td class="tt-select-col">
<input type="checkbox" name="tt_apply_id_htl_booking[]" value="{$ttApplyRoom.id|intval}" checked="checked"/>
</td>
<td><b>{$ttApplyRoom.room_num|escape:'html':'UTF-8'}</b></td>
<td>{$ttApplyRoom.room_type_name|escape:'html':'UTF-8'}</td>
{assign var="is_full_date" value=($show_full_date && ($ttApplyRoom['date_from']|date_format:'%D' == $ttApplyRoom['date_to']|date_format:'%D'))}
<td>{dateFormat date=$ttApplyRoom.date_from full=$is_full_date} - {dateFormat date=$ttApplyRoom.date_to full=$is_full_date}</td>
<td>{convertPriceWithCurrency price=$ttApplyRoom.total_room_price_ti currency=$currency->id}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{/if}
{if $ttApplyProducts|count}
<div id="tt_apply_products_tab" class="form-group table-responsive tab-pane{if !$ttApplyRooms|count} active{/if}">
<table class="table" id="tt-apply-products-table">
<thead>
<tr>
<th class="tt-select-col"></th>
<th>{l s='Name'}</th>
<th>{l s='Quantity'}</th>
<th>{l s='Total Price (Tax incl.)'}</th>
</tr>
</thead>
<tbody>
{foreach from=$ttApplyProducts item=ttApplyProduct}
<tr class="tt-apply-row" data-id_service_product_order_detail="{$ttApplyProduct.id_service_product_order_detail|intval}">
<td class="tt-select-col">
<input type="checkbox" name="tt_apply_id_service_product_order_detail[]" value="{$ttApplyProduct.id_service_product_order_detail|intval}" checked="checked"/>
</td>
<td><b>{$ttApplyProduct.name|escape:'html':'UTF-8'}{if $ttApplyProduct.option_name} : {$ttApplyProduct.option_name|escape:'html':'UTF-8'}{/if}</b></td>
<td>{if $ttApplyProduct.allow_multiple_quantity}{$ttApplyProduct.quantity|escape:'html':'UTF-8'}{else}--{/if}</td>
<td>{convertPriceWithCurrency price=$ttApplyProduct.total_price_tax_incl currency=$currency->id}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{/if}
{if $ttApplyRooms|count > 0 && $ttApplyProducts|count > 0}
</div>
{/if}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="tt-apply-confirm">
<i class="icon-check"></i> {l s='Apply Tourism Tax'}
</button>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
if ($('#customer_cart_details .price_info, #customer_products_details .price_info').length) {
$('#customer_cart_details .price_info, #customer_products_details .price_info').each(function (i, element) {
$(this).find('img').tooltip({
content: $(this).closest('td').find('.price_info_container').html(),
items: 'img',
trigger: 'hover',
tooltipClass: 'price_info-tooltip',
open: function (event, ui) {
if (typeof(event.originalEvent) === 'undefined') {
return false;
}
var $id = $(ui.tooltip).attr('id');
if ($('div.ui-tooltip').not('#' + $id).length) {
return false;
}
},
close: function (event, ui) {
ui.tooltip.hover(function () {
$(this).stop(true).fadeTo(400, 1);
}, function () {
$(this).fadeOut('400', function () {
$(this).remove();
});
});
}
});
});
}
function ttAjax(action, data) {
function ttAjax(action, data, $button) {
$.ajax({
type: 'POST',
url: admin_order_tab_link,
@@ -95,6 +272,9 @@ $(document).ready(function () {
dataType: 'json',
beforeSend: function () {
$('#page-loader').show();
if ($button) {
$button.prop('disabled', true);
}
},
success: function (resp) {
if (resp.hasError && resp.errors && resp.errors.length) {
@@ -108,72 +288,129 @@ $(document).ready(function () {
},
complete: function () {
$('#page-loader').hide();
if ($button) {
$button.prop('disabled', false);
}
}
});
}
$(document).on('click', '.tt-apply-booking', function (e) {
e.preventDefault();
ttAjax('ApplyTourismTax', { id_htl_booking: $(this).data('id_htl_booking') });
});
$(document).on('click', '.tt-apply-all-bookings', function (e) {
e.preventDefault();
ttAjax('ApplyTourismTax', { id_order: $(this).data('id_order') });
});
$(document).on('click', '.tt-apply-service-line', function (e) {
e.preventDefault();
ttAjax('ApplyTourismTax', { id_service_product_order_detail: $(this).data('id_service_product_order_detail') });
});
var ttExemptTarget = null;
var ttRoomsToBeExemptedLabel = '{l s='Rooms to be exempted' js=1}';
var ttProductsToBeExemptedLabel = '{l s='Products to be exempted' js=1}';
function ttShowExemptModal(labels, hasRooms) {
var $list = $('#tt-exempt-targets-list');
$list.empty();
$.each(labels, function (i, label) {
$list.append($('<li>').addClass('message-item-text').text(label));
});
$('#tt-exempt-targets-label b').text(hasRooms ? ttRoomsToBeExemptedLabel : ttProductsToBeExemptedLabel);
function ttShowExemptModal(onlyRow) {
var $modal = $('#exempt-tourism-tax-modal');
var $rows = $modal.find('.tt-exempt-row');
$rows.show().find('input[type=checkbox]').prop('checked', true);
$modal.find('.tt-select-col').toggle(!onlyRow);
if (onlyRow) {
$rows.each(function () {
var $row = $(this);
var isTarget = (onlyRow.id_htl_booking && $row.data('id_htl_booking') == onlyRow.id_htl_booking)
|| (onlyRow.id_service_product_order_detail && $row.data('id_service_product_order_detail') == onlyRow.id_service_product_order_detail);
if (!isTarget) {
$row.hide().find('input[type=checkbox]').prop('checked', false);
}
});
}
// show the tab holding the picked row, and hide the tab bar when a single row was picked
var $tabs = $('#tt-exempt-tabs');
if ($tabs.length) {
$tabs.toggle(!onlyRow);
var activeTab = (onlyRow && onlyRow.id_service_product_order_detail) ? '#tt_exempt_products_tab' : '#tt_exempt_rooms_tab';
$tabs.find('a[href="' + activeTab + '"]').tab('show');
}
$('#tt-exempt-note').val('');
$('#exempt-tourism-tax-modal').modal('show');
$modal.modal('show');
}
$(document).on('click', '.tt-exempt-booking', function (e) {
e.preventDefault();
ttExemptTarget = { id_htl_booking: $(this).data('id_htl_booking') };
ttShowExemptModal([$(this).data('label')], true);
ttShowExemptModal({ id_htl_booking: $(this).data('id_htl_booking') });
});
$(document).on('click', '.tt-exempt-all-bookings', function (e) {
e.preventDefault();
ttExemptTarget = { id_order: $(this).data('id_order') };
var labels = [];
var hasRooms = $('.tt-exempt-booking').length > 0;
$('.tt-exempt-booking').each(function () {
labels.push($(this).data('label'));
});
$('.tt-exempt-service-line').each(function () {
labels.push($(this).data('label'));
});
ttShowExemptModal(labels, hasRooms);
ttShowExemptModal(null);
});
$(document).on('click', '.tt-exempt-service-line', function (e) {
e.preventDefault();
ttExemptTarget = { id_service_product_order_detail: $(this).data('id_service_product_order_detail') };
ttShowExemptModal([$(this).data('label')], false);
ttShowExemptModal({ id_service_product_order_detail: $(this).data('id_service_product_order_detail') });
});
$(document).on('click', '#tt-exempt-confirm', function (e) {
if (!ttExemptTarget) {
var idsHtlBooking = $('#exempt-tourism-tax-modal input[name="tt_exempt_id_htl_booking[]"]:checked').map(function () {
return $(this).val();
}).get();
var idsServiceLine = $('#exempt-tourism-tax-modal input[name="tt_exempt_id_service_product_order_detail[]"]:checked').map(function () {
return $(this).val();
}).get();
if (!idsHtlBooking.length && !idsServiceLine.length) {
showErrorMessage('{l s='No booking/products has been selected.' js=1}');
return;
}
$('#exempt-tourism-tax-modal').modal('hide');
ttAjax('ExemptTourismTax', $.extend({ note: $('#tt-exempt-note').val() }, ttExemptTarget));
ttAjax('ExemptTourismTax', {
id_order: id_order,
id_htl_booking: idsHtlBooking,
id_service_product_order_detail: idsServiceLine,
note: $('#tt-exempt-note').val()
}, $(this));
});
function ttShowApplyModal(onlyRow) {
var $modal = $('#apply-tourism-tax-modal');
var $rows = $modal.find('.tt-apply-row');
$rows.show().find('input[type=checkbox]').prop('checked', true);
$modal.find('.tt-select-col').toggle(!onlyRow);
if (onlyRow) {
$rows.each(function () {
var $row = $(this);
var isTarget = (onlyRow.id_htl_booking && $row.data('id_htl_booking') == onlyRow.id_htl_booking)
|| (onlyRow.id_service_product_order_detail && $row.data('id_service_product_order_detail') == onlyRow.id_service_product_order_detail);
if (!isTarget) {
$row.hide().find('input[type=checkbox]').prop('checked', false);
}
});
}
// show the tab holding the picked row, and hide the tab bar when a single row was picked
var $tabs = $('#tt-apply-tabs');
if ($tabs.length) {
$tabs.toggle(!onlyRow);
var activeTab = (onlyRow && onlyRow.id_service_product_order_detail) ? '#tt_apply_products_tab' : '#tt_apply_rooms_tab';
$tabs.find('a[href="' + activeTab + '"]').tab('show');
}
$modal.modal('show');
}
$(document).on('click', '.tt-apply-booking', function (e) {
e.preventDefault();
ttShowApplyModal({ id_htl_booking: $(this).data('id_htl_booking') });
});
$(document).on('click', '.tt-apply-all-bookings', function (e) {
e.preventDefault();
ttShowApplyModal(null);
});
$(document).on('click', '.tt-apply-service-line', function (e) {
e.preventDefault();
ttShowApplyModal({ id_service_product_order_detail: $(this).data('id_service_product_order_detail') });
});
$(document).on('click', '#tt-apply-confirm', function (e) {
var idsHtlBooking = $('#apply-tourism-tax-modal input[name="tt_apply_id_htl_booking[]"]:checked').map(function () {
return $(this).val();
}).get();
var idsServiceLine = $('#apply-tourism-tax-modal input[name="tt_apply_id_service_product_order_detail[]"]:checked').map(function () {
return $(this).val();
}).get();
if (!idsHtlBooking.length && !idsServiceLine.length) {
showErrorMessage('{l s='No booking/products has been selected.' js=1}');
return;
}
ttAjax('ApplyTourismTax', {
id_order: id_order,
id_htl_booking: idsHtlBooking,
id_service_product_order_detail: idsServiceLine
}, $(this));
});
});
</script>

View File

@@ -22,11 +22,6 @@
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*}
<style>
.ui-tooltip.price_info-tooltip { border: unset; padding: 10px; box-shadow: 0px 0px 15px 0px #00000026; }
.ui-tooltip.price_info-tooltip span { margin-left: 15px; }
.ui-tooltip.price_info-tooltip label { font-weight: 600; }
</style>
<script type="text/javascript">
{if isset($cart->id) && $cart->id}
var id_cart = {$cart->id|intval};
@@ -62,31 +57,8 @@
}
});
$('.total_taxes_price_info img').tooltip({
content: function () {
return $(this).closest('.data-focus').find('.price_info_container').html();
},
items: 'img',
trigger: 'hover',
tooltipClass: 'price_info-tooltip',
open: function (event, ui) {
if (typeof(event.originalEvent) === 'undefined') {
return false;
}
var $id = $(ui.tooltip).attr('id');
if ($('div.ui-tooltip').not('#' + $id).length) {
return false;
}
},
close: function (event, ui) {
ui.tooltip.hover(function () {
$(this).stop(true).fadeTo(400, 1);
}, function () {
$(this).fadeOut('400', function () {
$(this).remove();
});
});
}
$(document).on('admin-theme.js.ready', function () {
initUITooltip();
});
$('#customer').typeWatch({
@@ -1462,7 +1434,7 @@
{
$("#customer_cart_details").empty();
$("#customer_cart_details").append(res.cart_detail_html);
initTooltip();
initUITooltip();
displaySummary(res);
}
@@ -1667,7 +1639,7 @@
},
complete: function() {
$(".loading_overlay").hide();
initTooltip();
initUITooltip();
}
});
});
@@ -1803,7 +1775,7 @@
},
complete: function() {
$(".loading_overlay").hide();
initTooltip();
initUITooltip();
}
});
});
@@ -1854,7 +1826,7 @@
},
complete: function() {
$(".loading_overlay").hide();
initTooltip();
initUITooltip();
}
});
});
@@ -2308,20 +2280,22 @@
</div>
<div class="col-lg-2">
<div class="data-focus">
<span>{l s='Total taxes'}
<span class="price_info total_taxes_price_info">&nbsp;<img src="{$info_icon_path|escape:'htmlall':'UTF-8'}" /></span>
</span><br/>
<span>{l s='Total taxes'}</span>
{capture name='total_taxes_tooltip_content'}
<div class="ui-tooltip-body">
<div class="ui-tooltip-service-tax-row">
<label class="ui-tooltip-label">{l s='Room & Service Tax:'}</label>
<span class="ui-tooltip-elem-txt" id="total_taxes_vat"></span>
</div>
<div class="ui-tooltip-tourism-tax-row">
<label class="ui-tooltip-label">{l s='Tourism Tax:'}</label>
<span class="ui-tooltip-elem-txt" id="total_taxes_tourism"></span>
</div>
</div>
{/capture}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.total_taxes_tooltip_content}
<br/>
<span id="total_taxes" class="size_l"></span>
<div class="price_info_container" style="display: none;">
<div>
<label>{l s='Room & Service Tax:'}</label>
<span class="pull-right" id="total_taxes_vat"></span>
</div>
<div>
<label>{l s='Tourism Tax:'}</label>
<span class="pull-right" id="total_taxes_tourism"></span>
</div>
</div>
</div>
</div>
<div class="col-lg-2">

View File

@@ -65,17 +65,19 @@
{$product['name']|escape:'html':'UTF-8'}
{capture name='room_type_service_tooltip_content'}
{assign var="priceCalcMethod" value=$product['price_calculation_method']|default:0}
<div class="tooltip-cont">
<div class="tooltip-popup-row"><label>{l s='Applied on:'}</label></div>
<ul class="tooltip-days">
{foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'}
<li>{$pcmDayLabel}</li>
{/foreach}
</ul>
</div>
<div class="ui-tooltip-header">
<div class="ui-tooltip-label">{l s='Applied on:'}</div>
</div>
<div class="ui-tooltip-body">
<ul>
{foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'}
<li>{$pcmDayLabel}</li>
{/foreach}
</ul>
</div>
{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true}
</div>
</td>
<td>

View File

@@ -64,7 +64,7 @@
</select>
</div>
</div>
<div class="row">
<div class="row hidden">
<div class="col-sm-12">
<p class="checkbox">
<label class="control-label" for="discount_all_invoices">

View File

@@ -69,14 +69,6 @@
</div>
<div class="row form-group">
<div class="col-sm-6">
<label class="control-label">{l s='Price (tax excl.)'}</label>
<div class="input-group">
{if $currency->format % 2}<div class="input-group-addon">{$currency->sign}</div>{/if}
<input class="form-control room_unit_price" type="text" name="room_unit_price" value=""/>
{if !($currency->format % 2)}<div class="input-group-addon">{$currency->sign}</div>{/if}
</div>
</div>
<div class="col-sm-6">
<label class="control-label">{l s='Occupancy'}</label>
<div class="booking_occupancy_edit">
@@ -138,6 +130,14 @@
</div>
</div>
</div>
<div class="col-sm-6">
<label class="control-label">{l s='Price (tax excl.)'}</label>
<div class="input-group">
{if $currency->format % 2}<div class="input-group-addon">{$currency->sign}</div>{/if}
<input class="form-control room_unit_price" type="text" name="room_unit_price" value=""/>
{if !($currency->format % 2)}<div class="input-group-addon">{$currency->sign}</div>{/if}
</div>
</div>
</div>
<div class="row form-group">
<div class="col-sm-12">

View File

@@ -57,9 +57,11 @@
{$service['name']|escape:'html':'UTF-8'}
{capture name='room_type_service_tooltip_content'}
{assign var="priceCalcMethod" value=$service['price_calculation_method']|default:0}
<div class="tooltip-cont">
<div class="tooltip-popup-row"><label>{l s='Applied on:'}</label></div>
<ul class="tooltip-days">
<div class="ui-tooltip-header">
<div class="ui-tooltip-label">{l s='Applied on:'}</div>
</div>
<div class="ui-tooltip-body">
<ul>
{foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'}
<li>{$pcmDayLabel}</li>
{/foreach}
@@ -67,7 +69,7 @@
</div>
{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_tooltip_content allow_html=true}
</div>
</div>
<input value="{$service['id_service_product_order_detail']|escape:'html':'UTF-8'}" name="id_service_product_order_detail[]" type="hidden"/>
@@ -145,16 +147,18 @@
{$product['name']|escape:'html':'UTF-8'}
{capture name='adm_pcm_tooltip_content'}
{assign var="priceCalcMethod" value=$product['price_calculation_method']|default:0}
<div class="tooltip-cont">
<div class="tooltip-popup-row"><label>{l s='Applied on:'}</label></div>
<ul class="tooltip-days">
<div class="ui-tooltip-header">
<div class="ui-tooltip-label">{l s='Applied on:'}</div>
</div>
<div class="ui-tooltip-body">
<ul>
{foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'}
<li>{$pcmDayLabel}</li>
{/foreach}
</ul>
</div>
{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.adm_pcm_tooltip_content allow_html=true}
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.adm_pcm_tooltip_content allow_html=true}
</td>
<td class="text-center">
{if $product['auto_add_to_cart'] && $product['price_addition_type'] == Product::PRICE_ADDITION_TYPE_WITH_ROOM}
@@ -321,16 +325,18 @@
{$service['name']|escape:'html':'UTF-8'}
{capture name='room_type_service_pcm_tooltip_content'}
{assign var="priceCalcMethod" value=$service['price_calculation_method']|default:0}
<div class="tooltip-cont">
<div class="tooltip-popup-row"><label>{l s='Applied on:'}</label></div>
<ul class="tooltip-days">
<div class="ui-tooltip-header">
<div class="ui-tooltip-label">{l s='Applied on:'}</div>
</div>
<div class="ui-tooltip-body">
<ul>
{foreach from=Product::getPriceCalculationMethodDaysLabel($priceCalcMethod) item='pcmDayLabel'}
<li>{$pcmDayLabel}</li>
{/foreach}
</ul>
</div>
{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_pcm_tooltip_content allow_html=true} </td>
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.room_type_service_pcm_tooltip_content allow_html=true} </td>
<td>
{if $service['product_auto_add'] && $service['product_price_addition_type'] == Product::PRICE_ADDITION_TYPE_INDEPENDENT}
<span class="badge badge-info label">{l s='Convenience fee'}</span>

View File

@@ -20,7 +20,7 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{sprintf({l s='The room "%s" already has a booking for the selected date range.'}, $orderDetails->room_num)}
{sprintf({l s='The room "%s" already has a booking for the selected date range.'}, $orderDetails->room_num|escape:'html':'UTF-8')}
<div class="row">
<div class="col-xs-12">
<span class="error_message_label">{l s='Order ID'}:</span> <a href="{$link->getAdminLink('AdminOrders')}&id_order={$orderDetails->id_order}&vieworder" target="_blank"><strong>#{$orderDetails->id_order|intval}</strong></a>

View File

@@ -95,20 +95,20 @@
<input type="checkbox" {if isset($room_info['id'])}value="{$room_info['id']}"{else}disabled{/if} name="selected_room_ids[]">
</td>
<td class="col-sm-1 center">
<input class="form-control" type="text" value="{$room_info['room_num']}" name="{$var_name_room_info|cat:'[room_num]'}">
<input class="form-control" type="text" value="{$room_info['room_num']|escape:'html':'UTF-8'}" name="{$var_name_room_info|cat:'[room_num]'}">
</td>
<td class="col-sm-2 center">
<input class="form-control" type="text" value="{$room_info['floor']}" name="{$var_name_room_info|cat:'[floor]'}">
<input class="form-control" type="text" value="{$room_info['floor']|escape:'html':'UTF-8'}" name="{$var_name_room_info|cat:'[floor]'}">
</td>
<td class="col-sm-2 center">
<select class="form-control room_status" name="{$var_name_room_info|cat:'[id_status]'}">
{foreach from=$rm_status item=room_stauts}
<option value="{$room_stauts['id']}" {if $room_info['id_status'] == {$room_stauts['id']}}selected="selected"{/if}>{$room_stauts['status']}</option>
<option value="{$room_stauts['id']}" {if $room_info['id_status'] == {$room_stauts['id']}}selected="selected"{/if}>{$room_stauts['status']|escape:'html':'UTF-8'}</option>
{/foreach}
</select>
</td>
<td class="col-sm-3 center">
<input type="text" class="form-control room_comment" value="{if isset($room_info['comment'])}{$room_info['comment']}{/if}" name="{$var_name_room_info|cat:'[comment]'}">
<input type="text" class="form-control room_comment" value="{if isset($room_info['comment'])}{$room_info['comment']|escape:'html':'UTF-8'}{/if}" name="{$var_name_room_info|cat:'[comment]'}">
</td>
<td class="col-sm-2 center">
<a class="btn btn-default deactiveDatesModal {if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }disabled{/if}" data-toggle="modal" data-target="#deactiveDatesModal" data-id-room="{if isset($room_info['id'])}{$room_info['id']}{/if}">{if $room_info['id_status'] != $rm_status['STATUS_TEMPORARY_INACTIVE']['id'] }{l s='Add Dates'}{else}{l s='View Dates'}{/if}
@@ -1609,7 +1609,7 @@
roomNum = '( '+'{l s='%s No' sprintf=$htl_room_type['selling_object_name']}'+' '+roomNum+')';
}
$('#deactiveDatesModal .disable_dates_room_num').html(roomNum);
$('#deactiveDatesModal .disable_dates_room_num').text(roomNum);
if (isNaN(idRoom)) {
DisableDatesObj.restrictCalendarActions();
return;

View File

@@ -21,13 +21,13 @@
*}
{if isset($htl_connected_rooms) && $htl_connected_rooms|@count > 0}
{capture name='connected_room_tooltip'}
<div class="tooltip_cont">
<div class="tip_header"><div class="tip_date">{l s='Connected Rooms'}</div></div>
<div class="tip-body tip-body-grid">
<div class="ui-tooltip-wrapper">
<div class="ui-tooltip-header"><div class="ui-tooltip-label">{l s='Connected Rooms'}</div></div>
<div class="ui-tooltip-body ui-tooltip-body-grid">
{foreach from=$htl_connected_rooms.connected_room_types item=group}
<div>
<div class="tip_element_head">{$group.room_type_name|escape:'html':'UTF-8'}</div>
<div class="tip_element_value">
<div class="ui-tooltip-elem-head">{$group.room_type_name|escape:'html':'UTF-8'}</div>
<div class="ui-tooltip-elem-txt">
{foreach from=$group.connected_rooms item=room name=connected_rooms}
{$room.name|escape:'html':'UTF-8'}{if !$smarty.foreach.connected_rooms.last}, {/if}
{/foreach}
@@ -37,5 +37,5 @@
</div>
</div>
{/capture}
{include file='helpers/tooltip.tpl' tooltip_content=$smarty.capture.connected_room_tooltip tooltip_icon_class='icon-random' tooltip_icon_style='color: #008abd;' }
{include file='helpers/ui-tooltip.tpl' tooltip_content=$smarty.capture.connected_room_tooltip tooltip_icon_class='icon-random' tooltip_icon_style='color: #008abd;' }
{/if}

View File

@@ -148,13 +148,13 @@
</td>
<td>
<div class="input-group">
<input class="form-control" type="text" name="restriction_min_los[]" value="{$restrictionInfo['min_los']}">
<input class="form-control" type="text" name="restriction_min_los[]" value="{$restrictionInfo['min_los']|escape:'html':'UTF-8'}">
<span class="input-group-addon">{l s='day(s)'}</span>
</div>
</td>
<td>
<div class="input-group">
<input class="form-control" type="text" name="restriction_max_los[]" value="{$restrictionInfo['max_los']}">
<input class="form-control" type="text" name="restriction_max_los[]" value="{$restrictionInfo['max_los']|escape:'html':'UTF-8'}">
<span class="input-group-addon">{l s='day(s)'}</span>
</div>
</td>

View File

@@ -383,4 +383,4 @@
<div id="main">
<div id="content" class="{if !$bootstrap}nobootstrap{else}bootstrap{/if}">
{/if}
<div id="page-loader"><span><i class="icon-refresh icon-spin icon-fw"></i></span></div>
<div id="page-loader"><span><i class="icon-refresh icon-spin icon-fw"></i></span></div>

View File

@@ -20,7 +20,7 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<span class="tooltip-trigger{if isset($tooltip_class) && $tooltip_class} {$tooltip_class|escape:'html':'UTF-8'}{/if}">
<span class="ui-tooltip-trigger{if isset($tooltip_class) && $tooltip_class} {$tooltip_class|escape:'html':'UTF-8'}{/if}">
{if isset($tooltip_title) && $tooltip_title}
{$tooltip_title nofilter}
{elseif isset($tooltip_icon_class) && $tooltip_icon_class}

View File

@@ -2732,7 +2732,6 @@ class CartCore extends ObjectModel
}
$final_package_list = $hotelWisePackageList;
/// ddd($final_package_list);
// END $package_list hotel wise
$cache[$cache_key] = $final_package_list;
return $final_package_list;

View File

@@ -147,6 +147,7 @@ class CustomerCore extends ObjectModel
'fields' => array(
'id_default_group' => array('xlink_resource' => 'groups'),
'id_lang' => array('xlink_resource' => 'languages'),
'id_country' => array('xlink_resource' => 'countries'),
'newsletter_date_add' => array(),
'ip_registration_newsletter' => array(),
'last_passwd_gen' => array('setter' => null),

View File

@@ -427,6 +427,7 @@ class ProductCore extends ObjectModel
// )
// ),
'id_tax_rules_group' => array('xlink_resource' => array('resourceName' => 'tax_rule_groups')),
'id_tourism_tax_rules_group' => array('xlink_resource' => array('resourceName' => 'tax_rule_groups')),
'position_in_category' => array('getter' => 'getWsPositionInCategory', 'setter' => 'setWsPositionInCategory'),
// 'manufacturer_name' => array(
// 'getter' => 'getWsManufacturerName',
@@ -523,6 +524,7 @@ class ProductCore extends ObjectModel
)
),
'id_tax_rules_group' => array('xlink_resource' => array('resourceName' => 'tax_rule_groups')),
'id_tourism_tax_rules_group' => array('xlink_resource' => array('resourceName' => 'tax_rule_groups')),
'position_in_category' => array('getter' => 'getWsPositionInCategory', 'setter' => 'setWsPositionInCategory'),
// 'manufacturer_name' => array(
// 'getter' => 'getWsManufacturerName',

View File

@@ -37,11 +37,65 @@ class RoomTypeSellingObjectCore extends ObjectModel
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true),
'plural_name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255),
'plural_name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255),
),
);
protected $webserviceParameters = array(
'objectsNodeName' => 'room_type_selling_objects',
'objectNodeName' => 'room_type_selling_object',
'objectMethods' => array('update' => 'updateWs', 'delete' => 'deleteWs'),
'fields' => array(
'name' => array('required' => true),
'plural_name' => array('required' => true),
'active' => array('required' => false),
),
);
/**
* Webservice: update, refusing to disable a selling object that is in use.
*
* @param bool $nullValues
*
* @return bool
*
* @throws WebserviceException
*/
public function updateWs($nullValues = false)
{
if (!$this->active && $this->id) {
$objOld = new RoomTypeSellingObject((int) $this->id);
if (Validate::isLoadedObject($objOld) && $objOld->active && $objOld->isUsed()) {
throw new WebserviceException(
Tools::displayError('You cannot disable this selling object because it is currently assigned.'),
array(400, 400)
);
}
}
return $this->update($nullValues);
}
/**
* Webservice: delete, refusing to delete a selling object that is in use.
*
* @return bool
*
* @throws WebserviceException
*/
public function deleteWs()
{
if ($this->isUsed()) {
throw new WebserviceException(
Tools::displayError('You cannot delete this selling object because it is currently assigned.'),
array(400, 400)
);
}
return $this->delete();
}
public function isUsed()
{
return (bool) Db::getInstance()->getValue(

View File

@@ -397,22 +397,94 @@ class ValidateCore
*/
public static function isCleanHtml($html, $allow_iframe = false)
{
if (isset($html)) {
$events = 'onmousedown|onmousemove|onmmouseup|onmouseover|onmouseout|onload|onunload|onfocus|onblur|onchange';
$events .= '|onsubmit|ondblclick|onclick|onkeydown|onkeyup|onkeypress|onmouseenter|onmouseleave|onerror|onselect|onreset|onabort|ondragdrop|onresize|onactivate|onafterprint|onmoveend';
$events .= '|onafterupdate|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onmove';
$events .= '|onbounce|oncellchange|oncontextmenu|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondeactivate|ondrag|ondragend|ondragenter|onmousewheel';
$events .= '|ondragleave|ondragover|ondragstart|ondrop|onerrorupdate|onfilterchange|onfinish|onfocusin|onfocusout|onhashchange|onhelp|oninput|onlosecapture|onmessage|onmouseup|onmovestart';
$events .= '|onoffline|ononline|onpaste|onpropertychange|onreadystatechange|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onsearch|onselectionchange';
$events .= '|onselectstart|onstart|onstop';
$eventAttributeRegex = '/<\s*\w+[^>]*\s(on\w+)=["\'][^"\']*["\']/ims';
if (preg_match('/<[\s]*script/ims', $html) || preg_match('/('.$events.')[\s]*=/ims', $html) || preg_match('/.*script\:/ims', $html)) {
return false;
}
$events = 'onabort|onactivate|onactive|onaddsourcebuffer|onaddstream|onaddtrack|onafterprint|onafterscriptexecute|onafterupdate|onalerting|onanimationcancel|onanimationend|onanimationiteration|onanimationstart'
. '|onantennaavailablechange|onappinstalled|onaudioend|onaudioprocess|onaudiostart|onautocomplete|onautocompleteerror|onauxclick'
. '|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforeinput|onbeforeinstallprompt|onbeforematch|onbeforepaste|onbeforeprint|onbeforescriptexecute|onbeforetoggle|onbeforeunload|onbeforeupdate|onbeforexrselect'
. '|onbegin|onbeginevent|onblocked|onblur|onbounce|onboundary|onbroadcast|onbusy|oncached|oncallschanged|oncancel|oncanplay|oncanplaythrough|oncardstatechange|oncellchange|oncfstatechange|onchange|onchargingchange|onchargingtimechange|oncheckboxstatechange|onchecking'
. '|onclick|onclose|oncommand|oncommandupdate|oncompassneedscalibration|oncomplete|oncompositionend|oncompositionstart|oncompositionupdate'
. '|onconnect|onconnected|onconnecting|onconnectioninfoupdate|oncontactchange|oncontentvisibilityautostatechange|oncontextlost|oncontextmenu|oncontextrestored'
. '|oncontrollerchange|oncontrolselect|oncopy|oncuechange|oncurrentchannelchanged|oncurrentsourcechanged|oncut'
. '|ondata|ondataavailable|ondatachange|ondatachannel|ondataerror|ondatasetchanged|ondatasetcomplete'
. '|ondblclick|ondeactivate|ondelivered|ondeliveryerror|ondeliverysuccess'
. '|ondevicechange|ondevicelight|ondevicemotion|ondeviceorientation|ondeviceproximity|ondialing|ondisabled|ondischargingtimechange|ondisconnected|ondisconnecting'
. '|ondomattrmodified|ondomcharacterdatamodified|ondomcontentloaded|ondommenuitemactive|ondommenuiteminactive|ondommousescroll|ondomnodeinserted|ondomnodeinsertedintodocument|ondomnoderemoved|ondomnoderemovedfromdocument|ondomsubtreemodified'
. '|ondownloading'
. '|ondrag|ondragdrop|ondragend|ondragenter|ondragexit|ondragleave|ondragover|ondragstart|ondrain|ondrop|ondurationchange'
. '|oneitbroadcasted|onemptied|onenabled|onencrypted'
. '|onend|onended|oneendevent|onenter|onenterpictureinpicture|onerror|onerrorupdate|onexit'
. '|onfailed|onfetch|onfilterchange|onfinish'
. '|onfocus|onfocusin|onfocusout'
. '|onformchange|onformdata|onforminput'
. '|onfrequencychange'
. '|onfullscreenchange|onfullscreenerror'
. '|ongamepadconnected|ongamepaddisconnected'
. '|ongesturechange|ongestureend|ongesturestart|ongotpointercapture'
. '|onhashchange|onheadphoneschange|onheld|onhelp|onholding'
. '|onicccardlockerror|oniccinfochange'
. '|onicecandidate|oniceconnectionstatechange|onicegatheringstatechange'
. '|onidentityresult|onidpassertionerror|onidpvalidationerror'
. '|oninactive|onincoming|oninput|oninstall|oninvalid|onisolationchange'
. '|onkeydown|onkeypress|onkeystatuschange|onkeyup'
. '|onlanguagechange|onlayoutcomplete|onleavepictureinpicture|onlevelchange'
. '|onload|onloaded|onloadeddata|onloadedmetadata|onloadend|onloading|onloadingdone|onloadingerror|onloadstart|onlocalized'
. '|onlosecapture|onlostpointercapture|onmark'
. '|onmediacomplete|onmediaerror'
. '|onmessage|onmessageerror|onmidimessage'
. '|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel'
. '|onmove|onmoveend|onmovestart|onmozaudioavailable'
// mozbrowser* events
. '|onmozbrowseractivitydone|onmozbrowserasyncscroll|onmozbrowseraudioplaybackchange|onmozbrowsercaretstatechanged|onmozbrowserclose|onmozbrowsercontextmenu|onmozbrowserdocumentfirstpaint|onmozbrowsererror|onmozbrowserfindchange|onmozbrowserfirstpaint|onmozbrowsericonchange|onmozbrowserloadend|onmozbrowserloadstart|onmozbrowserlocationchange|onmozbrowsermanifestchange|onmozbrowsermetachange|onmozbrowseropensearch|onmozbrowseropentab|onmozbrowseropenwindow|onmozbrowserresize|onmozbrowserscroll|onmozbrowserscrollareachanged|onmozbrowserselectionstatechanged|onmozbrowsershowmodalprompt|onmozbrowsertitlechange|onmozbrowserusernameandpasswordrequired|onmozbrowservisibilitychange'
. '|onmozfullscreenchange|onmozfullscreenerror|onmozgamepadbuttondown|onmozgamepadbuttonup|onmozinterruptbegin|onmozinterruptend|onmozmousepixelscroll|onmozorientation|onmozpointerlockchange|onmozpointerlockerror|onmozscrolledareachanged|onmoztimechange'
. '|onmscontentzoom|onmsgesturechange|onmsgesturedoubletap|onmsgestureend|onmsgesturehold|onmsgesturerestart|onmsgesturestart|onmsgesturetap|onmsgotpointercapture|onmsinertiastart|onmslostpointercapture|onmsmanipulationstatechanged|onmsneedkey|onmspointercancel|onmspointerdown|onmspointerenter|onmspointerhover|onmspointerleave|onmspointermove|onmspointerout|onmspointerover|onmspointerup'
. '|onmute|onnegotiationneeded|onnodecreate|onnomatch|onnotificationclick|onnoupdate|onobsolete|onoffline|ononline|onopen'
. '|onorientationchange|onoutofsync|onoverconstrained'
. '|onoverflow|onpage|onpagehide|onpagereveal|onpageshow|onpageswap'
. '|onpaste|onpause|onpeeridentity|onpeerinfoupdate'
. '|onplay|onplaying'
. '|onpointercancel|onpointerdown|onpointerenter|onpointerleave|onpointerlockchange|onpointerlockerror|onpointermove|onpointerout|onpointerover|onpointerrawupdate|onpointerup'
. '|onpopstate|onpopuphidden|onpopuphiding|onpopupshowing|onpopupshown'
. '|onprogress|onpropertychange|onpush|onpushsubscriptionchange|onradiostatechange|onratechange|onreadystatechange|onreceived|onrejectionhandled'
. '|onremovesourcebuffer|onremovestream|onremovetrack'
. '|onrepeat|onrepeatevent|onreset|onresize|onresizeend|onresizestart|onresourcetimingbufferfull'
. '|onresult|onresume|onresuming|onretrieving|onreverse'
. '|onrowdelete|onrowenter|onrowexit|onrowinserted|onrowsdelete|onrowsinserted'
. '|onscanningstatechanged|onscroll|onscrollend|onscrollsnapchange|onscrollsnapchanging'
. '|onsearch|onsecuritypolicyviolation|onseek|onseeked|onseeking'
. '|onselect|onselectionchange|onselectstart'
. '|onsending|onsent|onsessionavailable|onsessionconnect|onsettingchange'
. '|onshippingaddresschange|onshippingoptionchange|onshow|onsignalingstatechange|onslotchange|onsmartcard|onsort'
. '|onsoundend|onsoundstart|onsourceclose|onsourceended|onsourceopen|onspeakerforcedchange'
. '|onspeechend|onspeechstart|onstalled|onstart|onstarted|onstatechange|onstatuschange'
. '|onstkcommand|onstksessionend|onstop|onstorage|onsubmit|onsuccess|onsuspend'
. '|onsvgabort|onsvgerror|onsvgload|onsvgresize|onsvgscroll|onsvgunload|onsvgzoom|onsynchrestored'
. '|ontimeerror|ontimeout|ontimer|ontimeupdate|ontoggle|ontonechange'
. '|ontouchcancel|ontouchend|ontouchenter|ontouchleave|ontouchmove|ontouchstart'
. '|ontrackchange'
. '|ontransitioncancel|ontransitionend|ontransitionrun|ontransitionstart'
. '|onunderflow|onunhandledrejection|onunload|onunmute|onupdate|onupdateend|onupdatefound|onupdateready|onupdatestart|onupgradeneeded|onurlflip'
. '|onuserproximity|onussdreceived|onvaluechange|onversionchange|onvisibilitychange|onvoicechange|onvoiceschanged|onvolumechange'
. '|onvrdisplayactivate|onvrdisplayblur|onvrdisplayconnect|onvrdisplayconnected|onvrdisplaydeactivate|onvrdisplaydisconnect|onvrdisplaydisconnected|onvrdisplayfocus|onvrdisplaypresentchange'
. '|onwaiting|onwaitingforkey|onwebglcontextcreationerror|onwebglcontextlost|onwebglcontextrestored'
. '|onwebkitanimationend|onwebkitanimationiteration|onwebkitanimationstart|onwebkitfullscreenchange|onwebkitfullscreenerror|onwebkitmouseforcechanged|onwebkitmouseforcedown|onwebkitmouseforceup|onwebkitmouseforcewillbegin|onwebkitplaybacktargetavailabilitychanged|onwebkitpresentationmodechanged|onwebkittransitionend|onwebkitwillrevealbottom'
. '|onwheel|onwriteend|onzoom';
if (!$allow_iframe && preg_match('/<[\s]*(i?frame|form|input|embed|object)/ims', $html)) {
return false;
}
if (preg_match('/<[\s]*script/ims', $html) || preg_match($eventAttributeRegex, $html) || preg_match('/(' . $events . ')[\s]*=/ims', $html) || preg_match('/.*script\:/ims', $html)) {
return false;
}
if (!$allow_iframe && preg_match('/<[\s]*(i?frame|form|input|embed|object)/ims', $html)) {
return false;
}
// RLO characters detection
$rloCharacters = "\xE2\x80\xAE";
// Check if the RLO character is in the string
if (strpos($html, $rloCharacters) !== false) {
// RLO character found, potential RLO attack
return false;
}
return true;

View File

@@ -1187,6 +1187,11 @@ class AdminControllerCore extends Controller
*/
public function processDeleteImage()
{
if ($this->tabAccess['delete'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
return false;
}
if (Validate::isLoadedObject($object = $this->loadObject())) {
if (($object->deleteImage())) {
$redirect = self::$currentIndex.'&update'.$this->table.'&'.$this->identifier.'='.Tools::getValue($this->identifier).'&conf=7&token='.$this->token;
@@ -1270,6 +1275,9 @@ class AdminControllerCore extends Controller
$callback_obj = (isset($params['callback_object'])) ? $params['callback_object'] : $this->context->controller;
if (!preg_match('/<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/ism', call_user_func_array(array($callback_obj, $params['callback']), array($field_value, $row)))) {
$field_value = call_user_func_array(array($callback_obj, $params['callback']), array($field_value, $row));
} elseif (is_string($field_value)) {
// raw value is used for HTML output; ", " makes fputcsv quote it so comma separated values stay in one column
$field_value = preg_replace('/\s*,\s*/', ', ', $field_value);
}
}
$content[] = $field_value;
@@ -1289,6 +1297,11 @@ class AdminControllerCore extends Controller
*/
public function processDelete()
{
if ($this->tabAccess['delete'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
return false;
}
if (Validate::isLoadedObject($object = $this->loadObject())) {
$res = true;
// check if request at least one object with noZeroObject
@@ -1351,6 +1364,11 @@ class AdminControllerCore extends Controller
*/
public function processAdd()
{
if ($this->tabAccess['add'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to add this.');
return false;
}
if (!isset($this->className) || empty($this->className)) {
return false;
}
@@ -1402,6 +1420,11 @@ class AdminControllerCore extends Controller
*/
public function processUpdate()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
/* Checking fields validity */
$this->validateRules();
if (empty($this->errors)) {
@@ -1495,6 +1518,11 @@ class AdminControllerCore extends Controller
*/
public function processUpdateFields()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
if (!is_array($fields = Tools::getValue('fieldsBox'))) {
$fields = array();
}
@@ -1519,6 +1547,11 @@ class AdminControllerCore extends Controller
*/
public function processStatus()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
if (Validate::isLoadedObject($object = $this->loadObject())) {
if ($object->toggleStatus()) {
PrestaShopLogger::addLog(
@@ -1562,6 +1595,11 @@ class AdminControllerCore extends Controller
*/
public function processPosition()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
if (!Validate::isLoadedObject($object = $this->loadObject())) {
$this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').
' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
@@ -1619,6 +1657,11 @@ class AdminControllerCore extends Controller
*/
protected function processUpdateOptions()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
$this->beforeUpdateOptions();
$languages = Language::getLanguages(false);
@@ -2407,7 +2450,7 @@ class AdminControllerCore extends Controller
}
} else {
foreach (libxml_get_errors() as $error) {
$this->errors[] = Tools::displayError(sprintf('Error found : %1$s in country_module_list.xml file.', $error->message));
$this->errors[] = Tools::displayError(sprintf('Error found : %1$s in %2$s file.', $error->message, basename(Module::CACHE_FILE_DEFAULT_COUNTRY_MODULES_LIST)));
}
}
}
@@ -2893,7 +2936,7 @@ class AdminControllerCore extends Controller
public function setDeprecatedMedia()
{
}
public function setMedia()
{
//Bootstrap
@@ -2914,7 +2957,10 @@ class AdminControllerCore extends Controller
));
//loads specific javascripts for the admin theme
$this->addJqueryUI('ui.tooltip', 'base', true);
$this->addJS(_PS_JS_DIR_.'jquery-ui-tooltip-alias.js');
$this->addJS(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$this->bo_theme.'/js/vendor/bootstrap.min.js');
$this->addJS(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$this->bo_theme.'/js/vendor/modernizr.min.js');
$this->addJS(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$this->bo_theme.'/js/modernizr-loads.js');
$this->addJS(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$this->bo_theme.'/js/vendor/moment-with-langs.min.js');
@@ -3991,11 +4037,25 @@ class AdminControllerCore extends Controller
protected function postImage($id)
{
if (isset($this->fieldImageSettings['name']) && isset($this->fieldImageSettings['dir'])) {
return $this->uploadImage($id, $this->fieldImageSettings['name'], $this->fieldImageSettings['dir'].'/');
return $this->uploadImage(
$id,
$this->fieldImageSettings['name'],
$this->fieldImageSettings['dir'].'/',
false,
isset($this->fieldImageSettings['width']) ? $this->fieldImageSettings['width'] : null,
isset($this->fieldImageSettings['height']) ? $this->fieldImageSettings['height'] : null
);
} elseif (!empty($this->fieldImageSettings)) {
foreach ($this->fieldImageSettings as $image) {
if (isset($image['name']) && isset($image['dir'])) {
$this->uploadImage($id, $image['name'], $image['dir'].'/');
$this->uploadImage(
$id,
$image['name'],
$image['dir'].'/',
false,
isset($image['width']) ? $image['width'] : null,
isset($image['height']) ? $image['height'] : null
);
}
}
}
@@ -4065,6 +4125,11 @@ class AdminControllerCore extends Controller
*/
protected function processBulkDelete()
{
if ($this->tabAccess['delete'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
return false;
}
if (is_array($this->boxes) && !empty($this->boxes)) {
$object = new $this->className();
@@ -4266,6 +4331,11 @@ class AdminControllerCore extends Controller
*/
protected function processBulkStatusSelection($status)
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
$result = true;
if (is_array($this->boxes) && !empty($this->boxes)) {
foreach ($this->boxes as $id) {
@@ -4298,6 +4368,11 @@ class AdminControllerCore extends Controller
*/
protected function processBulkAffectZone()
{
if ($this->tabAccess['edit'] !== 1) {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
return false;
}
$result = false;
if (is_array($this->boxes) && !empty($this->boxes)) {
/** @var Country|State $object */

View File

@@ -1183,6 +1183,7 @@ class FrontControllerCore extends Controller
$this->addJS(_PS_JS_DIR_.'hookLiveEdit.js');
}
$this->addJqueryUI('ui.tooltip', 'base', true);
$this->addJS(_PS_JS_DIR_.'jquery-ui-tooltip-alias.js');
if (Configuration::get('PS_QUICK_VIEW')) {
$this->addjqueryPlugin('fancybox');

View File

@@ -1663,15 +1663,16 @@ abstract class ModuleCore
if (!in_array($modaddons->name, $modulesOnDisk)) {
if (isset($modaddons->img)) {
if (!file_exists(_PS_TMP_IMG_DIR_.md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg')) {
if (!file_put_contents(_PS_TMP_IMG_DIR_.md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg', Tools::file_get_contents($modaddons->img))) {
copy(_PS_IMG_DIR_.'404.gif', _PS_TMP_IMG_DIR_.md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg');
$imgFile = md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg';
if (!file_exists(_PS_TMP_IMG_DIR_.$imgFile)) {
$imgContent = Tools::file_get_contents($modaddons->img);
if ($imgContent) {
file_put_contents(_PS_TMP_IMG_DIR_.$imgFile, $imgContent);
}
}
if (file_exists(_PS_TMP_IMG_DIR_.md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg')) {
$item->image = '../img/tmp/'.md5((int)$modaddons->id.'-'.$modaddons->name).'.jpg';
}
// Show 404 image without caching it, so the download is retried next time
$item->image = file_exists(_PS_TMP_IMG_DIR_.$imgFile) ? '../img/tmp/'.$imgFile : '../img/404.gif';
}
}
@@ -1773,6 +1774,23 @@ abstract class ModuleCore
return Db::getInstance()->executeS($sql);
}
/**
* Writes downloaded XML to a cache file only when it parses, so a truncated
* response never replaces a good cache file.
*
* @param string $cacheFile Cache file path relative to _PS_ROOT_DIR_
* @param string|bool $xmlContent Downloaded content, false when the request failed
* @return bool True if the content was valid and written
*/
protected static function saveValidXmlCache($cacheFile, $xmlContent)
{
if (!$xmlContent || !@simplexml_load_string($xmlContent)) {
return false;
}
return (bool) file_put_contents(_PS_ROOT_DIR_.$cacheFile, $xmlContent);
}
public static function refreshModuleList($force_reload_cache = false)
{
$status = false;
@@ -1792,7 +1810,7 @@ abstract class ModuleCore
if ($status != 'error') {
if (!Tools::isFresh(Module::CACHE_FILE_DEFAULT_COUNTRY_MODULES_LIST, _TIME_1_DAY_) || $force_reload_cache) {
if (file_put_contents(_PS_ROOT_DIR_.Module::CACHE_FILE_DEFAULT_COUNTRY_MODULES_LIST, Tools::addonsRequest('native'))) {
if (Module::saveValidXmlCache(Module::CACHE_FILE_DEFAULT_COUNTRY_MODULES_LIST, Tools::addonsRequest('native'))) {
$status = 'refresh';
} else {
$status = 'error';
@@ -1804,7 +1822,7 @@ abstract class ModuleCore
if ($status != 'error') {
if (!Tools::isFresh(Module::CACHE_FILE_MUST_HAVE_MODULES_LIST, _TIME_1_DAY_) || $force_reload_cache) {
if (file_put_contents(_PS_ROOT_DIR_.Module::CACHE_FILE_MUST_HAVE_MODULES_LIST, Tools::addonsRequest('must-have'))) {
if (Module::saveValidXmlCache(Module::CACHE_FILE_MUST_HAVE_MODULES_LIST, Tools::addonsRequest('must-have'))) {
$status = 'refresh';
} else {
$status = 'error';
@@ -1816,7 +1834,7 @@ abstract class ModuleCore
if ($status != 'error') {
if (!Tools::isFresh(Module::CACHE_FILE_ADDONS_MODULES_LIST, _TIME_1_DAY_) || $force_reload_cache) {
if (file_put_contents(_PS_ROOT_DIR_.Module::CACHE_FILE_ADDONS_MODULES_LIST, Tools::addonsRequest('addons-modules'))) {
if (Module::saveValidXmlCache(Module::CACHE_FILE_ADDONS_MODULES_LIST, Tools::addonsRequest('addons-modules'))) {
$status = 'refresh';
} else {
$status = 'error';

View File

@@ -3377,7 +3377,8 @@ class OrderCore extends ObjectModel
FROM `'._DB_PREFIX_.'orders` o
INNER JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = o.`id_customer`)
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd
ON (hbd.`id_order` = o.`id_order` AND hbd.`is_cancelled` = 0 AND hbd.`is_refunded` = 0)
ON (hbd.`id_order` = o.`id_order` AND hbd.`id` NOT IN ('.OrderReturn::getRefundedBookingIdsSubquery().')
AND hbd.`id_status` != '.HotelBookingDetail::STATUS_CANCELLED.')
LEFT JOIN `'._DB_PREFIX_.'address` a
ON (a.`id_customer` = c.`id_customer` AND a.`deleted` = 0
AND a.`id_address` = (SELECT MAX(`id_address`) FROM `'._DB_PREFIX_.'address`

View File

@@ -188,7 +188,7 @@ class OrderPaymentCore extends ObjectModel
INNER JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = o.`id_customer`)
LEFT JOIN `'._DB_PREFIX_.'currency` cur ON (cur.`id_currency` = op.`id_currency`)
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd
ON (hbd.`id_order` = o.`id_order` AND hbd.`is_cancelled` = 0)
ON (hbd.`id_order` = o.`id_order` AND hbd.`id_status` != '.HotelBookingDetail::STATUS_CANCELLED.')
WHERE op.`date_add` BETWEEN "'.$dateFrom.' 00:00:00" AND "'.$dateTo.' 23:59:59"'
.($idOrder ? ' AND o.`id_order` = '.$idOrder : '')
.($idCustomer ? ' AND o.`id_customer` = '.$idCustomer : '')
@@ -213,7 +213,7 @@ class OrderPaymentCore extends ObjectModel
INNER JOIN `'._DB_PREFIX_.'orders` o
ON (o.`reference` = op.`order_reference` AND o.`valid` = 1)
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd
ON (hbd.`id_order` = o.`id_order` AND hbd.`is_cancelled` = 0)
ON (hbd.`id_order` = o.`id_order` AND hbd.`id_status` != '.HotelBookingDetail::STATUS_CANCELLED.')
WHERE op.`payment_method` IS NOT NULL AND op.`payment_method` != ""'
.HotelBranchInformation::addHotelRestriction($idHotel, 'hbd').'
ORDER BY op.`payment_method`'

View File

@@ -883,7 +883,8 @@ class OrderTaxDetailCore extends ObjectModel
return false;
}
$unitPriceTaxExcl = Tools::ps_round((float) $booking->total_price_tax_excl / $numNights, 6);
// getTaxesAmount() expects the price in the default currency and converts the amount to 'idCurrency' itself
$unitPriceTaxExcl = Tools::ps_round(Tools::convertPrice((float) $booking->total_price_tax_excl / $numNights, (int) $order->id_currency, false), 6);
$childrenAges = array();
if ($booking->child_ages) {
@@ -967,7 +968,7 @@ class OrderTaxDetailCore extends ObjectModel
return array(
'idTaxRulesGroup' => $idTaxRulesGroup,
'address' => $address,
'unitPriceTaxExcl' => (float) $serviceLine->unit_price_tax_excl,
'unitPriceTaxExcl' => Tools::convertPrice((float) $serviceLine->unit_price_tax_excl, (int) $order->id_currency, false),
'checkInDate' => $checkInDate,
'numNights' => $numNights,
'numAdults' => $numAdults,
@@ -1257,21 +1258,25 @@ class OrderTaxDetailCore extends ObjectModel
}
/**
* Exempt tourism tax for every booking (room + attached services) and every standalone service line
* of an order; returns only the failing entries.
* Exempt tourism tax for the bookings (room + attached services) and standalone service lines
* of an order — every one of them by default, or only the given ids; returns only the failing entries.
*
* @param int $idOrder
* @param int $idEmployee
* @param string|null $note Reason for exemption, applied to every booking/line in the order
* @param string|null $autoMsgLabel Pre-translated "Tourism Tax Exempted" label — null skips the Order Notes entry entirely, for every booking/line in the order
* @param string $remarkLabel Pre-translated "Remark" label
* @param int[]|null $idsHtlBooking Only these bookings are exempted (ids that don't belong to the order are ignored); null = every booking
* @param int[]|null $idsServiceLines Only these standalone service lines are exempted (ids that don't belong to the order are ignored); null = every line
* @return array [{'id_htl_booking' => int, 'result' => int}, ...] plus
* [{'id_service_product_order_detail' => int, 'result' => int}, ...] — failures only
*/
public static function exemptForOrder($idOrder, $idEmployee = 0, $note = null, $autoMsgLabel = null, $remarkLabel = 'Remark')
public static function exemptForOrder($idOrder, $idEmployee = 0, $note = null, $autoMsgLabel = null, $remarkLabel = 'Remark', $idsHtlBooking = null, $idsServiceLines = null)
{
$idOrder = (int) $idOrder;
$failures = array();
$selectedBookingIds = ($idsHtlBooking !== null) ? array_flip(array_map('intval', $idsHtlBooking)) : null;
$selectedServiceLineIds = ($idsServiceLines !== null) ? array_flip(array_map('intval', $idsServiceLines)) : null;
$objBookingDetail = new HotelBookingDetail();
$bookings = $objBookingDetail->getBookingDataByOrderId($idOrder);
if ($bookings) {
@@ -1283,6 +1288,9 @@ class OrderTaxDetailCore extends ObjectModel
if (isset($refundedIds[$booking['id']]) || $booking['id_status'] == HotelBookingDetail::STATUS_CANCELLED) {
continue;
}
if ($selectedBookingIds !== null && !isset($selectedBookingIds[(int) $booking['id']])) {
continue;
}
$result = self::exemptBooking($booking['id'], $idEmployee, $note, $autoMsgLabel, $remarkLabel);
if ($result !== self::EXEMPT_OK) {
$failures[] = array('id_htl_booking' => (int) $booking['id'], 'result' => $result);
@@ -1290,6 +1298,9 @@ class OrderTaxDetailCore extends ObjectModel
}
}
foreach (ServiceProductOrderDetail::getActiveStandaloneIdsByOrder($idOrder) as $idServiceLine) {
if ($selectedServiceLineIds !== null && !isset($selectedServiceLineIds[$idServiceLine])) {
continue;
}
$result = self::exemptServiceLine($idServiceLine, $idEmployee, $note, $autoMsgLabel, $remarkLabel);
if ($result !== self::EXEMPT_OK) {
$failures[] = array('id_service_product_order_detail' => $idServiceLine, 'result' => $result);
@@ -1299,21 +1310,25 @@ class OrderTaxDetailCore extends ObjectModel
}
/**
* Apply tourism tax for every booking and every standalone service line of an order; returns only
* the failing entries. A booking/line with nothing applicable (neither the room nor any attached
* Apply tourism tax for the bookings and standalone service lines of an order — every one of them by
* default, or only the given ids; returns only the failing entries. A booking/line with nothing applicable (neither the room nor any attached
* service, or the standalone line itself, has a tourism tax rule) is not a failure — it's silently
* skipped, same as if it had simply been left alone.
*
* @param int $idOrder
* @param int $idEmployee PS employee id (0 = resolved from Context)
* @param string|null $autoMsgLabel Pre-translated "Tourism Tax Applied" label — null skips the Order Notes entry entirely, for every booking/line in the order
* @param int[]|null $idsHtlBooking Only these bookings are applied (ids that don't belong to the order are ignored); null = every booking
* @param int[]|null $idsServiceLines Only these standalone service lines are applied (ids that don't belong to the order are ignored); null = every line
* @return array [{'id_htl_booking' => int, 'result' => int}, ...] plus
* [{'id_service_product_order_detail' => int, 'result' => int}, ...] — failures only
*/
public static function applyForOrder($idOrder, $idEmployee = 0, $autoMsgLabel = null)
public static function applyForOrder($idOrder, $idEmployee = 0, $autoMsgLabel = null, $idsHtlBooking = null, $idsServiceLines = null)
{
$idOrder = (int) $idOrder;
$failures = array();
$selectedBookingIds = ($idsHtlBooking !== null) ? array_flip(array_map('intval', $idsHtlBooking)) : null;
$selectedServiceLineIds = ($idsServiceLines !== null) ? array_flip(array_map('intval', $idsServiceLines)) : null;
$objBookingDetail = new HotelBookingDetail();
$bookings = $objBookingDetail->getBookingDataByOrderId($idOrder);
if ($bookings) {
@@ -1325,6 +1340,9 @@ class OrderTaxDetailCore extends ObjectModel
if (isset($refundedIds[$booking['id']]) || $booking['id_status'] == HotelBookingDetail::STATUS_CANCELLED) {
continue;
}
if ($selectedBookingIds !== null && !isset($selectedBookingIds[(int) $booking['id']])) {
continue;
}
$result = self::applyBooking($booking['id'], $idEmployee, $autoMsgLabel);
if ($result !== self::APPLY_OK && $result !== self::APPLY_ERROR_NOT_APPLICABLE) {
$failures[] = array('id_htl_booking' => (int) $booking['id'], 'result' => $result);
@@ -1332,6 +1350,9 @@ class OrderTaxDetailCore extends ObjectModel
}
}
foreach (ServiceProductOrderDetail::getActiveStandaloneIdsByOrder($idOrder) as $idServiceLine) {
if ($selectedServiceLineIds !== null && !isset($selectedServiceLineIds[$idServiceLine])) {
continue;
}
$result = self::applyServiceLine($idServiceLine, $idEmployee, $autoMsgLabel);
if ($result !== self::APPLY_OK && $result !== self::APPLY_ERROR_NOT_APPLICABLE) {
$failures[] = array('id_service_product_order_detail' => $idServiceLine, 'result' => $result);
@@ -1429,4 +1450,4 @@ class OrderTaxDetailCore extends ObjectModel
WHERE `id_order` = ' . $idOrder
);
}
}
}

View File

@@ -214,7 +214,7 @@ class PDFGeneratorCore extends TCPDF
{
$this->SetHeaderMargin(5);
$this->SetFooterMargin(21);
$this->setMargins(10, 40, 10);
$this->setMargins(10, 45, 10);
$this->AddPage();
$this->writeHTML($this->content, true, false, true, false, '');
}

View File

@@ -40,6 +40,9 @@ class TaxConfigurationCore extends ObjectModel
public $has_multiple_valid_ranges;
public $special_days;
/** @var string Tax name, webservice only (stored in tax_lang) */
public $name;
public static $definition = array(
'table' => 'tax_configuration',
'primary' => 'id_tax',
@@ -57,6 +60,145 @@ class TaxConfigurationCore extends ObjectModel
),
);
protected $webserviceParameters = array(
'objectsNodeName' => 'tourism_taxes',
'objectNodeName' => 'tourism_tax',
'objectMethods' => array(
'add' => 'addWs',
'update' => 'updateWs',
'delete' => 'deleteWs',
),
'fields' => array(
'name' => array('i18n' => false, 'getter' => 'getWsName'),
),
'associations' => array(
'price_tiers' => array(
'resource' => 'price_tier',
'fields' => array('min_amount' => array(), 'max_amount' => array(), 'tax_value' => array()),
),
'child_ranges' => array(
'resource' => 'child_range',
'fields' => array('min_age' => array(), 'max_age' => array(), 'tax_value' => array()),
),
'validity_ranges' => array(
'resource' => 'validity_range',
'fields' => array('valid_from' => array(), 'valid_to' => array()),
),
),
);
/**
* Webservice: add a tourism tax. The tax row is created first, the configuration reuses its id.
*
* @return bool
* @throws WebserviceException
*/
public function addWs()
{
$tax = new Tax();
$tax->is_tourism_tax = 1;
$tax->rate = 0;
$tax->active = 1;
foreach (Language::getIDs(false) as $idLang) {
$tax->name[$idLang] = (string) $this->name;
}
if (($error = $tax->validateFieldsLang(false, true)) !== true) {
throw new WebserviceException(sprintf(Tools::displayError('Validation error: "%s"'), $error), array(400, 400));
}
if (!$tax->add()) {
return false;
}
$this->id = (int) $tax->id;
return $this->add();
}
/**
* Webservice: update the configuration. Like in the admin, Tax::update() historizes a tax already used in
* orders; the tax then gets a new id, so the configuration and its ranges move to it.
*
* @param bool $nullValues
* @return bool
*/
public function updateWs($nullValues = false)
{
$idOldTax = (int) $this->id;
$tax = new Tax($idOldTax);
if (!$tax->update()) {
return false;
}
if ((int) $tax->id === $idOldTax) {
return $this->update($nullValues);
}
$this->id = (int) $tax->id;
$tiers = TaxPriceTier::getByTaxId($idOldTax);
TaxPriceTier::saveAll($this->id, array_column($tiers, 'min_amount'), array_column($tiers, 'max_amount'), array_column($tiers, 'tax_value'));
$childRanges = TaxChildRange::getByTaxId($idOldTax);
TaxChildRange::saveAll($this->id, array_column($childRanges, 'min_age'), array_column($childRanges, 'max_age'), array_column($childRanges, 'tax_value'));
$validityRanges = TaxValidityRange::getByTaxId($idOldTax);
TaxValidityRange::saveAll($this->id, array_column($validityRanges, 'valid_from'), array_column($validityRanges, 'valid_to'));
return $this->add();
}
/**
* Webservice: delete the tax. Tax::delete() only historizes a tax used in orders, so keep its configuration then.
*
* @return bool
*/
public function deleteWs()
{
$tax = new Tax((int) $this->id);
$isUsed = $tax->isUsed();
return $tax->delete() && ($isUsed || $this->delete());
}
/**
* @return string tax name in the default language
*/
public function getWsName()
{
return (new Tax((int) $this->id, (int) Configuration::get('PS_LANG_DEFAULT')))->name;
}
public function getWsPriceTiers()
{
return TaxPriceTier::getByTaxId((int) $this->id);
}
public function setWsPriceTiers($rows)
{
TaxPriceTier::saveAll((int) $this->id, array_column($rows, 'min_amount'), array_column($rows, 'max_amount'), array_column($rows, 'tax_value'));
return true;
}
public function getWsChildRanges()
{
return TaxChildRange::getByTaxId((int) $this->id);
}
public function setWsChildRanges($rows)
{
TaxChildRange::saveAll((int) $this->id, array_column($rows, 'min_age'), array_column($rows, 'max_age'), array_column($rows, 'tax_value'));
return true;
}
public function getWsValidityRanges()
{
return TaxValidityRange::getByTaxId((int) $this->id);
}
public function setWsValidityRanges($rows)
{
TaxValidityRange::saveAll((int) $this->id, array_column($rows, 'valid_from'), array_column($rows, 'valid_to'));
return true;
}
/**
* Override add() because id_tax is a FK-as-PK — the base ObjectModel::add() never writes the primary key column, which would default to 0 and create phantom rows.
*

View File

@@ -267,6 +267,7 @@ class WebserviceRequestCore
'contacts' => array('description' => 'Shop contacts','class' => 'Contact'),
'countries' => array('description' => 'The countries','class' => 'Country'),
'currencies' => array('description' => 'The currencies', 'class' => 'Currency'),
'room_type_selling_objects' => array('description' => 'The room type selling objects', 'class' => 'RoomTypeSellingObject'),
'customers' => array('description' => 'The e-shop\'s customers','class' => 'Customer'),
'customer_threads' => array('description' => 'Customer services threads','class' => 'CustomerThread'),
'customer_messages' => array('description' => 'Customer services messages','class' => 'CustomerMessage'),
@@ -306,6 +307,7 @@ class WebserviceRequestCore
'shops' => array('description' => 'Shops from multi-shop feature', 'class' => 'Shop'),
'shop_groups' => array('description' => 'Shop groups from multi-shop feature', 'class' => 'ShopGroup'),
'taxes' => array('description' => 'The tax rate', 'class' => 'Tax'),
'tourism_taxes' => array('description' => 'The tourism taxes with their configuration, price tiers, child ranges and validity ranges', 'class' => 'TaxConfiguration'),
'stock_movements' => array('description' => 'Stock movements', 'class' => 'StockMvtWS', 'forbidden_method' => array('PUT', 'POST', 'DELETE')),
'stock_movement_reasons' => array('description' => 'Stock movement reason', 'class' => 'StockMvtReason'),
'warehouses' => array('description' => 'Warehouses', 'class' => 'Warehouse', 'forbidden_method' => array('DELETE')),

View File

@@ -998,8 +998,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrder = new Order($idOrder);
foreach ($roomsToUpdate as $roomInfo) {
$objHotelBookingDetail = new HotelBookingDetail((int) $roomInfo['id']);
$taxMultiplier = $objHotelBookingDetail->total_price_tax_incl / $objHotelBookingDetail->total_price_tax_excl;
$roomNewPrice = ($objHotelBookingDetail->total_price_tax_incl / $roomsTotal) * $requestedPrice;
$taxMultiplier = $objHotelBookingDetail->total_price_tax_excl > 0 ? $objHotelBookingDetail->total_price_tax_incl / $objHotelBookingDetail->total_price_tax_excl : 1;
$roomNewPrice = $roomsTotal > 0 ? ($objHotelBookingDetail->total_price_tax_incl / $roomsTotal) * $requestedPrice : $requestedPrice / count($roomsToUpdate);
$oldPriceTaxIncl = $objHotelBookingDetail->total_price_tax_incl;
$oldPriceTaxExcl = $objHotelBookingDetail->total_price_tax_excl;
@@ -1177,8 +1177,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrderDetail->total_price_tax_excl += $priceDiffTaxExcl;
$objOrderDetail->total_price_tax_incl += $priceDiffTaxIncl;
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_excl += $priceDiffTaxExcl;
$objOrder->total_paid_tax_incl += $priceDiffTaxIncl;
@@ -1186,8 +1186,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
} else if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_price_without_tax'])) {
$totalPriceTaxExcl = $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_price_without_tax'];
$totalPriceTaxIncl = $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_price_without_tax'] * $oldTaxMultiplier;
$unitPriceTaxExcl = $totalPriceTaxExcl / $quantity;
$unitPriceTaxIncl = $totalPriceTaxIncl / $quantity;
$unitPriceTaxExcl = $totalPriceTaxExcl / max(1, $quantity);
$unitPriceTaxIncl = $totalPriceTaxIncl / max(1, $quantity);
$objServiceProductOrderDetail->unit_price_tax_excl = Tools::ps_round($unitPriceTaxExcl, _PS_PRICE_COMPUTE_PRECISION_);
$objServiceProductOrderDetail->unit_price_tax_incl = Tools::ps_round($unitPriceTaxIncl, _PS_PRICE_COMPUTE_PRECISION_);
@@ -1200,8 +1200,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrderDetail->total_price_tax_excl += $priceDiffTaxExcl;
$objOrderDetail->total_price_tax_incl += $priceDiffTaxIncl;
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_excl += $priceDiffTaxExcl;
$objOrder->total_paid_tax_incl += $priceDiffTaxIncl;
@@ -1244,7 +1244,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
$objOrderDetail->total_price_tax_incl += $priceDiffTaxIncl;
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_incl += $priceDiffTaxIncl;
$objOrder->total_paid += $priceDiffTaxIncl;
@@ -1774,7 +1774,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
if (isset($service['unit_price_without_tax'])) {
$price = $service['unit_price_without_tax'];
} else if (isset($service['total_price_without_tax'])) {
$price = $service['total_price_without_tax'] / $quantity;
$price = $service['total_price_without_tax'] / max(1, $quantity);
}
$objProduct->booking_product = false;
@@ -2221,8 +2221,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objBookingDetail->date_from,
$objBookingDetail->date_to
);
$unitPriceTaxExcl = $totalPriceTaxExcl / ($numDays * $service['quantity']);
$unitPriceTaxIncl = $totalPriceTaxIncl / ($numDays * $service['quantity']);
$unitPriceTaxExcl = $totalPriceTaxExcl / max(1, $numDays * $service['quantity']);
$unitPriceTaxIncl = $totalPriceTaxIncl / max(1, $numDays * $service['quantity']);
if ($unitPriceTaxExcl > 0) {
$taxMultiplier = $unitPriceTaxIncl / $unitPriceTaxExcl;
} else {
@@ -2244,15 +2244,15 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
if ($totalPriceTaxExcl > 0) {
$unitPriceTaxExcl = $totalPriceTaxExcl / $quantity;
$unitPriceTaxIncl = $totalPriceTaxIncl / $quantity;
$unitPriceTaxExcl = $totalPriceTaxExcl / max(1, $quantity);
$unitPriceTaxIncl = $totalPriceTaxIncl / max(1, $quantity);
}
} else if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_price_without_tax'])) {
$totalPriceTaxExcl = $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_price_without_tax'];
$totalPriceTaxIncl = $totalPriceTaxExcl * $taxMultiplier;
$unitPriceTaxExcl = $totalPriceTaxExcl / $quantity;
$unitPriceTaxIncl = $totalPriceTaxIncl / $quantity;
$unitPriceTaxExcl = $totalPriceTaxExcl / max(1, $quantity);
$unitPriceTaxIncl = $totalPriceTaxIncl / max(1, $quantity);
}
$objAddress = new Address((int) $objOrder->id_address_tax);
@@ -2283,8 +2283,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrderDetail->total_price_tax_excl += Tools::ps_round($priceDiffTaxExcl, _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->total_price_tax_incl += Tools::ps_round($priceDiffTaxIncl, _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / $objOrderDetail->product_quantity), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_excl = Tools::ps_round(($objOrderDetail->total_price_tax_excl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->unit_price_tax_incl = Tools::ps_round(($objOrderDetail->total_price_tax_incl / max(1, $objOrderDetail->product_quantity)), _PS_PRICE_COMPUTE_PRECISION_);
$objOrderDetail->save();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
@@ -3155,7 +3155,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objHotelBookingDetail->date_from,
$objHotelBookingDetail->date_to,
$objCart->id
)/ $numDays;
)/ max(1, $numDays);
$unitPriceTaxIncl = Product::getServiceProductPrice(
(int) $product['id_product'],
0,
@@ -3166,7 +3166,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objHotelBookingDetail->date_from,
$objHotelBookingDetail->date_to,
$objCart->id
)/ $numDays;
)/ max(1, $numDays);
if ($unitPriceTaxIncl > 0) {
$oldTaxMultiplier = $unitPriceTaxExcl / $unitPriceTaxIncl;
@@ -3189,14 +3189,14 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$totalPriceTaxExcl = $services[$product['id_product']]['total_price_without_tax'];
$totalPriceTaxIncl = $totalPriceTaxExcl * $oldTaxMultiplier;
$unitPriceTaxExcl = $totalPriceTaxExcl / $quantity;
$unitPriceTaxIncl = $totalPriceTaxIncl / $quantity;
$unitPriceTaxExcl = $totalPriceTaxExcl / max(1, $quantity);
$unitPriceTaxIncl = $totalPriceTaxIncl / max(1, $quantity);
}
if (!empty($services[$product['id_product']]['total_tax'])) {
$totalPriceTaxIncl = $totalPriceTaxExcl + $services[$product['id_product']]['total_tax'];
$totalPriceTaxIncl = Tools::ps_round(($totalPriceTaxIncl), _PS_PRICE_COMPUTE_PRECISION_);
$unitPriceTaxIncl = Tools::ps_round($totalPriceTaxIncl / $quantity, _PS_PRICE_COMPUTE_PRECISION_);
$unitPriceTaxIncl = Tools::ps_round($totalPriceTaxIncl / max(1, $quantity), _PS_PRICE_COMPUTE_PRECISION_);
} else if (isset($services[$product['id_product']]['total_tax'])) {
$objOrderDetail->id_tax_rules_group = 0;
Db::getInstance()->execute(
@@ -3692,7 +3692,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$services['id_service'] = (int) $service['id_product'];
$services['name'] = $service['name'];
$services['quantity'] = (int) $service['quantity'];
$services['unit_price_without_tax'] = Tools::ps_round(($service['total_price_tax_excl'] / $services['quantity']), _PS_PRICE_COMPUTE_PRECISION_);
$services['unit_price_without_tax'] = Tools::ps_round(($service['total_price_tax_excl'] / max(1, $services['quantity'])), _PS_PRICE_COMPUTE_PRECISION_);
$services['total_price_without_tax'] = Tools::ps_round(($service['total_price_tax_excl']), _PS_PRICE_COMPUTE_PRECISION_);
$services['total_tax'] = Tools::ps_round(($service['total_price_tax_incl'] - $service['total_price_tax_excl']), _PS_PRICE_COMPUTE_PRECISION_);

View File

@@ -278,7 +278,6 @@ class AdminCartRulesControllerCore extends AdminController
'room_rmv_txt' => $this->l('Unselect below room types'),
)
);
$this->addJqueryUI('ui.tooltip', 'base', true);
$this->addJS(_PS_JS_DIR_.'admin/cart-rules.js');
$this->addJqueryPlugin(array('typewatch', 'fancybox', 'autocomplete'));
}

View File

@@ -50,7 +50,8 @@ class AdminCartsControllerCore extends AdminController
IF(o.id_order, 1, 0) badge_success, IF(o.id_order, 0, 1) badge_danger, IF(co.id_guest, 1, 0) id_guest';
$this->_join = 'LEFT JOIN '._DB_PREFIX_.'customer c ON (c.id_customer = a.id_customer)
LEFT JOIN '._DB_PREFIX_.'currency cu ON (cu.id_currency = a.id_currency)
LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = a.id_cart)
LEFT JOIN '._DB_PREFIX_.'htl_booking_detail hbd ON (hbd.id_cart = a.id_cart)
LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = a.id_cart OR o.id_order = hbd.id_order)
LEFT JOIN `'._DB_PREFIX_.'connections` co ON (a.id_guest = co.id_guest AND TIME_TO_SEC(TIMEDIFF(\''.pSQL(date('Y-m-d H:i:00', time())).'\', co.`date_add`)) < 1800)';
$this->_group = ' GROUP BY a.`id_cart`';
@@ -407,6 +408,7 @@ class AdminCartsControllerCore extends AdminController
'total_discounts' => $total_discounts,
'total_wrapping' => $total_wrapping,
'total_price' => $total_price,
'total_tourism_tax' => isset($summary['total_tourism_tax']) ? $summary['total_tourism_tax'] : 0,
'total_shipping' => $total_shipping,
'customized_datas' => $customized_datas,
'tax_calculation_method' => $tax_calculation_method

View File

@@ -365,7 +365,7 @@ class AdminCustomersControllerCore extends AdminController
// Added this to check if the filter for the banned(deleted) is used, since $this->delete = true will not display the deleted customers.
$prefix = $this->getCookieFilterPrefix();
$filters = $this->context->cookie->getFamily($prefix.$this->table.'Filter_');
if (isset($filters[$prefix.$this->table.'Filter_deleted']) && $filters[$prefix.$this->table.'Filter_deleted'] == 1) {
if (isset($filters[$prefix.$this->table.'Filter_a!deleted']) && $filters[$prefix.$this->table.'Filter_a!deleted'] == 1) {
$this->deleted = false;
}
}
@@ -970,7 +970,7 @@ class AdminCustomersControllerCore extends AdminController
$helper->color = 'color2';
$helper->title = $this->l('Banned Customers', null, null, false);
$helper->subtitle = $this->l('All Time', null, null, false);
$helper->href = $this->context->link->getAdminLink('AdminCustomers').'&submitResetcustomer&submitFiltercustomer=1&customerFilter_deleted=1';
$helper->href = $this->context->link->getAdminLink('AdminCustomers').'&submitResetcustomer&submitFiltercustomer=1&customerFilter_a!deleted=1';
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_banned_customers';
$helper->tooltip = $this->l('The total number of banned customers.', null, null, false);
$this->kpis[] = $helper;

View File

@@ -33,7 +33,7 @@ class AdminEmailsControllerCore extends AdminController
{
$this->bootstrap = true;
if (Configuration::get('PS_LOG_EMAILS')) {
if (Tools::getValue('PS_LOG_EMAILS', Configuration::get('PS_LOG_EMAILS'))) {
$this->table = 'mail';
$this->className = 'Mail';

View File

@@ -43,7 +43,9 @@ class AdminLanguagesControllerCore extends AdminController
$this->fieldImageSettings = array(
array(
'name' => 'flag',
'dir' => 'l'
'dir' => 'l',
'width' => 16,
'height' => 11
),
array(
'name' => 'no_picture',

View File

@@ -446,11 +446,11 @@ class AdminModulesPositionsControllerCore extends AdminController
$file_list = ($file_list) ? array($file_list) : array();
}
$content = '<p><input type="text" name="exceptions['.$shop_id.']" value="'.implode(', ', $file_list).'" id="em_text_'.$shop_id.'" placeholder="'.$this->l('E.g. address, addresses, attachment').'"/></p>';
$content = '<p><input type="text" name="exceptions['.(int) $shop_id.']" value="'.Tools::safeOutput(implode(', ', $file_list)).'" id="em_text_'.(int) $shop_id.'" placeholder="'.$this->l('E.g. address, addresses, attachment').'"/></p>';
if ($shop_id) {
$shop = new Shop($shop_id);
$content .= ' ('.$shop->name.')';
$content .= ' ('.Tools::safeOutput($shop->name).')';
}
$content .= '<p>
@@ -463,14 +463,14 @@ class AdminModulesPositionsControllerCore extends AdminController
foreach ($file_list as $k => $v) {
if (! array_key_exists($v, $controllers)) {
$content .= '<option value="'.$v.'">'.$v.'</option>';
$content .= '<option value="'.Tools::safeOutput($v).'">'.Tools::safeOutput($v).'</option>';
}
}
$content .= '<option disabled="disabled">'.$this->l('____________ CORE ____________').'</option>';
foreach ($controllers as $k => $v) {
$content .= '<option value="'.$k.'">'.$k.'</option>';
$content .= '<option value="'.Tools::safeOutput($k).'">'.Tools::safeOutput($k).'</option>';
}
$modules_controllers_type = array('admin' => $this->l('Admin modules controller'), 'front' => $this->l('Front modules controller'));
@@ -479,7 +479,7 @@ class AdminModulesPositionsControllerCore extends AdminController
$all_modules_controllers = Dispatcher::getModuleControllers($type);
foreach ($all_modules_controllers as $module => $modules_controllers) {
foreach ($modules_controllers as $cont) {
$content .= '<option value="module-'.$module.'-'.$cont.'">module-'.$module.'-'.$cont.'</option>';
$content .= '<option value="module-'.Tools::safeOutput($module.'-'.$cont).'">module-'.Tools::safeOutput($module.'-'.$cont).'</option>';
}
}
}

View File

@@ -224,13 +224,14 @@ class AdminNormalProductsControllerCore extends AdminController
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop ON (image_shop.`id_product` = a.`id_product` AND image_shop.`cover` = 1 AND image_shop.id_shop = '.$id_shop.')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_image` = image_shop.`id_image`)
LEFT JOIN `'._DB_PREFIX_.'product_download` pd ON (pd.`id_product` = a.`id_product` AND pd.`active` = 1)
LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` ttrg ON (ttrg.`id_tax_rules_group` = sa.`id_tourism_tax_rules_group`)
LEFT JOIN `'._DB_PREFIX_.'htl_room_type_service_product` rsp ON (rsp.`id_product` = a.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'htl_room_type` hrt ON (rsp.`id_element` = hrt.`id_product` AND rsp.`element_type` = '.(int)RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE.')
'.HotelBranchInformation::addHotelRestriction(false, 'hrt');
$this->_select .= ' IF(a.`auto_add_to_cart`, "'.$this->l('Yes').'", "'.$this->l('No').'") as auto_added, IF(a.`auto_add_to_cart`, 1, 0) as badge_success, IF(a.`show_at_front`, "'.$this->l('Yes').'", "'.$this->l('No').'") as show_at_front_txt, (SELECT COUNT(hri.`id`) FROM `'._DB_PREFIX_.'htl_room_information` hri WHERE hri.`id_product` = a.`id_product`) as num_rooms, ';
$this->_select .= ' COUNT(hrt.`id_product`) as products_associated, ';
$this->_select .= 'shop.`name` AS `shopname`, a.`id_shop_default`, ';
$this->_select .= 'shop.`name` AS `shopname`, a.`id_shop_default`, ttrg.`name` AS `tourism_tax_rules_group`, ';
$this->_select .= $alias_image.'.`id_image` AS `id_image`, cl.`name` AS `name_category`, '.$alias.'.`price`, 0 AS `price_final`, a.`is_virtual`, pd.`nb_downloadable`, sav.`quantity` AS `sav_quantity`, '.$alias.'.`active`, IF(sav.`quantity`<=0, 1, 0) AS `badge_danger`';
if ($join_category) {
@@ -354,6 +355,21 @@ class AdminNormalProductsControllerCore extends AdminController
);
}
$tourismTaxRulesGroups = array();
foreach (TaxRulesGroup::getTaxRulesGroups(true, true) as $taxRulesGroup) {
$tourismTaxRulesGroups[$taxRulesGroup['id_tax_rules_group']] = $taxRulesGroup['name'];
}
$this->fields_list['tourism_tax_rules_group'] = array(
'title' => $this->l('Tourism tax rule'),
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'sa!id_tourism_tax_rules_group',
'list' => $tourismTaxRulesGroups,
'optional' => true,
'class' => 'chosen',
);
$this->fields_list['price'] = array(
'title' => $this->l('Base price'),
'type' => 'price',
@@ -1578,8 +1594,6 @@ class AdminNormalProductsControllerCore extends AdminController
_PS_JS_DIR_.'jquery/plugins/timepicker/jquery-ui-timepicker-addon.css',
_PS_CSS_DIR_.'ps-hotel-reservation.css',
));
}else {
$this->addJqueryUI('ui.tooltip', 'base', true);
}
}

View File

@@ -1431,9 +1431,7 @@ class AdminOrdersControllerCore extends AdminController
parent::setMedia();
$this->addJqueryUI('ui.datepicker');
$this->addJqueryUI('ui.tooltip', 'base', true);
$this->addJS(_PS_JS_DIR_.'vendor/d3.v3.min.js');
$this->addJqueryUI(array('ui.tooltip'), 'base', true);
if ($this->display == 'view') {
if ($this->loadObject()) {
@@ -2332,35 +2330,6 @@ class AdminOrdersControllerCore extends AdminController
throw new PrestaShopException('Can\'t load Currency object');
}
// Update order detail amount
foreach ($order->getOrderDetailList() as $row) {
$order_detail = new OrderDetail($row['id_order_detail']);
$fields = array(
'ecotax',
'product_price',
'reduction_amount',
'total_shipping_price_tax_excl',
'total_shipping_price_tax_incl',
'total_price_tax_incl',
'total_price_tax_excl',
'product_quantity_discount',
'purchase_supplier_price',
'reduction_amount',
'reduction_amount_tax_incl',
'reduction_amount_tax_excl',
'unit_price_tax_incl',
'unit_price_tax_excl',
'original_product_price'
);
foreach ($fields as $field) {
$order_detail->{$field} = Tools::convertPriceFull($order_detail->{$field}, $old_currency, $currency);
}
$order_detail->update();
$order_detail->updateTaxAmount($order);
}
$id_order_carrier = (int)$order->getIdOrderCarrier();
if ($id_order_carrier) {
$order_carrier = $order_carrier = new OrderCarrier((int)$order->getIdOrderCarrier());
@@ -2521,6 +2490,71 @@ class AdminOrdersControllerCore extends AdminController
}
// Update order detail amount and taxes, only after every other line price (room bookings, service products) is converted, otherwise taxes get calculated on the old currency prices
foreach ($order->getOrderDetailList() as $row) {
$order_detail = new OrderDetail($row['id_order_detail']);
$fields = array(
'ecotax',
'product_price',
'reduction_amount',
'total_shipping_price_tax_excl',
'total_shipping_price_tax_incl',
'total_price_tax_incl',
'total_price_tax_excl',
'product_quantity_discount',
'purchase_supplier_price',
'reduction_amount',
'reduction_amount_tax_incl',
'reduction_amount_tax_excl',
'unit_price_tax_incl',
'unit_price_tax_excl',
'original_product_price'
);
foreach ($fields as $field) {
$order_detail->{$field} = Tools::convertPriceFull($order_detail->{$field}, $old_currency, $currency);
}
$order_detail->update();
$order_detail->updateTaxAmount($order);
}
// Tourism tax depends on the order currency, and updateTaxAmount() only rebuilds VAT, so rebuild it from the converted prices
if (Configuration::get('QLO_USE_TOURISM_TAX')) {
$tourismTaxParamsList = array();
if ($activeRoomBookings = $objHtlBookingDetail->getOrderCurrentDataByOrderId($order->id, array(), false)) {
foreach ($activeRoomBookings as $roomBooking) {
$tourismTaxParamsList[] = OrderTaxDetail::buildRoomTaxParams((int) $roomBooking['id']);
}
}
if ($orderServices = $objRoomTypeServProdOrderDtl->getServiceProductsInOrder($order->id)) {
foreach ($orderServices as $serviceProduct) {
if (!$serviceProduct['is_refunded'] && !$serviceProduct['is_cancelled']) {
$tourismTaxParamsList[] = OrderTaxDetail::buildServiceLineTaxParams((int) $serviceProduct['id_service_product_order_detail']);
}
}
}
foreach (array_filter($tourismTaxParamsList) as $tourismTaxParams) {
OrderTaxDetail::saveTourismTax(
$tourismTaxParams['idTaxRulesGroup'],
$tourismTaxParams['address'],
$tourismTaxParams['unitPriceTaxExcl'],
$tourismTaxParams['checkInDate'],
$tourismTaxParams['numNights'],
$tourismTaxParams['numAdults'],
$tourismTaxParams['childrenAges'],
$tourismTaxParams['idCurrency'],
$tourismTaxParams['collectionType'],
$tourismTaxParams['idLang'],
$tourismTaxParams['quantity'],
$tourismTaxParams['idOrder'],
$tourismTaxParams['idOrderDetail'],
$tourismTaxParams['idHtlBooking'],
$tourismTaxParams['idServiceProductOrderDetail']
);
}
}
// update Order refund prices (order_return and order_return_detail)
if ($orderReturns = OrderReturn::getOrdersReturn($order->id_customer, $order->id)) {
$fields = array(
@@ -3638,7 +3672,9 @@ class AdminOrdersControllerCore extends AdminController
$orderTourismTaxHasUnapplied = false;
if ($useTourismTax && $order_detail_data) {
foreach ($order_detail_data as $bookingRow) {
if (!empty($bookingRow['is_cancelled']) || !empty($bookingRow['is_refunded'])) {
if (!empty($bookingRow['is_cancelled']) || !empty($bookingRow['is_refunded'])
|| $bookingRow['id_status'] == HotelBookingDetail::STATUS_CANCELLED
) {
continue;
}
if (isset($bookingRow['tourism_tax_status'])) {
@@ -3739,7 +3775,17 @@ class AdminOrdersControllerCore extends AdminController
$allowBackdateOrder = Configuration::get($backOrderConfigKey);
// applicable refund policies
$applicableRefundPolicies = HotelOrderRefundRules::getApplicableRefundRules($order->id);
$applicableRefundPolicies = array();
if (($idHotel = HotelBookingDetail::getIdHotelByIdOrder($order->id))) {
$objBranchRefundRules = new HotelBranchRefundRules();
$applicableRefundPolicies = $objBranchRefundRules->getHotelRefundRules(
$idHotel,
0,
1,
$this->context->language->id,
1,
);
}
// Overbookings information of the order
$orderOverBookings = $objHotelBookingDetail->getOverbookedRooms($order->id, 0, '', '', 0, 0, 1);
@@ -4218,6 +4264,16 @@ class AdminOrdersControllerCore extends AdminController
$idHotel = false;
}
// Stay dates for feature price calculation (defaults to one night from today)
$dateFrom = Tools::getValue('date_from');
$dateTo = Tools::getValue('date_to');
if (!Validate::isDate($dateFrom) || !Validate::isDate($dateTo) || strtotime($dateTo) <= strtotime($dateFrom)) {
$dateFrom = date('Y-m-d');
$dateTo = date('Y-m-d', strtotime('+1 day'));
}
$numDays = max(1, (int) HotelHelper::getNumberOfDays($dateFrom, $dateTo));
$this->context->currency = $currency;
if ($products = Product::searchByName((int)$this->context->language->id, pSQL(Tools::getValue('product_search')), 1, null, $idHotel)) {
$objRoomType = new HotelRoomType();
foreach ($products as $key => &$product) {
@@ -4233,22 +4289,21 @@ class AdminOrdersControllerCore extends AdminController
}
$idHotelAddress = $order->id_address_tax;
// Concret price
$product['price_tax_excl'] = Tools::ps_round(Tools::convertPrice($product['price_tax_excl'], $currency), _PS_PRICE_COMPUTE_PRECISION_);
$product['price_tax_incl'] = Tools::ps_round(Tools::convertPrice(Product::getPriceStatic(
// Apply room type feature price (advance price rules) for the stay duration
$roomTotalPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$product['id_product'],
true,
null,
6,
null,
false,
true,
1,
false,
null,
null,
$idHotelAddress
), $currency), _PS_PRICE_COMPUTE_PRECISION_);
$dateFrom,
$dateTo,
0,
Group::getCurrent()->id,
0,
0,
0,
0,
1
);
$product['price_tax_excl'] = Tools::ps_round($roomTotalPrice['total_price_tax_excl'] / $numDays, _PS_PRICE_COMPUTE_PRECISION_);
$product['price_tax_incl'] = Tools::ps_round($roomTotalPrice['total_price_tax_incl'] / $numDays, _PS_PRICE_COMPUTE_PRECISION_);
// Formatted price
$product['formatted_price'] = Tools::displayPrice(Tools::convertPrice($product['price_tax_incl'], $currency), $currency);
@@ -5163,20 +5218,9 @@ class AdminOrdersControllerCore extends AdminController
$use_taxes = true;
$this->context->currency = new Currency($order->id_currency);
$initial_product_price_tax_incl = Product::getPriceStatic(
$product->id,
$use_taxes,
isset($combination) ? $combination->id : null,
2,
null,
false,
true,
1,
false,
$order->id_customer,
$cart->id,
$order->id_address_tax
);
// price for the selected dates (advance price rules are applied), same as shown in the modal
$roomTotalPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice($product->id, $date_from, $date_to, 0, Group::getCurrent()->id, 0, 0, 0, 0, 1);
$initial_product_price_tax_incl = Tools::ps_round($roomTotalPrice['total_price_tax_incl'] / $num_days, _PS_PRICE_COMPUTE_PRECISION_);
// create feature price if needed
$createFeaturePrice = $product_informations['product_price_tax_incl'] != $initial_product_price_tax_incl;
@@ -6199,6 +6243,54 @@ class AdminOrdersControllerCore extends AdminController
)));
}
/**
* Get the per night room price (tax excl.) for the selected dates while editing a room booking.
* Advance price rules are applied according to the stay duration.
*/
public function ajaxProcessGetEditRoomPrice()
{
$response = array('success' => false);
$idProduct = (int) Tools::getValue('id_product');
$dateFrom = Tools::getValue('date_from');
$dateTo = Tools::getValue('date_to');
$idRoom = (int) Tools::getValue('id_room');
if (Validate::isLoadedObject($objOrder = new Order((int) Tools::getValue('id_order')))
&& Validate::isLoadedObject(new Product($idProduct))
&& Validate::isDate($dateFrom)
&& Validate::isDate($dateTo)
&& strtotime($dateTo) > strtotime($dateFrom)
) {
$this->context->currency = new Currency($objOrder->id_currency);
$idGroup = Group::getCurrent()->id;
$numDays = (int) HotelHelper::getNumberOfDays($dateFrom, $dateTo);
$roomTotalPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$idProduct,
$dateFrom,
$dateTo,
0,
$idGroup,
0,
0,
$idRoom,
0,
1
);
if ($numDays > 0) {
$response['success'] = true;
$response['unit_price_tax_excl'] = Tools::ps_round(
(float) $roomTotalPrice['total_price_tax_excl'] / $numDays,
_PS_PRICE_COMPUTE_PRECISION_
);
$response['unit_price_tax_incl'] = Tools::ps_round(
(float) $roomTotalPrice['total_price_tax_incl'] / $numDays,
_PS_PRICE_COMPUTE_PRECISION_
);
}
}
$this->ajaxDie(json_encode($response));
}
public function ajaxProcessEditRoomOnOrder()
{
// Check tab access is allowed to edit
@@ -8897,6 +8989,10 @@ class AdminOrdersControllerCore extends AdminController
|| $objHotelBookingDetail->id_status == HotelBookingDetail::STATUS_CHECKED_OUT)
) {
$this->errors[] = Tools::displayError('Room status cannot be changed to No-show or Cancelled once the guest has already checked in.');
} elseif ($newStatus == HotelBookingDetail::STATUS_CHECKED_IN
&& strtotime($dateFrom) > time()
) {
$this->errors[] = Tools::displayError('Check-in is not allowed before the booking\'s check-in date. For an early arrival, please change the stay dates first.');
} elseif ($newStatus == HotelBookingDetail::STATUS_CHECKED_IN
|| $newStatus == HotelBookingDetail::STATUS_CHECKED_OUT
) {
@@ -8951,6 +9047,19 @@ class AdminOrdersControllerCore extends AdminController
if ($remainingCheckoutRooms == 1 && $newStatus == HotelBookingDetail::STATUS_CHECKED_OUT && $hasPendingBills) {
$this->errors[] = Tools::displayError('You cannot checkout the last room while there are pending bills for this order.');
} else {
Hook::exec(
'actionRoomBookingStatusUpdateBefore',
array(
'id_hotel_booking_detail' => $objHotelBookingDetail->id,
'id_order' => $objHotelBookingDetail->id_order,
'id_room' => $objHotelBookingDetail->id_room,
'date_from' => $objHotelBookingDetail->date_from,
'date_to' => $objHotelBookingDetail->date_to,
'id_status_from' => (int) $objHotelBookingDetail->id_status,
'id_status_to' => $newStatus,
)
);
if ($newStatus == HotelBookingDetail::STATUS_CHECKED_IN) {
$objHotelBookingDetail->check_in = $statusDate;
// reverting from Checked-out: clear the stale check-out timestamp
@@ -9145,15 +9254,22 @@ class AdminOrdersControllerCore extends AdminController
}
/**
* Apply tourism tax to a booking (id_htl_booking), a standalone service line
* (id_service_product_order_detail), or every booking of a whole order (id_order) —
* see OrderTaxDetail::applyBooking()/applyServiceLine().
* Apply tourism tax to the rooms (id_htl_booking[]) and/or standalone service lines
* (id_service_product_order_detail[]) selected in the apply modal of an order (id_order) —
* see OrderTaxDetail::applyForOrder().
*/
public function ajaxProcessApplyTourismTax()
{
$idHtlBooking = (int) Tools::getValue('id_htl_booking', 0);
$idServiceProductOrderDetail = (int) Tools::getValue('id_service_product_order_detail', 0);
if ($this->tabAccess['edit'] !== 1) {
die(Tools::jsonEncode(array(
'hasError' => true,
'errors' => array(Tools::displayError('You do not have permission to edit this order.')),
)));
}
$idOrder = (int) Tools::getValue('id_order', 0);
$idsHtlBooking = array_filter(array_map('intval', (array) Tools::getValue('id_htl_booking', array())));
$idsServiceProductOrderDetail = array_filter(array_map('intval', (array) Tools::getValue('id_service_product_order_detail', array())));
$idEmployee = (int) Context::getContext()->employee->id;
$autoMsgLabel = $this->l('Tourism Tax Applied');
$errors = array();
@@ -9162,20 +9278,15 @@ class AdminOrdersControllerCore extends AdminController
OrderTaxDetail::APPLY_ERROR_NOT_APPLICABLE => $this->l('Tourism tax is not applicable for this booking.'),
);
if ($idHtlBooking) {
$result = OrderTaxDetail::applyBooking($idHtlBooking, $idEmployee, $autoMsgLabel);
if (isset($messagesByResult[$result])) {
$errors[] = $messagesByResult[$result];
}
} elseif ($idServiceProductOrderDetail) {
$result = OrderTaxDetail::applyServiceLine($idServiceProductOrderDetail, $idEmployee, $autoMsgLabel);
if (isset($messagesByResult[$result])) {
$errors[] = $messagesByResult[$result];
}
} elseif ($idOrder) {
$errors = self::tourismTaxErrorsFromResults(OrderTaxDetail::applyForOrder($idOrder, $idEmployee, $autoMsgLabel), $messagesByResult);
} else {
if (!Validate::isLoadedObject(new Order($idOrder))) {
$errors[] = $this->l('Invalid request parameters.');
} elseif (!$idsHtlBooking && !$idsServiceProductOrderDetail) {
$errors[] = Tools::displayError('No booking/products has been selected.');
} else {
$errors = self::tourismTaxErrorsFromResults(
OrderTaxDetail::applyForOrder($idOrder, $idEmployee, $autoMsgLabel, $idsHtlBooking, $idsServiceProductOrderDetail),
$messagesByResult
);
}
die(Tools::jsonEncode(array(
@@ -9185,15 +9296,22 @@ class AdminOrdersControllerCore extends AdminController
}
/**
* Exempt tourism tax for a booking (id_htl_booking), a standalone service line
* (id_service_product_order_detail), or every booking of a whole order (id_order) —
* see OrderTaxDetail::exemptBooking()/exemptServiceLine().
* Exempt tourism tax for the rooms (id_htl_booking[]) and/or standalone service lines
* (id_service_product_order_detail[]) selected in the exemption modal of an order (id_order) —
* see OrderTaxDetail::exemptForOrder().
*/
public function ajaxProcessExemptTourismTax()
{
$idHtlBooking = (int) Tools::getValue('id_htl_booking', 0);
$idServiceProductOrderDetail = (int) Tools::getValue('id_service_product_order_detail', 0);
if ($this->tabAccess['edit'] !== 1) {
die(Tools::jsonEncode(array(
'hasError' => true,
'errors' => array(Tools::displayError('You do not have permission to edit this order.')),
)));
}
$idOrder = (int) Tools::getValue('id_order', 0);
$idsHtlBooking = array_filter(array_map('intval', (array) Tools::getValue('id_htl_booking', array())));
$idsServiceProductOrderDetail = array_filter(array_map('intval', (array) Tools::getValue('id_service_product_order_detail', array())));
$idEmployee = (int) Context::getContext()->employee->id;
$note = trim((string) Tools::getValue('note', ''));
$note = ($note !== '') ? $note : null;
@@ -9205,20 +9323,15 @@ class AdminOrdersControllerCore extends AdminController
OrderTaxDetail::EXEMPT_ERROR_SAVE => $this->l('Could not exempt tourism tax.'),
);
if ($idHtlBooking) {
$result = OrderTaxDetail::exemptBooking($idHtlBooking, $idEmployee, $note, $autoMsgLabel, $remarkLabel);
if (isset($messagesByResult[$result])) {
$errors[] = $messagesByResult[$result];
}
} elseif ($idServiceProductOrderDetail) {
$result = OrderTaxDetail::exemptServiceLine($idServiceProductOrderDetail, $idEmployee, $note, $autoMsgLabel, $remarkLabel);
if (isset($messagesByResult[$result])) {
$errors[] = $messagesByResult[$result];
}
} elseif ($idOrder) {
$errors = self::tourismTaxErrorsFromResults(OrderTaxDetail::exemptForOrder($idOrder, $idEmployee, $note, $autoMsgLabel, $remarkLabel), $messagesByResult);
} else {
if (!Validate::isLoadedObject(new Order($idOrder))) {
$errors[] = $this->l('Invalid request parameters.');
} elseif (!$idsHtlBooking && !$idsServiceProductOrderDetail) {
$errors[] = Tools::displayError('No booking/products has been selected.');
} else {
$errors = self::tourismTaxErrorsFromResults(
OrderTaxDetail::exemptForOrder($idOrder, $idEmployee, $note, $autoMsgLabel, $remarkLabel, $idsHtlBooking, $idsServiceProductOrderDetail),
$messagesByResult
);
}
die(Tools::jsonEncode(array(

View File

@@ -437,6 +437,14 @@ class AdminPPreferencesControllerCore extends AdminController
Db::getInstance()->execute($sql);
}
if (Tools::getValue('PS_FRONT_SEARCH_TYPE') == HotelBookingDetail::SEARCH_TYPE_OWS) {
$_POST['PS_FRONT_ROOM_UNIT_SELECTION_TYPE'] = HotelBookingDetail::PS_ROOM_UNIT_SELECTION_TYPE_OCCUPANCY;
}
if (Tools::getValue('PS_BACKOFFICE_SEARCH_TYPE') == HotelBookingDetail::SEARCH_TYPE_OWS) {
$_POST['PS_BACKOFFICE_ROOM_BOOKING_TYPE'] = HotelBookingDetail::PS_ROOM_UNIT_SELECTION_TYPE_OCCUPANCY;
}
if (Tools::getIsset('PS_CATALOG_MODE')) {
Tools::clearSmartyCache();
Media::clearCache();

View File

@@ -229,6 +229,9 @@ class AdminProductsControllerCore extends AdminController
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_image` = image_shop.`id_image`)
LEFT JOIN `'._DB_PREFIX_.'product_download` pd ON (pd.`id_product` = a.`id_product` AND pd.`active` = 1)
LEFT JOIN `'._DB_PREFIX_.'address` aa ON (aa.`id_hotel` = hb.`id`)
LEFT JOIN `'._DB_PREFIX_.'htl_property_type_lang` hptl ON (hptl.`id_htl_property_type` = hb.`id_property_type` AND hptl.`id_lang` = '.(int) $this->context->language->id.')
LEFT JOIN `'._DB_PREFIX_.'room_type_selling_object_lang` rsol ON (rsol.`id_room_type_selling_object` = a.`id_selling_object` AND rsol.`id_lang` = '.(int) $this->context->language->id.')
LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` ttrg ON (ttrg.`id_tax_rules_group` = a.`id_tourism_tax_rules_group`)
LEFT JOIN `'._DB_PREFIX_.'feature_product` fp ON (fp.`id_product` = a.`id_product`)
LEFT JOIN (
SELECT rsp.*, GROUP_CONCAT(pl.`name`) AS service_products
@@ -240,7 +243,7 @@ class AdminProductsControllerCore extends AdminController
LEFT JOIN `'._DB_PREFIX_.'htl_advance_payment` hap ON (hap.`id_product` = a.`id_product`)';
$this->_select .= ' a.`show_at_front`, (SELECT COUNT(hri.`id`) FROM `'._DB_PREFIX_.'htl_room_information` hri WHERE hri.`id_product` = a.`id_product`) as num_rooms, ';
$this->_select .= 'hrt.`adults`, hrt.`children`, hrt.`max_guests`, hb.`id` as id_hotel, aa.`city`, hbl.`hotel_name`, ';
$this->_select .= 'hrt.`adults`, hrt.`children`, hrt.`max_guests`, hb.`id` as id_hotel, aa.`city`, hbl.`hotel_name`, hptl.`name` AS `property_type`, rsol.`name` AS `selling_object`, ttrg.`name` AS `tourism_tax_rules_group`, ';
$this->_select .= 'shop.`name` AS `shopname`, a.`id_shop_default`, ';
$this->_select .= $alias_image.'.`id_image` AS `id_image`, cl.`name` AS `name_category`, '.$alias.'.`price`, 0 AS `price_final`, a.`is_virtual`, pd.`nb_downloadable`, sav.`quantity` AS `sav_quantity`, '.$alias.'.`active`, IF(sav.`quantity`<=0, 1, 0) AS `badge_danger`, a.`id_tourism_tax_rules_group`';
$this->_select .= ', IFNULL(hap.`active`, 0) AS advance_payment';
@@ -300,6 +303,48 @@ class AdminProductsControllerCore extends AdminController
'visible_default' => true,
);
}
$propertyTypes = array();
foreach (HotelPropertyType::getPropertyTypes($this->context->language->id) as $propertyType) {
$propertyTypes[$propertyType['id_property_type']] = $propertyType['name'];
}
$this->fields_list['property_type'] = array(
'title' => $this->l('Property type'),
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'hb!id_property_type',
'list' => $propertyTypes,
'optional' => true,
'class' => 'chosen',
);
$sellingObjects = array();
foreach (RoomTypeSellingObject::getRoomTypeSellingObjects($this->context->language->id) as $sellingObject) {
$sellingObjects[$sellingObject['id_room_type_selling_object']] = $sellingObject['name'];
}
$this->fields_list['selling_object'] = array(
'title' => $this->l('Selling object'),
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'a!id_selling_object',
'list' => $sellingObjects,
'optional' => true,
'class' => 'chosen',
);
$tourismTaxRulesGroups = array();
foreach (TaxRulesGroup::getTaxRulesGroups(true, true) as $taxRulesGroup) {
$tourismTaxRulesGroups[$taxRulesGroup['id_tax_rules_group']] = $taxRulesGroup['name'];
}
$this->fields_list['tourism_tax_rules_group'] = array(
'title' => $this->l('Tourism tax rule'),
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'a!id_tourism_tax_rules_group',
'list' => $tourismTaxRulesGroups,
'optional' => true,
'class' => 'chosen',
);
$this->fields_list['adults'] = array(
'title' => $this->l('Adults'),
'filter_key' => 'hrt!adults',

View File

@@ -644,11 +644,11 @@ class AdminStatsControllerCore extends AdminStatsTabController
if ($result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT
LEFT(`invoice_date`, 10) as date,
SUM(orr.`refunded_amount`) as total_refund_amount
SUM(orr.`refunded_amount` * (o.`total_paid_tax_excl` / o.`total_paid_tax_incl`) / o.`conversion_rate`) as total_refund_amount
FROM `'._DB_PREFIX_.'orders` o
LEFT JOIN `'._DB_PREFIX_.'order_return` orr ON (o.id_order = orr.id_order)
LEFT JOIN `'._DB_PREFIX_.'order_state` os ON (o.current_state = os.id_order_state)
WHERE orr.`payment_mode` != "" AND `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00"
WHERE os.`logable` = 1 AND o.`total_paid_tax_incl` > 0 AND orr.`payment_mode` != "" AND `invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00"
AND "'.pSQL($date_to).' 23:59:59"
AND (
EXISTS (
@@ -1646,9 +1646,9 @@ class AdminStatsControllerCore extends AdminStatsTabController
public static function getRevenue($dateFrom, $dateTo, $idHotel = false, $orderSource = '')
{
$sql = 'SELECT SUM(total_paid_tax_excl - refunded_amount)
$sql = 'SELECT SUM(GREATEST(total_paid_tax_excl - refunded_amount, 0))
FROM (SELECT o.`total_paid_tax_excl` / o.`conversion_rate` AS total_paid_tax_excl,
(SELECT IFNULL(SUM(orr.`refunded_amount`), 0) FROM`'._DB_PREFIX_.'order_return` orr WHERE orr.`id_order` = o.`id_order`) AS refunded_amount,
(SELECT IFNULL(SUM(orr.`refunded_amount`), 0) FROM`'._DB_PREFIX_.'order_return` orr WHERE orr.`id_order` = o.`id_order`) * IF(o.`total_paid_tax_incl` > 0, o.`total_paid_tax_excl` / o.`total_paid_tax_incl`, 1) / o.`conversion_rate` AS refunded_amount,
(SELECT hbd.`id_hotel` FROM`'._DB_PREFIX_.'htl_booking_detail` hbd WHERE hbd.`id_order` = o.`id_order` LIMIT 1) AS id_hotel
FROM `'._DB_PREFIX_.'orders` o

View File

@@ -336,6 +336,23 @@ class AdminTabsControllerCore extends AdminController
}
}
/**
* Prevent creating a tab whose class name is already used.
*
* @return ObjectModel|false
*/
public function processSave()
{
$className = trim((string) Tools::getValue('class_name'));
$idExisting = Tab::getIdFromClassName($className);
if ($idExisting && $idExisting != (int) $this->id_object) {
$this->errors[] = Tools::displayError('A tab with this class name already exists.');
return false;
}
return parent::processSave();
}
protected function afterImageUpload()
{
/** @var Tab $obj */

View File

@@ -52,6 +52,19 @@ class AdminTaxRulesGroupControllerCore extends AdminController
'name' => array(
'title' => $this->l('Name')
),
'is_tourism_tax_rule_group' => array(
'title' => $this->l('Tourism tax'),
'callback' => 'tourismTaxAsLabel',
'badge_success' => true,
'badge_danger' => true,
'type' => 'bool',
'align' => 'center',
'class' => 'fixed-width-sm',
'optional' => true,
'visible_default' => true,
'filter_key' => 'a!is_tourism_tax_rule_group',
'orderby' => false,
),
'active' => array(
'title' => $this->l('Enabled'),
'active' => 'status',
@@ -70,10 +83,15 @@ class AdminTaxRulesGroupControllerCore extends AdminController
)
);
$this->_select = 'a.`is_tourism_tax_rule_group` AS `badge_success`, IF(a.`is_tourism_tax_rule_group`, 0, 1) AS `badge_danger`';
$this->_where .= ' AND a.deleted = 0';
parent::__construct();
}
public function tourismTaxAsLabel($value, $row)
{
return $value ? $this->l('Yes') : $this->l('No');
}
public function initPageHeaderToolbar()
{

View File

@@ -138,7 +138,7 @@ class AdminThemesControllerCore extends AdminController
'icon' => 'icon-html5',
'tabs' => array(
'logo' => $this->l('Logo'),
'logo2' => $this->l('Invoice & Email Logos'),
'logo2' => $this->l('Documents & Email Logos'),
'icons' => $this->l('Icons'),
'mobile' => $this->l('Mobile'),
),
@@ -170,9 +170,9 @@ class AdminThemesControllerCore extends AdminController
'thumb' => (Configuration::get('PS_LOGO_MAIL') !== false && (bool)Tools::file_get_contents($this->context->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO_MAIL')))) ? $this->context->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO_MAIL')) : $this->context->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO'))
),
'PS_LOGO_INVOICE' => array(
'title' => $this->l('Invoice logo'),
'title' => $this->l('Documents logo'),
'desc' => ((Configuration::get('PS_LOGO_INVOICE') === false) ? '<span class="light-warning">'.$this->l('Warning: if no invoice logo is available, the main logo will be used instead.').'</span><br />' : ''),
'hint' => $this->l('Will appear on invoice headers.').' '.$this->l('Warning: you can use a PNG file for transparency, but it can take up to 1 second per page for processing. Please consider using JPG instead.'),
'hint' => $this->l('Will appear in the headers of invoices, payment receipts, booking vouchers, credit slips, and GRCs.').' '.$this->l('Warning: you can use a PNG file for transparency, but it can take up to 1 second per page for processing. Please consider using JPG instead.'),
'type' => 'file',
'name' => 'PS_LOGO_INVOICE',
'tab' => 'logo2',

View File

@@ -62,7 +62,7 @@ class ContactControllerCore extends FrontController
} elseif (!$id_customer_thread && !$subject) {
$this->errors[] = Tools::displayError('The title cannot be blank.');
} elseif (!$id_customer_thread && !Validate::isCleanHtml($subject)) {
$this->errors[] = Tools::displayError('Invalid subject$subject');
$this->errors[] = Tools::displayError('Invalid subject.');
} else if (!$id_customer_thread && $nameRequired && !trim($userName)) {
$this->errors[] = Tools::displayError('Name is required.');
} else if (!$id_customer_thread && trim($nameRequired) && !Validate::isGenericName($userName)) {
@@ -101,6 +101,9 @@ class ContactControllerCore extends FrontController
$id_order,
$id_contact,
' AND a.`status` !='. CustomerThread::QLO_CUSTOMER_THREAD_STATUS_CLOSED
.' AND a.`user_name` = \''.pSQL($userName).'\''
.' AND a.`phone` = \''.pSQL($phone).'\''
.' AND a.`subject` = \''.pSQL($subject).'\''
);
}

View File

@@ -590,7 +590,6 @@ class GuestTrackingControllerCore extends FrontController
));
$this->addJqueryPlugin(array('fancybox', 'scrollTo', 'footable', 'footable-sort'));
$this->addJqueryUI(array('ui.tooltip'), 'base', true);
// load Google Maps library if configured
if (!count($this->errors)) {

View File

@@ -43,20 +43,15 @@ class OrderConfirmationControllerCore extends FrontController
parent::init();
$this->id_cart = (int)(Tools::getValue('id_cart', 0));
$is_guest = false;
/* check if the cart has been made by a Guest customer, for redirect link */
if (Cart::isGuestCartByCartId($this->id_cart)) {
$is_guest = true;
$redirectLink = 'index.php?controller=guest-tracking';
} else {
$redirectLink = 'index.php?controller=history';
}
$this->id_module = (int)(Tools::getValue('id_module', 0));
$this->id_order = Order::getOrderByCartId((int)($this->id_cart));
$this->secure_key = Tools::getValue('key', false);
$order = new Order((int)($this->id_order));
if ($is_guest) {
$is_guest = Cart::isGuestCartByCartId($this->id_cart);
$redirectLink = $is_guest ? 'index.php?controller=guest-tracking' : 'index.php?controller=history';
if ($is_guest && Validate::isLoadedObject($order) && $this->secure_key && hash_equals((string) $order->secure_key, (string) $this->secure_key)) {
$customer = new Customer((int)$order->id_customer);
$redirectLink .= '&id_order='.$order->reference.'&email='.urlencode($customer->email);
}
@@ -499,7 +494,6 @@ class OrderConfirmationControllerCore extends FrontController
$this->addJS(_THEME_JS_DIR_.'order-confirmation.js');
$this->addCSS(_THEME_CSS_DIR_.'order-confirmation.css');
$this->addJqueryPlugin(array('fancybox')); //fancybox not found for some client theme
$this->addJqueryUI('ui.tooltip', 'base', true);
}
}
}

View File

@@ -599,6 +599,16 @@ class OrderDetailControllerCore extends FrontController
}
if ($idServiceProductOrderDetails) {
foreach ($idServiceProductOrderDetails as $idServiceProductOrderDetail) {
$objServiceProductOrderDetail = new ServiceProductOrderDetail((int) $idServiceProductOrderDetail);
// the service line must exist and belong to the customer's own order
if (!Validate::isLoadedObject($objServiceProductOrderDetail)
|| $objServiceProductOrderDetail->id_order != $objOrder->id
) {
$this->errors[] = Tools::displayError('Something went wrong. Please try later.');
break;
}
if (OrderReturn::getOrdersReturnDetail($objOrder->id, 0, 0, $idServiceProductOrderDetail)) {
$this->errors[] = Tools::displayError('Some selected rooms have already been requested for cancellation.');
break;
@@ -837,7 +847,6 @@ class OrderDetailControllerCore extends FrontController
));
$this->addJqueryPlugin(array('fancybox', 'scrollTo', 'footable', 'footable-sort'));
$this->addJqueryUI(array('ui.tooltip'), 'base', true);
// load Google Maps library if configured
if ($idHotel = HotelBookingDetail::getIdHotelByIdOrder(Tools::getValue('id_order'))) {

View File

@@ -413,7 +413,6 @@ class OrderOpcControllerCore extends ParentOrderController
} else {
$this->addJS(_THEME_MOBILE_JS_DIR_.'opc.js');
}
$this->addJqueryUI(array('ui.tooltip'), 'base', true);
$this->addJS(array(
_THEME_JS_DIR_.'tools/statesManagement.js',

View File

@@ -129,7 +129,6 @@ class OurPropertiesControllerCore extends FrontController
'hotelsInfo' => $hotelsInfo,
'hotelLocationArray' => $hotelLocationArray,
'displayHotelMap' => $displayHotelMap,
'WK_HTL_SHORT_DESC' => Configuration::get('WK_HTL_SHORT_DESC', $this->context->language->id),
'currentIndex' => $this->context->link->getPageLink('our-properties')
)
);

View File

@@ -40,7 +40,6 @@ class ProductControllerCore extends FrontController
if (count($this->errors)) {
return;
}
$this->addJqueryUI(array('ui.tooltip'), 'base', true);
if (!$this->useMobileTheme()) {
$this->addCSS(_THEME_CSS_DIR_.'product.css');

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -131,10 +131,10 @@
<url_rewrite>order-slip</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>আমাদের সম্পত্তিসমূহ</title>
<title>সম্পত্তিসমূহ</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id='order' id_shop='1'>
<title>অর্ডার </title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>acompanhar-meu-pedido</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Nossas propriedades</title>
<title>Propriedades</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>propriedades</url_rewrite>
</meta>
<meta id='order-slip' id_shop='1'>
<title>Nota do pedido</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Naše nemovitosti</title>
<title>Nemovitosti</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>nemovitosti</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Dobropis</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>bestellungsverfolgung</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Unsere Immobilien</title>
<title>Immobilien</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>immobilien</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Bestellschein</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>seguimiento-pedido</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Nuestras propiedades</title>
<title>Propiedades</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>propiedades</url_rewrite>
</meta>
<meta id='order-slip' id_shop='1'>
<title>Albarán</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>املاک ما</title>
<title>املاک</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>رسید سفارش</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>suivi-commande</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Nos propriétés</title>
<title>Propriétés</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>proprietes</url_rewrite>
</meta>
<meta id='order-slip' id_shop='1'>
<title>Avoirs</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>מעקב-הזמנות</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>הנכסים שלנו</title>
<title>נכסים</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>נכסים</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>שוברי הזמנה</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -131,10 +131,10 @@
<url_rewrite>order-slip</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order" id_shop="1">
<title>Order</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>pantau-order</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Properti kami</title>
<title>Properti</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properti</url_rewrite>
</meta>
<meta id='order-slip' id_shop='1'>
<title>Slip order</title>

View File

@@ -131,10 +131,10 @@
<url_rewrite>buono-ordine</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Le nostre proprietà</title>
<title>Proprietà</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>proprieta</url_rewrite>
</meta>
<meta id='order' id_shop='1'>
<title>Ordine</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Order slip</title>

View File

@@ -178,4 +178,10 @@
<url_rewrite>product-vergelijking</url_rewrite>
</meta>
-->
<meta id='our-properties' id_shop='1'>
<title>Eigendommen</title>
<description/>
<keywords/>
<url_rewrite>eigendommen</url_rewrite>
</meta>
</entity_meta>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Order slip</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>sledzenie-zamowienia</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Nasze nieruchomości</title>
<title>Nieruchomości</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>nieruchomosci</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Pokwitowania</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>acompanhar-encomenda</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Nossas propriedades</title>
<title>Propriedades</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>propriedades</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Nota de Encomenda</title>

View File

@@ -178,4 +178,10 @@
<url_rewrite>comparaison-produits</url_rewrite>
</meta>
-->
<meta id='our-properties' id_shop='1'>
<title>Propriétés</title>
<description/>
<keywords/>
<url_rewrite>proprietes</url_rewrite>
</meta>
</entity_meta>

View File

@@ -125,10 +125,10 @@
<url_rewrite>returnari</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Proprietățile noastre</title>
<title>Proprietăți</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>proprietati</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Bon de comandă</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Наши объекты</title>
<title>Объекты</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Бланк заказа</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -119,10 +119,10 @@
<url_rewrite>my-account</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-follow" id_shop="1">
<title>Order follow</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Credit slip</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>我們的物業</title>
<title>物業</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>訂購單</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Các bất động sản của chúng tôi</title>
<title>Bất động sản</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Phiếu tín dụng</title>

View File

@@ -125,10 +125,10 @@
<url_rewrite>order-follow</url_rewrite>
</meta>
<meta id='our-properties' id_shop='1'>
<title>Our Properties</title>
<title>Properties</title>
<description/>
<keywords/>
<url_rewrite>our-properties</url_rewrite>
<url_rewrite>properties</url_rewrite>
</meta>
<meta id="order-slip" id_shop="1">
<title>Order slip</title>

View File

@@ -1130,6 +1130,7 @@ $(document).ready(function() {
if (!jsonData.hasError) {
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
initUITooltip();
}
showSuccessMessage(txtExtraServiceSucc);
} else {
@@ -1191,6 +1192,7 @@ $(document).ready(function() {
if (!jsonData.hasError) {
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
initUITooltip();
}
showSuccessMessage(txtExtraServiceSucc);
} else {
@@ -1359,7 +1361,7 @@ $(document).ready(function() {
},
complete: function() {
$(".loading_overlay").hide();
initTooltip();
initUITooltip();
}
});
});
@@ -2358,6 +2360,7 @@ const AddRoomBookingModal = {
objDateToMin.setDate(objDateToMin.getDate() + 1);
$('#new_room .add_room_date_to').datepicker('option', 'minDate', objDateToMin);
AddRoomBookingModal.updateRoomPrice();
},
beforeShow : function () {
if(allowBackdateOrder) {
@@ -2373,6 +2376,9 @@ const AddRoomBookingModal = {
{
showOtherMonths: true,
dateFormat: 'dd-mm-yy',
onSelect: function() {
AddRoomBookingModal.updateRoomPrice();
},
beforeShow : function () {
var date_from = $.datepicker.parseDate('dd-mm-yy', $(this).closest('.bookingDuration').find('.add_room_date_from').val());
date_from.setDate(date_from.getDate() + 1);
@@ -2381,6 +2387,43 @@ const AddRoomBookingModal = {
}
});
},
// Fetch the room price for the selected dates (advance price rules depend on stay duration) and update the price fields
updateRoomPrice: function() {
const dateFrom = $('#new_room .add_room_date_from').val();
const dateTo = $('#new_room .add_room_date_to').val();
const idProduct = $('#add_product_product_id').val();
if (!dateFrom || !dateTo || !parseInt(idProduct)) {
return;
}
const objDateFrom = $.datepicker.parseDate('dd-mm-yy', dateFrom);
const objDateTo = $.datepicker.parseDate('dd-mm-yy', dateTo);
if (objDateTo <= objDateFrom) {
return;
}
$.ajax({
type: 'POST',
url: admin_order_tab_link,
dataType: 'JSON',
cache: false,
data: {
ajax: 1,
token: token,
action: 'getEditRoomPrice',
id_order: id_order,
id_product: idProduct,
date_from: $.datepicker.formatDate('yy-mm-dd', objDateFrom),
date_to: $.datepicker.formatDate('yy-mm-dd', objDateTo),
},
success: function(result) {
if (result.success) {
$('#add_product_product_price_tax_excl').val(result.unit_price_tax_excl);
$('#add_product_product_price_tax_incl').val(result.unit_price_tax_incl);
}
}
});
},
close: function() {
$('#add-room-booking-modal').modal('hide');
},
@@ -2437,7 +2480,7 @@ const EditRoomBookingModal = {
// initialize datepickers
EditRoomBookingModal.initDatePickers();
initTooltip();
initUITooltip();
$('#edit_product .extra-services-container #id_htl_booking').val(jsonProductLineData.id);
$('#edit-room-booking-modal').modal('show');
} else {
@@ -2450,6 +2493,48 @@ const EditRoomBookingModal = {
}
});
},
// Fetch the room price for the selected dates (advance price rules depend on stay duration) and update the price field
updateRoomPrice: function() {
const dateFrom = $('#edit_product .edit_product_date_from').val();
const dateTo = $('#edit_product .edit_product_date_to').val();
if (!dateFrom || !dateTo) {
return;
}
const objDateFrom = $.datepicker.parseDate('dd-mm-yy', dateFrom);
const objDateTo = $.datepicker.parseDate('dd-mm-yy', dateTo);
if (objDateTo <= objDateFrom) {
return;
}
$.ajax({
type: 'POST',
url: admin_order_tab_link,
dataType: 'JSON',
cache: false,
data: {
ajax: 1,
token: token,
action: 'getEditRoomPrice',
id_order: $('#edit_product input[name="id_order"]').val(),
id_product: $('#edit_product input[name="id_product"]').val(),
id_room: $('#edit_product input[name="id_room"]').val(),
date_from: $.datepicker.formatDate('yy-mm-dd', objDateFrom),
date_to: $.datepicker.formatDate('yy-mm-dd', objDateTo),
},
beforeSend: function() {
$('#edit_product .room_unit_price').prop('readonly', true);
},
success: function(result) {
if (result.success) {
$('#edit_product .room_unit_price').val(result.unit_price_tax_excl);
}
},
complete: function() {
$('#edit_product .room_unit_price').prop('readonly', false);
}
});
},
initDatePickers: function() {
$('#edit_product .edit_product_date_from').datepicker({
showOtherMonths: true,
@@ -2460,6 +2545,7 @@ const EditRoomBookingModal = {
objDateToMin.setDate(objDateToMin.getDate() + 1);
$('#edit_product .edit_product_date_to').datepicker('option', 'minDate', objDateToMin);
EditRoomBookingModal.updateRoomPrice();
},
beforeShow : function () {
if(allowBackdateOrder) {
@@ -2475,6 +2561,9 @@ const EditRoomBookingModal = {
showOtherMonths: true,
dateFormat: 'dd-mm-yy',
altField: '#edit_product .edit_product_date_to_actual',
onSelect: function() {
EditRoomBookingModal.updateRoomPrice();
},
beforeShow : function () {
var date_from = $.datepicker.parseDate('dd-mm-yy', $(this).closest('.form-group').find('.edit_product_date_from').val());
date_from.setDate(date_from.getDate() + 1);

11
js/jquery-ui-tooltip-alias.js vendored Normal file
View File

@@ -0,0 +1,11 @@
/* Preserve jQuery UI's tooltip widget under $.fn.uiTooltip before it may be
* overwritten (e.g. by Bootstrap re-registering $.fn.tooltip). Shared by both
* the back office and front office, since the load order differs between the
* two but the aliasing logic itself doesn't depend on either context. */
(function ($) {
'use strict';
if ($ && $.fn && $.isFunction($.fn.tooltip) && !$.fn.tooltip.Constructor) {
$.fn.uiTooltip = $.fn.tooltip;
}
}(window.jQuery));

View File

@@ -50,9 +50,6 @@ class BankwirePaymentModuleFrontController extends ModuleFrontController
$total = $cart->getOrderTotal(true, Cart::BOTH);
}
// check all service products are available
ServiceProductCartDetail::validateServiceProductsInCart();
$restrict_order = false;
/*Check Order restrict condition before Payment by the customer*/
if (Module::isInstalled('hotelreservationsystem') && Module::isEnabled('hotelreservationsystem')) {

View File

@@ -49,9 +49,6 @@ class BankwireValidationModuleFrontController extends ModuleFrontController
if (!$authorized)
die($this->module->l('This payment method is not available.', 'validation'));
// check all service products are available
ServiceProductCartDetail::validateServiceProductsInCart();
// Check Order restrict condition before Payment by the customer
if (Module::isInstalled('hotelreservationsystem') && Module::isEnabled('hotelreservationsystem')) {
require_once _PS_MODULE_DIR_.'hotelreservationsystem/define.php';

View File

@@ -273,7 +273,7 @@
<div class="layer_cart_row">
<strong class="dark">
{l s='Total Rooms Cost in cart' mod='blockcart'}
{if $display_tax_label}
{if $use_taxes && $display_tax_label}
{if $priceDisplay == 1}
{l s='(tax excl.)' mod='blockcart'}
{else}
@@ -292,7 +292,7 @@
<div class="layer_cart_row">
<strong class="dark">
{l s='Total Product Cost in cart' mod='blockcart'}
{if $display_tax_label}
{if $use_taxes && $display_tax_label}
{if $priceDisplay == 1}
{l s='(tax excl.)' mod='blockcart'}
{else}
@@ -331,7 +331,7 @@
{/if} -->
<!-- <div class="layer_cart_row">
<strong class="dark{if $shipping_cost_float == 0 && (!isset($cart->id_address_delivery) || !$cart->id_address_delivery)} unvisible{/if}">
{l s='Total shipping' mod='blockcart'}&nbsp;{if $display_tax_label}{if $priceDisplay == 1}{l s='(tax excl.)' mod='blockcart'}{else}{l s='(tax incl.)' mod='blockcart'}{/if}{/if}
{l s='Total shipping' mod='blockcart'}&nbsp;{if $use_taxes && $display_tax_label}{if $priceDisplay == 1}{l s='(tax excl.)' mod='blockcart'}{else}{l s='(tax incl.)' mod='blockcart'}{/if}{/if}
</strong>
<span class="ajax_cart_shipping_cost{if $shipping_cost_float == 0 && (!isset($cart->id_address_delivery) || !$cart->id_address_delivery)} unvisible{/if}">
{if $shipping_cost_float == 0}
@@ -346,7 +346,7 @@
<div class="layer_cart_row">
<strong class="dark">
{l s='Convenience Fees' mod='blockcart'}
{if $display_tax_label}
{if $use_taxes && $display_tax_label}
{if $priceDisplay == 1}
{l s='(tax excl.)' mod='blockcart'}
{else}
@@ -386,7 +386,7 @@
<div class="layer_cart_row">
<strong class="dark">
{l s='Total' mod='blockcart'}
{if $display_tax_label}
{if $use_taxes && $display_tax_label}
{if $priceDisplay == 1}
{l s='(tax excl.)' mod='blockcart'}
{else}

View File

@@ -193,7 +193,7 @@ class WkCustomNavigationLink extends ObjectModel
'link' => 'index',
),
array(
'name' => 'Our Properties',
'name' => 'Properties',
'id_cms' => 0,
'show_at_navigation' => 1,
'show_at_footer' => 0,

View File

@@ -50,9 +50,6 @@ class ChequePaymentModuleFrontController extends ModuleFrontController
$total = $cart->getOrderTotal(true, Cart::BOTH);
}
// check all service products are available
ServiceProductCartDetail::validateServiceProductsInCart();
$restrict_order = false;
/*Check Order restrict condition before Payment by the customer*/
if (Module::isInstalled('hotelreservationsystem') && Module::isEnabled('hotelreservationsystem')) {

View File

@@ -48,9 +48,6 @@ class ChequeValidationModuleFrontController extends ModuleFrontController
if (!$authorized)
die($this->module->l('This payment method is not available.', 'validation'));
// check all service products are available
ServiceProductCartDetail::validateServiceProductsInCart();
/*Check Order restrict condition before Payment by the customer*/
if (Module::isInstalled('hotelreservationsystem') && Module::isEnabled('hotelreservationsystem')) {
require_once _PS_MODULE_DIR_.'hotelreservationsystem/define.php';

View File

@@ -178,7 +178,9 @@ class Dashgoals extends Module
{
$year = ((isset($params['extra']) && $params['extra'] > 1970 && $params['extra'] < 2999) ? $params['extra'] : Configuration::get('PS_DASHGOALS_CURRENT_YEAR'));
return array('data_chart' => array('dash_goals_chart1' => $this->getChartData($year)));
$idHotel = isset($params['id_hotel']) ? (int) $params['id_hotel'] : 0;
return array('data_chart' => array('dash_goals_chart1' => $this->getChartData($year, $idHotel)));
}
protected function fakeConfigurationKPI_get($key)
@@ -198,7 +200,7 @@ class Dashgoals extends Module
}
}
public function getChartData($year)
public function getChartData($year, $idHotel = 0)
{
// There are stream types (different charts) and for each types there are 3 available zones (one color for the goal, one if you over perform and one if you under perfom)
$stream_types = array(
@@ -370,8 +372,8 @@ class Dashgoals extends Module
} else {
// Retrieve gross data from AdminStatsController
$visits = AdminStatsController::getVisits(false, $year.date('-01-01'), $year.date('-12-31'), 'month');
$orders = AdminStatsController::getOrders($year.date('-01-01'), $year.date('-12-31'), 'month');
$sales = AdminStatsController::getTotalSales($year.date('-01-01'), $year.date('-12-31'), 'month');
$orders = AdminStatsController::getOrders($year.date('-01-01'), $year.date('-12-31'), 'month', $idHotel);
$sales = AdminStatsController::getTotalSales($year.date('-01-01'), $year.date('-12-31'), 'month', $idHotel);
// Now we can calculate the value for every months
for ($i = '01'; $i <= 12; $i = sprintf('%02d', $i + 1)) {

View File

@@ -57,7 +57,7 @@
<section class="loading text-center">
<div class="alert alert-info text-left">
<p>{l s='Set your targets by clicking the configuration button at right position of the header in this section.' mod='dashgoals'}</p>
<p><b>{l s='Note' mod='dashgoals'}:</b> {l s='Targets will be set and data will be displayed for all the hotels.' mod='dashgoals'}</p>
<p><b>{l s='Note' mod='dashgoals'}:</b> {l s='Targets are common for all the hotels, while the data is displayed for the selected hotel.' mod='dashgoals'}</p>
</div>
<div class="dashgoals row">
<div class="col-xs-6 col-sm-3">

View File

@@ -260,7 +260,7 @@ class DashProducts extends Module
FROM `'._DB_PREFIX_.'htl_booking_detail` hbd
LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = hbd.`id_order`)
WHERE o.`invoice_date` BETWEEN "'.pSQL($date_from).' 00:00:00" AND "'.pSQL($date_to).' 23:59:59"
AND o.`valid` = 1 AND hbd.`id` NOT IN ('.OrderReturn::getRefundedBookingIdsSubquery().').'.
AND o.`valid` = 1 AND hbd.`id` NOT IN ('.OrderReturn::getRefundedBookingIdsSubquery().')'.
(!is_null($id_hotel) ? HotelBranchInformation::addHotelRestriction($id_hotel, 'hbd') : '').'
GROUP BY hbd.`id_product`
ORDER BY `sales` DESC

View File

@@ -146,15 +146,17 @@ class Dashtrends extends Module
$refined_data['net_profits'][$date] = 0;
// calculate actual values now for current date from available $gross_data to be used to display in line chart
$refined_data['sales'][$date] = isset($gross_data['total_paid_tax_excl'][$date]) ? $gross_data['total_paid_tax_excl'][$date] : 0;
// sales are net of refunded amount
$refunds = isset($gross_data['total_refunds'][$date]) ? $gross_data['total_refunds'][$date] : 0;
$refined_data['sales'][$date] = (isset($gross_data['total_paid_tax_excl'][$date]) ? $gross_data['total_paid_tax_excl'][$date] : 0) - $refunds;
$refined_data['orders'][$date] = isset($gross_data['orders'][$date]) ? $gross_data['orders'][$date] : 0;
$refined_data['average_cart_value'][$date] = $refined_data['orders'][$date] ? $refined_data['sales'][$date] / $refined_data['orders'][$date] : 0;
$refined_data['visits'][$date] = isset($gross_data['visits'][$date]) ? $gross_data['visits'][$date] : 0;
$refined_data['conversion_rate'][$date] = $refined_data['visits'][$date] ? ($refined_data['orders'][$date] / $refined_data['visits'][$date] * 100) : 0;
$refined_data['net_profits'][$date] += (isset($gross_data['total_paid_tax_excl'][$date]) ? $gross_data['total_paid_tax_excl'][$date] : 0);
// sales already have refunds deducted
$refined_data['net_profits'][$date] += $refined_data['sales'][$date];
$refined_data['net_profits'][$date] -= (isset($gross_data['total_purchases'][$date]) ? $gross_data['total_purchases'][$date] : 0);
$refined_data['net_profits'][$date] -= (isset($gross_data['total_expenses'][$date]) ? $gross_data['total_expenses'][$date] : 0);
$refined_data['net_profits'][$date] -= (isset($gross_data['total_refunds'][$date]) ? $gross_data['total_refunds'][$date] : 0);
}
return $refined_data;

Some files were not shown because too many files have changed in this diff Show More