Merge branch 'Qloapps:develop' into gli-version_upgrade
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
@font-face
|
||||
font-family: 'FontAwesomePlaceholder'
|
||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}')
|
||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg')
|
||||
font-weight: normal
|
||||
font-style: normal
|
||||
unicode-range: U+f000-f2ff
|
||||
|
||||
@mixin background-image-with-ms($image)
|
||||
@include background-image($image) // Compass default version, for everything but IE 10.
|
||||
background-image: -ms-#{$image} // Vendor prefixes for IE 10.
|
||||
@@ -29,6 +37,16 @@
|
||||
.form-control
|
||||
height: inherit !important
|
||||
padding: 10px 8px !important
|
||||
&::-webkit-input-placeholder
|
||||
font-family: 'FontAwesomePlaceholder', $font-family-sans-serif
|
||||
&:-moz-placeholder
|
||||
font-family: 'FontAwesomePlaceholder', $font-family-sans-serif
|
||||
&::-moz-placeholder
|
||||
font-family: 'FontAwesomePlaceholder', $font-family-sans-serif
|
||||
&:-ms-input-placeholder
|
||||
font-family: 'FontAwesomePlaceholder', $font-family-sans-serif
|
||||
&::placeholder
|
||||
font-family: 'FontAwesomePlaceholder', $font-family-sans-serif
|
||||
|
||||
@media (max-width: $screen-phone)
|
||||
width: 90%
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-3 control-label">{l s='Total spent since registration:'}</label>
|
||||
<div class="col-lg-3"><p class="form-control-static">{displayWtPriceWithCurrency price=Tools::convertPrice($customer_stats.total_orders|floatval, $currency) currency=$currency}</p></div>
|
||||
<div class="col-lg-3"><p class="form-control-static">{displayWtPriceWithCurrency price=Tools::convertPrice($customer_stats.total_spent|floatval, $currency) currency=$currency}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
{else}
|
||||
@@ -102,7 +102,7 @@
|
||||
<td>{dateFormat date=$room['date_from'] full=$is_full_date} - {dateFormat date=$room['date_to'] full=$is_full_date}</td>
|
||||
<td>
|
||||
<span>
|
||||
{if $stay['adults']}{$stay['adults']}{/if} {if $stay['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$stay['children']}}, {$stay['children']} {if $stay['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}
|
||||
{if $room['adults']}{$room['adults']}{/if} {if $room['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$room['children']}}, {$room['children']} {if $room['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}
|
||||
</span>
|
||||
</td>
|
||||
<td>{displayWtPriceWithCurrency price=$room['feature_price_tax_excl'] currency=$currency}</td>
|
||||
@@ -131,7 +131,7 @@
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active" ><a href="#room_type_service_product_desc_{$stay['id']}" 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_{$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_services']) && $room['selected_services']}
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
<label>
|
||||
<input type="checkbox" id="sp_standalone" name="selling_preference_type[]" value="{Product::SELLING_PREFERENCE_WITH_STANDALONE}"
|
||||
{if Product::isSellableAsStandalone($product->id) }checked="checked"{/if}>
|
||||
{l s='Sell With Standalone'}
|
||||
{l s='Sell as a Standalone'}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -106,13 +106,6 @@
|
||||
{$cartCurrency->sign}
|
||||
</span>
|
||||
<input class="service_cart_price_input" id="service_cart_price_{$selectedRoomServiceProduct['id']}_{$product['id_product']}" type="text" value="{$product.price_tax_exc}" name="service_price[{$product['id_product']|escape:'html':'UTF-8'}]"{if isset($can_edit) && !$can_edit} readonly{/if}/>
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$product['price_calculation_method'],
|
||||
$selectedRoomServiceProduct['date_from'],
|
||||
$selectedRoomServiceProduct['date_to']
|
||||
) > 1}
|
||||
<span class="input-group-addon">{l s='/ night'}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
|
||||
@@ -98,13 +98,6 @@
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">{$currencySign}</span>
|
||||
<input type="text" class="form-control unit_price" value="{Tools::ps_round($service['unit_price_tax_excl'], 2)}" data-id-product="{$service['id_product']}" name="service_price[{$service['id_service_product_order_detail']}]">
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$service.price_calculation_method,
|
||||
$additionalServices['date_from'],
|
||||
$additionalServices['date_to']
|
||||
) > 1}
|
||||
<span class="input-group-addon">{l s='/ night'}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<td>{displayPrice price=$service['total_price_tax_excl']|escape:'html':'UTF-8' currency=$orderCurrency}</td>
|
||||
@@ -184,13 +177,6 @@
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">{$currencySign}</span>
|
||||
<input type="text" class="form-control unit_price" name="service_price[{$product['id_product']|escape:'html':'UTF-8'}]" value="{$product['price_tax_exc']}" data-id-product="{$product.id_product}">
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$product['price_calculation_method'],
|
||||
$additionalServices['date_from'],
|
||||
$additionalServices['date_to']
|
||||
) > 1}
|
||||
<span class="input-group-addon">{l s='/ night'}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -362,13 +348,6 @@
|
||||
</td>
|
||||
<td>
|
||||
{displayPrice price=$service['unit_price_tax_excl'] currency=$orderCurrency}
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$service['price_calculation_method'],
|
||||
$additionalServices['date_from'],
|
||||
$additionalServices['date_to']
|
||||
) > 1}
|
||||
{l s='/ night'}
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
{displayPrice price=$service['total_price_tax_excl'] currency=$orderCurrency}
|
||||
|
||||
@@ -1606,7 +1606,7 @@
|
||||
$('#deactiveDatesModal').attr('data-room-row-index', roomRowIndex);
|
||||
$('#deactiveDatesModal').attr('data-id-room', idRoom);
|
||||
if ($.trim(roomNum) != '') {
|
||||
roomNum = '( '+'{l s='%s No' sprintf=$htl_room_type['selling_object_plural_name']}'+' '+roomNum+')';
|
||||
roomNum = '( '+'{l s='%s No' sprintf=$htl_room_type['selling_object_name']}'+' '+roomNum+')';
|
||||
}
|
||||
|
||||
$('#deactiveDatesModal .disable_dates_room_num').html(roomNum);
|
||||
@@ -2005,7 +2005,7 @@
|
||||
$('#connected_room_title').html('');
|
||||
}
|
||||
} else {
|
||||
alert(response.message);
|
||||
showErrorMessage(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2016,7 +2016,7 @@
|
||||
var connectedRoomId = $row.find('.connect-room').val();
|
||||
|
||||
if (!connectedRoomId) {
|
||||
alert(selectRoomText);
|
||||
showErrorMessage(selectRoomText);
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
@@ -2043,7 +2043,7 @@
|
||||
$icon.text(response.connected_count);
|
||||
}
|
||||
} else {
|
||||
alert(response.message);
|
||||
showErrorMessage(response.message);
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
@@ -2132,7 +2132,7 @@
|
||||
$icon.text(response.connected_count);
|
||||
}
|
||||
} else {
|
||||
alert(response.message);
|
||||
showErrorMessage(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<input type="checkbox" name="{$node['input_name']}[]" value="{$node['value']}"{if isset($node['selected']) && $node['selected'] == true} checked="checked"{/if}{if isset($node['disabled']) && $node['disabled'] == true} disabled="disabled"{/if} {if isset($node['hidden']) && $node['hidden'] == true} hidden="hidden"{/if}/>
|
||||
{/if}
|
||||
<i class="icon-folder-close"></i>
|
||||
<label class="tree-toggler">{if isset($node['name'])}{$node['name']|escape:'html':'UTF-8'}{/if}{if isset($node['selected_childs']) && (int)$node['selected_childs'] > 0} {l s='(%s selected)' sprintf=$node['selected_childs']}{/if}</label>
|
||||
<label class="tree-toggler">{if isset($node['name'])}{$node['name']|escape:'html':'UTF-8':false}{/if}{if isset($node['selected_childs']) && (int)$node['selected_childs'] > 0} {l s='(%s selected)' sprintf=$node['selected_childs']}{/if}</label>
|
||||
</span>
|
||||
{if isset($node['badge'])}
|
||||
<span class="badge {if isset($node['badge']['class'])}{$node['badge']['class']}{/if}">{$node['badge']['title']}</span>
|
||||
|
||||
@@ -1895,6 +1895,11 @@ class CartCore extends ObjectModel
|
||||
(int)$product['price_addition_type']
|
||||
)) {
|
||||
foreach ($servicesWithRoom as $service) {
|
||||
|
||||
if (isset($product['id_hotel']) && $service['id_room_type_hotel'] != $product['id_hotel']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!empty($service['id_hotel_cart_booking']) && empty($service['id_hotel'])) {
|
||||
if ($with_taxes) {
|
||||
$servicePrice = $service['total_price_tax_incl'];
|
||||
@@ -4061,7 +4066,7 @@ class CartCore extends ObjectModel
|
||||
) {
|
||||
if ($serviceProducts = $objServiceProductCartDetail->getServiceProductsInCart(
|
||||
$this->id,
|
||||
[Product::SELLING_PREFERENCE_HOTEL_STANDALONE, Product::SELLING_PREFERENCE_WITH_HOTEL_AND_WITH_ROOM_TYPE],
|
||||
[Product::SELLING_PREFERENCE_WITH_HOTEL, Product::SELLING_PREFERENCE_WITH_HOTEL_AND_WITH_ROOM_TYPE],
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
|
||||
@@ -689,7 +689,11 @@ class LanguageCore extends ObjectModel
|
||||
$key = 'Language::getIdByIso_'.$iso_code;
|
||||
if ($no_cache || !Cache::isStored($key)) {
|
||||
$id_lang = Db::getInstance()->getValue('SELECT `id_lang` FROM `'._DB_PREFIX_.'lang` WHERE `iso_code` = \''.pSQL(strtolower($iso_code)).'\'');
|
||||
|
||||
|
||||
if (empty($id_lang)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Cache::store($key, $id_lang);
|
||||
return $id_lang;
|
||||
}
|
||||
@@ -796,7 +800,7 @@ class LanguageCore extends ObjectModel
|
||||
|
||||
public static function checkAndAddLanguage($iso_code, $lang_pack = false, $only_add = false, $params_lang = null)
|
||||
{
|
||||
if (Language::getIdByIso($iso_code)) {
|
||||
if (Language::getIdByIso($iso_code, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -619,7 +619,7 @@ abstract class PaymentModuleCore extends Module
|
||||
$serviceProducts = $objServiceProductCartDetail->getServiceProductsInCart(
|
||||
$order->id_cart,
|
||||
[],
|
||||
null,
|
||||
isset($product['id_hotel']) ? (int) $product['id_hotel'] : null,
|
||||
0,
|
||||
null,
|
||||
$product['id_product']
|
||||
|
||||
@@ -6868,8 +6868,8 @@ class ProductCore extends ObjectModel
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
$unitPriceExcl = ($useTax ? Product::getServiceProductPrice($idProduct, $idProductOption, $idHotel, $idProductRoomType, false, 1, $dateFrom, $dateTo, $idCart, $idAddress, $useReduc, $idGroup, $idCartBooking) : $price / (int) $quantity) / max(1, $numdays);
|
||||
|
||||
$fallbackAddress = new Address(Cart::getIdAddressForTaxCalculation($idProduct));
|
||||
if ($numAdults === null) {
|
||||
|
||||
@@ -1885,6 +1885,8 @@ class ToolsCore
|
||||
|
||||
public static function math_round($value, $places, $mode = PS_ROUND_HALF_UP)
|
||||
{
|
||||
$value = (float) $value;
|
||||
|
||||
//If PHP_ROUND_HALF_UP exist (PHP 5.3) use it and pass correct mode value (PrestaShop define - 1)
|
||||
if (defined('PHP_ROUND_HALF_UP')) {
|
||||
return round($value, $places, $mode - 1);
|
||||
|
||||
@@ -592,7 +592,7 @@ class OrderDetailCore extends ObjectModel
|
||||
{
|
||||
$this->setContext((int)$this->id_shop);
|
||||
$address = new Address((int)$order->id_address_tax);
|
||||
$tax_manager = TaxManagerFactory::getManager($address, (int)Product::getIdTaxRulesGroupByIdProduct((int)$this->product_id, $this->context));
|
||||
$tax_manager = TaxManagerFactory::getManager($address, (int)$this->id_tax_rules_group);
|
||||
$this->tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
$result = $this->saveTaxCalculator($order, true);
|
||||
|
||||
@@ -121,7 +121,7 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->order->products = null;
|
||||
$this->order->products = array();
|
||||
}
|
||||
|
||||
unset($product); // remove reference
|
||||
|
||||
@@ -270,12 +270,12 @@ class AdminCartsControllerCore extends AdminController
|
||||
if (!($cart = $this->loadObject(true))) {
|
||||
return;
|
||||
}
|
||||
$this->context->cart = $cart;
|
||||
if ($this->tabAccess['kpi'] === 1) {
|
||||
$this->content .= $this->renderKpis();
|
||||
}
|
||||
$customer = new Customer($cart->id_customer);
|
||||
$currency = new Currency($cart->id_currency);
|
||||
$this->context->cart = $cart;
|
||||
$this->context->currency = $currency;
|
||||
$this->context->customer = $customer;
|
||||
$this->toolbar_title = sprintf($this->l('Cart #%06d'), $this->context->cart->id);
|
||||
@@ -1717,45 +1717,52 @@ class AdminCartsControllerCore extends AdminController
|
||||
$idCartBooking
|
||||
))) {
|
||||
$originalPrice = Product::getPriceStatic($idServiceProduct, false);
|
||||
$specificPriceInfo = SpecificPrice::getSpecificPrice(
|
||||
(int)$idServiceProduct,
|
||||
0,
|
||||
$objCart->id_currency,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
$objCart->id,
|
||||
0,
|
||||
$objHotelCartBookingData->id
|
||||
);
|
||||
// if price is different than the original service price then update the price
|
||||
if ($canEdit && $operator == 'up' && $originalPrice != $unitPrice) {
|
||||
if ($specificPriceInfo = SpecificPrice::getSpecificPrice(
|
||||
(int)$idServiceProduct,
|
||||
0,
|
||||
$objCart->id_currency,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
$objCart->id,
|
||||
0,
|
||||
$objHotelCartBookingData->id
|
||||
)) {
|
||||
$objSpecificPrice = new SpecificPrice($specificPriceInfo['id_specific_price']);
|
||||
} else {
|
||||
$objSpecificPrice = new SpecificPrice();
|
||||
}
|
||||
$objSpecificPrice->id_shop = 0;
|
||||
$objSpecificPrice->id_shop_group = 0;
|
||||
$objSpecificPrice->id_cart = $objCart->id;
|
||||
$objSpecificPrice->id_currency = $objCart->id_currency;
|
||||
$objSpecificPrice->id_country = 0;
|
||||
$objSpecificPrice->id_group = 0;
|
||||
$objSpecificPrice->id_customer = 0;
|
||||
$objSpecificPrice->id_product = $idServiceProduct;
|
||||
$objSpecificPrice->id_product_attribute = 0;
|
||||
$objSpecificPrice->price = $unitPrice;
|
||||
$objSpecificPrice->from_quantity = 1;
|
||||
$objSpecificPrice->reduction = 0;
|
||||
$objSpecificPrice->id_htl_cart_booking = $objHotelCartBookingData->id;
|
||||
$objSpecificPrice->reduction_type = 'amount';
|
||||
$objSpecificPrice->reduction_tax = 0;
|
||||
$objSpecificPrice->from = '0000-00-00 00:00:00';
|
||||
$objSpecificPrice->to = '0000-00-00 00:00:00';
|
||||
if($canEdit && $operator == 'up'){
|
||||
if ($originalPrice != $unitPrice) {
|
||||
if ($specificPriceInfo) {
|
||||
$objSpecificPrice = new SpecificPrice($specificPriceInfo['id_specific_price']);
|
||||
} else {
|
||||
$objSpecificPrice = new SpecificPrice();
|
||||
}
|
||||
$objSpecificPrice->id_shop = 0;
|
||||
$objSpecificPrice->id_shop_group = 0;
|
||||
$objSpecificPrice->id_cart = $objCart->id;
|
||||
$objSpecificPrice->id_currency = $objCart->id_currency;
|
||||
$objSpecificPrice->id_country = 0;
|
||||
$objSpecificPrice->id_group = 0;
|
||||
$objSpecificPrice->id_customer = 0;
|
||||
$objSpecificPrice->id_product = $idServiceProduct;
|
||||
$objSpecificPrice->id_product_attribute = 0;
|
||||
$objSpecificPrice->price = $unitPrice;
|
||||
$objSpecificPrice->from_quantity = 1;
|
||||
$objSpecificPrice->reduction = 0;
|
||||
$objSpecificPrice->id_htl_cart_booking = $objHotelCartBookingData->id;
|
||||
$objSpecificPrice->reduction_type = 'amount';
|
||||
$objSpecificPrice->reduction_tax = 0;
|
||||
$objSpecificPrice->from = '0000-00-00 00:00:00';
|
||||
$objSpecificPrice->to = '0000-00-00 00:00:00';
|
||||
|
||||
$result &= $objSpecificPrice->save();
|
||||
$result &= $objSpecificPrice->save();
|
||||
} elseif ($specificPriceInfo) {
|
||||
$objSpecificPrice = new SpecificPrice($specificPriceInfo['id_specific_price']);
|
||||
$result &= $objSpecificPrice->delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1217,6 +1217,14 @@ class AdminCustomersControllerCore extends AdminController
|
||||
$objCustomerGuestDetail->email = $objCustomer->email;
|
||||
$objCustomerGuestDetail->save();
|
||||
}
|
||||
|
||||
if ($threads = CustomerThread::getCustomerMessages($objCustomer->id)) {
|
||||
foreach ($threads as $thread) {
|
||||
$objThread = new CustomerThread($thread['id_customer_thread']);
|
||||
$objThread->email = $objCustomer->email;
|
||||
$objThread->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token;
|
||||
|
||||
@@ -4068,7 +4068,9 @@ class AdminOrdersControllerCore extends AdminController
|
||||
$this->errors[] = $this->l('Uploaded file size is too large.');
|
||||
} else {
|
||||
$objHotelBookingDocument->setFileType();
|
||||
if (!$objHotelBookingDocument->file_type) {
|
||||
if ($objHotelBookingDocument->isUnsafePdf) {
|
||||
$this->errors[] = $this->l('This PDF file is invalid or contains unsafe content and cannot be uploaded.');
|
||||
} elseif (!$objHotelBookingDocument->file_type) {
|
||||
$this->errors[] = $this->l('Please upload an image or a PDF file only. Allowed image formats: .gif, .jpg, .jpeg and .png');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,6 +937,7 @@ class AdminProductsControllerCore extends AdminController
|
||||
&& Product::duplicateCustomizationFields($id_product_old, $product->id)
|
||||
&& Product::duplicateTags($id_product_old, $product->id)
|
||||
&& Product::duplicateDownload($id_product_old, $product->id)
|
||||
&& HotelAdvancedPayment::duplicateAdvancePayment($id_product_old, $product->id)
|
||||
) {
|
||||
$obj_hotel_room_type = new HotelRoomType();
|
||||
$room_type_info = $obj_hotel_room_type->getRoomTypeInfoByIdProduct($id_product_old);
|
||||
@@ -1249,6 +1250,10 @@ class AdminProductsControllerCore extends AdminController
|
||||
|
||||
if ($payment_type == 1) {
|
||||
$adv_pay_value = Tools::getValue('adv_pay_percent');
|
||||
if ($adv_pay_value > 100) {
|
||||
$this->errors[] = Tools::displayError('Advance payment percentage cannot be more than 100.');
|
||||
return false;
|
||||
}
|
||||
} elseif ($payment_type == 2) {
|
||||
$adv_pay_value = Tools::getValue('adv_pay_amount');
|
||||
}
|
||||
@@ -5715,6 +5720,19 @@ class AdminProductsControllerCore extends AdminController
|
||||
$idHotel = (int) $objRoom->id_hotel;
|
||||
|
||||
if ($mode === 'add') {
|
||||
if (!Validate::isLoadedObject($objRoom)) {
|
||||
die(json_encode(['success' => false, 'message' => $this->l('Invalid room selected.')]));
|
||||
}
|
||||
|
||||
$objConnectedRoom = new HotelRoomInformation($connectedRoomId);
|
||||
if (
|
||||
$connectedRoomId === $roomId
|
||||
|| !Validate::isLoadedObject($objConnectedRoom)
|
||||
|| (int) $objConnectedRoom->id_hotel !== $idHotel
|
||||
) {
|
||||
die(json_encode(['success' => false, 'message' => $this->l('Invalid room selected for connection.')]));
|
||||
}
|
||||
|
||||
$connection = new HotelConnectedRoom();
|
||||
$connection->id_room = $roomId;
|
||||
$connection->id_room_connected = $connectedRoomId;
|
||||
|
||||
@@ -781,7 +781,19 @@ class CartControllerCore extends FrontController
|
||||
);
|
||||
$currentQty = $qty * $numDays;
|
||||
$finalQty = (int)$cartTotalQty + $currentQty;
|
||||
if ($objProduct->max_quantity && $finalQty > $objProduct->max_quantity) {
|
||||
// max quantity limit applies per room, not on the whole cart
|
||||
$serviceQtyInRoom = (int) $qty;
|
||||
if ($roomServices = (new ServiceProductCartDetail())->getServiceProductsInCart(
|
||||
(int) $this->context->cart->id,
|
||||
[],
|
||||
null,
|
||||
(int) $idCartBooking,
|
||||
null,
|
||||
(int) $idServiceProduct
|
||||
)) {
|
||||
$serviceQtyInRoom += (int) array_sum(array_column($roomServices, 'quantity'));
|
||||
}
|
||||
if ($objProduct->max_quantity && $serviceQtyInRoom > $objProduct->max_quantity) {
|
||||
$this->errors[] = Tools::displayError(sprintf('cannot add more than %d quantity.', $objProduct->max_quantity));
|
||||
} else if (!Product::isAvailableWhenOutOfStock($objProduct->out_of_stock) && !$objProduct->checkQty($finalQty)) {
|
||||
$this->errors[] = Tools::displayError('There isn\'t enough product in stock.');
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset(Context::getContext()->controller)) {
|
||||
$controller = Context::getContext()->controller;
|
||||
} else {
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset(Context::getContext()->controller)) {
|
||||
$controller = Context::getContext()->controller;
|
||||
} else {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 613 B |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
4
init.php
4
init.php
@@ -24,6 +24,10 @@
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset(Context::getContext()->controller)) {
|
||||
$controller = Context::getContext()->controller;
|
||||
} else {
|
||||
|
||||
@@ -70,7 +70,9 @@ $('document').ready( function() {
|
||||
});
|
||||
|
||||
$('#proceed-install-anyway').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
if ($(this).attr('href') === '#') {
|
||||
e.preventDefault();
|
||||
}
|
||||
})
|
||||
|
||||
function displayErrors(response, module)
|
||||
|
||||
@@ -97,7 +97,7 @@ function removeTaxes(price)
|
||||
|
||||
function getEcotaxTaxIncluded()
|
||||
{
|
||||
return ps_round(ecotax_tax_excl * (1 + ecotaxTaxRate), 2);
|
||||
return ps_round((isNaN(ecotax_tax_excl) ? 0 : ecotax_tax_excl) * (1 + ecotaxTaxRate), 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,9 @@ function calcPriceTI()
|
||||
|
||||
function calcPriceTE()
|
||||
{
|
||||
ecotax_tax_excl = $('#ecotax').val() / (1 + ecotaxTaxRate);
|
||||
if ($('#ecotax').length) {
|
||||
ecotax_tax_excl = $('#ecotax').val() / (1 + ecotaxTaxRate);
|
||||
}
|
||||
var priceTI = parseFloat($('#priceTI').val().replace(/,/g, '.'));
|
||||
var newPrice = removeTaxes(ps_round(priceTI - getEcotaxTaxIncluded(), priceDisplayPrecision));
|
||||
var tourismTaxIncluded = getTourismTaxIncluded(newPrice);
|
||||
|
||||
@@ -79,6 +79,31 @@ class HotelAdvancedPayment extends ObjectModel
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the advance payment configuration of a room type for its duplicate
|
||||
*
|
||||
* @param int $id_product_old Id of the room type (product) being duplicated
|
||||
* @param int $id_product_new Id of the newly duplicated room type (product)
|
||||
* @return bool
|
||||
*/
|
||||
public static function duplicateAdvancePayment($id_product_old, $id_product_new)
|
||||
{
|
||||
$row = Db::getInstance()->getRow(
|
||||
'SELECT * FROM `'._DB_PREFIX_.'htl_advance_payment` WHERE `id_product` = '.(int)$id_product_old
|
||||
);
|
||||
|
||||
if (!$row) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unset($row['id']);
|
||||
$row['id_product'] = (int)$id_product_new;
|
||||
$row['date_add'] = date('Y-m-d H:i:s');
|
||||
$row['date_upd'] = date('Y-m-d H:i:s');
|
||||
|
||||
return Db::getInstance()->insert('htl_advance_payment', $row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the advance payment amount of the room type in the cart
|
||||
* @param [int] $idCart : cart id
|
||||
|
||||
@@ -604,7 +604,7 @@ class HotelBookingDetail extends ObjectModel
|
||||
$sql[] = 'SELECT hri.`id` AS `id_room`, hri.`id_product`, hri.`id_hotel`, hri.`room_num`, hri.`comment` AS `room_comment`, hri.`id_status`, hrdd.`date_from` AS `date_from`, hrdd.`date_to` AS `date_to`
|
||||
FROM `'._DB_PREFIX_.'htl_room_information` AS hri
|
||||
INNER JOIN `'._DB_PREFIX_.'htl_room_disable_dates` AS hrdd ON (hrdd.`id_room_type` = hri.`id_product` AND hrdd. id_room = hri.`id`)
|
||||
WHERE hri.`id_hotel`='.$idHotel.' AND hri.`id_status` = '. HotelRoomInformation::STATUS_TEMPORARY_INACTIVE .' AND (
|
||||
WHERE hri.`id_hotel`='.(int) $idHotel.' AND hri.`id_status` = '. HotelRoomInformation::STATUS_TEMPORARY_INACTIVE .' AND (
|
||||
(hrdd.`date_from` <= \''.pSQL($dateFrom).'\' AND hrdd.`date_to` > \''.pSQL($dateFrom).'\' AND hrdd.`date_to` <= \''.pSQL($dateTo).'\') OR
|
||||
(hrdd.`date_from` >= \''.pSQL($dateFrom).'\' AND hrdd.`date_to` > \''.pSQL($dateFrom).'\' AND hrdd.`date_to` <= \''.pSQL($dateTo).'\') OR
|
||||
(hrdd.`date_from` >= \''.pSQL($dateFrom).'\' AND hrdd.`date_from` < \''.pSQL($dateTo).'\' AND hrdd.`date_to` >= \''.pSQL($dateTo).'\') OR
|
||||
@@ -2097,7 +2097,17 @@ class HotelBookingDetail extends ObjectModel
|
||||
|
||||
if ($roomAvailabilityInfo = $objOldHotelBooking->dataForFrontSearch($bookingParams)) {
|
||||
if ($availableRooms = $roomAvailabilityInfo['rm_data'][$idNewRoomType]['data']['available']) {
|
||||
$roomInfo = reset($availableRooms);
|
||||
$roomInfo = null;
|
||||
foreach ($availableRooms as $availableRoom) {
|
||||
if ($availableRoom['id_room'] == $idRoom) {
|
||||
$roomInfo = $availableRoom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$roomInfo) {
|
||||
return false;
|
||||
}
|
||||
$objCartBookingData = new HotelCartBookingData();
|
||||
$objCartBookingData->id_cart = $context->cart->id;
|
||||
$objCartBookingData->id_guest = $context->cookie->id_guest;
|
||||
|
||||
@@ -30,6 +30,9 @@ class HotelBookingDocument extends ObjectModel
|
||||
public $file_name;
|
||||
public $date_add;
|
||||
|
||||
/** @var bool True when the file is a PDF but was rejected for unsafe content. */
|
||||
public $isUnsafePdf = false;
|
||||
|
||||
const FILE_TYPE_IMAGE = 1;
|
||||
const FILE_TYPE_PDF = 2;
|
||||
|
||||
@@ -139,16 +142,28 @@ class HotelBookingDocument extends ObjectModel
|
||||
public function setFileType()
|
||||
{
|
||||
$content = @file_get_contents($this->fileInfo['tmp_name']);
|
||||
$activeContentPattern = '/\/(JavaScript|JS|OpenAction|AA|Launch|SubmitForm|ImportData)\b/i';
|
||||
|
||||
// PDF names can hide keywords with hex escapes (/J#53 is /JS), so decode them before matching.
|
||||
$decodedContent = ($content === false) ? '' : preg_replace_callback('/#([0-9a-f]{2})/i', function ($match) {
|
||||
return chr(hexdec($match[1]));
|
||||
}, $content);
|
||||
|
||||
// A complete PDF ends with startxref <offset> %%EOF; anything else is truncated or corrupt.
|
||||
// Encrypted PDFs cannot be scanned, so /Encrypt is blocked too.
|
||||
// /OpenAction followed by '[' is a plain page destination (zoom/fit).
|
||||
// for every generated PDF. Any other /OpenAction value is an action and stays blocked.
|
||||
$activeContentPattern = '/\/(JavaScript|JS|AA|Launch|SubmitForm|ImportData|GoToR|GoToE|EmbeddedFile|RichMedia|XFA|Encrypt)\b|\/OpenAction\b(?!\s*\[)/i';
|
||||
|
||||
$this->isUnsafePdf = false;
|
||||
$this->imageInfo = @getimagesize($this->fileInfo['tmp_name']);
|
||||
|
||||
if ($this->imageInfo && ImageManager::isRealImage($this->fileInfo['tmp_name'])) {
|
||||
$this->file_type = self::FILE_TYPE_IMAGE;
|
||||
} elseif ($content !== false && substr($content, 0, 5) === '%PDF-' && !preg_match($activeContentPattern, $content)) {
|
||||
} elseif ($content !== false && substr($content, 0, 5) === '%PDF-' && preg_match('/startxref\s+\d+\s+%%EOF\s*$/', substr($content, -1024)) && !preg_match($activeContentPattern, $decodedContent)) {
|
||||
$this->file_type = self::FILE_TYPE_PDF;
|
||||
} else {
|
||||
$this->file_type = 0;
|
||||
$this->isUnsafePdf = ($content !== false && substr($content, 0, 5) === '%PDF-');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -385,17 +385,20 @@ class HotelRoomTypeFeaturePricing extends ObjectModel
|
||||
$numNights = max(1, (int) HotelHelper::getNumberOfDays($date_from, $date_to));
|
||||
$unitPriceTe = (float) $totalPrice['total_price_tax_excl'] / $numNights;
|
||||
$taxCalculator = TaxManagerFactory::getManager($objAddress, $idTourismTaxRulesGroup)->getTaxCalculator();
|
||||
$childAges = !empty($occupancy[0]['child_ages']) ? (array) $occupancy[0]['child_ages'] : array();
|
||||
$totalPrice['total_price_tax_incl'] += $taxCalculator->getTaxesTotalAmount(
|
||||
$unitPriceTe,
|
||||
$date_from,
|
||||
$numNights,
|
||||
$occupancy[0]['adults'],
|
||||
$childAges,
|
||||
$collectionType,
|
||||
1,
|
||||
$id_currency
|
||||
);
|
||||
$roomsTourismTax = 0;
|
||||
foreach ($occupancy as $roomOccupancy) {
|
||||
$roomsTourismTax += $taxCalculator->getTaxesTotalAmount(
|
||||
$unitPriceTe,
|
||||
$date_from,
|
||||
$numNights,
|
||||
isset($roomOccupancy['adults']) ? (int) $roomOccupancy['adults'] : 0,
|
||||
!empty($roomOccupancy['child_ages']) ? (array) $roomOccupancy['child_ages'] : array(),
|
||||
$collectionType,
|
||||
1,
|
||||
$id_currency
|
||||
);
|
||||
}
|
||||
$totalPrice['total_price_tax_incl'] += $roomsTourismTax / count($occupancy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ class ServiceProductCartDetail extends ObjectModel
|
||||
$language = new Language($idLang);
|
||||
}
|
||||
|
||||
$sql = 'SELECT spc.*, p.`selling_preference_type`, hcbd.`date_from`, spc.`id_cart` as service_id_cart, hcbd.`date_to`, p.`price_calculation_method`, hcbd.`id_product` as `id_product_room_type`';
|
||||
$sql = 'SELECT spc.*, p.`selling_preference_type`, hcbd.`date_from`, spc.`id_cart` as service_id_cart, hcbd.`date_to`, p.`price_calculation_method`, hcbd.`id_product` as `id_product_room_type`, hcbd.`id_hotel` as `id_room_type_hotel`';
|
||||
if (!$getTotalPrice) {
|
||||
$sql .= ', hbil.`hotel_name`, p.`auto_add_to_cart`, p.`price_addition_type` ';
|
||||
}
|
||||
@@ -232,6 +232,9 @@ class ServiceProductCartDetail extends ObjectModel
|
||||
$context = Context::getContext();
|
||||
foreach ($serviceProducts as $product) {
|
||||
$objProduct = new Product($product['id_product'], false, $language->id);
|
||||
if (!Validate::isLoadedObject($objProduct)) {
|
||||
continue;
|
||||
}
|
||||
if (!$objProduct->booking_product) {
|
||||
$quantity = $product['quantity'] ? (int) $product['quantity'] : 1;
|
||||
|
||||
|
||||
@@ -57,6 +57,17 @@ class AdminHotelPropertyTypesController extends ModuleAdminController
|
||||
$this->addRowAction('edit');
|
||||
$this->addRowAction('delete');
|
||||
$this->bulk_actions = array(
|
||||
'enableSelection' => array(
|
||||
'text' => $this->l('Enable selected'),
|
||||
'icon' => 'icon-power-off text-success',
|
||||
),
|
||||
'disableSelection' => array(
|
||||
'text' => $this->l('Disable selected'),
|
||||
'icon' => 'icon-power-off text-danger',
|
||||
),
|
||||
'divider' => array(
|
||||
'text' => 'divider',
|
||||
),
|
||||
'delete' => array(
|
||||
'text' => $this->l('Delete selected'),
|
||||
'confirm' => $this->l('Delete selected items?'),
|
||||
@@ -157,6 +168,13 @@ class AdminHotelPropertyTypesController extends ModuleAdminController
|
||||
|
||||
$this->display = $idPropertyType ? 'edit' : 'add';
|
||||
|
||||
if (!$this->errors && !Tools::getValue('active') && $idPropertyType) {
|
||||
$objPropertyType = new HotelPropertyType((int) $idPropertyType);
|
||||
if (Validate::isLoadedObject($objPropertyType) && $objPropertyType->active && $objPropertyType->isUsed()) {
|
||||
$this->errors[] = $this->l('You cannot disable this property type because it is currently assigned to one or more properties.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->errors) {
|
||||
parent::postProcess();
|
||||
}
|
||||
@@ -165,6 +183,34 @@ class AdminHotelPropertyTypesController extends ModuleAdminController
|
||||
}
|
||||
}
|
||||
|
||||
public function processStatus()
|
||||
{
|
||||
$object = $this->loadObject();
|
||||
if (Validate::isLoadedObject($object) && $object->active && $object->isUsed()) {
|
||||
$this->errors[] = $this->l('You cannot disable this property type because it is currently assigned to one or more properties.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::processStatus();
|
||||
}
|
||||
|
||||
protected function processBulkDisableSelection()
|
||||
{
|
||||
if (is_array($this->boxes) && !empty($this->boxes)) {
|
||||
foreach ($this->boxes as $idPropertyType) {
|
||||
$object = new HotelPropertyType((int) $idPropertyType);
|
||||
if (Validate::isLoadedObject($object) && $object->isUsed()) {
|
||||
$this->errors[] = $this->l('You cannot disable this property type because it is currently assigned to one or more properties.');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::processBulkDisableSelection();
|
||||
}
|
||||
|
||||
public function processDelete()
|
||||
{
|
||||
$object = $this->loadObject();
|
||||
|
||||
@@ -134,13 +134,16 @@ class AdminHotelRoomsBookingController extends ModuleAdminController
|
||||
$date_from = date('Y-m-d');
|
||||
}
|
||||
}
|
||||
if (Tools::getValue('date_to')) {
|
||||
$date_to = Tools::getValue('date_to');
|
||||
} else {
|
||||
if (!Validate::isDate($date_from)) {
|
||||
$date_from = date('Y-m-d');
|
||||
}
|
||||
$date_to = Tools::getValue('date_to');
|
||||
if (!$date_to || !Validate::isDate($date_to)) {
|
||||
$date_to = date('Y-m-d');
|
||||
if (strtotime($date_from) >= strtotime($date_to)) {
|
||||
$date_to = date('Y-m-d', strtotime('+1 day', strtotime($date_to)));
|
||||
}
|
||||
}
|
||||
// Check-out date must always be after check-in date
|
||||
if (strtotime($date_from) >= strtotime($date_to)) {
|
||||
$date_to = date('Y-m-d', strtotime('+1 day', strtotime($date_from)));
|
||||
}
|
||||
|
||||
if (Tools::getValue('id_hotel')) {
|
||||
|
||||
@@ -510,33 +510,23 @@ class AdminOrderRefundRequestsController extends ModuleAdminController
|
||||
$objHtlBooking = new HotelBookingDetail($idHtlBooking);
|
||||
$idOrderDetail = $objHtlBooking->id_order_detail;
|
||||
|
||||
// split the admin's single tax-incl entry using the booking's
|
||||
// own tax ratio; (float) cast since DB decimals come back as
|
||||
// strings like "0.000000", which PHP treats as truthy
|
||||
$refundedAmountTaxExcl = (float) $objHtlBooking->total_price_tax_incl
|
||||
? $refundedAmount * ($objHtlBooking->total_price_tax_excl / $objHtlBooking->total_price_tax_incl)
|
||||
: $refundedAmount;
|
||||
|
||||
// $refundedAmount is already tax-incl. (see the "tax incl."
|
||||
$bookingList[$idRetDetail] = array(
|
||||
'id_htl_booking' => $idHtlBooking,
|
||||
'id_order_detail' => $idOrderDetail,
|
||||
'quantity' => $numDays,
|
||||
'num_days' => $numDays,
|
||||
'unit_price' => $refundedAmountTaxExcl / $numDays,
|
||||
'unit_price' => $refundedAmount / $numDays,
|
||||
);
|
||||
} elseif ($idServiceProductOrder = $objOrderReturnDetail->id_service_product_order_detail) {
|
||||
$objServiceProductOrderDetail = new ServiceProductOrderDetail($idServiceProductOrder);
|
||||
|
||||
// same reasoning as the booking branch above
|
||||
$refundedAmountTaxExcl = (float) $objServiceProductOrderDetail->total_price_tax_incl
|
||||
? $refundedAmount * ($objServiceProductOrderDetail->total_price_tax_excl / $objServiceProductOrderDetail->total_price_tax_incl)
|
||||
: $refundedAmount;
|
||||
|
||||
$bookingList[$idRetDetail] = array(
|
||||
'id_service_product_order_detail' => $idServiceProductOrder,
|
||||
'id_order_detail' => $objServiceProductOrderDetail->id_order_detail,
|
||||
'quantity' => $objServiceProductOrderDetail->quantity,
|
||||
'unit_price' => $refundedAmountTaxExcl / $objServiceProductOrderDetail->quantity,
|
||||
'unit_price' => $refundedAmount / $objServiceProductOrderDetail->quantity,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,7 +444,6 @@ class HotelReservationSystem extends Module
|
||||
$langTables = array(
|
||||
'htl_room_type_feature_pricing',
|
||||
'htl_branch_info',
|
||||
'htl_features',
|
||||
'htl_amenity',
|
||||
'htl_order_refund_rules',
|
||||
'htl_settings_link'
|
||||
|
||||
@@ -120,8 +120,8 @@
|
||||
@keyframes wkZoomIn { from { opacity:0; transform:scale(0.88); } to { opacity:1; transform:scale(1); } }
|
||||
@keyframes wkBlurOut { from { opacity:1; filter:blur(0); } to { opacity:0; filter:blur(10px); } }
|
||||
@keyframes wkBlurIn { from { opacity:0; filter:blur(10px); } to { opacity:1; filter:blur(0); } }
|
||||
@keyframes wkSlideOut { from { opacity:1; transform:translateX(0); } to { opacity:0; transform:translateX(-60px); } }
|
||||
@keyframes wkSlideIn { from { opacity:0; transform:translateX(60px); } to { opacity:1; transform:translateX(0); } }
|
||||
@keyframes wkSlideOut { from { transform:translateX(0); } to { transform:translateX(-100%); } }
|
||||
@keyframes wkSlideIn { from { transform:translateX(100%); } to { transform:translateX(0); } }
|
||||
|
||||
/* Description slide animation on slide change */
|
||||
.js-header-description {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label class="control-label col-lg-3">{l s='Hotel' mod='qlohotelreview'}</label>
|
||||
<label class="control-label col-lg-3">{if $obj_hotel->propertyTypeName}{$obj_hotel->propertyTypeName|escape:'html':'UTF-8'}{else}{l s='Property' mod='qlohotelreview'}{/if}</label>
|
||||
<div class="col-lg-9">
|
||||
<p class="form-control-static">
|
||||
<a href="{$link->getAdminLink('AdminAddHotel')}&updatehtl_branch_info&id={$currentObject->id_hotel}" target="_blank">
|
||||
|
||||
@@ -100,6 +100,17 @@ class WkPaypalCommerceWebhook
|
||||
$capturedAmount = isset($purchase['payments']['captures'][0]['amount']['value'])
|
||||
? (float)$purchase['payments']['captures'][0]['amount']['value']
|
||||
: 0;
|
||||
$capturedCurrency = isset($purchase['payments']['captures'][0]['amount']['currency_code'])
|
||||
? $purchase['payments']['captures'][0]['amount']['currency_code']
|
||||
: '';
|
||||
$cartCurrency = Currency::getCurrency((int)$objCart->id_currency);
|
||||
if (Tools::strtoupper($capturedCurrency) !== Tools::strtoupper($cartCurrency['iso_code'])) {
|
||||
WkPaypalCommerceHelper::logMsg(
|
||||
'webhook',
|
||||
'PayPal currency mismatch for cart '.(int)$cartID.'. Captured currency: '.$capturedCurrency
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$fullTotal = (float)$objCart->getOrderTotal(true, Cart::BOTH);
|
||||
$orderStatus = $capturedAmount >= $fullTotal
|
||||
? Configuration::get('PS_OS_PAYMENT_ACCEPTED')
|
||||
@@ -131,6 +142,17 @@ class WkPaypalCommerceWebhook
|
||||
$capturedAmount = isset($eventData['resource']['amount']['value'])
|
||||
? (float)$eventData['resource']['amount']['value']
|
||||
: 0;
|
||||
$capturedCurrency = isset($eventData['resource']['amount']['currency_code'])
|
||||
? $eventData['resource']['amount']['currency_code']
|
||||
: '';
|
||||
$cartCurrency = Currency::getCurrency((int)$objCart->id_currency);
|
||||
if (Tools::strtoupper($capturedCurrency) !== Tools::strtoupper($cartCurrency['iso_code'])) {
|
||||
WkPaypalCommerceHelper::logMsg(
|
||||
'webhook',
|
||||
'PayPal currency mismatch for cart '.(int)$cartID.'. Captured currency: '.$capturedCurrency
|
||||
);
|
||||
return;
|
||||
}
|
||||
$fullTotal = (float)$objCart->getOrderTotal(true, Cart::BOTH);
|
||||
$orderStatus = $capturedAmount >= $fullTotal
|
||||
? Configuration::get('PS_OS_PAYMENT_ACCEPTED')
|
||||
|
||||
@@ -135,7 +135,31 @@ class QloPaypalCommercePaymentModuleFrontController extends ModuleFrontControlle
|
||||
$paypalOrderCartId = isset($returnData['data']['purchase_units'][0]['custom_id']) ? $returnData['data']['purchase_units'][0]['custom_id'] : null;
|
||||
$belongsToCurrentCart = ((int) $paypalOrderCartId === (int) $cart->id);
|
||||
|
||||
if ($paypalOrderID && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && $belongsToCurrentCart) {
|
||||
// captured currency must match the cart currency, otherwise the captured amount cannot be compared with the cart total
|
||||
$capturedCurrency = isset($returnData['data']['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code']) ?
|
||||
$returnData['data']['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code'] : '';
|
||||
// payment is deducted in the captured currency, so order must be created in that currency
|
||||
if ($capturedCurrency && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && $belongsToCurrentCart) {
|
||||
$cartCurrency = Currency::getCurrency((int) $cart->id_currency);
|
||||
if (Tools::strtoupper($capturedCurrency) !== Tools::strtoupper($cartCurrency['iso_code'])) {
|
||||
$idCapturedCurrency = (int) Currency::getIdByIsoCode($capturedCurrency);
|
||||
$objCapturedCurrency = new Currency($idCapturedCurrency);
|
||||
if (Validate::isLoadedObject($objCapturedCurrency) && $objCapturedCurrency->active && !$objCapturedCurrency->deleted) {
|
||||
WkPaypalCommerceHelper::logMsg(
|
||||
'payment',
|
||||
'Switching cart currency from '.$cartCurrency['iso_code'].' to PayPal captured currency '.$capturedCurrency
|
||||
);
|
||||
$cart->id_currency = $idCapturedCurrency;
|
||||
$cart->update();
|
||||
$this->context->currency = $objCapturedCurrency;
|
||||
$this->context->cart = $cart;
|
||||
}
|
||||
}
|
||||
}
|
||||
$cartCurrency = Currency::getCurrency((int) $cart->id_currency);
|
||||
$currencyMatches = (Tools::strtoupper($capturedCurrency) === Tools::strtoupper($cartCurrency['iso_code']));
|
||||
|
||||
if ($paypalOrderID && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && $belongsToCurrentCart && $currencyMatches) {
|
||||
// Save order data
|
||||
$this->saveOrderData($returnData);
|
||||
$currency = $this->context->currency;
|
||||
@@ -204,6 +228,12 @@ class QloPaypalCommercePaymentModuleFrontController extends ModuleFrontControlle
|
||||
'PayPal order/cart mismatch. Expected cart: '.$cart->id.', PayPal custom_id: '.$paypalOrderCartId
|
||||
);
|
||||
}
|
||||
if ($paypalOrderID && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && $belongsToCurrentCart && !$currencyMatches) {
|
||||
WkPaypalCommerceHelper::logMsg(
|
||||
'payment',
|
||||
'PayPal currency mismatch. Expected currency: '.$cartCurrency['iso_code'].', PayPal captured currency: '.$capturedCurrency
|
||||
);
|
||||
}
|
||||
WkPaypalCommerceHelper::logMsg('payment', 'Payment status'. $returnData['data']['status']);
|
||||
WkPaypalCommerceHelper::logMsg('payment', '--------------', true);
|
||||
Tools::redirect('index.php?controller=order&step=1');
|
||||
|
||||
@@ -155,7 +155,7 @@ class AdminFeaturesModuleSettingController extends ModuleAdminController
|
||||
parent::initToolbar();
|
||||
$this->page_header_toolbar_btn['new'] = array(
|
||||
'href' => self::$currentIndex.'&add'.$this->table.'&token='.$this->token,
|
||||
'desc' => $this->l('Add New Hotel Amenity')
|
||||
'desc' => $this->l('Add New Property Amenity')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ class WkHotelFeaturesBlock extends Module
|
||||
public function callInstallTab()
|
||||
{
|
||||
//Controllers which are to be used in this modules but we have not to create tab for those Controllers...
|
||||
$this->installTab('AdminFeaturesModuleSetting', 'Hotel Amenities Configurations');
|
||||
$this->installTab('AdminFeaturesModuleSetting', 'Property Amenities Configurations');
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class WkHotelRoom extends Module
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
array(array('adults' => 1, 'children' => 0, 'child_ages' => array()))
|
||||
);
|
||||
$htlRoom['feature_price'] = $featurePrice;
|
||||
|
||||
@@ -228,12 +228,6 @@
|
||||
</div> {l s='Buy Standalone.'}
|
||||
</label>
|
||||
</div>
|
||||
<label class="control-label">{l s='Select Property'}</label>
|
||||
<select class="chosen input-hotel" name="id_hotel" id="service_id_hotel">
|
||||
{foreach $associated_hotels as $hotel}
|
||||
<option value="{$hotel.id_hotel}" {if isset($service_id_hotel) && $service_id_hotel == $hotel['id_hotel']}selected{elseif $hotel@first}selected{/if}>{$hotel.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
{/block}
|
||||
@@ -241,7 +235,7 @@
|
||||
<div id="hotel_selection_block" {if isset($buying_option) && $buying_option == '2'}style="display: none;"{/if}>
|
||||
{if isset($associated_hotels) && $associated_hotels}
|
||||
<div class="form-group">
|
||||
<label class="control-label">{l s='Select Hotel'}</label>
|
||||
<label class="control-label">{l s='Select Property'}</label>
|
||||
<select class="chosen input-hotel" name="id_hotel" id="service_id_hotel">
|
||||
{foreach $associated_hotels as $hotel}
|
||||
<option value="{$hotel.id_hotel}" {if isset($service_id_hotel) && $service_id_hotel == $hotel['id_hotel']}selected{elseif $hotel@first}selected{/if}>{$hotel.name}</option>
|
||||
|
||||
@@ -94,16 +94,7 @@
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
{if ($product.show_price && !isset($restricted_country_mode)) || isset($groups)}
|
||||
<span class="pull-right">{if !$priceDisplay}{convertPrice price=$product.price_tax_incl}{else}{convertPrice price=$product.price_tax_exc}{/if}
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$product.price_calculation_method,
|
||||
$product.date_from|default:$date_from|default:'',
|
||||
$product.date_to|default:$date_to|default:''
|
||||
) > 1}
|
||||
<span class="price-label">{l s='/Night'}</span>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<span class="pull-right">{if !$priceDisplay}{convertPrice price=$product.price_tax_incl}{else}{convertPrice price=$product.price_tax_exc}{/if}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,13 +66,6 @@
|
||||
<div class="service-product-price">
|
||||
{block name='service_product_price'}
|
||||
{if !$priceDisplay}{convertPrice price=$service_product.price_tax_incl}{else}{convertPrice price=$service_product.price_tax_exc}{/if}
|
||||
{if Product::getServicePriceBillableDays(
|
||||
$service_product.price_calculation_method,
|
||||
$service_product.date_from|default:$date_from|default:'',
|
||||
$service_product.date_to|default:$date_to|default:''
|
||||
) > 1}
|
||||
<span class="price-label">{l s='/Night'}</span>
|
||||
{/if}
|
||||
{/block}
|
||||
{if $service_product.allow_multiple_quantity && $service_product.available_for_order && $service_product.max_quantity > 0}
|
||||
<div class="service-max-quantity-info">
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<div class="row">
|
||||
<div class="{if isset($nationality_mandatory) && $nationality_mandatory}required {/if}form-group col-sm-6">
|
||||
<label for="id_nationality">{l s='Nationality'}{if isset($nationality_mandatory) && $nationality_mandatory} <sup>*</sup>{/if}</label>
|
||||
<select name="id_nationality" id="id_nationality" class="form-control">
|
||||
<select name="id_nationality" id="id_nationality" >
|
||||
<option value="">-</option>
|
||||
{foreach from=$nationality_countries item=c}
|
||||
<option value="{$c.id_country}"{if isset($smarty.post.id_nationality) && $smarty.post.id_nationality == $c.id_country || (isset($guestInformations) && isset($guestInformations.id_nationality) && $guestInformations.id_nationality == $c.id_country)} selected="selected"{/if}>{$c.name|escape:'html':'UTF-8'}</option>
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
{if isset($hotel_dynamic_amenities) && $hotel_dynamic_amenities}
|
||||
<div class="info_margin_div">
|
||||
<div class="room_info_heading">
|
||||
<span>{l s='Hotel Amenities'}</span>
|
||||
<span>{l s='%s Amenities' sprintf=$property_type}</span>
|
||||
</div>
|
||||
<div class="room_info_content row">
|
||||
{foreach from=$hotel_dynamic_amenities item=amenity}
|
||||
|
||||
Reference in New Issue
Block a user