Merge branch 'Qloapps:develop' into gli-3097

This commit is contained in:
Shazar Rahman
2026-09-11 16:24:11 +05:30
committed by GitHub
290 changed files with 16318 additions and 7629 deletions

View File

@@ -127,4 +127,4 @@ if (Tools::isSubmit('getZones')) {
if (Tools::isSubmit('getEmailHTML') && $email = Tools::getValue('email')) {
$email_html = AdminTranslationsController::getEmailHTML($email);
die($email_html);
}
}

View File

@@ -125,7 +125,7 @@ var // currently active contextMenu trigger
offset = {top: y, left: x};
}
// correct offset if viewport demands it
// correct offset if viewport it
var bottom = $win.scrollTop() + $win.height(),
right = $win.scrollLeft() + $win.width(),
height = opt.$menu.height(),

View File

@@ -107,92 +107,42 @@
</td>
<td>{displayWtPriceWithCurrency price=$room['feature_price_tax_excl'] currency=$currency}</td>
<td>
{if (isset($room['selected_demands']) && $room['selected_demands']) || (isset($room['selected_services']) && $room['selected_services'])}
<a href="#" data-toggle="modal" data-target="#rooms_type_extra_demands_{$room['id']}">
{displayWtPriceWithCurrency price=($room['demand_price'] + $room['additional_service_price'] + $room['additional_services_auto_add_price'])|escape:'html':'UTF-8' currency=$currency}
{if isset($room['selected_services']) && $room['selected_services']}
<a href="#" data-toggle="modal" data-target="#rooms_type_extra_services_{$room['id']}">
{displayWtPriceWithCurrency price=($room['additional_service_price'] + $room['additional_services_auto_add_price'])|escape:'html':'UTF-8' currency=$currency}
</a>
{else}
{displayWtPriceWithCurrency price=0 currency=$currency}
{/if}
</td>
<td class="text-right">
{if (isset($room['selected_demands']) && $room['selected_demands']) || (isset($room['selected_services']) && $room['selected_services'])}
{displayWtPriceWithCurrency price=($room['amt_with_qty'] + $room['additional_services_auto_add_price'] + $room['demand_price'] + $room['additional_service_price'])|escape:'html':'UTF-8' currency=$currency}
{if isset($room['selected_services']) && $room['selected_services']}
{displayWtPriceWithCurrency price=($room['amt_with_qty'] + $room['additional_services_auto_add_price'] + $room['additional_service_price'])|escape:'html':'UTF-8' currency=$currency}
{else}
{displayWtPriceWithCurrency price=$room['amt_with_qty']|escape:'html':'UTF-8' currency=$currency}
{/if}
</td>
</tr>
<div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_demands_{$room['id']}">
<div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_services_{$room['id']}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body" id="rooms_extra_demands">
<div class="modal-body" id="rooms_extra_services">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<ul class="nav nav-tabs" role="tablist">
{if isset($room['selected_demands']) && $room['selected_demands']}
<li role="presentation" class="active"><a href="#room_type_demands_desc_{$room['id']}" aria-controls="facilities" role="tab" data-toggle="tab">{l s='Facilities'}</a></li>
{/if}
{if isset($room['selected_services']) && $room['selected_services']}
<li role="presentation" {if !isset($room['selected_demands']) || !$room['selected_demands']}class="active"{/if}><a href="#room_type_service_product_desc_{$room['id']}" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
{/if}
<li role="presentation" class="active" ><a href="#room_type_service_product_desc_{$room['id']}" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
</ul>
<div class="tab-content panel">
{if isset($room['selected_demands']) && $room['selected_demands']}
<div id="room_type_demands_desc_{$room['id']}" class="tab-pane active">
<div id="room_type_demands_desc">
{if isset($room['selected_demands']) && $room['selected_demands']}
{assign var=roomCount value=1}
{foreach $room['selected_demands'] as $demand}
<div class="row room_demands_container">
<div class="col-sm-12 room_demand_detail">
{if isset($room['selected_demands']) && $room['selected_demands']}
{foreach $room['extra_demands'] as $idGlobalDemand => $roomDemand}
{if $demand.id_global_demand == $idGlobalDemand}
<div class="row room_demand_block">
<div class="col-xs-6">
<div class="row">
<div class="col-xs-10 demand_adv_option_block">
<p>
{$roomDemand['name']|escape:'html':'UTF-8'}<br>
{if isset($roomDemand['adv_option']) && $roomDemand['adv_option']}
{$roomDemand['adv_option'][$demand['id_option']]['name']}
{/if}
</p>
</div>
</div>
</div>
<div class="col-xs-6">
<p><span class="pull-right extra_demand_option_price">
{if isset($roomDemand['adv_option']) && $roomDemand['adv_option']}
{convertPrice price = $roomDemand['adv_option'][$demand['id_option']]['price_tax_excl']|escape:'html':'UTF-8'}
{else}
{convertPrice price = $roomDemand['price_tax_excl']|escape:'html':'UTF-8'}
{/if}
</span></p>
</div>
</div>
{/if}
{/foreach}
{/if}
</div>
</div>
{assign var=roomCount value=$roomCount+1}
{/foreach}
{/if}
</div>
</div>
{/if}
{if isset($room['selected_services']) && $room['selected_services']}
<div id="room_type_service_product_desc_{$room['id']}" class="tab-pane{if !isset($room['selected_demands']) || !$room['selected_demands']} active{/if}">
<div id="room_type_service_product_desc_{$room['id']}" class="tab-pane active">
<div id="room_type_services_desc">
{assign var=roomCount value=1}
<div class="row room_demands_container">
<div class="col-sm-12 room_demand_detail">
<div class="row room_service_container">
<div class="col-sm-12 room_service_detail">
{if isset($room['selected_services']) && $room['selected_services']}
{foreach $room['selected_services'] as $service}
<div class="row room_demand_block">
<div class="row room_service_block">
<div class="col-xs-5">
<div class="row">
<div class="col-xs-10">

View File

@@ -72,6 +72,12 @@
</p>
</div>
</div>
<div class="row">
<label class="control-label col-lg-3">{l s='Nationality'}</label>
<div class="col-lg-9">
<p class="form-control-static">{if $nationality}{$nationality}{else}--{/if}</p>
</div>
</div>
<div class="row">
<label class="control-label col-lg-3">{l s='Registration Date'}</label>
<div class="col-lg-9">

View File

@@ -187,6 +187,7 @@ $(document).ready(function () {
</div>
</div>
{/if}
{* Code For eco-tax working
<div class="form-group" {if !$ps_use_ecotax} style="display:none;"{/if}>
<div class="col-lg-1"><span class="pull-right">{include file="controllers/products/multishop/checkbox.tpl" field="ecotax" type="default"}</span></div>
<label class="control-label col-lg-2" for="ecotax">
@@ -197,6 +198,9 @@ $(document).ready(function () {
<input maxlength="27" id="ecotax" name="ecotax" type="text" value="{$product->ecotax|string_format:$priceDisplayPrecisionFormat}" onkeyup="$('#priceType').val('TI');if (isArrowKey(event))return; calcPriceTE(); this.value = this.value.replace(/,/g, '.'); if (parseInt(this.value) > getE('priceTE').value) this.value = getE('priceTE').value; if (isNaN(this.value)) this.value = 0;" />
</div>
</div>
*}
{include file="controllers/products/_tourism_tax_rule_field.tpl"}
{* <div class="form-group {if $product->auto_add_to_cart && $product->price_addition_type == Product::PRICE_ADDITION_TYPE_WITH_ROOM}hide_on_auto_add_Withroom{/if}" {if !$country_display_tax_label || $tax_exclude_taxe_option}style="display:none;"{/if} {if $product->auto_add_to_cart && $product->price_addition_type == Product::PRICE_ADDITION_TYPE_WITH_ROOM}style="display:none"{/if}>
<label class="control-label col-lg-3" for="priceTI">{l s='Retail price with tax'}</label>
<div class="input-group col-lg-2">

View File

@@ -100,6 +100,8 @@
});
}
{/if}
changeStandardProductAddressType();
});
</script>
{/if}
@@ -110,6 +112,5 @@
<script type="text/javascript">
changeCMSActivationAuthorization();
changeOverbookingOrderAction();
changeStandardProductAddressType();
</script>
{/block}

View File

@@ -1,113 +0,0 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_demands">
<div class="modal-dialog modal-lg" 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 icon-bed"></i> &nbsp;{l s='Room Services'}</h4>
</div>
<div class="modal-body" id="rooms_extra_demands">
<ul class="nav nav-tabs" role="tablist">
{if isset($selectedRoomDemands) && $selectedRoomDemands}
<li role="presentation" class="active"><a href="#room_type_demands_desc" aria-controls="facilities" role="tab" data-toggle="tab">{l s='Facilities'}</a></li>
{/if}
<li role="presentation" {if !isset($selectedRoomDemands) || !$selectedRoomDemands}class="active"{/if}><a href="#room_type_service_product_desc" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
</ul>
<div class="tab-content">
{if isset($selectedRoomDemands) && $selectedRoomDemands}
<div id="room_type_demands_desc" class="tab-pane active">
<div id="room_type_demands_desc">
{if isset($selectedRoomDemands) && $selectedRoomDemands}
{assign var=roomCount value=1}
{foreach $selectedRoomDemands as $key => $roomDemand}
<div class="row room_demands_container">
<div class="col-sm-12 room_demand_detail">
{if isset($roomTypeDemands) && $roomTypeDemands}
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>{l s='Name'}</th>
<th>{l s='Options'}</th>
<th>{l s='Unit Price (tax excl.)'}</th>
</tr>
</thead>
<tbody>
{foreach $roomTypeDemands as $idGlobalDemand => $demand}
<tr class="room_demand_block">
<td>
<input id_cart_booking="{$roomDemand['id']}" value="{$idGlobalDemand|escape:'html':'UTF-8'}" type="checkbox" class="id_room_type_demand" {if isset($roomDemand['selected_global_demands']) && $roomDemand['selected_global_demands'] && ($idGlobalDemand|in_array:$roomDemand['selected_global_demands'])}checked{/if} />
</td>
<td class="demand_adv_option_block">
<p>{$demand['name']|escape:'html':'UTF-8'}</p>
</td>
<td class="demand_adv_option_block">
{if isset($demand['adv_option']) && $demand['adv_option']}
<select class="id_option">
{foreach $demand['adv_option'] as $idOption => $option}
{assign var=demand_key value="`$idGlobalDemand`-`$idOption`"}
<option optionPrice="{$option['price_tax_excl']|escape:'html':'UTF-8'}" value="{$idOption|escape:'html':'UTF-8'}" {if isset($roomDemand['extra_demands'][$demand_key])}selected{/if} key="{$demand_key}">{$option['name']}</option>
{if isset($roomDemand['extra_demands'][$demand_key])}
{assign var=selected_adv_option value="$idOption"}
{/if}
{/foreach}
</select>
{else}
--
<input type="hidden" class="id_option" value="0" />
{/if}
</td>
<td>
<span class="extra_demand_option_price">
{if isset($selected_adv_option) && isset($demand['adv_option'][$selected_adv_option]['price_tax_excl'])}{convertPrice price = $demand['adv_option'][$selected_adv_option]['price_tax_excl']|escape:'html':'UTF-8'}{else if isset($demand['adv_option']) && $demand['adv_option']}{convertPrice price = $demand['adv_option'][$demand['adv_option']|@key]['price_tax_excl']}{else}{convertPrice price = $demand['price_tax_excl']|escape:'html':'UTF-8'}{/if}
</span>
{if $demand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY}
{l s='/ night'}
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{/if}
</div>
</div>
{assign var=roomCount value=$roomCount+1}
{/foreach}
{/if}
</div>
</div>
{/if}
{include file='controllers/orders/modals/_add_order_extra_services_tab_content.tpl'}
</div>
{if isset($loaderImg) && $loaderImg}
<div class="loading_overlay">
<img src='{$loaderImg}' class="loading-img"/>
</div>
{/if}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,45 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_services">
<div class="modal-dialog modal-lg" 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 icon-bed"></i> &nbsp;{l s='Room Services'}</h4>
</div>
<div class="modal-body" id="rooms_extra_services">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#room_type_service_product_desc" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
</ul>
<div class="tab-content">
{include file='controllers/orders/modals/_add_order_extra_services_tab_content.tpl'}
</div>
{if isset($loaderImg) && $loaderImg}
<div class="loading_overlay">
<img src='{$loaderImg}' class="loading-img"/>
</div>
{/if}
</div>
</div>
</div>
</div>

View File

@@ -137,13 +137,13 @@
</div>
</td>
<td>
{displayPrice price=($data.demand_price + $data.additional_service_price + $data.additional_services_auto_add_price)|escape:'html':'UTF-8'}
{displayPrice price=($data.additional_service_price + $data.additional_services_auto_add_price)|escape:'html':'UTF-8'}
</td>
{* <td class="cart_line_total_rooms_price" id="cart_detail_data_price_{$data.id|escape:'html':'UTF-8'}">
{displayPrice price=$data.amt_with_qty}</td> *}
<td class="cart_line_total_price">
{if (isset($data.extra_demands) && $data.extra_demands) || (isset($data.additional_service) && $data.additional_service) || (isset($data.selected_services) && $data.selected_services)}
{displayPrice price=($data.amt_with_qty + $data.additional_services_auto_add_price + $data.demand_price + $data.additional_service_price)|escape:'html':'UTF-8'}
{if isset($data.additional_service) && $data.additional_service}
{displayPrice price=($data.amt_with_qty + $data.additional_services_auto_add_price + $data.additional_service_price)|escape:'html':'UTF-8'}
{else}
{displayPrice price=$data.amt_with_qty|escape:'html':'UTF-8'}
{/if}
@@ -153,7 +153,7 @@
<i class="icon-trash"></i>&nbsp;{l s='Delete'}
</button>
<br />
<a href="#" id_hotel_cart_booking="{$data.id|escape:'html':'UTF-8'}" id_room="{$data.id_room|escape:'html':'UTF-8'}" date_from="{$data.date_from|escape:'html':'UTF-8'}" date_to="{$data.date_to|escape:'html':'UTF-8'}" id_product="{$data.id_product|escape:'html':'UTF-8'}" id_cart="{$data.id_cart|escape:'html':'UTF-8'}" class="open_rooms_extra_demands btn btn-success" title="{l s='Click here to add or remove the extra services of this room type.'}">
<a href="#" id_hotel_cart_booking="{$data.id|escape:'html':'UTF-8'}" id_room="{$data.id_room|escape:'html':'UTF-8'}" date_from="{$data.date_from|escape:'html':'UTF-8'}" date_to="{$data.date_to|escape:'html':'UTF-8'}" id_product="{$data.id_product|escape:'html':'UTF-8'}" id_cart="{$data.id_cart|escape:'html':'UTF-8'}" class="open_rooms_extra_services btn btn-success" title="{l s='Click here to add or remove the extra services of this room type.'}">
<i class="icon-pencil"></i>&nbsp;{l s='Services'}
</a>
</td>
@@ -168,31 +168,22 @@
</div>
{* Modal for extra demands *}
{* <div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_demands">
{* <div class="modal" tabindex="-1" role="dialog" id="rooms_type_extra_services">
</div> *}
{strip}
{addJsDefL name=txtExtraDemandSucc}{l s='Updated Successfully' js=1}{/addJsDefL}
{addJsDefL name=txtExtraDemandErr}{l s='Some error occurred while updating demands' js=1}{/addJsDefL}
{/strip}
{* Css for handling extra demands changes *}
{* Css for handling extra changes *}
<style type="text/css">
#customer_cart_details .extra-demand-list {
padding-left:15px;}
#customer_cart_details .delete_hotel_cart_data {
margin-bottom:2px !important;}
#customer_cart_details .room_type_old_price {
text-decoration: line-through;
color:#979797;
font-size:12px;}
/*Extra demands CSS*/
#rooms_extra_demands .rooms_extra_demands_head {
margin-bottom: 18px;}
#rooms_extra_demands .room_demand_block {
margin-bottom: 15px;
color: #333;}
#room_type_service_product_desc #back_to_service_btn {
display: none;}
#add_new_room_services_block {

View File

@@ -69,6 +69,23 @@
</td>
<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>
</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>
{/if}
</td>
<td>
<span>{displayPrice price=$product.total_price_tax_incl currency=$currency->id}</span>
@@ -136,6 +153,23 @@
{l s='Delete'}
</a>
</li>
{if isset($use_tourism_tax) && $use_tourism_tax && isset($product.tourism_tax_status) && $product.tourism_tax_status != $tourism_tax_status_not_applicable && !$product.is_cancelled && !$product.is_refunded}
{if $product.tourism_tax_status == $tourism_tax_status_applied}
<li>
<a href="#" class="tt-exempt-service-line" data-id_service_product_order_detail="{$product.id_service_product_order_detail|intval}" data-label="{$product.name|escape:'html':'UTF-8'}">
<i class="icon-ban"></i>
{l s='Exempt Tourism Tax'}
</a>
</li>
{else}
<li>
<a href="#" class="tt-apply-service-line" data-id_service_product_order_detail="{$product.id_service_product_order_detail|intval}">
<i class="icon-check"></i>
{l s='Apply Tourism Tax'}
</a>
</li>
{/if}
{/if}
</ul>
</div>
{/if}

View File

@@ -96,8 +96,8 @@
</td>
<td class="center">
{convertPriceWithCurrency price=($data['extra_demands_price_te'] + $data['additional_services_price_te'] + $data['convenience_fee_te'] + $data['additional_services_price_auto_add_te']) currency=$currency->id}
{if $data['extra_demands']|count || $data['additional_services']|count}
{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']}">
<i class="icon icon-lg icon-info-circle"></i>
</a>
@@ -105,6 +105,21 @@
</td>
<td class="center">
{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>
</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>
{/if}
</div>
</td>
<td class="center">
{convertPriceWithCurrency price=($data['total_room_price_ti']) currency=$currency->id}
@@ -181,6 +196,23 @@
{l s='Delete'}
</a>
</li>
{if isset($use_tourism_tax) && $use_tourism_tax && isset($data.tourism_tax_status) && $data.tourism_tax_status != $tourism_tax_status_not_applicable && !$data.is_cancelled && !$data.is_refunded}
{if $data.tourism_tax_status == $tourism_tax_status_applied}
<li>
<a href="#" class="tt-exempt-booking" data-id_htl_booking="{$data.id|intval}" data-label="{$data.room_num|escape:'html':'UTF-8'} - {$data.room_type_name|escape:'html':'UTF-8'}: ({$data.date_from|date_format:"%d/%m/%Y"} - {$data.date_to|date_format:"%d/%m/%Y"})">
<i class="icon-ban"></i>
{l s='Exempt Tourism Tax'}
</a>
</li>
{else}
<li>
<a href="#" class="tt-apply-booking" data-id_htl_booking="{$data.id|intval}">
<i class="icon-check"></i>
{l s='Apply Tourism Tax'}
</a>
</li>
{/if}
{/if}
</ul>
{/if}
</div>

View File

@@ -40,8 +40,8 @@
{if (isset($refundReqBookings) && $refundReqBookings)}
<th class="center"><span class="title_box help-tooltip" data-toggle="tooltip" title="" data-original-title="{l s='Refund or cancellation status and refunded amount for this room booking'}">{l s='Refund'}</span></th>
{/if}
{if ($can_edit && !$order->hasBeenDelivered())}
<th class="fixed-width-md center"><span >{l s='Actions'}</span></th>
{if (isset($can_edit) && $can_edit && !$order->hasBeenDelivered())}
<th class="fixed-width-md"><span class="title_box">{l s='Actions'}</th>
{/if}
</tr>
</thead>
@@ -62,4 +62,6 @@
{l s='Room information not available.'}
</div>
</div>
{/if}
{/if}
{include file='controllers/orders/_tourism_tax_actions.tpl'}

View File

@@ -69,6 +69,23 @@
</td>
<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>
</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>
{/if}
</td>
<td>
<span>{displayPrice price=$product.total_price_tax_incl currency=$currency->id}</span>
@@ -136,6 +153,23 @@
{l s='Delete'}
</a>
</li>
{if isset($use_tourism_tax) && $use_tourism_tax && isset($product.tourism_tax_status) && $product.tourism_tax_status != $tourism_tax_status_not_applicable && !$product.is_cancelled && !$product.is_refunded}
{if $product.tourism_tax_status == $tourism_tax_status_applied}
<li>
<a href="#" class="tt-exempt-service-line" data-id_service_product_order_detail="{$product.id_service_product_order_detail|intval}" data-label="{$product.name|escape:'html':'UTF-8'}">
<i class="icon-ban"></i>
{l s='Exempt Tourism Tax'}
</a>
</li>
{else}
<li>
<a href="#" class="tt-apply-service-line" data-id_service_product_order_detail="{$product.id_service_product_order_detail|intval}">
<i class="icon-check"></i>
{l s='Apply Tourism Tax'}
</a>
</li>
{/if}
{/if}
</ul>
</div>
{/if}

View File

@@ -0,0 +1,179 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{* Shared tourism tax price-breakdown tooltip + apply/exempt modal & handlers — included wherever a
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>
<div class="modal fade" id="exempt-tourism-tax-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" 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>
<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>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="tt-exempt-confirm">
<i class="icon-ban"></i> {l s='Exempt 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) {
$.ajax({
type: 'POST',
url: admin_order_tab_link,
data: $.extend({ ajax: 1, action: action }, data),
dataType: 'json',
beforeSend: function () {
$('#page-loader').show();
},
success: function (resp) {
if (resp.hasError && resp.errors && resp.errors.length) {
showErrorMessage(resp.errors.join('<br>'));
} else {
window.location.href = admin_order_tab_link + '&conf=4&vieworder&id_order=' + id_order;
}
},
error: function () {
showErrorMessage('{l s='Tourism tax request failed. Please try again.' js=1}');
},
complete: function () {
$('#page-loader').hide();
}
});
}
$(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);
$('#tt-exempt-note').val('');
$('#exempt-tourism-tax-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);
});
$(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);
});
$(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);
});
$(document).on('click', '#tt-exempt-confirm', function (e) {
if (!ttExemptTarget) {
return;
}
$('#exempt-tourism-tax-modal').modal('hide');
ttAjax('ExemptTourismTax', $.extend({ note: $('#tt-exempt-note').val() }, ttExemptTarget));
});
});
</script>

View File

@@ -22,6 +22,11 @@
* @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};
@@ -49,6 +54,33 @@
$(document).ready(function() {
$('.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();
});
});
}
});
$('#customer').typeWatch({
captureLength: 3,
highlight: true,
@@ -763,10 +795,18 @@
$('#total_convenience_fees').html(formatCurrency(parseFloat(jsonSummary.summary.convenience_fee), currency_format, currency_sign, currency_blank));
$('#total_without_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.cart_total_without_discount_te), currency_format, currency_sign, currency_blank));
// $('#total_service_products').html(formatCurrency(parseFloat(jsonSummary.summary.total_service_products), currency_format, currency_sign, currency_blank));
$('#total_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount), currency_format, currency_sign, currency_blank));
$('#total_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount) + parseFloat(jsonSummary.summary.total_tourism_tax || 0), currency_format, currency_sign, currency_blank));
$('#total_taxes_vat').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount || 0), currency_format, currency_sign, currency_blank));
var totalTaxesTourismAmt = parseFloat(jsonSummary.summary.total_tourism_tax || 0);
$('#total_taxes_tourism').closest('div').toggle(totalTaxesTourismAmt > 0);
$('#total_taxes_tourism').html(formatCurrency(totalTaxesTourismAmt, currency_format, currency_sign, currency_blank));
$('#total_with_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_price), currency_format, currency_sign, currency_blank));
$('#payment_amount').val(jsonSummary.summary.total_price);
if (parseInt($('input[name="is_full_payment"]:checked').val())) {
$('#payment_amount').val(jsonSummary.summary.total_price);
}
$('#full_payment_amount_value').html(formatCurrency(parseFloat(jsonSummary.summary.total_price), currency_format, currency_sign, currency_blank));
if (jsonSummary.summary.is_advance_payment_active) {
$('#advance_payment_amount').html(formatCurrency(parseFloat(jsonSummary.summary.advance_payment_amount_with_tax), currency_format, currency_sign, currency_blank));
$('#advance_payment_amount_block').show();
@@ -778,7 +818,8 @@
if (jsonSummary.summary.total_price == 0) { // if free order
$('#send_email_to_customer, [name="is_full_payment"], #payment_amount, #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').hide(200);
} else {
$('#send_email_to_customer, [name="is_full_payment"], #payment_amount, #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
$('#send_email_to_customer, [name="is_full_payment"], #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
$('#payment_amount').closest('.form-group').toggle(!parseInt($('input[name="is_full_payment"]:checked').val()));
}
}
@@ -1275,7 +1316,11 @@
shipping_price_selected_carrier = jsonSummary.summary.total_shipping;
$('#total_vouchers').html(formatCurrency(parseFloat(jsonSummary.summary.total_discounts), currency_format, currency_sign, currency_blank));
$('#total_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount), currency_format, currency_sign, currency_blank));
$('#total_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount) + parseFloat(jsonSummary.summary.total_tourism_tax || 0), currency_format, currency_sign, currency_blank));
$('#total_taxes_vat').html(formatCurrency(parseFloat(jsonSummary.summary.total_tax_without_discount || 0), currency_format, currency_sign, currency_blank));
var totalTaxesTourismAmt2 = parseFloat(jsonSummary.summary.total_tourism_tax || 0);
$('#total_taxes_tourism').closest('div').toggle(totalTaxesTourismAmt2 > 0);
$('#total_taxes_tourism').html(formatCurrency(totalTaxesTourismAmt2, currency_format, currency_sign, currency_blank));
$('#total_without_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.cart_total_without_discount_te), currency_format, currency_sign, currency_blank));
$('#total_with_taxes').html(formatCurrency(parseFloat(jsonSummary.summary.total_price), currency_format, currency_sign, currency_blank));
$('#total_rooms').html(formatCurrency(parseFloat(jsonSummary.summary.total_rooms_with_services_without_discount_te), currency_format, currency_sign, currency_blank));
@@ -1297,7 +1342,11 @@
}
$('#order_message').val(jsonSummary.order_message);
$('#payment_amount').siblings('.input-group-addon').html(currency_sign);
$('#payment_amount').val(jsonSummary.summary.total_price);
if (parseInt($('input[name="is_full_payment"]:checked').val())) {
$('#payment_amount').val(jsonSummary.summary.total_price);
}
$('#full_payment_amount_value').html(formatCurrency(parseFloat(jsonSummary.summary.total_price), currency_format, currency_sign, currency_blank));
if (jsonSummary.summary.is_advance_payment_active) {
$('#advance_payment_amount').html(formatCurrency(parseFloat(jsonSummary.summary.advance_payment_amount_with_tax), currency_format, currency_sign, currency_blank));
$('#advance_payment_amount_block').show();
@@ -1309,7 +1358,8 @@
if (jsonSummary.summary.total_price == 0) { // if free order
$('#send_email_to_customer, [name="is_full_payment"], #payment_amount, #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').hide(200);
} else {
$('#send_email_to_customer, [name="is_full_payment"], #payment_amount, #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
$('#send_email_to_customer, [name="is_full_payment"], #payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
$('#payment_amount').closest('.form-group').toggle(!parseInt($('input[name="is_full_payment"]:checked').val()));
}
resetBind();
@@ -1562,10 +1612,10 @@
});
}
{* JS for handling extra demands changes *}
{* JS for handling extra services changes *}
$(document).ready(function() {
// modalbox for extra demands
$('body').on('click', '.open_rooms_extra_demands', function() {
// modalbox for extra services
$('body').on('click', '.open_rooms_extra_services', function() {
var idProduct = $(this).attr('id_product');
var idCart = $(this).attr('id_cart');
var idRoom = $(this).attr('id_room');
@@ -1590,7 +1640,7 @@
id_product: idProduct,
id_customer: id_customer,
id_hotel_cart_booking: idHotelCartBooking,
action: 'getRoomTypeCartDemands',
action: 'getRoomTypeCartServices',
ajax: true
},
success: function(response) {
@@ -1603,10 +1653,8 @@
errorHtml += '</ol>';
showErrorMessage(errorHtml);
} else {
$('#customer_cart_details').after(response.html_exta_demands);
// $('#rooms_type_extra_demands').find('#room_type_demands_desc').html('');
// $('#rooms_type_extra_demands').find('#room_type_demands_desc').append(response.html_exta_demands);
$('#rooms_type_extra_demands').modal('show');
$('#customer_cart_details').after(response.html_exta_services);
$('#rooms_type_extra_services').modal('show');
}
},
complete: function() {
@@ -1614,98 +1662,11 @@
}
});
});
$(document).on('hidden.bs.modal', '#rooms_type_extra_demands', function (e) {
$(document).on('hidden.bs.modal', '#rooms_type_extra_services', function (e) {
// reload to make changes reflect everywhere
location.reload();
});
// select/unselect extra demand
$(document).on('click', '.id_room_type_demand', function() {
var roomDemands = [];
// get the selected extra demands by customer
$(this).closest('.room_demand_detail').find('input:checkbox.id_room_type_demand:checked').each(function () {
roomDemands.push({
'id_global_demand':$(this).val(),
'id_option': $(this).closest('.room_demand_block').find('.id_option').val()
});
});
var idBookingCart = $(this).attr('id_cart_booking');
$(".loading_overlay").show();
$.ajax({
type: 'POST',
dataType: 'JSON',
headers: {
"cache-control": "no-cache"
},
url: "{$link->getAdminLink('AdminCarts')|addslashes}",
dataType: 'JSON',
cache: false,
data: {
id_cart_booking: idBookingCart,
room_demands: JSON.stringify(roomDemands),
action: 'changeRoomDemands',
ajax: true
},
success: function(response) {
if (response.status) {
showSuccessMessage(txtExtraDemandSucc);
} else {
showErrorMessage(txtExtraDemandErr);
}
},
complete: function() {
$(".loading_overlay").hide();
}
});
});
// change advanced option of extra demand
$(document).on('change', '.demand_adv_option_block .id_option', function(e) {
var option_selected = $(this).find('option:selected');
var extra_demand_price = option_selected.attr("optionPrice")
extra_demand_price = parseFloat(extra_demand_price);
extra_demand_price = formatCurrency(extra_demand_price, currency_format, currency_sign, currency_blank);
$(this).closest('.room_demand_block').find('.extra_demand_option_price').text(extra_demand_price);
var roomDemands = [];
if ($(this).closest('.room_demand_block').find('input:checkbox.id_room_type_demand').is(':checked')) {
// get the selected extra demands by customer
$(this).closest('.room_demand_detail').find('input:checkbox.id_room_type_demand:checked').each(function () {
roomDemands.push({
'id_global_demand':$(this).val(),
'id_option': $(this).closest('.room_demand_block').find('.id_option').val()
});
});
var idBookingCart = $(this).closest('.room_demand_block').find('.id_room_type_demand').attr('id_cart_booking');
$(".loading_overlay").show();
$.ajax({
type: 'POST',
dataType: 'JSON',
headers: {
"cache-control": "no-cache"
},
url: "{$link->getAdminLink('AdminCarts')|addslashes}",
dataType: 'JSON',
cache: false,
data: {
id_cart_booking: idBookingCart,
room_demands: JSON.stringify(roomDemands),
action: 'changeRoomDemands',
ajax: true
},
success: function(response) {
if (response.status) {
showSuccessMessage(txtExtraDemandSucc);
} else {
showErrorMessage(txtExtraDemandErr);
}
},
complete: function() {
$(".loading_overlay").hide();
}
});
}
});
$(document).on('keyup', '#payment_module_name', function() {
let paymentMethod = $('#payment_module_name').val().trim().toLowerCase();
@@ -1729,11 +1690,13 @@
$(document).on('change', 'input[name="is_full_payment"]', function() {
if (parseInt($('input[name="is_full_payment"]:checked').val())) {
$('#payment_amount').attr('disabled', true);
$('#payment_amount').val({$order_total|floatval}).attr('disabled', true);
$('#payment_amount').closest('.form-group').hide(200);
$('#payment_type, #payment_transaction_id').closest('.form-group').show(200);
$('#payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
} else {
$('#payment_amount').attr('disabled', false);
$('#payment_amount').val({$order_total|floatval}).attr('disabled', false);
$('#payment_amount').closest('.form-group').show(200);
managePaymentOptions();
}
@@ -1747,9 +1710,9 @@
let paymentAmount = parseFloat($('#payment_amount').val().trim());
if (paymentAmount != 0) {
$('#payment_type, #payment_transaction_id').closest('.form-group').show(200);
$('#payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').show(200);
} else {
$('#payment_type, #payment_transaction_id').closest('.form-group').hide(200);
$('#payment_type, #payment_module_name, #payment_transaction_id').closest('.form-group').hide(200);
}
}
@@ -1764,7 +1727,7 @@
}
});
// click on back button on created facilities while additional facilities edit
// click on back button on created extra service edit
$(document).on('click', '#back_to_service_btn', function() {
$('#room_type_services_desc').show();
$('#add_new_room_services_block').hide();
@@ -1818,7 +1781,7 @@
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
}
showSuccessMessage(txtExtraDemandSucc);
showSuccessMessage(txtExtraServiceSucc);
} else {
var errorHtml = error_found_txt + ':<br>';
errorHtml += '<ol>';
@@ -1866,7 +1829,7 @@
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
}
showSuccessMessage(txtExtraDemandSucc);
showSuccessMessage(txtExtraServiceSucc);
} else {
if (jsonData.errors != 'undefined' && jsonData.errors.length) {
var errorHtml = error_found_txt + ':<br>';
@@ -2334,8 +2297,20 @@
</div>
<div class="col-lg-2">
<div class="data-focus">
<span>{l s='Total taxes'}</span><br/>
<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 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">
@@ -2399,8 +2374,13 @@
<p class="help-block">{l s='If disabled, no mail related to this order will be sent during order creation.'}</p>
</div>
</div>
<div class="form-group" {if $order_total <= 0}style="display: none;"{/if}>
<label class="control-label col-lg-3">{l s="Full payment"}</label>
<div class="form-group" {if $order_total <= 0}style="display: none;"{/if}>
<label class="control-label col-lg-3">
<span class="label-tooltip" data-toggle="tooltip"
title="{l s='Keep this option enabled for full payment and disable it to take partial payment of the booking.'}">
{l s="Full payment"}
</span>
</label>
<div class="col-lg-9">
<span class="switch prestashop-switch fixed-width-lg">
<input type="radio" name="is_full_payment" id="is_full_payment_on" value="1" {if $is_full_payment}checked="checked"{/if}>
@@ -2409,15 +2389,18 @@
<label for="is_full_payment_off">{l s="No"}</label>
<a class="slide-button btn"></a>
</span>
<p class="help-block">{l s='Keep this option enabled for full payment and disable it to take partial payment of the booking.'}</p>
<p class="help-block">
<span>{l s='Total amount: '}</span>
<span id="full_payment_amount_value">{displayPrice price=$order_total currency=$currency->id}</span>
</p>
</div>
</div>
<div class="form-group" {if $order_total <= 0}style="display: none;"{/if}>
<div class="form-group" {if $order_total <= 0 || $is_full_payment}style="display: none;"{/if}>
<label class="control-label required col-lg-3">{l s='Payment amount'}</label>
<div class="col-lg-9">
<div class="input-group fixed-width-xxl">
<span class="input-group-addon">{$currency->sign}</span>
<input type="text" name="payment_amount" id="payment_amount" value="{if isset($smarty.post.payment_amount)}{$smarty.post.payment_amount|escape:'html':'UTF-8'}{elseif $is_full_payment}{$order_total}{/if}" {if $is_full_payment}disabled{/if} />
<input type="text" name="payment_amount" id="payment_amount" value="{if !$is_full_payment && isset($smarty.post.payment_amount)}{$smarty.post.payment_amount|escape:'html':'UTF-8'}{else}{$order_total}{/if}" {if $is_full_payment}disabled{/if} />
</div>
<p class="help-block" id="advance_payment_amount_block" {if isset($is_advance_payment_active) && $is_advance_payment_active}style="display: block;"{else}style="display: none;"{/if}>
<span>{l s='Advance payment amount: '}</span>
@@ -2425,6 +2408,27 @@
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3">{l s='Booking Source'}</label>
<div class="col-lg-9">
<select class="fixed-width-xxl" name="id_booking_source" id="id_booking_source">
<option value="">{l s='-- Select Booking Source --'}</option>
{assign var="prev_business_source" value=""}
{foreach from=$booking_sources item=booking_source name=booking_sources_loop}
{if $booking_source.business_source_name != $prev_business_source}
{if !$smarty.foreach.booking_sources_loop.first}</optgroup>{/if}
<optgroup label="{$booking_source.business_source_name}">
{assign var="prev_business_source" value=$booking_source.business_source_name}
{/if}
<option value="{$booking_source.id_source}" {if (isset($smarty.post.id_booking_source) && $booking_source.id_source == $smarty.post.id_booking_source) || (!isset($smarty.post.id_booking_source) && $booking_source.code == 'WALKIN')}selected="selected"{/if}>
{$booking_source.name}
</option>
{/foreach}
{if $booking_sources}</optgroup>{/if}
</select>
<p class="help-block">{l s='Walk-in is selected by default. Change it if this booking came from a different source.'}</p>
</div>
</div>
<div class="form-group" {if $order_total <= 0}style="display: none;"{/if}>
<label class="control-label col-lg-3">{l s='Payment source'}</label>
<div class="col-lg-9">
@@ -2487,6 +2491,7 @@
{addJsDefL name='no_children_allowed_txt'}{l s='Only adults can be accommodated' js=1}{/addJsDefL}
{addJsDefL name='invalid_occupancy_txt'}{l s='Invalid occupancy(adults/children) found.' js=1}{/addJsDefL}
{addJsDefL name='error_found_txt'}{l s='Errors found' js=1}{/addJsDefL}
{addJsDefL name='txtExtraServiceSucc'}{l s='Updated Successfully' js=1}{/addJsDefL}
{/strip}
<div id="loader_container">

View File

@@ -770,6 +770,18 @@
<i class="icon-plus-sign"></i> {l s='Add Rooms'}
</button>
{/if}
{if isset($use_tourism_tax) && $use_tourism_tax && $order_detail_data}
{if isset($order_tourism_tax_has_applied) && $order_tourism_tax_has_applied}
<button type="button" class="btn btn-default pull-right tt-exempt-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-ban"></i> {l s='Exempt Tourism Tax'}
</button>
{/if}
{if isset($order_tourism_tax_has_unapplied) && $order_tourism_tax_has_unapplied}
<button type="button" class="btn btn-default pull-right tt-apply-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-check"></i> {l s='Apply Tourism Tax'}
</button>
{/if}
{/if}
</div>
{* by webkul this code is added for showing rooms information on the order detail page *}
{include file='controllers/orders/_rooms_informaion_table.tpl'}
@@ -790,6 +802,18 @@
<i class="icon-plus-sign"></i> {l s='Add Product'}
</button>
{/if}
{if isset($use_tourism_tax) && $use_tourism_tax && $hotel_service_products}
{if isset($products_tourism_tax_has_applied) && $products_tourism_tax_has_applied}
<button type="button" class="btn btn-default pull-right tt-exempt-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-ban"></i> {l s='Exempt Tourism Tax'}
</button>
{/if}
{if isset($products_tourism_tax_has_unapplied) && $products_tourism_tax_has_unapplied}
<button type="button" class="btn btn-default pull-right tt-apply-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-check"></i> {l s='Apply Tourism Tax'}
</button>
{/if}
{/if}
</div>
{include file='controllers/orders/_hotel_service_products_table.tpl'}
@@ -810,8 +834,21 @@
<i class="icon-plus-sign"></i> {l s='Add Product'}
</button>
{/if}
{if isset($use_tourism_tax) && $use_tourism_tax && $standalone_service_products}
{if isset($products_tourism_tax_has_applied) && $products_tourism_tax_has_applied}
<button type="button" class="btn btn-default pull-right tt-exempt-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-ban"></i> {l s='Exempt Tourism Tax'}
</button>
{/if}
{if isset($products_tourism_tax_has_unapplied) && $products_tourism_tax_has_unapplied}
<button type="button" class="btn btn-default pull-right tt-apply-all-bookings" data-id_order="{$order->id|intval}" style="margin-right:5px; text-transform:uppercase">
<i class="icon-check"></i> {l s='Apply Tourism Tax'}
</button>
{/if}
{/if}
</div>
{include file='controllers/orders/_standalone_service_products_table.tpl'}
{include file='controllers/orders/_tourism_tax_actions.tpl'}
{if ($order->getTaxCalculationMethod() == $smarty.const.PS_TAX_EXC)}
<input type="hidden" name="TaxMethod" value="0">
@@ -843,10 +880,6 @@
{assign var=order_shipping_price value=$order->total_shipping_tax_incl}
{/if}
{* total extra demands prices *}
{* $totalDemandsPriceTE
$totalDemandsPriceTI *}
{* Get total rooms prices *}
{assign var=total_rooms_price_tax_excl value=$order->getTotalProductsWithoutTaxes(false, true)}
{assign var=total_rooms_price_tax_incl value=$order->getTotalProductsWithTaxes(false, true)}
@@ -855,16 +888,21 @@
{assign var=total_products_price_tax_excl value=($order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE) + $order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE))}
{assign var=total_products_price_tax_incl value=($order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE) + $order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE))}
{* Get total of extra services and extra demands prices(excluding convenience fee) *}
{assign var=total_room_services_and_demands_tax_excl value=($order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE) + $totalDemandsPriceTE)}
{assign var=total_room_services_and_demands_tax_incl value=($order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE) + $totalDemandsPriceTI)}
{* Get total of extra services prices(excluding convenience fee) *}
{assign var=total_room_services_tax_excl value=($order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE))}
{assign var=total_room_services_tax_incl value=($order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE))}
{* Get total of only convenience fees prices *}
{assign var=total_convenience_fee_tax_excl value=$order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT)}
{assign var=total_convenience_fee_tax_incl value=$order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT)}
{assign var=order_total_price_tax_excl value=($total_rooms_price_tax_excl + $total_room_services_and_demands_tax_excl + $total_products_price_tax_excl)}
{assign var=order_total_price_tax_incl value=($total_rooms_price_tax_incl + $total_room_services_and_demands_tax_incl + $total_products_price_tax_incl)}
{assign var=total_convenience_fee_vat_incl value=$order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, null, false)}
{assign var=order_total_price_tax_excl value=($total_rooms_price_tax_excl + $total_room_services_tax_excl + $total_products_price_tax_excl)}
{assign var=order_total_price_tax_incl value=($total_rooms_price_tax_incl + $total_room_services_tax_incl + $total_products_price_tax_incl)}
{assign var=total_rooms_tax_only value=(($total_rooms_price_tax_incl - $total_rooms_price_tax_excl) - $tourism_tax_room)}
{assign var=total_convenience_fee_tax_only value=($total_convenience_fee_vat_incl - $total_convenience_fee_tax_excl)}
{assign var=total_products_tax_only value=(($total_products_price_tax_incl - $total_products_price_tax_excl) - $tourism_tax_products)}
{if $total_rooms_price_tax_excl}
<tr id="total_products">
@@ -884,11 +922,11 @@
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
{/if}
{if isset($total_room_services_and_demands_tax_excl) && $total_room_services_and_demands_tax_excl > 0}
{if isset($total_room_services_tax_excl) && $total_room_services_tax_excl > 0}
<tr id="total_products">
<td class="text-right">{l s='Total Extra services (Tax excl.)'}</td>
<td class="amount text-right nowrap">
{displayPrice price=($total_room_services_and_demands_tax_excl - $total_convenience_fee_tax_excl) currency=$currency->id}
{displayPrice price=($total_room_services_tax_excl - $total_convenience_fee_tax_excl) currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
@@ -940,28 +978,54 @@
<td colspan="3" class="panel">
<table class="table table-responsive">
<tbody>
{if $total_rooms_price_tax_excl}
{if $total_rooms_price_tax_excl && $total_rooms_tax_only > 0}
<tr>
<td class="text-left">{l s='Total Rooms Tax'}</td>
<td class="text-right">
{displayPrice price=($total_rooms_price_tax_incl - $total_rooms_price_tax_excl) currency=$currency->id}
{displayPrice price=$total_rooms_tax_only currency=$currency->id}
</td>
</tr>
{/if}
{if isset($total_room_services_and_demands_tax_incl) && (($total_room_services_and_demands_tax_incl - $total_room_services_and_demands_tax_excl) - ($total_convenience_fee_tax_incl - $total_convenience_fee_tax_excl)) > 0}
{if isset($tourism_tax_room) && $tourism_tax_room > 0}
<tr>
<td class="text-left">{l s='Tourism Tax on Room'}</td>
<td class="text-right">
{displayPrice price=$tourism_tax_room currency=$currency->id}
</td>
</tr>
{/if}
{if isset($total_room_services_tax_incl) && (($total_room_services_tax_incl - $total_room_services_tax_excl) - ($total_convenience_fee_tax_incl - $total_convenience_fee_tax_excl)) > 0}
<tr>
<td class="text-left">{l s='Extra services Tax'}</td>
<td class="text-right nowrap">
{displayPrice price=(($total_room_services_and_demands_tax_incl - $total_room_services_and_demands_tax_excl) - ($total_convenience_fee_tax_incl - $total_convenience_fee_tax_excl)) currency=$currency->id}
{displayPrice price=(($total_room_services_tax_incl - $total_room_services_tax_excl) - ($total_convenience_fee_tax_incl - $total_convenience_fee_tax_excl)) currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
{/if}
{if ($total_products_price_tax_incl - $total_products_price_tax_excl) > 0}
{if isset($tourism_tax_service) && $tourism_tax_service > 0}
<tr>
<td class="text-left">{l s='Tourism Tax on Extra Services'}</td>
<td class="text-right nowrap">
{displayPrice price=$tourism_tax_service currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
{/if}
{if $total_products_tax_only > 0}
<tr id="total_products">
<td class="text-left">{l s='Products Tax'}</td>
<td class="amount text-right nowrap">
{displayPrice price=($total_products_price_tax_incl - $total_products_price_tax_excl) currency=$currency->id}
{displayPrice price=$total_products_tax_only currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
{/if}
{if isset($tourism_tax_products) && $tourism_tax_products > 0}
<tr id="total_products">
<td class="text-left">{l s='Tourism Tax on Products'}</td>
<td class="amount text-right nowrap">
{displayPrice price=$tourism_tax_products currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
@@ -970,7 +1034,7 @@
<tr id="total_products">
<td class="text-left">{l s='Convenience Fee Tax'}</td>
<td class="amount text-right nowrap">
{displayPrice price=($total_convenience_fee_tax_incl - $total_convenience_fee_tax_excl) currency=$currency->id}
{displayPrice price=$total_convenience_fee_tax_only currency=$currency->id}
</td>
<td class="partial_refund_fields current-edit" style="display:none;"></td>
</tr>
@@ -1261,12 +1325,12 @@
{addJsDefL name=no_swap_rm_avail_txt}{l s='No room available for swap.' js=1}{/addJsDefL}
{addJsDefL name=slct_rm_type_err}{l s='Please select a room type first.' js=1}{/addJsDefL}
{addJsDefL name=slct_rm_err}{l s='Please select a room first.' js=1}{/addJsDefL}
{addJsDefL name=txtExtraDemandSucc}{l s='Updated Successfully' js=1}{/addJsDefL}
{addJsDefL name=txtExtraServiceSucc}{l s='Updated Successfully' js=1}{/addJsDefL}
{addJsDefL name=atleastSelectTxt}{l s='Select at least one facility to update.' js=1}{/addJsDefL}
{addJsDefL name=txtSomeErr}{l s='Some error occurred. Please try again.' js=1}{/addJsDefL}
{addJsDefL name=txtDeleteSucc}{l s='Deleted successfully' js=1}{/addJsDefL}
{addJsDefL name=txtInvalidDemandVal}{l s='Invalid demand value found' js=1}{/addJsDefL}
{addJsDefL name=txtInvalidServiceVal}{l s='Invalid service value found' js=1}{/addJsDefL}
{addJsDefL name='select_age_txt'}{l s='Select age' js=1}{/addJsDefL}
{addJsDefL name='under_1_age'}{l s='Under 1' js=1}{/addJsDefL}
{addJsDefL name='room_txt'}{l s='Room' js=1}{/addJsDefL}

View File

@@ -20,7 +20,7 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<div id="room_type_service_product_desc" class="tab-pane{if !isset($selectedRoomDemands) || !$selectedRoomDemands} active{/if}">
<div id="room_type_service_product_desc" class="tab-pane{if isset($serviceProducts) || $serviceProducts} active{/if}">
{if $customServiceAllowed}
<div class="row">
<button id="btn_new_room_service" class="btn btn-success pull-right"><i class="icon-plus-circle"></i> {l s='Add a new service'}</button>
@@ -31,8 +31,8 @@
{if isset($serviceProducts) && $serviceProducts}
<div id="room_type_services_desc">
{assign var=roomCount value=1}
<div class="row room_demands_container">
<div class="col-sm-12 room_demand_detail">
<div class="row room_service_container">
<div class="col-sm-12 room_service_detail">
{if isset($serviceProducts) && $serviceProducts}
<form id="update_selected_room_services_form">
<table class="table table-striped">
@@ -54,7 +54,7 @@
{else}
{assign var='serviceSelected' value=false}
{/if}
<tr class="room_demand_block">
<tr class="room_service_block">
<td>
<input data-id_cart_booking="{$selectedRoomServiceProduct['id']}" value="{$product['id_product']|escape:'html':'UTF-8'}" type="checkbox" class="change_room_type_service_product" {if $serviceSelected}checked{/if}/>

View File

@@ -128,6 +128,26 @@
</div>
{/if}
</div>
{if isset($use_tourism_tax) && $use_tourism_tax}
<div class="form-group row">
<div class="col-sm-12">
<label class="control-label">{l s='Apply tourism tax'}</label>
<div>
<span class="switch prestashop-switch fixed-width-lg">
<input type="radio" name="add_product[apply_tourism_tax]" id="add_product_apply_tourism_tax_on" value="1" checked="checked"/>
<label for="add_product_apply_tourism_tax_on" class="radioCheck">
{l s='Yes'}
</label>
<input type="radio" name="add_product[apply_tourism_tax]" id="add_product_apply_tourism_tax_off" value="0"/>
<label for="add_product_apply_tourism_tax_off" class="radioCheck">
{l s='No'}
</label>
<a class="slide-button btn"></a>
</span>
</div>
</div>
</div>
{/if}
<div class="form-group row">
<div class="col-sm-12">
<label class="control-label">{l s='Remark'}</label>

View File

@@ -26,9 +26,6 @@
<li role="presentation" class="active">
<a href="#edit_room_tab" role="tab" data-toggle="tab">{l s='Rooms'}</a>
</li>
<li role="presentation">
<a href="#room_type_demands_desc" aria-controls="facilities" role="tab" data-toggle="tab">{l s='Facilities'}</a>
</li>
<li role="presentation">
<a href="#room_type_service_product_desc" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a>
</li>

View File

@@ -22,8 +22,7 @@
<div class="extra-services-content modal-body">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#room_type_demands_desc" aria-controls="facilities" role="tab" data-toggle="tab">{l s='Facilities'}</a></li>
<li role="presentation"><a href="#room_type_service_product_desc" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
<li role="presentation" class="active"><a href="#room_type_service_product_desc" aria-controls="services" role="tab" data-toggle="tab">{l s='Services'}</a></li>
</ul>
<div class="tab-content clearfix">
{include file='controllers/orders/modals/_partials/_room_extra_services_content.tpl'}

View File

@@ -1,181 +0,0 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<div id="room_type_demands_desc" class="tab-pane {if (isset($show_active) && $show_active) || (!isset($orderEdit) || !$orderEdit)}active{/if} extra-services-container">
<input type="hidden" value="{$id_booking_detail}" id="id_htl_booking">
{if isset($orderEdit) && $orderEdit}
<p class="col-sm-12 facility_nav_btn">
<button id="btn_new_room_demand" class="btn btn-success"><i class="icon-plus"></i> {l s='Add new facility'}</button>
<button id="back_to_demands_btn" class="btn btn-default"><i class="icon-arrow-left"></i> {l s='Back'}</button>
</p>
{* Already selected room demands *}
<div class="col-sm-12 room_ordered_demands table-responsive">
<table class="table">
<thead>
<tr>
<th>{l s='Name'}</th>
<th>{l s='Unit Price (tax excl.)'}</th>
<th>{l s='Total Price (tax excl.)'}</th>
<th>{l s='Total Price (tax incl.)'}</th>
<th class="text-right">{l s='Action'}</th>
</tr>
</thead>
<tbody>
{if isset($extraDemands) && $extraDemands}
{foreach $extraDemands as $roomDemand}
{foreach $roomDemand['extra_demands'] as $demand}
<tr data-id_booking_demand="{$demand['id_booking_demand']}">
<td>{$demand['name']}</td>
<td>
<div class="input-group">
<span class="input-group-addon">{$currencySign}</span>
<input type="text" class="form-control unit_price" value="{$demand['unit_price_tax_excl']}">
{if $demand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY}
<span class="input-group-addon">{l s='/ night'}</span>
{/if}
</div>
</td>
<td>{displayPrice price=$demand['total_price_tax_excl'] currency=$orderCurrency}</td>
<td>{displayPrice price=$demand['total_price_tax_incl'] currency=$orderCurrency}</td>
<td class="text-right"><a class="btn btn-danger pull-right del-order-room-demand" href="#" id_booking_demand="{$demand['id_booking_demand']}"><i class="icon-trash"></i></a></td>
</tr>
{/foreach}
{/foreach}
{else}
<tr>
<td colspan="4">
<i class="icon-warning"></i> {l s='No facilities added yet.'}
</td>
</tr>
{/if}
</tbody>
</table>
</div>
{* Room demands available for the current editing room*}
<div class="col-sm-12 room_demands_container">
<div class="room_demand_detail">
{if isset($roomTypeDemands) && $roomTypeDemands}
<table class="table">
<thead>
<tr>
<th></th>
<th>{l s='Name'}</th>
<th>{l s='Option'}</th>
<th>{l s='Unit Price (tax excl.)'}</th>
</tr>
</thead>
<tbody>
{foreach $roomTypeDemands as $idGlobalDemand => $demand}
<tr class="room_demand_block">
<td>
<input id_cart_booking="{$roomDemand['id']}" value="{$idGlobalDemand|escape:'html':'UTF-8'}" type="checkbox" class="id_room_type_demand" {if isset($roomDemand['selected_global_demands']) && $roomDemand['selected_global_demands'] && ($idGlobalDemand|in_array:$roomDemand['selected_global_demands'])}checked{/if} />
</td>
<td>
{$demand['name']|escape:'html':'UTF-8'}
</td>
<td class="demand_adv_option_block">
{if isset($demand['adv_option']) && $demand['adv_option']}
<select class="id_option">
{foreach $demand['adv_option'] as $idOption => $option}
{assign var=demand_key value="`$idGlobalDemand`-`$idOption`"}
<option optionPrice="{$option['price_tax_excl']|escape:'html':'UTF-8'}" value="{$idOption|escape:'html':'UTF-8'}" {if isset($roomDemand['extra_demands'][$demand_key])}selected{/if} key="{$demand_key}">{$option['name']}</option>
{if isset($roomDemand['extra_demands'][$demand_key])}
{assign var=selected_adv_option value="$idOption"}
{/if}
{/foreach}
</select>
{else}
{l s='--'}
<input type="hidden" class="id_option" value="0" />
{/if}
</td>
<td>
<div class="input-group">
<span class="input-group-addon">{$currencySign}</span>
{if isset($selected_adv_option) && isset($demand['adv_option'][$selected_adv_option]['price_tax_excl'])}
{assign var=demand_price value=$demand['adv_option'][$selected_adv_option]['price_tax_excl']}
{else if isset($demand['adv_option']) && $demand['adv_option']}
{assign var=demand_price value=$demand['adv_option'][$demand['adv_option']|@key]['price_tax_excl']}
{else}
{assign var=demand_price value=$demand['price_tax_excl']}
{/if}
<input type="text" class="form-control unit_price" value="{$demand_price}" data-id-product="{$product['id_product']}">
{if $demand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY}
<span class="input-group-addon">{l s='/ night'}</span>
{/if}
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
<div class="modal-footer">
<button type="button" id="save_room_demands" class="btn btn-primary"><i class="icon icon-save"></i> &nbsp;{l s="Update Facilities"}</button>
</div>
{else}
<i class="icon-warning"></i> {l s='No facilities available for this room.'}
{/if}
</div>
</div>
{else}
<div class="room_demand_detail">
<table class="table">
<thead>
<tr>
<th>{l s='Name'}</th>
<th>{l s='Unit Price (tax excl.)'}</th>
<th>{l s='Total Price (tax excl.)'}</th>
<th>{l s='Total Price (tax incl.)'}</th>
</tr>
</thead>
<tbody>
{if isset($extraDemands) && $extraDemands}
{foreach $extraDemands as $roomDemand}
{foreach $roomDemand['extra_demands'] as $demand}
<tr class="room_demand_block">
<td>{$demand['name']}</td>
<td>
{displayPrice price=$demand['unit_price_tax_excl'] currency=$orderCurrency}
{if $demand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY}
{l s='/ night'}
{/if}
</td>
<td>{displayPrice price=$demand['total_price_tax_excl'] currency=$orderCurrency}</td>
<td>{displayPrice price=$demand['total_price_tax_incl'] currency=$orderCurrency}</td>
</tr>
{/foreach}
{/foreach}
{else}
<tr>
<td colspan="3">
<i class="icon-warning"></i> {l s='No facilities added yet.'}
</td>
</tr>
{/if}
</tbody>
</table>
</div>
{/if}
</div>

View File

@@ -20,7 +20,7 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<div id="room_type_service_product_desc" class="tab-pane {if isset($show_active) && $show_active}active{/if} extra-services-container">
<div id="room_type_service_product_desc" class="tab-pane {if isset($show_active) && $show_active}active{/if} extra-services-container">
{if isset($orderEdit) && $orderEdit}
<div class="col-sm-12 facility_nav_btn">
@@ -51,7 +51,7 @@
<tbody>
{if isset($additionalServices) && $additionalServices}
{foreach $additionalServices['additional_services'] as $service}
<tr class="room_demand_block" data-id_service_product_order_detail="{$service['id_service_product_order_detail']}">
<tr class="room_service_block" data-id_service_product_order_detail="{$service['id_service_product_order_detail']}">
<td>
<div>{$service['name']|escape:'html':'UTF-8'}</div>
<input value="{$service['id_service_product_order_detail']|escape:'html':'UTF-8'}" name="id_service_product_order_detail[]" type="hidden"/>
@@ -110,7 +110,7 @@
{* add already available service interface *}
<form id="add_existing_room_services_form" class="col-sm-12 room_services_container">
<div class="room_demand_detail">
<div class="room_service_detail">
{if isset($serviceProducts) && $serviceProducts}
<table class="table">
<thead>
@@ -124,7 +124,7 @@
</thead>
<tbody>
{foreach $serviceProducts as $product}
<tr class="room_demand_block">
<tr class="room_service_block">
<td>
<input data-id_booking_detail="{$id_booking_detail}" value="{$product['id_product']|escape:'html':'UTF-8'}" name="selected_service[]" type="checkbox" class="id_room_type_service"/>
</td>
@@ -250,7 +250,7 @@
{/if}
{elseif isset($additionalServices) && $additionalServices}
<table class="table room_demand_detail">
<table class="table room_service_detail">
<thead>
<tr>
<th>{l s='ID'}</th>
@@ -264,7 +264,7 @@
</thead>
</tbody>
{foreach $additionalServices['additional_services'] as $service}
<tr class="room_demand_block">
<tr class="room_service_block">
<td>
{$service['id_product']|escape:'html':'UTF-8'}{if !$service['product_deleted']} <a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service['id_product']|escape:'html':'UTF-8'}&amp;updateproduct"><i class="icon-external-link-sign"></i></a>{/if}
</td>

View File

@@ -20,17 +20,14 @@
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{include file='controllers/orders/modals/_extra_services_facilities_tab_content.tpl'}
{include file='controllers/orders/modals/_extra_services_service_products_tab_content.tpl'}
{* Css for handling extra demands changes *}
{* Css for handling extra services changes *}
<style type="text/css">
/*Extra demands CSS*/
#edit_product .extra-services-container .room_demands_container,
/*Extra services CSS*/
#edit_product .extra-services-container .room_service_container,
#edit_product .extra-services-container .room_services_container {
display: none;}
#edit_product .extra-services-container #save_room_demands,
#edit_product .extra-services-container #back_to_demands_btn,
#edit_product .extra-services-container #save_service_service,
#edit_product .extra-services-container #back_to_service_btn {
display: none;}

View File

@@ -89,8 +89,8 @@
</div>
<div class="row">
<div class="alert alert-warning col-sm-12 realloc_roomtype_change_message" style="display:none">
<p>{l s="If room type is changed while room reallocation then all additional facilities and services will be assigned to the selected room of new room type."}</p>
<p>{l s="If you want to change additional facilities or services, you can update by editing the room after reallocation."}</p>
<p>{l s="If room type is changed while room reallocation then all extra services will be assigned to the selected room of new room type."}</p>
<p>{l s="If you want to change extra services, you can update by editing the room after reallocation."}</p>
</div>
</div>
<p class="error_text" id="realloc_sel_rm_err_p"></p>

View File

@@ -0,0 +1,52 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{if isset($tourismTaxRulesGroups)}
<div class="form-group">
<div class="col-lg-1"></div>
<label class="control-label col-lg-2" for="id_tourism_tax_rules_group">{l s='Tourism Tax Rule:'}</label>
<div class="col-lg-8">
<div class="row">
<div class="col-lg-6">
<select name="id_tourism_tax_rules_group" id="id_tourism_tax_rules_group"{if isset($tourismTaxRatesByGroup)} onchange="javascript:calcPrice();"{/if}>
{foreach from=$tourismTaxRulesGroups item=ttrg}
<option value="{$ttrg.id_tax_rules_group|intval}"
{if isset($id_tourism_tax_rules_group) && $id_tourism_tax_rules_group == $ttrg.id_tax_rules_group}selected="selected"{/if}>
{$ttrg.name|escape:'htmlall':'UTF-8'}
</option>
{/foreach}
</select>
</div>
<div class="col-lg-2">
<a class="btn btn-link confirm_leave" href="{$link->getAdminLink('AdminTaxRulesGroup')|escape:'html':'UTF-8'}&amp;addtax_rules_group&amp;id_product={$product->id}&amp;is_tourism_tax_rule_group=1">
<i class="icon-plus-sign"></i> {l s='Create new tax'} <i class="icon-external-link-sign"></i>
</a>
</div>
</div>
</div>
</div>
{if isset($tourismTaxRatesByGroup)}
<script type="text/javascript">
var tourismTaxRatesByGroup = {$tourismTaxRatesByGroup|json_encode};
</script>
{/if}
{/if}

View File

@@ -1,156 +0,0 @@
{**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{if isset($product->id) && $product->id}
<input type="hidden" name="submitted_tabs[]" value="AdditionalFacilities" />
<div class="panel">
<div class="panel-heading">
<i class="icon-user"></i> {l s='Room Type Additional Facilities'}
</div>
<div class="alert alert-info">
{l s='To create new additional facilities please visit'} <a target="_blank" href="{$link->getAdminLink('AdminRoomTypeGlobalDemand')}">{l s='Additional facilities'}</a> {l s='page.'}
</div>
{if isset($allDemands) && $allDemands}
<div class="from-group table-responsive-row clearfix">
<table class="table" id="demands_table">
<thead>
<tr>
<th></th>
<th>
{l s='Name'}
</th>
<th>
{l s='Option'}
</th>
<th class="fixed-width-xl">
{l s='Price'}
</th>
<th>
{l s='Tax rule'}
</th>
<th class="fixed-width-lg text-center">
{l s='Per day price calculation'}
</th>
</tr>
</thead>
<tbody>
{foreach $allDemands as $key => $demand}
{assign var="rowcount" value=0}
{if isset($demand['adv_option']) && $demand['adv_option']}
{assign var="rowspan" value=$demand['adv_option']|count}
{assign var="adv_option" value=$demand['adv_option']}
{else}
{assign var="rowspan" value=1}
{assign var="adv_option" value=[]}
{/if}
{foreach $adv_option as $option}
{assign var="rowcount" value=$rowcount + 1}
<tr>
{if $rowcount <= 1}
<td rowspan="{$rowspan}">
<input class="selected_demand" type="checkbox" name="selected_demand[]" value="{$demand['id_global_demand']|escape:'html':'UTF-8'}" {if isset($selectedDemands[$demand['id_global_demand']])}checked{/if} />
<input type="hidden" name="demand_price_{$demand['id_global_demand']|escape:'html':'UTF-8'}" value="{if isset($selectedDemands[$demand['id_global_demand']]['price'])}{$selectedDemands[$demand['id_global_demand']]['price']|escape:'html':'UTF-8'}{elseif isset($demand['price'])}{$demand['price']|escape:'html':'UTF-8'}{/if}"/>
</td>
<td rowspan="{$rowspan}">
<a target="blank" href="{$link->getAdminLink('AdminRoomTypeGlobalDemand')|escape:'html':'UTF-8'}&amp;id_global_demand={$demand['id_global_demand']|escape:'html':'UTF-8'}&amp;updatehtl_room_type_global_demand"><i class="icon-external-link-sign"></i></a> {$demand['name']|escape:'html':'UTF-8'}
</td>
{/if}
<td>
{$option['name']|escape:'html':'UTF-8'}
</td>
<td class="demand_price_{$demand['id_global_demand']}">
<div class="input-group price_input" {if !isset($selectedDemands[$demand['id_global_demand']])}style="display:none"{/if}>
<span class="input-group-addon">{$defaultcurrencySign|escape:'html':'UTF-8'}</span>
<input type="text" name="option_price_{$option['id']|escape:'html':'UTF-8'}" value="{if isset($selectedDemands[$demand['id_global_demand']]['adv_option'][$option['id']]['price'])}{$selectedDemands[$demand['id_global_demand']]['adv_option'][$option['id']]['price']|escape:'html':'UTF-8'}{else}{$option['price']|escape:'html':'UTF-8'}{/if}"/>
</div>
<div class="price_display" {if isset($selectedDemands[$demand['id_global_demand']])}style="display:none"{/if}>
{displayPrice price={$option['price']|escape:'html':'UTF-8'} currency=$idDefaultcurrency}
</div>
</td>
{if $rowcount == 1}
<td rowspan="{$rowspan}">
{$demand['default_tax_rules_group_name']}
</td>
<td class="text-center" rowspan="{$rowspan}">
{if $demand['price_calc_method'] == 1}
<span class="badge badge-success">{l s='Yes'}</span>
{else}
<span>{l s='No'}</span>
{/if}
</td>
{/if}
</tr>
{foreachelse}
<tr>
<td>
<input class="selected_demand" type="checkbox" name="selected_demand[]" value="{$demand['id_global_demand']|escape:'html':'UTF-8'}" {if isset($selectedDemands[$demand['id_global_demand']])}checked{/if} />
</td>
<td>
<a target="blank" href="{$link->getAdminLink('AdminRoomTypeGlobalDemand')|escape:'html':'UTF-8'}&amp;id_global_demand={$demand['id_global_demand']|escape:'html':'UTF-8'}&amp;updatehtl_room_type_global_demand"><i class="icon-external-link-sign"></i></a> {$demand['name']|escape:'html':'UTF-8'}
</td>
<td></td>
<td class="demand_price_{$demand['id_global_demand']}">
<div class="input-group price_input" {if !isset($selectedDemands[$demand['id_global_demand']])}style="display:none"{/if}>
<span class="input-group-addon">{$defaultcurrencySign|escape:'html':'UTF-8'}</span>
<input type="text" name="demand_price_{$demand['id_global_demand']|escape:'html':'UTF-8'}"
value="{if isset($selectedDemands[$demand['id_global_demand']]['price'])}{$selectedDemands[$demand['id_global_demand']]['price']|escape:'html':'UTF-8'}{elseif isset($demand['price'])}{$demand['price']|escape:'html':'UTF-8'}{/if}"/>
</div>
<div class="price_display" {if isset($selectedDemands[$demand['id_global_demand']])}style="display:none"{/if}>
{displayPrice price={$demand['price']|escape:'html':'UTF-8'} currency=$idDefaultcurrency}
</div>
</td>
<td>
{$demand['default_tax_rules_group_name']}
</td>
<td class="text-center">
{if $demand['price_calc_method'] == 1}
<span class="badge badge-success">{l s='Yes'}</span>
{else}
<span>{l s='No'}</span>
{/if}
</td>
</tr>
{/foreach}
{/foreach}
</tbody>
</table>
</div>
<div class="panel-footer">
<a href="{$link->getAdminLink('AdminProducts')|escape:'html':'UTF-8'}{if isset($smarty.request.page) && $smarty.request.page > 1}&amp;submitFilterproduct={$smarty.request.page|intval}{/if}" class="btn btn-default">
<i class="process-icon-cancel"></i>
{l s='Cancel'}
</a>
<button type="submit" name="submitAddproduct" class="btn btn-default pull-right" disabled="disabled">
<i class="process-icon-loading"></i>
{l s='Save'}
</button>
<button type="submit" name="submitAddproductAndStay" class="btn btn-default pull-right" disabled="disabled">
<i class="process-icon-loading"></i>
{l s='Save and stay'}
</button>
</div>
{/if}
</div>
{/if}

View File

@@ -121,7 +121,7 @@
<a href="#" class="btn btn-default connectedRoomModal" data-toggle="modal"
data-target="#connectedRoomModal" data-id-room="{$room_info['id']|intval}"
data-room-num="{$room_info['room_num']|escape:'html':'UTF-8'}"
data-room-type="{$room_info['id_product']|intval}">
data-room-type="{if isset($room_info['id_product'])}{$room_info['id_product']|intval}{/if}">
<span class="connected-room-icon-wrapper">
<i class="icon-random"></i>
<span class="connected-room-count">

View File

@@ -183,6 +183,7 @@ $(document).ready(function () {
</div>
</div>
{/if}
{* Code For eco-tax working
<div class="form-group" {if !$ps_use_ecotax} style="display:none;"{/if}>
<div class="col-lg-1"><span class="pull-right">{include file="controllers/products/multishop/checkbox.tpl" field="ecotax" type="default"}</span></div>
<label class="control-label col-lg-2" for="ecotax">
@@ -193,6 +194,8 @@ $(document).ready(function () {
<input maxlength="27" id="ecotax" name="ecotax" type="text" value="{$product->ecotax|string_format:$priceDisplayPrecisionFormat}" onkeyup="$('#priceType').val('TI');if (isArrowKey(event))return; calcPriceTE(); this.value = this.value.replace(/,/g, '.'); if (parseInt(this.value) > getE('priceTE').value) this.value = getE('priceTE').value; if (isNaN(this.value)) this.value = 0;" />
</div>
</div>
*}
{include file="controllers/products/_tourism_tax_rule_field.tpl"}
<div class="form-group" {if !$country_display_tax_label || $tax_exclude_taxe_option}style="display:none;"{/if} >
<label class="control-label col-lg-3" for="priceTI">{l s='Retail price with tax'}</label>
<div class="input-group col-lg-2">
@@ -465,6 +468,7 @@ $(document).ready(function () {
</div>
</div>
{if isset($specificPriceModificationForm)}
<div class="panel">
<h3>{l s='Specific prices'}</h3>

View File

@@ -121,6 +121,19 @@ $(function() {
</div>
{/if}
{if isset($num_hotel_amenities) && $num_hotel_amenities}
<div class="panel">
<h3>
{if $num_hotel_amenities == 1}
{l s='1 hotel amenity'}
{else}
{l s='%d hotel amenities' sprintf=$num_hotel_amenities}
{/if}
</h3>
{$hotel_amenities}
</div>
{/if}
{if isset($num_hotel_features) && $num_hotel_features}
<div class="panel">
<h3>
@@ -173,19 +186,6 @@ $(function() {
</div>
{/if}
{if isset($num_global_demands) && $num_global_demands}
<div class="panel">
<h3>
{if $num_global_demands == 1}
{l s='1 global demand'}
{else}
{l s='%d global demands' sprintf=$num_global_demands}
{/if}
</h3>
{$global_demands}
</div>
{/if}
{if isset($num_refund_rules) && $num_refund_rules}
<div class="panel">
<h3>

View File

@@ -0,0 +1,18 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
{extends file="helpers/list/list_header.tpl"}
{block name="override_form_extra"}
{if isset($smarty.get.id_business_source)}
<input type="hidden" name="id_business_source" value="{$smarty.get.id_business_source|intval}" />
{/if}
{/block}

View File

@@ -0,0 +1,33 @@
{*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*}
<form action="{$current_index}&token={$token}" method="post">
<div class="modal-body">
<div class="form-group">
<label>{l s='Current Source'}</label>
<input type="text" name="merge_current_source" id="merge_current_source" class="form-control" readonly="true" value="{$current_source->name}"/>
</div>
<div class="form-group">
<label>{l s='Target Source'}</label>
<select name="target_source" id="target_source" class="form-control">
{foreach from=$sources item=source}
<option value="{$source.id_source}">{$source.name}</option>
{/foreach}
</select>
</div>
<p class="help-block">{l s='Every order currently attributed to Current Source will be reattributed to Target Source. Current Source itself is left as-is.'}</p>
<input type="hidden" name="id_business_source" value="{$id_business_source|intval}" />
<input type="hidden" name="current_source" value="{$current_source->id|intval}" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{l s='Cancel'}</button>
<button type="submit" name="submitMergeSource" class="btn btn-primary"> <i class="icon-random"></i> &nbsp {l s='Update'}</button>
</div>
</form>

View File

@@ -54,14 +54,10 @@
<input type="hidden" name="lang" value="{$lang}" />
<input type="hidden" name="type" value="{$type}" />
<input type="hidden" name="theme" value="{$theme}" />
<script type="text/javascript">
$(document).ready(function(){
$('a.useSpecialSyntax').click(function(){
var syntax = $(this).find('img').attr('alt');
$('#BoxUseSpecialSyntax .syntax span').html(syntax+".");
});
});
</script>
<input type="hidden" name="reset_mail_name" id="reset_mail_name" value="" />
<input type="hidden" name="reset_template_type" id="reset_template_type" value="" />
<input type="hidden" name="reset_module_name" id="reset_module_name" value="" />
<input type="hidden" name="token" id="translation_mails_token" value="{$token}" />
<div id="BoxUseSpecialSyntax">
<div class="alert alert-warning">
<p>
@@ -80,6 +76,10 @@
<a name="submitTranslations{$type|ucfirst}" href="{$cancel_url}" class="btn btn-default">
<i class="process-icon-cancel"></i> {l s='Cancel'}
</a>
<button type="button" id="{$table}_form_reset_btn" class="btn btn-default mail-template-reset-btn label-tooltip" disabled="disabled" data-toggle="tooltip" title="">
<i class="process-icon-refresh"></i>
{l s='Reset'}
</button>
{*$toggle_button*}
<button type="submit" id="{$table}_form_submit_btn" name="submitTranslations{$type|ucfirst}" class="btn btn-default pull-right">
<i class="process-icon-save"></i>
@@ -101,56 +101,6 @@
</span>
</h3>
{$mail_content}
{literal}
<script type="text/javascript">
//<![CDATA[
$(document).ready(function () {
$('.mails_field').on('shown.bs.collapse', function () {
// get active email
var active_email = $(this).find('.email-collapse.in');
// get iframe container for active email
var frame = active_email.find('.email-html-frame');
// get source url for active email
var src = frame.data('email-src');
// get rte container for active email
var rte_mail_selector = active_email.find('textarea.rte-mail').data('rte');
// create special config
var rte_mail_config = {};
rte_mail_config['editor_selector'] = 'rte-mail-' + rte_mail_selector;
rte_mail_config['height'] = '500px';
// We want the default plugins + 'fullpage' plugin for HTML emails
rte_mail_config['plugins'] = "colorpicker link image paste pagebreak table contextmenu filemanager table code media autoresize textcolor anchor fullpage";
// move controls to active panel
$('#translation_mails-control-actions').appendTo($(this).find('.panel-collapse.in'));
// when user first open email
if (frame.find('iframe.email-frame').length == 0) {
// load iframe
frame.append('<iframe class="email-frame" />');
$.ajax({
url:'ajax.php',
type: 'POST',
dataType: 'html',
data: {
getEmailHTML : true,
email : src
},
success: function(result)
{
var doc = frame.find('iframe')[0].contentWindow.document;
doc.open();
doc.write(result);
doc.close();
tinySetup(rte_mail_config);
// init tinyMCE with special config
}
});
}
});
})
//]]>
</script>
{/literal}
</div>
<div class="panel">
<h3>

View File

@@ -32,5 +32,6 @@ class BoOrder extends PaymentModule
$this->validateOrderAmount = false;
// Default payment type for backoffice order should be PAY_AT_HOTEL
$this->payment_type = OrderPayment::PAYMENT_TYPE_PAY_AT_HOTEL;
$this->idBookingSource = Source::getIdByCode('WALKIN');
}
}

239
classes/BusinessSource.php Normal file
View File

@@ -0,0 +1,239 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class BusinessSourceCore extends ObjectModel
{
public $name;
public $code;
public $position;
public $unremovable;
public $active;
public $deleted = 0;
public $date_add;
public $date_upd;
public static $definition = array(
'table' => 'business_source',
'primary' => 'id_business_source',
'multilang' => true,
'fields' => array(
'code' => array('type' => self::TYPE_STRING, 'validate' => 'isModuleName', 'required' => true, 'size' => 64),
'position' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'unremovable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
),
);
public function add($autodate = true, $nullValues = false)
{
if ($this->position <= 0) {
$this->position = BusinessSource::getHigherPosition() + 1;
}
return parent::add($autodate, $nullValues);
}
public function update($nullValues = false)
{
if (!$this->active && $this->hasUnremovableSource()) {
return false;
}
$result = parent::update($nullValues);
if ($result && !$this->active) {
$this->disableSources();
}
return $result;
}
public function disableSources()
{
return (bool)Db::getInstance()->execute(
'UPDATE `'._DB_PREFIX_.'source` SET `active` = 0
WHERE `id_business_source` = '.(int)$this->id.' AND `deleted` = 0'
);
}
public static function getHigherPosition()
{
$position = Db::getInstance()->getValue(
'SELECT MAX(`position`) FROM `'._DB_PREFIX_.'business_source` WHERE `deleted` = 0'
);
return is_numeric($position) ? (int)$position : -1;
}
public function updatePosition($way, $position)
{
if (!$res = Db::getInstance()->executeS('
SELECT `position`, `id_business_source`
FROM `'._DB_PREFIX_.'business_source`
WHERE `deleted` = 0
ORDER BY `position` ASC'
)) {
return false;
}
$moved_item = null;
foreach ($res as $row) {
if ((int)$row['id_business_source'] == (int)$this->id) {
$moved_item = $row;
}
}
if (!$moved_item) {
return false;
}
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = `position` '.($way ? '- 1' : '+ 1').'
WHERE `deleted` = 0 AND `position`
'.($way
? '> '.(int)$moved_item['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_item['position'].' AND `position` >= '.(int)$position)
) && Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = '.(int)$position.'
WHERE `id_business_source` = '.(int)$moved_item['id_business_source']));
}
public static function cleanPositions()
{
$return = true;
$result = Db::getInstance()->executeS('
SELECT `id_business_source`
FROM `'._DB_PREFIX_.'business_source`
WHERE `deleted` = 0
ORDER BY `position` ASC'
);
$i = 0;
foreach ($result as $row) {
$return = Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'business_source`
SET `position` = '.(int)$i++.'
WHERE `id_business_source` = '.(int)$row['id_business_source']
) && $return;
}
return $return;
}
public static function codeExists($code, $idExclude = 0)
{
return (bool)Db::getInstance()->getValue(
'SELECT `id_business_source` FROM `'._DB_PREFIX_.'business_source`
WHERE `code` = \''.pSQL($code).'\' AND `id_business_source` != '.(int)$idExclude
);
}
public static function getUnremovableIds()
{
$rows = Db::getInstance()->executeS(
'SELECT `id_business_source` FROM `'._DB_PREFIX_.'business_source` WHERE `unremovable` = 1 AND `deleted` = 0'
);
return array_map('intval', array_column($rows, 'id_business_source'));
}
public static function getActiveList($idLang)
{
return Db::getInstance()->executeS('
SELECT bs.`id_business_source`, bsl.`name`
FROM `'._DB_PREFIX_.'business_source` bs
LEFT JOIN `'._DB_PREFIX_.'business_source_lang` bsl
ON (bsl.`id_business_source` = bs.`id_business_source` AND bsl.`id_lang` = '.(int)$idLang.')
WHERE bs.`deleted` = 0
ORDER BY bs.`position` ASC
');
}
public function isRemovable()
{
return !$this->unremovable;
}
public function hasUnremovableSource()
{
return (bool)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'source`
WHERE `id_business_source` = '.(int)$this->id.' AND `unremovable` = 1 AND `deleted` = 0'
);
}
public function hasSourceUsedByOrder()
{
return (bool)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'source` s
INNER JOIN `'._DB_PREFIX_.'orders` o ON o.`id_source` = s.`id_source`
WHERE s.`id_business_source` = '.(int)$this->id
);
}
public function getOrderCount()
{
return (int)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'source` s
INNER JOIN `'._DB_PREFIX_.'orders` o ON o.`id_source` = s.`id_source`
WHERE s.`id_business_source` = '.(int)$this->id
);
}
public function delete()
{
if (!$this->isRemovable()) {
return false;
}
$keepSoft = $this->hasSourceUsedByOrder();
$sources = Db::getInstance()->executeS(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source` WHERE `id_business_source` = '.(int)$this->id.' AND `deleted` = 0'
);
foreach ($sources as $row) {
$objSource = new Source((int)$row['id_source']);
if (!$objSource->delete()) {
return false;
}
}
if ($keepSoft) {
$this->deleted = 1;
if (!$this->update()) {
return false;
}
} elseif (!parent::delete()) {
return false;
}
return BusinessSource::cleanPositions();
}
}

View File

@@ -186,7 +186,8 @@ class CartCore extends ObjectModel
const ONLY_ROOM_SERVICES_WITH_AUTO_ADD_WITHOUT_CONVENIENCE_FEE = 17;
const ONLY_CONVENIENCE_FEE = 18;
const ONLY_PRODUCTS_WITH_DEMANDS = 19;
const ONLY_TOURISM_TAX = 19;
const ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE = 20;
public function __construct($id = null, $id_lang = null)
{
@@ -368,8 +369,8 @@ class CartCore extends ObjectModel
*/
public function getAverageProductsTaxRate(&$cart_amount_te = null, &$cart_amount_ti = null)
{
$cart_amount_ti = $this->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$cart_amount_te = $this->getOrderTotal(false, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$cart_amount_ti = $this->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
$cart_amount_te = $this->getOrderTotal(false, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
$cart_vat_amount = $cart_amount_ti - $cart_amount_te;
@@ -1548,7 +1549,7 @@ class CartCore extends ObjectModel
$compute_precision = $configuration->get('_PS_PRICE_COMPUTE_PRECISION_');
if (!$this->id) {
return 0;
return $type == Cart::ONLY_TOURISM_TAX ? array('tourism_tax' => 0.0, 'tourism_tax_room' => 0.0, 'tourism_tax_service' => 0.0, 'tourism_tax_standalone_products' => 0.0, 'tourism_tax_convenience_fee' => 0.0) : 0;
}
$type = (int)$type;
@@ -1570,7 +1571,8 @@ class CartCore extends ObjectModel
Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING,
Cart::ADVANCE_PAYMENT,
Cart::ADVANCE_PAYMENT_ONLY_PRODUCTS,
Cart::ONLY_PRODUCTS_WITH_DEMANDS,
Cart::ONLY_TOURISM_TAX,
Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE,
);
// Define virtual context to prevent case where the cart is not the in the global context
@@ -1637,7 +1639,11 @@ class CartCore extends ObjectModel
}
$products_total = array();
$ecotax_total = 0;
$totalDemandsPrice = 0;
$tourism_tax_total = 0.0;
$tourism_tax_room = 0.0;
$tourism_tax_service = 0.0;
$tourism_tax_standalone_products = 0.0;
$tourism_tax_convenience_fee = 0.0;
$objCartBookingData = new HotelCartBookingData();
$objServiceProductCartDetail = new ServiceProductCartDetail();
$objAdvPayment = new HotelAdvancedPayment();
@@ -1773,6 +1779,11 @@ class CartCore extends ObjectModel
} else {
$products_total[$id_tax_rules_group] += $lineTotal;
}
if ($with_taxes && in_array($type, array(Cart::BOTH, Cart::BOTH_WITHOUT_SHIPPING, Cart::ONLY_TOURISM_TAX))) {
$tourism_tax_total += $servicePorduct['tourism_tax'];
$tourism_tax_standalone_products += $servicePorduct['tourism_tax'];
}
}
}
@@ -1826,6 +1837,11 @@ class CartCore extends ObjectModel
} else {
$products_total[$id_tax_rules_group] += $priceAdd;
}
if ($with_taxes && in_array($type, array(Cart::BOTH, Cart::BOTH_WITHOUT_SHIPPING, Cart::ONLY_TOURISM_TAX))) {
$tourism_tax_total += $servicePorduct['tourism_tax'];
$tourism_tax_standalone_products += $servicePorduct['tourism_tax'];
}
}
}
} else if (Product::SELLING_PREFERENCE_WITH_ROOM_TYPE == $product['selling_preference_type']) {
@@ -1855,6 +1871,17 @@ class CartCore extends ObjectModel
} else {
$products_total[$id_tax_rules_group] += $servicePrice;
}
if ($with_taxes && in_array($type, array(Cart::BOTH, Cart::BOTH_WITHOUT_SHIPPING, Cart::ONLY_TOURISM_TAX))) {
$tourism_tax_total += $service['tourism_tax'];
if ($product['auto_add_to_cart'] && Product::PRICE_ADDITION_TYPE_INDEPENDENT == $product['price_addition_type']) {
$tourism_tax_convenience_fee += $service['tourism_tax'];
} elseif ($product['auto_add_to_cart'] && Product::PRICE_ADDITION_TYPE_WITH_ROOM == $product['price_addition_type']) {
$tourism_tax_room += $service['tourism_tax'];
} else {
$tourism_tax_service += $service['tourism_tax'];
}
}
}
}
}
@@ -1864,8 +1891,6 @@ class CartCore extends ObjectModel
$priceDisplay = Group::getPriceDisplayMethod(Group::getCurrent()->id);
if ($type == Cart::ADVANCE_PAYMENT || $type == Cart::ADVANCE_PAYMENT_ONLY_PRODUCTS) {
// getProductMinAdvPaymentAmountByIdCart already aggregates all rooms for this product internally,
// so call it once and add once — not inside the per-room loop.
$advProductPrice = $objAdvPayment->getProductMinAdvPaymentAmountByIdCart(
$this->id,
$product['id_product'],
@@ -1911,18 +1936,49 @@ class CartCore extends ObjectModel
} else {
$products_total[$id_tax_rules_group] += Tools::processPriceRounding($totalPriceByProduct);
}
if ($with_taxes && in_array($type, array(Cart::BOTH, Cart::BOTH_WITHOUT_SHIPPING, Cart::ONLY_TOURISM_TAX))) {
if ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct((int) $cartRoomInfo['id_product'])) {
$roomAddress = new Address((int) HotelRoomType::getHotelIdAddressByIdProduct($cartRoomInfo['id_product']));
$hotelBranch = new HotelBranchInformation((int) $roomAddress->id_hotel);
$numNights = max(1, (int) HotelHelper::getNumberOfDays($cartRoomInfo['date_from'], $cartRoomInfo['date_to']));
$unitPriceTe = (float) $roomTotalPrice['total_price_tax_excl'] / $numNights;
$childAges = !empty($occupancy[0]['child_ages']) ? (array) $occupancy[0]['child_ages'] : array();
$roomTaxCalculator = TaxManagerFactory::getManager($roomAddress, $idTourismTaxRulesGroup)->getTaxCalculator();
$roomTourismTax = $roomTaxCalculator->getTaxesTotalAmount(
$unitPriceTe,
$cartRoomInfo['date_from'],
$numNights,
$occupancy[0]['adults'],
$childAges,
(int) $hotelBranch->tourism_tax_collection_type,
1,
(int) $this->id_currency
);
$tourism_tax_total += $roomTourismTax;
$tourism_tax_room += $roomTourismTax;
}
}
}
}
}
// price of extra demands on room type in the cart
$totalDemandsPrice += $objCartBookingData->getCartExtraDemands($this->id, $product['id_product'], 0, 0, 0, 1, 0, (int)$with_taxes);
}
if ($type == Cart::ONLY_TOURISM_TAX) {
return array(
'tourism_tax' => $tourism_tax_total,
'tourism_tax_room' => $tourism_tax_room,
'tourism_tax_service' => $tourism_tax_service,
'tourism_tax_standalone_products' => $tourism_tax_standalone_products,
'tourism_tax_convenience_fee' => $tourism_tax_convenience_fee,
);
}
foreach ($products_total as $key => $price) {
$order_total += $price;
}
$order_total_products = $order_total + $totalDemandsPrice;
$order_total_products = $order_total;
if ($type == Cart::ONLY_DISCOUNTS) {
$order_total = 0;
@@ -1941,15 +1997,6 @@ class CartCore extends ObjectModel
return $wrapping_fees;
}
// price of extra demands on room type in the cart
if ($type == Cart::BOTH
|| $type == Cart::BOTH_WITHOUT_SHIPPING
|| $type == Cart::ADVANCE_PAYMENT
|| $type == Cart::ONLY_PRODUCTS_WITH_DEMANDS
) {
$order_total += $totalDemandsPrice;
}
$order_total_discount = 0;
$order_shipping_discount = 0;
$advance_payment_products_discount = 0;
@@ -1964,7 +2011,7 @@ class CartCore extends ObjectModel
Cart::ONLY_ROOM_SERVICES_WITHOUT_AUTO_ADD,
Cart::ONLY_ROOM_SERVICES_WITHOUT_CONVENIENCE_FEE,
Cart::ONLY_ROOM_SERVICES_WITH_AUTO_ADD_WITHOUT_CONVENIENCE_FEE,
Cart::ONLY_PRODUCTS_WITH_DEMANDS)
Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE)
) && CartRule::isFeatureActive()
) {
// First, retrieve the cart rules associated to this "getOrderTotal"
@@ -2052,6 +2099,10 @@ class CartCore extends ObjectModel
$order_total += $shipping_fees + $wrapping_fees;
}
if ($tourism_tax_total > 0) {
$order_total += $tourism_tax_total;
}
if ($order_total < 0 && $type != Cart::ONLY_DISCOUNTS) {
return 0;
}
@@ -3163,8 +3214,17 @@ class CartCore extends ObjectModel
}
}
} elseif ($sellingPreferenceType == Product::SELLING_PREFERENCE_STANDALONE) {
if (isset($id_customer)) {
$id_address = (int)Address::getFirstCustomerAddressId($id_customer);
$addressPreferenceType = Configuration::get('PS_STANDARD_PRODUCT_ORDER_ADDRESS_PREFRENCE');
if ($addressPreferenceType == Product::STANDARD_PRODUCT_ADDRESS_PREFERENCE_CUSTOM) {
$id_address = (int) Configuration::get('PS_STANDARD_PRODUCT_ORDER_ADDRESS_ID');
} elseif ($addressPreferenceType != Product::STANDARD_PRODUCT_ADDRESS_PREFERENCE_HOTEL) {
$customer = Context::getContext()->customer;
if (Validate::isLoadedObject($customer) && ($idCustomerAddress = Address::getFirstCustomerAddressId($customer->id))) {
$id_address = $idCustomerAddress;
}
}
if (!$id_address && ($htlAddress = HotelBranchInformation::getAddress(Configuration::get('WK_PRIMARY_HOTEL')))) {
$id_address = $htlAddress['id_address'];
}
}
}
@@ -3827,26 +3887,6 @@ class CartCore extends ObjectModel
$total_discounts = $this->getOrderTotal(true, Cart::ONLY_DISCOUNTS);
$total_discounts_tax_exc = $this->getOrderTotal(false, Cart::ONLY_DISCOUNTS);
$objCartBookingData = new HotelCartBookingData();
$total_demands_wt = $objCartBookingData->getCartExtraDemands(
$this->id,
0,
0,
0,
0,
1,
0,
1
);
$total_demands = $objCartBookingData->getCartExtraDemands(
$this->id,
0,
0,
0,
0,
1,
0,
0
);
// The cart content is altered for display
foreach ($cart_rules as &$cart_rule) {
// If the cart rule is automatic (wihtout any code) and include free shipping, it should not be displayed as a cart rule but only set the shipping cost to 0
@@ -3932,9 +3972,41 @@ class CartCore extends ObjectModel
}
}
$totalRoomsCount = 0;
if ($htlCartData = HotelCartBookingData::getHotelCartBookingData(0)) {
foreach ($htlCartData as $roomTypeCart) {
$totalRoomsCount += $roomTypeCart['total_num_rooms'];
}
}
$nbTotalProducts = 0;
$objServiceProductCartDetail = new ServiceProductCartDetail();
foreach ($products as &$product) {
if (!$product['booking_product']) {
if (Product::SELLING_PREFERENCE_STANDALONE == $product['selling_preference_type']) {
$nbTotalProducts += (int) $product['cart_quantity'];
} elseif (Product::SELLING_PREFERENCE_HOTEL_STANDALONE == $product['selling_preference_type']
|| Product::SELLING_PREFERENCE_HOTEL_STANDALONE_AND_WITH_ROOM_TYPE == $product['selling_preference_type']
) {
if ($serviceProducts = $objServiceProductCartDetail->getServiceProductsInCart(
$this->id,
[Product::SELLING_PREFERENCE_HOTEL_STANDALONE, Product::SELLING_PREFERENCE_HOTEL_STANDALONE_AND_WITH_ROOM_TYPE],
null,
0,
null,
$product['id_product']
)) {
foreach ($serviceProducts as $serviceProduct) {
if ($serviceProduct['id_hotel'] && $serviceProduct['id_product'] == $product['id_product']) {
$nbTotalProducts += (int) $serviceProduct['quantity'];
}
}
}
}
}
}
$objHotelAdvancedPayment = new HotelAdvancedPayment();
$total_rooms_with_services_without_discount_te = $total_rooms + $total_demands + $total_additional_services + $total_additional_services_auto_add + $total_standalone_service_products;
$total_rooms_with_services_without_discount_ti = $total_rooms_wt + $total_demands_wt + $total_additional_services_wt + $total_additional_services_auto_add_wt + $total_standalone_service_products_wt;
$total_rooms_with_services_without_discount_te = $total_rooms + $total_additional_services + $total_additional_services_auto_add + $total_standalone_service_products;
$total_rooms_with_services_without_discount_ti = $total_rooms_wt + $total_additional_services_wt + $total_additional_services_auto_add_wt + $total_standalone_service_products_wt;
$cart_total_without_discount_te = $total_rooms_with_services_without_discount_te + $convenience_fee;
$cart_total_without_discount_ti = $total_rooms_with_services_without_discount_ti + $convenience_fee_wt;
@@ -3943,6 +4015,23 @@ class CartCore extends ObjectModel
$total_tax_without_discount = 0;
}
$tourismTaxTotals = $this->getOrderTotal(true, Cart::ONLY_TOURISM_TAX);
$tourism_tax = $tourismTaxTotals['tourism_tax'];
$tourism_tax_convenience_fee = $tourismTaxTotals['tourism_tax_convenience_fee'];
$tourism_tax_service = $tourismTaxTotals['tourism_tax_service'];
$tourism_tax_room = $tourismTaxTotals['tourism_tax_room'];
$tourism_tax_standalone_products = $tourismTaxTotals['tourism_tax_standalone_products'];
$roomGrossUpAmount = TaxConfiguration::isGrossedUp($tourism_tax_room) ? $tourism_tax_room : 0.0;
$serviceGrossUpAmount = TaxConfiguration::isGrossedUp($tourism_tax_service) ? $tourism_tax_service : 0.0;
$standaloneProductsGrossUpAmount = TaxConfiguration::isGrossedUp($tourism_tax_standalone_products) ? $tourism_tax_standalone_products : 0.0;
$convenienceFeeGrossUpAmount = TaxConfiguration::isGrossedUp($tourism_tax_convenience_fee) ? $tourism_tax_convenience_fee : 0.0;
$total_rooms_wt += $roomGrossUpAmount;
$total_additional_services_wt += $serviceGrossUpAmount;
$total_standalone_service_products_wt += $standaloneProductsGrossUpAmount;
$convenience_fee_wt += $convenienceFeeGrossUpAmount;
$total_rooms_with_services_without_discount_ti += $roomGrossUpAmount + $serviceGrossUpAmount + $standaloneProductsGrossUpAmount + $convenienceFeeGrossUpAmount;
$summary = array(
'delivery' => $delivery,
'delivery_state' => State::getNameById($delivery->id_state),
@@ -3972,8 +4061,6 @@ class CartCore extends ObjectModel
'convenience_fee_tax' => $convenience_fee_tax,
'total_standalone_service_products_wt' => $total_standalone_service_products_wt,
'total_standalone_service_products' => $total_standalone_service_products,
'total_extra_demands_wt' => $total_demands_wt,
'total_extra_demands' => $total_demands,
'total_price' => $base_total_tax_inc,
'total_tax' => $total_tax,
'total_price_without_tax' => $base_total_tax_exc,
@@ -3988,7 +4075,11 @@ class CartCore extends ObjectModel
'total_rooms_with_services_without_discount_ti' => $total_rooms_with_services_without_discount_ti,
'cart_total_without_discount_te' => $cart_total_without_discount_te,
'cart_total_without_discount_ti' => $cart_total_without_discount_ti,
'total_tax_without_discount' => $total_tax_without_discount
'total_tax_without_discount' => $total_tax_without_discount,
'tourism_tax' => max(0.0, (float) $tourism_tax),
'total_tourism_tax' => max(0.0, (float) $tourism_tax),
'tourism_tax_grossed_up' => TaxConfiguration::isGrossedUp($tourism_tax),
'total_products_in_cart' => $totalRoomsCount + $nbTotalProducts,
);
$hook = Hook::exec('actionCartSummary', $summary, null, true);
if (is_array($hook)) {
@@ -4907,20 +4998,11 @@ class CartCore extends ObjectModel
$idCustomer = $objCart->id_customer;
$idCurrency = $objCart->id_currency;
$extraDemands = null;
// We have to check the alreadt entered rooms for booking parameters with this variable as Also is sending all the rooms everytime
// because id_guest is not managed in the API call
$roomsAddedToCart = [];
foreach ($bookingRows as $booking) {
$booking = json_decode(json_encode($booking, true), true);
if (isset($booking['extra_demands']['extra_demand'])) {
$extraDemands = $booking['extra_demands']['extra_demand'];
if (isset($extraDemands['id_global_demand'])) {
$extraDemands = array($extraDemands);
}
$extraDemands = json_encode($extraDemands);
}
// get room booking info
$idProduct = $booking['id_product'];
@@ -5027,7 +5109,6 @@ class CartCore extends ObjectModel
$objCartBooking->id_hotel = $val_hotel_room_info['id_hotel'];
$objCartBooking->booking_type = HotelBookingDetail::ALLOTMENT_AUTO;
$objCartBooking->quantity = $numDays;
$objCartBooking->extra_demands = $extraDemands;
$objCartBooking->date_from = $dateFrom;
$objCartBooking->date_to = $dateTo;
$objCartBooking->save();

View File

@@ -1018,8 +1018,8 @@ class CartRuleCore extends ObjectModel
$all_cart_rules_ids = $context->cart->getOrderedCartRulesIds();
$cart_amount_ti = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$cart_amount_te = $context->cart->getOrderTotal(false, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$cart_amount_ti = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
$cart_amount_te = $context->cart->getOrderTotal(false, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
// Free shipping on selected carriers
if ($this->free_shipping && in_array($filter, array(CartRule::FILTER_ACTION_ALL, CartRule::FILTER_ACTION_ALL_NOCAP, CartRule::FILTER_ACTION_SHIPPING))) {
@@ -1045,7 +1045,7 @@ class CartRuleCore extends ObjectModel
// Discount (%) on the whole order
if ($this->reduction_percent && $this->reduction_product == 0) {
// Do not give a reduction on free products!
$order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_DEMANDS, $package_products);
$order_total = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE, $package_products);
foreach ($context->cart->getCartRules(CartRule::FILTER_ACTION_GIFT) as $cart_rule) {
$order_total -= Tools::ps_round($cart_rule['obj']->getContextualValue($use_tax, $context, CartRule::FILTER_ACTION_GIFT, $package), _PS_PRICE_COMPUTE_PRECISION_);
}
@@ -1118,9 +1118,9 @@ class CartRuleCore extends ObjectModel
if ((float)$this->reduction_amount > 0) {
$prorata = 1;
if (!is_null($package) && count($all_products)) {
$total_products = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$total_products = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
if ($total_products) {
$prorata = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_DEMANDS, $package['products']) / $total_products;
$prorata = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE, $package['products']) / $total_products;
}
}
@@ -1169,7 +1169,7 @@ class CartRuleCore extends ObjectModel
if ($this->reduction_tax == $use_tax) {
// The reduction cannot exceed the products total, except when we do not want it to be limited (for the partial use calculation)
if ($filter != CartRule::FILTER_ACTION_ALL_NOCAP) {
$cart_amount = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_DEMANDS);
$cart_amount = $context->cart->getOrderTotal($use_tax, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE);
$reduction_amount = min($reduction_amount, $cart_amount);
}
$reduction_value += $prorata * $reduction_amount;
@@ -1467,7 +1467,7 @@ class CartRuleCore extends ObjectModel
return array();
}
$order_total = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_DEMANDS, null, null, false);
$order_total = $context->cart->getOrderTotal(true, Cart::ONLY_PRODUCTS_WITH_ADDITIONAL_SERVICE, null, null, false);
static $errors = array();
foreach ($context->cart->getCartRules() as $cart_rule) {
if ($error = $cart_rule['obj']->checkValidity($context, true)) {

View File

@@ -41,6 +41,9 @@ class CustomerCore extends ObjectModel
/** @var int Gender ID */
public $id_gender = 0;
/** @var int Nationality, stored as a country ID */
public $id_country = 0;
/** @var int Default group ID */
public $id_default_group;
@@ -170,6 +173,7 @@ class CustomerCore extends ObjectModel
'passwd' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 60),
'last_passwd_gen' => array('type' => self::TYPE_STRING, 'copy_post' => false),
'id_gender' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_country' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'birthday' => array('type' => self::TYPE_DATE, 'validate' => 'isBirthDate'),
'newsletter' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'newsletter_date_add' => array('type' => self::TYPE_DATE,'copy_post' => false),
@@ -209,6 +213,10 @@ class CustomerCore extends ObjectModel
if (Configuration::get('PS_ONE_PHONE_AT_LEAST')) {
self::$definition['fields']['phone']['required'] = true;
}
if (Configuration::get('PS_CUSTOMER_NATIONALITY') && Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY')) {
self::$definition['fields']['id_country']['required'] = true;
}
}
public function validateFields($die = true, $error_return = false)
@@ -830,6 +838,16 @@ class CustomerCore extends ObjectModel
return (int) Configuration::get('PS_COUNTRY_DEFAULT');
}
public static function getNationalities($id_lang)
{
$nationalities = Country::getCountries((int) $id_lang);
$nationalities[-1] = array(
'id_country' => -1,
'name' => Translate::getAdminTranslation('Other', 'AdminCustomers'),
);
return $nationalities;
}
public function toggleStatus()
{

View File

@@ -26,6 +26,9 @@
class LanguageCore extends ObjectModel
{
const EMAIL_TEMPLATE_TYPE_CORE = 1;
const EMAIL_TEMPLATE_TYPE_MODULE = 2;
public $id;
/** @var string Name */
@@ -1065,4 +1068,69 @@ class LanguageCore extends ObjectModel
}
}
}
}
public static function resetEmailTemplate($mail_template_name, $iso, $template_type, $module_name = false, $theme = '')
{
$is_module_template = ($template_type === self::EMAIL_TEMPLATE_TYPE_MODULE);
if ($theme) {
$dest_dir = $is_module_template
? _PS_ROOT_DIR_.'/themes/'.$theme.'/modules/'.$module_name.'/mails/'.$iso.'/'
: _PS_ROOT_DIR_.'/themes/'.$theme.'/mails/'.$iso.'/';
} else {
$dest_dir = $is_module_template
? rtrim(_PS_MODULE_DIR_, '/').'/'.$module_name.'/mails/'.$iso.'/'
: _PS_MAIL_DIR_.$iso.'/';
}
// Reuse the already-downloaded language pack if we have one, only hit the API when it's missing
$gzip_file = _PS_TRANSLATIONS_DIR_.$iso.'.gzip';
if (!file_exists($gzip_file)) {
Language::downloadAndInstallLanguagePack($iso, null, null, false);
}
if (!file_exists($gzip_file)) {
return array('hasError' => true, 'error' => Tools::displayError('Could not download the language pack from the QloApps API. Please check your internet connection and try again.'));
}
require_once(_PS_TOOL_DIR_.'tar/Tar.php');
$gz = new Archive_Tar($gzip_file, true);
if ($gz->error_object) {
return array('hasError' => true, 'error' => Tools::displayError('The downloaded language pack is corrupted. Please try again.'));
}
$archive_dir = $is_module_template
? 'modules/'.$module_name.'/mails/'.$iso.'/'
: 'mails/'.$iso.'/';
$mail_dir = $is_module_template
? rtrim(_PS_MODULE_DIR_, '/').'/'.$module_name.'/mails/'
: _PS_MAIL_DIR_;
$content = array('html' => null, 'txt' => null);
foreach (array_keys($content) as $ext) {
$file_content = $gz->extractInString($archive_dir.$mail_template_name.'.'.$ext);
if ($file_content === null) {
if (file_exists($mail_dir.$iso.'/'.$mail_template_name.'.'.$ext)) {
$file_content = file_get_contents($mail_dir.$iso.'/'.$mail_template_name.'.'.$ext);
} elseif (file_exists($mail_dir.'en/'.$mail_template_name.'.'.$ext)) {
$file_content = file_get_contents($mail_dir.'en/'.$mail_template_name.'.'.$ext);
}
}
if ($file_content !== null) {
if (file_put_contents($dest_dir.$mail_template_name.'.'.$ext, $file_content) === false) {
return array('hasError' => true, 'error' => sprintf(Tools::displayError('Could not write file "%s".'), $dest_dir.$mail_template_name.'.'.$ext));
}
$content[$ext] = $file_content;
}
}
if ($content['html'] === null && $content['txt'] === null) {
return array('hasError' => true, 'error' => Tools::displayError('This template was not found in the downloaded language pack.'));
}
return array(
'hasError' => false,
'html' => $content['html'],
'txt' => $content['txt'],
);
}
}

View File

@@ -45,9 +45,9 @@ class MediaCore
'ui.tabs' => array('fileName' => 'jquery.ui.tabs.min.js', 'dependencies' => array('ui.core', 'ui.widget'), 'theme' => true),
'ui.datepicker' => array('fileName' => 'jquery.ui.datepicker.min.js', 'dependencies' => array('ui.core'), 'theme' => true),
'ui.progressbar' => array('fileName' => 'jquery.ui.progressbar.min.js', 'dependencies' => array('ui.core', 'ui.widget'), 'theme' => true),
'ui.tooltip' => array('fileName' => 'jquery.ui.tooltip.min.js', 'dependencies' => array('ui.core', 'ui.widget','ui.position','effects.core'), 'theme' => true),
'ui.accordion' => array('fileName' => 'jquery.ui.accordion.min.js', 'dependencies' => array('ui.core', 'ui.widget','effects.core'), 'theme' => true),
'effects.core' => array('fileName' => 'jquery.effects.core.min.js', 'dependencies' => array(), 'theme' => false),
'ui.tooltip' => array('fileName' => 'jquery.ui.tooltip.min.js', 'dependencies' => array('ui.core', 'ui.widget','ui.position','ui.effect'), 'theme' => true),
'ui.accordion' => array('fileName' => 'jquery.ui.accordion.min.js', 'dependencies' => array('ui.core', 'ui.widget','ui.effect'), 'theme' => true),
'ui.effect' => array('fileName' => 'jquery.ui.effect.min.js', 'dependencies' => array(), 'theme' => false),
'effects.blind' => array('fileName' => 'jquery.effects.blind.min.js', 'dependencies' => array('effects.core'), 'theme' => false),
'effects.bounce' => array('fileName' => 'jquery.effects.bounce.min.js', 'dependencies' => array('effects.core'), 'theme' => false),
'effects.clip' => array('fileName' => 'jquery.effects.clip.min.js', 'dependencies' => array('effects.core'), 'theme' => false),

View File

@@ -357,6 +357,13 @@ abstract class PaymentModuleCore extends Module
$order->source = Configuration::get('PS_SHOP_DOMAIN');
}
// Booking Source (business categorization, e.g. Direct Website/Walk-in/OTA) —
if (isset($this->idBookingSource) && $this->idBookingSource) {
$order->id_source = (int)$this->idBookingSource;
} else {
$order->id_source = (int)Source::getDefaultSourceId();
}
if (self::DEBUG_MODE) {
PrestaShopLogger::addLog('PaymentModule::validateOrder - Order is about to be added', 1, null, 'Cart', (int)$id_cart, true);
}
@@ -510,6 +517,7 @@ abstract class PaymentModuleCore extends Module
$objMail = new Mail();
$objServiceProductCartDetail = new ServiceProductCartDetail();
$cart_rules = $this->context->cart->getCartRules();
$useTourismTax = (bool) Configuration::get('QLO_USE_TOURISM_TAX');
foreach ($order_detail_list as $key => $order_detail) {
/** @var OrderDetail $order_detail */
@@ -913,64 +921,37 @@ abstract class PaymentModuleCore extends Module
);
}
}
if ($objBookingDetail->save()) {
// save extra demands info
if ($objCartBookingData->extra_demands
&& ($extraDemands = json_decode($objCartBookingData->extra_demands, true))
) {
$objRoomDemandPrice = new HotelRoomTypeDemandPrice();
foreach ($extraDemands as $demand) {
$idGlobalDemand = $demand['id_global_demand'];
$idOption = $demand['id_option'];
$objBookingDemand = new HotelBookingDemands();
$objBookingDemand->id_htl_booking = $objBookingDetail->id;
$objGlobalDemand = new HotelRoomTypeGlobalDemand($idGlobalDemand, $idLang);
if ($idOption) {
$objOption = new HotelRoomTypeGlobalDemandAdvanceOption($idOption, $idLang);
$objBookingDemand->name = $objOption->name;
} else {
$idOption = 0;
$objBookingDemand->name = $objGlobalDemand->name;
}
$objBookingDemand->unit_price_tax_excl = HotelRoomTypeDemand::getPriceStatic(
$idProduct,
$idGlobalDemand,
$idOption,
0
);
$objBookingDemand->unit_price_tax_incl = HotelRoomTypeDemand::getPriceStatic(
$idProduct,
$idGlobalDemand,
$idOption,
1
);
if (!$objBookingDetail->save()) {
PrestaShopLogger::addLog('PaymentModule::validateOrder - Cannot save Booking Detail', 3, null, 'Cart', (int)$id_cart, true);
throw new PrestaShopException('Can\'t save Booking Detail');
}
$numDays = 1;
if ($objGlobalDemand->price_calc_method == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY) {
$numDays = HotelHelper::getNumberOfDays(
$objBookingDetail->date_from,
$objBookingDetail->date_to
);
}
OrderTaxDetail::updateVatScoping((int) $id_order_detail, (int) $objBookingDetail->id, 0);
$objBookingDemand->total_price_tax_excl = $objBookingDemand->unit_price_tax_excl * $numDays;
$objBookingDemand->total_price_tax_incl = $objBookingDemand->unit_price_tax_incl * $numDays;
if ($useTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$hotelTaxContext = TaxConfiguration::resolveHotelAddressAndCollectionType($objCartBookingData->id_hotel, new Address((int) Cart::getIdAddressForTaxCalculation($idProduct)));
$numNights = max(1, HotelHelper::getNumberOfDays($objBookingDetail->date_from, $objBookingDetail->date_to));
$numAdults = (int) $objCartBookingData->adults;
$childAges = !empty($objCartBookingData->child_ages) ? (array) json_decode($objCartBookingData->child_ages, true) : array();
$unitPriceTaxExcl = (float) $total_price['total_price_tax_excl'] / $numNights;
$objBookingDemand->price_calc_method = $objGlobalDemand->price_calc_method;
$objBookingDemand->id_tax_rules_group = $objGlobalDemand->id_tax_rules_group;
$taxManager = TaxManagerFactory::getManager(
$vatAddress,
$objGlobalDemand->id_tax_rules_group
);
$taxCalc = $taxManager->getTaxCalculator();
$objBookingDemand->tax_computation_method = (int)$taxCalc->computation_method;
if ($objBookingDemand->save()) {
$objBookingDemand->tax_calculator = $taxCalc;
// Now save tax details of the extra demand
$objBookingDemand->setBookingDemandTaxDetails();
}
}
}
OrderTaxDetail::saveTourismTax(
$idTourismTaxRulesGroup,
$hotelTaxContext['address'],
$unitPriceTaxExcl,
$objBookingDetail->date_from,
$numNights,
$numAdults,
$childAges,
(int) $this->context->cart->id_currency,
$hotelTaxContext['collectionType'],
(int) $idLang,
1,
$order->id,
(int) $id_order_detail,
$objBookingDetail->id,
0
);
}
}
} else {
@@ -1013,7 +994,30 @@ abstract class PaymentModuleCore extends Module
$objServiceProductOrderDetail->name = $product['name'];
$objServiceProductOrderDetail->quantity = $roomTypeService['quantity'];
$objServiceProductOrderDetail->auto_added = $product['auto_add_to_cart'];
$objServiceProductOrderDetail->save();
if ($objServiceProductOrderDetail->save()) {
OrderTaxDetail::updateVatScoping((int) $objServiceProductOrderDetail->id_order_detail, 0, (int) $objServiceProductOrderDetail->id);
if ($useTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$tourismTaxContext = TaxConfiguration::resolveServiceLineTaxContext($roomBookingDetail['id_hotel'], $roomBookingDetail['id'], new Address((int) Cart::getIdAddressForTaxCalculation($idProduct)));
OrderTaxDetail::saveTourismTax(
$idTourismTaxRulesGroup,
$tourismTaxContext['address'],
(float) $objServiceProductOrderDetail->unit_price_tax_excl,
$tourismTaxContext['checkInDate'],
$tourismTaxContext['numNights'],
$tourismTaxContext['numAdults'],
$tourismTaxContext['childrenAges'],
(int) $this->context->cart->id_currency,
$tourismTaxContext['collectionType'],
(int) $idLang,
(int) $objServiceProductOrderDetail->quantity,
$order->id,
(int) $objServiceProductOrderDetail->id_order_detail,
0,
(int) $objServiceProductOrderDetail->id
);
}
}
}
}
} elseif (Product::SELLING_PREFERENCE_HOTEL_STANDALONE == $product['selling_preference_type']) {
@@ -1046,7 +1050,30 @@ abstract class PaymentModuleCore extends Module
$objServiceProductOrderDetail->hotel_name = $objHotelBranch->hotel_name;
}
$objServiceProductOrderDetail->quantity = $hotelProduct['quantity'];
$objServiceProductOrderDetail->save();
if ($objServiceProductOrderDetail->save()) {
OrderTaxDetail::updateVatScoping((int) $objServiceProductOrderDetail->id_order_detail, 0, (int) $objServiceProductOrderDetail->id);
if ($useTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$tourismTaxContext = TaxConfiguration::resolveServiceLineTaxContext($product['id_hotel'], 0, new Address((int) Cart::getIdAddressForTaxCalculation($idProduct)));
OrderTaxDetail::saveTourismTax(
$idTourismTaxRulesGroup,
$tourismTaxContext['address'],
(float) $objServiceProductOrderDetail->unit_price_tax_excl,
$tourismTaxContext['checkInDate'],
$tourismTaxContext['numNights'],
$tourismTaxContext['numAdults'],
$tourismTaxContext['childrenAges'],
(int) $this->context->cart->id_currency,
$tourismTaxContext['collectionType'],
(int) $idLang,
(int) $objServiceProductOrderDetail->quantity,
$order->id,
(int) $objServiceProductOrderDetail->id_order_detail,
0,
(int) $objServiceProductOrderDetail->id
);
}
}
}
}
@@ -1074,7 +1101,30 @@ abstract class PaymentModuleCore extends Module
$objServiceProductOrderDetail->name = $standaloneProduct['name'];
$objServiceProductOrderDetail->option_name = $standaloneProduct['option_name'];
$objServiceProductOrderDetail->quantity = $standaloneProduct['quantity'];
$objServiceProductOrderDetail->save();
if ($objServiceProductOrderDetail->save()) {
OrderTaxDetail::updateVatScoping((int) $objServiceProductOrderDetail->id_order_detail, 0, (int) $objServiceProductOrderDetail->id);
if ($useTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$tourismTaxContext = TaxConfiguration::resolveServiceLineTaxContext(0, 0, new Address((int) Cart::getIdAddressForTaxCalculation($idProduct)));
OrderTaxDetail::saveTourismTax(
$idTourismTaxRulesGroup,
$tourismTaxContext['address'],
(float) $objServiceProductOrderDetail->unit_price_tax_excl,
$tourismTaxContext['checkInDate'],
$tourismTaxContext['numNights'],
$tourismTaxContext['numAdults'],
$tourismTaxContext['childrenAges'],
(int) $this->context->cart->id_currency,
$tourismTaxContext['collectionType'],
(int) $idLang,
(int) $objServiceProductOrderDetail->quantity,
$order->id,
(int) $objServiceProductOrderDetail->id_order_detail,
0,
(int) $objServiceProductOrderDetail->id
);
}
}
}
}
@@ -1131,7 +1181,32 @@ abstract class PaymentModuleCore extends Module
$objServiceProductOrderDetail->id_htl_booking_detail = $roomBookingDetail['id'];
$objServiceProductOrderDetail->auto_added = $product['auto_add_to_cart'];
}
$objServiceProductOrderDetail->save();
if ($objServiceProductOrderDetail->save()) {
OrderTaxDetail::updateVatScoping((int) $objServiceProductOrderDetail->id_order_detail, 0, (int) $objServiceProductOrderDetail->id);
$idHotel = $serviceProduct['id_hotel'] ? $serviceProduct['id_hotel'] : (isset($roomBookingDetail['id_hotel']) ? (int) $roomBookingDetail['id_hotel'] : 0);
$idHtlBookingDetail = $serviceProduct['id_hotel'] ? 0 : (isset($roomBookingDetail['id']) ? (int) $roomBookingDetail['id'] : 0);
if ($useTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$tourismTaxContext = TaxConfiguration::resolveServiceLineTaxContext($idHotel, $idHtlBookingDetail, new Address((int) Cart::getIdAddressForTaxCalculation($idProduct)));
OrderTaxDetail::saveTourismTax(
$idTourismTaxRulesGroup,
$tourismTaxContext['address'],
(float) $objServiceProductOrderDetail->unit_price_tax_excl,
$tourismTaxContext['checkInDate'],
$tourismTaxContext['numNights'],
$tourismTaxContext['numAdults'],
$tourismTaxContext['childrenAges'],
(int) $this->context->cart->id_currency,
$tourismTaxContext['collectionType'],
(int) $idLang,
(int) $objServiceProductOrderDetail->quantity,
$order->id,
(int) $objServiceProductOrderDetail->id_order_detail,
0,
(int) $objServiceProductOrderDetail->id
);
}
}
}
}
}
@@ -1237,8 +1312,8 @@ abstract class PaymentModuleCore extends Module
$cart_booking_data_text = $this->getEmailTemplateContent('hotel_booking_cart_data_text.tpl', Mail::TYPE_TEXT, $cart_booking_data['cart_htl_data']);
$cart_booking_data_html = $this->getEmailTemplateContent('hotel_booking_cart_data.tpl', Mail::TYPE_HTML, $cart_booking_data['cart_htl_data']);
$extra_demands_details_html = $this->getEmailTemplateContent('booking_extra_demands.tpl', Mail::TYPE_HTML, $cart_booking_data['cart_htl_data']);
$extra_demands_details_text = $this->getEmailTemplateContent('booking_extra_demands_text.tpl', Mail::TYPE_TEXT, $cart_booking_data['cart_htl_data']);
$extra_services_details_html = $this->getEmailTemplateContent('booking_extra_services.tpl', Mail::TYPE_HTML, $cart_booking_data['cart_htl_data']);
$extra_services_details_text = $this->getEmailTemplateContent('booking_extra_services_text.tpl', Mail::TYPE_TEXT, $cart_booking_data['cart_htl_data']);
$normal_products_data_html = $this->getEmailTemplateContent('service_product_data.tpl', Mail::TYPE_HTML, $orderServiceProducts);
$normal_products_data_txt = $this->getEmailTemplateContent('service_product_data_text.tpl', Mail::TYPE_TEXT, $orderServiceProducts);
@@ -1250,8 +1325,8 @@ abstract class PaymentModuleCore extends Module
$room_tax = ($room_price_tax_incl - $room_price_tax_excl);
// extra services
$additional_service_price_tax_excl = ($order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0) + $cart_booking_data['total_extra_demands_te']);
$additional_service_price_tax_incl = ($order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0) + $cart_booking_data['total_extra_demands_ti']);
$additional_service_price_tax_excl = ($order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0));
$additional_service_price_tax_incl = ($order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0));
$additional_service_tax = ($additional_service_price_tax_incl - $additional_service_price_tax_excl);
// convenience fee price
@@ -1267,7 +1342,8 @@ abstract class PaymentModuleCore extends Module
$service_products_tax = ($standalone_products_price_tax_incl + $hotel_standalone_products_price_tax_incl) - ($standalone_products_price_tax_excl + $hotel_standalone_products_price_tax_excl);
$total_order_tax = $room_tax + $additional_service_tax + $total_convenience_fee_tax + $service_products_tax;
$totalTourismTax = OrderTaxDetail::getOrderTourismTaxTotal((int) $order->id);
$total_order_tax = max(0, $room_tax + $additional_service_tax + $total_convenience_fee_tax + $service_products_tax - $totalTourismTax);
$total_products = Tools::displayPrice(Product::getTaxCalculationMethod() == PS_TAX_EXC ? $order->total_products : $order->total_products_wt, $this->context->currency, false);
@@ -1293,6 +1369,8 @@ abstract class PaymentModuleCore extends Module
),
'service_products_tax' => Tools::displayPrice($service_products_tax, $this->context->currency, false),
'total_order_tax' => Tools::displayPrice($total_order_tax, $this->context->currency, false),
'total_tourism_tax' => Tools::displayPrice($totalTourismTax, $this->context->currency, false),
'has_tourism_tax' => $totalTourismTax > 0,
'total_paid' => Tools::displayPrice($order->total_paid, $this->context->currency, false),
'total_products' => Tools::displayPrice($total_products, $this->context->currency, false),
'total_discounts' => Tools::displayPrice(-$order->total_discounts, $this->context->currency, false),
@@ -1311,22 +1389,12 @@ abstract class PaymentModuleCore extends Module
$data = array(
'{cart_booking_data_html}' => $cart_booking_data_html,
'{cart_booking_data_text}' => $cart_booking_data_text,
'{extra_demands_details_html}' => $extra_demands_details_html,
'{extra_demands_details_text}' => $extra_demands_details_text,
'{extra_services_details_html}' => $extra_services_details_html,
'{extra_services_details_text}' => $extra_services_details_text,
'{normal_products_data_html}' => $normal_products_data_html,
'{normal_products_data_txt}' => $normal_products_data_txt,
'{order_total_info_html}' => $order_total_info_html,
'{order_total_info_txt}' => $order_total_info_txt,
'{total_extra_demands_te}' => Tools::displayPrice(
$cart_booking_data['total_extra_demands_te'],
$this->context->currency,
false
),
'{extra_demands_tax}' => Tools::displayPrice(
($cart_booking_data['total_extra_demands_ti']-$cart_booking_data['total_extra_demands_te']),
$this->context->currency,
false
),
'{delivery_company}' => $delivery->company,
'{delivery_firstname}' => $delivery->firstname,
'{delivery_lastname}' => $delivery->lastname,
@@ -1895,10 +1963,7 @@ abstract class PaymentModuleCore extends Module
$obj_cart_bk_data = new HotelCartBookingData();
$obj_htl_bk_dtl = new HotelBookingDetail();
$obj_rm_type = new HotelRoomType();
$objBookingDemand = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$result['total_extra_demands_te'] = 0;
$result['total_extra_demands_ti'] = 0;
$cart_htl_data = array();
if (!empty($products)) {
foreach ($products as $type_key => $type_value) {
@@ -1972,35 +2037,6 @@ abstract class PaymentModuleCore extends Module
$cart_htl_data[$type_key]['date_diff'][$date_join]['adults'] = $data_v['adults'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['children'] = $data_v['children'];
// extra demands prices
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to']
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services'] = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$order->id,
0,
@@ -2046,9 +2082,6 @@ abstract class PaymentModuleCore extends Module
$cart_htl_data[$type_key]['date_diff'][$date_join]['avg_paid_unit_price_tax_excl'] = ($cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] + $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te']);
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = ($data_v['total_price_tax_incl'] + $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_ti']);
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_excl'] = ($data_v['total_price_tax_excl'] + $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te']);
$result['total_extra_demands_te'] += $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'];
$result['total_extra_demands_ti'] += $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'];
}
}
// calculate averages now

View File

@@ -226,6 +226,9 @@ class ProductCore extends ObjectModel
public $id_tax_rules_group = 1;
/** @var int Tourism tax rules group id (0 = no tourism tax) */
public $id_tourism_tax_rules_group = 0;
/**
* We keep this variable for retrocompatibility for themes
* @deprecated 1.5.0
@@ -313,8 +316,9 @@ class ProductCore extends ObjectModel
/* Shop fields */
'id_category_default' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedId'),
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedId'),
'on_sale' => array('type' => self::TYPE_BOOL, 'shop' => true, 'validate' => 'isBool'),
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedId'),
'id_tourism_tax_rules_group' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedId'),
'on_sale' => array('type' => self::TYPE_BOOL, 'shop' => true, 'validate' => 'isBool'),
'online_only' => array('type' => self::TYPE_BOOL, 'shop' => true, 'validate' => 'isBool'),
'ecotax' => array('type' => self::TYPE_FLOAT, 'shop' => true, 'validate' => 'isPrice'),
'minimal_quantity' => array('type' => self::TYPE_INT, 'shop' => true, 'validate' => 'isUnsignedInt'),
@@ -469,14 +473,6 @@ class ProductCore extends ObjectModel
'id' => array('required' => true),
)
),
'extra_demands' => array(
'resource' => 'extra_demand',
'fields' => array(
'id' => array('required' => true),
'id_option' => array(),
'price' => array(),
)
),
'services' => array(
'resource' => 'service',
'fields' => array(
@@ -5426,6 +5422,31 @@ class ProductCore extends ObjectModel
return Cache::retrieve($key);
}
/**
* Returns the tourism tax rules group assigned to a product, mirroring
* getIdTaxRulesGroupByIdProduct() for tourism tax's own product_shop column.
*
* @param int $id_product
* @param Context|null $context
* @return int
*/
public static function getIdTourismTaxRulesGroupByIdProduct($id_product, ?Context $context = null)
{
if (!$context) {
$context = Context::getContext();
}
$key = 'product_id_tourism_tax_rules_group_'.(int)$id_product.'_'.(int)$context->shop->id;
if (!Cache::isStored($key)) {
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `id_tourism_tax_rules_group`
FROM `'._DB_PREFIX_.'product_shop`
WHERE `id_product` = '.(int)$id_product.' AND id_shop='.(int)$context->shop->id);
Cache::store($key, (int)$result);
return (int)$result;
}
return Cache::retrieve($key);
}
/**
* Returns tax rate.
*
@@ -6627,35 +6648,6 @@ class ProductCore extends ObjectModel
);
}
public function getWsExtraDemands()
{
$objHotelRoomTypeDemand = new HotelRoomTypeDemand();
$selectedDemands = Db::getInstance()->executeS(
'SELECT `id_global_demand` as `id` FROM `'._DB_PREFIX_.'htl_room_type_demand`
WHERE `id_product` = '.(int)$this->id
);
$res = array();
$demands = $objHotelRoomTypeDemand->getRoomTypeDemands($this->id);
if ($selectedDemands) {
foreach ($selectedDemands as $id_demand => $demand) {
$option['id'] = $demand['id'];
if (isset($demands[$demand['id']]['adv_option']) && count($demands[$demand['id']]['adv_option'])) {
foreach ($demands[$demand['id']]['adv_option'] as $id_option => $adv_option) {
$option['id_option'] = $id_option;
$option['price'] = $adv_option['price_tax_excl'];
$res[] = $option;
}
} else {
$option['id_option'] = false;
$option['price'] = $demand['price_tax_excl'];
$res[] = $option;
}
}
}
return $res;
}
public function getWsServices()
{
return Db::getInstance()->executeS(
@@ -6718,59 +6710,6 @@ class ProductCore extends ObjectModel
return $this->delete();
}
public function setWsExtraDemands($demands)
{
Db::getInstance()->execute('
DELETE FROM `'._DB_PREFIX_.'htl_room_type_demand`
WHERE `id_product` = '.(int)$this->id
);
Db::getInstance()->execute('
DELETE FROM `'._DB_PREFIX_.'htl_room_type_demand_price`
WHERE `id_product` = '.(int)$this->id
);
$objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption();
$savedDemands = array();
foreach ($demands as $globalDemand) {
if (Validate::isLoadedObject($objGlobalDemand = new HotelRoomTypeGlobalDemand($globalDemand['id']))) {
if (!isset($savedDemands[$globalDemand['id']])) {
$objRoomTypeDemand = new HotelRoomTypeDemand();
$objRoomTypeDemand->id_product = $this->id;
$objRoomTypeDemand->id_global_demand = $objGlobalDemand->id;
$objRoomTypeDemand->save();
$savedDemands[$globalDemand['id']] = $objRoomTypeDemand->id;
}
if (isset($globalDemand['price'])) {
if ($objAdvOption->getGlobalDemandAdvanceOptions($objGlobalDemand->id)
&& isset($globalDemand['id_option'])
&& Validate::isLoadedObject($objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption($globalDemand['id_option']))
) {
if ($globalDemand['price'] != $objAdvOption->price) {
$objRoomTypeDemandPrice = new HotelRoomTypeDemandPrice();
$objRoomTypeDemandPrice->id_product = $this->id;
$objRoomTypeDemandPrice->id_global_demand = $objGlobalDemand->id;
$objRoomTypeDemandPrice->id_option = $objAdvOption->id;
$objRoomTypeDemandPrice->price = $globalDemand['price'];
$objRoomTypeDemandPrice->save();
}
} else {
// save selected demands prices for this room type
if ($objGlobalDemand->price != $globalDemand['price']) {
$objRoomTypeDemandPrice = new HotelRoomTypeDemandPrice();
$objRoomTypeDemandPrice->id_product = $this->id;
$objRoomTypeDemandPrice->id_global_demand = $objGlobalDemand->id;
$objRoomTypeDemandPrice->id_option = 0;
$objRoomTypeDemandPrice->price = $globalDemand['price'];
$objRoomTypeDemandPrice->save();
}
}
}
}
}
return true;
}
public function setWsServices($services)
{
Db::getInstance()->execute('
@@ -6833,21 +6772,24 @@ class ProductCore extends ObjectModel
$idAddress = null,
$useReduc = 1,
$idGroup = null,
$idCartBooking = 0
$idCartBooking = 0,
$includeTourismTax = false,
$numAdults = null,
$childrenAges = null
) {
if ($useTax === null) {
$useTax = Product::$_taxCalculationMethod == PS_TAX_EXC ? false : true;
}
$price = Product::getPriceStatic(
(int)$idProduct,
$idProduct,
$useTax,
$idProductOption,
6,
null,
false,
$useReduc,
(int)$quantity,
$quantity,
false,
null,
$idCart,
@@ -6857,8 +6799,8 @@ class ProductCore extends ObjectModel
true,
null,
true,
(int)$idHotel,
(int)$idProductRoomType,
$idHotel,
$idProductRoomType,
$idGroup,
$idCartBooking
);
@@ -6879,22 +6821,56 @@ class ProductCore extends ObjectModel
)
);
if (Product::getProductPriceCalculation($idProduct) == Product::PRICE_CALCULATION_METHOD_PER_DAY
&& $dateFrom && $dateTo
) {
$isPerDay = Product::getProductPriceCalculation($idProduct) == Product::PRICE_CALCULATION_METHOD_PER_DAY
&& $dateFrom && $dateTo;
if ($isPerDay) {
$price = $price * HotelHelper::getNumberOfDays($dateFrom, $dateTo);
}
$price = $price * (int)$quantity;
$price = $price * $quantity;
if (!$specificPrice || ($specificPrice['id_cart'] == 0 && $specificPrice['id_htl_cart_booking'] == 0)) {
if (!$idGroup || !Validate::isLoadedObject(new Group((int)$idGroup))) {
$idGroup = (int)Group::getCurrent()->id;
$tourismTaxHotelId = $idHotel;
if (!$tourismTaxHotelId && $idProductRoomType) {
$objRoomType = new HotelRoomType();
if ($roomTypeInfo = $objRoomType->getRoomTypeInfoByIdProduct($idProductRoomType)) {
$tourismTaxHotelId = $roomTypeInfo['id_hotel'];
}
$price = Product::applyGroupDiscount($price, $idProduct, $idGroup);
}
if ($includeTourismTax && ($idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct($idProduct))) {
$priceCalcNumDays = $isPerDay ? HotelHelper::getNumberOfDays($dateFrom, $dateTo) : 1;
$unitPriceExcl = ($useTax ? Product::getServiceProductPrice($idProduct, $idProductOption, $idHotel, $idProductRoomType, false, 1, $dateFrom, $dateTo, $idCart, $idAddress, $useReduc, $idGroup, $idCartBooking) : $price / (int) $quantity) / $priceCalcNumDays;
$fallbackAddress = new Address(Cart::getIdAddressForTaxCalculation($idProduct));
if ($numAdults === null) {
$taxContext = TaxConfiguration::resolveServiceLineTaxContext($tourismTaxHotelId, 0, $fallbackAddress, $idCartBooking);
} else {
// caller supplied its own occupancy (e.g. a live search form) — use it as-is, only resolve address/collection type
$hotelContext = TaxConfiguration::resolveHotelAddressAndCollectionType($tourismTaxHotelId, $fallbackAddress);
$taxContext = array(
'address' => $hotelContext['address'],
'collectionType' => $hotelContext['collectionType'],
'checkInDate' => $dateFrom,
'numNights' => max(1, HotelHelper::getNumberOfDays($dateFrom, $dateTo)),
'numAdults' => $numAdults,
'childrenAges' => $childrenAges ?: array(),
);
}
// no $idCurrency passed — TaxCalculator::getTaxesAmount() already resolves it from the current context when null
$taxCalculator = TaxManagerFactory::getManager($taxContext['address'], $idTourismTaxRulesGroup)->getTaxCalculator();
$price += $taxCalculator->getTaxesTotalAmount(
$unitPriceExcl,
$taxContext['checkInDate'],
$taxContext['numNights'],
$taxContext['numAdults'],
$taxContext['childrenAges'],
$taxContext['collectionType'],
$quantity
);
}
return $price;
}
/**

241
classes/Source.php Normal file
View File

@@ -0,0 +1,241 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class SourceCore extends ObjectModel
{
public $name;
public $id_business_source;
public $code;
public $position;
public $unremovable;
public $active;
public $deleted = 0;
public $date_add;
public $date_upd;
public static $definition = array(
'table' => 'source',
'primary' => 'id_source',
'multilang' => true,
'fields' => array(
'id_business_source' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'code' => array('type' => self::TYPE_STRING, 'validate' => 'isModuleName', 'required' => true, 'size' => 64),
'position' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'unremovable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
),
);
public function add($autodate = true, $nullValues = false)
{
if ($this->position <= 0) {
$this->position = Source::getHigherPosition($this->id_business_source) + 1;
}
return parent::add($autodate, $nullValues);
}
public static function getHigherPosition($idBusinessSource)
{
$position = Db::getInstance()->getValue(
'SELECT MAX(`position`) FROM `'._DB_PREFIX_.'source`
WHERE `id_business_source` = '.(int)$idBusinessSource.' AND `deleted` = 0'
);
return is_numeric($position) ? (int)$position : -1;
}
public function updatePosition($way, $position)
{
if (!$res = Db::getInstance()->executeS('
SELECT `position`, `id_source`
FROM `'._DB_PREFIX_.'source`
WHERE `id_business_source` = '.(int)$this->id_business_source.' AND `deleted` = 0
ORDER BY `position` ASC'
)) {
return false;
}
$moved_item = null;
foreach ($res as $row) {
if ((int)$row['id_source'] == (int)$this->id) {
$moved_item = $row;
}
}
if (!$moved_item) {
return false;
}
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = `position` '.($way ? '- 1' : '+ 1').'
WHERE `id_business_source` = '.(int)$this->id_business_source.' AND `deleted` = 0 AND `position`
'.($way
? '> '.(int)$moved_item['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_item['position'].' AND `position` >= '.(int)$position)
) && Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = '.(int)$position.'
WHERE `id_source` = '.(int)$moved_item['id_source']));
}
public static function codeExists($code, $idExclude = 0)
{
return (bool)Db::getInstance()->getValue(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source`
WHERE `code` = \''.pSQL($code).'\' AND `id_source` != '.(int)$idExclude
);
}
public static function getIdByCode($code)
{
return (int)Db::getInstance()->getValue(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source`
WHERE `code` = \''.pSQL($code).'\' AND `deleted` = 0'
);
}
public static function getUnremovableIds()
{
$rows = Db::getInstance()->executeS(
'SELECT `id_source` FROM `'._DB_PREFIX_.'source` WHERE `unremovable` = 1 AND `deleted` = 0'
);
return array_map('intval', array_column($rows, 'id_source'));
}
public static function getActiveSource($idBusinessSource, $idSource, $idLang)
{
return Db::getInstance()->executeS('
SELECT a.`id_source`, al.`name`
FROM `'._DB_PREFIX_.'source` a
LEFT JOIN `'._DB_PREFIX_.'source_lang` al ON (al.`id_source` = a.`id_source` AND al.`id_lang` = '.(int)$idLang.')
WHERE a.`id_business_source` = '.(int)$idBusinessSource.' AND a.`deleted` = 0 AND a.`id_source` NOT IN ('.(int)$idSource.') AND a.`active` = 1
ORDER BY a.`position` ASC
');
}
public static function getAllSource($active = null, $idLang = null)
{
$idLang = $idLang ?: (int)Context::getContext()->language->id;
$where = ' WHERE a.`deleted` = 0';
if ($active !== null) {
$where .= ' AND a.`active` = '.(int)(bool)$active;
}
return Db::getInstance()->executeS('
SELECT a.`id_source`, a.`id_business_source`, a.`code`, al.`name`, bsl.`name` AS `business_source_name`
FROM `'._DB_PREFIX_.'source` a
LEFT JOIN `'._DB_PREFIX_.'source_lang` al ON (al.`id_source` = a.`id_source` AND al.`id_lang` = '.(int)$idLang.')
LEFT JOIN `'._DB_PREFIX_.'business_source_lang` bsl ON (bsl.`id_business_source` = a.`id_business_source` AND bsl.`id_lang` = '.(int)$idLang.')
'.$where.'
ORDER BY a.`id_business_source` ASC, a.`position` ASC
');
}
public static function getSourcesUsedInOrders($idLang)
{
return Db::getInstance()->executeS('
SELECT DISTINCT o.`id_source`, sl.`name`
FROM `'._DB_PREFIX_.'orders` o
INNER JOIN `'._DB_PREFIX_.'source` s ON (s.`id_source` = o.`id_source`)
LEFT JOIN `'._DB_PREFIX_.'source_lang` sl ON (sl.`id_source` = s.`id_source` AND sl.`id_lang` = '.(int)$idLang.')
');
}
public static function cleanPositions($idBusinessSource)
{
$return = true;
$result = Db::getInstance()->executeS('
SELECT `id_source`
FROM `'._DB_PREFIX_.'source`
WHERE `id_business_source` = '.(int)$idBusinessSource.' AND `deleted` = 0
ORDER BY `position` ASC'
);
$i = 0;
foreach ($result as $row) {
$return = Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'source`
SET `position` = '.(int)$i++.'
WHERE `id_source` = '.(int)$row['id_source']
) && $return;
}
return $return;
}
public function isRemovable()
{
return !$this->unremovable;
}
public function isUsedByOrder()
{
return (bool)Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` WHERE `id_source` = '.(int)$this->id
);
}
public function mergeOrdersInto($idTargetSource)
{
return (bool)Db::getInstance()->execute(
'UPDATE `'._DB_PREFIX_.'orders` SET `id_source` = '.(int)$idTargetSource.' WHERE `id_source` = '.(int)$this->id
);
}
public static function getTotalOrderCount()
{
return (int)Db::getInstance()->getValue('SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders`');
}
public function delete()
{
if (!$this->isRemovable()) {
return false;
}
if ($this->isUsedByOrder()) {
$this->deleted = 1;
if (!$this->update()) {
return false;
}
} elseif (!parent::delete()) {
return false;
}
return Source::cleanPositions($this->id_business_source);
}
public static function getDefaultSourceId()
{
return (int)Configuration::get('PS_DEFAULT_BOOKING_SOURCE');
}
}

View File

@@ -255,8 +255,10 @@ class TranslateCore
$i18n_file = $override_i18n_file;
}
if (!include($i18n_file)) {
Tools::displayError(sprintf('Cannot include PDF translation language file : %s', $i18n_file));
if (file_exists($i18n_file)) {
if (!include($i18n_file)) {
Tools::displayError(sprintf('Cannot include PDF translation language file : %s', $i18n_file));
}
}
if (!isset($_LANGPDF) || !is_array($_LANGPDF)) {

View File

@@ -660,11 +660,11 @@ class FrontControllerCore extends Controller
}
/**
* Renders and outputs maintenance page and ends controller process.
* Redirects a cursed request (e.g. an invalid/expired access token) to page not found and ends controller process.
*/
public function initCursedPage()
{
$this->displayMaintenancePage();
Tools::redirect($this->context->link->getPageLink('pagenotfound'));
}
/**

View File

@@ -44,7 +44,7 @@ class HelperKpiRowCore extends Helper
if (isset($this->context->cookie->$cookieKey)) {
$kpi->visible = (bool) $this->context->cookie->$cookieKey;
} else {
$kpi->visible = true;
$kpi->visible = isset($kpi->visible) ? (bool) $kpi->visible : true;
}
$countVisible = $kpi->visible ? ++$countVisible : $countVisible;

View File

@@ -271,6 +271,7 @@ class OrderCore extends ObjectModel
'invoice_date' => array('type' => self::TYPE_DATE),
'delivery_date' => array('type' => self::TYPE_DATE),
'source' => array('type' => self::TYPE_STRING),
'id_source' => array('type' => self::TYPE_INT),
'valid' => array('type' => self::TYPE_BOOL),
'reference' => array('type' => self::TYPE_STRING),
'is_advance_payment' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'default' => 0),
@@ -1161,16 +1162,25 @@ class OrderCore extends ObjectModel
$selling_preference_type = null,
$product_auto_add = null,
$product_price_addition_type = null,
$ids_order_detail = []
$ids_order_detail = [],
$includeTourismTax = true
) {
/* Retro-compatibility (now set directly on the validateOrder() method) */
if (!$products) {
$products = $this->getProductsDetail($bookingProducts, $selling_preference_type, $product_auto_add, $product_price_addition_type, $ids_order_detail);
}
$tourismTaxByOrderDetail = array();
if (!$includeTourismTax && $products) {
$tourismTaxByOrderDetail = OrderTaxDetail::getAmountsByOrderDetail((int) $this->id);
}
$return = 0;
foreach ($products as $row) {
$return += $row['total_price_tax_incl'];
if (!$includeTourismTax) {
$return -= isset($tourismTaxByOrderDetail[$row['id_order_detail']]) ? $tourismTaxByOrderDetail[$row['id_order_detail']] : 0;
}
}
return $return;
@@ -1821,10 +1831,11 @@ class OrderCore extends ObjectModel
// if one of the order details use the tax computation method the display will be different
return Db::getInstance()->getValue('
SELECT od.`tax_computation_method`
FROM `'._DB_PREFIX_.'order_detail_tax` odt
FROM `'._DB_PREFIX_.'order_tax_detail` odt
LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = '.(int)$this->id.'
AND od.`tax_computation_method` = '.(int)TaxCalculator::ONE_AFTER_ANOTHER_METHOD
AND od.`tax_computation_method` = '.(int)TaxCalculator::ONE_AFTER_ANOTHER_METHOD.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = odt.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
}
@@ -2152,61 +2163,6 @@ class OrderCore extends ObjectModel
return $this->update();
}
/**
* Returns the correct product taxes breakdown.
*
* @since 1.5.0.1
* @return array
*/
public function getProductTaxesBreakdown()
{
$tmp_tax_infos = array();
if ($this->useOneAfterAnotherTaxComputationMethod()) {
// sum by taxes
$taxes_by_tax = Db::getInstance()->executeS('
SELECT odt.`id_order_detail`, t.`name`, t.`rate`, SUM(`total_amount`) AS `total_amount`
FROM `'._DB_PREFIX_.'order_detail_tax` odt
LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = odt.`id_tax`)
LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = '.(int)$this->id.'
GROUP BY odt.`id_tax`
');
// format response
$tmp_tax_infos = array();
foreach ($taxes_by_tax as $tax_infos) {
$tmp_tax_infos[$tax_infos['rate']]['total_amount'] = $tax_infos['tax_amount'];
$tmp_tax_infos[$tax_infos['rate']]['name'] = $tax_infos['name'];
}
} else {
// sum by order details in order to retrieve real taxes rate
$taxes_infos = Db::getInstance()->executeS('
SELECT odt.`id_order_detail`, t.`rate` AS `name`, SUM(od.`total_price_tax_excl`) AS total_price_tax_excl, SUM(t.`rate`) AS rate, SUM(`total_amount`) AS `total_amount`
FROM `'._DB_PREFIX_.'order_detail_tax` odt
LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = odt.`id_tax`)
LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = '.(int)$this->id.'
GROUP BY odt.`id_order_detail`
');
// sum by taxes
$tmp_tax_infos = array();
foreach ($taxes_infos as $tax_infos) {
if (!isset($tmp_tax_infos[$tax_infos['rate']])) {
$tmp_tax_infos[$tax_infos['rate']] = array('total_amount' => 0,
'name' => 0,
'total_price_tax_excl' => 0);
}
$tmp_tax_infos[$tax_infos['rate']]['total_amount'] += $tax_infos['total_amount'];
$tmp_tax_infos[$tax_infos['rate']]['name'] = $tax_infos['name'];
$tmp_tax_infos[$tax_infos['rate']]['total_price_tax_excl'] += $tax_infos['total_price_tax_excl'];
}
}
return $tmp_tax_infos;
}
/**
* Returns the shipping taxes breakdown
*
@@ -2538,7 +2494,7 @@ class OrderCore extends ObjectModel
} else {
$order_details = $this->getOrderDetailList();
}
$expected_total_tax = (float)$this->getTotalProductsWithTaxes($limitToOrderDetails) - (float)$this->getTotalProductsWithoutTaxes($limitToOrderDetails);
$expected_total_tax = (float)$this->getTotalProductsWithTaxes($limitToOrderDetails, null, null, null, null, [], false) - (float)$this->getTotalProductsWithoutTaxes($limitToOrderDetails);
$order_ecotax_tax = 0;
@@ -3157,15 +3113,11 @@ class OrderCore extends ObjectModel
$totalRoomsAndServices = $this->getTotalProductsWithoutTaxes();
}
// Get total of extra demands
$objBookingDemand = new HotelBookingDemands();
$totalExtraDemands = $objBookingDemand->getRoomTypeBookingExtraDemands($this->id, 0, 0, 0, 0, 0, 1, $useTax);
// Get cart rules total
$orderTotalDiscount = $this->getCartRulesTotal($useTax);
// Update order with new amounts after removing cart rule
$totalOrder = ($totalExtraDemands + $totalRoomsAndServices) - $orderTotalDiscount;
$totalOrder = $totalRoomsAndServices - $orderTotalDiscount;
$totalOrder = $totalOrder > 0 ? $totalOrder : 0;
return $totalOrder;

View File

@@ -218,7 +218,7 @@ class OrderDetailCore extends ObjectModel
'tax_computation_method' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'ecotax' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'ecotax_tax_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'ecotax_tax_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'discount_quantity_applied' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'download_hash' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'download_nb' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
@@ -292,7 +292,11 @@ class OrderDetailCore extends ObjectModel
return false;
}
Db::getInstance()->delete('order_detail_tax', 'id_order_detail='.(int)$this->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$this->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
return $res;
}
@@ -345,15 +349,23 @@ class OrderDetailCore extends ObjectModel
public static function getTaxCalculatorStatic($id_order_detail)
{
$sql = 'SELECT t.*, d.`tax_computation_method`
FROM `'._DB_PREFIX_.'order_detail_tax` t
FROM `'._DB_PREFIX_.'order_tax_detail` t
LEFT JOIN `'._DB_PREFIX_.'order_detail` d ON (d.`id_order_detail` = t.`id_order_detail`)
WHERE d.`id_order_detail` = '.(int)$id_order_detail;
WHERE d.`id_order_detail` = '.(int)$id_order_detail.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = t.`id_tax` AND tc.`is_tourism_tax` = 1)';
$computation_method = 1;
$taxes = array();
$seenTaxIds = array();
if ($results = Db::getInstance()->executeS($sql)) {
foreach ($results as $result) {
$taxes[] = new Tax((int)$result['id_tax']);
$idTax = (int) $result['id_tax'];
if (isset($seenTaxIds[$idTax])) {
continue;
}
$seenTaxIds[$idTax] = true;
$taxes[] = new Tax($idTax);
}
$computation_method = $result['tax_computation_method'];
@@ -449,26 +461,30 @@ class OrderDetailCore extends ObjectModel
0,
$taxGroupInfo['id_room_type'],
)) {
$serviceProductData = array_shift($serviceProductData);
$numDays = 1;
if ((Product::PRICE_CALCULATION_METHOD_PER_DAY == $this->product_price_calculation_method)
&& (!$numDays = HotelHelper::getNumberOfDays($serviceProductData['date_from'], $serviceProductData['date_to']))
) {
$numDays = 1;
$quantity = 0;
$totalPriceTaxExcl = 0.0;
$firstServiceProduct = null;
foreach ($serviceProductData as $bookingServiceData) {
$bookingNumDays = 1;
if (Product::PRICE_CALCULATION_METHOD_PER_DAY == $this->product_price_calculation_method) {
$bookingNumDays = HotelHelper::getNumberOfDays($bookingServiceData['date_from'], $bookingServiceData['date_to']) ?: 1;
}
foreach ($bookingServiceData['additional_services'] as $item) {
$itemQuantity = (isset($item['quantity']) ? $item['quantity'] : 0) * $bookingNumDays;
$quantity += $itemQuantity;
$totalPriceTaxExcl += $itemQuantity * (isset($item['unit_price_tax_excl']) ? $item['unit_price_tax_excl'] : 0);
if ($firstServiceProduct === null) {
$firstServiceProduct = $item;
}
}
}
$quantity = array_reduce($serviceProductData['additional_services'], function ($totalQty, $item) {
return $totalQty + (isset($item['quantity']) ? $item['quantity'] : 0);
}, 0);
$unit_price_tax_excl = $quantity > 0 ? ($totalPriceTaxExcl / $quantity) : 0;
$firstServiceProduct = array_shift($serviceProductData['additional_services']);
$unit_price_tax_excl = isset($firstServiceProduct['unit_price_tax_excl']) ? $firstServiceProduct['unit_price_tax_excl'] : 0;
$quantity = $quantity * $numDays;
$tax_manager = TaxManagerFactory::getManager($this->vat_address, (int)$firstServiceProduct['id_tax_rules_group']);
$this->tax_calculator = $tax_manager->getTaxCalculator();
if ($firstServiceProduct) {
$tax_manager = TaxManagerFactory::getManager($this->vat_address, (int)$firstServiceProduct['id_tax_rules_group']);
$this->tax_calculator = $tax_manager->getTaxCalculator();
}
} elseif ($serviceProductData = $objServiceProductCartDetail->getServiceProductsInCart(
$idCart,
array(),
@@ -477,22 +493,21 @@ class OrderDetailCore extends ObjectModel
$taxGroupInfo['id_room_type'],
$this->product_id
)) {
$quantity = array_reduce($serviceProductData, function ($totalQty, $item) {
return $totalQty + (isset($item['quantity']) ? $item['quantity'] : 0);
}, 0);
$serviceProductData = array_shift($serviceProductData);
$unit_price_tax_excl = isset($serviceProductData['unit_price_tax_excl']) ? $serviceProductData['unit_price_tax_excl'] : 0;
$numDays = 1;
if ((Product::PRICE_CALCULATION_METHOD_PER_DAY == $this->product_price_calculation_method)
&& (!$numDays = HotelHelper::getNumberOfDays($serviceProductData['date_from'], $serviceProductData['date_to']))
) {
$numDays = 1;
// Same sum-across-every-row fix as above, cart-side: don't let array_shift() collapse
// the representative unit price/day-count down to just the first cart row.
$quantity = 0;
$totalPriceTaxExcl = 0.0;
foreach ($serviceProductData as $cartServiceItem) {
$itemNumDays = 1;
if (Product::PRICE_CALCULATION_METHOD_PER_DAY == $this->product_price_calculation_method) {
$itemNumDays = HotelHelper::getNumberOfDays($cartServiceItem['date_from'], $cartServiceItem['date_to']) ?: 1;
}
$itemQuantity = (isset($cartServiceItem['quantity']) ? $cartServiceItem['quantity'] : 0) * $itemNumDays;
$quantity += $itemQuantity;
$totalPriceTaxExcl += $itemQuantity * (isset($cartServiceItem['unit_price_tax_excl']) ? $cartServiceItem['unit_price_tax_excl'] : 0);
}
$quantity = $quantity * $numDays;
$unit_price_tax_excl = $quantity > 0 ? ($totalPriceTaxExcl / $quantity) : 0;
}
if ($this->tax_calculator == null) {
@@ -512,7 +527,7 @@ class OrderDetailCore extends ObjectModel
$total_amount = Tools::processPriceRounding($amount, $quantity, $order->round_type, $order->round_mode);
$values .= '('.(int)$this->id.','.(int)$id_tax.','.(float)$amount.','.(float)$total_amount.'),';
$values .= '('.(int)$order->id.','.(int)$this->id.',0,0,'.(int)$id_tax.','.(float)$amount.','.(float)$total_amount.',NOW()),';
}
}
}
@@ -546,7 +561,7 @@ class OrderDetailCore extends ObjectModel
$total_amount = Tools::processPriceRounding($amount, $this->product_quantity, $order->round_type, $order->round_mode);
$values .= '('.(int)$this->id.','.(int)$id_tax.','.(float)$amount.','.(float)$total_amount.'),';
$values .= '('.(int)$order->id.','.(int)$this->id.',0,0,'.(int)$id_tax.','.(float)$amount.','.(float)$total_amount.',NOW()),';
}
}
@@ -554,10 +569,15 @@ class OrderDetailCore extends ObjectModel
if ($values) {
if ($replace) {
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$this->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$this->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
}
$sql = 'INSERT INTO `'._DB_PREFIX_.'order_detail_tax` (id_order_detail, id_tax, unit_amount, total_amount)
$sql = 'INSERT INTO `'._DB_PREFIX_.'order_tax_detail`
(id_order, id_order_detail, id_htl_booking, id_service_product_order_detail, id_tax, unit_amount, total_amount, date_add)
VALUES '.$values;
return Db::getInstance()->execute($sql);
@@ -573,7 +593,10 @@ class OrderDetailCore extends ObjectModel
$tax_manager = TaxManagerFactory::getManager($address, (int)Product::getIdTaxRulesGroupByIdProduct((int)$this->product_id, $this->context));
$this->tax_calculator = $tax_manager->getTaxCalculator();
return $this->saveTaxCalculator($order, true);
$result = $this->saveTaxCalculator($order, true);
OrderTaxDetail::rescopeVatAfterReset((int) $this->id);
return $result;
}
/**
@@ -593,9 +616,25 @@ class OrderDetailCore extends ObjectModel
public static function getTaxListStatic($id_order_detail)
{
$sql = 'SELECT * FROM `'._DB_PREFIX_.'order_detail_tax`
WHERE `id_order_detail` = '.(int)$id_order_detail;
return Db::getInstance()->executeS($sql);
$sql = 'SELECT * FROM `'._DB_PREFIX_.'order_tax_detail` t
WHERE t.`id_order_detail` = '.(int)$id_order_detail.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = t.`id_tax` AND tc.`is_tourism_tax` = 1)';
$rows = Db::getInstance()->executeS($sql);
if (!$rows) {
return $rows;
}
$seenTaxIds = array();
$deduped = array();
foreach ($rows as $row) {
if (isset($seenTaxIds[$row['id_tax']])) {
continue;
}
$seenTaxIds[$row['id_tax']] = true;
$deduped[] = $row;
}
return $deduped;
}
/*
@@ -729,6 +768,11 @@ class OrderDetailCore extends ObjectModel
$this->total_price_tax_incl = (float)$product['total_wt'];
$this->total_price_tax_excl = (float)$product['total'];
if (isset($this->tax_calculator) && Product::getIdTourismTaxRulesGroupByIdProduct((int) $product['id_product'])) {
$this->unit_price_tax_incl = $this->tax_calculator->addTaxes($this->unit_price_tax_excl);
$this->total_price_tax_incl = $this->tax_calculator->addTaxes($this->total_price_tax_excl);
}
$this->purchase_supplier_price = (float)$product['wholesale_price'];
if ($product['id_supplier'] > 0 && ($supplier_price = ProductSupplier::getProductPrice((int)$product['id_supplier'], $product['id_product'], $product['id_product_attribute'], true)) > 0) {
$this->purchase_supplier_price = (float)$supplier_price;
@@ -896,10 +940,11 @@ class OrderDetailCore extends ObjectModel
public function getWsTaxes()
{
$query = new DbQuery();
$query->select('id_tax as id');
$query->from('order_detail_tax', 'tax');
$query->select('tax.`id_tax` as id');
$query->from('order_tax_detail', 'tax');
$query->leftJoin('order_detail', 'od', 'tax.`id_order_detail` = od.`id_order_detail`');
$query->where('od.`id_order_detail` = '.(int)$this->id_order_detail);
$query->where('NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = tax.`id_tax` AND tc.`is_tourism_tax` = 1)');
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
}

View File

@@ -147,6 +147,28 @@ class OrderInvoiceCore extends ObjectModel
'.($this->id && $this->number ? ' AND od.`id_order_invoice` = '.(int)$this->id : '').' ORDER BY od.`product_name`');
}
/**
* Recompute this invoice's totals live from its own order_detail lines, instead of trusting
* accumulated deltas. Mirrors Order::getOrderTotal()'s formula, scoped to this invoice only.
*
* @return bool
*/
public function recomputeTotalsFromLines()
{
$order = new Order((int) $this->id_order);
$invoiceProducts = $this->getProductsDetail();
$totalProductsTe = $order->getTotalProductsWithoutTaxes($invoiceProducts);
$totalProductsTi = $order->getTotalProductsWithTaxes($invoiceProducts);
$this->total_products = $totalProductsTe;
$this->total_products_wt = $totalProductsTi;
$this->total_paid_tax_excl = max(0, $totalProductsTe + $this->total_shipping_tax_excl + $this->total_wrapping_tax_excl - $this->total_discount_tax_excl);
$this->total_paid_tax_incl = max(0, $totalProductsTi + $this->total_shipping_tax_incl + $this->total_wrapping_tax_incl - $this->total_discount_tax_incl);
return $this->update();
}
public static function getInvoiceByNumber($id_invoice)
{
if (is_numeric($id_invoice)) {
@@ -323,11 +345,12 @@ class OrderInvoiceCore extends ObjectModel
// if one of the order details use the tax computation method the display will be different
return Db::getInstance()->getValue('
SELECT od.`tax_computation_method`
FROM `' . _DB_PREFIX_ . 'order_detail_tax` odt
FROM `' . _DB_PREFIX_ . 'order_tax_detail` odt
LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = ' . (int) $this->id_order . '
AND od.`id_order_invoice` = ' . (int) $this->id . '
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD . '
AND NOT EXISTS (SELECT 1 FROM `' . _DB_PREFIX_ . 'tax` tc WHERE tc.`id_tax` = odt.`id_tax` AND tc.`is_tourism_tax` = 1)')
|| Configuration::get('PS_INVOICE_TAXES_BREAKDOWN');
}
@@ -662,71 +685,6 @@ class OrderInvoiceCore extends ObjectModel
return $breakdown;
}
public function getExtraDemandTaxesBreakdown($order = null)
{
if (!$order) {
$order = $this->getOrder();
}
$breakdown = array();
$order_details = $this->getProducts();
$objBookingDemand = new HotelBookingDemands();
$order_details = array_column($order_details, 'id_order_detail');
$details = $objBookingDemand->getExtraDemandsTaxesDetails($order->id, $order_details);
if (!$this->useOneAfterAnotherTaxComputationMethod()) {
$grouped_details = array();
foreach ($details as $row) {
if (!isset($grouped_details[$row['id_htl_booking']][$row['id_booking_demand']])) {
$grouped_details[$row['id_htl_booking']][$row['id_booking_demand']] = array(
'tax_rate' => 0,
'total_tax_base' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
);
$grouped_details[$row['id_htl_booking']][$row['id_booking_demand']]['total_tax_base'] += $row['total_price_tax_excl'];
}
$grouped_details[$row['id_htl_booking']][$row['id_booking_demand']]['total_amount'] += $row['total_amount'];
$grouped_details[$row['id_htl_booking']][$row['id_booking_demand']]['tax_rate'] += $row['rate'];
}
$details = $grouped_details;
foreach ($details as $detail) {
foreach ($detail as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' =>$rate,
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
}
}
} else {
foreach ($details as $row) {
$key = $row['id_tax'];
$rate = sprintf('%.3f', $row['rate']);
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
);
}
$breakdown[$key]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$key]['total_amount'] += $row['total_amount'];
}
}
foreach ($breakdown as $rate => $data) {
$breakdown[$rate]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$rate]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
return $breakdown;
}
/**
* Returns the shipping taxes breakdown
*
@@ -860,6 +818,28 @@ class OrderInvoiceCore extends ObjectModel
return $wrapping_breakdown;
}
/**
* Return tourism tax breakdown grouped by id_tax for invoice display. Collapsed into a single
* combined row when the invoice's tax breakdown display is off — same rule every other tax
* category (rooms, services, ...) already applies via useOneAfterAnotherTaxComputationMethod().
*
* @return array [['tax_name' => string, 'total_amount' => float], ...]
*/
public function getTourismTaxBreakdown()
{
$breakdown = OrderTaxDetail::getBreakdownForInvoice((int) $this->id_order);
if (!$breakdown || $this->useOneAfterAnotherTaxComputationMethod()) {
return $breakdown;
}
$total = 0.0;
foreach ($breakdown as $row) {
$total += (float) $row['total_amount'];
}
return array(array('id_tax' => 0, 'tax_name' => '', 'total_amount' => $total));
}
/**
* Returns the ecotax taxes breakdown
*

View File

@@ -203,7 +203,6 @@ class OrderReturnCore extends ObjectModel
}
$objOrder = new Order($idOrder);
$objBookingDemands = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$calcServicePriceFirst = false;
@@ -211,6 +210,9 @@ class OrderReturnCore extends ObjectModel
$calcServicePriceFirst = true;
}
$appliedTourismTaxByBooking = OrderTaxDetail::getAppliedTourismTaxTotals($idOrder, OrderTaxDetail::SCOPE_ROOM);
$appliedServiceTourismTaxByBooking = OrderTaxDetail::getAppliedTourismTaxTotals($idOrder, OrderTaxDetail::SCOPE_SERVICE);
foreach ($returnDetails as $key => &$bookingRow) {
if ($skipReqCompletedNonRefunded) {
$objReturnState = new OrderReturnState($bookingRow['id_return_state']);
@@ -224,32 +226,9 @@ class OrderReturnCore extends ObjectModel
$bookingRow['extra_service_total_paid_amount'] = 0;
$bookingRow['extra_service_total_price_tax_incl'] = 0;
$bookingRow['room_paid_amount'] = 0;
$bookingRow['tourism_tax_applied_amount'] = 0;
$bookingRow['tourism_tax_paid_amount'] = 0;
$roomSelectedDemands = $objBookingDemands->getRoomTypeBookingExtraDemands(
$idOrder,
$bookingRow['id_product'],
$bookingRow['id_room'],
$bookingRow['date_from'],
$bookingRow['date_to'],
0,
0,
1,
$bookingRow['id']
);
if (count($roomSelectedDemands)) {
foreach ($roomSelectedDemands as $demand) {
if ($demand['total_price_tax_incl'] > 0) {
if ($objOrder->total_paid_real > 0) {
if ($calcServicePriceFirst) {
$bookingRow['extra_service_total_paid_amount'] += $demand['total_price_tax_incl'];
} else {
$bookingRow['extra_service_total_paid_amount'] += ($objOrder->total_paid_real*$demand['total_price_tax_incl'])/($objOrder->total_paid_tax_incl + $objOrder->total_discounts_tax_incl);
}
}
$bookingRow['extra_service_total_price_tax_incl'] += $demand['total_price_tax_incl'];
}
}
}
if ($roomSelectedServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
0,
@@ -291,6 +270,12 @@ class OrderReturnCore extends ObjectModel
}
}
}
$bookingRow['tourism_tax_applied_amount'] = (isset($appliedTourismTaxByBooking[$bookingRow['id_htl_booking']]) ? (float) $appliedTourismTaxByBooking[$bookingRow['id_htl_booking']] : 0.0)
+ (isset($appliedServiceTourismTaxByBooking[$bookingRow['id_htl_booking']]) ? (float) $appliedServiceTourismTaxByBooking[$bookingRow['id_htl_booking']] : 0.0);
if ($bookingRow['tourism_tax_applied_amount'] > 0 && $objOrder->total_paid_real > 0) {
$denominator = $objOrder->total_paid_tax_incl + $objOrder->total_discounts_tax_incl;
$bookingRow['tourism_tax_paid_amount'] = $denominator > 0 ? ($objOrder->total_paid_real * $bookingRow['tourism_tax_applied_amount'] / $denominator) : 0.0;
}
if ($customerView) {
$dateJoin = $bookingRow['id_product'].'_'.strtotime($bookingRow['date_from']).strtotime($bookingRow['date_to']);
if (isset($returnsCustView[$dateJoin]['num_rooms'])) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class OrderTaxExemptionCore extends ObjectModel
{
public $id_order_tax_exemption;
public $id_htl_booking;
public $id_service_product_order_detail;
public $id_order;
public $id_employee;
public $note;
public $date_add;
public static $definition = array(
'table' => 'order_tax_exemption',
'primary' => 'id_order_tax_exemption',
'fields' => array(
'id_htl_booking' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_service_product_order_detail' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_employee' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'note' => array('type' => self::TYPE_STRING, 'validate' => 'isMessage', 'allow_null' => true),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
}

View File

@@ -159,17 +159,6 @@ class HTMLTemplateBookingVoucherCore extends HTMLTemplate
// Services for this booking
$bookingServices = array();
$objBookingDemand = new HotelBookingDemands();
$extraDemands = $objBookingDemand->getRoomTypeBookingExtraDemands(
(int)$this->order->id, 0, 0, 0, 0, 0, 0, 0,
(int)$booking['id'], (int)$booking['id_order_detail']
);
if (is_array($extraDemands)) {
foreach ($extraDemands as $demand) {
$bookingServices[] = array('name' => $demand['name'], 'quantity' => 1);
}
}
// Auto-added services bundled with room price (for cost calculation only)
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$autoAddedWithRoomPriceTaxExcl = (float)$objServiceProductOrderDetail->getRoomTypeServiceProducts(
@@ -181,7 +170,7 @@ class HTMLTemplateBookingVoucherCore extends HTMLTemplate
1, 0, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM
);
// Additional services chosen by guest
// Extra services chosen by guest
$additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, null, 0, (int)$booking['id']
);
@@ -274,13 +263,10 @@ class HTMLTemplateBookingVoucherCore extends HTMLTemplate
}
}
// --- Totals ---
$objBookingDemand = new HotelBookingDemands();
$totalDemandsPriceTE = (float)$objBookingDemand->getRoomTypeBookingExtraDemands(
(int)$this->order->id, 0, 0, 0, 0, 1, 1, 0
);
$totalDemandsPriceTI = (float)$objBookingDemand->getRoomTypeBookingExtraDemands(
(int)$this->order->id, 0, 0, 0, 0, 1, 1, 1
);
// Extra demands feature was removed from the system; kept as 0 so the
// additive totals below stay correct without the deleted HotelBookingDemands class.
$totalDemandsPriceTE = 0;
$totalDemandsPriceTI = 0;
$orderDetails = OrderDetail::getList((int)$this->order->id);
$idsOrderDetail = is_array($orderDetails)
@@ -321,7 +307,9 @@ class HTMLTemplateBookingVoucherCore extends HTMLTemplate
$footer['total_without_discount_te'] = $footer['room_price_tax_excl'] + $footer['total_convenience_fee_te'] + $footer['additional_service_price_tax_excl'] + $footer['service_products_price_tax_excl'];
$totalWithoutDiscountTaxIncl = $roomsCostTaxIncl + $serviceProductsCostTaxIncl + $additionalServicesCostTaxIncl + $convenienceFeeTaxIncl;
$footer['total_tax_without_discount'] = max(0, $totalWithoutDiscountTaxIncl - $footer['total_without_discount_te']);
$totalTourismTax = OrderTaxDetail::getOrderTourismTaxTotal((int) $this->order->id);
$footer['total_tax_without_discount'] = max(0, $totalWithoutDiscountTaxIncl - $footer['total_without_discount_te'] - $totalTourismTax);
$footer['total_tourism_tax'] = $totalTourismTax;
$grandTotal = max(0.0, $totalWithoutDiscountTaxIncl - $productDiscountsTaxIncl);
$footer['product_discounts_tax_incl'] = $productDiscountsTaxIncl;
$footer['total_paid_tax_incl'] = $grandTotal;

View File

@@ -312,7 +312,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$cart_htl_data = array();
$service_product_data = array();
$room_extra_demands = array();
$room_additinal_services = array();
$formattedHotelAddress = '';
if (Module::isInstalled('hotelreservationsystem')) {
@@ -335,8 +334,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
}
if (!empty($order_details)) {
$processed_product = array();
$totalDemandsPriceTE = 0;
$totalDemandsPriceTI = 0;
foreach ($order_details as $type_key => $type_value) {
$processProductKey = $type_value['product_id'].'_'.$type_value['selling_preference_type'].'_'.$type_value['id_order_detail'];
if (isset($processed_product[$processProductKey])) {
@@ -360,9 +357,32 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, 0, $type_value['product_id'], $idCustomer, $type_value['id_order_detail']);
$cart_htl_data[$type_key]['id_product'] = $type_value['product_id'];
$objBookingDemand = new HotelBookingDemands();
foreach ($order_bk_data as $data_k => $data_v) {
$date_join = strtotime($data_v['date_from']).strtotime($data_v['date_to']);
$display_date_from = $data_v['date_from'];
$display_date_to = $data_v['date_to'];
if ($data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_OUT) {
if ($data_v['check_in']) {
$display_date_from = $data_v['check_in'];
}
if ($data_v['check_out']) {
$display_date_to = $data_v['check_out'];
}
} elseif ($data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_IN) {
if ($data_v['check_in']) {
$display_date_from = $data_v['check_in'];
}
if ($data_v['check_out_time']) {
$display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
}
} else {
if ($data_v['check_in_time']) {
$display_date_from = date('Y-m-d', strtotime($data_v['date_from'])) . ' ' . date('H:i:s', strtotime($data_v['check_in_time']));
}
if ($data_v['check_out_time']) {
$display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
}
}
$date_join = strtotime($data_v['date_from']).strtotime($data_v['date_to']).strtotime($display_date_from).strtotime($display_date_to);
/*Product price when order was created*/
$order_details_obj = new OrderDetail($data_v['id_order_detail']);
@@ -386,30 +406,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
// For order refund
$cart_htl_data[$type_key]['date_diff'][$date_join]['id_room'] = $data_v['id_room'];
} else {
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order_obj->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0,
0,
$type_value['id_order_detail']
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order_obj->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1,
0,
$type_value['id_order_detail']
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services'] = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$order_obj->id,
0,
@@ -473,31 +469,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$num_days = HotelHelper::getNumberOfDays($data_v['date_from'], $data_v['date_to']);
$cart_htl_data[$type_key]['date_diff'][$date_join]['num_rm'] = 1;
$fullDate = (isset($context->controller->show_full_date) && $context->controller->show_full_date && (date('Y-m-d', strtotime($data_v['date_from'])) == date('Y-m-d', strtotime($data_v['date_to'])))) ? true : false;
$display_date_from = $data_v['date_from'];
$display_date_to = $data_v['date_to'];
if ((int)$data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_OUT) {
if ($data_v['check_in']) {
$display_date_from = $data_v['check_in'];
}
if ($data_v['check_out']) {
$display_date_to = $data_v['check_out'];
}
} elseif ((int)$data_v['id_status'] === HotelBookingDetail::STATUS_CHECKED_IN) {
if ($data_v['check_in']) {
$display_date_from = $data_v['check_in'];
}
if ($data_v['check_out_time']) {
$display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
}
} else {
if ($data_v['check_in_time']) {
$display_date_from = date('Y-m-d', strtotime($data_v['date_from'])) . ' ' . date('H:i:s', strtotime($data_v['check_in_time']));
}
if ($data_v['check_out_time']) {
$display_date_to = date('Y-m-d', strtotime($data_v['date_to'])) . ' ' . date('H:i:s', strtotime($data_v['check_out_time']));
}
}
$cart_htl_data[$type_key]['date_diff'][$date_join]['data_form'] = Tools::displayDate($display_date_from, null, true);
$cart_htl_data[$type_key]['date_diff'][$date_join]['data_to'] = Tools::displayDate($display_date_to, null, true);
$cart_htl_data[$type_key]['date_diff'][$date_join]['num_days'] = $num_days;
@@ -514,32 +485,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$cart_htl_data[$type_key]['date_diff'][$date_join]['id_room'] = $data_v['id_room'];
}
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order_obj->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0,
$data_v['id']
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order_obj->id,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1,
$data_v['id']
);
$totalDemandsPriceTE += $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'];
$totalDemandsPriceTI += $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['total_price_tax_excl'] += $data_v['total_price_tax_excl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['total_price_tax_incl'] += $data_v['total_price_tax_incl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_ti'] += $objServiceProductOrderDetail->getroomTypeServiceProducts(
@@ -569,25 +514,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
Product::PRICE_ADDITION_TYPE_WITH_ROOM
);
if ($extraDemands = $objBookingDemand->getRoomTypeBookingExtraDemands(
$order_obj->id,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
1,
0,
1,
$data_v['id']
)) {
$extraDemands = array_shift($extraDemands);
$extraDemands['product_id'] = $type_value['product_id'];
$extraDemands['room_type_name'] = $type_value['product_name'];
$extraDemands['date_from'] = $data_v['date_from'];
$extraDemands['date_to'] = $data_v['date_to'];
$room_extra_demands[] = $extraDemands;
}
if ($additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
0,
0,
@@ -657,10 +583,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
}
}
unset($tax_temp);
// enter extra demands price to the footer total details
$footer['total_extra_demands_ti'] = $totalDemandsPriceTI;
$footer['total_extra_demands_te'] = $totalDemandsPriceTE;
}
}
@@ -677,8 +599,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$footer['room_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail);
$footer['service_products_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE, false, false, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE, false, false, $idsOrderDetail);
$footer['service_products_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_STANDALONE, false, false, $idsOrderDetail) + $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_HOTEL_STANDALONE, false, false, $idsOrderDetail);
$footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTE;
$footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI;
$footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail);
$footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 0, null, $idsOrderDetail);
$footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail);
$footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail);
}
@@ -687,7 +609,9 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$footer['total_without_discount_te'] = $footer['room_price_tax_excl'] + $footer['total_convenience_fee_te'] + $footer['additional_service_price_tax_excl'] + $footer['service_products_price_tax_excl'];
$footer['total_without_discount_ti'] = $footer['room_price_tax_incl'] + $footer['total_convenience_fee_ti'] + $footer['additional_service_price_tax_incl'] + $footer['service_products_price_tax_incl'];
$footer['total_tax_without_discount'] = $footer['total_without_discount_ti'] - $footer['total_without_discount_te'];
$footer['total_tourism_tax'] = OrderTaxDetail::getOrderTourismTaxTotal((int) $this->order->id);
$footer['total_tax_without_discount'] = $footer['total_without_discount_ti'] - $footer['total_without_discount_te'] - $footer['total_tourism_tax'];
if ($footer['total_tax_without_discount'] < 0) {
$footer['total_tax_without_discount'] = 0;
}
@@ -696,7 +620,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
'cart_htl_data' => $cart_htl_data,
'is_hotel_order' => HotelBookingDetail::getIdHotelByIdOrder($this->order->id),
'service_product_data' => $service_product_data,
'room_extra_demands' => $room_extra_demands,
'room_additinal_services' => $room_additinal_services,
'order' => $this->order,
'order_invoice' => $this->order_invoice,
@@ -728,7 +651,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
'summary_tab' => $this->smarty->fetch($this->getTemplate('invoice.summary-tab')),
'product_tab' => $this->smarty->fetch($this->getTemplate('invoice.product-tab')),
'service_product_tab' => $this->smarty->fetch($this->getTemplate('invoice.service-product-tab')),
'extra_demands_tab' => $this->smarty->fetch($this->getTemplate('invoice.extra-demands-tab')),
'additinal_services_tab' => $this->smarty->fetch($this->getTemplate('invoice.additinal-services-tab')),
'tax_tab' => $this->getTaxTabContent(),
'payment_tab' => $this->smarty->fetch($this->getTemplate('invoice.payment-tab')),
'note_tab' => $this->smarty->fetch($this->getTemplate('invoice.note-tab')),
@@ -807,11 +730,11 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
'room_tax' => $this->order_invoice->getRoomsTaxesBreakdown($this->order),
'additional_services_tax' => $this->order_invoice->getAdditionalServicesTaxesBreakdown($this->order),
'convenience_fee_tax' => $this->order_invoice->getConvenienceFeeTaxesBreakdown($this->order),
'extra_demands_tax' => $this->order_invoice->getExtraDemandTaxesBreakdown($this->order),
'service_products_tax' => $this->order_invoice->getServiceProductsTaxesBreakdown($this->order),
'shipping_tax' => $this->order_invoice->getShippingTaxesBreakdown($this->order),
'ecotax_tax' => $this->order_invoice->getEcoTaxTaxesBreakdown(),
'wrapping_tax' => $this->order_invoice->getWrappingTaxesBreakdown(),
'tourism_tax' => $this->order_invoice->getTourismTaxBreakdown(),
);
foreach ($breakdowns as $type => $bd) {
@@ -842,12 +765,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
}
}
if (isset($breakdowns['extra_demands_tax'])) {
foreach ($breakdowns['extra_demands_tax'] as &$bd) {
$bd['total_tax_excl'] = $bd['total_price_tax_excl'];
}
}
if (isset($breakdowns['service_products_tax'])) {
foreach ($breakdowns['service_products_tax'] as &$bd) {
$bd['total_tax_excl'] = $bd['total_price_tax_excl'];

View File

@@ -267,10 +267,11 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice
// if one of the order details use the tax computation method the display will be different
return Db::getInstance()->getValue('
SELECT od.`tax_computation_method`
FROM `' . _DB_PREFIX_ . 'order_detail_tax` odt
FROM `' . _DB_PREFIX_ . 'order_tax_detail` odt
LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = ' . (int) $this->order->id . '
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD . '
AND NOT EXISTS (SELECT 1 FROM `' . _DB_PREFIX_ . 'tax` tc WHERE tc.`id_tax` = odt.`id_tax` AND tc.`is_tourism_tax` = 1)')
|| Configuration::get('PS_INVOICE_TAXES_BREAKDOWN');
}

View File

@@ -20,9 +20,10 @@ class AverageTaxOfProductsTaxCalculator
$sql = 'SELECT t.id_tax, t.rate, od.total_price_tax_excl FROM '.$prefix.'orders o
INNER JOIN '.$prefix.'order_detail od ON od.id_order = o.id_order
INNER JOIN '.$prefix.'order_detail_tax odt ON odt.id_order_detail = od.id_order_detail
INNER JOIN '.$prefix.'order_tax_detail odt ON odt.id_order_detail = od.id_order_detail
INNER JOIN '.$prefix.'tax t ON t.id_tax = odt.id_tax
WHERE o.id_order = '.(int)$this->id_order;
WHERE o.id_order = '.(int)$this->id_order.'
AND NOT EXISTS (SELECT 1 FROM '.$prefix.'tax tc WHERE tc.id_tax = odt.id_tax AND tc.is_tourism_tax = 1)';
return $this->db->select($sql);
}

View File

@@ -39,6 +39,9 @@ class TaxCore extends ObjectModel
/** @var bool true if the tax has been historized */
public $deleted = 0;
/** @var int 1 = this ps_tax row is a tourism tax (subtype params in tourism_tax) */
public $is_tourism_tax = 0;
/**
* @see ObjectModel::$definition
*/
@@ -47,11 +50,12 @@ class TaxCore extends ObjectModel
'primary' => 'id_tax',
'multilang' => true,
'fields' => array(
'rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'active' => array('type' => self::TYPE_BOOL),
'deleted' => array('type' => self::TYPE_BOOL),
'rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'active' => array('type' => self::TYPE_BOOL),
'deleted' => array('type' => self::TYPE_BOOL),
'is_tourism_tax' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
/* Lang fields */
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
),
);
@@ -133,7 +137,7 @@ class TaxCore extends ObjectModel
{
return Db::getInstance()->getValue('
SELECT `id_tax`
FROM `'._DB_PREFIX_.'order_detail_tax`
FROM `'._DB_PREFIX_.'order_tax_detail`
WHERE `id_tax` = '.(int)$this->id
);
}

View File

@@ -132,14 +132,155 @@ class TaxCalculatorCore
/**
* Return the tax amount associated to each taxes of the TaxCalculator
*
* @param float $price_te
* @param float $price_te
* @param string|null $checkInDate
* @param int $numNights
* @param int $numAdults
* @param int[] $childrenAges
* @param int|null $collectionType
* @param int $quantity
* @param int|null $idCurrency
* @return array $taxes_amount
*/
public function getTaxesAmount($price_te)
{
public function getTaxesAmount(
$price_te,
$checkInDate = null,
$numNights = 1,
$numAdults = 1,
$childrenAges = array(),
$collectionType = null,
$quantity = 1,
$idCurrency = null,
&$validNightsByTax = null
) {
$taxes_amounts = array();
$tourismTaxIds = array();
foreach ($this->taxes as $tax) {
if (TaxConfiguration::getByTaxId((int) $tax->id)) {
$tourismTaxIds[] = $tax->id;
}
}
if ($checkInDate !== null && $collectionType !== null && Configuration::get('QLO_USE_TOURISM_TAX') && $collectionType !== HotelBranchInformation::TAX_COLLECTION_TYPE_AT_HOTEL) {
if (!$idCurrency) {
$context = Context::getContext();
$idCurrency = Validate::isLoadedObject($context->currency) ? (int) $context->currency->id : (int) Configuration::get('PS_CURRENCY_DEFAULT');
}
$checkIn = new DateTime($checkInDate);
$isoDayIndex = $checkIn->format('N') - 1;
$infantMaxAge = Configuration::get('QLO_GLOBAL_MAX_INFANT_AGE');
$childMaxAge = Configuration::get('WK_GLOBAL_CHILD_MAX_AGE');
$eligibleChildAges = array_filter($childrenAges, function ($age) use ($infantMaxAge, $childMaxAge) {
return $age >= $infantMaxAge && $age < $childMaxAge;
});
$runningPriceExcl = (float) $price_te;
foreach ($this->taxes as $tax) {
$tourismTax = TaxConfiguration::getByTaxId((int) $tax->id);
if (!$tourismTax) {
continue;
}
$hasMultiRanges = (bool) $tourismTax->has_multiple_valid_ranges;
$validityRanges = $hasMultiRanges ? TaxValidityRange::getByTaxId((int) $tax->id) : null;
$specialDays = null;
if ($tourismTax->special_days) {
$decoded = json_decode($tourismTax->special_days, true);
$specialDays = is_array($decoded) ? $decoded : array();
}
$isPerNight = (bool) $tourismTax->per_night;
if ($isPerNight) {
$validNights = 0;
for ($i = 0; $i < $numNights; $i++) {
$night = clone $checkIn;
$night->modify('+' . $i . ' days');
if ($hasMultiRanges && !TaxValidityRange::dateMatchesAnyRange($validityRanges, $night)) {
continue;
}
if ($specialDays !== null && !in_array(TaxConfiguration::DAY_KEYS[$night->format('N') - 1], $specialDays)) {
continue;
}
$validNights++;
}
if ($validNights === 0) {
continue;
}
} else {
if ($hasMultiRanges && !TaxValidityRange::dateMatchesAnyRange($validityRanges, $checkIn)) {
continue;
}
if ($specialDays !== null && !in_array(TaxConfiguration::DAY_KEYS[$isoDayIndex], $specialDays)) {
continue;
}
$validNights = $numNights;
}
if ($validNightsByTax !== null) {
$validNightsByTax[$tax->id] = $validNights;
}
$taxType = (int) $tourismTax->calculation_type;
$baseValue = (float) $tourismTax->tax_value;
if ($tourismTax->has_tiered_pricing) {
$tier = TaxPriceTier::getMatchingTier((int) $tax->id, $runningPriceExcl);
if ($tier) {
$baseValue = (float) $tier['tax_value'];
}
}
$adultMultiplier = 1;
if ($isPerNight) {
$adultMultiplier *= $validNights;
}
if ($tourismTax->per_person) {
$adultMultiplier *= $numAdults;
}
if ($taxType === TaxConfiguration::CALCULATION_TYPE_FIXED) {
$unitAmountAdult = $baseValue;
$totalAmountAdult = $baseValue * $adultMultiplier;
} else {
$unitAmountAdult = $runningPriceExcl * ($baseValue / 100);
$totalAmountAdult = $unitAmountAdult * $adultMultiplier;
}
$totalAmountChild = 0.0;
if ($tourismTax->apply_on_child && !empty($eligibleChildAges)) {
$contribution = TaxChildRange::getChildContribution(
$tax->id,
$eligibleChildAges,
(int) $tourismTax->child_calculation_type,
$unitAmountAdult,
$tourismTax->has_child_age_range
);
if ($contribution['count'] > 0) {
$nightMultiplier = $isPerNight ? $validNights : 1;
$totalAmountChild = $contribution['total'] * $nightMultiplier;
}
}
if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD) {
$runningPriceExcl += $unitAmountAdult;
}
$totalAmountAdult = Tools::convertPrice($totalAmountAdult, $idCurrency);
$totalAmountChild = Tools::convertPrice($totalAmountChild, $idCurrency);
$taxes_amounts[$tax->id] = Tools::ps_round(($totalAmountAdult + $totalAmountChild) * max(1, $quantity), 6);
}
}
foreach ($this->taxes as $tax) {
if (in_array($tax->id, $tourismTaxIds)) {
continue;
}
if (!isset($taxes_amounts[$tax->id])) {
$taxes_amounts[$tax->id] = 0;
}
@@ -155,20 +296,59 @@ class TaxCalculatorCore
}
/**
* Return the total taxes amount
*
* @param float $price_te
* @return float $amount
*/
public function getTaxesTotalAmount($price_te)
{
public function getTaxesTotalAmount(
$price_te,
$checkInDate = null,
$numNights = 1,
$numAdults = 1,
$childrenAges = array(),
$collectionType = null,
$quantity = 1,
$idCurrency = null
) {
$amount = 0;
$taxes = $this->getTaxesAmount($price_te);
$taxes = $this->getTaxesAmount($price_te, $checkInDate, $numNights, $numAdults, $childrenAges, $collectionType, $quantity, $idCurrency);
foreach ($taxes as $tax) {
$amount += $tax;
}
return $amount;
}
/**
*
* @param float $price_te
* @param string $checkInDate
* @param int $numNights
* @param int $numAdults
* @param int[] $childrenAges
* @param int $collectionType
* @param int $quantity
* @return float price with tourism tax
*/
public function addTourismTaxes($price_te, $checkInDate, $numNights, $numAdults, $childrenAges, $collectionType, $quantity = 1)
{
return $price_te + $this->getTaxesTotalAmount($price_te, $checkInDate, $numNights, $numAdults, $childrenAges, $collectionType, $quantity);
}
/**
*
* @param float $price_ti
* @param string $checkInDate 'YYYY-MM-DD'
* @param int $numNights
* @param int $numAdults
* @param int[] $childrenAges Ages at check-in date
* @param int $collectionType HotelBranchInformation::TAX_COLLECTION_TYPE_*
* @param int $quantity Line quantity multiplier
* @return float price without tourism tax
*/
public function removeTourismTaxes($price_ti, $checkInDate, $numNights, $numAdults, $childrenAges, $collectionType, $quantity = 1)
{
return $price_ti - $this->getTaxesTotalAmount($price_ti, $checkInDate, $numNights, $numAdults, $childrenAges, $collectionType, $quantity);
}
}

View File

@@ -0,0 +1,134 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class TaxChildRangeCore extends ObjectModel
{
public $id_tax_child_range;
public $id_tax;
public $min_age;
public $max_age;
public $tax_value;
public static $definition = array(
'table' => 'tax_child_range',
'primary' => 'id_tax_child_range',
'fields' => array(
'id_tax' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'min_age' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'max_age' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'tax_value' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
),
);
/**
* All child age ranges for a tax in entry order (id_tax_child_range order), cached per request.
*
* @param int $idTax
* @return array
*/
public static function getByTaxId($idTax)
{
$idTax = (int) $idTax;
$cacheId = 'TaxChildRange::getByTaxId-' . $idTax;
if (Cache::isStored($cacheId)) {
return Cache::retrieve($cacheId);
}
$ranges = Db::getInstance()->executeS(
'SELECT * FROM `' . _DB_PREFIX_ . 'tax_child_range`
WHERE `id_tax` = ' . $idTax . '
ORDER BY `id_tax_child_range` ASC'
);
Cache::store($cacheId, $ranges);
return $ranges;
}
/**
* Replace all child range rows for $idTax with the submitted arrays, skipping entries where tax_value is empty.
*
* @param int $idTax
* @param array $mins
* @param array $maxs
* @param array $values
* @return void
*/
public static function saveAll($idTax, $mins, $maxs, $values)
{
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_child_range`
WHERE `id_tax` = ' . (int) $idTax
);
foreach ($values as $rowIndex => $value) {
if ($value === '' || $value === false) {
continue;
}
$range = new TaxChildRange();
$range->id_tax = (int) $idTax;
$range->min_age = isset($mins[$rowIndex]) ? (int) $mins[$rowIndex] : 0;
$range->max_age = isset($maxs[$rowIndex]) ? (int) $maxs[$rowIndex] : 0;
$range->tax_value = (float) $value;
$range->add();
}
}
/**
* Sum per-band tax contributions for the given child ages — each child matched to the first qualifying
* band (band value interpreted per $childCalcType); unmatched children pay the adult's own already-computed
* per-unit tourism tax amount flatly, since they're not governed by any band.
*
* @param int $idTax
* @param int[] $ages Ages at check-in date
* @param int $childCalcType 0=fixed, 1=percentage — governs matched-band contributions only
* @param float $unitTourismTaxAmountAdult Adult's already-computed per-unit tourism tax amount (tier-aware);
* @param bool $useRanges false = skip band lookup, every child is treated as unmatched
* @return array ['total' => float, 'count' => int]
*/
public static function getChildContribution($idTax, $ages, $childCalcType, $unitTourismTaxAmountAdult, $useRanges = true)
{
$ranges = $useRanges ? self::getByTaxId((int) $idTax) : array();
$total = 0.0;
$count = 0;
foreach ($ages as $age) {
$age = (int) $age;
$matched = false;
foreach ($ranges as $range) {
$maxAge = (int) $range['max_age'];
$inLower = ($age >= (int) $range['min_age']);
$inUpper = ($maxAge == 0 || $age <= $maxAge);
if ($inLower && $inUpper) {
$bandValue = (float) $range['tax_value'];
$total += ($childCalcType === TaxConfiguration::CALCULATION_TYPE_FIXED) ? $bandValue : ($unitTourismTaxAmountAdult * ($bandValue / 100));
$count++;
$matched = true;
break;
}
}
if (!$matched) {
$total += $unitTourismTaxAmountAdult;
$count++;
}
}
return array('total' => $total, 'count' => $count);
}
}

View File

@@ -0,0 +1,365 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class TaxConfigurationCore extends ObjectModel
{
const DAY_KEYS = array('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun');
const CALCULATION_TYPE_FIXED = 0;
const CALCULATION_TYPE_PERCENTAGE = 1;
public $id_tax;
public $tax_value;
public $calculation_type;
public $per_night = 1;
public $per_person;
public $has_tiered_pricing;
public $apply_on_child;
public $has_child_age_range;
public $child_calculation_type;
public $has_multiple_valid_ranges;
public $special_days;
public static $definition = array(
'table' => 'tax_configuration',
'primary' => 'id_tax',
'fields' => array(
'tax_value' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
'calculation_type' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'per_night' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'per_person' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'has_tiered_pricing' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'apply_on_child' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'has_child_age_range' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'child_calculation_type' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'has_multiple_valid_ranges' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'special_days' => array('type' => self::TYPE_STRING),
),
);
/**
* 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.
*
* @param bool $auto_date ignored — table has no date_add/date_upd
* @param bool $null_values ignored
* @return bool
*/
public function add($auto_date = true, $null_values = false)
{
$idTax = (int) $this->id;
if (!$idTax) {
return false;
}
$result = Db::getInstance()->insert(
'tax_configuration',
array(
'id_tax' => $idTax,
'tax_value' => (float) $this->tax_value,
'calculation_type' => (int) $this->calculation_type,
'per_night' => (int) $this->per_night,
'per_person' => (int) $this->per_person,
'has_tiered_pricing' => (int) $this->has_tiered_pricing,
'apply_on_child' => (int) $this->apply_on_child,
'has_child_age_range' => (int) $this->has_child_age_range,
'child_calculation_type' => (int) $this->child_calculation_type,
'has_multiple_valid_ranges' => (int) $this->has_multiple_valid_ranges,
'special_days' => $this->special_days ? pSQL($this->special_days) : null,
)
);
if ($result) {
$this->id_tax = $idTax;
}
return $result;
}
/**
* Load a tourism tax subtype row by id_tax, cached per request.
*
* @param int $idTax
* @return TaxConfiguration|false
*/
public static function getByTaxId($idTax)
{
$idTax = (int) $idTax;
$cacheId = 'TaxConfiguration::getByTaxId-' . $idTax;
if (Cache::isStored($cacheId)) {
return Cache::retrieve($cacheId);
}
$obj = new TaxConfiguration($idTax);
$result = Validate::isLoadedObject($obj) ? $obj : false;
Cache::store($cacheId, $result);
return $result;
}
/**
* Shared core for cleanFromTourismTaxRulesGroups()/cleanFromVatTaxRulesGroups().
*
* @param int $idTax
* @param bool $isTourismTaxRulesGroup true = clean from tourism tax rules groups, false = clean from VAT tax rules groups
* @return int
*/
protected static function cleanTaxRulesGroupsByTourismFlag($idTax, $isTourismTaxRulesGroup)
{
$flag = $isTourismTaxRulesGroup ? 1 : 0;
$db = Db::getInstance();
$db->execute(
'DELETE tr FROM `' . _DB_PREFIX_ . 'tax_rule` tr
INNER JOIN `' . _DB_PREFIX_ . 'tax_rules_group` trg
ON trg.`id_tax_rules_group` = tr.`id_tax_rules_group`
WHERE tr.`id_tax` = ' . (int) $idTax . '
AND trg.`is_tourism_tax_rule_group` = ' . $flag
);
return $db->Affected_Rows();
}
/**
* Remove this tax from all tourism tax rules groups.
*
* @param int $idTax
* @return int
*/
public static function cleanFromTourismTaxRulesGroups($idTax)
{
return self::cleanTaxRulesGroupsByTourismFlag($idTax, true);
}
/**
* Remove this tax from all standard (non-tourism) tax rules groups — symmetric counterpart of cleanFromTourismTaxRulesGroups().
*
* @param int $idTax
* @return int
*/
public static function cleanFromVatTaxRulesGroups($idTax)
{
return self::cleanTaxRulesGroupsByTourismFlag($idTax, false);
}
/**
* Format a tax rate/amount for display, VAT as a percentage and tourism tax per its own calc type.
*
* @param mixed $value ps_tax.rate (used for non-tourism rows)
* @param array $row List row — must include is_tourism_tax, tourism_tax_calc_type, tourism_tax_value
* @param Currency $currency
* @return string
*/
public static function getFormattedRateForDisplay($value, $row, $currency)
{
if (!(int) $row['is_tourism_tax']) {
return Tools::safeOutput($value) . '%';
}
$displayValue = Tools::safeOutput((float) $row['tourism_tax_value']);
if ((int) $row['tourism_tax_calc_type'] === self::CALCULATION_TYPE_PERCENTAGE) {
return $displayValue . '%';
}
$currencySign = Tools::safeOutput(trim($currency->prefix . $currency->suffix));
return $currencySign . ' ' . $displayValue;
}
/**
* Delete the subtype row and all related tiers/child-ranges.
*
* @return bool
*/
public function delete()
{
if (parent::delete()) {
$idTax = (int) $this->id;
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_price_tier`
WHERE `id_tax` = ' . $idTax
);
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_child_range`
WHERE `id_tax` = ' . $idTax
);
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_validity_range`
WHERE `id_tax` = ' . $idTax
);
return true;
}
return false;
}
/**
* Whether tourism tax should be visually folded into the displayed room/service price.
*
* @param float $tourismTax
* @return bool
*/
public static function isGrossedUp($tourismTax)
{
return (float) $tourismTax > 0 && (bool) Configuration::get('QLO_TOURISM_TAX_GROSSED_UP');
}
/**
* Resolve the hotel's own jurisdiction address and current tourism-tax collection type — shared by every cart, order, and preview caller that needs this context.
*
* @param int $idHotel 0 = no hotel context (fully standalone product)
* @param Address $fallbackAddress Used only when the hotel has no address on file
* @return array ['address' => Address, 'collectionType' => int]
*/
public static function resolveHotelAddressAndCollectionType($idHotel, $fallbackAddress)
{
$idHotel = (int) $idHotel;
$address = null;
if ($idHotel) {
$hotelAddress = HotelBranchInformation::getAddress($idHotel);
if ($hotelAddress && !empty($hotelAddress['id_address'])) {
$address = new Address((int) $hotelAddress['id_address']);
}
}
if (!$address || !Validate::isLoadedObject($address)) {
$address = $fallbackAddress;
}
$collectionType = HotelBranchInformation::TAX_COLLECTION_TYPE_ONLINE;
if ($idHotel && Validate::isLoadedObject($hotelBranch = new HotelBranchInformation($idHotel))) {
$collectionType = (int) $hotelBranch->tourism_tax_collection_type;
}
return array(
'address' => $address,
'collectionType' => $collectionType,
);
}
/**
* Resolve the jurisdiction address, collection type, and occupancy (check-in/nights/adults/children) a service product line needs before computing its tourism tax.
*
* @param int $idHotel 0 = no hotel context (fully standalone product)
* @param int $idHtlBookingDetail 0 = not attached to an order-side room booking
* @param Address $fallbackAddress Used only when the hotel has no address on file
* @param int $idHtlCartBooking 0 = not attached to a cart-side room booking (pre-order preview only —
* ignored when $idHtlBookingDetail is given)
* @return array ['address' => Address, 'collectionType' => int, 'checkInDate' => string,
* 'numNights' => int, 'numAdults' => int, 'childrenAges' => int[]]
*/
public static function resolveServiceLineTaxContext($idHotel, $idHtlBookingDetail, $fallbackAddress, $idHtlCartBooking = 0)
{
$idHotel = (int) $idHotel;
$idHtlBookingDetail = (int) $idHtlBookingDetail;
$idHtlCartBooking = (int) $idHtlCartBooking;
$hotelContext = self::resolveHotelAddressAndCollectionType($idHotel, $fallbackAddress);
$address = $hotelContext['address'];
$collectionType = $hotelContext['collectionType'];
$roomBooking = $idHtlBookingDetail ? new HotelBookingDetail($idHtlBookingDetail) : null;
$cartBooking = (!$roomBooking && $idHtlCartBooking) ? new HotelCartBookingData($idHtlCartBooking) : null;
if ($roomBooking && Validate::isLoadedObject($roomBooking)) {
$checkInDate = $roomBooking->date_from;
$numNights = max(1, (int) HotelHelper::getNumberOfDays($roomBooking->date_from, $roomBooking->date_to));
$numAdults = (int) $roomBooking->adults;
$childrenAges = array();
if ($roomBooking->child_ages) {
$decoded = json_decode($roomBooking->child_ages, true);
if (is_array($decoded)) {
$childrenAges = array_map('intval', $decoded);
}
}
} elseif ($cartBooking && Validate::isLoadedObject($cartBooking)) {
$checkInDate = $cartBooking->date_from;
$numNights = max(1, (int) HotelHelper::getNumberOfDays($cartBooking->date_from, $cartBooking->date_to));
$numAdults = (int) $cartBooking->adults;
$childrenAges = !empty($cartBooking->child_ages) ? (array) json_decode($cartBooking->child_ages, true) : array();
} else {
$checkInDate = date('Y-m-d');
$numNights = 1;
$numAdults = 1;
$childrenAges = array();
}
return array(
'address' => $address,
'collectionType' => $collectionType,
'checkInDate' => $checkInDate,
'numNights' => $numNights,
'numAdults' => $numAdults,
'childrenAges' => $childrenAges,
);
}
/**
* Preview parameters for a tax rules group — a deliberate 1-adult/1-night approximation for js/admin/price.js's live price preview.
*
* @param int $idTaxRulesGroup
* @param Address $address
* @param int $idLang
* @return array List of ['tax_calc_type','is_tiered','tax_value','tiers']
*/
public static function getPreviewParams($idTaxRulesGroup, $address, $idLang, $collectionType = HotelBranchInformation::TAX_COLLECTION_TYPE_ONLINE)
{
$idTaxRulesGroup = (int) $idTaxRulesGroup;
if (!$idTaxRulesGroup || Tax::excludeTaxeOption() || (int) $collectionType === HotelBranchInformation::TAX_COLLECTION_TYPE_AT_HOTEL) {
return array();
}
$taxCalculator = TaxManagerFactory::getManager($address, $idTaxRulesGroup)->getTaxCalculator();
$preview = array();
$today = new DateTime(date('Y-m-d'));
$todayDayKey = self::DAY_KEYS[$today->format('N') - 1];
foreach ($taxCalculator->taxes as $tax) {
$tourismTax = self::getByTaxId((int) $tax->id);
if (!$tourismTax) {
continue;
}
if ((bool) $tourismTax->has_multiple_valid_ranges
&& !TaxValidityRange::dateMatchesAnyRange(TaxValidityRange::getByTaxId((int) $tax->id), $today)
) {
continue;
}
if ($tourismTax->special_days) {
$specialDays = json_decode($tourismTax->special_days, true);
if (!is_array($specialDays) || !in_array($todayDayKey, $specialDays)) {
continue;
}
}
$tiers = array();
if ((bool) $tourismTax->has_tiered_pricing) {
foreach (TaxPriceTier::getByTaxId((int) $tax->id) as $tier) {
$tiers[] = array(
'min_amount' => (float) $tier['min_amount'],
'max_amount' => (float) $tier['max_amount'],
'tax_value' => (float) $tier['tax_value'],
);
}
}
$preview[] = array(
'tax_calc_type' => (int) $tourismTax->calculation_type,
'is_tiered' => (bool) $tourismTax->has_tiered_pricing,
'tax_value' => (float) $tourismTax->tax_value,
'tiers' => $tiers,
);
}
return $preview;
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class TaxPriceTierCore extends ObjectModel
{
public $id_tax_price_tier;
public $id_tax;
public $min_amount;
public $max_amount;
public $tax_value;
public static $definition = array(
'table' => 'tax_price_tier',
'primary' => 'id_tax_price_tier',
'fields' => array(
'id_tax' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'min_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
'max_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
'tax_value' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat'),
),
);
/**
* All tiers for a tax in entry order (id_tax_price_tier order), cached per request.
*
* @param int $idTax
* @return array
*/
public static function getByTaxId($idTax)
{
$idTax = (int) $idTax;
$cacheId = 'TaxPriceTier::getByTaxId-' . $idTax;
if (Cache::isStored($cacheId)) {
return Cache::retrieve($cacheId);
}
$tiers = Db::getInstance()->executeS(
'SELECT * FROM `' . _DB_PREFIX_ . 'tax_price_tier`
WHERE `id_tax` = ' . $idTax . '
ORDER BY `id_tax_price_tier` ASC'
);
Cache::store($cacheId, $tiers);
return $tiers;
}
/**
* Find the matching tier for a given unit price, or false when no tier matches.
*
* @param int $idTax
* @param float $unitPrice
* @return array|false
*/
public static function getMatchingTier($idTax, $unitPrice)
{
$tiers = self::getByTaxId($idTax);
foreach ($tiers as $tier) {
$maxAmount = (float) $tier['max_amount'];
$inLower = ($unitPrice >= (float) $tier['min_amount']);
$inUpper = ($maxAmount == 0 || $unitPrice <= $maxAmount);
if ($inLower && $inUpper) {
return $tier;
}
}
return false;
}
/**
* Replace all tier rows for $idTax with the submitted arrays, skipping entries where tax_value is empty.
*
* @param int $idTax
* @param array $mins
* @param array $maxs
* @param array $values
* @return void
*/
public static function saveAll($idTax, $mins, $maxs, $values)
{
$idTax = (int) $idTax;
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_price_tier`
WHERE `id_tax` = ' . $idTax
);
foreach ($values as $rowIndex => $value) {
if ($value === '' || $value === false) {
continue;
}
$tier = new TaxPriceTier();
$tier->id_tax = $idTax;
$tier->min_amount = isset($mins[$rowIndex]) ? (float) $mins[$rowIndex] : 0;
$tier->max_amount = isset($maxs[$rowIndex]) ? (float) $maxs[$rowIndex] : 0;
$tier->tax_value = (float) $value;
$tier->add();
}
}
}

View File

@@ -40,6 +40,9 @@ class TaxRulesGroupCore extends ObjectModel
/** @var string Object last modification date */
public $date_upd;
/** @var int 1 = all rules in this TRG reference tourism taxes only */
public $is_tourism_tax_rule_group = 0;
/**
* @see ObjectModel::$definition
*/
@@ -47,11 +50,12 @@ class TaxRulesGroupCore extends ObjectModel
'table' => 'tax_rules_group',
'primary' => 'id_tax_rules_group',
'fields' => array(
'name' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'name' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'is_tourism_tax_rule_group' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
@@ -139,23 +143,31 @@ class TaxRulesGroupCore extends ObjectModel
return false;
}
public static function getTaxRulesGroups($only_active = true)
/**
* @param bool $only_active
* @param bool $isTourismTax true = return only tourism TRGs; false (default) = return standard TRGs
* @return array
*/
public static function getTaxRulesGroups($only_active = true, $isTourismTax = false)
{
return Db::getInstance()->executeS('
SELECT DISTINCT g.id_tax_rules_group, g.name, g.active
FROM `'._DB_PREFIX_.'tax_rules_group` g'
.Shop::addSqlAssociation('tax_rules_group', 'g').' WHERE deleted = 0'
.Shop::addSqlAssociation('tax_rules_group', 'g').' WHERE deleted = 0
AND g.`is_tourism_tax_rule_group` = '.($isTourismTax ? 1 : 0)
.($only_active ? ' AND g.`active` = 1' : '').'
ORDER BY name ASC');
}
/**
* @return array an array of tax rules group formatted as $id => $name
*/
public static function getTaxRulesGroupsForOptions()
* @param bool $onlyActive
* @param bool $isTourismTax true = tourism TRG list with "None" placeholder; false (default) = standard TRG list with "No tax" placeholder
* @return array
*/
public static function getTaxRulesGroupsForOptions($onlyActive = true, $isTourismTax = false)
{
$tax_rules[] = array('id_tax_rules_group' => 0, 'name' => Tools::displayError('No tax'));
return array_merge($tax_rules, TaxRulesGroup::getTaxRulesGroups());
$tax_rules[] = array('id_tax_rules_group' => 0, 'name' => Tools::displayError('No Tax'));
return array_merge($tax_rules, TaxRulesGroup::getTaxRulesGroups($onlyActive, $isTourismTax));
}
public function delete()
@@ -222,6 +234,61 @@ class TaxRulesGroupCore extends ObjectModel
);
}
/**
* @return bool true if any of this group's tax rules reference a tourism tax
*/
public function hasTourismTaxRules()
{
return (bool) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT tr.`id_tax_rule` FROM `'._DB_PREFIX_.'tax_rule` tr
INNER JOIN `'._DB_PREFIX_.'tax` t ON t.`id_tax` = tr.`id_tax`
WHERE tr.`id_tax_rules_group` = '.(int) $this->id.'
AND t.`is_tourism_tax` = 1'
);
}
/**
* @return bool true if any product currently uses this group as its tourism tax rule
*/
public function hasProductsUsingAsTourismGroup()
{
return (bool) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `id_product` FROM `'._DB_PREFIX_.'product_shop`
WHERE `id_tourism_tax_rules_group` = '.(int) $this->id
);
}
/**
* @return bool true if any of this group's tax rules reference a non-tourism (VAT) tax
*/
public function hasVatTaxRules()
{
return (bool) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT tr.`id_tax_rule` FROM `'._DB_PREFIX_.'tax_rule` tr
INNER JOIN `'._DB_PREFIX_.'tax` t ON t.`id_tax` = tr.`id_tax`
WHERE tr.`id_tax_rules_group` = '.(int) $this->id.'
AND tr.`id_tax` != 0
AND t.`is_tourism_tax` = 0'
);
}
/**
* @return bool true if any product or service price currently uses this group as its regular (VAT) tax rule
*/
public function hasProductsUsingAsVatGroup()
{
$hasRegularProductConflict = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `id_product` FROM `'._DB_PREFIX_.'product_shop`
WHERE `id_tax_rules_group` = '.(int) $this->id
);
$hasServicePriceConflict = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `id_room_type_service_product_price` FROM `'._DB_PREFIX_.'htl_room_type_service_product_price`
WHERE `id_tax_rules_group` = '.(int) $this->id
);
return (bool) ($hasRegularProductConflict || $hasServicePriceConflict);
}
/**
* @deprecated since 1.5
*/

View File

@@ -0,0 +1,113 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class TaxValidityRangeCore extends ObjectModel
{
public $id_tax_validity_range;
public $id_tax;
public $valid_from;
public $valid_to;
public static $definition = array(
'table' => 'tax_validity_range',
'primary' => 'id_tax_validity_range',
'fields' => array(
'id_tax' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'valid_from' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'allow_null' => true),
'valid_to' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'allow_null' => true),
),
);
/**
* All validity ranges for a tax in entry order (id_tax_validity_range order), cached per request.
*
* @param int $idTax
* @return array
*/
public static function getByTaxId($idTax)
{
$idTax = (int) $idTax;
$cacheId = 'TaxValidityRange::getByTaxId-' . $idTax;
if (Cache::isStored($cacheId)) {
return Cache::retrieve($cacheId);
}
$ranges = Db::getInstance()->executeS(
'SELECT * FROM `' . _DB_PREFIX_ . 'tax_validity_range`
WHERE `id_tax` = ' . $idTax . '
ORDER BY `id_tax_validity_range` ASC'
);
Cache::store($cacheId, $ranges);
return $ranges;
}
/**
* Whether $date falls within any of the given ranges (OR across rows) — a blank bound on either
* @param array $ranges Rows as returned by getByTaxId()
* @param DateTime $date
* @return bool
*/
public static function dateMatchesAnyRange($ranges, $date)
{
if (empty($ranges)) {
return true;
}
foreach ($ranges as $range) {
$from = (!empty($range['valid_from']) && $range['valid_from'] !== '0000-00-00') ? new DateTime($range['valid_from']) : null;
$to = (!empty($range['valid_to']) && $range['valid_to'] !== '0000-00-00') ? new DateTime($range['valid_to']) : null;
if ((!$from || $date >= $from) && (!$to || $date <= $to)) {
return true;
}
}
return false;
}
/**
* Replace all validity-range rows for $idTax with the submitted arrays, skipping rows where
* @param int $idTax
* @param array $froms
* @param array $tos
* @return void
*/
public static function saveAll($idTax, $froms, $tos)
{
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'tax_validity_range`
WHERE `id_tax` = ' . $idTax
);
foreach ($froms as $rowIndex => $from) {
$to = isset($tos[$rowIndex]) ? $tos[$rowIndex] : '';
$fromEmpty = ($from === '' || $from === false);
$toEmpty = ($to === '' || $to === false);
if ($fromEmpty && $toEmpty) {
continue;
}
$range = new TaxValidityRange();
$range->id_tax = $idTax;
$range->valid_from = $fromEmpty ? null : $from;
$range->valid_to = $toEmpty ? null : $to;
$range->add();
}
}
}

View File

@@ -31,5 +31,6 @@ class WebserviceOrderCore extends PaymentModule
$this->displayName = $this->l('Order from API');
$this->validateOrderAmount = false;
$this->payment_type = OrderPayment::PAYMENT_TYPE_ONLINE;
$this->idBookingSource = Source::getIdByCode('API_ORDER');
}
}

View File

@@ -144,16 +144,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'total_tax' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice')
)
),
'facilities' => array(
'resource' => 'facility',
'fields' => array(
'id_facility' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'id_option' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'name' => array('type' => self::TYPE_STRING, 'validate' => 'isString'),
'unit_price_without_tax' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
)
)
)
)
@@ -273,7 +263,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$parentKeys = array(
'room_types' => 'room_type',
'rooms' => 'room',
'facilities' => 'facility',
'services' => 'service',
'cart_rules' => 'cart_rule',
'remarks' => 'remark',
@@ -504,10 +493,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
if (count($rooms)) {
$formattedRooms = array();
foreach ($rooms as $roomKey => $room) {
$selectedDemands = $this->formatDemandsInRequestData($room);
$selectedServices = $this->formatServicesInRequestData($room);
$occupancy = $this->formatOccupancyInRequestData($room, $data['id_room_type']);
$rooms[$roomKey]['facilities'] = $selectedDemands;
$rooms[$roomKey]['services'] = $selectedServices;
$rooms[$roomKey]['occupancy'] = $occupancy;
$key = $roomKey;
@@ -516,7 +503,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
$formattedRooms[$key] = $room;
$formattedRooms[$key]['facilities'] = $selectedDemands;
$formattedRooms[$key]['services'] = $selectedServices;
$formattedRooms[$key]['occupancy'] = $occupancy;
if (isset($room['id_tax_rules_group'])) {
@@ -609,36 +595,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
return $formattedServices;
}
public function formatDemandsInRequestData($data)
{
$selectedDemands = array();
if (isset($data['facilities']['facility'][0])) {
$selectedDemands = $data['facilities']['facility'];
} else if (isset($data['facilities'])
&& !isset($data['facilities'][0])
&& isset($data['facilities']['facility'])
) {
$selectedDemands[] = $data['facilities']['facility'];
} else if (isset($data['facilities']) && isset($data['facilities'][0])) {
$selectedDemands = $data['facilities'];
}
$formattedDemands = array();
foreach ($selectedDemands as $key => $demand) {
$formattedDemands[$key]['id_global_demand'] = isset($demand['id_facility']) ? $demand['id_facility'] : 0;
$formattedDemands[$key]['id_option'] = isset($demand['id_option']) ? $demand['id_option'] : 0;
if (isset($demand['unit_price_without_tax'])) {
$formattedDemands[$key]['unit_price_without_tax'] = $demand['unit_price_without_tax'];
}
if (isset($demand['id_tax_rules_group'])) {
$formattedDemands[$key]['id_tax_rules_group'] = $demand['id_tax_rules_group'];
}
}
return $formattedDemands;
}
/**
* Validating the POST request.
*/
@@ -823,11 +779,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
return false;
}
if (isset($room['facilities']) && $room['facilities']
&& !$this->validateRequestedDemands($room['facilities'], $roomType['id_room_type'])
) {
return false;
}
}
}
} else {
@@ -973,7 +924,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
null,
false
)) {
$this->updateServicesAndDemandsInOrder($objPaymentModule->currentOrder);
$this->updateServicesInOrder($objPaymentModule->currentOrder);
if (!empty($this->wsRequestedRooms)) {
$this->updateRoomTaxRulesGroupsInOrder($objPaymentModule->currentOrder);
}
@@ -1015,7 +966,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$this->addCartRulesToOrder(array($cartRule), $objOrder->id);
} else if ($params['price_details']['total_price_with_tax'] > $objOrder->total_paid_tax_incl) {
$objHotelBookingDetail = new HotelBookingDetail();
$objHotelBookingDemands = new HotelBookingDemands();
if ($roomsInOrder = $objHotelBookingDetail->getOrderCurrentDataByOrderId($idOrder)) {
$requestedPrice = $params['price_details']['total_price_with_tax'];
$roomsToUpdate = array();
@@ -1030,12 +980,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
$serviceProductPrice = $objOrder->getTotalProductsWithTaxes(false, false, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE);
if ($demands = $objHotelBookingDemands->getExtraDemandsTaxesDetails($objOrder->id)) {
$demandsPrice = array_sum(array_column($demands, 'total_price_tax_excl'));
// Adding the tax
$demandsPrice += array_sum(array_column($demands, 'total_amount'));
$serviceProductPrice += $demandsPrice;
}
$requestedPrice -= $serviceProductPrice;
// This empty means that all the rooms are sent with price in the request, so we will add a service to a room to manage the order total sent in the request.
@@ -1105,7 +1049,11 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$this->wsRequestedRooms[$dateRoomJoinKey]['id_tax_rules_group'] = $this->createTaxRule(($this->wsRequestedRooms[$dateRoomJoinKey]['total_tax']/$objHotelBookingDetail->total_price_tax_excl)*100, $objAddress);
} else if (isset($this->wsRequestedRooms[$dateRoomJoinKey]['total_tax'])) {
$objOrderDetail->id_tax_rules_group = 0;
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$objOrderDetail->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$objOrderDetail->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
$priceWithTax = $objHotelBookingDetail->total_price_tax_excl + $this->wsRequestedRooms[$dateRoomJoinKey]['total_tax'];
}
@@ -1134,7 +1082,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrderDetail->save();
if (isset($this->wsRequestedRooms[$dateRoomJoinKey]['id_tax_rules_group'])) {
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRooms[$dateRoomJoinKey]['id_tax_rules_group']);
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRooms[$dateRoomJoinKey]['id_tax_rules_group'], (int) $objHotelBookingDetail->id, 0);
}
$objOrder->total_paid += $taxDiff;
$objOrder->total_paid_tax_incl += $taxDiff;
@@ -1146,17 +1094,22 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
}
public function saveTaxCalculator($idOrderDetail, $idTaxRulesGroup)
public function saveTaxCalculator($idOrderDetail, $idTaxRulesGroup, $idHtlBooking = 0, $idServiceProductOrderDetail = 0)
{
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$idOrderDetail);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$idOrderDetail.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
$idTax = $this->wsTaxRulesGroup[$idTaxRulesGroup]['tax'];
$objOrderDetail = new OrderDetail($idOrderDetail);
$values = '('.(int)$objOrderDetail->id.','.(int)$idTax.','.
$values = '('.(int)$objOrderDetail->id_order.','.(int)$objOrderDetail->id.','.(int)$idHtlBooking.','.(int)$idServiceProductOrderDetail.','.(int)$idTax.','.
(float)($objOrderDetail->unit_price_tax_incl - $objOrderDetail->unit_price_tax_excl).','.
(float)($objOrderDetail->total_price_tax_incl - $objOrderDetail->total_price_tax_excl).'),';
(float)($objOrderDetail->total_price_tax_incl - $objOrderDetail->total_price_tax_excl).',NOW()),';
$values = rtrim($values, ',');
$sql = 'INSERT INTO `'._DB_PREFIX_.'order_detail_tax` (id_order_detail, id_tax, unit_amount, total_amount)
$sql = 'INSERT INTO `'._DB_PREFIX_.'order_tax_detail`
(id_order, id_order_detail, id_htl_booking, id_service_product_order_detail, id_tax, unit_amount, total_amount, date_add)
VALUES '.$values;
return Db::getInstance()->execute($sql);
@@ -1165,7 +1118,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
/**
* Updating the services and their prices.
*/
public function updateServicesAndDemandsInOrder($idOrder)
public function updateServicesInOrder($idOrder)
{
$objOrder = new Order($idOrder);
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
@@ -1267,7 +1220,11 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'] = $this->createTaxRule(($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax']/$objServiceProductOrderDetail->total_price_tax_excl)*100, $objAddress);
} else if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax'])) {
$objOrderDetail->id_tax_rules_group = 0;
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$objOrderDetail->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$objOrderDetail->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
$unitPriceTaxIncl = $objServiceProductOrderDetail->total_price_tax_excl + $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax'];
$priceDiffTaxIncl = $unitPriceTaxIncl - $objServiceProductOrderDetail->total_price_tax_incl;
@@ -1296,27 +1253,17 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objServiceProductOrderDetail->save();
$objOrderDetail->save();
if (!$isAutoAdded && isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'])) {
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group']);
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'], 0, (int) $objServiceProductOrderDetail->id);
}
}
}
}
// To save the changes made till now, since we are again loading this order while adding demands if any.
// To save the changes made till now, since we are again loading this order while adding if any.
$objOrder->save();
}
$objHotelBookingDetail = new HotelBookingDetail();
if ($orderedRooms = $objHotelBookingDetail->getOrderCurrentDataByOrderId($objOrder->id)) {
foreach ($orderedRooms as $orderedRoom) {
$dateRoomJoinKey = strtotime($orderedRoom['date_from']).''.strtotime($orderedRoom['date_to']).$orderedRoom['id_room'];
if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands']) && $this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands']) {
if ($demands = json_decode($this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands'], true)) {
$this->addDemandsInOrderedRoom($demands, $orderedRoom['id']);
}
}
}
}
}
}
@@ -1626,47 +1573,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
return true;
}
/**
* Validating the demands related information.
*/
public function validateRequestedDemands($requestedDemands, $idRoomType)
{
$objHotelRoomTypeDemand = new HotelRoomTypeDemand();
$objHotelDemandOptions = new HotelRoomTypeGlobalDemandAdvanceOption();
// Incase the there is no demand for this room but demands are still sent in the request for this room type.
if ($roomTypeDemands = $objHotelRoomTypeDemand->getRoomTypeDemands($idRoomType)) {
foreach ($requestedDemands as $demandKey => $requestedDemand) {
if (!isset($requestedDemand['id_global_demand'])
|| !isset($roomTypeDemands[$requestedDemand['id_global_demand']])
) {
$this->error_msg = Tools::displayError('Invalid request for facilities.');
return false;
} else if (isset($roomTypeDemands[$requestedDemand['id_global_demand']]['adv_option'])
&& (!isset($requestedDemand['id_option']))
) {
$this->error_msg = sprintf(Tools::displayError('Id option is required for the facility with ID %s.'), $requestedDemand['id_global_demand']);
return false;
} else if (isset($roomTypeDemands[$requestedDemand['id_global_demand']]['adv_option'])
&& !isset($roomTypeDemands[$requestedDemand['id_global_demand']]['adv_option'][$requestedDemand['id_option']])
) {
$this->error_msg = sprintf(Tools::displayError('Invalid id option for the facility with ID %s.'), $requestedDemand['id_global_demand']);
return false;
} else if (isset($requestedDemand['id_tax_rules_group']) && !Validate::isLoadedObject(new TaxRulesGroup((int) $requestedDemand['id_tax_rules_group']))) {
$this->error_msg = Tools::displayError('Invalid id_tax_rules_group for facilities.');
return false;
} else if (isset($requestedDemand['total_tax']) && !Validate::isPrice($requestedDemand['total_tax'])) {
$this->error_msg = Tools::displayError('Invalid tax for facilities.');
return false;
}
}
} else {
$this->error_msg = Tools::displayError('Invalid request for facilities.');
return false;
}
return true;
}
/**
* Adding rooms in the cart.
*/
@@ -1719,7 +1625,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
// since we cannot update them after ordering them and will have to replace them if orderd here. So, we will not add them for now.
$roomDemands = json_encode(array());
if (isset($room['occupancy']) && count($room['occupancy'])) {
$occupancy = $room['occupancy'];
@@ -1742,7 +1647,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$idRoom,
$dateFrom,
$dateTo,
$roomDemands,
$roomServices,
$this->context->cart->id,
$this->context->cart->id_guest
@@ -1750,14 +1654,8 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objCartBookingData = new HotelCartBookingData((int) $idHtlCartBookingData);
$dateRoomJoinKey = strtotime($dateFrom).strtotime($dateTo).$objCartBookingData->id_room;
// To update the price after valiate order is called.
if (isset($room['facilities'])
&& $room['facilities']
) {
$roomDemands = json_encode($room['facilities']);
}
$this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'] = $roomServices;
$this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands'] = $roomDemands;
$this->wsRequestedRoomTypes[$dateRoomJoinKey]['room'] = $room;
if (isset($room['id_tax_rules_group']) && Validate::isLoadedObject(new TaxRulesGroup((int) $room['id_tax_rules_group']))) {
$this->wsRequestedRooms[$dateRoomJoinKey]['id_tax_rules_group'] = $room['id_tax_rules_group'];
@@ -1795,7 +1693,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$roomWiseOccupancy = count($roomWiseOccupancy);
}
$roomDemands = json_encode(array());
$roomServices = array();
$objHotelCartBookingData->updateCartBooking(
$roomType['id_room_type'],
@@ -1805,7 +1702,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
0,
$dateFrom,
$dateTo,
$roomDemands,
$roomServices,
$this->context->cart->id,
$this->context->cart->id_guest
@@ -2031,7 +1927,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
// Update the information for the services that were updated in the existing rooms
if (count($roomsToUpdate)) {
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$objBookingDemand = new HotelBookingDemands();
foreach ($roomsToUpdate as $roomsByDate) {
if (isset($roomsByDate['requested'])
&& $roomsByDate['requested']
@@ -2080,18 +1975,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
$this->addServicesInOrderedRoom($room['services'], $idHotelBookingDetail);
// Since we don't store the id_global_demand in the order, we will remove the previous ones and add the new ones.
$requestedDemands = $room['facilities'];
$roomExtraDemand = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$idProduct,
$idRoom,
$dateFrom,
$dateTo,
0
);
$this->removeDemandsInOrderedRoom($roomExtraDemand);
$this->addDemandsInOrderedRoom($requestedDemands, $idHotelBookingDetail);
}
} else if (isset($roomsByDate['order'])
&& $roomsByDate['order']
@@ -2375,7 +2258,11 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'] = $this->createTaxRule(($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax']/$totalPriceTaxExcl)*100, $objAddress);
} else if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax'])) {
$objOrderDetail->id_tax_rules_group = 0;
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$objOrderDetail->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$objOrderDetail->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
$unitPriceTaxIncl = $objServiceProductOrderDetail->total_price_tax_excl + $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['total_tax'];
$priceDiffTaxIncl = $unitPriceTaxIncl - $objServiceProductOrderDetail->total_price_tax_incl;
}
@@ -2434,19 +2321,13 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
if (!$isAutoAdded && isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'])) {
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group']);
$this->saveTaxCalculator($objOrderDetail->id, $this->wsRequestedRoomTypes[$dateRoomJoinKey]['services'][$service['id_product']]['id_tax_rules_group'], 0, (int) $objServiceProductOrderDetail->id);
}
}
$objOrder->save();
}
if (isset($this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands']) && $this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands']) {
if ($demands = json_decode($this->wsRequestedRoomTypes[$dateRoomJoinKey]['demands'], true)) {
$this->addDemandsInOrderedRoom($demands, $objBookingDetail->id);
}
}
}
}
}
@@ -2580,7 +2461,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
public function removeRoomLineFromOrder($params, $roomsToRemove)
{
$objOrder = new Order((int) $params['id']);
$objBookingDemand = new HotelBookingDemands();
$objHotelBookingDetail = new HotelBookingDetail();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
foreach ($roomsToRemove as $roomType) {
@@ -2592,26 +2472,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$idHotel = $roomType['id_hotel'];
$bookingPriceTaxIncl = $roomType['total_price_tax_incl'];
$bookingPriceTaxExcl = $roomType['total_price_tax_excl'];
$roomExtraDemandTI = $objBookingDemand->getRoomTypeBookingExtraDemands(
$objOrder->id,
$roomType['id_product'],
$roomType['id_room'],
$dateFrom,
$dateTo,
0,
1,
1
);
$roomExtraDemandTE = $objBookingDemand->getRoomTypeBookingExtraDemands(
$objOrder->id,
$roomType['id_product'],
$roomType['id_room'],
$dateFrom,
$dateTo,
0,
1,
0
);
$additionlServicesTI = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
0,
0,
@@ -2691,9 +2551,9 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
// Update Order
// values changes as values are calculated accoding to the quantity of the product by webkul
$objOrder->total_paid = Tools::ps_round($objOrder->total_paid - ($diffProductsTaxIncl + $roomExtraDemandTI + $additionlServicesTI), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_incl = Tools::ps_round($objOrder->total_paid_tax_incl - ($diffProductsTaxIncl + $roomExtraDemandTI + $additionlServicesTI), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_excl = Tools::ps_round($objOrder->total_paid_tax_excl - ($diffProductsTaxExcl + $roomExtraDemandTE + $additionlServicesTE), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid = Tools::ps_round($objOrder->total_paid - ($diffProductsTaxIncl + $additionlServicesTI), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_incl = Tools::ps_round($objOrder->total_paid_tax_incl - ($diffProductsTaxIncl + $additionlServicesTI), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_paid_tax_excl = Tools::ps_round($objOrder->total_paid_tax_excl - ($diffProductsTaxExcl + $additionlServicesTE), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_products = Tools::ps_round($objOrder->total_products - ($diffProductsTaxExcl + $additionlServicesTE), _PS_PRICE_COMPUTE_PRECISION_);
$objOrder->total_products_wt = Tools::ps_round($objOrder->total_products_wt - ($diffProductsTaxIncl + $additionlServicesTI), _PS_PRICE_COMPUTE_PRECISION_);
@@ -2725,8 +2585,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
$objOrder->update();
// delete the demands of this booking
$objBookingDemand->deleteBookingDemands($idHotelBooking);
$objServiceProductOrderDetail->deleteSeviceProducts(0, $idHotelBooking);
$objHotelCartBookingData = new HotelCartBookingData();
$objHotelCartBookingData->deleteOrderedRoomFromCart(
@@ -2967,12 +2825,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
return false;
}
if (isset($room['facilities']) && $room['facilities']
&& !$this->validateRequestedDemands($room['facilities'], $roomType['id_room_type'])
) {
return false;
}
if (isset($room['id_tax_rules_group']) && !Validate::isLoadedObject(new TaxRulesGroup((int) $room['id_tax_rules_group']))) {
$this->error_msg = Tools::displayError('Invalid id_tax_rules_group.');
return false;
@@ -3340,7 +3192,11 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$unitPriceTaxIncl = Tools::ps_round($totalPriceTaxIncl / $quantity, _PS_PRICE_COMPUTE_PRECISION_);
} else if (isset($services[$product['id_product']]['total_tax'])) {
$objOrderDetail->id_tax_rules_group = 0;
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'order_detail_tax` WHERE id_order_detail='.(int)$objOrderDetail->id);
Db::getInstance()->execute(
'DELETE otd FROM `'._DB_PREFIX_.'order_tax_detail` otd
WHERE otd.`id_order_detail` = '.(int)$objOrderDetail->id.'
AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'tax` tc WHERE tc.`id_tax` = otd.`id_tax` AND tc.`is_tourism_tax` = 1)'
);
$unitPriceTaxIncl = $unitPriceTaxExcl + $services[$product['id_product']]['total_tax'];
$totalPriceTaxIncl = Tools::ps_round(($unitPriceTaxIncl * $quantity), _PS_PRICE_COMPUTE_PRECISION_);
}
@@ -3393,7 +3249,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$objOrderDetail->update();
if (!$isAutoAdded && isset($services[$product['id_product']]['id_tax_rules_group'])) {
$this->saveTaxCalculator($objOrderDetail->id, $services[$product['id_product']]['id_tax_rules_group']);
$this->saveTaxCalculator($objOrderDetail->id, $services[$product['id_product']]['id_tax_rules_group'], 0, (int) $objServiceProductOrderDetail->id);
}
}
}
@@ -3406,117 +3262,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
}
/**
* Adding the demands into the order.
*/
public function addDemandsInOrderedRoom($demands, $idHotelBooking)
{
if (Validate::isLoadedObject($objBookingDetail = new HotelBookingDetail((int) $idHotelBooking))) {
if ($demands) {
$objOrder = new Order($objBookingDetail->id_order);
// set context currency So that we can get prices in the order currency
$this->context->currency = new Currency($objOrder->id_currency);
$objAddress = new Address((int) $objOrder->id_address_tax);
$idLang = (int) $objOrder->id_lang;
$idProduct = $objBookingDetail->id_product;
$objHtlBkDtl = new HotelBookingDetail();
$objRoomDemandPrice = new HotelRoomTypeDemandPrice();
foreach ($demands as $demand) {
$idGlobalDemand = $demand['id_global_demand'];
$idOption = $demand['id_option'];
$objBookingDemand = new HotelBookingDemands();
$objBookingDemand->id_htl_booking = $idHotelBooking;
$objGlobalDemand = new HotelRoomTypeGlobalDemand($idGlobalDemand, $idLang);
if ($idOption) {
$objOption = new HotelRoomTypeGlobalDemandAdvanceOption($idOption, $idLang);
$objBookingDemand->name = $objOption->name;
} else {
$idOption = 0;
$objBookingDemand->name = $objGlobalDemand->name;
}
$unitPriceTaxExcl = HotelRoomTypeDemand::getPriceStatic($idProduct, $idGlobalDemand, $idOption, 0);
$unitPriceTaxIncl = HotelRoomTypeDemand::getPriceStatic($idProduct, $idGlobalDemand, $idOption, 1);
$taxMultiplier = 1;
if ($unitPriceTaxExcl > 0) {
$taxMultiplier = $unitPriceTaxIncl / $unitPriceTaxExcl;
}
$qty = 1;
if ($objGlobalDemand->price_calc_method == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY) {
$numDays = HotelHelper::getNumberOfDays(
$objBookingDetail->date_from,
$objBookingDetail->date_to
);
if ($numDays > 1) {
$qty *= $numDays;
}
}
$totalPriceTaxExcl = $unitPriceTaxExcl * $qty;
$totalPriceTaxIncl = $unitPriceTaxIncl * $qty;
if (isset($demand['unit_price_without_tax'])) {
$unitPriceTaxExcl = $demand['unit_price_without_tax'];
$unitPriceTaxIncl = $demand['unit_price_without_tax'] * $taxMultiplier;
$totalPriceTaxExcl = $unitPriceTaxExcl * $qty;
$totalPriceTaxIncl = $unitPriceTaxIncl * $qty;
}
if (isset($demand['id_tax_rules_group'])) {
$objTaxManager = TaxManagerFactory::getManager(
$objAddress,
$demand['id_tax_rules_group']
);
$objTaxManager = TaxManagerFactory::getManager($objAddress, $demand['id_tax_rules_group']);
$objTaxCalculator = $objTaxManager->getTaxCalculator();
$unitPriceTaxIncl = $objTaxCalculator->addTaxes($unitPriceTaxExcl);
$totalPriceTaxIncl = $unitPriceTaxIncl * $qty;
} else {
$objTaxManager = TaxManagerFactory::getManager(
$objAddress,
$objGlobalDemand->id_tax_rules_group
);
$objTaxCalculator = $objTaxManager->getTaxCalculator();
}
$objBookingDemand->unit_price_tax_excl = $unitPriceTaxExcl;
$objBookingDemand->unit_price_tax_incl = $unitPriceTaxIncl;
$objBookingDemand->total_price_tax_excl = $totalPriceTaxExcl;
$objBookingDemand->total_price_tax_incl = $totalPriceTaxIncl;
$objOrderDetail = new OrderDetail($objBookingDetail->id_order_detail);
// Update OrderInvoice of this OrderDetail
if ($objOrderDetail->id_order_invoice != 0) {
// values changes as values are calculated accoding to the quantity of the product by webkul
$objOrderInvoice = new OrderInvoice($objOrderDetail->id_order_invoice);
$objOrderInvoice->total_paid_tax_excl += $objBookingDemand->total_price_tax_excl;
$objOrderInvoice->total_paid_tax_incl += $objBookingDemand->total_price_tax_incl;
$objOrderInvoice->update();
}
// change order total
$objOrder->total_paid_tax_excl += $objBookingDemand->total_price_tax_excl;
$objOrder->total_paid_tax_incl += $objBookingDemand->total_price_tax_incl;
$objOrder->total_paid += $objBookingDemand->total_price_tax_incl;
$objBookingDemand->price_calc_method = $objGlobalDemand->price_calc_method;
$objBookingDemand->id_tax_rules_group = $objGlobalDemand->id_tax_rules_group;
if ($objBookingDemand->save()
&& Validate::isLoadedObject($objAddress)
) {
$objBookingDemand->tax_computation_method = (int)$objTaxCalculator->computation_method;
$objBookingDemand->tax_calculator = $objTaxCalculator;
// Now save tax details of the extra demand
$objBookingDemand->setBookingDemandTaxDetails();
}
}
$objOrder->save();
}
}
}
/**
* Deleting the demands into the order.
*/
@@ -3555,7 +3300,7 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
}
private function manageBookingFilter($filters)
private function manageBookingFilter($filters)
{
$ret = '';
$allowedFilters = $this->allowedFilters;
@@ -4072,7 +3817,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
} else {
$objCurrency = new Currency($objOrder->id_currency);
$objBookingDetail = new HotelBookingDetail();
$objBookingDemand = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$objOrderReturn = new OrderReturn();
$idHotel = HotelBookingDetail::getIdHotelByIdOrder($objOrder->id);
@@ -4154,35 +3898,6 @@ class WebserviceSpecificManagementBookingsCore Extends ObjectModel implements We
$roomInfo['child'] = (int) $orderData['children'];
$roomInfo['unit_price_without_tax'] = Tools::ps_round($orderData['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_);
$roomInfo['total_tax'] = Tools::ps_round(($orderData['total_price_tax_incl'] - $orderData['total_price_tax_excl']), _PS_PRICE_COMPUTE_PRECISION_);
if(isset($roomInfo['facilities'])) {
unset($roomInfo['facilities']);
}
if ($extraDemands = $objBookingDemand->getRoomTypeBookingExtraDemands(
$orderData['id_order'],
$orderData['id_product'],
$orderData['id_room'],
$orderData['date_from'],
$orderData['date_to'],
0,
0,
$useTax
)) {
$roomInfo['facilities'] = array();
foreach ($extraDemands as $extraDemand) {
$demand = array();
$demand['name'] = $extraDemand['name'];
$demand['quantity'] = 1;
$demand['unit_price_without_tax'] = Tools::ps_round($extraDemand['unit_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_);
$demand['total_tax'] = Tools::ps_round(($extraDemand['unit_price_tax_incl']- $extraDemand['unit_price_tax_excl']), _PS_PRICE_COMPUTE_PRECISION_);
$demand['per_night'] = 0;
if ($extraDemand['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY) {
$demand['per_night'] = 1;
}
$roomInfo['facilities'][] = $demand;
}
}
if(isset($roomInfo['services'])) {
unset($roomInfo['services']);

View File

@@ -1057,7 +1057,7 @@ class AdminCartsControllerCore extends AdminController
if ($bookingInfo['id'] == $id_booking_data) {
$amt_with_qty = $bookingInfo['amt_with_qty'];
$bookingInfo['amt_with_qty'] = Tools::displayPrice($amt_with_qty);
$bookingInfo['total_price'] = Tools::displayPrice($amt_with_qty + $bookingInfo['demand_price'] + $bookingInfo['additional_service_price'] + $bookingInfo['additional_services_auto_add_price']);
$bookingInfo['total_price'] = Tools::displayPrice($amt_with_qty + $bookingInfo['additional_service_price'] + $bookingInfo['additional_services_auto_add_price']);
$response = array(
'curr_booking_info' => $bookingInfo,
'cart_info' => $this->ajaxReturnVars(),
@@ -1130,7 +1130,7 @@ class AdminCartsControllerCore extends AdminController
if ($bookingInfo['id'] == $idBookingData) {
$amtWithQty = $bookingInfo['amt_with_qty'];
$bookingInfo['amt_with_qty'] = Tools::displayPrice($amtWithQty);
$bookingInfo['total_price'] = Tools::displayPrice($amtWithQty + $bookingInfo['demand_price'] + $bookingInfo['additional_service_price'] + $bookingInfo['additional_services_auto_add_price']);
$bookingInfo['total_price'] = Tools::displayPrice($amtWithQty + $bookingInfo['additional_service_price'] + $bookingInfo['additional_services_auto_add_price']);
$response = array(
'curr_booking_info' => $bookingInfo,
'cart_info' => $this->ajaxReturnVars(),
@@ -1154,8 +1154,8 @@ class AdminCartsControllerCore extends AdminController
}
}
// Process to get extra demands of any room while order creation process form.tpl
public function ajaxProcessGetRoomTypeCartDemands()
// Process to get extra services of any room while order creation process form.tpl
public function ajaxProcessGetRoomTypeCartServices()
{
$response['hasError'] = false;
$response['errors'] = [];
@@ -1167,38 +1167,6 @@ class AdminCartsControllerCore extends AdminController
&& ($idHotelCartBooking = Tools::getValue('id_hotel_cart_booking'))
) {
$objCartBookingData = new HotelCartBookingData();
if ($selectedRoomDemands = $objCartBookingData->getCartExtraDemands(
$idCart,
$idProduct,
$idRoom,
$dateFrom,
$dateTo
)) {
// get room type additional demands
$objRoomDemands = new HotelRoomTypeDemand();
if ($roomTypeDemands = $objRoomDemands->getRoomTypeDemands($idProduct)) {
foreach ($roomTypeDemands as &$demand) {
// if demand has advance options then set demand price as first advance option price.
if (isset($demand['adv_option']) && $demand['adv_option']) {
$demand['price'] = current($demand['adv_option'])['price'];
}
}
foreach ($selectedRoomDemands as &$selectedDemand) {
$objRoom = new HotelRoomInformation($selectedDemand['id_room']);
$selectedDemand['room_num'] = $objRoom->room_num;
if (isset($selectedDemand['extra_demands']) && $selectedDemand['extra_demands']) {
$extraDmd = array();
foreach ($selectedDemand['extra_demands'] as $sDemand) {
$selectedDemand['selected_global_demands'][] = $sDemand['id_global_demand'];
$extraDmd[$sDemand['id_global_demand'].'-'.$sDemand['id_option']] = $sDemand;
}
$selectedDemand['extra_demands'] = $extraDmd;
}
}
$this->context->smarty->assign('roomTypeDemands', $roomTypeDemands);
$this->context->smarty->assign('selectedRoomDemands', $selectedRoomDemands);
}
}
$selectedRoomServiceProduct = array();
if (Configuration::get('PS_ALLOW_ADD_ALL_SERVICES_IN_BOOKING')) {
@@ -1270,8 +1238,8 @@ class AdminCartsControllerCore extends AdminController
'can_edit' => $this->tabAccess['edit'],
));
$response['html_exta_demands'] = $this->context->smarty->fetch(
_PS_ADMIN_DIR_.'/themes/default/template/controllers/orders/_cart_booking_demands.tpl'
$response['html_exta_services'] = $this->context->smarty->fetch(
_PS_ADMIN_DIR_.'/themes/default/template/controllers/orders/_cart_booking_services.tpl'
);
} else {
$response['hasError'] = true;
@@ -1281,26 +1249,6 @@ class AdminCartsControllerCore extends AdminController
$this->ajaxDie(json_encode($response));
}
// Process when admin changes extra demands of any room while order creation process form.tpl
public function ajaxProcessChangeRoomDemands()
{
if ($this->tabAccess['edit'] === 1) {
$response = array('status' => false);
if ($idCartBooking = Tools::getValue('id_cart_booking')) {
if (Validate::isLoadedObject($objCartbookingCata = new HotelCartBookingData($idCartBooking))) {
$roomDemands = Tools::getValue('room_demands');
$roomDemands = json_decode($roomDemands, true);
$roomDemands = json_encode($roomDemands);
$objCartbookingCata->extra_demands = $roomDemands;
if ($objCartbookingCata->save()) {
$response['status'] = true;
}
}
}
$this->ajaxDie(json_encode($response));
}
}
public static function getOrderTotalUsingTaxCalculationMethod($id_cart)
{
$context = Context::getContext();

View File

@@ -107,6 +107,20 @@ class AdminCustomerPreferencesControllerCore extends AdminController
'cast' => 'intval',
'type' => 'bool'
),
'PS_CUSTOMER_NATIONALITY' => array(
'title' => $this->l('Enable nationality'),
'hint' => $this->l('Display or not the nationality field.'),
'validation' => 'isBool',
'cast' => 'intval',
'type' => 'bool'
),
'PS_CUSTOMER_NATIONALITY_MANDATORY' => array(
'title' => $this->l('Nationality is mandatory'),
'hint' => $this->l('If you choose yes, your customer will have to select their nationality.'),
'validation' => 'isBool',
'cast' => 'intval',
'type' => 'bool'
),
'PS_CUSTOMER_NWSL' => array(
'title' => $this->l('Enable newsletter registration'),
'hint' => $this->l('Display or not the newsletter registration tick box.'),

View File

@@ -77,12 +77,39 @@ class AdminCustomersControllerCore extends AdminController
$groups_array[$group['id_group']] = $group['name'];
}
$selected_nationalities = array();
$nationalities_result = Db::getInstance()->executeS('
SELECT DISTINCT cl.id_country, cl.name
FROM '._DB_PREFIX_.'customer c
INNER JOIN '._DB_PREFIX_.'country_lang cl ON (cl.id_country = c.id_country AND cl.id_lang = '.(int)$this->context->language->id.')
WHERE c.id_country != 0 AND c.deleted = 0
ORDER BY cl.name ASC
');
foreach ($nationalities_result as $row) {
$selected_nationalities[$row['id_country']] = $row['name'];
}
$selected_nationalities[-1] = $this->l('Other');
$selected_nationalities[0] = $this->l('None');
$selected_countries = array();
$countries_result = Db::getInstance()->executeS('
SELECT DISTINCT cl.id_country, cl.name
FROM '._DB_PREFIX_.'address ad
INNER JOIN '._DB_PREFIX_.'country_lang cl ON (cl.id_country = ad.id_country AND cl.id_lang = '.(int)$this->context->language->id.')
WHERE ad.deleted = 0
ORDER BY cl.name ASC
');
foreach ($countries_result as $row) {
$selected_countries[$row['id_country']] = $row['name'];
}
$this->_join = 'LEFT JOIN '._DB_PREFIX_.'gender_lang gl ON (a.id_gender = gl.id_gender AND gl.id_lang = '.(int)$this->context->language->id.')';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'group_lang grl ON (a.id_default_group = grl.id_group AND grl.id_lang = '.(int)$this->context->language->id.')';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'orders o ON (a.id_customer = o.id_customer)';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'address ad ON (ad.id_customer = a.id_customer AND ad.deleted = 0)';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'state adstate ON (adstate.id_state = ad.id_state)';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'country_lang adcountry ON (adcountry.id_country = ad.id_country AND adcountry.id_lang = '.(int)$this->context->language->id.')';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'country_lang natcountry ON (natcountry.id_country = a.id_country AND natcountry.id_lang = '.(int)$this->context->language->id.')';
$this->_group = 'GROUP BY a.`id_customer`';
$this->fields_list = array(
@@ -134,6 +161,16 @@ class AdminCustomersControllerCore extends AdminController
'list' => $groups_array,
'filter_key' => 'a!id_default_group',
),
'nationality' => array(
'title' => $this->l('Nationality'),
'optional' => true,
'visible_default' => false,
'type' => 'select',
'list' => $selected_nationalities,
'filter_key' => 'a!id_country',
'filter_type' => 'int',
'orderby' => false,
),
'total_orders' => array(
'title' => $this->l('Number of orders'),
'type' => 'range',
@@ -205,7 +242,10 @@ class AdminCustomersControllerCore extends AdminController
'title' => $this->l('Country'),
'optional' => true,
'visible_default' => false,
'havingFilter' => true,
'type' => 'select',
'list' => $selected_countries,
'filter_key' => 'ad!id_country',
'filter_type' => 'int',
'orderby' => false,
),
'address_phone' => array(
@@ -299,7 +339,8 @@ class AdminCustomersControllerCore extends AdminController
ad.company as address_company, ad.vat_number,
ad.address1, ad.address2, ad.city, adstate.name as state,
ad.postcode, adcountry.name as country, ad.phone as address_phone,
ad.phone_mobile, ad.dni';
ad.phone_mobile, ad.dni,
(CASE WHEN a.id_country = -1 THEN \''.pSQL($this->l('Other')).'\' ELSE natcountry.name END) as nationality';
// Check if we can add a customer
if (Shop::isFeatureActive() && (Shop::getContext() == Shop::CONTEXT_ALL || Shop::getContext() == Shop::CONTEXT_GROUP)) {
@@ -585,6 +626,22 @@ class AdminCustomersControllerCore extends AdminController
'years' => $years
)
),
array(
'type' => 'select',
'label' => $this->l('Nationality'),
'name' => 'id_country',
'required' => (bool)(Configuration::get('PS_CUSTOMER_NATIONALITY') && Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY')),
'col' => '4',
'options' => array(
'query' => Customer::getNationalities($this->context->language->id),
'id' => 'id_country',
'name' => 'name',
'default' => array(
'value' => '',
'label' => $this->l('-- Choose --')
)
),
),
array(
'type' => 'switch',
'label' => $this->l('Enabled'),
@@ -942,6 +999,16 @@ class AdminCustomersControllerCore extends AdminController
$gender = new Gender($customer->id_gender, $this->context->language->id);
$gender_image = $gender->getImage();
$nationality = '';
if ($customer->id_country == -1) {
$nationality = Translate::getAdminTranslation('Other', 'AdminCustomers');
} elseif ($customer->id_country) {
$nationalityCountry = new Country($customer->id_country, $this->context->language->id);
if (Validate::isLoadedObject($nationalityCountry)) {
$nationality = $nationalityCountry->name;
}
}
$customer_stats = $customer->getStats();
$sql = 'SELECT SUM(total_paid_real) FROM '._DB_PREFIX_.'orders WHERE id_customer = %d AND valid = 1';
if ($total_customer = Db::getInstance()->getValue(sprintf($sql, $customer->id))) {
@@ -1091,6 +1158,7 @@ class AdminCustomersControllerCore extends AdminController
'shop_is_feature_active' => Shop::isFeatureActive(),
'name_shop' => $shop->name,
'customer_birthday' => Tools::displayDate($customer->birthday),
'nationality' => $nationality,
'last_update' => Tools::displayDate($customer->date_upd, null, true),
'customer_exists' => Customer::customerExists($customer->email),
'id_lang' => $customer->id_lang,
@@ -1326,6 +1394,10 @@ class AdminCustomersControllerCore extends AdminController
}
}
if (Configuration::get('PS_CUSTOMER_NATIONALITY') && Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY') && !Tools::getValue('id_country')) {
$this->errors[] = Tools::displayError('Nationality is required.');
}
$customer = new Customer();
$this->errors = array_merge($this->errors, $customer->validateFieldsRequiredDatabase());

View File

@@ -161,7 +161,6 @@ class AdminImportControllerCore extends AdminController
$this->required_fields = array('id_hotel', 'name');
self::$validators['image'] = array('AdminImportController', 'split');
self::$validators['id_additional_facilities'] = array('AdminImportController', 'split');
self::$validators['id_service_products'] = array('AdminImportController', 'split');
self::$validators['id_features'] = array('AdminImportController', 'split');
$this->available_fields = array(
@@ -194,7 +193,6 @@ class AdminImportControllerCore extends AdminController
'max_children' => array('label' => $this->l('Maximum children')),
'max_room_occupancy' => array('label' => $this->l('Maximum room occupancy')),
'show_at_front' => array('label' => $this->l('Show at front (0/1)')),
'id_additional_facilities' => array('label' => $this->l('Additional facilities IDs (x,y,z...)')),
'id_service_products' => array('label' => $this->l('Service products IDs (x, y, z...)')),
'id_features' => array('label' => $this->l('Feature IDs (x, y, z...)')),
'description_short' => array('label' => $this->l('Short description')),
@@ -285,7 +283,6 @@ class AdminImportControllerCore extends AdminController
case $this->entities[$this->l('Bookings')]:
$this->required_fields = array('id_customer', 'duration_dates', 'num_rooms', 'id_product');
self::$validators['duration_dates'] = array('AdminImportController', 'split');
self::$validators['id_additional_facilities'] = array('AdminImportController', 'split');
self::$validators['id_service_products'] = array('AdminImportController', 'split');
$this->available_fields = array(
@@ -312,10 +309,6 @@ class AdminImportControllerCore extends AdminController
'label' => $this->l('Service Product IDs (x:n, y:n, z:n,..)'),
'help' => $this->l('id_service_product:quantity')
),
'id_additional_facilities' => array(
'label' => $this->l('Additional Facilities IDs (x:a, y:b, z:c,...)'),
'help' => $this->l('id_additional_facility:id_option')
),
);
break;
case $this->entities[$this->l('Customers')]:
@@ -1746,18 +1739,6 @@ class AdminImportControllerCore extends AdminController
}
$objHotelAdvancePayment->save();
if (isset($product->id_additional_facilities) && $product->id_additional_facilities) {
$objRoomTypeDemand = new HotelRoomTypeDemand();
$objRoomTypeDemand->deleteRoomTypeDemands($product->id);
foreach ($product->id_additional_facilities as $idGlobalDemand) {
if (Validate::isLoadedObject(new HotelRoomTypeGlobalDemand((int) $idGlobalDemand))) {
$objRoomTypeDemand = new HotelRoomTypeDemand();
$objRoomTypeDemand->id_product = $product->id;
$objRoomTypeDemand->id_global_demand = $idGlobalDemand;
$objRoomTypeDemand->save();
}
}
}
//delete existing images if "delete_existing_images" is set to 1
if (isset($product->delete_existing_images)) {
@@ -2558,7 +2539,6 @@ class AdminImportControllerCore extends AdminController
}
$serviceProducts = array();
$globalDemands = array();
if (isset($orderProduct['id_service_products']) && count($orderProduct['id_service_products'])) {
foreach ($orderProduct['id_service_products'] as $serviceProdKey => $serviceProd) {
$serviceProd = explode(':', $serviceProd);
@@ -2579,28 +2559,6 @@ class AdminImportControllerCore extends AdminController
}
}
if (isset($orderProduct['id_additional_facilities']) && count($orderProduct['id_additional_facilities'])) {
foreach ($orderProduct['id_additional_facilities'] as $globalDemandKey => $globalDemand) {
$globalDemand = explode(':', $globalDemand);
$objGlobalDemand = new HotelRoomTypeGlobalDemand($globalDemand[0], $this->context->language->id);
if (Validate::isLoadedObject($objGlobalDemand)) {
$objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption();
// incase no option is provided or if the provided id is not valid or the id is not connected to the diffrent option, we will set the first option as default.
if ((!isset($globalDemand[1])
|| !Validate::isLoadedObject($objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption($globalDemand[1])
|| $objAdvOption->id_global_demand != $globalDemand[0]))
&& ($advOptions = $objAdvOption->getGlobalDemandAdvanceOptions($objGlobalDemand->id))
) {
$globalDemand[1] = $advOptions[0]['id'];
}
$globalDemands[$globalDemandKey]['id_global_demand'] = $globalDemand[0];
$globalDemands[$globalDemandKey]['id_option'] = isset($globalDemand[1]) ? $globalDemand[1] : 0;
}
}
}
$globalDemands = json_encode($globalDemands);
$objCartBooking->updateCartBooking(
$orderProduct['id_product'],
$occupancy,
@@ -2609,7 +2567,6 @@ class AdminImportControllerCore extends AdminController
0,
date('Y-m-d', strtotime($dateFrom)),
date('Y-m-d', strtotime($dateTo)),
$globalDemands,
$serviceProducts,
$this->context->cart->id,
$this->context->cart->id_guest
@@ -3364,12 +3321,6 @@ class AdminImportControllerCore extends AdminController
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_feature_pricing`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_feature_pricing_lang`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_feature_pricing_group`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_global_demand`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_global_demand_lang`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_global_demand_advance_option`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_global_demand_advance_option_lang`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_demand_price`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_demand`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_service_product_price`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'service_product_cart_detail`');
Db::getInstance()->execute('TRUNCATE TABLE `'._DB_PREFIX_.'htl_room_type_restriction_date_range`');
@@ -3472,8 +3423,6 @@ class AdminImportControllerCore extends AdminController
'referrer_cache',
'htl_cart_booking_data',
'htl_booking_detail',
'htl_booking_demands',
'htl_booking_demands_tax',
'service_product_order_detail',
'service_product_cart_detail',
);

View File

@@ -587,6 +587,12 @@ class AdminNormalProductsControllerCore extends AdminController
if ($this->_list) {
$context = $this->context->cloneContext();
$context->shop = clone($context->shop);
$useTourismTax = (bool) Configuration::get('QLO_USE_TOURISM_TAX');
$tourismTaxContext = $useTourismTax ? TaxConfiguration::resolveServiceLineTaxContext(
(int) Configuration::get('WK_PRIMARY_HOTEL'),
0,
new Address(0)
) : null;
/* update product final price */
for ($i = 0; $i < $nb; $i++) {
if (Context::getContext()->shop->getContext() != Shop::CONTEXT_SHOP) {
@@ -598,6 +604,31 @@ class AdminNormalProductsControllerCore extends AdminController
$this->_list[$i]['price_tmp'] = Product::getPriceStatic($this->_list[$i]['id_product'], true, null,
(int)Configuration::get('PS_PRICE_DISPLAY_PRECISION'), null, false, true, 1, true, null, null, null, $nothing, true, true,
$context);
if ($useTourismTax) {
$unitPriceTaxExcl = Product::getPriceStatic($this->_list[$i]['id_product'], false, null,
6, null, false, true, 1, true, null, null, null, $nothing, true, true,
$context);
$serviceTourismTaxAmount = 0.0;
$idTourismTaxRulesGroup = Product::getIdTourismTaxRulesGroupByIdProduct((int) $this->_list[$i]['id_product']);
if ($idTourismTaxRulesGroup) {
$taxCalculator = TaxManagerFactory::getManager(
$tourismTaxContext['address'],
$idTourismTaxRulesGroup
)->getTaxCalculator();
$serviceTourismTaxAmount = $taxCalculator->getTaxesTotalAmount(
(float) $unitPriceTaxExcl,
$tourismTaxContext['checkInDate'],
$tourismTaxContext['numNights'],
$tourismTaxContext['numAdults'],
$tourismTaxContext['childrenAges'],
$tourismTaxContext['collectionType'],
1,
$this->context->currency->id
);
}
$this->_list[$i]['price_tmp'] += $serviceTourismTaxAmount;
}
}
}
@@ -3373,6 +3404,26 @@ class AdminNormalProductsControllerCore extends AdminController
// $data->assign('productFeaturePrices', $productFeaturePrices);
// }
if (Configuration::get('QLO_USE_TOURISM_TAX') && !Tax::excludeTaxeOption()) {
$tourismTaxRulesGroups = TaxRulesGroup::getTaxRulesGroupsForOptions(true, true);
$data->assign('tourismTaxRulesGroups', $tourismTaxRulesGroups);
$data->assign('id_tourism_tax_rules_group', isset($product->id_tourism_tax_rules_group) ? (int) $product->id_tourism_tax_rules_group : 0);
$tourismTaxRates = array();
foreach ($tourismTaxRulesGroups as $tourismTaxRulesGroup) {
$idTourismTaxRulesGroup = (int) $tourismTaxRulesGroup['id_tax_rules_group'];
if (!$idTourismTaxRulesGroup) {
continue;
}
$tourismTaxRates[$idTourismTaxRulesGroup] = TaxConfiguration::getPreviewParams(
$idTourismTaxRulesGroup,
$address,
(int) $this->context->language->id
);
}
$data->assign('tourismTaxRatesByGroup', $tourismTaxRates);
}
$this->tpl_form_vars['custom_form'] = $data->fetch();
}

File diff suppressed because it is too large Load Diff

View File

@@ -112,7 +112,6 @@ class AdminProductsControllerCore extends AdminController
'Configuration' => $this->l('Rooms'),
'Occupancy' => $this->l('Occupancy'),
'LengthOfStay' => $this->l('Length of Stay'),
'AdditionalFacilities' => $this->l('Additional Facilities'),
);
if ($this->context->shop->getContext() != Shop::CONTEXT_GROUP) {
@@ -128,7 +127,6 @@ class AdminProductsControllerCore extends AdminController
'Occupancy' => 8,
'ServiceProduct' => 9,
'LengthOfStay' => 10,
'AdditionalFacilities' => 11,
));
}
@@ -232,7 +230,6 @@ class AdminProductsControllerCore extends AdminController
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_.'feature_product` fp ON (fp.`id_product` = a.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'htl_room_type_demand` hrtd ON (hrtd.`id_product` = a.`id_product`)
LEFT JOIN (
SELECT rsp.*, GROUP_CONCAT(pl.`name`) AS service_products
FROM `'._DB_PREFIX_.'htl_room_type_service_product` rsp
@@ -245,7 +242,7 @@ class AdminProductsControllerCore extends AdminController
$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 .= '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`';
$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';
$this->_select .= ', IF(IFNULL(hap.`active`, 0), 1, 0) badge_success, IF(IFNULL(hap.`active`, 0), 0, 1) badge_danger ';
@@ -435,23 +432,6 @@ class AdminProductsControllerCore extends AdminController
'displayed' => false,
);
$additionalFacilities = array();
$objHotelRoomTypeGlobalDemand = new HotelRoomTypeGlobalDemand();
$demands = $objHotelRoomTypeGlobalDemand->getAllDemands();
foreach ($demands as $demand) {
$additionalFacilities[$demand['id_global_demand']] = $demand['name'];
}
$this->fields_list['id_global_demand'] = array(
'title' => $this->l('Additional Facilities'),
'align' => 'text-center',
'type' => 'select',
'multiple' => true,
'operator' => 'and',
'filter_key' => 'hrtd!id_global_demand',
'list' => $additionalFacilities,
'displayed' => false,
);
$this->locationsAndHotels = array();
$idLocationsCategory = Configuration::get('PS_LOCATIONS_CATEGORY');
$this->objLocationsCategory = new Category($idLocationsCategory, $this->context->language->id);
@@ -665,13 +645,13 @@ class AdminProductsControllerCore extends AdminController
{
$prefix = $this->getCookieFilterPrefix();
$orderByPriceFinal = (empty($orderBy) ? ($this->context->cookie->__get($prefix.$this->table.'Orderby') ? $this->context->cookie->__get($prefix.$this->table.'Orderby') : 'id_'.$this->table) : $orderBy);
$orderWayPriceFinal = (empty($orderWay) ? ($this->context->cookie->__get($prefix.$this->table.'Orderway') ? $this->context->cookie->__get($prefix.$this->table.'Orderby') : 'ASC') : $orderWay);
$orderWayPriceFinal = (empty($orderWay) ? ($this->context->cookie->__get($prefix.$this->table.'Orderway') ? $this->context->cookie->__get($prefix.$this->table.'Orderway') : 'ASC') : $orderWay);
if ($orderByPriceFinal == 'price_final') {
$orderBy = 'id_'.$this->table;
$orderWay = 'ASC';
}
if ($this->action == 'export' && empty($this->_listsql)) {
$this->_select .= ' , trg.`name` AS `id_tax_rules_group`, `features`, hrtdl.`global_demands`';
$this->_select .= ' , trg.`name` AS `id_tax_rules_group`, `features`';
$this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg
ON trg.`id_tax_rules_group` = a.`id_tax_rules_group`
LEFT JOIN (SELECT GROUP_CONCAT(fpl.`name`) AS features, fp.`id_product`
@@ -682,14 +662,6 @@ class AdminProductsControllerCore extends AdminController
GROUP BY fp.`id_product`
) AS fpl ON (a.`id_product` = fpl.`id_product`)';
$this->_join .= ' LEFT JOIN (SELECT hrtgd.`id_product`, `id_lang`, GROUP_CONCAT(`name`) AS `global_demands`
FROM `'._DB_PREFIX_.'htl_room_type_global_demand_lang` hrtgdl
LEFT JOIN `'._DB_PREFIX_.'htl_room_type_demand` hrtgd
ON hrtgd.`id_global_demand` = hrtgdl.`id_global_demand`
WHERE `id_lang`='.(int) $this->context->language->id.'
GROUP BY hrtgd.`id_product`
) AS hrtdl ON (hrtdl.`id_product` = a.`id_product`)';
$this->fields_list = array_merge($this->fields_list, array(
'id_tax_rules_group' => array(
'title' => $this->l('Id Tax Rules group'),
@@ -701,35 +673,59 @@ class AdminProductsControllerCore extends AdminController
'service_products' => array(
'title' => $this->l('Services Products'),
),
'global_demands' => array(
'title' => $this->l('Additional Facilities'),
)
)
);
unset($this->fields_list['id_category_default']);
unset($this->fields_list['id_global_demand']);
unset($this->fields_list['id_feature']);
unset($this->fields_list['id_service_product']);
}
parent::getList($id_lang, $orderBy, $orderWay, $start, $limit, $this->context->shop->id);
parent::getList($id_lang, $orderBy, $orderWay, $start, $limit, $id_lang_shop ?: $this->context->shop->id);
/* update product quantity with attributes ...*/
$nb = count($this->_list);
if ($this->_list) {
$context = $this->context->cloneContext();
$context->shop = clone($context->shop);
$isAllShopsContext = (Context::getContext()->shop->getContext() != Shop::CONTEXT_SHOP);
$priceDisplayPrecision = (int) Configuration::get('PS_PRICE_DISPLAY_PRECISION');
$useTourismTax = (bool) Configuration::get('QLO_USE_TOURISM_TAX');
$todayDate = date('Y-m-d');
$tomorrowDate = date('Y-m-d', strtotime('+1 day', strtotime($todayDate)));
/* update product final price */
for ($i = 0; $i < $nb; $i++) {
if (Context::getContext()->shop->getContext() != Shop::CONTEXT_SHOP) {
if ($isAllShopsContext) {
$context->shop = new Shop((int)$this->_list[$i]['id_shop_default']);
}
// convert price with the currency from context
$this->_list[$i]['price'] = Tools::convertPrice($this->_list[$i]['price'], $this->context->currency, true, $this->context);
$this->_list[$i]['price_tmp'] = Product::getPriceStatic($this->_list[$i]['id_product'], true, null,
(int)Configuration::get('PS_PRICE_DISPLAY_PRECISION'), null, false, true, 1, true, null, null, null, $nothing, true, true,
$priceDisplayPrecision, null, false, true, 1, true, null, null, null, $nothing, true, true,
$context);
$idTourismTaxRulesGroup = (int) $this->_list[$i]['id_tourism_tax_rules_group'];
$idHotel = (int) $this->_list[$i]['id_hotel'];
if ($useTourismTax && $idTourismTaxRulesGroup && $idHotel) {
$idProduct = $this->_list[$i]['id_product'];
$vatAddress = new Address(HotelRoomType::getHotelIdAddressByIdProduct($idProduct));
$vatCalculator = TaxManagerFactory::getManager($vatAddress, Product::getIdTaxRulesGroupByIdProduct($idProduct))->getTaxCalculator();
$unitPriceTaxExcl = $vatCalculator->removeTaxes($this->_list[$i]['price_tmp']);
$hotelTaxContext = TaxConfiguration::resolveHotelAddressAndCollectionType($idHotel, $vatAddress);
$taxCalculator = TaxManagerFactory::getManager($hotelTaxContext['address'], $idTourismTaxRulesGroup)->getTaxCalculator();
$this->_list[$i]['price_tmp'] += $taxCalculator->getTaxesTotalAmount(
$unitPriceTaxExcl,
$todayDate,
1,
1,
array(),
$hotelTaxContext['collectionType'],
1,
$this->context->currency->id
);
}
}
}
@@ -967,11 +963,6 @@ class AdminProductsControllerCore extends AdminController
)) {
$this->errors[] = Tools::displayError('An error occurred while duplicating rooms.');
}
if (!HotelRoomTypeDemand::duplicateRoomTypeDemands($id_product_old, $product->id)) {
$this->errors[] = Tools::displayError(
'An error occurred while duplicating additional facilities.'
);
}
} else {
$this->errors[] = Tools::displayError('An error occurred while duplicating room type.');
}
@@ -2261,9 +2252,6 @@ class AdminProductsControllerCore extends AdminController
if ($this->isTabSubmitted('Configuration')) {
$this->processConfiguration();
}
if ($this->isTabSubmitted('AdditionalFacilities')) {
$this->processAdditionalFacilities();
}
// $this->updatePackItems($object);
// Disallow avanced stock management if the product become a pack
@@ -3303,7 +3291,7 @@ class AdminProductsControllerCore extends AdminController
if (Validate::isLoadedObject($objTaxRuleGroup = new TaxRulesGroup(
$serviceProductPriceInfo['id_tax_rules_group'],
$this->context->language->id
))) {
)) && !$objTaxRuleGroup->is_tourism_tax_rule_group) {
$associationInfo['tax_rules_group_name'] = $objTaxRuleGroup->name;
}
$associationInfo['id_room_type_service_product_price'] = $serviceProductPriceInfo['id_room_type_service_product_price'];
@@ -3313,7 +3301,7 @@ class AdminProductsControllerCore extends AdminController
if (Validate::isLoadedObject($objTaxRuleGroup = new TaxRulesGroup(
$objProduct->id_tax_rules_group,
$this->context->language->id
))) {
)) && !$objTaxRuleGroup->is_tourism_tax_rule_group) {
$associationInfo['default_tax_rules_group_name'] = $objTaxRuleGroup->name;
}
@@ -3327,7 +3315,7 @@ class AdminProductsControllerCore extends AdminController
if (Validate::isLoadedObject($objTaxRulesGroup = new TaxRulesGroup(
$serviceProduct['id_tax_rules_group'],
$this->context->language->id
))) {
)) && !$objTaxRulesGroup->is_tourism_tax_rule_group) {
$serviceProduct['tax_rules_group_name'] = $objTaxRulesGroup->name;
}
@@ -3834,136 +3822,6 @@ class AdminProductsControllerCore extends AdminController
die(json_encode($response));
}
public function initFormAdditionalFacilities($obj)
{
$data = $this->createTemplate($this->tpl_form);
if ($obj->id) {
$objGlobalDemand = new HotelRoomTypeGlobalDemand();
$allDemands = $objGlobalDemand->getAllDemands();
foreach($allDemands as &$demand) {
if ($demand['id_tax_rules_group'] == 0) {
$demand['default_tax_rules_group_name'] = 'No tax';
} else {
$objTaxRuleGroup = new TaxRulesGroup(
$demand['id_tax_rules_group'],
$this->context->language->id
);
$demand['default_tax_rules_group_name'] = $objTaxRuleGroup->name;
}
}
$objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT'));
// get room type additional facilities
$objRoomDemand = new HotelRoomTypeDemand();
$selectedDemands = $objRoomDemand->getRoomTypeDemands($obj->id, 0, 0);
$data->assign(array(
'product' => $obj,
'selectedDemands' => $selectedDemands,
'allDemands' => $allDemands,
'defaultcurrencySign' => $objCurrency->sign,
'idDefaultcurrency' => $objCurrency->id,
));
} else {
$this->displayWarning($this->l('You must save this room type before managing additional facilities.'));
}
$this->tpl_form_vars['custom_form'] = $data->fetch();
}
public function processAdditionalFacilities()
{
if ($idProduct = Tools::getValue('id_product')) {
$errors = array();
$objRoomTypeDemand = new HotelRoomTypeDemand();
$objRoomTypeDemandPrice = new HotelRoomTypeDemandPrice();
// first delete all the previously saved prices and demands of this room type
$objRoomTypeDemand->deleteRoomTypeDemands($idProduct);
$objRoomTypeDemandPrice->deleteRoomTypeDemandPrices($idProduct);
if ($selectedDemands = Tools::getValue('selected_demand')) {
$objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption();
foreach ($selectedDemands as $idGlobalDemand) {
if (Validate::isLoadedObject($objGlobalDemand = new HotelRoomTypeGlobalDemand($idGlobalDemand))) {
// save selected demands for this room type
$objRoomTypeDemand = new HotelRoomTypeDemand();
$objRoomTypeDemand->id_product = $idProduct;
$objRoomTypeDemand->id_global_demand = $idGlobalDemand;
$objRoomTypeDemand->save();
// save selected demands prices for this room type
$demandPrice = Tools::getValue('demand_price_'.$idGlobalDemand);
if (Validate::isPrice($demandPrice)) {
if ($objGlobalDemand->price != $demandPrice) {
$objRoomTypeDemandPrice = new HotelRoomTypeDemandPrice();
$objRoomTypeDemandPrice->id_product = $idProduct;
$objRoomTypeDemandPrice->id_global_demand = $idGlobalDemand;
$objRoomTypeDemandPrice->id_option = 0;
$objRoomTypeDemandPrice->price = $demandPrice;
$objRoomTypeDemandPrice->save();
}
} else {
$errors[] = Tools::displayError('Invalid demand price of facility.').
' : '.$objGlobalDemand->name[$this->context->language->id];
}
if ($advOptions = $objAdvOption->getGlobalDemandAdvanceOptions($idGlobalDemand)) {
foreach ($advOptions as $option) {
if (Validate::isLoadedObject($objAdvOption = new HotelRoomTypeGlobalDemandAdvanceOption($option['id']))) {
$optionPrice = Tools::getValue('option_price_'.$option['id']);
if (Validate::isPrice($optionPrice)) {
if ($optionPrice != $objAdvOption->price) {
$objRoomTypeDemandPrice = new HotelRoomTypeDemandPrice();
$objRoomTypeDemandPrice->id_product = $idProduct;
$objRoomTypeDemandPrice->id_global_demand = $idGlobalDemand;
$objRoomTypeDemandPrice->id_option = $option['id'];
$objRoomTypeDemandPrice->price = $optionPrice;
$objRoomTypeDemandPrice->save();
}
} else {
$errors[] = Tools::displayError('Invalid price of advanced option: ').$objAdvOption->name[$this->context->language->id];
}
}
}
}
}
}
if (count($errors)) {
$this->warnings[] = Tools::displayError('Invalid price values for additional facilities were not saved. Please correct them and try again.');
$this->errors = array_merge($this->errors, $errors);
}
$objCartBookingData = new HotelCartBookingData();
if ($cartExtraDemands = $objCartBookingData->getCartExtraDemands(0, $idProduct)) {
// delete the demands from cart if not available in cart
$objRoomDemand = new HotelRoomTypeDemand();
$roomTypeDemandIds = array();
if ($roomTypeDemands = $objRoomDemand->getRoomTypeDemands($idProduct)) {
$roomTypeDemandIds = array_keys($roomTypeDemands);
}
foreach ($cartExtraDemands as &$demandInfo) {
if (isset($demandInfo['extra_demands']) && $demandInfo['extra_demands']) {
$cartChanged = 0;
foreach ($demandInfo['extra_demands'] as $key => $demand) {
if (!in_array($demand['id_global_demand'], $roomTypeDemandIds)) {
$cartChanged = 1;
unset($demandInfo['extra_demands'][$key]);
}
}
if ($cartChanged) {
if (Validate::isLoadedObject(
$objCartBooking = new HotelCartBookingData($demandInfo['id'])
)) {
$objCartBooking->extra_demands = json_encode($demandInfo['extra_demands']);
$objCartBooking->save();
}
}
}
}
}
}
}
}
/**
* @param Product $obj
*
@@ -4192,6 +4050,25 @@ class AdminProductsControllerCore extends AdminController
$data->assign('productFeaturePrices', $productFeaturePrices);
}
if (Configuration::get('QLO_USE_TOURISM_TAX') && !Tax::excludeTaxeOption()) {
$tourismTaxRulesGroups = TaxRulesGroup::getTaxRulesGroupsForOptions(true, true);
$data->assign('tourismTaxRulesGroups', $tourismTaxRulesGroups);
$data->assign('id_tourism_tax_rules_group', isset($product->id_tourism_tax_rules_group) ? (int) $product->id_tourism_tax_rules_group : 0);
$roomTypeInfo = (new HotelRoomType())->getRoomTypeInfoByIdProduct((int) $product->id);
$idHotel = $roomTypeInfo ? (int) $roomTypeInfo['id_hotel'] : 0;
$collectionType = TaxConfiguration::resolveHotelAddressAndCollectionType($idHotel, $address)['collectionType'];
$tourismTaxRates = array();
foreach ($tourismTaxRulesGroups as $tourismTaxRulesGroup) {
if (!$tourismTaxRulesGroup['id_tax_rules_group']) {
continue;
}
$tourismTaxRates[$tourismTaxRulesGroup['id_tax_rules_group']] = TaxConfiguration::getPreviewParams($tourismTaxRulesGroup['id_tax_rules_group'], $address, $this->context->language->id, $collectionType);
}
$data->assign('tourismTaxRatesByGroup', $tourismTaxRates);
}
$this->tpl_form_vars['custom_form'] = $data->fetch();
}

View File

@@ -36,7 +36,6 @@ class AdminSearchControllerCore extends AdminController
'AdminFeatures' => 1,
'AdminOrders' => 1,
'AdminOrderRefundRules' => 1,
'AdminRoomTypeGlobalDemand' => 1,
'AdminGroups' => 1,
'AdminHotelAmenities' => 1,
'AdminCustomers' => 1,
@@ -191,7 +190,6 @@ class AdminSearchControllerCore extends AdminController
if (!$searchType) {
$this->searchAddress();
$this->searchHotelAmenities();
$this->searchAdditionalFacilities();
$this->searchRefundRules();
}
}
@@ -436,6 +434,7 @@ class AdminSearchControllerCore extends AdminController
if ($hotelAmenities = $objHotelAmenities->searchByName($this->query, $this->context->language->id)) {
$amenities = array();
foreach ($hotelAmenities as $key => $hotelAmenity) {
$amenities[$hotelAmenity['id_amenity']]['id_amenity'] = $hotelAmenity['id_amenity'];
$amenities[$hotelAmenity['id_amenity']]['name'] = $hotelAmenity['name'];
if ($hotelAmenity['id_parent']) {
$amenities[$hotelAmenity['id_amenity']]['id'] = $hotelAmenity['id_parent'];
@@ -450,29 +449,6 @@ class AdminSearchControllerCore extends AdminController
}
}
public function searchAdditionalFacilities()
{
if (class_exists('HotelRoomTypeGlobalDemand')) {
if (isset($this->controllerAccess['AdminRoomTypeGlobalDemand']) && $this->controllerAccess['AdminRoomTypeGlobalDemand']) {
$objHotelRoomTypeGlobalDemands = new HotelRoomTypeGlobalDemand();
if ($globalDemads = $objHotelRoomTypeGlobalDemands->searchByName($this->query, $this->context->language->id)) {
foreach ($globalDemads as $key => $demand) {
if (!(int) $globalDemads[$key]['price']) {
$globalDemads[$key]['price'] = $globalDemads[$key]['option_price'];
}
$globalDemads[$key]['per_day_price_calc'] = $this->l('No');
if ($globalDemads[$key]['price_calc_method'] == HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY) {
$globalDemads[$key]['per_day_price_calc'] = $this->l('Yes');
}
}
$this->_list['global_demands'] = $globalDemads;
}
}
}
}
public function searchRefundRules()
{
if (class_exists('HotelOrderRefundRules')) {
@@ -559,18 +535,6 @@ class AdminSearchControllerCore extends AdminController
);
}
protected function initGlobalDemandList()
{
$this->show_toolbar = false;
$this->fields_list['global_demands'] = array(
'id_global_demand' => array('title' => $this->l('ID'), 'align' => 'center', 'width' => 25),
'name' => array('title' => $this->l('Name')),
'option_name' => array('title' => $this->l('Advance Option Name')),
'price' => array('title' => $this->l('Price'), 'type' => 'price', 'currency' => true),
'per_day_price_calc' => array('title' => $this->l('Per day price calculation'))
);
}
protected function initRefundRuleList()
{
$this->show_toolbar = false;
@@ -854,10 +818,10 @@ class AdminSearchControllerCore extends AdminController
$helper = new HelperList();
$helper->shopLinkType = '';
$helper->simple_header = true;
$helper->identifier = 'id_customer_message';
$helper->actions = array('edit');
$helper->identifier = 'id_customer_thread';
$helper->actions = array('view');
$helper->show_toolbar = false;
$helper->table = 'feature';
$helper->table = 'customer_thread';
$helper->currentIndex = $this->context->link->getAdminLink('AdminCustomerThreads', false);
$query = trim(Tools::getValue('bo_query'));
@@ -980,27 +944,6 @@ class AdminSearchControllerCore extends AdminController
$this->tpl_view_vars['groups'] = $view;
}
if (isset($this->_list['global_demands']) && count($this->_list['global_demands'])) {
$view = '';
$this->initGlobalDemandList();
$helper = new HelperList();
$helper->shopLinkType = '';
$helper->simple_header = true;
$helper->identifier = 'id_global_demand';
$helper->actions = array('edit');
$helper->show_toolbar = false;
$helper->table = 'htl_room_type_global_demand';
$helper->currentIndex = $this->context->link->getAdminLink('AdminRoomTypeGlobalDemand', false);
$helper->token = Tools::getAdminTokenLite('AdminRoomTypeGlobalDemand');
if ($this->_list['global_demands']) {
$view = $helper->generateList($this->_list['global_demands'], $this->fields_list['global_demands']);
}
$this->tpl_view_vars['num_global_demands'] = count($this->_list['global_demands']);
$this->tpl_view_vars['global_demands'] = $view;
}
if (isset($this->_list['refund_rules']) && count($this->_list['refund_rules'])) {
$view = '';
$this->initRefundRuleList();

View File

@@ -560,29 +560,11 @@ public function initPageHeaderToolbar()
$objHotelBookingDetail = new HotelBookingDetail();
$bookingDetails = $objHotelBookingDetail->getBookingDataByOrderId($idOrder);
$objBookingDemands = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
foreach ($bookingDetails as &$booking) {
$booking['extra_service_total_price_tax_incl'] = 0;
$extraDemands = $objBookingDemands->getRoomTypeBookingExtraDemands(
$idOrder,
$booking['id_product'],
$booking['id_room'],
$booking['date_from'],
$booking['date_to'],
0,
0,
1,
$booking['id']
);
if ($extraDemands) {
foreach ($extraDemands as $demand) {
$booking['extra_service_total_price_tax_incl'] += (float) $demand['total_price_tax_incl'];
}
}
$roomServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0, $booking['id']
);

View File

@@ -0,0 +1,850 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License version 3.0
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/license/osl-3-0-php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade QloApps to newer
* versions in the future. If you wish to customize QloApps for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/license/osl-3-0-php Open Software License version 3.0
*/
class AdminSourcesControllerCore extends AdminController
{
protected $position_identifier = 'id_business_source';
protected $ordersTotal = 0;
protected $viewBusinessSource;
public function __construct()
{
$this->bootstrap = true;
$this->table = 'business_source';
$this->className = 'BusinessSource';
$this->identifier = 'id_business_source';
$this->list_id = 'business_source';
$this->lang = true;
$this->deleted = false;
$this->_defaultOrderBy = 'position';
$this->_defaultOrderWay = 'ASC';
$this->context = Context::getContext();
$this->_new_list_header_design = true;
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'icon' => 'icon-trash',
'confirm' => $this->l('Delete selected items?')
)
);
parent::__construct();
}
public function setMedia()
{
parent::setMedia();
$this->addJS(_PS_JS_DIR_.'admin/sources.js');
}
public function init()
{
if (Tools::isSubmit('addsource') || Tools::isSubmit('addbusiness_source')) {
$this->display = 'add';
}
if (Tools::isSubmit('updatesource') || Tools::isSubmit('updatebusiness_source')) {
$this->display = 'edit';
}
if (Tools::isSubmit('submitAddsource') || Tools::isSubmit('submitAddsourceAndStay')) {
$this->display = Tools::getValue('id_source') ? 'edit' : 'add';
}
if (Tools::isSubmit('submitAddbusiness_source') || Tools::isSubmit('submitAddbusiness_sourceAndStay')) {
$this->display = Tools::getValue('id_business_source') ? 'edit' : 'add';
}
return parent::init();
}
public function initContent()
{
if (Tools::isSubmit('submitFiltersource') || Tools::isSubmit('submitResetsource')) {
$this->list_id = 'source';
$this->display = 'view';
$idBusinessSource = (int) Tools::getValue('id_business_source');
self::$currentIndex .= '&id_business_source=' . $idBusinessSource . '&viewbusiness_source';
if (Tools::isSubmit('submitResetsource')) {
$this->processResetFilters('source');
}
}
parent::initContent();
}
/**
* @see AdminController::initPageHeaderToolbar()
*/
public function initPageHeaderToolbar()
{
if (empty($this->display)) {
$this->page_header_toolbar_btn['new_business_source'] = array(
'href' => self::$currentIndex.'&addbusiness_source&token='.$this->token,
'desc' => $this->l('Add new Business Source', null, null, false),
'icon' => 'process-icon-new'
);
} elseif ($this->display == 'view') {
$idBusinessSource = (int)Tools::getValue('id_business_source');
if ($idBusinessSource) {
$this->page_header_toolbar_btn['new_source'] = array(
'href' => self::$currentIndex.'&addsource&id_business_source='.$idBusinessSource.'&token='.$this->token,
'desc' => $this->l('Add new Booking Source', null, null, false),
'icon' => 'process-icon-new'
);
$this->page_header_toolbar_btn['back_to_business'] = array(
'href' => self::$currentIndex.'&token='.$this->token,
'desc' => $this->l('Back To Business Source', null, null, false),
'icon' => 'process-icon-back'
);
}
}
unset($this->toolbar_btn['back']);
parent::initPageHeaderToolbar();
}
protected function initBusinessSourcesList()
{
$this->fields_list = array(
'id_business_source' => array(
'title' => $this->l('ID'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'filter_key' => 'b!name'
),
'code' => array(
'title' => $this->l('Code'),
'align' => 'text-center'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'position' => 'position'
),
'orders_count' => array(
'title' => $this->l('Orders (%)'),
'align' => 'text-center',
'orderby' => false,
'search' => false,
'callback' => 'formatOrdersPercentage',
),
'active' => array(
'title' => $this->l('Enabled'),
'active' => 'status',
'type' => 'bool',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'orderby' => false
),
);
}
protected function initSourcesList()
{
$this->fields_list = array(
'id_source' => array(
'title' => $this->l('ID'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'name' => array(
'title' => $this->l('Booking Source'),
'width' => 'auto',
'filter_key' => 'b!name'
),
'source_type_name' => array(
'title' => $this->l('Business Source'),
'orderby' => false,
'search' => false,
),
'code' => array(
'title' => $this->l('Code'),
'align' => 'text-center'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'position' => 'position'
),
'orders_count' => array(
'title' => $this->l('Orders (%)'),
'align' => 'text-center',
'orderby' => false,
'search' => false,
'callback' => 'formatOrdersPercentage',
),
'active' => array(
'title' => $this->l('Enabled'),
'active' => 'status',
'type' => 'bool',
'align' => 'text-center',
'class' => 'fixed-width-xs',
'orderby' => false
),
);
}
public function renderList()
{
$this->addRowAction('view');
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowActionSkipList('delete', BusinessSource::getUnremovableIds());
$this->_where = 'AND a.`deleted` = 0';
$this->_select = '(SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` o
INNER JOIN `'._DB_PREFIX_.'source` s ON s.`id_source` = o.`id_source`
WHERE s.`id_business_source` = a.`id_business_source`) AS `orders_count`';
$this->ordersTotal = Source::getTotalOrderCount();
$this->initBusinessSourcesList();
$this->toolbar_title = $this->l('Business Source');
return parent::renderList();
}
public function renderView()
{
$idBusinessSource = (int)Tools::getValue('id_business_source');
$objBusinessSource = new BusinessSource($idBusinessSource, (int)$this->context->language->id);
if (!Validate::isLoadedObject($objBusinessSource)) {
Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token);
}
$this->viewBusinessSource = $objBusinessSource;
$this->addRowAction('edit');
$this->addRowAction('merge');
$this->addRowAction('delete');
$this->addRowActionSkipList('delete', Source::getUnremovableIds());
$this->table = 'source';
$this->className = 'Source';
$this->identifier = 'id_source';
$this->list_id = 'source';
$this->_select = 'bsl.`name` AS `source_type_name`,
(SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` o WHERE o.`id_source` = a.`id_source`) AS `orders_count`';
$this->ordersTotal = $objBusinessSource->getOrderCount();
$this->_join = 'LEFT JOIN `'._DB_PREFIX_.'business_source` bs ON (bs.`id_business_source` = a.`id_business_source`)';
$this->_join .= 'LEFT JOIN `'._DB_PREFIX_.'business_source_lang` bsl ON (bsl.`id_business_source` = bs.`id_business_source` AND bsl.`id_lang` = '.(int)$this->context->language->id.')';
$this->_where = 'AND a.`deleted` = 0 AND a.`id_business_source` = '.(int)$objBusinessSource->id;
$this->initSourcesList();
$this->processFilter();
$list = parent::renderList();
$this->page_header_toolbar_title = $this->l('Business Source:').' '.$objBusinessSource->name;
$this->toolbar_title = $this->getSourcesListTitle();
return $list;
}
protected function getSourcesListTitle()
{
if (!Validate::isLoadedObject($this->viewBusinessSource)) {
return $this->l('Booking Sources');
}
return $this->viewBusinessSource->name.' <span class="badge">'.$this->_listTotal.'</span>';
}
public function getTemplateListVars()
{
$vars = parent::getTemplateListVars();
if ($this->display == 'view' && $this->table == 'source') {
$vars['title'] = $this->getSourcesListTitle();
}
return $vars;
}
public function renderForm()
{
if (Tools::isSubmit('updatesource')
|| Tools::isSubmit('addsource')
|| Tools::isSubmit('submitAddsource')
|| Tools::isSubmit('submitAddsourceAndStay')
) {
return $this->renderSourceForm();
}
return $this->renderBusinessSourceForm();
}
protected function renderBusinessSourceForm()
{
if (!($objBusinessSource = $this->loadObject(true))) {
return;
}
$this->fields_form = array(
'legend' => array(
'title' => $this->l('Business Source'),
'icon' => 'icon-edit'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'lang' => true,
'required' => true,
'hint' => $this->l('Invalid characters:').' &lt;&gt;;=#{}'
),
array(
'type' => 'text',
'label' => $this->l('Code'),
'name' => 'code',
'required' => true,
'class' => 'fixed-width-xl',
'readonly' => (bool)$objBusinessSource->id,
'hint' => $objBusinessSource->id
? $this->l('The code cannot be changed after creation.')
: $this->l('A short unique machine code, e.g. "OTA". Letters, numbers, underscores and hyphens only.')
),
array(
'type' => 'switch',
'label' => $this->l('Enabled'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'default_value' => 1,
'values' => array(
array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')),
array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled')),
)
),
),
'submit' => array(
'title' => $this->l('Save'),
'name' => 'submitAddbusiness_source'
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAddbusiness_sourceAndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
return parent::renderForm();
}
protected function renderSourceForm()
{
$this->table = 'source';
$this->className = 'Source';
$this->identifier = 'id_source';
$this->object = null;
if (!($objSource = $this->loadObject(true))) {
return;
}
$businessSources = BusinessSource::getActiveList((int)$this->context->language->id);
$isUnremovableSource = $objSource->id && in_array($objSource->id, Source::getUnremovableIds());
$this->fields_form = array(
'legend' => array(
'title' => $this->l('Booking Source'),
'icon' => 'icon-edit'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'lang' => true,
'required' => true,
'hint' => $this->l('Invalid characters:').' &lt;&gt;;=#{}'
),
array(
'type' => 'select',
'label' => $this->l('Business Source'),
'name' => 'id_business_source',
'required' => true,
'options' => array(
'query' => $businessSources,
'id' => 'id_business_source',
'name' => 'name',
),
),
array(
'type' => 'text',
'label' => $this->l('Source Code'),
'name' => 'code',
'required' => true,
'class' => 'fixed-width-xl',
'readonly' => (bool)$objSource->id,
'hint' => $objSource->id
? $this->l('The code cannot be changed after creation.')
: $this->l('A short unique machine code, e.g. "BOOKING_COM". Letters, numbers, underscores and hyphens only.')
),
array(
'type' => 'switch',
'label' => $this->l('Enabled'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'default_value' => 1,
'disabled' => $isUnremovableSource,
'hint' => $isUnremovableSource ? $this->l('Built-in Booking Sources cannot be disabled.') : null,
'values' => array(
array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')),
array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled')),
)
),
),
'submit' => array(
'title' => $this->l('Save'),
'name' => 'submitAddsource'
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAddsourceAndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
return parent::renderForm();
}
public function postProcess()
{
if (Tools::isSubmit('submitAddsource') || Tools::isSubmit('submitAddsourceAndStay')) {
return $this->postProcessSource();
} elseif (Tools::isSubmit('submitMergeSource')) {
return $this->postProcessMergeSource();
} elseif (Tools::isSubmit('deletesource')) {
return $this->postProcessDeleteSource();
} elseif (Tools::isSubmit('statussource')) {
return $this->postProcessStatusSource();
} elseif (Tools::isSubmit('submitBulkenableSelectionsource')) {
return $this->processUpdateStatusBulk(1);
} elseif (Tools::isSubmit('submitBulkdisableSelectionsource')) {
return $this->processUpdateStatusBulk(0);
} elseif (Tools::isSubmit('submitBulkdeletesource')) {
return $this->postProcessBulkDeleteSource();
} elseif (Tools::isSubmit('submitAddbusiness_source') || Tools::isSubmit('submitAddbusiness_sourceAndStay')) {
return $this->postProcessBusinessSource();
} elseif (Tools::isSubmit('status'.$this->table)) {
return $this->postProcessStatusBusinessSource();
} elseif (Tools::isSubmit('delete'.$this->table)) {
return $this->postProcessDeleteBusinessSource();
} elseif (Tools::isSubmit('submitBulkdelete'.$this->table)) {
return $this->postProcessBulkDeleteBusinessSource();
} else {
return parent::postProcess();
}
}
protected function postProcessDeleteSource()
{
$objSource = new Source((int)Tools::getValue('id_source'));
if (!$objSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Booking Source.');
} elseif (!$objSource->delete()) {
$this->errors[] = Tools::displayError('An error occurred while deleting the Booking Source.');
} else {
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_business_source='.(int)$objSource->id_business_source.'&conf=1&token='.$this->token);
}
}
protected function postProcessStatusSource()
{
if (Validate::isLoadedObject($objSource = new Source((int)Tools::getValue('id_source')))) {
$idBusinessSource = $objSource->id_business_source;
$newActive = !$objSource->active;
$objBusinessSource = new BusinessSource($idBusinessSource);
if ($newActive && (!Validate::isLoadedObject($objBusinessSource) || !$objBusinessSource->active)) {
$this->errors[] = $this->l('You cannot enable this Booking Source because its Business Source is disabled.');
} else {
$objSource->active = $newActive;
if ($objSource->save()) {
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_business_source='.(int)$idBusinessSource.'&conf=5&token='.$this->token;
}
}
}
}
protected function postProcessStatusBusinessSource()
{
if (Validate::isLoadedObject($objBusinessSource = new BusinessSource((int)Tools::getValue('id_business_source')))) {
$newActive = !$objBusinessSource->active;
if (!$newActive && $objBusinessSource->hasUnremovableSource()) {
$this->errors[] = $this->l('You cannot disable this Business Source because it has one or more permanent (built-in) Booking Sources under it.');
} else {
$objBusinessSource->active = $newActive;
if ($objBusinessSource->save()) {
$this->redirect_after = self::$currentIndex.'&token='.$this->token.'&conf=5';
}
}
}
}
protected function postProcessBulkDeleteSource()
{
$idBusinessSource = 0;
foreach (Tools::getValue('sourceBox') as $selection) {
$objSource = new Source((int)$selection);
$idBusinessSource = $objSource->id_business_source;
if (!$objSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Booking Source.');
break;
}
}
if (!count($this->errors)) {
$this->className = 'Source';
$this->table = 'source';
$this->boxes = Tools::getValue('sourceBox');
parent::processBulkDelete();
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_business_source='.(int)$idBusinessSource.'&conf=1&token='.$this->token;
}
}
protected function postProcessDeleteBusinessSource()
{
$objBusinessSource = new BusinessSource((int)Tools::getValue('id_business_source'));
if (!$objBusinessSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Business Source.');
} else {
return parent::postProcess();
}
}
protected function postProcessBulkDeleteBusinessSource()
{
foreach (Tools::getValue($this->table.'Box') as $selection) {
$objBusinessSource = new BusinessSource((int)$selection);
if (!$objBusinessSource->isRemovable()) {
$this->errors[] = $this->l('For security reasons, you cannot delete a built-in Business Source.');
break;
}
}
if (!count($this->errors)) {
return parent::postProcess();
}
}
protected function processUpdateStatusBulk($status = 1)
{
$idBusinessSource = (int)Tools::getValue('id_business_source');
$this->className = 'Source';
$this->table = 'source';
$this->boxes = Tools::getValue('sourceBox');
if(empty($this->boxes)){
$this->errors[] = $this->l('You must select at least one item to perform a bulk action.');
} elseif ($status) {
foreach ($this->boxes as $selection) {
$objSource = new Source((int)$selection);
$objBusinessSource = new BusinessSource($objSource->id_business_source);
if (!Validate::isLoadedObject($objBusinessSource) || !$objBusinessSource->active) {
$this->errors[] = $this->l('You cannot enable a Booking Source whose Business Source is disabled.');
break;
}
}
}
$this->display = 'view';
if(!$this->errors){
parent::processBulkStatusSelection($status);
$this->redirect_after = self::$currentIndex.'&viewbusiness_source&id_business_source='.(int)$idBusinessSource.'&conf=5&token='.$this->token;
}
}
protected function postProcessSource()
{
$idSource = (int)Tools::getValue('id_source');
$idBusinessSource = (int)Tools::getValue('id_business_source');
$objSource = new Source($idSource);
$sourceCode = $idSource ? $objSource->code : trim(Tools::getValue('code'));
$isUnremovableSource = $idSource && in_array($idSource, Source::getUnremovableIds());
$defaultLangId = Configuration::get('PS_LANG_DEFAULT');
$objDefaultLanguage = Language::getLanguage((int) $defaultLangId);
$languages = Language::getLanguages(false);
if (!trim(Tools::getValue('name_'.$defaultLangId))) {
$this->errors[] = $this->l('Name is required at least in ').
$objDefaultLanguage['name'];
} else {
foreach ($languages as $lang) {
if (trim(Tools::getValue('name_'.$lang['id_lang']))) {
if (!Validate::isGenericName(Tools::getValue('name_'.$lang['id_lang']))) {
$this->errors[] = $this->l('Invalid name in ').$lang['name'];
}
}
}
}
$objBusinessSource = new BusinessSource($idBusinessSource);
if (!Validate::isLoadedObject($objBusinessSource) || $objBusinessSource->deleted) {
$this->errors[] = $this->l('Please select a valid Business Source.');
} elseif (!$isUnremovableSource && (int)Tools::getValue('active') && !$objBusinessSource->active) {
$this->errors[] = $this->l('You cannot enable this Booking Source because its Business Source is disabled.');
}
if (!$idSource) {
if (!$sourceCode || !Validate::isModuleName($sourceCode)) {
$this->errors[] = $this->l('Source Code is invalid. Only letters, numbers, underscores and hyphens are allowed.');
} elseif (Source::codeExists($sourceCode, $idSource)) {
$this->errors[] = $this->l('This Source Code is already used by another Booking Source.');
}
}
if (count($this->errors)) {
$this->display = $idSource ? 'edit' : 'add';
return false;
}
$objSource->id_business_source = $idBusinessSource;
$objSource->code = $sourceCode;
$objSource->active = $isUnremovableSource ? $objSource->active : (int)Tools::getValue('active');
$objSource->name = array();
foreach (Language::getIDs(false) as $idLang) {
$objSource->name[$idLang] = Tools::getValue('name_'.$idLang);
}
if (!$objSource->save()) {
$this->errors[] = Tools::displayError('An error occurred while saving the Booking Source.');
$this->display = $idSource ? 'edit' : 'add';
return false;
}
if (Tools::isSubmit('submitAddsourceAndStay')) {
Tools::redirectAdmin(self::$currentIndex.'&updatesource&id_source='.$objSource->id.'&conf='.($idSource ? 4 : 3).'&token='.$this->token);
}
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_business_source='.$idBusinessSource.'&conf='.($idSource ? 4 : 3).'&token='.$this->token);
}
protected function postProcessMergeSource()
{
$idBusinessSource = (int)Tools::getValue('id_business_source');
$idCurrentSource = (int)Tools::getValue('current_source');
$idTargetSource = (int)Tools::getValue('target_source');
$objCurrent = new Source($idCurrentSource);
$objTarget = new Source($idTargetSource);
if (!Validate::isLoadedObject($objCurrent) || !Validate::isLoadedObject($objTarget)
|| (int)$objCurrent->id_business_source !== $idBusinessSource || (int)$objTarget->id_business_source !== $idBusinessSource
) {
$this->errors[] = $this->l('Please select valid Current and Target Booking Sources.');
} elseif ($idCurrentSource === $idTargetSource) {
$this->errors[] = $this->l('Current and Target Booking Source cannot be the same.');
} else {
$objCurrent->mergeOrdersInto($idTargetSource);
}
$this->display = 'view';
if (!count($this->errors)) {
Tools::redirectAdmin(self::$currentIndex.'&viewbusiness_source&id_business_source='.$idBusinessSource.'&conf=4&token='.$this->token);
}
}
protected function postProcessBusinessSource()
{
$idBusinessSource = (int)Tools::getValue('id_business_source');
if ($idBusinessSource) {
$sourceTypeCode = (new BusinessSource($idBusinessSource))->code;
$_POST['code'] = $sourceTypeCode;
} else {
$sourceTypeCode = trim(Tools::getValue('code'));
}
$defaultLangId = Configuration::get('PS_LANG_DEFAULT');
$objDefaultLanguage = Language::getLanguage((int) $defaultLangId);
$languages = Language::getLanguages(false);
if (!trim(Tools::getValue('name_'.$defaultLangId))) {
$this->errors[] = $this->l('Name is required at least in ').
$objDefaultLanguage['name'];
} else {
foreach ($languages as $lang) {
if (trim(Tools::getValue('name_'.$lang['id_lang']))) {
if (!Validate::isGenericName(Tools::getValue('name_'.$lang['id_lang']))) {
$this->errors[] = $this->l('Invalid name in ').$lang['name'];
}
}
}
}
if (!$idBusinessSource) {
if (!$sourceTypeCode || !Validate::isModuleName($sourceTypeCode)) {
$this->errors[] = $this->l('Code is invalid. Only letters, numbers, underscores and hyphens are allowed.');
} elseif (BusinessSource::codeExists($sourceTypeCode, $idBusinessSource)) {
$this->errors[] = $this->l('This Code is already used by another Business Source.');
}
}
if ($idBusinessSource && !(int)Tools::getValue('active')) {
$objBusinessSource = new BusinessSource($idBusinessSource);
if ($objBusinessSource->hasUnremovableSource()) {
$this->errors[] = $this->l('You cannot disable this Business Source because it has one or more permanent (built-in) Booking Sources under it.');
}
}
if (count($this->errors)) {
$this->display = $idBusinessSource ? 'edit' : 'add';
return false;
}
return parent::postProcess();
}
public function formatOrdersPercentage($count, $row)
{
$percentage = $this->ordersTotal ? round(((int)$count / $this->ordersTotal) * 100, 1) : 0;
return $percentage.'%';
}
public function displayEnableLink($token, $id, $value, $active, $id_category = null, $id_product = null, $ajax = false)
{
if ($this->table == 'source' && in_array((int)$id, Source::getUnremovableIds())) {
return '<span class="list-action-enable action-enabled" title="'.$this->l('Built-in Booking Sources cannot be disabled.').'">
<i class="icon-check"></i>
</span>';
}
$helper = new HelperList();
$helper->token = $this->token;
$helper->currentIndex = self::$currentIndex;
$helper->table = $this->table;
$helper->identifier = $this->identifier;
return $helper->displayEnableLink($token, $id, $value, $active, $id_category, $id_product, $ajax);
}
public function displayMergeLink($token, $id, $name = null)
{
$idBusinessSource = (int) Tools::getValue('id_business_source');
return '<a href="#"
class="merge-source-btn"
title="' . $this->l('Merge') . '"
data-id-source="' . (int) $id . '"
data-id-business-source="' . $idBusinessSource . '"
data-ajax-url="' . self::$currentIndex . '&token=' . ($token ?: $this->token) . '">
<i class="icon-random"></i> ' . $this->l('Merge') . '
</a>';
}
public function ajaxProcessInitMergeSourceModal()
{
$response = array('hasError' => 1);
if ($this->tabAccess['edit'] === 1) {
$idBusinessSource = (int)Tools::getValue('id_business_source');
$idSource = (int)Tools::getValue('id_source');
$objSource = new Source($idSource,(int)$this->context->language->id);
if (Validate::isLoadedObject($objSource) && (int)$objSource->id_business_source === $idBusinessSource) {
$this->context->smarty->assign(array(
'sources' => Source::getActiveSource($idBusinessSource, $idSource, (int)$this->context->language->id),
'current_source' => $objSource,
'id_business_source' => $idBusinessSource,
'current_index' => self::$currentIndex,
'token' => $this->token,
));
$this->context->smarty->assign(array(
'modal_id' => 'merge_source_modal',
'modal_class' => 'modal-md',
'modal_title' => '<i class="icon-random"></i> &nbsp ' .$this->l('Merge Booking Source'),
'modal_content' => $this->context->smarty->fetch('controllers/sources/modals/_merge_source_form.tpl'),
));
$response['hasError'] = 0;
$response['modalHtml'] = $this->context->smarty->fetch('modal.tpl');
}
}
die(Tools::jsonEncode($response));
}
protected function filterToField($key, $filter)
{
if ($this->table == 'source') {
$this->initSourcesList();
} else {
$this->initBusinessSourcesList();
}
return parent::filterToField($key, $filter);
}
public function ajaxProcessUpdatePositions()
{
if ($this->tabAccess['edit'] !== 1) {
die(json_encode(array('hasError' => true, 'errors' => $this->l('You do not have permission to edit this.'))));
}
$way = (int)Tools::getValue('way');
$id = (int)Tools::getValue('id');
if ($positions = Tools::getValue('source')) {
$className = 'Source';
} elseif ($positions = Tools::getValue('source_type')) {
$className = 'BusinessSource';
} else {
die(json_encode(array('hasError' => true, 'errors' => 'Unknown table for position update.')));
}
foreach ($positions as $position => $value) {
$pos = explode('_', $value);
if (isset($pos[2]) && (int)$pos[2] === $id) {
if ($object = new $className((int)$pos[2])) {
if (isset($position) && $object->updatePosition($way, $position)) {
echo 'ok position '.(int)$position.' for '.$className.' '.$id;
} else {
echo '{"hasError" : true, "errors" : "Can not update tab '.(int)$id.' to position '.(int)$position.' "}';
}
} else {
echo json_encode(array(
'hasError' => true,
'errors' => 'Can not update '.$className.' '.$id.' to position '.(int)$position,
));
}
break;
}
}
}
}

View File

@@ -1909,7 +1909,7 @@ class AdminStatsControllerCore extends AdminStatsTabController
return $result;
}
// Calculate total services revenue (services and demands)
// Calculate total services revenue (services )
public static function getServicesRevenueForDiscreteDates($dateFrom, $dateTo = null, $idHotel = null, $useCache = true)
{
$dateTo = !$dateTo ? date('Y-m-d', strtotime('+1 day', strtotime($dateFrom))) : $dateTo;
@@ -1946,23 +1946,6 @@ class AdminStatsControllerCore extends AdminStatsTabController
$totalServicesRevenue += $servicesRevenue;
}
// Calculate demands revenue
$demandsRevenueSql = 'SELECT SUM((hdmd.`total_price_tax_excl` / o.`conversion_rate`) / DATEDIFF(hbd.`date_to`, hbd.`date_from`))
FROM `'._DB_PREFIX_.'htl_booking_demands` hdmd
LEFT JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd
ON (hdmd.`id_htl_booking` = hbd.`id`)
LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product` = hbd.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = hbd.`id_order`)
WHERE p.`active` = 1
AND o.`valid` = 1
AND hbd.`is_refunded` = 0
AND hbd.`date_from` < "'.pSQL($discreteDate['date_to']).' 00:00:00" AND hbd.`date_to` > "'.pSQL($discreteDate['date_from']).' 00:00:00"'.
(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel, 'hbd') : '');
if ($demandsRevenue = Db::getInstance()->getValue($demandsRevenueSql)) {
$totalServicesRevenue += $demandsRevenue;
}
$result[$discreteDate['timestamp_from']] = $totalServicesRevenue;
}

View File

@@ -96,6 +96,59 @@ class AdminTaxRulesGroupControllerCore extends AdminController
return parent::renderList();
}
/**
* Return taxes for the rule-form dropdown, filtered by whether this TRG is a tourism group.
*
* @return array
*/
protected function getTaxOptionsForGroup()
{
$idTaxRulesGroup = (int) Tools::getValue('id_tax_rules_group');
$isTourism = false;
if ($idTaxRulesGroup) {
$taxRulesGroup = new TaxRulesGroup($idTaxRulesGroup);
if (Validate::isLoadedObject($taxRulesGroup)) {
$isTourism = (bool) $taxRulesGroup->is_tourism_tax_rule_group;
}
}
$idLang = (int) $this->context->language->id;
$sql = new DbQuery();
if ($isTourism) {
$sql->select(
't.`id_tax`, tl.`name`,'
. ' IFNULL(tourism_tax.`calculation_type`, 0) AS tourism_tax_calc_type,'
. ' IFNULL(tourism_tax.`tax_value`, 0) AS tourism_tax_value'
);
} else {
$sql->select('t.`id_tax`, tl.`name`, t.`rate`');
}
$sql->from('tax', 't');
$sql->leftJoin('tax_lang', 'tl', 't.`id_tax` = tl.`id_tax` AND tl.`id_lang` = ' . $idLang);
if ($isTourism) {
$sql->leftJoin('tax_configuration', 'tourism_tax', 'tourism_tax.`id_tax` = t.`id_tax`');
}
$sql->where('t.`deleted` != 1 AND t.`active` = 1');
$sql->where('t.`is_tourism_tax` = ' . ($isTourism ? 1 : 0));
$sql->orderBy('tl.`name` ASC');
$rows = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
if ($isTourism && is_array($rows)) {
$currency = $this->context->currency;
$currencySign = Tools::safeOutput(trim($currency->prefix . $currency->suffix));
foreach ($rows as &$row) {
$typeLabel = ((int) $row['tourism_tax_calc_type'] === TaxConfiguration::CALCULATION_TYPE_PERCENTAGE)
? (float) $row['tourism_tax_value'] . '%'
: $currencySign . ' ' . (float) $row['tourism_tax_value'];
$row['name'] = $row['name'] . ' (' . $typeLabel . ')';
}
unset($row);
}
return $rows;
}
public function initRulesList($id_group)
{
$this->table = 'tax_rule';
@@ -127,7 +180,10 @@ class AdminTaxRulesGroupControllerCore extends AdminController
),
'rate' => array(
'title' => $this->l('Tax'),
'class' => 'fixed-width-sm'
'class' => 'fixed-width-sm',
'callback' => 'displayTaxRuleRate',
'orderby' => false,
'search' => false,
),
'description' => array(
'title' => $this->l('Description')
@@ -141,7 +197,10 @@ class AdminTaxRulesGroupControllerCore extends AdminController
c.`name` AS country_name,
s.`name` AS state_name,
CONCAT_WS(" - ", a.`zipcode_from`, a.`zipcode_to`) AS zipcode,
t.rate';
t.`rate`,
t.`is_tourism_tax`,
IFNULL(tourism_tax.`calculation_type`, 0) AS tourism_tax_calc_type,
IFNULL(tourism_tax.`tax_value`, 0) AS tourism_tax_value';
$this->_join = '
LEFT JOIN `'._DB_PREFIX_.'country_lang` c
@@ -149,7 +208,9 @@ class AdminTaxRulesGroupControllerCore extends AdminController
LEFT JOIN `'._DB_PREFIX_.'state` s
ON (a.`id_state` = s.`id_state`)
LEFT JOIN `'._DB_PREFIX_.'tax` t
ON (a.`id_tax` = t.`id_tax`)';
ON (a.`id_tax` = t.`id_tax`)
LEFT JOIN `'._DB_PREFIX_.'tax_configuration` tourism_tax
ON (tourism_tax.`id_tax` = t.`id_tax`)';
$this->_where = 'AND `id_tax_rules_group` = '.(int)$id_group;
$this->_use_found_rows = false;
@@ -194,7 +255,19 @@ class AdminTaxRulesGroupControllerCore extends AdminController
'label' => $this->l('Disabled')
)
)
)
),
array(
'type' => 'switch',
'label' => $this->l('Tourism tax rule group'),
'name' => 'is_tourism_tax_rule_group',
'required' => false,
'is_bool' => true,
'hint' => $this->l('Mark this group as tourism-only. All tax rules added here must reference tourism taxes.'),
'values' => array(
array('id' => 'is_tourism_tax_rule_on', 'value' => 1, 'label' => $this->l('Yes')),
array('id' => 'is_tourism_tax_rule_off', 'value' => 0, 'label' => $this->l('No')),
)
),
),
'submit' => array(
'title' => $this->l('Save and stay'),
@@ -309,7 +382,7 @@ class AdminTaxRulesGroupControllerCore extends AdminController
$this->l('- This tax only: Will apply only this tax').'<br>',
$this->l('- Combine: Combine taxes (e.g.: 10% + 5% = 15%)').'<br>',
$this->l('- One after another: Apply taxes one after another (e.g.: 0 + 10% = 0 + 5% = 5.5)')
)
),
),
array(
'type' => 'select',
@@ -317,7 +390,7 @@ class AdminTaxRulesGroupControllerCore extends AdminController
'name' => 'id_tax',
'required' => false,
'options' => array(
'query' => Tax::getTaxes((int)$this->context->language->id),
'query' => $this->getTaxOptionsForGroup(),
'id' => 'id_tax',
'name' => 'name',
'default' => array(
@@ -325,7 +398,7 @@ class AdminTaxRulesGroupControllerCore extends AdminController
'label' => $this->l('No Tax')
)
),
'hint' => sprintf($this->l('(Total tax: %s)'), '9%')
'hint' => $this->l('Select the tax to apply for this rule.')
),
array(
'type' => 'text',
@@ -374,6 +447,75 @@ class AdminTaxRulesGroupControllerCore extends AdminController
}
/**
* List column callback: render the Tax column in the tax rules list.
* Tourism-fixed taxes show the currency sign; tourism-percent and regular VAT taxes show %.
*
* @param mixed $value t.rate (always 0 for tourism taxes)
* @param array $row Full list row — includes is_tourism_tax, tourism_tax_calc_type, tourism_tax_value
* @return string
*/
public function displayTaxRuleRate($value, $row)
{
return TaxConfiguration::getFormattedRateForDisplay($value, $row, $this->context->currency);
}
public function postProcess()
{
if ($this->action == 'save') {
$idGroup = (int) Tools::getValue('id_tax_rules_group');
$newIsTourism = (int) Tools::getValue('is_tourism_tax_rule_group');
if ($idGroup) {
$taxRulesGroup = new TaxRulesGroup($idGroup);
if (Validate::isLoadedObject($taxRulesGroup)) {
$oldIsTourism = (int) $taxRulesGroup->is_tourism_tax_rule_group;
if ($oldIsTourism && !$newIsTourism) {
if ($taxRulesGroup->hasTourismTaxRules()) {
$this->errors[] = $this->l(
'Cannot convert this to a VAT group: it still contains tourism taxes. Remove the tourism tax rules first.'
);
$_POST['is_tourism_tax_rule_group'] = $oldIsTourism;
$this->display = 'edit';
return;
}
if ($taxRulesGroup->hasProductsUsingAsTourismGroup()) {
$this->errors[] = $this->l(
'Cannot convert this to a VAT group: one or more products still use it as their tourism tax rule. Reassign them first.'
);
$_POST['is_tourism_tax_rule_group'] = $oldIsTourism;
$this->display = 'edit';
return;
}
}
if (!$oldIsTourism && $newIsTourism) {
if ($taxRulesGroup->hasVatTaxRules()) {
$this->errors[] = $this->l(
'Cannot convert this to a tourism group: it still contains VAT taxes. Remove the VAT tax rules first.'
);
$_POST['is_tourism_tax_rule_group'] = $oldIsTourism;
$this->display = 'edit';
return;
}
if ($taxRulesGroup->hasProductsUsingAsVatGroup()) {
$this->errors[] = $this->l(
'Cannot convert this to a tourism group: one or more products or services still use it as their regular tax rule. Reassign them first.'
);
$_POST['is_tourism_tax_rule_group'] = $oldIsTourism;
$this->display = 'edit';
return;
}
}
}
}
}
parent::postProcess();
}
public function initProcess()
{
if (Tools::isSubmit('deletetax_rule')) {
@@ -430,27 +572,27 @@ class AdminTaxRulesGroupControllerCore extends AdminController
$this->errors[] = Tools::displayError('A tax rule already exists for this country/state with tax only behavior.');
continue;
}
$tr = new TaxRule();
$taxRule = new TaxRule();
// update or creation?
if (isset($id_rule) && $first) {
$tr->id = $id_rule;
$taxRule->id = $id_rule;
$first = false;
}
$tr->id_tax = $id_tax;
$taxRule->id_tax = $id_tax;
$tax_rules_group = new TaxRulesGroup((int)$id_tax_rules_group);
$tr->id_tax_rules_group = (int)$tax_rules_group->id;
$tr->id_country = (int)$id_country;
$tr->id_state = (int)$id_state;
list($tr->zipcode_from, $tr->zipcode_to) = $tr->breakDownZipCode($zip_code);
$taxRule->id_tax_rules_group = (int)$tax_rules_group->id;
$taxRule->id_country = (int)$id_country;
$taxRule->id_state = (int)$id_state;
list($taxRule->zipcode_from, $taxRule->zipcode_to) = $taxRule->breakDownZipCode($zip_code);
// Construct Object Country
$country = new Country((int)$id_country, (int)$this->context->language->id);
if ($zip_code && $country->need_zip_code) {
if ($country->zip_code_format) {
foreach (array($tr->zipcode_from, $tr->zipcode_to) as $zip_code) {
foreach (array($taxRule->zipcode_from, $taxRule->zipcode_to) as $zip_code) {
if ($zip_code) {
if (!$country->checkZipCode($zip_code)) {
$this->errors[] = sprintf(
@@ -463,19 +605,19 @@ class AdminTaxRulesGroupControllerCore extends AdminController
}
}
$tr->behavior = (int)$behavior;
$tr->description = $description;
$this->tax_rule = $tr;
$_POST['id_state'] = $tr->id_state;
$taxRule->behavior = (int)$behavior;
$taxRule->description = $description;
$this->tax_rule = $taxRule;
$_POST['id_state'] = $taxRule->id_state;
$this->errors = array_merge($this->errors, $this->validateTaxRule($tr));
$this->errors = array_merge($this->errors, $this->validateTaxRule($taxRule));
if (count($this->errors) == 0) {
$tax_rules_group = $this->updateTaxRulesGroup($tax_rules_group);
$tr->id = (int)$tax_rules_group->getIdTaxRuleGroupFromHistorizedId((int)$tr->id);
$tr->id_tax_rules_group = (int)$tax_rules_group->id;
$taxRule->id = (int)$tax_rules_group->getIdTaxRuleGroupFromHistorizedId((int)$taxRule->id);
$taxRule->id_tax_rules_group = (int)$tax_rules_group->id;
if (!$tr->save()) {
if (!$taxRule->save()) {
$this->errors[] = Tools::displayError('An error has occurred: Cannot save the current tax rule.');
}
}
@@ -525,14 +667,14 @@ class AdminTaxRulesGroupControllerCore extends AdminController
/**
* Check if the tax rule could be added in the database
*
* @param TaxRule $tr
* @param TaxRule $taxRule
*
* @return array
*/
protected function validateTaxRule(TaxRule $tr)
protected function validateTaxRule(TaxRule $taxRule)
{
// @TODO: check if the rule already exists
return $tr->validateController();
return $taxRule->validateController();
}
protected function displayAjaxUpdateTaxRule()

File diff suppressed because it is too large Load Diff

View File

@@ -110,6 +110,23 @@ class AdminTranslationsControllerCore extends AdminController
'page_header_toolbar_title' => $this->page_header_toolbar_title,
'page_header_toolbar_btn' => $this->page_header_toolbar_btn));
}
public function setMedia()
{
parent::setMedia();
if (Tools::getValue('type') == 'mails') {
Media::addJsDef(array(
'mailResetSuccessMsg' => $this->l('The template is reset to its original content.'),
'mailResetErrorMsg' => $this->l('An error occurred while resetting the template.'),
'mailResetTooltipCore' => $this->l('On reset, the template will be reset to the default mail template.'),
'mailResetTooltipModule' => $this->l('On reset, the template will be reset using modules/{module}/mails/{iso}/'),
'admin_translations_link' => $this->context->link->getAdminLink('AdminTranslations'),
'EMAIL_TEMPLATE_TYPE_CORE' => Language::EMAIL_TEMPLATE_TYPE_CORE,
'EMAIL_TEMPLATE_TYPE_MODULE' => Language::EMAIL_TEMPLATE_TYPE_MODULE,
));
$this->addJS(_PS_JS_DIR_.'admin/translations.js');
}
}
/**
* This function create vars by default and call the good method for generate form
@@ -1429,6 +1446,9 @@ class AdminTranslationsControllerCore extends AdminController
*/
public function postProcess()
{
if ($this->ajax) {
return parent::postProcess();
}
$this->getInformations();
/* PrestaShop demo mode */
@@ -1663,6 +1683,50 @@ class AdminTranslationsControllerCore extends AdminController
}
}
public function ajaxProcessResetMailTemplate()
{
if (empty($this->tabAccess['edit'])) {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('You do not have permission to edit this.'))));
}
$iso_code = Tools::getValue('iso_code') ? Tools::getValue('iso_code') : null;
$theme = Tools::getValue('theme');
$mail_template_name = Tools::getValue('mail_name');
$template_type = (int)Tools::getValue('template_type');
$module_name = Tools::getValue('module_name') ? Tools::getValue('module_name') : false;
if (!Validate::isLanguageIsoCode($iso_code)) {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid iso code.'))));
}
if (!Validate::isTplName($mail_template_name)) {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid mail template to reset.'))));
}
if ($template_type === Language::EMAIL_TEMPLATE_TYPE_MODULE) {
if (!$module_name || !Validate::isModuleName($module_name)) {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid module name.'))));
}
} elseif ($template_type === Language::EMAIL_TEMPLATE_TYPE_CORE) {
$module_name = false;
} else {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid template type.'))));
}
if ($theme) {
$themes_base_dir = realpath(_PS_ALL_THEMES_DIR_);
$theme_real_path = realpath(_PS_ALL_THEMES_DIR_.$theme);
if ($themes_base_dir === false
|| $theme_real_path === false
|| strncmp($theme_real_path, $themes_base_dir.DIRECTORY_SEPARATOR, strlen($themes_base_dir) + 1) !== 0
) {
die(json_encode(array('hasError' => true, 'error' => Tools::displayError('Invalid theme.'))));
}
}
die(json_encode(Language::resetEmailTemplate($mail_template_name, $iso_code, $template_type, $module_name, $theme)));
}
/**
* Include file $dir/$file and return the var $var declared in it.
* This create the file if not exists
@@ -2362,9 +2426,12 @@ class AdminTranslationsControllerCore extends AdminController
$str_return .= '</div>';
}
$mail_available_variables = $this->displayMailAvailableVariables($mail_files);
if (array_key_exists('txt', $mail_files)) {
$str_return .= '<div class="tab-pane" id="'.$mail_name.'-text">';
$str_return .= $this->displayMailBlockTxt($mail_files['txt'], $obj_lang->iso_code, $mail_name, $group_name, $name_for_module);
$str_return .= $mail_available_variables;
$str_return .= '</div>';
}
@@ -2372,6 +2439,7 @@ class AdminTranslationsControllerCore extends AdminController
if (isset($mail_files['html'])) {
$str_return .= $this->displayMailEditor($mail_files['html'], $obj_lang->iso_code, $url_mail, $mail_name, $group_name, $name_for_module);
}
$str_return .= $mail_available_variables;
$str_return .= '</div>';
$str_return .= '</div>';
@@ -2389,6 +2457,46 @@ class AdminTranslationsControllerCore extends AdminController
$str_return .= '</div><!-- #'.$id_html.' --></div><!-- end .mails_field -->';
return $str_return;
}
protected function displayMailAvailableVariables($mail_files)
{
$variables = $this->getMailTemplateVariables($mail_files);
if (empty($variables)) {
return '';
}
$str_return = '<div class="mail-available-variables" style="margin-top:10px;">';
foreach ($variables as $variable) {
$tag = '{'.$variable.'}';
$str_return .= '<span class="label label-default pointer mail-variable-tag" style="display:inline-block;margin:0 4px 6px 0;" data-variable="'.Tools::htmlentitiesUTF8($tag).'">'.Tools::htmlentitiesUTF8($tag).'</span> ';
}
$str_return .= '</div>';
return $str_return;
}
protected function getMailTemplateVariables($mail_files)
{
$content = '';
foreach (array('html', 'txt') as $type) {
if (empty($mail_files[$type]) || !is_array($mail_files[$type])) {
continue;
}
if (isset($mail_files[$type]['en'])) {
$content .= ' '.$mail_files[$type]['en'];
} else {
$content .= ' '.reset($mail_files[$type]);
}
}
$variables = array();
if ($content !== '' && preg_match_all('/\{([a-zA-Z0-9_]+)\}/', $content, $matches)) {
$variables = array_unique($matches[1]);
sort($variables);
}
return $variables;
}
/**
* Just build the html structure for display txt mails
* @since 1.4.0.14
@@ -3070,12 +3178,31 @@ class AdminTranslationsControllerCore extends AdminController
}
$sanitizedFilePath = realpath($email_file);
$permittedMailDir = realpath(_PS_MAIL_DIR_) . DIRECTORY_SEPARATOR;
if ($sanitizedFilePath === false) {
return false;
}
if ($sanitizedFilePath === false || $permittedMailDir === false || strpos($sanitizedFilePath, $permittedMailDir) !== 0) {
$permitted_roots = array(
realpath(_PS_MAIL_DIR_),
realpath(_PS_ROOT_DIR_.'/themes/'),
realpath(_PS_ROOT_DIR_.'/modules/'),
);
$is_permitted = false;
foreach ($permitted_roots as $permitted_root) {
if ($permitted_root !== false
&& strpos($sanitizedFilePath, $permitted_root.DIRECTORY_SEPARATOR) === 0
&& strpos($sanitizedFilePath, DIRECTORY_SEPARATOR.'mails'.DIRECTORY_SEPARATOR) !== false
) {
$is_permitted = true;
break;
}
}
if (!$is_permitted) {
return false;
}
return file_get_contents($sanitizedFilePath);
}
}
}

View File

@@ -106,6 +106,9 @@ class AuthControllerCore extends FrontController
$newsletter = Configuration::get('PS_CUSTOMER_NWSL') || (Module::isInstalled('blocknewsletter') && Module::getInstanceByName('blocknewsletter')->active);
$this->context->smarty->assign('birthday', (bool) Configuration::get('PS_CUSTOMER_BIRTHDATE'));
$this->context->smarty->assign('nationality', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY'));
$this->context->smarty->assign('nationality_mandatory', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY'));
$this->context->smarty->assign('nationality_countries', Customer::getNationalities($this->context->language->id));
$this->context->smarty->assign('newsletter', $newsletter);
$this->context->smarty->assign('optin', (bool)Configuration::get('PS_CUSTOMER_OPTIN'));
@@ -429,6 +432,10 @@ class AuthControllerCore extends FrontController
$this->errors[] = Tools::displayError('Phone number is required.');
}
if (Configuration::get('PS_CUSTOMER_NATIONALITY') && Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY') && !Tools::getValue('id_nationality')) {
$this->errors[] = Tools::displayError('Nationality is required.');
}
if (!Tools::getValue('is_new_customer', 1)) {
if (Validate::isEmail($email = Tools::getValue('email'))
&& $idCustomer = Customer::customerExists(Tools::getValue('email'), true, false)
@@ -461,6 +468,7 @@ class AuthControllerCore extends FrontController
if (!count($this->errors)) {
$customer->phone = Tools::getValue('phone');
$customer->id_country = (int)Tools::getValue('id_nationality');
if ($customer->add()) {
if (!$customer->is_guest) {
if (!$this->sendConfirmationMail($customer)) {
@@ -607,6 +615,7 @@ class AuthControllerCore extends FrontController
$customer->is_guest = 0;
}
$customer->phone = Tools::getValue('phone');
$customer->id_country = (int)Tools::getValue('id_nationality');
if (!$customer->save()) {
$this->errors[] = Tools::displayError('An error occurred while creating your account.');
} else {

View File

@@ -155,8 +155,8 @@ class CartControllerCore extends FrontController
$result = $this->context->cart->deleteProduct($this->id_product, $this->id_product_attribute, $this->customization_id, $this->id_address_delivery);
// now get updated available rooms
$date_from = Tools::getValue('dateFrom');
$date_to = Tools::getValue('dateTo');
$date_from = Tools::getValue('date_from');
$date_to = Tools::getValue('date_to');
$date_from = date("Y-m-d H:i:s", strtotime($date_from));
$date_to = date("Y-m-d H:i:s", strtotime($date_to));
$objRoomType = new HotelRoomType();
@@ -315,7 +315,7 @@ class CartControllerCore extends FrontController
}
if ($occupancyRequiredForBooking && $operator == 'up') {
if ($occupancy = json_decode(Tools::getValue('occupancy'), true)) {
if ($occupancy = Tools::getValue('occupancy')) {
$this->qty = count($occupancy);
} else {
$this->errors[] = Tools::displayError('Invalid occupnacy.');
@@ -337,11 +337,21 @@ class CartControllerCore extends FrontController
if (!$this->errors) {
$objRoomType = new HotelRoomType();
if ($roomTypeInfo = $objRoomType->getRoomTypeInfoByIdProduct($this->id_product)) {
$date_from = Tools::getValue('dateFrom');
$date_to = Tools::getValue('dateTo');
$date_from = Tools::getValue('date_from');
$date_to = Tools::getValue('date_to');
$date_from = date("Y-m-d H:i:s", strtotime($date_from));
$date_to = date("Y-m-d H:i:s", strtotime($date_to));
$serviceProducts = json_decode(Tools::getValue('serviceProducts'),true);
$rawServiceProducts = Tools::getValue('service_product');
$serviceProducts = [];
if (is_array($rawServiceProducts) && !empty($rawServiceProducts)) {
foreach ($rawServiceProducts as $id_product => $data) {
$serviceProducts[] = [
'id_product' => (int) $id_product,
'quantity' => isset($data['quantity']) ? (int) $data['quantity'] : 1,
];
}
}
// valdiate occupancy if providede
if ($operator == 'up' && $occupancyRequiredForBooking) {
@@ -419,7 +429,11 @@ class CartControllerCore extends FrontController
$total_available_rooms = $hotelRoomData['stats']['num_avail'];
if (Tools::getValue('op', 'up') == 'up') {
if ($total_available_rooms < $req_rm) {
die(json_encode(array('status' => 'unavailable_quantity', 'avail_rooms' => $total_available_rooms)));
if (Tools::getValue('ajax')) {
die(json_encode(array('status' => 'unavailable_quantity', 'avail_rooms' => $total_available_rooms)));
} else {
$this->errors[] = Tools::displayError('All rooms are sold out for the selected dates. Please try with different dates.');
}
} else {
// validate service products if available
if ($serviceProducts) {
@@ -450,10 +464,18 @@ class CartControllerCore extends FrontController
}
}
} else {
die(json_encode(array('status' => 'failed3')));
if (Tools::getValue('ajax')) {
die(json_encode(array('status' => 'failed3')));
} else {
$this->errors[] = Tools::displayError('An error occurred while processing your request.');
}
}
} else {
die(json_encode(array('status' => 'failed4')));
if (Tools::getValue('ajax')) {
die(json_encode(array('status' => 'failed4')));
} else {
$this->errors[] = Tools::displayError('An error occurred while processing your request.');
}
}
}
} else {
@@ -607,8 +629,6 @@ class CartControllerCore extends FrontController
*/
if ($product->booking_product) {
$objHotelCartBookingData = new HotelCartBookingData();
$roomDemand = json_decode(Tools::getValue('roomDemands'), true);
$roomDemand = json_encode($roomDemand);
$availQty = $total_available_rooms;
$update_quantity = $objHotelCartBookingData->updateCartBooking(
$this->id_product,
@@ -618,7 +638,6 @@ class CartControllerCore extends FrontController
0,
$date_from,
$date_to,
$roomDemand,
$serviceProducts,
$id_cart,
$id_guest
@@ -630,7 +649,6 @@ class CartControllerCore extends FrontController
'date_to' => $date_to,
'id_product' => $this->id_product,
'occupancy' => $occupancy,
'room_demand' => $roomDemand,
'req_rm' => $req_rm
));
} else {

View File

@@ -59,6 +59,7 @@ class CategoryControllerCore extends FrontController
$this->addCSS(_THEME_CSS_DIR_.'occupancy.css');
$this->addJS(_THEME_JS_DIR_.'occupancy.js');
$this->addJS(_THEME_JS_DIR_.'room-type-service-products.js');
$scenes = Scene::getScenes($this->category->id, $this->context->language->id, true, false);
if ($scenes && count($scenes)) {
$this->addJS(_THEME_JS_DIR_.'scenes.js');

View File

@@ -311,7 +311,7 @@ class ContactControllerCore extends FrontController
)
) {
// by webkul to get media link.
$htlImgLink = $this->context->link->getMediaLink($objHotelImage->getImageLink($hotel['id_cover_img'], ImageType::getFormatedName('medium')));
$htlImgLink = $this->context->link->getMediaLink($objHotelImage->getImageLink($hotel['id_cover_img'], ImageType::getFormatedName('large')));
if ((bool)Tools::file_get_contents($htlImgLink)) {
$hotel['image_url'] = $htlImgLink;
@@ -330,7 +330,6 @@ class ContactControllerCore extends FrontController
$this->context->smarty->assign(
array(
'hotelsInfo' => $hotelsInfo,
'viewOnMap' => Configuration::get('WK_GOOGLE_ACTIVE_MAP'),
'displayHotels' => Configuration::get('WK_DISPLAY_CONTACT_PAGE_HOTEL_LIST'),
'gblHtlPhone' => $gblHtlPhone,
'gblHtlEmail' => $gblHtlEmail,

View File

@@ -106,35 +106,25 @@ class GuestTrackingControllerCore extends FrontController
}
}
public function displayAjaxGetRoomTypeBookingDemands()
public function displayAjaxgetRoomTypeBookingServices()
{
$response = array('extra_demands' => false);
$response = array('extra_services' => false);
$order = new Order((int) Tools::getValue('id_order'));
if (!Validate::isLoadedObject($order) || $order->secure_key != Tools::getValue('secure_key')) {
$this->ajaxDie(json_encode($response));
}
if (($idProduct = Tools::getValue('id_product'))
&& ($idOrder = Tools::getValue('id_order'))
&& ($dateFrom = Tools::getValue('date_from'))
&& ($dateTo = Tools::getValue('date_to'))
) {
$objHotelBookingDemands = new HotelBookingDemands();
$useTax = 0;
if (Group::getPriceDisplayMethod($this->context->customer->id_default_group) == PS_TAX_INC) {
$useTax = 1;
}
if ($extraDemands = $objHotelBookingDemands->getRoomTypeBookingExtraDemands(
$idOrder,
$idProduct,
0,
$dateFrom,
$dateTo,
1,
0,
$useTax
)) {
$this->context->smarty->assign(array(
'useTax' => $useTax,
'extraDemands' => $extraDemands,
));
}
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
if ($additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
@@ -158,7 +148,7 @@ class GuestTrackingControllerCore extends FrontController
'objOrder' => new Order($idOrder),
));
$response['extra_demands'] = $this->context->smarty->fetch(_PS_THEME_DIR_.'_partials/order-extra-services.tpl');
$response['extra_services'] = $this->context->smarty->fetch(_PS_THEME_DIR_.'_partials/order-extra-services.tpl');
}
$this->ajaxDie(json_encode($response));
@@ -257,10 +247,9 @@ class GuestTrackingControllerCore extends FrontController
$hotelServiceProducts = array();
if ($hotelresInstalled) {
if ($orderProducts = $order->getProducts()) {
$total_demands_price_te = 0;
$total_demands_price_ti = 0;
$total_convenience_fee_te = 0;
$total_convenience_fee_ti = 0;
$total_tourism_tax = OrderTaxDetail::getOrderTourismTaxTotal($idOrder);
$objOrderReturn = new OrderReturn();
$refundReqBookings = $objOrderReturn->getOrderRefundRequestedBookings($order->id, 0, 1);
@@ -291,8 +280,6 @@ class GuestTrackingControllerCore extends FrontController
$cartHotelData[$type_key]['id_product'] = $type_value['product_id'];
$cartHotelData[$type_key]['cover_img'] = $cover_img;
$objBookingDemand = new HotelBookingDemands();
foreach ($order_bk_data as $data_k => $data_v) {
$date_join = strtotime($data_v['date_from']).strtotime($data_v['date_to']);
@@ -366,41 +353,6 @@ class GuestTrackingControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['ids_htl_booking_detail'][] = $data_v['id'];
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to']
);
if (empty($cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'])) {
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = 0;
}
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] += $extraDemandPriceTI = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1
);
if (empty($cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'])) {
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = 0;
}
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] += $extraDemandPriceTE = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0
);
$total_demands_price_ti += $extraDemandPriceTI;
$total_demands_price_te += $extraDemandPriceTE;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_tax_excl'] = $order_details_obj->unit_price_tax_excl;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_tax_incl'] = $order_details_obj->unit_price_tax_incl;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_without_reduction_tax_excl'] = $order_details_obj->unit_price_tax_excl + $order_details_obj->reduction_amount_tax_excl;
@@ -410,7 +362,7 @@ class GuestTrackingControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['feature_price_diff'] = $feature_price_diff;
$cartHotelData[$type_key]['hotel_name'] = $data_v['hotel_name'];
// add additional services products in hotel detail.
// add extra services products in hotel detail.
$cartHotelData[$type_key]['date_diff'][$date_join]['additional_services'] = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
0,
@@ -575,8 +527,6 @@ class GuestTrackingControllerCore extends FrontController
// set order specific values
$order->total_convenience_fee_ti = $total_convenience_fee_ti;
$order->total_convenience_fee_te = $total_convenience_fee_te;
$order->total_demands_price_ti = $total_demands_price_ti;
$order->total_demands_price_te = $total_demands_price_te;
$order->any_back_order = $anyBackOrder;
$order->shw_bo_msg = Configuration::get('WK_SHOW_MSG_ON_BO');
$order->back_ord_msg = Configuration::get('WK_BO_MESSAGE');
@@ -606,6 +556,7 @@ class GuestTrackingControllerCore extends FrontController
'use_tax' => Configuration::get('PS_TAX'),
'guestInformations' => (array)$customer,
'view_on_map' => Configuration::get('WK_GOOGLE_ACTIVE_MAP'),
'total_tourism_tax' => isset($total_tourism_tax) ? $total_tourism_tax : 0,
));
}

View File

@@ -63,6 +63,10 @@ class IdentityControllerCore extends FrontController
}
}
if (Configuration::get('PS_CUSTOMER_NATIONALITY') && Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY') && !Tools::getValue('id_nationality')) {
$this->errors[] = Tools::displayError('Nationality is required.');
}
if (Tools::getIsset('old_passwd')) {
$old_passwd = trim(Tools::getValue('old_passwd'));
}
@@ -91,6 +95,7 @@ class IdentityControllerCore extends FrontController
if (!count($this->errors)) {
$this->customer->phone = $phone;
$this->customer->id_country = (int)Tools::getValue('id_nationality');
$this->customer->id_default_group = (int)$prev_id_default_group;
$this->customer->firstname = Tools::ucwords($this->customer->firstname);
@@ -127,6 +132,7 @@ class IdentityControllerCore extends FrontController
} else {
$_POST = array_map('stripslashes', $this->customer->getFields());
$_POST['phone'] = $this->customer->phone;
$_POST['id_nationality'] = $this->customer->id_country;
}
return $this->customer;
@@ -167,6 +173,9 @@ class IdentityControllerCore extends FrontController
$newsletter = Configuration::get('PS_CUSTOMER_NWSL') || (Module::isInstalled('blocknewsletter') && Module::getInstanceByName('blocknewsletter')->active);
$this->context->smarty->assign('birthday', (bool) Configuration::get('PS_CUSTOMER_BIRTHDATE'));
$this->context->smarty->assign('nationality', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY'));
$this->context->smarty->assign('nationality_mandatory', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY'));
$this->context->smarty->assign('nationality_countries', Customer::getNationalities($this->context->language->id));
$this->context->smarty->assign('newsletter', $newsletter);
$this->context->smarty->assign('optin', (bool)Configuration::get('PS_CUSTOMER_OPTIN'));

View File

@@ -114,8 +114,6 @@ class OrderConfirmationControllerCore extends FrontController
$any_back_order = 0;
$processed_product = array();
$orderTotalInfo = array();
$orderTotalInfo['total_demands_price_te'] = 0;
$orderTotalInfo['total_demands_price_ti'] = 0;
$orderTotalInfo['total_products_te'] = 0;
$orderTotalInfo['total_products_ti'] = 0;
$orderTotalInfo['total_rooms_te'] = 0;
@@ -135,6 +133,7 @@ class OrderConfirmationControllerCore extends FrontController
$orderTotalInfo['total_paid_real'] = 0;
$orderTotalInfo['total_wrapping'] = 0;
$orderTotalInfo['total_order_amount'] = 0;
$orderTotalInfo['total_tourism_tax'] = 0.0;
$orders_has_invoice = 1;
if ($cartOrders = Order::getAllOrdersByCartId($order->id_cart)) {
@@ -144,7 +143,6 @@ class OrderConfirmationControllerCore extends FrontController
$obj_rm_type = new HotelRoomType();
$orderTotalInfo['total_order_amount'] = 0;
$hotelCartBookingData = new HotelCartBookingData();
$objBookingDemand = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$cart_standalone_service_products = array();
$cart_hotel_service_products = array();
@@ -154,6 +152,7 @@ class OrderConfirmationControllerCore extends FrontController
$idOrder = $cartOrder['id_order'];
$objCartOrder = new Order($idOrder);
$orderProducts = $objCartOrder->getProducts();
$roomTourismTaxByBooking = OrderTaxDetail::getAppliedTourismTaxTotals($idOrder, OrderTaxDetail::SCOPE_ROOM);
if (!empty($orderProducts)) {
foreach ($orderProducts as $type_key => $type_value) {
@@ -189,6 +188,7 @@ class OrderConfirmationControllerCore extends FrontController
$order_details_obj = new OrderDetail($data_v['id_order_detail']);
$cart_htl_data[$type_key]['name'] = $order_details_obj->product_name;
$stage_name = '';
$roomTotalPriceTaxIncl = (float) $data_v['total_price_tax_incl'];
if (isset($cart_htl_data[$type_key]['date_diff'][$date_join])) {
$cart_htl_data[$type_key]['date_diff'][$date_join]['num_rm'] += 1;
@@ -200,8 +200,8 @@ class OrderConfirmationControllerCore extends FrontController
//// By webkul New way to calculate product prices with feature Prices
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] = $data_v['total_price_tax_excl']/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $data_v['total_price_tax_incl']/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] += $data_v['total_price_tax_incl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $roomTotalPriceTaxIncl/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] += $roomTotalPriceTaxIncl;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_excl'] += $data_v['total_price_tax_excl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['is_backorder'] = $data_v['is_back_order'];
if ($data_v['is_back_order']) {
@@ -223,8 +223,8 @@ class OrderConfirmationControllerCore extends FrontController
// By webkul New way to calculate product prices with feature Prices
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] = $data_v['total_price_tax_excl']/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $data_v['total_price_tax_incl']/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = $data_v['total_price_tax_incl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $roomTotalPriceTaxIncl/$num_days;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = $roomTotalPriceTaxIncl;
$cart_htl_data[$type_key]['date_diff'][$date_join]['amount_tax_excl'] = $data_v['total_price_tax_excl'];
if ($data_v['is_back_order']) {
$any_back_order = 1;
@@ -235,43 +235,6 @@ class OrderConfirmationControllerCore extends FrontController
}
// $orderTotalInfo['total_rooms_te'] += $data_v['total_price_tax_excl'];
// $orderTotalInfo['total_rooms_ti'] += $data_v['total_price_tax_incl'];
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to']
);
if (empty($cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'])) {
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = 0;
}
$extraDemandPriceTI = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] += $extraDemandPriceTI;
if (empty($cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'])) {
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = 0;
}
$extraDemandPriceTE = $objBookingDemand->getRoomTypeBookingExtraDemands(
$idOrder,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0
);
$cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] += $extraDemandPriceTE;
$orderTotalInfo['total_demands_price_ti'] += $extraDemandPriceTI;
$orderTotalInfo['total_demands_price_te'] += $extraDemandPriceTE;
$cart_htl_data[$type_key]['date_diff'][$date_join]['product_price_tax_excl'] = $order_details_obj->unit_price_tax_excl;
$cart_htl_data[$type_key]['date_diff'][$date_join]['product_price_tax_incl'] = $order_details_obj->unit_price_tax_incl;
$cart_htl_data[$type_key]['date_diff'][$date_join]['product_price_without_reduction_tax_excl'] = $order_details_obj->unit_price_tax_excl + $order_details_obj->reduction_amount_tax_excl;
@@ -283,7 +246,7 @@ class OrderConfirmationControllerCore extends FrontController
//enter hotel name
$cart_htl_data[$type_key]['hotel_name'] = $data_v['hotel_name'];
// add additional services products in hotel detail.
// add extra services products in hotel detail.
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services'] = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
0,
@@ -299,7 +262,7 @@ class OrderConfirmationControllerCore extends FrontController
if (empty($cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'])) {
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'] = 0;
}
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'] += $extraDemandPriceTI = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'] += $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
0,
0,
@@ -314,7 +277,7 @@ class OrderConfirmationControllerCore extends FrontController
if (empty($cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'])) {
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'] = 0;
}
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'] += $extraDemandPriceTE = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'] += $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
0,
0,
@@ -432,13 +395,18 @@ class OrderConfirmationControllerCore extends FrontController
$orderTotalInfo['total_tax'] += $objCartOrder->total_paid_tax_incl - $objCartOrder->total_paid_tax_excl;
$orderTotalInfo['total_paid'] += $objCartOrder->total_paid;
$orderTotalInfo['total_paid_real'] += $objCartOrder->total_paid_real;
$orderTotalInfo['total_tourism_tax'] += OrderTaxDetail::getOrderTourismTaxTotal($idOrder);
}
$totalTaxIncl = $orderTotalInfo['total_rooms_ti'] + $orderTotalInfo['total_services_ti'] + $orderTotalInfo['total_convenience_fee_ti'] + $orderTotalInfo['total_auto_add_services_ti'] + $orderTotalInfo['total_demands_price_ti'] + $orderTotalInfo['total_standalone_products_ti'];
$totalTaxIncl = $orderTotalInfo['total_rooms_ti'] + $orderTotalInfo['total_services_ti'] + $orderTotalInfo['total_convenience_fee_ti'] + $orderTotalInfo['total_auto_add_services_ti'] + $orderTotalInfo['total_standalone_products_ti'];
$totalTaxExcl = $orderTotalInfo['total_rooms_te'] + $orderTotalInfo['total_services_te'] + $orderTotalInfo['total_convenience_fee_te'] + $orderTotalInfo['total_auto_add_services_te'] + $orderTotalInfo['total_demands_price_te'] + $orderTotalInfo['total_standalone_products_te'];
$totalTaxExcl = $orderTotalInfo['total_rooms_te'] + $orderTotalInfo['total_services_te'] + $orderTotalInfo['total_convenience_fee_te'] + $orderTotalInfo['total_auto_add_services_te'] + $orderTotalInfo['total_standalone_products_te'];
$orderTotalInfo['total_tax_without_discount'] = $totalTaxIncl - $totalTaxExcl;
$orderTotalInfo['total_tax_without_discount'] = ($totalTaxIncl - $totalTaxExcl) - $orderTotalInfo['total_tourism_tax'];
if ($orderTotalInfo['total_tax_without_discount'] < 0) {
$orderTotalInfo['total_tax_without_discount'] = 0;
}
}
$this->context->smarty->assign('orderTotalInfo', $orderTotalInfo);

View File

@@ -87,8 +87,8 @@ class OrderDetailControllerCore extends FrontController
//To show order details properly on order history page
$objBookingDetail = new HotelBookingDetail();
$objRoomType = new HotelRoomType();
$objBookingDemand = new HotelBookingDemands();
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
$roomTourismTaxByBooking = OrderTaxDetail::getAppliedTourismTaxTotals($order->id, OrderTaxDetail::SCOPE_ROOM);
$anyBackOrder = 0;
$processedProducts = array();
$cartHotelData = array();
@@ -96,8 +96,6 @@ class OrderDetailControllerCore extends FrontController
$hotelServiceProducts = array();
$standaloneServiceProducts = array();
$serviceProductsFormatted = array();
$total_demands_price_te = 0;
$total_demands_price_ti = 0;
$total_convenience_fee_te = 0;
$total_convenience_fee_ti = 0;
$roomTypes = array();
@@ -132,8 +130,6 @@ class OrderDetailControllerCore extends FrontController
$cartHotelData[$type_key]['id_product'] = $type_value['product_id'];
$cartHotelData[$type_key]['cover_img'] = $type_value['cover_img'];
$objBookingDemand = new HotelBookingDemands();
foreach ($order_bk_data as $data_k => $data_v) {
$date_join = strtotime($data_v['date_from']).strtotime($data_v['date_to']);
@@ -150,6 +146,8 @@ class OrderDetailControllerCore extends FrontController
$bookingRefundDetail = reset($bookingRefundDetail);
}
$roomTotalPriceTaxIncl = (float) $data_v['total_price_tax_incl'];
if (isset($cartHotelData[$type_key]['date_diff'][$date_join])) {
$cartHotelData[$type_key]['date_diff'][$date_join]['num_rm'] += 1;
@@ -160,10 +158,10 @@ class OrderDetailControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['children'] += $data_v['children'];
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] = $data_v['total_price_tax_excl']/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $data_v['total_price_tax_incl']/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $roomTotalPriceTaxIncl/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['avg_paid_unit_price_tax_excl'] += $cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['avg_paid_unit_price_tax_incl'] += $cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_incl'] += $data_v['total_price_tax_incl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_incl'] += $roomTotalPriceTaxIncl;
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_excl'] += $data_v['total_price_tax_excl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['is_backorder'] = $data_v['is_back_order'];
if ($data_v['is_back_order']) {
@@ -187,10 +185,10 @@ class OrderDetailControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['children'] = $data_v['children'];
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'] = $data_v['total_price_tax_excl']/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $data_v['total_price_tax_incl']/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] = $roomTotalPriceTaxIncl/$num_days;
$cartHotelData[$type_key]['date_diff'][$date_join]['avg_paid_unit_price_tax_excl'] = $cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_excl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['avg_paid_unit_price_tax_incl'] = $cartHotelData[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = $data_v['total_price_tax_incl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_incl'] = $roomTotalPriceTaxIncl;
$cartHotelData[$type_key]['date_diff'][$date_join]['amount_tax_excl'] = $data_v['total_price_tax_excl'];
$cartHotelData[$type_key]['date_diff'][$date_join]['is_backorder'] = $data_v['is_back_order'];
if ($data_v['is_back_order']) {
@@ -227,41 +225,6 @@ class OrderDetailControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['ids_htl_booking_detail'][] = $data_v['id'];
$cartHotelData[$type_key]['date_diff'][$date_join]['ids_rooms'][] = $data_v['id_room'];
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands'] = $objBookingDemand->getRoomTypeBookingExtraDemands(
$id_order,
$type_value['product_id'],
0,
$data_v['date_from'],
$data_v['date_to']
);
if (empty($cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'])) {
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = 0;
}
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] += $extraDemandPriceTI = $objBookingDemand->getRoomTypeBookingExtraDemands(
$id_order,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
1
);
if (empty($cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'])) {
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] = 0;
}
$cartHotelData[$type_key]['date_diff'][$date_join]['extra_demands_price_te'] += $extraDemandPriceTE = $objBookingDemand->getRoomTypeBookingExtraDemands(
$id_order,
$type_value['product_id'],
$data_v['id_room'],
$data_v['date_from'],
$data_v['date_to'],
0,
1,
0
);
$total_demands_price_ti += $extraDemandPriceTI;
$total_demands_price_te += $extraDemandPriceTE;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_tax_excl'] = $order_details_obj->unit_price_tax_excl;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_tax_incl'] = $order_details_obj->unit_price_tax_incl;
$cartHotelData[$type_key]['date_diff'][$date_join]['product_price_without_reduction_tax_excl'] = $order_details_obj->unit_price_tax_excl + $order_details_obj->reduction_amount_tax_excl;
@@ -271,7 +234,7 @@ class OrderDetailControllerCore extends FrontController
$cartHotelData[$type_key]['date_diff'][$date_join]['feature_price_diff'] = $feature_price_diff;
$cartHotelData[$type_key]['hotel_name'] = $data_v['hotel_name'];
// add additional services products in hotel detail.
// add extra services products in hotel detail.
$cartHotelData[$type_key]['date_diff'][$date_join]['additional_services'] = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$id_order,
0,
@@ -422,6 +385,7 @@ class OrderDetailControllerCore extends FrontController
}
}
$totalTourismTax = OrderTaxDetail::getOrderTourismTaxTotal((int) $id_order);
$this->context->smarty->assign(
array(
@@ -429,8 +393,7 @@ class OrderDetailControllerCore extends FrontController
'THEME_DIR' => _THEME_DIR_,
'total_convenience_fee_ti' => $total_convenience_fee_ti,
'total_convenience_fee_te' => $total_convenience_fee_te,
'total_demands_price_ti' => $total_demands_price_ti,
'total_demands_price_te' => $total_demands_price_te,
'total_tourism_tax' => $totalTourismTax,
'any_back_order' => $anyBackOrder,
'shw_bo_msg' => Configuration::get('WK_SHOW_MSG_ON_BO'),
'back_ord_msg' => Configuration::get('WK_BO_MESSAGE'),
@@ -519,9 +482,9 @@ class OrderDetailControllerCore extends FrontController
$this->setTemplate(_PS_THEME_DIR_.'order-detail.tpl');
}
public function displayAjaxGetRoomTypeBookingDemands()
public function displayAjaxgetRoomTypeBookingServices()
{
$response = array('extra_demands' => false);
$response = array('extra_services' => false);
$idOrder = (int) Tools::getValue('id_order');
$order = new Order($idOrder);
@@ -538,26 +501,11 @@ class OrderDetailControllerCore extends FrontController
&& ($dateFrom = Tools::getValue('date_from'))
&& ($dateTo = Tools::getValue('date_to'))
) {
$objHotelBookingDemands = new HotelBookingDemands();
$useTax = 0;
if (Group::getPriceDisplayMethod($this->context->customer->id_default_group) == PS_TAX_INC) {
$useTax = 1;
}
if ($extraDemands = $objHotelBookingDemands->getRoomTypeBookingExtraDemands(
$idOrder,
$idProduct,
0,
$dateFrom,
$dateTo,
1,
0,
$useTax
)) {
$this->context->smarty->assign(array(
'useTax' => $useTax,
'extraDemands' => $extraDemands,
));
}
$objServiceProductOrderDetail = new ServiceProductOrderDetail();
if ($additionalServices = $objServiceProductOrderDetail->getRoomTypeServiceProducts(
$idOrder,
@@ -581,7 +529,7 @@ class OrderDetailControllerCore extends FrontController
'objOrder' => $order,
));
$response['extra_demands'] = $this->context->smarty->fetch(_PS_THEME_DIR_.'_partials/order-extra-services.tpl');
$response['extra_services'] = $this->context->smarty->fetch(_PS_THEME_DIR_.'_partials/order-extra-services.tpl');
}
$this->ajaxDie(json_encode($response));

View File

@@ -126,6 +126,7 @@ class OrderOpcControllerCore extends ParentOrderController
}
$this->context->customer->phone = $phone;
$this->context->customer->id_country = (int)Tools::getValue('id_nationality');
$_POST['lastname'] = $_POST['customer_lastname'];
$_POST['firstname'] = $_POST['customer_firstname'];
$this->errors = array_merge($this->errors, $this->context->customer->validateController());
@@ -376,14 +377,10 @@ class OrderOpcControllerCore extends ParentOrderController
$this->context->cart->setNoMultishipping();
$this->ajaxDie();
break;
case 'getRoomTypeBookingDemands':
case 'getRoomTypeBookingServices':
$this->ajaxDie($this->getRoomTypeBookingServices());
exit;
break;
case 'changeRoomDemands':
$this->ajaxDie($this->changeRoomDemands());
exit;
break;
case 'getCustomerGuestDetail':
$this->ajaxDie($this->getCustomerGuestDetail());
exit;
@@ -495,15 +492,9 @@ class OrderOpcControllerCore extends ParentOrderController
$this->context->smarty->assign('checkout_process_steps', $this->checkoutProcess->getSteps());
// set room type demands
// $objGlobalDemand = new HotelRoomTypeGlobalDemand();
// $allDemands = $objGlobalDemand->getAllDemands();
// $objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT'));
$this->_assignCheckoutVars();
$this->context->smarty->assign(
array(
// 'allDemands' => $allDemands,
// 'defaultcurrencySign' => $objCurrency->sign,
'PS_REGISTRATION_PROCESS_TYPE' => Configuration::get('PS_REGISTRATION_PROCESS_TYPE'),
'free_shipping' => $free_shipping,
'isGuest' => isset($this->context->cookie->is_guest) ? $this->context->cookie->is_guest : 0,
@@ -559,6 +550,9 @@ class OrderOpcControllerCore extends ParentOrderController
$newsletter = Module::isInstalled('blocknewsletter') && Module::getInstanceByName('blocknewsletter')->active && Configuration::get('PS_CUSTOMER_NWSL');
$this->context->smarty->assign('birthday', (bool) Configuration::get('PS_CUSTOMER_BIRTHDATE'));
$this->context->smarty->assign('nationality', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY'));
$this->context->smarty->assign('nationality_mandatory', (bool) Configuration::get('PS_CUSTOMER_NATIONALITY_MANDATORY'));
$this->context->smarty->assign('nationality_countries', Customer::getNationalities($this->context->language->id));
$this->context->smarty->assign('newsletter', $newsletter);
$this->context->smarty->assign('optin', (bool)Configuration::get('PS_CUSTOMER_OPTIN'));
$this->context->smarty->assign('field_required', $this->context->customer->validateFieldsRequiredDatabase());
@@ -645,6 +639,7 @@ class OrderOpcControllerCore extends ParentOrderController
'id_country' => (int)$address_delivery->id_country,
'id_state' => (int)$address_delivery->id_state,
'id_gender' => (int)$customer->id_gender,
'id_nationality' => (int)$customer->id_country,
'phone' => $customer->phone,
'sl_year' => $birthday[0],
'sl_month' => $birthday[1],
@@ -950,41 +945,18 @@ class OrderOpcControllerCore extends ParentOrderController
&& ($dateTo = Tools::getValue('date_to'))
) {
$objCartBookingData = new HotelCartBookingData();
if ($selectedRoomDemands = $objCartBookingData->getCartExtraDemands(
$this->context->cart->id,
$idProduct,
0,
$dateFrom,
$dateTo
)) {
// get room type additional demands
$objRoomDemands = new HotelRoomTypeDemand();
if ($roomTypeDemands = $objRoomDemands->getRoomTypeDemands($idProduct)) {
foreach ($roomTypeDemands as &$demand) {
// if demand has advance options then set demand price as first advance option price.
if (isset($demand['adv_option']) && $demand['adv_option']) {
$demand['price'] = current($demand['adv_option'])['price'];
}
}
foreach ($selectedRoomDemands as &$selectedDemand) {
if (isset($selectedDemand['extra_demands']) && $selectedDemand['extra_demands']) {
$extraDmd = array();
foreach ($selectedDemand['extra_demands'] as $sDemand) {
$selectedDemand['selected_global_demands'][] = $sDemand['id_global_demand'];
$extraDmd[$sDemand['id_global_demand'].'-'.$sDemand['id_option']] = $sDemand;
}
$selectedDemand['extra_demands'] = $extraDmd;
}
}
$this->context->smarty->assign('roomTypeDemands', $roomTypeDemands);
$this->context->smarty->assign('selectedRoomDemands', $selectedRoomDemands);
}
}
$objServiceProductCartDetail = new ServiceProductCartDetail();
$objRoomTypeServiceProduct = new RoomTypeServiceProduct();
$roomTypeServiceProducts = $objRoomTypeServiceProduct->getServiceProductsData($idProduct, 1, 0, true, 1);
$cartBookings = $objCartBookingData->getHotelCartRoomsInfoByRoomType($this->context->cart->id, $idProduct,$dateFrom, $dateTo);
$availableServicePricing = $objRoomTypeServiceProduct->getServiceProductsPricingForCartBookings(
$roomTypeServiceProducts,
$cartBookings,
$idProduct,
$dateFrom,
$dateTo
);
foreach($cartBookings as &$cartBookingData) {
$cartBookingData['selected_service'] = $objServiceProductCartDetail->getServiceProductsInCart(
$cartBookingData['id_cart'],
@@ -1000,36 +972,35 @@ class OrderOpcControllerCore extends ParentOrderController
null,
1
);
foreach ($cartBookingData['selected_service'] as &$selectedService) {
if ($selectedService['tourism_tax'] > 0 && TaxConfiguration::isGrossedUp($selectedService['tourism_tax'])) {
$selectedService['total_price_tax_incl'] += $selectedService['tourism_tax'];
$quantity = $selectedService['quantity'] ?: 1;
$impliedNumDays = $selectedService['unit_price_tax_excl'] > 0 ? $selectedService['total_price_tax_excl'] / ($selectedService['unit_price_tax_excl'] * $quantity) : 1;
$unitDivisor = $impliedNumDays * $quantity;
$selectedService['unit_price_tax_incl'] += $unitDivisor > 0 ? ($selectedService['tourism_tax'] / $unitDivisor) : 0;
}
}
unset($selectedService);
$cartBookingData['available_service_pricing'] = isset($availableServicePricing[$cartBookingData['id']])
? $availableServicePricing[$cartBookingData['id']]
: array();
}
unset($cartBookingData);
$this->context->smarty->assign(array(
'roomTypeServiceProducts' => $roomTypeServiceProducts,
'cartRooms' => $cartBookings
));
}
}
$response['extra_demands'] = $this->context->smarty->fetch(
_PS_THEME_DIR_.'_partials/cart_booking_demands.tpl'
$response['extra_services'] = $this->context->smarty->fetch(
_PS_THEME_DIR_.'_partials/cart_booking_services.tpl'
);
return json_encode($response);
}
public function changeRoomDemands()
{
if ($idCartBooking = Tools::getValue('id_cart_booking')) {
if (Validate::isLoadedObject($objCartbookingCata = new HotelCartBookingData($idCartBooking))) {
$roomDemands = Tools::getValue('room_demands');
$roomDemands = json_decode($roomDemands, true);
$roomDemands = json_encode($roomDemands);
$objCartbookingCata->extra_demands = $roomDemands;
if ($objCartbookingCata->save()) {
die('1');
}
}
}
die('0');
}
public function getCustomerGuestDetail()
{
$response = array('status' => false);

View File

@@ -49,7 +49,7 @@ class OurPropertiesControllerCore extends FrontController
&& $hotel['id_cover_img']
&& Validate::isLoadedObject($objHotelImage = new HotelImage($hotel['id_cover_img']))
) {
$htlImgLink = $this->context->link->getMediaLink($objHotelImage->getImageLink($hotel['id_cover_img'], ImageType::getFormatedName('medium')));
$htlImgLink = $this->context->link->getMediaLink($objHotelImage->getImageLink($hotel['id_cover_img'], ImageType::getFormatedName('large')));
if ((bool)Tools::file_get_contents($htlImgLink)) {
$hotelsInfo[$hotelKey]['image_url'] = $htlImgLink;
} else {
@@ -128,7 +128,6 @@ class OurPropertiesControllerCore extends FrontController
array(
'hotelsInfo' => $hotelsInfo,
'hotelLocationArray' => $hotelLocationArray,
'viewOnMap' => Configuration::get('WK_GOOGLE_ACTIVE_MAP'),
'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

@@ -345,6 +345,14 @@ class ParentOrderControllerCore extends FrontController
[Product::SELLING_PREFERENCE_STANDALONE]
);
foreach ($standaloneProducts as &$standaloneProduct) {
if (TaxConfiguration::isGrossedUp($standaloneProduct['tourism_tax_amount'])) {
$standaloneProduct['unit_price_tax_incl'] += $standaloneProduct['tourism_tax_amount'] / max(1, (int) $standaloneProduct['quantity']);
$standaloneProduct['total_price_tax_incl'] += $standaloneProduct['tourism_tax_amount'];
}
}
unset($standaloneProduct);
if (count($standaloneProducts)) {
$this->context->smarty->assign('standalone_products', $standaloneProducts);
}

View File

@@ -49,6 +49,7 @@ class ProductControllerCore extends FrontController
$this->addJS(array(
_THEME_JS_DIR_.'tools.js', // retro compat themes 1.5
_THEME_JS_DIR_.'product.js',
_THEME_JS_DIR_.'room-type-service-products.js',
));
} else {
$this->addJqueryPlugin(array('scrollTo', 'serialScroll'));
@@ -402,17 +403,6 @@ class ProductControllerCore extends FrontController
);
}
// get room type additional demands
$objRoomDemands = new HotelRoomTypeDemand();
if ($roomTypeDemands = $objRoomDemands->getRoomTypeDemands($this->product->id)) {
foreach ($roomTypeDemands as &$demand) {
// if demand has advance options then set demand price as first advance option price.
if (isset($demand['adv_option']) && $demand['adv_option']) {
$demand['price'] = current($demand['adv_option'])['price'];
}
}
}
$roomFeatures = $this->product->getFrontFeatures($this->context->language->id);
$roomAmenities = HotelRoomTypeAmenities::getAmenities($this->product->id, $this->context->language->id);
$hotelAmenities = HotelBranchAmenities::getAmenities($hotel_id, $this->context->language->id);
@@ -420,7 +410,6 @@ class ProductControllerCore extends FrontController
$this->context->smarty->assign(
array(
'id_hotel' => $hotel_id,
'room_type_demands' => $roomTypeDemands,
'room_type_info' => $room_info_by_product_id,
'isHotelRefundable' => $hotel_branch_obj->isRefundable(),
'max_order_date' => $max_order_date,
@@ -478,7 +467,6 @@ class ProductControllerCore extends FrontController
);
}
}
$this->assignBookingFormVars($this->product->id, $date_from, $date_to, $occupancy_value);
$this->assignRoomServiceProductVars();
@@ -491,6 +479,36 @@ class ProductControllerCore extends FrontController
$feature_price = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay($this->product->id, $date_from, $date_to, false, 0, 0, 0, 0, 1, 1, $occupancy_value);
}
$productPriceWithoutReduction = $this->product->getPriceWithoutReduct(!$useTax);
if ($useTax && (bool) Configuration::get('QLO_TOURISM_TAX_GROSSED_UP')) {
$totalExclTourismTax = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$this->product->id,
$date_from,
$date_to,
$occupancy_value,
0,
0,
0,
0,
1,
0
);
$totalInclTourismTax = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$this->product->id,
$date_from,
$date_to,
$occupancy_value,
0,
0,
0,
0,
1,
0,
true
);
$tourismTaxTotal = $totalInclTourismTax['total_price_tax_incl'] - $totalExclTourismTax['total_price_tax_incl'];
$numDaysInDuration = HotelHelper::getNumberOfDays($date_from, $date_to);
$productPriceWithoutReduction += $tourismTaxTotal / $numDaysInDuration;
}
$feature_price_diff = (float)($productPriceWithoutReduction - $feature_price);
$this->context->smarty->assign('feature_price', $feature_price);
$this->context->smarty->assign('feature_price_diff', $feature_price_diff);
@@ -531,7 +549,6 @@ class ProductControllerCore extends FrontController
array(
'product_controller_url' => $this->context->link->getPageLink('product'),
'ratting_img_path' => _MODULE_DIR_.'hotelreservationsystem/views/img/Slices/icons-sprite.png',
'WK_PRICE_CALC_METHOD_EACH_DAY' => HotelRoomTypeGlobalDemand::WK_PRICE_CALC_METHOD_EACH_DAY,
'stock_management' => Configuration::get('PS_STOCK_MANAGEMENT'),
'customizationFields' => $customization_fields,
'id_customization' => empty($customization_datas) ? null : $customization_datas[0]['id_customization'],
@@ -624,7 +641,6 @@ class ProductControllerCore extends FrontController
$dateFrom,
$dateTo,
$occupancy = array(),
$jsonDemands = '',
$roomServiceProducts = null
) {
$objProduct = new Product($idProduct, true, $this->context->language->id, $this->context->shop->id);
@@ -637,8 +653,6 @@ class ProductControllerCore extends FrontController
$objHotel = new HotelBranchInformation();
$objHotelCartBookingData = new HotelCartBookingData();
$objBookingDetail = new HotelBookingDetail();
$objHRTDemand = new HotelRoomTypeDemand();
$objHRTDemandPrice = new HotelRoomTypeDemandPrice();
$idCart = (int) $this->context->cart->id;
$idGuest = (int) $this->context->cart->id_guest;
@@ -726,6 +740,7 @@ class ProductControllerCore extends FrontController
// calculate room type price first
$useTax = HotelBookingDetail::useTax();
$totalPrice = 0;
$includeTourismTax = $useTax && Configuration::get('QLO_TOURISM_TAX_GROSSED_UP');
$priceWithoutDiscount = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$idProduct,
$dateFrom,
@@ -736,13 +751,21 @@ class ProductControllerCore extends FrontController
0,
0,
1,
0
0,
$includeTourismTax
);
$roomTypeDateRangePrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice(
$idProduct,
$dateFrom,
$dateTo,
$occupancy
$occupancy,
0,
0,
0,
0,
1,
1,
$includeTourismTax
);
$featurePrice = 0;
@@ -760,9 +783,8 @@ class ProductControllerCore extends FrontController
1,
$occupancy
);
$roomTypeDateRangePrice = $roomTypeDateRangePrice['total_price_tax_incl'];
$totalPriceWithoutDiscount = $priceWithoutDiscount['total_price_tax_incl'];
$roomTypeDateRangePrice = $roomTypeDateRangePrice['total_price_tax_incl'];
} else {
$featurePrice = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay(
$idProduct,
@@ -782,57 +804,18 @@ class ProductControllerCore extends FrontController
}
$totalRoomPrice = $roomTypeDateRangePrice;
// calculate demand price now
$demandsPricePerRoom = 0;
$roomTypeDemands = $objHRTDemand->getRoomTypeDemands($idProduct);
if ($jsonDemands !== '') {
$cartDemands = json_decode($jsonDemands, true);
$demandsPricePerRoom = $objHRTDemandPrice->getRoomTypeDemandsTotalPrice(
$idProduct,
$cartDemands,
$useTax,
$dateFrom,
$dateTo
);
// send demand info to booking form
foreach($cartDemands as &$demand) {
if (Validate::isLoadedObject(
$objRoomTypeGlobalDemand = new HotelRoomTypeGlobalDemand($demand['id_global_demand'], $this->context->language->id)
)) {
$demand['name'] = $objRoomTypeGlobalDemand->name;
if ($demand['id_option']) {
if (Validate::isLoadedObject($objDemandAdvanceOption = new HotelRoomTypeGlobalDemandAdvanceOption($demand['id_option'], $this->context->language->id))) {
if ($objDemandAdvanceOption->id_global_demand != $objRoomTypeGlobalDemand->id) {
unset($demand);
continue;
}
$demand['advance_option'] = array(
'id_option' => $objDemandAdvanceOption->id,
'name' => $objDemandAdvanceOption->name
);
} else {
unset($demand);
continue;
}
}
$demand['price'] = HotelRoomTypeDemand::getPriceStatic(
$idProduct,
$objRoomTypeGlobalDemand->id,
$demand['id_option'],
$useTax
);
}
}
$smartyVars['selected_demands'] = $cartDemands;
}
// calculate service product price now
$serviceProductPricePerRoom = 0;
if ($roomServiceProducts) {
$serviceProductsPrice = 0;
if ($roomServiceProducts = json_decode($roomServiceProducts, true)) {
$objRoomTypeServiceProductPrice = new RoomTypeServiceProductPrice();
$objRoomTypeServiceProduct = new RoomTypeServiceProduct();
$serviceOccupancy = (is_array($occupancy) && isset($occupancy[0])) ? $occupancy[0] : array('adults' => 1, 'child_ages' => array());
$serviceNumAdults = isset($serviceOccupancy['adults']) ? (int) $serviceOccupancy['adults'] : 1;
$serviceChildAges = !empty($serviceOccupancy['child_ages']) ? (array) $serviceOccupancy['child_ages'] : array();
foreach ($roomServiceProducts as &$product) {
if (!$objRoomTypeServiceProduct->isRoomTypeLinkedWithProduct($idProduct, $product['id_product'])) {
unset($product);
@@ -857,20 +840,29 @@ class ProductControllerCore extends FrontController
$useTax,
$product['quantity'],
$dateFrom,
$dateTo
$dateTo,
false,
null,
1,
null,
0,
$useTax && Configuration::get('QLO_TOURISM_TAX_GROSSED_UP'),
$serviceNumAdults,
$serviceChildAges
);
$product['price'] = $productPrice;
$serviceProductsPrice += $productPrice;
}
$smartyVars['selected_service_product'] = $roomServiceProducts;
}
$demandsPricePerRoom += $serviceProductsPrice;
$serviceProductPricePerRoom += $serviceProductsPrice;
$totalPrice += $serviceProductsPrice;
}
// multiply price by number of room required
$demandsPrice = $demandsPricePerRoom * $quantity;
$serviceProductPrice = $serviceProductPricePerRoom * $quantity;
// calculate total price
$totalPrice = $totalRoomPrice + $demandsPrice;
$totalPrice = $totalRoomPrice + $serviceProductPrice;
// send occupancy information searched by the user
if ($occupancy && is_array($occupancy)) {
$smartyVars['occupancies'] = $occupancy;
@@ -893,11 +885,10 @@ class ProductControllerCore extends FrontController
$smartyVars['los_max_days'] = $losMaxDays;
$smartyVars['los_min_failed'] = $losMinFailed;
$smartyVars['los_max_failed'] = $losMaxFailed;
$smartyVars['has_room_type_demands'] = $roomTypeDemands ? true : false; // whether to show price breakup
$smartyVars['rooms_price'] = $totalRoomPrice;
$smartyVars['demands_price_per_room'] = $demandsPricePerRoom;
$smartyVars['total_price_without_discount'] = $totalPriceWithoutDiscount + $demandsPrice;
$smartyVars['demands_price'] = $demandsPrice;
$smartyVars['service_product_price_per_room'] = $serviceProductPricePerRoom;
$smartyVars['total_price_without_discount'] = $totalPriceWithoutDiscount + $serviceProductPrice;
$smartyVars['service_product_price'] = $serviceProductPrice;
$smartyVars['total_price'] = $totalPrice;
$this->context->smarty->assign($smartyVars);
return true;
@@ -924,43 +915,75 @@ class ProductControllerCore extends FrontController
}
}
$smartyVars['associated_hotels'] = $associatedHotels;
if (!$idHotel) {
// no hotel picked yet (e.g. initial page load) — price/tourism tax must match
// the hotel the dropdown defaults to, which is simply its first option
$idHotel = reset($associatedHotels)['id_hotel'];
}
}
}
if ($idHotel) {
$smartyVars['service_id_hotel'] = $idHotel;
}
$useTax = HotelBookingDetail::useTax();
$includeTourismTax = $useTax && Configuration::get('QLO_TOURISM_TAX_GROSSED_UP');
$objServiceProductOption = new ServiceProductOption();
if ($serviceProductOptions = $objServiceProductOption->getProductOptions($this->product->id)) {
foreach ($serviceProductOptions as &$serviceProductOption) {
if ($idProductOption == null) {
$idProductOption = $serviceProductOption['id_product_option'];
}
$serviceProductOption['price'] = RoomTypeServiceProductPrice::getPrice(
$serviceProductOption['price'] = Product::getServiceProductPrice(
$this->product->id,
$idHotel,
$serviceProductOption['id_product_option'],
$idHotel,
false,
$useTax,
1
1,
null,
null,
false,
null,
1,
null,
0,
$includeTourismTax
);
}
}
$smartyVars['product_option'] = $serviceProductOptions;
$smartyVars['service_price'] = RoomTypeServiceProductPrice::getPrice(
$smartyVars['service_price'] = Product::getServiceProductPrice(
$this->product->id,
$idHotel,
$idProductOption,
$useTax,
$quantity
);
$smartyVars['service_price_without_reduction'] = RoomTypeServiceProductPrice::getPrice(
$this->product->id,
$idHotel,
$idProductOption,
false,
$useTax,
$quantity,
false
null,
null,
false,
null,
1,
null,
0,
$includeTourismTax
);
$smartyVars['service_price_without_reduction'] = Product::getServiceProductPrice(
$this->product->id,
$idProductOption,
$idHotel,
false,
$useTax,
$quantity,
null,
null,
false,
null,
false,
null,
0,
$includeTourismTax
);
if ($quantity) {
$smartyVars['quantity'] = $quantity;
@@ -1443,8 +1466,8 @@ class ProductControllerCore extends FrontController
$response = array('status' => false);
$idProduct = (int) Tools::getValue('id_product');
if ($this->product->booking_product) {
$dateFrom = Tools::getValue('room_check_in');
$dateTo = Tools::getValue('room_check_out');
$dateFrom = Tools::getValue('date_from');
$dateTo = Tools::getValue('date_to');
$occupancy = Tools::getValue('occupancy');
if (Configuration::get('PS_FRONT_ROOM_UNIT_SELECTION_TYPE') == HotelBookingDetail::PS_ROOM_UNIT_SELECTION_TYPE_OCCUPANCY) {
if (!Validate::isOccupancy($occupancy)) {
@@ -1453,7 +1476,6 @@ class ProductControllerCore extends FrontController
} else {
$occupancy = Tools::getValue('qty', 1);
}
$roomTypeDemands = Tools::getValue('room_type_demands');
$roomServiceProducts = Tools::getValue('room_service_products');
$dateFrom = date('Y-m-d H:i:s', strtotime($dateFrom));
$dateTo = date('Y-m-d H:i:s', strtotime($dateTo));
@@ -1463,14 +1485,13 @@ class ProductControllerCore extends FrontController
$dateFrom,
$dateTo,
$occupancy,
$roomTypeDemands,
$roomServiceProducts
)) {
}
} else {
$idHotel = Tools::getValue('service_id_hotel');
$idHotel = Tools::getValue('id_hotel');
$id_product_option = Tools::getValue('id_product_option');
$quantity = Tools::getValue('service_product_qty');
$quantity = Tools::getValue('qty');
$this->assignServiceProductVars(
$id_product_option,
$quantity,
@@ -1478,6 +1499,7 @@ class ProductControllerCore extends FrontController
);
}
$this->context->smarty->assign('static_token', Tools::getToken(false));
$html = $this->context->smarty->fetch('_partials/booking-form.tpl');
$response['status'] = true;
$response['html_booking_form'] = $html;

View File

@@ -594,6 +594,7 @@ CREATE TABLE `PREFIX_customer` (
`id_gender` int(10) unsigned NOT NULL,
`id_default_group` int(10) unsigned NOT NULL DEFAULT '1',
`id_lang` int(10) unsigned NULL,
`id_country` int(10) NOT NULL DEFAULT '0',
`id_risk` int(10) unsigned NOT NULL DEFAULT '1',
`company` varchar(64),
`siret` varchar(14),
@@ -1181,6 +1182,7 @@ CREATE TABLE `PREFIX_orders` (
`invoice_date` datetime NOT NULL,
`delivery_date` datetime NOT NULL,
`source` varchar(255) DEFAULT NULL,
`id_source` int(10) unsigned DEFAULT NULL,
`valid` int(1) unsigned NOT NULL DEFAULT '0',
`is_advance_payment` tinyint(1) NOT NULL DEFAULT '0',
`advance_paid_amount` decimal(20,6) NOT NULL DEFAULT '0.00',
@@ -1200,16 +1202,83 @@ CREATE TABLE `PREFIX_orders` (
KEY `id_shop_group` (`id_shop_group`),
KEY (`current_state`),
KEY `id_shop` (`id_shop`),
KEY `id_source` (`id_source`),
INDEX `date_add`(`date_add`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_order_detail_tax` (
`id_order_detail` int(11) NOT NULL,
`id_tax` int(11) NOT NULL,
`unit_amount` DECIMAL(16, 6) NOT NULL DEFAULT '0.00',
`total_amount` DECIMAL(16, 6) NOT NULL DEFAULT '0.00',
KEY (`id_order_detail`),
KEY `id_tax` (`id_tax`)
CREATE TABLE `PREFIX_tax_configuration` (
`id_tax` int(11) unsigned NOT NULL,
`tax_value` decimal(20,6) NOT NULL DEFAULT '0.000000',
`calculation_type` tinyint(1) NOT NULL DEFAULT '0',
`per_night` tinyint(1) NOT NULL DEFAULT '1',
`per_person` tinyint(1) NOT NULL DEFAULT '0',
`has_tiered_pricing` tinyint(1) NOT NULL DEFAULT '0',
`apply_on_child` tinyint(1) NOT NULL DEFAULT '0',
`has_child_age_range` tinyint(1) NOT NULL DEFAULT '0',
`child_calculation_type` tinyint(1) NOT NULL DEFAULT '0',
`has_multiple_valid_ranges` tinyint(1) NOT NULL DEFAULT '0',
`special_days` text,
PRIMARY KEY (`id_tax`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_tax_price_tier` (
`id_tax_price_tier` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_tax` int(11) unsigned NOT NULL,
`min_amount` decimal(20,6) NOT NULL DEFAULT '0.000000',
`max_amount` decimal(20,6) NOT NULL DEFAULT '0.000000',
`tax_value` decimal(20,6) NOT NULL DEFAULT '0.000000',
PRIMARY KEY (`id_tax_price_tier`),
KEY `id_tax` (`id_tax`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_tax_child_range` (
`id_tax_child_range` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_tax` int(11) unsigned NOT NULL,
`min_age` tinyint(3) unsigned NOT NULL DEFAULT '0',
`max_age` tinyint(3) unsigned NOT NULL DEFAULT '17',
`tax_value` decimal(20,6) NOT NULL DEFAULT '0.000000',
PRIMARY KEY (`id_tax_child_range`),
KEY `id_tax` (`id_tax`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_tax_validity_range` (
`id_tax_validity_range` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_tax` int(11) unsigned NOT NULL,
`valid_from` date DEFAULT NULL,
`valid_to` date DEFAULT NULL,
PRIMARY KEY (`id_tax_validity_range`),
KEY `id_tax` (`id_tax`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_order_tax_detail` (
`id_order_tax_detail` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_order` int(11) unsigned NOT NULL,
`id_order_detail` int(11) unsigned NOT NULL,
`id_htl_booking` int(11) unsigned NOT NULL,
`id_service_product_order_detail` int(11) unsigned NOT NULL DEFAULT '0',
`id_tax` int(11) unsigned NOT NULL,
`unit_amount` decimal(20,6) NOT NULL DEFAULT '0.000000',
`total_amount` decimal(20,6) NOT NULL DEFAULT '0.000000',
`date_add` datetime NOT NULL,
PRIMARY KEY (`id_order_tax_detail`),
KEY `id_order` (`id_order`),
KEY `id_order_detail` (`id_order_detail`),
KEY `id_htl_booking` (`id_htl_booking`),
KEY `id_service_product_order_detail` (`id_service_product_order_detail`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_order_tax_exemption` (
`id_order_tax_exemption` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_htl_booking` int(11) unsigned NOT NULL DEFAULT '0',
`id_service_product_order_detail` int(11) unsigned NOT NULL DEFAULT '0',
`id_order` int(11) unsigned NOT NULL,
`id_employee` int(11) unsigned NOT NULL,
`note` text,
`date_add` datetime NOT NULL,
PRIMARY KEY (`id_order_tax_exemption`),
KEY `id_htl_booking` (`id_htl_booking`),
KEY `id_service_product_order_detail` (`id_service_product_order_detail`),
KEY `id_order` (`id_order`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_order_invoice` (
@@ -1279,6 +1348,7 @@ CREATE TABLE `PREFIX_order_detail` (
`product_supplier_reference` varchar(32) DEFAULT NULL,
`product_weight` DECIMAL(20,6) NOT NULL,
`id_tax_rules_group` INT(11) UNSIGNED DEFAULT '0',
`id_tourism_tax_rule_group` INT(11) UNSIGNED DEFAULT '0',
`tax_computation_method` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tax_name` varchar(16) NOT NULL,
`tax_rate` DECIMAL(10,3) NOT NULL DEFAULT '0.000',
@@ -1535,6 +1605,7 @@ CREATE TABLE `PREFIX_product` (
`id_category_default` int(10) unsigned DEFAULT NULL,
`id_shop_default` int(10) unsigned NOT NULL DEFAULT 1,
`id_tax_rules_group` INT(11) UNSIGNED NOT NULL,
`id_tourism_tax_rules_group` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`on_sale` tinyint(1) unsigned NOT NULL DEFAULT '0',
`online_only` tinyint(1) unsigned NOT NULL DEFAULT '0',
`ean13` varchar(13) DEFAULT NULL,
@@ -1598,6 +1669,7 @@ CREATE TABLE IF NOT EXISTS `PREFIX_product_shop` (
`id_shop` int(10) unsigned NOT NULL,
`id_category_default` int(10) unsigned DEFAULT NULL,
`id_tax_rules_group` INT(11) UNSIGNED NOT NULL,
`id_tourism_tax_rules_group` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`on_sale` tinyint(1) unsigned NOT NULL DEFAULT '0',
`online_only` tinyint(1) unsigned NOT NULL DEFAULT '0',
`ecotax` decimal(17,6) NOT NULL DEFAULT '0.000000',
@@ -1887,6 +1959,48 @@ CREATE TABLE `PREFIX_search_word` (
UNIQUE KEY `id_lang` (`id_lang`,`id_shop`, `word`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_business_source` (
`id_business_source` int(10) unsigned NOT NULL auto_increment,
`code` varchar(64) NOT NULL,
`position` int(10) unsigned NOT NULL DEFAULT '0',
`unremovable` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
`deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`date_add` datetime NOT NULL,
`date_upd` datetime NOT NULL,
PRIMARY KEY (`id_business_source`),
UNIQUE KEY `code` (`code`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_business_source_lang` (
`id_business_source` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id_business_source`,`id_lang`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_source` (
`id_source` int(10) unsigned NOT NULL auto_increment,
`id_business_source` int(10) unsigned NOT NULL,
`code` varchar(64) NOT NULL,
`position` int(10) unsigned NOT NULL DEFAULT '0',
`unremovable` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
`deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`date_add` datetime NOT NULL,
`date_upd` datetime NOT NULL,
PRIMARY KEY (`id_source`),
UNIQUE KEY `code` (`code`),
KEY `id_business_source` (`id_business_source`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_source_lang` (
`id_source` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id_source`,`id_lang`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
CREATE TABLE `PREFIX_specific_price` (
`id_specific_price` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_specific_price_rule` INT(11) UNSIGNED NOT NULL,
@@ -1996,6 +2110,7 @@ CREATE TABLE `PREFIX_tag_count` (
CREATE TABLE `PREFIX_tax` (
`id_tax` int(10) unsigned NOT NULL auto_increment,
`rate` DECIMAL(10, 3) NOT NULL,
`is_tourism_tax` TINYINT(1) NOT NULL DEFAULT '0',
`active` tinyint(1) unsigned NOT NULL DEFAULT '1',
`deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_tax`)
@@ -2121,6 +2236,7 @@ CREATE TABLE `PREFIX_tax_rules_group` (
`id_tax_rules_group` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR( 50 ) NOT NULL,
`active` INT NOT NULL,
`is_tourism_tax_rule_group` TINYINT(1) NOT NULL DEFAULT '0',
`deleted` TINYINT(1) UNSIGNED NOT NULL,
`date_add` DATETIME NOT NULL,
`date_upd` DATETIME NOT NULL

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity_business_source>
<fields id="name" class="BusinessSource">
<field name="code"/>
<field name="position"/>
<field name="unremovable"/>
<field name="active"/>
</fields>
<entities>
<business_source id="Direct" code="DIRECT" position="0" unremovable="1" active="1">
</business_source>
<business_source id="OTA" code="OTA" position="1" unremovable="1" active="1">
</business_source>
<business_source id="Corporate" code="CORPORATE" position="2" unremovable="1" active="1">
</business_source>
<business_source id="Travel_Agent" code="TRAVEL_AGENT" position="3" unremovable="1" active="1">
</business_source>
<business_source id="Group" code="GROUP" position="4" unremovable="1" active="1">
</business_source>
<business_source id="Api" code="API" position="5" unremovable="1" active="1">
</business_source>
</entities>
</entity_business_source>

View File

@@ -911,6 +911,12 @@
<configuration id="PS_CUSTOMER_BIRTHDATE" name="PS_CUSTOMER_BIRTHDATE">
<value>1</value>
</configuration>
<configuration id="PS_CUSTOMER_NATIONALITY" name="PS_CUSTOMER_NATIONALITY">
<value>0</value>
</configuration>
<configuration id="PS_CUSTOMER_NATIONALITY_MANDATORY" name="PS_CUSTOMER_NATIONALITY_MANDATORY">
<value>0</value>
</configuration>
<configuration id="PS_CUSTOMER_NWSL" name="PS_CUSTOMER_NWSL">
<value>1</value>
</configuration>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity_source>
<fields id="name" class="Source">
<field name="id_business_source" relation="business_source"/>
<field name="code"/>
<field name="position"/>
<field name="unremovable"/>
<field name="active"/>
</fields>
<entities>
<source id="Direct_Website" id_business_source="Direct" code="DIRECT_WEBSITE" position="0" unremovable="1" active="1">
</source>
<source id="Walk_in" id_business_source="Direct" code="WALKIN" position="1" unremovable="1" active="1">
</source>
<source id="Phone" id_business_source="Direct" code="PHONE" position="2" unremovable="0" active="1">
</source>
<source id="Email" id_business_source="Direct" code="EMAIL" position="3" unremovable="0" active="1">
</source>
<source id="Social_Media" id_business_source="Direct" code="SOCIAL_MEDIA" position="4" unremovable="0" active="1">
</source>
<source id="WhatsApp" id_business_source="Direct" code="WHATSAPP" position="5" unremovable="0" active="1">
</source>
<source id="Booking_com" id_business_source="OTA" code="BOOKING_COM" position="0" unremovable="0" active="1">
</source>
<source id="Expedia" id_business_source="OTA" code="EXPEDIA" position="1" unremovable="0" active="1">
</source>
<source id="GoMMT" id_business_source="OTA" code="GOMMT" position="2" unremovable="0" active="1">
</source>
<source id="Agoda" id_business_source="OTA" code="AGODA" position="3" unremovable="0" active="1">
</source>
<source id="Airbnb" id_business_source="OTA" code="AIRBNB" position="4" unremovable="0" active="1">
</source>
<source id="Trip_com" id_business_source="OTA" code="TRIP_COM" position="5" unremovable="0" active="1">
</source>
<source id="Bakuun" id_business_source="OTA" code="BAKUUN" position="6" unremovable="0" active="1">
</source>
<source id="Despegar" id_business_source="OTA" code="DESPEGAR" position="7" unremovable="0" active="1">
</source>
<source id="Yatra" id_business_source="OTA" code="YATRA" position="8" unremovable="0" active="1">
</source>
<source id="Hostelworld" id_business_source="OTA" code="HOSTELWORLD" position="9" unremovable="0" active="1">
</source>
<source id="HyperGuest" id_business_source="OTA" code="HYPERGUEST" position="10" unremovable="0" active="1">
</source>
<source id="Api_Order" id_business_source="Api" code="API_ORDER" position="0" unremovable="1" active="1">
</source>
</entities>
</entity_source>

View File

@@ -117,6 +117,9 @@
<tab id="Statuses" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminStatuses</class_name>
</tab>
<tab id="Sources" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminSources</class_name>
</tab>
<tab id="Order_Messages" id_parent="Orders" active="1" hide_host_mode="0">
<class_name>AdminOrderMessage</class_name>
</tab>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<entity_business_source>
<business_source id="Direct">
<name>Директен</name>
</business_source>
<business_source id="OTA">
<name>OTA</name>
</business_source>
<business_source id="Corporate">
<name>Корпоративен</name>
</business_source>
<business_source id="Travel_Agent">
<name>Туристическа агенция</name>
</business_source>
<business_source id="Group">
<name>Група</name>
</business_source>
<business_source id="Api">
<name>API</name>
</business_source>
</entity_business_source>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0"?>
<entity_source>
<source id="Direct_Website">
<name>Директен уебсайт</name>
</source>
<source id="Walk_in">
<name>Без резервация</name>
</source>
<source id="Phone">
<name>Телефон</name>
</source>
<source id="Email">
<name>Имейл</name>
</source>
<source id="Social_Media">
<name>Социални медии</name>
</source>
<source id="WhatsApp">
<name>WhatsApp</name>
</source>
<source id="Booking_com">
<name>Booking.com</name>
</source>
<source id="Expedia">
<name>Expedia</name>
</source>
<source id="GoMMT">
<name>GoMMT (GoIbibo/MakeMyTrip)</name>
</source>
<source id="Agoda">
<name>Agoda</name>
</source>
<source id="Airbnb">
<name>Airbnb</name>
</source>
<source id="Trip_com">
<name>Trip.com (Ctrip)</name>
</source>
<source id="Bakuun">
<name>Bakuun</name>
</source>
<source id="Despegar">
<name>Despegar</name>
</source>
<source id="Yatra">
<name>Yatra</name>
</source>
<source id="Hostelworld">
<name>Hostelworld</name>
</source>
<source id="HyperGuest">
<name>HyperGuest</name>
</source>
<source id="Api_Order">
<name>API поръчка</name>
</source>
</entity_source>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<entity_business_source>
<business_source id="Direct">
<name>সরাসরি</name>
</business_source>
<business_source id="OTA">
<name>OTA</name>
</business_source>
<business_source id="Corporate">
<name>কর্পোরেট</name>
</business_source>
<business_source id="Travel_Agent">
<name>ট্রাভেল এজেন্ট</name>
</business_source>
<business_source id="Group">
<name>গ্রুপ</name>
</business_source>
<business_source id="Api">
<name>API</name>
</business_source>
</entity_business_source>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0"?>
<entity_source>
<source id="Direct_Website">
<name>সরাসরি ওয়েবসাইট</name>
</source>
<source id="Walk_in">
<name>ওয়াক-ইন</name>
</source>
<source id="Phone">
<name>ফোন</name>
</source>
<source id="Email">
<name>ইমেইল</name>
</source>
<source id="Social_Media">
<name>সোশ্যাল মিডিয়া</name>
</source>
<source id="WhatsApp">
<name>WhatsApp</name>
</source>
<source id="Booking_com">
<name>Booking.com</name>
</source>
<source id="Expedia">
<name>Expedia</name>
</source>
<source id="GoMMT">
<name>GoMMT (GoIbibo/MakeMyTrip)</name>
</source>
<source id="Agoda">
<name>Agoda</name>
</source>
<source id="Airbnb">
<name>Airbnb</name>
</source>
<source id="Trip_com">
<name>Trip.com (Ctrip)</name>
</source>
<source id="Bakuun">
<name>Bakuun</name>
</source>
<source id="Despegar">
<name>Despegar</name>
</source>
<source id="Yatra">
<name>Yatra</name>
</source>
<source id="Hostelworld">
<name>Hostelworld</name>
</source>
<source id="HyperGuest">
<name>HyperGuest</name>
</source>
<source id="Api_Order">
<name>API অর্ডার</name>
</source>
</entity_source>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<entity_business_source>
<business_source id="Direct">
<name>Direto</name>
</business_source>
<business_source id="OTA">
<name>OTA</name>
</business_source>
<business_source id="Corporate">
<name>Corporativo</name>
</business_source>
<business_source id="Travel_Agent">
<name>Agência de Viagens</name>
</business_source>
<business_source id="Group">
<name>Grupo</name>
</business_source>
<business_source id="Api">
<name>API</name>
</business_source>
</entity_business_source>

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