Merge branch 'develop' into gli-1466

This commit is contained in:
Abhishek Kumar
2024-03-15 20:28:34 +05:30
568 changed files with 15454 additions and 12474 deletions

View File

@@ -58,6 +58,8 @@ if ($excludeIds && $excludeIds != 'NaN') {
$excludeVirtuals = (bool)Tools::getValue('excludeVirtuals', true);
$exclude_packs = (bool)Tools::getValue('exclude_packs', true);
$bookingProduct = (int) Tools::getValue('booking_product');
$context = Context::getContext();
$sql = 'SELECT p.`id_product`, pl.`link_rewrite`, p.`reference`, pl.`name`, image_shop.`id_image` id_image, il.`legend`, p.`cache_default_attribute`
@@ -72,6 +74,7 @@ $sql = 'SELECT p.`id_product`, pl.`link_rewrite`, p.`reference`, pl.`name`, imag
(!empty($excludePackItself) ? ' AND p.id_product <> '.$excludePackItself.' ' : ' ').
($excludeVirtuals ? 'AND NOT EXISTS (SELECT 1 FROM `'._DB_PREFIX_.'product_download` pd WHERE (pd.id_product = p.id_product))' : '').
($exclude_packs ? 'AND (p.cache_is_pack IS NULL OR p.cache_is_pack = 0)' : '').
($bookingProduct ? 'AND p.`booking_product` = '.(int) $bookingProduct : '').
' GROUP BY p.id_product';
$items = Db::getInstance()->executeS($sql);

View File

@@ -1,29 +1,29 @@
<?php
/*
* 2010-2022 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through LICENSE.txt file inside our module
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please refer to CustomizationPolicy.txt file inside our module for more information.
*
* @author Webkul IN
* @copyright 2010-2022 Webkul IN
* @license LICENSE.txt
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../../');
exit;
<?php
/**
* 2010-2023 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through this link for complete license : https://store.webkul.com/license.html
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to 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 <support@webkul.com>
* @copyright 2010-2023 Webkul IN
* @license https://store.webkul.com/license.html
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../../../');
exit;

View File

@@ -0,0 +1 @@
.dashboard-chart-tooltip{background-color:#333;padding:0px 10px 10px 10px;color:#fff;min-width:100px}.dashboard-chart-tooltip label{display:flex;align-items:baseline;gap:5px;font-weight:bold;padding-top:10px}.dashboard-chart-tooltip .tooltip-content{margin-top:5px}.dashboard-chart-tooltip .tooltip-content p{display:flex;align-items:baseline;gap:5px;text-align:left;padding-left:5px}.dashboard-chart-tooltip .tooltip-data-color{display:flex;flex-direction:column;align-items:baseline;padding:5px;max-width:2px}.dashboard-chart-tooltip .text-danger{color:#FF655C}.dashboard-chart-tooltip .text-success{color:#56CE56}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -106,6 +106,7 @@
@import "partials/ladda"
@import "partials/date-picker"
@import "partials/select2"
@import "partials/ndv3"
//Backward compatibility
@import "partials/backward"

View File

@@ -132,6 +132,12 @@
.data_value
display: block
text-align: center
.nv-axis.nv-x .tick line, .nv-axis.nv-y .tick line, .nv-interactive .nv-interactiveGuideLine line
display: none
.nvd3.nv-pie path
fill-opacity: 1
.nv-label text
fill: #FFF!important
#dashgoals
svg

View File

@@ -4,10 +4,20 @@
#customization_list
border: 0px
.booking_occupancy_edit, .booking_occupancy
.occupancy-info-separator
margin-top: 0px
margin-bottom: 10px
.close_occupancy
text-decoration: underline
.booking_occupancy
.booking_occupancy_wrapper
max-height: 250px
overflow-x: auto
label.room_num_wrapper
text-decoration: underline
margin-bottom: 10px
#booking-documents-modal
.documents-list
@@ -16,3 +26,23 @@
img
max-height: 55px
max-width: 55px
.loading_overlay
display: none
position: fixed
left: 0
top: 0
height: 100%
width: 100%
background-color: rgba(0, 0, 0, 0.5)
z-index: 100000
.loading-img
position: absolute
top: 50%
left: 0
right: 0
margin: 0 auto
.room_status_info_form
.room_status
white-space: normal

View File

@@ -64,7 +64,7 @@ $sidebar-menu-hover-color: white !default
$sidebar-menu-bg-hover-color: #282b30
// Toolbar
$toolbar-buttons-color: #2eacce
$toolbar-buttons-color: #00aff0
$toolbar-buttons-hover-color: #40c9ed
// Scaffolding

View File

@@ -200,6 +200,8 @@ $chosen-sprite-path: '../img/chosen-sprite.png'
input
position: absolute
@include left(-9000px)
&:before
visibility: hidden
.chosen-container-multi
.chosen-choices
@@ -227,6 +229,7 @@ $chosen-sprite-path: '../img/chosen-sprite.png'
border: 0 !important
color: $gray
height: $chosen-multi-height - 8px
width: 100% !important
margin: 0
padding: 4px
outline: 0
@@ -295,6 +298,15 @@ $chosen-sprite-path: '../img/chosen-sprite.png'
.search-field input
color: #111 !important
.chosen-container-multi.chosen-options-horizontal .chosen-choices
max-height: 55px !important
white-space: nowrap
overflow-x: auto
.chosen-container-multi.chosen-options-horizontal .chosen-choices li
float: none
display: inline-block
.chosen-disabled
cursor: default
opacity: 0.5 !important
@@ -341,4 +353,7 @@ $chosen-sprite-path: '../img/chosen-sprite.png'
.chosen-search input
background: url($chosen-sprite-path) no-repeat -28px -20px, $chosen-background
direction: rtl
padding: 4px 5px 4px 20px
padding: 4px 5px 4px 20px
#list_filters_panel .chosen-container
width: 100% !important

View File

@@ -16,7 +16,7 @@ body
@include float(left)
#content.bootstrap
padding: 120px 10px 0
padding: 90px 10px 0
@include transition-property(margin)
@include transition-duration(0.4s)
@include transition-timing-function(ease-out)

View File

@@ -311,7 +311,7 @@
@extend .icon-cogs
.icon-AdminAdmin
@extend .icon-cog
.icon-AdminParentStats
.icon-AdminStats
@extend .icon-bar-chart
.icon-AdminStock
@extend .icon-archive
@@ -362,7 +362,7 @@
@extend .icon-edit
.process-icon-newAttributes, .process-icon-new, .process-icon-new-url
@extend .icon-plus-sign
.process-icon-modules-list
.process-icon-modules-list, .process-icon-puzzle-piece
@extend .icon-puzzle-piece
.process-icon-save-date
@extend .icon-download

View File

@@ -268,6 +268,11 @@ $min-height: 850px
width: 200px
@include margin-right(5px)
@include float(right)
.clear_search
position: absolute
top: 6px
z-index: 10
@include right(8px)
li.maintab, li.subtab
height: 28px
padding: 0

View File

@@ -1,6 +1,6 @@
.page-head
width: 100%
height: 100px
height: 78px
padding: 0
margin: 0
position: fixed
@@ -14,10 +14,11 @@
@include float(left)
position: relative
margin: 0
font: 20pt $font-family-sans-serif
font: 14pt $font-family-sans-serif
font-weight: bold
color: #363A41
white-space: nowrap
@include padding(26px, 0, 0, ($widthSidebarNav+20px))
@include padding(31px, 0, 0, ($widthSidebarNav+20px))
@media (max-width: $screen-tablet)
@include padding(26px, 0, 0, 70px)
a
@@ -40,6 +41,7 @@
position: absolute
background-color: transparent!important
@include right(0)
top: 18px
@media (max-width: $screen-sm)
#toolbar-nav
border: none
@@ -48,37 +50,54 @@
@include padding(3px, 0, 0, 0)
.toolbar_btn
position: relative
padding: 20px 5px !important
padding: 10px 10px !important
font-size: 12px
line-height: 8px
color: $main-color
color: $toolbar-buttons-color
text-align: center
text-shadow: none
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
border: 1px solid $toolbar-buttons-color
border-radius: 2px
@include margin(0, 3px, 2px, 0)
@media (max-width: $screen-desktop)
width: 46px
font-size: 11px
div
color: #363A41
i
color: $toolbar-buttons-color
display: inline
font-size: 18px
&:hover
color: $toolbar-buttons-hover-color
div
padding-top: 10px
span
position: relative
top: -2px
left: 2px
color: #363A41
font-weight: 400
.dropdown-toolbar
display: none
@include float(right)
@include border-radius(3px)
@media (max-width: $screen-sm)
display: block
padding: 6px 10px !important
margin-right: 10px
@media (max-width: $screen-xs)
margin-right: 5px
#toolbar-nav
li + li
margin-left: 8px
ul.page-breadcrumb
position: absolute
list-style: none
margin: 0
padding: 0
top: 4px
top: 9px
height: 20px
line-height: 20px
color: black

View File

@@ -0,0 +1,29 @@
.dashboard-chart-tooltip
background-color: #333
padding: 0px 10px 10px 10px
color: #fff
min-width: 100px
label
display: flex
align-items: baseline
gap: 5px
font-weight: bold
padding-top: 10px
.tooltip-content
margin-top: 5px
.tooltip-content p
display: flex
align-items: baseline
gap: 5px
text-align: left
padding-left: 5px
.tooltip-data-color
display: flex
flex-direction: column
align-items: baseline
padding: 5px
max-width: 2px
.text-danger
color: #FF655C
.text-success
color: #56CE56

View File

@@ -84,7 +84,7 @@
<i class="icon-info"></i>
{l s='Server information'}
</h3>
{if count($uname)}
{if Tools::strlen($uname) > 0}
<p>
<strong>{l s='Server information:'}</strong> {$uname|escape:'html':'UTF-8'}
</p>

View File

@@ -36,7 +36,7 @@
<div class="panel">
<div class="row">
<div class="col-lg-3 col-md-4 col-sm-12 col-xs-12">
<img class="img-responsive" alt="PrestaShop Addons" src="themes/default/img/prestashop-addons-logo.png">
<img class="img-responsive" alt="QloApps Addons" src="themes/default/img/prestashop-addons-logo.png">
</div>
<div class="col-lg-4 col-lg-offset-1 col-md-4 col-sm-7 col-xs-12 addons-style-search-bar">
<form id="addons-search-form" method="get" action="http://addons.prestashop.com/{$iso_code}/search" class="float">
@@ -64,7 +64,7 @@
<div class="form-wrapper">
<div class="form-group">
<p>{l s='To add a new module, simply connect to your PrestaShop Addons account and all your purchases will be automatically imported.'}</p>
<p>{l s='To add a new module, simply connect to your QloApps Addons account and all your purchases will be automatically imported.'}</p>
</div>
</div><!-- /.form-wrapper -->
@@ -82,7 +82,7 @@
<div class="alert alert-info">
<h4>{l s='Can I add my own modules?'}</h4>
<p>{l s='Please note that for security reasons, you can only add modules that are being distributed on PrestaShop Addons, the official marketplace.'}</p>
<p>{l s='Please note that for security reasons, you can only add modules that are being distributed on QloApps Addons, the official marketplace.'}</p>
</div>
</div>

View File

@@ -49,7 +49,7 @@
<li>
<a id="desc-module-update-all" class="toolbar_btn" href="{$currentIndex|escape:'html':'UTF-8'}&amp;token={$token|escape:'html':'UTF-8'}&amp;updateAll=1" title="{l s='Update all'}">
<i class="process-icon-refresh"></i>
<div>{l s='Update all'}</div>
<span>{l s='Update all'}</span>
</a>
</li>
{/if}
@@ -57,30 +57,32 @@
<li>
<a id="desc-module-check-and-update-all" class="toolbar_btn" href="{$currentIndex|escape:'html':'UTF-8'}&amp;token={$token|escape:'html':'UTF-8'}&amp;check=1" title="{l s='Check for update'}">
<i class="process-icon-refresh"></i>
<div>{l s='Check for update'}</div>
<span>{l s='Check for update'}</span>
</a>
</li>
{/if}
<li>
<a id="desc-module-catalog" class="toolbar_btn anchor" href="{$link->getAdminLink('AdminModulesCatalog')}" title="{l s='Recommended Modules and Services'}">
<i class="process-icon-modules-list"></i>
<div>{l s='Recommended Modules and Services'}</div>
</a>
</li>
{if $add_permission eq '1' && ($context_mode != Context::MODE_HOST)}
<li>
<a id="desc-module-new" class="toolbar_btn anchor" href="#" onclick="$('#module_install').slideToggle();" title="{l s='Add a new module'}">
<i class="process-icon-new"></i>
<div>{l s='Add a new module'}</div>
</a>
</li>
{else}
<li>
<a id="desc-module-new" class="toolbar_btn" href="{$link->getAdminLink('AdminModules')}&addnewmodule" title="{l s='Add a new module'}">
<i class="process-icon-new"></i>
<div>{l s='Add a new module'}</div>
<span>{l s='Recommended Modules and Services'}</span>
</a>
</li>
{if $add_permission eq '1'}
{if $context_mode != Context::MODE_HOST}
<li>
<a id="desc-module-new" class="toolbar_btn anchor" href="#" onclick="$('#module_install').slideToggle();" title="{l s='Add a new module'}">
<i class="process-icon-new"></i>
<span>{l s='Add a new module'}</span>
</a>
</li>
{else}
<li>
<a id="desc-module-new" class="toolbar_btn" href="{$link->getAdminLink('AdminModules')}&addnewmodule" title="{l s='Add a new module'}">
<i class="process-icon-new"></i>
<span>{l s='Add a new module'}</span>
</a>
</li>
{/if}
{/if}
{if isset($help_link)}
{* <li>

View File

@@ -391,7 +391,7 @@
</div>
</div>
<div id="allow_multiple_quantity_container" {if (!$product->available_for_order && $product->isAssociatedToShop()) || $product->auto_add_to_cart}style="display:none;"{/if}>
<div id="allow_multiple_quantity_container" {if $product->auto_add_to_cart && $product->isAssociatedToShop()}style="display:none;"{/if}>
<div class="form-group">
<label class="control-label col-lg-3">
<span class="label-tooltip" data-toggle="tooltip" title="{l s='When enabled, customer can order multiple quantity of product otherwise only one quantity can be purchased by customer per room/hotel'}">
@@ -412,7 +412,7 @@
</span>
</div>
</div>
<div id="max_quantity_container" class="form-group" {if (!$product->available_for_order && $product->isAssociatedToShop()) || $product->auto_add_to_cart || !$product->allow_multiple_quantity}style="display:none;"{/if}>
<div id="max_quantity_container" class="form-group" {if ($product->auto_add_to_cart && $product->isAssociatedToShop()) || !$product->allow_multiple_quantity}style="display:none;"{/if}>
<label class="control-label col-lg-3" for="max_quantity">
<span class="label-tooltip" data-toggle="tooltip"
title="{l s='Enter max allowed quantity per room, enter 0 for unlimited.'}">

View File

@@ -395,7 +395,7 @@ $(document).ready(function () {
<div class="col-lg-9">
<div class="row">
{if !$multi_shop}
<input type="hidden" name="sp_id_shop" value="0" />
<input type="hidden" name="sp_id_shop" value="1" />
{else}
<div class="col-lg-3">
<select name="sp_id_shop" id="sp_id_shop">

View File

@@ -134,7 +134,10 @@
<p>{$product['name']|escape:'html':'UTF-8'}</p>
{if $product.allow_multiple_quantity}
<div class="qty_container">
<input type="number" class="form-control room_type_service_product_qty qty" id="qty_{$product.id_product}" name="service_product_qty_{$product.id_product}" data-id-product="{$product.id_product}" min="1" value="{if isset($selectedRoomServiceProduct['selected_service']) && $selectedRoomServiceProduct['selected_service'] && ($product['id_product']|array_key_exists:$selectedRoomServiceProduct['selected_service'])}{$selectedRoomServiceProduct['selected_service'][$product['id_product']]['quantity']}{else}1{/if}">
<input type="number" class="form-control room_type_service_product_qty qty" id="qty_{$product.id_product}" name="service_product_qty_{$product.id_product}" data-id-product="{$product.id_product}" min="1" data-max-quantity="{$product.max_quantity}" value="{if isset($selectedRoomServiceProduct['selected_service']) && $selectedRoomServiceProduct['selected_service'] && ($product['id_product']|array_key_exists:$selectedRoomServiceProduct['selected_service'])}{$selectedRoomServiceProduct['selected_service'][$product['id_product']]['quantity']}{else}1{/if}">
<p style="display:{if isset($selectedRoomServiceProduct['selected_service']) && $selectedRoomServiceProduct['selected_service'] && ($product['id_product']|array_key_exists:$selectedRoomServiceProduct['selected_service']) && $selectedRoomServiceProduct['selected_service'][$product['id_product']]['quantity'] > $product.max_quantity}block{else}none{/if}; margin-top: 4px;">
<span class="label label-warning">{l s='Maximum allowed quantity: %s' sprintf=$product.max_quantity}</span>
</p>
</div>
{/if}
</div>

View File

@@ -46,7 +46,7 @@
{assign var=curr_id value=$cart->id_currency|intval}
{foreach from=$cart_detail_data item=data}
<tr data-id-booking-data="{$data.id}" data-id-product="{$data.id_product}" data-id-room="{$data.id_room}" data-date-from="{$data.date_from}" data-date-to="{$data.date_to}" >
<td>{$data.room_num|escape:'html':'UTF-8'}</td>
<td>{$data.room_num|escape:'html':'UTF-8'} {hook h='displayRoomNumAfter' data=$data type='adminOrder'}</td>
<td><img src="{$data.image_link|escape:'html':'UTF-8'}" title="Room image" /></td>
<td>
<p>{$data.room_type|escape:'html':'UTF-8'}</p>

View File

@@ -43,97 +43,70 @@
</thead>
<tbody>
{foreach from=$order->getDocuments() item=document}
{if get_class($document) eq 'OrderInvoice'}
{if isset($document->is_delivery)}
<tr id="delivery_{$document->id}">
{else}
<tr id="invoice_{$document->id}">
{/if}
{elseif get_class($document) eq 'OrderSlip'}
<tr id="orderslip_{$document->id}">
{/if}
<td>{dateFormat date=$document->date_add}</td>
<td>
{if get_class($document) eq 'OrderInvoice'}
{if isset($document->is_delivery)}
{l s='Delivery slip'}
{else}
{l s='Invoice'}
{/if}
{elseif get_class($document) eq 'OrderSlip'}
{l s='Credit Slip'}
{/if}
</td>
<td>
{if get_class($document) eq 'OrderInvoice'}
{if isset($document->is_delivery)}
<a class="_blank" title="{l s='See the document'}" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateDeliverySlipPDF&amp;id_order_invoice={$document->id}">
{else}
<a class="_blank" title="{l s='See the document'}" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateInvoicePDF&amp;id_order_invoice={$document->id}">
{/if}
{elseif get_class($document) eq 'OrderSlip'}
<a class="_blank" title="{l s='See the document'}" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateOrderSlipPDF&amp;id_order_slip={$document->id}">
{/if}
{if get_class($document) eq 'OrderInvoice'}
{if isset($document->is_delivery)}
{Configuration::get('PS_DELIVERY_PREFIX', $current_id_lang, null, $order->id_shop)}{'%06d'|sprintf:$document->delivery_number}
{else}
{$document->getInvoiceNumberFormatted($current_id_lang, $order->id_shop)}
{/if}
{elseif get_class($document) eq 'OrderSlip'}
{Configuration::get('PS_CREDIT_SLIP_PREFIX', $current_id_lang)}{'%06d'|sprintf:$document->id}
{/if}
</a>
</td>
<td>
<td>{dateFormat date=$document->date_add}</td>
<td>
{if get_class($document) eq 'OrderInvoice'}
{if isset($document->is_delivery)}
--
{else}
{displayPrice price=$document->total_paid_tax_incl currency=$currency->id}&nbsp;
{if $document->getTotalPaid()}
<span>
{if $document->getRestPaid() > 0}
({displayPrice price=$document->getRestPaid() currency=$currency->id} {l s='not paid'})
{elseif $document->getRestPaid() < 0}
({displayPrice price=-$document->getRestPaid() currency=$currency->id} {l s='overpaid'})
{/if}
</span>
{/if}
{/if}
{l s='Invoice'}
{elseif get_class($document) eq 'OrderSlip'}
{displayPrice price=$document->total_products_tax_incl+$document->total_shipping_tax_incl currency=$currency->id}
{l s='Credit Slip'}
{/if}
</td>
<td class="text-right document_action">
</td>
<td>
{if get_class($document) eq 'OrderInvoice'}
{if !isset($document->is_delivery)}
{if $document->getRestPaid()}
<a href="#form_add_payment_panel" class="js-set-payment btn btn-default anchor" data-amount="{$document->getRestPaid()}" data-id-invoice="{$document->id}" title="{l s='Set payment form'}">
<i class="icon-money"></i>
{l s='Enter payment'}
</a>
{/if}
<a href="#" class="btn btn-default" onclick="$('#invoiceNote{$document->id}').show(); return false;" title="{if $document->note eq ''}{l s='Add note'}{else}{l s='Edit note'}{/if}">
{if $document->note eq ''}
<i class="icon-plus-sign-alt"></i>
{l s='Add note'}
{else}
<i class="icon-pencil"></i>
{l s='Edit note'}
{/if}
</a>
{/if}
<a class="_blank" title="{l s='See the document'}" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateInvoicePDF&amp;id_order_invoice={$document->id}">
{elseif get_class($document) eq 'OrderSlip'}
<a class="_blank" title="{l s='See the document'}" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateOrderSlipPDF&amp;id_order_slip={$document->id}">
{/if}
</td>
</tr>
{if get_class($document) eq 'OrderInvoice'}
{$document->getInvoiceNumberFormatted($current_id_lang, $order->id_shop)}
{elseif get_class($document) eq 'OrderSlip'}
{Configuration::get('PS_CREDIT_SLIP_PREFIX', $current_id_lang)}{'%06d'|sprintf:$document->id}
{/if}
</a>
</td>
<td>
{if get_class($document) eq 'OrderInvoice'}
{displayPrice price=$document->total_paid_tax_incl currency=$currency->id}&nbsp;
{if $document->getTotalPaid()}
<span>
{if $document->getRestPaid() > 0}
({displayPrice price=$document->getRestPaid() currency=$currency->id} {l s='not paid'})
{elseif $document->getRestPaid() < 0}
({displayPrice price=-$document->getRestPaid() currency=$currency->id} {l s='overpaid'})
{/if}
</span>
{/if}
{elseif get_class($document) eq 'OrderSlip'}
{displayPrice price=$document->total_products_tax_incl+$document->total_shipping_tax_incl currency=$currency->id}
{/if}
</td>
<td class="text-right document_action">
{if get_class($document) eq 'OrderInvoice'}
{if $document->getRestPaid()}
<a href="#form_add_payment_panel" class="js-set-payment btn btn-default anchor" data-amount="{$document->getRestPaid()}" data-id-invoice="{$document->id}" title="{l s='Set payment form'}">
<i class="icon-money"></i>
{l s='Enter payment'}
</a>
{/if}
<a href="#" class="btn btn-default" onclick="$('#invoiceNote{$document->id}').show(); return false;" title="{if $document->note eq ''}{l s='Add note'}{else}{l s='Edit note'}{/if}">
{if $document->note eq ''}
<i class="icon-plus-sign-alt"></i>
{l s='Add note'}
{else}
<i class="icon-pencil"></i>
{l s='Edit note'}
{/if}
</a>
{/if}
</td>
</tr>
{if get_class($document) eq 'OrderInvoice'}
{if !isset($document->is_delivery)}
<tr id="invoiceNote{$document->id}" style="display:none">
<td colspan="5">
<form action="{$current_index}&amp;viewOrder&amp;id_order={$order->id}{if isset($smarty.get.token)}&amp;token={$smarty.get.token|escape:'html':'UTF-8'}{/if}" method="post">
@@ -155,7 +128,6 @@
</form>
</td>
</tr>
{/if}
{/if}
{foreachelse}
<tr>

View File

@@ -0,0 +1,25 @@
{**
* 2010-2024 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through LICENSE.txt file inside our module
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please refer to CustomizationPolicy.txt file inside our module for more information.
*
* @author Webkul IN
* @copyright 2010-2024 Webkul IN
* @license LICENSE.txt
*}
{if is_array($hotel_rooms_info) && count($hotel_rooms_info)}
<option value="" selected="selected">-</option>
{foreach from=$hotel_rooms_info item=hotel_room}
<option value="{$hotel_room.id}">{$hotel_room.room_num}, {$hotel_room.room_type_name}, {$hotel_room.hotel_name}</option>
{/foreach}
{/if}

View File

@@ -0,0 +1,25 @@
{**
* 2010-2024 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through LICENSE.txt file inside our module
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please refer to CustomizationPolicy.txt file inside our module for more information.
*
* @author Webkul IN
* @copyright 2010-2024 Webkul IN
* @license LICENSE.txt
*}
{if is_array($room_types_info) && count($room_types_info)}
<option value="" selected="selected">-</option>
{foreach from=$room_types_info item=room_type}
<option value="{$room_type.id_product}">{$room_type.room_type}, {$room_type.hotel_name}</option>
{/foreach}
{/if}

View File

@@ -74,9 +74,6 @@
<input type="hidden" class="max_avail_type_qty" value="">
<div class="dropdown-menu booking_occupancy_wrapper fixed-width-xxl well well-sm">
<div class="booking_occupancy_inner">
<input type="hidden" class="max_adults" value="">
<input type="hidden" class="max_children" value="">
<input type="hidden" class="max_guests" value="">
<div class="occupancy_info_block col-sm-12" occ_block_index="0">
<div class="occupancy_info_head col-sm-12"><label class="room_num_wrapper">{l s='Room - 1'}</label></div>
<div class="col-sm-12">
@@ -87,7 +84,7 @@
</div>
<div class="form-group col-xs-6 occupancy_count_block">
<label>{l s='Child'} <span class="label-desc-txt"></span></label>
<input type="number" class="form-control num_occupancy num_children" name="occupancy[0][children]" value="0" min="0" {if $max_child_in_room}max="{$max_child_in_room}"{/if}>
<input type="number" class="form-control num_occupancy num_children" name="occupancy[0][children]" value="0" min="0">
({l s='Below'} {$max_child_age|escape:'htmlall':'UTF-8'} {l s='years'})
</div>
</div>
@@ -101,12 +98,13 @@
</div>
</div>
</div>
<hr class="occupancy-info-separator col-sm-12">
</div>
</div>
<div class="add_occupancy_block">
<a class="add_new_occupancy_btn" href="#"><i class="icon-plus"></i> <span>{l s='Add Room'}</span></a>
</div>
<hr class="occupancy-info-separator col-sm-12">
<div class="add_occupancy_block col-sm-12">
<a class="add_new_occupancy_btn" href="#"><i class="icon-plus"></i> <span>{l s='Add Room'}</span></a>
<a class="pull-right close_occupancy_link" href="#">{l s='close'} <i class="icon-remove"></i></a>
</div>
</div>
</div>
</div>

View File

@@ -32,10 +32,10 @@
</a>
{/if}
{* Generate HTML code for printing Delivery Icon with link *}
{if $order->delivery_number}
{* {if $order->delivery_number}
<a class="btn btn-default _blank" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&amp;submitAction=generateDeliverySlipPDF&amp;id_order={$order->id}">
<i class="icon-truck"></i>
</a>
{/if}
{/if} *}
</span>
</span>

View File

@@ -23,10 +23,10 @@
* International Registered Trademark & Property of PrestaShop SA
*}
<tr class="product-line-row" data-id_room="{$data.id_room}" data-id_product="{$data.id_product}" data-id_hotel="{$data.id_hotel}" data-date_from="{$data.date_from}" data-date_to="{$data.date_to}" data-product_price="{$data.unit_amt_tax_incl}" data-id_order_detail="{$data.id_order_detail}">
<tr class="product-line-row" data-id_htl_booking="{$data.id|escape:'html':'UTF-8'}" data-id_room="{$data.id_room}" data-id_product="{$data.id_product}" data-id_hotel="{$data.id_hotel}" data-date_from="{$data.date_from}" data-date_to="{$data.date_to}" data-product_price="{$data.unit_amt_tax_incl}" data-id_order_detail="{$data.id_order_detail}">
{if $refund_allowed}
<td class="standard_refund_fields" style="display:none">
<input type="checkbox" name="id_htl_booking[]" value="{$data.id|escape:'html':'UTF-8'}" {if isset($refundReqBookings) && ($data.id|in_array:$refundReqBookings)}disabled{/if}/>
<input type="checkbox" name="id_htl_booking[]" value="{$data.id|escape:'html':'UTF-8'}" {if (isset($refundReqBookings) && ($data.id|in_array:$refundReqBookings)) || $data.is_refunded}disabled{/if}/>
</td>
{/if}
<td class="text-center">
@@ -79,7 +79,7 @@
{/if}
</td>
<td class="text-center">
{if $order->with_occupancy && $data['children']}
{if $data['children']}
<div class="dropdown booking_occupancy_show">
<button class="btn btn-default btn-left btn-block" data-toggle="dropdown" type="button">
<span>{if $data['adults']}{$data['adults']}{/if} {if $data['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$data['children']}}, {$data['children']} {if $data['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}</span>
@@ -98,67 +98,63 @@
{else}
<span class="booking_occupancy_show">{if $data['adults']}{$data['adults']}{/if} {if $data['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$data['children']}}, {$data['children']} {if $data['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}</span>
{/if}
{if $order->with_occupancy}
<div class="booking_occupancy_edit" style="display:none;">
<div class="dropdown">
<button class="booking_guest_occupancy btn btn-default btn-left btn-block input-occupancy" type="button">
<span>
{if $data['adults']}{$data['adults']}{/if} {if $data['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$data['children']}}, {$data['children']} {if $data['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}
</span>
</button>
<div class="dropdown-menu booking_occupancy_wrapper fixed-width-xxl well well-sm">
<div class="booking_occupancy_inner">
<input type="hidden" class="max_adults" value="{if isset($data['room_type_info'])}{$data['room_type_info']['max_adults']|escape:'html':'UTF-8'}{/if}">
<input type="hidden" class="max_children" value="{if isset($data['room_type_info'])}{$data['room_type_info']['max_children']|escape:'html':'UTF-8'}{/if}">
<input type="hidden" class="max_guests" value="{if isset($data['room_type_info'])}{$data['room_type_info']['max_guests']|escape:'html':'UTF-8'}{/if}">
<div class="occupancy_info_block" occ_block_index="0">
<div class="occupancy_info_head col-sm-12"><span class="room_num_wrapper">{l s='Room - 1'}</span></div>
<div class="row">
<div class="col-xs-6 occupancy_count_block">
<div class="col-sm-12">
<label>{l s='Adults'}</label>
<input type="number" class="form-control num_occupancy num_adults" name="occupancy[0][adults]" value="{$data['adults']}" min="1" max="{$data['room_type_info']['max_adults']|escape:'html':'UTF-8'}">
</div>
</div>
<div class="col-xs-6 occupancy_count_block">
<div class="col-sm-12">
<label>{l s='Child'} <span class="label-desc-txt"></span></label>
<input type="number" class="form-control num_occupancy num_children" name="occupancy[0][children]" value="{$data['children']}" min="0" max="{$data['room_type_info']['max_children']|escape:'html':'UTF-8'}">
({l s='Below'} {$max_child_age|escape:'htmlall':'UTF-8'} {l s='years'})
</div>
</div>
</div>
<div class="row children_age_info_block" {if !isset($data['child_ages']) || !$data['child_ages']}style="display:none"{/if}>
<div class="col-sm-12">
<label class="col-sm-12">{l s='All Children'}</label>
<div class="col-sm-12">
<div class="row children_ages">
{if isset($data['child_ages']) && $data['child_ages']}
{foreach $data['child_ages'] as $childAge}
<p class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
<select class="guest_child_age room_occupancies" name="occupancy[0][child_ages][]">
<option value="-1" {if $childAge == -1}selected{/if}>{l s='Select 1'}</option>
<option value="0" {if $childAge == 0}selected{/if}>{l s='Under 1'}</option>
{for $age=1 to ($max_child_age-1)}
<option value="{$age|escape:'htmlall':'UTF-8'}" {if $childAge == $age}selected{/if}>{$age|escape:'htmlall':'UTF-8'}</option>
{/for}
</select>
</p>
{/foreach}
{/if}
</div>
</div>
</div>
</div>
<hr class="occupancy-info-separator">
</div>
</div>
</div>
</div>
</div>
{else}
<span class="booking_occupancy_edit" style="display:none;">{if $data['adults']}{$data['adults']}{/if} {if $data['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$data['children']}}, {$data['children']} {if $data['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}</span>
{/if}
<div class="booking_occupancy_edit" style="display:none;">
<div class="dropdown">
<button class="booking_guest_occupancy btn btn-default btn-left btn-block input-occupancy" type="button">
<span>
{if $data['adults']}{$data['adults']}{/if} {if $data['adults'] > 1}{l s='Adults'}{else}{l s='Adult'}{/if}{if {$data['children']}}, {$data['children']} {if $data['children'] > 1}{l s='Children'}{else}{l s='Child'}{/if}{/if}
</span>
</button>
<div class="dropdown-menu booking_occupancy_wrapper fixed-width-xxl well well-sm">
<div class="booking_occupancy_inner row">
<div class="occupancy_info_block col-sm-12" occ_block_index="0">
<div class="row">
<div class="col-xs-6 form-group occupancy_count_block">
<div class="col-sm-12">
<label>{l s='Adults'}</label>
<input type="number" class="form-control num_occupancy num_adults" name="occupancy[0][adults]" value="{$data['adults']}" min="1">
</div>
</div>
<div class="col-xs-6 form-group occupancy_count_block">
<div class="col-sm-12">
<label>{l s='Child'} <span class="label-desc-txt"></span></label>
<input type="number" class="form-control num_occupancy num_children" name="occupancy[0][children]" value="{$data['children']}" min="0">
({l s='Below'} {$max_child_age|escape:'htmlall':'UTF-8'} {l s='years'})
</div>
</div>
</div>
<div class="row children_age_info_block" {if !isset($data['child_ages']) || !$data['child_ages']}style="display:none"{/if}>
<div class="col-sm-12 form-group">
<label class="col-sm-12">{l s='All Children'}</label>
<div class="col-sm-12">
<div class="row children_ages">
{if isset($data['child_ages']) && $data['child_ages']}
{foreach $data['child_ages'] as $childAge}
<p class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
<select class="guest_child_age room_occupancies" name="occupancy[0][child_ages][]">
<option value="-1" {if $childAge == -1}selected{/if}>{l s='Select 1'}</option>
<option value="0" {if $childAge == 0}selected{/if}>{l s='Under 1'}</option>
{for $age=1 to ($max_child_age-1)}
<option value="{$age|escape:'htmlall':'UTF-8'}" {if $childAge == $age}selected{/if}>{$age|escape:'htmlall':'UTF-8'}</option>
{/for}
</select>
</p>
{/foreach}
{/if}
</div>
</div>
</div>
</div>
<hr class="occupancy-info-separator col-sm-12">
<div class="col-sm-12">
<a class="pull-right close_occupancy_link" href="#">{l s='close'} <i class="icon-remove"></i></a>
</div>
</div>
</div>
</div>
</div>
</div>
</td>
<td class="text-center">
<span class="room_unit_price_show">
@@ -182,7 +178,7 @@
<td class="text-center">
<span class="extra_service_show">
{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_price_te'] + $data['additional_services_price_te'] + $data['convenience_fee_te'] + $data['additional_services_price_auto_add_te']) > 0}
{if $data['extra_demands']|count || $data['additional_services']|count}
<a href="#" data-toggle="modal" data-target="#rooms_type_extra_demands" date_from="{$data['date_from']}" date_to="{$data['date_to']}" id_product="{$data['id_product']}" id_room="{$data['id_room']}" id_order="{$order->id}" class="open_room_extra_services" id_htl_booking="{$data['id']}">
<i class="icon icon-lg icon-info-circle"></i>
</a>
@@ -263,9 +259,9 @@
</button>
<ul class="dropdown-menu" role="menu">
<li>
<a href="#" data-toggle="modal" data-target="#mySwappigModal" data-id_order="{$order->id}" data-room_num='{$data.room_num}' data-date_from='{$data.date_from}' data-date_to='{$data.date_to}' data-id_room='{$data.id_room}' data-cust_name='{$data.alloted_cust_name}' data-cust_email='{$data.alloted_cust_email}' data-avail_rm_swap='{$data.avail_rooms_to_swap|@json_encode}' data-avail_rm_realloc='{$data.avail_rooms_to_realloc|@json_encode}'>
<a href="#" id="reallocate_room_{$data['id']}" data-room_type_name="{$data['room_type_name']}" data-toggle="modal" data-target="#mySwappigModal" data-id_htl_booking="{$data['id']}" data-room_num='{$data.room_num}' data-id_room_type='{$data.id_product}' data-cust_name='{$data.alloted_cust_name}' data-cust_email='{$data.alloted_cust_email}' data-avail_rm_swap='{$data.avail_rooms_to_swap|@json_encode}' data-avail_realloc_room_types='{$data.avail_room_types_to_realloc|@json_encode}'>
<i class="icon-refresh"></i>
{l s='Reallocate Room'}
{l s='Reallocate/Swap Room'}
</a>
</li>
<li>
@@ -287,4 +283,4 @@
</button>
</td>
{/if}
</tr>
</tr>

View File

@@ -53,10 +53,13 @@
<span class="badge badge-info label">{l s='Convenience fee'}</span>
{/if}
</td>
<td>
<td class="col-sm-4">
{if $service['allow_multiple_quantity']}
<div class="qty_container">
<input type="number" class="form-control qty" min="1" data-id_room_type_service_product_order_detail="{$service['id_room_type_service_product_order_detail']}" data-id_product="{$service['id_product']|escape:'html':'UTF-8'}" value="{$service['quantity']|escape:'html':'UTF-8'}">
<input type="number" class="form-control qty" min="1" data-max-quantity="{$service['max_quantity']}" data-id_room_type_service_product_order_detail="{$service['id_room_type_service_product_order_detail']}" data-id_product="{$service['id_product']|escape:'html':'UTF-8'}" value="{$service['quantity']|escape:'html':'UTF-8'}">
<p style="display:{if $service['quantity'] > $service['max_quantity']}block{else}none{/if}; margin-top: 4px;">
<span class="label label-warning">{l s='Maximum allowed quantity: %s' sprintf=$service['max_quantity']}</span>
</p>
</div>
{else}
--

View File

@@ -21,7 +21,7 @@
<th class="text-center"><span class="title_box">{l s='Refunded amount'}</span></th>
{/if}
{if ($can_edit && !$order->hasBeenDelivered())}
<th class="text-center fixed-width-lg"><span class="title_box">{l s='Edit Order'}</th>
<th class="text-center fixed-width-lg"><span class="title_box">{l s='Edit Order'}</th>
{/if}
</tr>
</thead>
@@ -32,9 +32,14 @@
{include file='controllers/orders/_product_line.tpl'}
{/foreach}
{else}
{* <tr>
<td>{l s='No Data Found.'}</td>
</tr> *}
<tr>
<td class="list-empty" colspan="14">
<div class="list-empty-msg">
<i class="icon-warning-sign list-empty-icon"></i>
{l s='No rooms found'}
</div>
</td>
</tr>
{/if}
{* Include product line partial *}
{include file='controllers/orders/_new_product.tpl'}

View File

@@ -98,6 +98,7 @@
selectFirst: false,
scroll: false,
dataType: "json",
cacheLength: 0,
formatItem: function(data, i, max, value, term) {
return value;
},
@@ -115,7 +116,8 @@
ajax: "1",
token: "{getAdminToken tab='AdminCartRules'}",
tab: "AdminCartRules",
action: "searchCartRuleVouchers"
action: "searchCartRuleVouchers",
id_customer: function () { return window.id_customer },
}
}
)
@@ -808,7 +810,9 @@
ajax: "1",
tab: "AdminCustomers",
action: "searchCustomers",
customer_search: $('#customer').val()},
customer_search: $('#customer').val(),
skip_deleted: "1",
},
success : function(res)
{
if(res.found)
@@ -1579,6 +1583,17 @@
}
});
$(document).on('change', '.room_type_service_product_qty', function(e) {
let quantityInputField = this;
let maximumQuantity = parseInt($(quantityInputField).attr('data-max-quantity'));
let currentQuantity = parseInt($(quantityInputField).val());
if (currentQuantity > maximumQuantity) {
$(quantityInputField).siblings('p').show();
} else {
$(quantityInputField).siblings('p').hide();
}
});
function updateServiceProducts(element)
{
var operator = $(element).is(':checked') ? 'up' : 'down';

View File

@@ -122,25 +122,37 @@
{if ($params.type == 'date' || $params.type == 'datetime' || $params.type == 'range') && $params.value|is_array}
{assign var="filter_value" value=''}
{foreach $params.value as $value}
{if ($value|is_string && !empty($value))}
{if empty($filter_value)}
{if (isset($value) && ($value !== '' || $value === 0))}
{if !(isset($filter_value) && ($filter_value !== '' || $filter_value === 0))}
{assign var="filter_value" value=$value}
{else}
{assign var="filter_value" value="`$filter_value` - `$value`"}
{/if}
{/if}
{/foreach}
{if !empty($filter_value)}
{if (isset($filter_value) && ($filter_value !== '' || $filter_value === 0))}
<span data-filter_key="{if isset($params.name_date)}{$params.name_date}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$filter_value|escape:'html':'UTF-8'}</span>
<i class="icon-times"></i>
</span>
{/if}
{else if $params.type == 'select'}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$params['list'][$params['value']]|escape:'html':'UTF-8'}</span>
<i class="icon-times"></i>
</span>
{elseif $params.type == 'select'}
{if isset($params.multiple) && $params.multiple}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}" data-multiple="{$params.multiple|intval}" data-operator="{$params.operator}">
{$params['title']|escape:'html':'UTF-8'}:
<span class="filter_value">
{foreach from=$params.value item=option name=foreachInfo}
{$params.list[$option]}{if !$smarty.foreach.foreachInfo.last}{if $params.operator == 'or'} | {else}, {/if}{/if}
{/foreach}
</span>
<i class="icon-times"></i>
</span>
{else}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$params['list'][$params['value']]|replace: '&nbsp;' : ''}</span>
<i class="icon-times"></i>
</span>
{/if}
{else}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$params['value']|escape:'html':'UTF-8'}</span>
@@ -166,7 +178,7 @@
<input type="text" class="filter form-control" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}[0]" placeholder="{l s='From'}" value="{if isset($params.value.0)}{$params.value.0}{/if}">
<input type="text" class="filter form-control" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}[1]" placeholder="{l s='To'}" value="{if isset($params.value.1)}{$params.value.1}{/if}">
</div>
{else if $params.type == 'bool'}
{elseif $params.type == 'bool'}
<select id="filter_input_{$key}" class="filter fixed-width-sm center" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}">
<option value="">-</option>
<option value="1" {if $params.value == 1} selected="selected" {/if}>{l s='Yes'}</option>
@@ -205,21 +217,13 @@
prevText: '',
nextText: '',
dateFormat: 'yy-mm-dd',
beforeShow: function() {
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (typeof dateTo != 'undefined' && dateTo != '') {
let objDateToMax = $.datepicker.parseDate('yy-mm-dd', dateTo);
objDateToMax.setDate(objDateToMax.getDate() - 1);
$('#local_{$params.id_date}_0').datepicker('option', 'maxDate', objDateToMax);
}
},
onClose: function() {
let dateFrom = $('#local_{$params.id_date}_0').val().trim();
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (dateFrom >= dateTo) {
if ((dateFrom && dateTo) && (dateFrom >= dateTo)) {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
objDateToMin.setDate(objDateToMin.getDate());
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}
@@ -235,7 +239,7 @@
if (typeof dateFrom != 'undefined' && dateFrom != '') {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
objDateToMin.setDate(objDateToMin.getDate());
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}
@@ -245,18 +249,28 @@
</script>
</div>
{elseif $params.type == 'select'}
{if isset($params.filter_key)}
<select id="filter_input_{$key}" class="filter{if isset($params.align) && $params.align == 'center'}center{/if}" onchange="$('#submitFilterButton{$list_id}').focus();$('#submitFilterButton{$list_id}').click();" name="{$list_id}Filter_{$params.filter_key}" {if isset($params.width)} style="width:{$params.width}px"{/if}>
<option value="" {if $params.value == ''} selected="selected" {/if}>-</option>
{if isset($params.multiple) && $params.multiple}
<select id="filter_input_{$key}" class="filter{if isset($params.align) && $params.align == 'center'}center{/if} select_multiple_{$params.operator} chosen chosen-options-horizontal" multiple name="{$list_id}Filter_{$params.filter_key}[]" {if isset($params.width)} style="width:{$params.width}px"{/if}>
{if isset($params.list) && is_array($params.list)}
{foreach $params.list AS $option_value => $option_display}
<option value="{$option_value}" {if (string)$option_display === (string)$params.value || (string)$option_value === (string)$params.value} selected="selected"{/if}>{$option_display}</option>
<option value="{$option_value}" {if isset($params.value) && $params.value}{if in_array($option_value, $params.value)} selected="selected"{/if}{/if}>{$option_display}</option>
{/foreach}
{/if}
</select>
{else}
{if isset($params.filter_key)}
<select id="filter_input_{$key}" class="filter{if isset($params.align) && $params.align == 'center'}center{/if} {if isset($params.class)}{$params.class}{/if}" {if !isset($params.remove_onchange) || !$params.remove_onchange}onchange="$('#submitFilterButton{$list_id}').focus();$('#submitFilterButton{$list_id}').click();"{/if} name="{$list_id}Filter_{$params.filter_key}" {if isset($params.width)} style="width:{$params.width}px"{/if}>
<option value="" {if $params.value == ''} selected="selected" {/if}>-</option>
{if isset($params.list) && is_array($params.list)}
{foreach $params.list AS $option_value => $option_display}
<option value="{$option_value}" {if (string)$option_display === (string)$params.value || (string)$option_value === (string)$params.value} selected="selected"{/if}>{$option_display}</option>
{/foreach}
{/if}
</select>
{/if}
{/if}
{else}
<input type="text" class="filter" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" value="{$params.value|escape:'html':'UTF-8'}" {if isset($params.width) && $params.width != 'auto'} style="width:{$params.width}px"{/if} />
<input type="text" id="filter_input_{$key}" class="filter" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" value="{$params.value|escape:'html':'UTF-8'}" {if isset($params.width) && $params.width != 'auto'} style="width:{$params.width}px"{/if} />
{/if}
</div>
</div>
@@ -297,12 +311,112 @@
} else if (type == 'range') {
$('#list_filters_panel').find('[name*="orderFilter_'+$(this).parent().data('filter_key')+'"]').val('');
} else if (type == 'select') {
$('#list_filters_panel').find('select[name="orderFilter_'+$(this).parent().data('filter_key')+'"] option:selected').prop("selected", false);
$('#list_filters_panel').find('select[name*="orderFilter_'+$(this).parent().data('filter_key')+'"] option:selected').prop('selected', false);
} else {
$('#list_filters_panel').find('input[name="orderFilter_'+$(this).parent().data('filter_key')+'"]').val('');
}
// set post data for empty multi-select filters
$(form).find('select[multiple]').each(function (i, selectElement) {
if ($(selectElement).find('option:selected').length == 0) {
$(form).append('<input type="hidden" name="' + $(selectElement).attr('name').slice(0, -2) + '" value="">');
}
});
form.submit();
});
$('#form-order').submit(function () {
let form = $(this);
$(form).find('select[multiple]').each(function (i, selectElement) {
if ($(selectElement).val() == null) {
$(form).append('<input type="hidden" name="' + $(selectElement).attr('name').slice(0, -2) + '" value="">');
}
});
return true;
});
});
function updateRoomTypeFilter() {
let filterInputHotelName = $('#filter_input_hotel_name');
let filterInputRoomTypeName = $('#filter_input_room_type_name');
let idHotel = parseInt($(filterInputHotelName).val() || '0');
$.ajax({
url: currentIndex + '&token=' + token,
data: {
ajax: true,
action: 'GetHotelRoomTypes',
id_hotel: idHotel,
},
type: 'POST',
dataType: 'JSON',
success: function(response) {
if (response.status) {
if (response.has_room_types) {
$(filterInputRoomTypeName).html(response.html_room_types);
} else {
$(filterInputRoomTypeName).find('option').not(':first').remove();
}
// destroy current chosen and re-initialize
$(filterInputRoomTypeName).chosen('destroy');
$(filterInputRoomTypeName).chosen({
disable_search_threshold: 5,
search_contains: true,
});
}
},
});
}
function updateHotelRoomsFilter(useRoomType = true) {
let filterInputHotelName = $('#filter_input_hotel_name');
let filterInputRoomTypeName = $('#filter_input_room_type_name');
let filterInputRoomNumber = $('#filter_input_id_room_information');
let idHotel = parseInt($(filterInputHotelName).val() || '0');
let idProduct = parseInt($(filterInputRoomTypeName).val() || '0');
$.ajax({
url: currentIndex + '&token=' + token,
data: {
ajax: true,
action: 'GetHotelRooms',
id_hotel: idHotel,
id_product: useRoomType ? idProduct : 0,
},
type: 'POST',
dataType: 'JSON',
success: function(response) {
if (response.status) {
if (response.has_hotel_rooms) {
$(filterInputRoomNumber).html(response.html_hotel_rooms);
} else {
$(filterInputRoomNumber).find('option').not(':first').remove();
}
// destroy current chosen and re-initialize
$(filterInputRoomNumber).chosen('destroy');
$(filterInputRoomNumber).chosen({
disable_search_threshold: 5,
search_contains: true,
});
}
},
});
}
// manage Hotel and Room type filter inputs
$(document).on('change', '#filter_input_hotel_name', function () {
updateRoomTypeFilter();
updateHotelRoomsFilter(false);
});
$(document).on('change', '#filter_input_room_type_name', function () {
updateHotelRoomsFilter();
});
</script>
<style>
@@ -354,7 +468,7 @@
.list_filters {
padding: 0 30px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(3, minmax(0, 1fr));;
gap: 8px 40px;}
.list_filters > .row {
display: flex;

View File

@@ -157,7 +157,8 @@
{/if} -->
<!-- End -->
&nbsp;
{if $refund_allowed && !$hasCompletelyRefunded}
<!-- Check if refund is allowed and all bookings are not requested for refund -->
{if $refund_allowed && !$completeRefundRequestOrCancel}
<a id="desc-order-standard_refund" class="btn btn-default" href="#refundForm">
<i class="icon-exchange"></i>
{if $order->getTotalPaid()|floatval}
@@ -232,23 +233,26 @@
</table>
</div>
<!-- Change status form -->
<form action="{$currentIndex|escape:'html':'UTF-8'}&amp;vieworder&amp;token={$smarty.get.token}" method="post" class="form-horizontal well hidden-print">
<div class="row">
<div class="col-lg-9">
<select id="id_order_state" class="chosen form-control" name="id_order_state">
{foreach from=$states item=state}
<option value="{$state['id_order_state']|intval}"{if isset($currentState) && $state['id_order_state'] == $currentState->id} selected="selected" disabled="disabled"{/if}>{$state['name']|escape}</option>
{/foreach}
</select>
<input type="hidden" name="id_order" value="{$order->id}" />
</div>
<div class="col-lg-3">
<button type="submit" name="submitState" class="btn btn-primary">
{l s='Update status'}
</button>
</div>
</div>
</form>
{* If current state is refunded or cancelled the further order status changes are not allowed *}
{if !isset($currentState) || (isset($currentState) && ($currentState->id != Configuration::get('PS_OS_REFUND') && $currentState->id != Configuration::get('PS_OS_CANCELED')))}
<form action="{$currentIndex|escape:'html':'UTF-8'}&amp;vieworder&amp;id_order={$order->id|intval}&amp;token={$smarty.get.token}" method="post" class="form-horizontal well hidden-print">
<div class="row">
<div class="col-lg-9">
<select id="id_order_state" class="chosen form-control" name="id_order_state">
{foreach from=$states item=state}
<option value="{$state['id_order_state']|intval}"{if isset($currentState) && $state['id_order_state'] == $currentState->id} selected="selected" disabled="disabled"{elseif ($state['id_order_state'] == Configuration::get('PS_OS_REFUND') && !$allBookingsRefunded)} disabled="disabled"{elseif ($state['id_order_state'] == Configuration::get('PS_OS_CANCELED') && !$allBookingsCancelled)} disabled="disabled"{elseif ($state['id_order_state'] == Configuration::get('PS_OS_OVERBOOKING_PAID') || $state['id_order_state'] == Configuration::get('PS_OS_OVERBOOKING_UNPAID') || $state['id_order_state'] == Configuration::get('PS_OS_OVERBOOKING_PARTIAL_PAID')) && (!isset($orderOverBookings) || !$orderOverBookings)} disabled="disabled"{/if}>{$state['name']|escape}</option>
{/foreach}
</select>
<input type="hidden" name="id_order" value="{$order->id}" />
</div>
<div class="col-lg-3">
<button type="submit" name="submitState" class="btn btn-primary">
{l s='Update status'}
</button>
</div>
</div>
</form>
{/if}
</div>
<!-- Tab documents -->
<div class="tab-pane" id="documents">
@@ -277,61 +281,69 @@
<th>{l s='Hotel Name'}</th>
<th>{l s='Duration'}</th>
<th>{l s='Documents'}</th>
<th>{l s='Order Status'}</th>
<th>{l s='Room Status'}</th>
</tr>
{if isset($htl_booking_order_data) && $htl_booking_order_data}
{foreach from=$htl_booking_order_data item=data}
{if !$data.is_refunded}
<tr>
<td>
{$data['room_num']}
</td>
<td>
<a href="{$link->getAdminLink('AdminAddHotel')}&amp;id={$data['id_hotel']}&amp;updatehtl_branch_info" target="_blank">
<span>{$data['hotel_name']}</span>
</a>
</td>
<td>
{dateFormat date=$data['date_from']} - {dateFormat date=$data['date_to']}
</td>
<td>
<a class="btn btn-default" onclick="BookingDocumentsModal.init({$data.id|intval}, this); return false;">
<i class="icon icon-file-text"></i>
{l s='Documents'} <span class="badge badge-info count-documents">{$data.num_checkin_documents}</span>
</a>
</td>
<td>
<form action="" method="post" class="form-horizontal row room_status_info_form">
<div class="col-sm-7">
<select name="booking_order_status" class="form-control booking_order_status margin-bottom-5">
{foreach from=$hotel_order_status item=state}
<option value="{$state['id_status']|intval}" {if isset($data.id_status) && $state.id_status == $data.id_status} selected="selected" disabled="disabled"{/if}>{$state.name|escape}</option>
{/foreach}
</select>
<tr>
<td>
{$data['room_num']}
</td>
<td>
<a href="{$link->getAdminLink('AdminAddHotel')}&amp;id={$data['id_hotel']}&amp;updatehtl_branch_info" target="_blank">
<span>{$data['hotel_name']}</span>
</a>
</td>
<td>
{dateFormat date=$data['date_from']} - {dateFormat date=$data['date_to']}
</td>
<td>
<a class="btn btn-default" onclick="BookingDocumentsModal.init({$data.id|intval}, this); return false;">
<i class="icon icon-file-text"></i>
{l s='Documents'} <span class="badge badge-info count-documents">{$data.num_checkin_documents}</span>
</a>
</td>
<td>
<form action="" method="post" class="form-horizontal row room_status_info_form">
<div class="col-sm-7">
{if $data.is_refunded || $data.is_cancelled}
{if $data['id_status'] == $hotel_order_status['STATUS_ALLOTED']['id_status']}
<p><span class="room_status badge badge-infomation">{l s='Room alloted'}</span></p>
{/if}
{else}
<select name="booking_order_status" class="form-control booking_order_status margin-bottom-5">
{foreach from=$hotel_order_status item=state}
<option value="{$state['id_status']|intval}" {if isset($data.id_status) && $state.id_status == $data.id_status} selected="selected" disabled="disabled"{/if}>{$state.name|escape}</option>
{/foreach}
</select>
{/if}
{if $data['id_status'] == $hotel_order_status['STATUS_CHECKED_IN']['id_status']}
<p class="text-center"><span class="badge badge-success margin-bottom-5">{l s='Checked in on'} {dateFormat date=$data['check_in']}</span></p>
{elseif $data['id_status'] == $hotel_order_status['STATUS_CHECKED_OUT']['id_status']}
<p class="text-center"><span class="badge badge-success margin-bottom-5">{l s='Checked out on'} {dateFormat date=$data['check_out']}</span></p>
{/if}
{if $data['id_status'] == $hotel_order_status['STATUS_CHECKED_IN']['id_status']}
<p><span class="room_status badge badge-success">{l s='Checked in on'} {dateFormat date=$data['check_in']}</span></p>
{elseif $data['id_status'] == $hotel_order_status['STATUS_CHECKED_OUT']['id_status']}
<p><span class="room_status badge badge-success">{l s='Checked out on'} {dateFormat date=$data['check_out']}</span></p>
{/if}
{* field for the current date *}
<input class="room_status_date wk-input-date" type="text" name="status_date" value="{if $data['id_status'] == $hotel_order_status['STATUS_CHECKED_IN']['id_status']}{$data['date_to']|date_format:"%d-%m-%Y"}{else}{$data['date_from']|date_format:"%d-%m-%Y"}{/if}" readonly/>
{* field for the current date *}
<input class="room_status_date wk-input-date" type="text" name="status_date" value="{if $data['id_status'] == $hotel_order_status['STATUS_CHECKED_IN']['id_status']}{$data['date_to']|date_format:"%d-%m-%Y"}{else}{$data['date_from']|date_format:"%d-%m-%Y"}{/if}" readonly/>
<input type="hidden" name="date_from" value="{$data['date_from']|date_format:"%Y-%m-%d"}" />
<input type="hidden" name="date_to" value="{$data['date_to']|date_format:"%Y-%m-%d"}" />
<input type="hidden" name="id_room" value="{$data['id_room']}" />
<input type="hidden" name="id_order" value="{$order->id}" />
</div>
<div class="col-sm-5">
<button type="submit" name="submitbookingOrderStatus" class="btn btn-primary">
{l s='Update Status'}
</button>
</div>
</form>
</td>
</tr>
{/if}
<input type="hidden" name="date_from" value="{$data['date_from']|date_format:"%Y-%m-%d"}" />
<input type="hidden" name="date_to" value="{$data['date_to']|date_format:"%Y-%m-%d"}" />
<input type="hidden" name="id_room" value="{$data['id_room']}" />
<input type="hidden" name="id_order" value="{$order->id}" />
</div>
<div class="col-sm-5 text-right">
{if $data.is_refunded || $data.is_cancelled}
<span class="badge badge-danger">{if $data.is_cancelled}{l s='Cancelled'}{else}{l s='Refunded'}{/if}</span>
{else}
<button type="submit" name="submitbookingOrderStatus" class="btn btn-primary">
{l s='Update Status'}
</button>
{/if}
</div>
</form>
</td>
</tr>
{/foreach}
{else}
<tr>
@@ -352,121 +364,123 @@
</script>
<hr />
<!-- Tab nav -->
<ul class="nav nav-tabs" id="myTab" style="display:none"><!-- by webkul -->
{$HOOK_TAB_SHIP}
<li class="active">
<a href="#shipping">
<i class="icon-truck "></i>
{l s='Shipping'} <span class="badge">{$order->getShipping()|@count}</span>
</a>
</li>
<li>
<a href="#returns">
<i class="icon-undo"></i>
{l s='Merchandise Returns'} <span class="badge">{$order->getReturn()|@count}</span>
</a>
</li>
</ul>
<!-- Tab content -->
<div class="tab-content panel" style="display:none"><!-- by webkul -->
{$HOOK_CONTENT_SHIP}
<!-- Tab shipping -->
<div class="tab-pane active" id="shipping">
<h4 class="visible-print">{l s='Shipping'} <span class="badge">({$order->getShipping()|@count})</span></h4>
<!-- Shipping block -->
{if !$order->isVirtual()}
<div class="form-horizontal">
{if $order->gift_message}
<div class="form-group">
<label class="control-label col-lg-3">{l s='Message'}</label>
<div class="col-lg-9">
<p class="form-control-static">{$order->gift_message|nl2br}</p>
</div>
</div>
{/if}
{include file='controllers/orders/_shipping.tpl'}
{if $carrierModuleCall}
{$carrierModuleCall}
{/if}
<hr />
{if $order->recyclable}
<span class="label label-success"><i class="icon-check"></i> {l s='Recycled packaging'}</span>
{else}
<span class="label label-inactive"><i class="icon-remove"></i> {l s='Recycled packaging'}</span>
{/if}
{* <!-- commented by qlo -->
<ul class="nav nav-tabs" id="myTab" style="display:none">
{$HOOK_TAB_SHIP}
<li class="active">
<a href="#shipping">
<i class="icon-truck "></i>
{l s='Shipping'} <span class="badge">{$order->getShipping()|@count}</span>
</a>
</li>
<li>
<a href="#returns">
<i class="icon-undo"></i>
{l s='Merchandise Returns'} <span class="badge">{$order->getReturn()|@count}</span>
</a>
</li>
</ul>
<!-- Tab content -->
<div class="tab-content panel" style="display:none">
{$HOOK_CONTENT_SHIP}
<!-- Tab shipping -->
<div class="tab-pane active" id="shipping">
<h4 class="visible-print">{l s='Shipping'} <span class="badge">({$order->getShipping()|@count})</span></h4>
<!-- Shipping block -->
{if !$order->isVirtual()}
<div class="form-horizontal">
{if $order->gift_message}
<div class="form-group">
<label class="control-label col-lg-3">{l s='Message'}</label>
<div class="col-lg-9">
<p class="form-control-static">{$order->gift_message|nl2br}</p>
</div>
</div>
{/if}
{include file='controllers/orders/_shipping.tpl'}
{if $carrierModuleCall}
{$carrierModuleCall}
{/if}
<hr />
{if $order->recyclable}
<span class="label label-success"><i class="icon-check"></i> {l s='Recycled packaging'}</span>
{else}
<span class="label label-inactive"><i class="icon-remove"></i> {l s='Recycled packaging'}</span>
{/if}
{if $order->gift}
<span class="label label-success"><i class="icon-check"></i> {l s='Gift wrapping'}</span>
{else}
<span class="label label-inactive"><i class="icon-remove"></i> {l s='Gift wrapping'}</span>
{/if}
</div>
{/if}
</div>
<!-- Tab returns -->
<div class="tab-pane" id="returns">
<h4 class="visible-print">{l s='Merchandise Returns'} <span class="badge">({$order->getReturn()|@count})</span></h4>
{if !$order->isVirtual()}
<!-- Return block -->
{if $order->getReturn()|count > 0}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><span class="title_box ">{l s='Date'}</span></th>
<th><span class="title_box ">{l s='Type'}</span></th>
<th><span class="title_box ">{l s='Carrier'}</span></th>
<th><span class="title_box ">{l s='Tracking number'}</span></th>
</tr>
</thead>
<tbody>
{foreach from=$order->getReturn() item=line}
<tr>
<td>{$line.date_add}</td>
<td>{l s=$line.type}</td>
<td>{$line.state_name}</td>
<td class="actions">
<span class="shipping_number_show">{if isset($line.url) && isset($line.tracking_number)}<a href="{$line.url|replace:'@':$line.tracking_number|escape:'html':'UTF-8'}">{$line.tracking_number}</a>{elseif isset($line.tracking_number)}{$line.tracking_number}{/if}</span>
{if $line.can_edit}
<form method="post" action="{$link->getAdminLink('AdminOrders')|escape:'html':'UTF-8'}&amp;vieworder&amp;id_order={$order->id|intval}&amp;id_order_invoice={if $line.id_order_invoice}{$line.id_order_invoice|intval}{else}0{/if}&amp;id_carrier={if $line.id_carrier}{$line.id_carrier|escape:'html':'UTF-8'}{else}0{/if}">
<span class="shipping_number_edit" style="display:none;">
<button type="button" name="tracking_number">
{$line.tracking_number|htmlentities}
</button>
<button type="submit" class="btn btn-default" name="submitShippingNumber">
{l s='Update'}
</button>
</span>
<button href="#" class="edit_shipping_number_link">
<i class="icon-pencil"></i>
{l s='Edit'}
</button>
<button href="#" class="cancel_shipping_number_link" style="display: none;">
<i class="icon-remove"></i>
{l s='Cancel'}
</button>
</form>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{else}
<div class="list-empty hidden-print">
<div class="list-empty-msg">
<i class="icon-warning-sign list-empty-icon"></i>
{l s='No merchandise returned yet'}
</div>
</div>
{/if}
{if $carrierModuleCall}
{$carrierModuleCall}
{/if}
{/if}
</div>
</div>
{if $order->gift}
<span class="label label-success"><i class="icon-check"></i> {l s='Gift wrapping'}</span>
{else}
<span class="label label-inactive"><i class="icon-remove"></i> {l s='Gift wrapping'}</span>
{/if}
</div>
{/if}
</div>
<!-- Tab returns -->
<div class="tab-pane" id="returns">
<h4 class="visible-print">{l s='Merchandise Returns'} <span class="badge">({$order->getReturn()|@count})</span></h4>
{if !$order->isVirtual()}
<!-- Return block -->
{if $order->getReturn()|count > 0}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><span class="title_box ">{l s='Date'}</span></th>
<th><span class="title_box ">{l s='Type'}</span></th>
<th><span class="title_box ">{l s='Carrier'}</span></th>
<th><span class="title_box ">{l s='Tracking number'}</span></th>
</tr>
</thead>
<tbody>
{foreach from=$order->getReturn() item=line}
<tr>
<td>{$line.date_add}</td>
<td>{l s=$line.type}</td>
<td>{$line.state_name}</td>
<td class="actions">
<span class="shipping_number_show">{if isset($line.url) && isset($line.tracking_number)}<a href="{$line.url|replace:'@':$line.tracking_number|escape:'html':'UTF-8'}">{$line.tracking_number}</a>{elseif isset($line.tracking_number)}{$line.tracking_number}{/if}</span>
{if $line.can_edit}
<form method="post" action="{$link->getAdminLink('AdminOrders')|escape:'html':'UTF-8'}&amp;vieworder&amp;id_order={$order->id|intval}&amp;id_order_invoice={if $line.id_order_invoice}{$line.id_order_invoice|intval}{else}0{/if}&amp;id_carrier={if $line.id_carrier}{$line.id_carrier|escape:'html':'UTF-8'}{else}0{/if}">
<span class="shipping_number_edit" style="display:none;">
<button type="button" name="tracking_number">
{$line.tracking_number|htmlentities}
</button>
<button type="submit" class="btn btn-default" name="submitShippingNumber">
{l s='Update'}
</button>
</span>
<button href="#" class="edit_shipping_number_link">
<i class="icon-pencil"></i>
{l s='Edit'}
</button>
<button href="#" class="cancel_shipping_number_link" style="display: none;">
<i class="icon-remove"></i>
{l s='Cancel'}
</button>
</form>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{else}
<div class="list-empty hidden-print">
<div class="list-empty-msg">
<i class="icon-warning-sign list-empty-icon"></i>
{l s='No merchandise returned yet'}
</div>
</div>
{/if}
{if $carrierModuleCall}
{$carrierModuleCall}
{/if}
{/if}
</div>
</div>
*}
<script>
$('#myTab a').click(function (e) {
e.preventDefault()
@@ -1163,7 +1177,7 @@
<div class="panel" id="refundForm">
<div class="panel-heading">
<i class="icon-shopping-cart"></i>
{l s='Order Detail'} <span class="badge">{$order_detail_data|@count}</span>
{l s='Rooms Detail'} <span class="badge">{$order_detail_data|@count}</span>
{* by webkul products changes as rooms *}
</div>
{* by webkul this code is added for showing rooms information on the order detail page *}
@@ -1185,9 +1199,11 @@
<input type="hidden" name="TaxMethod" value="1">
{/if}
{if $can_edit}
<div class="row-margin-bottom row-margin-top standard_refund_fields" style="display: none;">
<textarea class="cancellation_reason" name="cancellation_reason" placeholder="{l s='Enter reason to cancel bookings'}"></textarea>
</div>
{if $refund_allowed && !$completeRefundRequestOrCancel}
<div class="row-margin-bottom row-margin-top standard_refund_fields" style="display: none;">
<textarea class="cancellation_reason" name="cancellation_reason" placeholder="{l s='Enter reason to cancel bookings'}"></textarea>
</div>
{/if}
<div class="row-margin-bottom row-margin-top order_action">
{if !$order->hasBeenDelivered()}
{* <button type="button" id="add_product" class="btn btn-default">
@@ -1204,7 +1220,7 @@
{l s='Add a new discount'}
</button>
{if $refund_allowed && !$hasCompletelyRefunded}
{if $refund_allowed && !$completeRefundRequestOrCancel}
<div class="pull-right">
<button style="display: none;" type="button" class="btn btn-default standard_refund_fields" id="cancelRefund">
{l s='Cancel'}
@@ -1228,7 +1244,7 @@
</div>
<div class="col-xs-6 pull-right">
<div class="panel panel-vouchers" style="{if !sizeof($discounts)}display:none;{/if}">
{if (sizeof($discounts) || $can_edit)}
{if sizeof($discounts)}
<div class="table-responsive">
<table class="table">
<thead>
@@ -1259,9 +1275,9 @@
{displayPrice price=$discount['value'] currency=$currency->id}
</td>
{if $can_edit}
<td>
<a href="{$current_index}&amp;submitDeleteVoucher&amp;id_order_cart_rule={$discount['id_order_cart_rule']}&amp;id_order={$order->id}&amp;token={$smarty.get.token|escape:'html':'UTF-8'}">
<i class="icon-minus-sign"></i>
<td class="text-center">
<a class="btn btn-default" href="{$current_index}&amp;submitDeleteVoucher&amp;id_order_cart_rule={$discount['id_order_cart_rule']}&amp;id_order={$order->id}&amp;token={$smarty.get.token|escape:'html':'UTF-8'}">
<i class="icon-trash"></i>
{l s='Delete voucher'}
</a>
</td>
@@ -1271,6 +1287,8 @@
</tbody>
</table>
</div>
{/if}
{if $can_edit}
<div class="current-edit" id="voucher_form" style="display:none;">
{include file='controllers/orders/_discount_form.tpl'}
</div>
@@ -1392,16 +1410,14 @@
</tr>
{/if}
{if $order->total_paid_tax_incl > $order->total_paid_real}
<tr>
<td class="text-right"><strong>{l s='Due Amount'}</strong></td>
<td class="amount text-right nowrap">
<strong>
{displayPrice currency=$order->id_currency price=($order->total_paid_tax_incl - $order->total_paid_real)}
</strong>
</td>
</tr>
{/if}
<tr>
<td class="text-right"><strong>{l s='Due Amount'}</strong></td>
<td class="amount text-right nowrap">
<strong>
{displayPrice currency=$order->id_currency price=($order->total_paid_tax_incl - $order->total_paid_real)}
</strong>
</td>
</tr>
</table>
</div>
</div>
@@ -1493,7 +1509,7 @@
<li role="presentation" class="active"><a href="#reallocate_room_tab" aria-controls="reallocate" role="tab" data-toggle="tab">{l s='Room Reallocation'}</a></li>
<li role="presentation"><a href="#swap_room_tab" aria-controls="swap" role="tab" data-toggle="tab">{l s='Swap Room'}</a></li>
</ul>
<div class="tab-content panel active">
<div class="tab-content active">
<div role="tabpanel" class="tab-pane active" id="reallocate_room_tab">
<form method="post" action="{$link->getAdminLink('AdminOrders')|escape:'html':'UTF-8'}&amp;vieworder&amp;id_order={$order->id|intval}">
<div class="modal-header">
@@ -1501,31 +1517,63 @@
<h4 class="modal-title" id="realloc_myModalLabel">{l s='Reallocate Rooms'}</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="curr_room_num" class="control-label model-label">{l s='Current Room Number:'}</label>
<input type="text" class="form-control modal_curr_room_num" name="modal_curr_room_num" readonly="true">
<input type="hidden" class="form-control modal_date_from" name="modal_date_from">
<input type="hidden" class="form-control modal_date_to" name="modal_date_to">
<input type="hidden" class="form-control modal_id_room" name="modal_id_room">
</div>
<div class="form-group">
<label for="realloc_avail_rooms" class="control-label model-label">{l s='Available Rooms To Reallocate:'}</label>
<div class="realloc_avail_rooms_container" style="width: 195px;">
<select class="form-control" name="realloc_avail_rooms" id="realloc_avail_rooms">
<option value="0" selected="selected">{l s='Select Rooms'}</option>
</select>
</div>
<p class="error_text" id="realloc_sel_rm_err_p"></p>
</div>
<div class="form-group">
<label style="text-decoration:underline;margin-top:5px;" for="message-text" class="col-sm-12 control-label model-label"><i class="icon-info-circle"></i>&nbsp;{l s='Currently Alloted Customer Information:'}</label>
<dl class="well list-detail">
<dt>{l s='Name'}</dt>
<dd class="cust_name"></dd><br>
<dt>{l s='Email'}</dt>
<dd class="cust_email"></dd><br>
</dl>
</div>
<div class="row">
<div class="form-group col-sm-6">
<label for="curr_room_num" class="control-label model-label">{l s='Current Room Number:'}</label>
<input type="text" class="form-control modal_curr_room_num" name="modal_curr_room_num" readonly="true">
<input type="hidden" class="form-control modal_id_htl_booking" name="id_htl_booking">
</div>
</div>
<div class="panel">
<div class="panel-heading"><i class="icon-user"></i> {l s='Currently Alloted Customer'}</div>
<div class="panel-content">
<div class="form-group">
<label class="col-sm-3 control-label model-label">{l s='Name'} :</label>
<div class="dol-sm-9 cust_name"></div>
</div>
<div class="">
<label class="col-sm-3 control-label model-label">{l s='Email'} :</label>
<div class="dol-sm-9 cust_email"></div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="form-group col-sm-6">
<label for="realloc_avail_room_type" class="control-label model-label">{l s='Room Type To Reallocate:'}</label>
<div class="realloc_avail_room_type_container">
<select class="form-control" name="realloc_avail_room_type" id="realloc_avail_room_type">
<option value="0" selected="selected">{l s='Select Room Type'}</option>
</select>
</div>
<p class="error_text" id="realloc_sel_rm_type_err_p"></p>
</div>
<div class="form-group col-sm-6">
<label for="realloc_avail_rooms" class="control-label model-label">{l s='Room To Reallocate:'}</label>
<div class="realloc_avail_rooms_container">
<select class="form-control" name="realloc_avail_rooms" id="realloc_avail_rooms">
<option value="0" selected="selected">{l s='Select Rooms'}</option>
</select>
</div>
<p class="error_text" id="realloc_sel_rm_err_p"></p>
</div>
</div>
<div class="row" id="reallocation_price_diff_block" style="display:none;">
<div class="form-group col-sm-6">
<label for="reallocation_price_diff" class="control-label model-label alert-warning">{l s='Price Difference'} *</label>
<div class="input-group">
<span class="input-group-addon">{$currency->prefix}{$currency->suffix}</span>
<input type="text" name="reallocation_price_diff" id="reallocation_price_diff" value="0" />
<span class="input-group-addon">{l s='Tax excl.'}</span>
</div>
</div>
</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>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{l s="Close" mod="hotelreservationsyatem"}</button>
@@ -1540,29 +1588,35 @@
<h4 class="modal-title" id="swap_myModalLabel">{l s='Swap Rooms'}</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="swap_curr_room_num" class="control-label model-label">{l s='Current Room Number:'}</label>
<input type="text" class="form-control modal_curr_room_num" name="modal_curr_room_num" readonly="true">
<input type="hidden" class="form-control modal_date_from" name="modal_date_from">
<input type="hidden" class="form-control modal_date_to" name="modal_date_to">
<input type="hidden" class="form-control modal_id_room" name="modal_id_room">
<input type="hidden" class="form-control modal_id_order" name="modal_id_order">
<div class="row">
<div class="form-group col-sm-6">
<label for="swap_curr_room_num" class="control-label model-label">{l s='Current Room Number:'}</label>
<input type="text" class="form-control modal_curr_room_num" name="modal_curr_room_num" readonly="true">
<input type="hidden" class="form-control modal_id_htl_booking" name="id_htl_booking">
</div>
</div>
<div class="form-group">
<label for="swap_avail_rooms" class="control-label model-label">{l s='Available Rooms To Swap:'}</label>
<div class="swap_avail_rooms_container"></div>
<p class="error_text" id="swap_sel_rm_err_p"></p>
</div>
<div class="form-group">
<label style="text-decoration:underline;margin-top:5px;" for="message-text" class="col-sm-12 control-label model-label"><i class="icon-info-circle"></i>&nbsp;{l s='Currently Alloted Customer Information:'}</label>
<dl class="well list-detail">
<dt>{l s='Name'}</dt>
<dd class="cust_name"></dd><br>
<dt>{l s='Email'}</dt>
<dd class="cust_email"></dd><br>
</dl>
</div>
</div>
<div class="panel">
<div class="panel-heading"><i class="icon-user"></i> {l s='Currently Alloted Customer'}</div>
<div class="panel-content">
<div class="form-group">
<label class="col-sm-3 control-label model-label">{l s='Name'} :</label>
<div class="dol-sm-9 cust_name"></div>
</div>
<div class="">
<label class="col-sm-3 control-label model-label">{l s='Email'} :</label>
<div class="dol-sm-9 cust_email"></div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="form-group col-sm-6">
<label for="swap_avail_rooms" class="control-label model-label">{l s='Rooms To Swap:'}</label>
<div class="swap_avail_rooms_container"></div>
<p class="error_text" id="swap_sel_rm_err_p"></p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{l s="Close" mod="hotelreservationsyatem"}</button>
<input type="submit" id="swap_allocated_rooms" name="swap_allocated_rooms" class="btn btn-primary" value="Swap">
@@ -1571,6 +1625,11 @@
</div>
</div>
</div>
{* loader before loading data *}
<div class="loading_overlay">
<img src='{$link->getMediaLink("`$img_dir`admin/ajax-loader.gif")}' class="loading-img"/>
</div>
</div>
</div>
@@ -1604,7 +1663,11 @@
{strip}
{addJsDefL name=no_rm_avail_txt}{l s='No rooms available.' js=1}{/addJsDefL}
{addJsDefL name=no_rm_avail_txt}{l s='No room available.' js=1}{/addJsDefL}
{addJsDefL name=no_realloc_rm_avail_txt}{l s='No room available for reallocation.' js=1}{/addJsDefL}
{addJsDefL name=no_realloc_rm_type_avail_txt}{l s='No room type available for reallocation.' js=1}{/addJsDefL}
{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=atleastSelectTxt}{l s='Select at least one facility to update.' js=1}{/addJsDefL}
@@ -1625,8 +1688,10 @@
{addJsDefL name='years_txt'}{l s='years' js=1}{/addJsDefL}
{addJsDefL name='all_children_txt'}{l s='All Children' js=1}{/addJsDefL}
{addJsDefL name='invalid_occupancy_txt'}{l s='Invalid occupancy(adults/children) found.' js=1}{/addJsDefL}
{addJsDefL name='select_room_txt'}{l s='Select room' js=1}{/addJsDefL}
{addJsDef max_child_age=$max_child_age|escape:'quotes':'UTF-8'}
{addJsDef max_child_in_room=$max_child_in_room|escape:'quotes':'UTF-8'}
{addJsDefL name='undo_cancellation_success'}{l s='Booking cancellation undo process is done successfully.' js=1}{/addJsDefL}
{/strip}
{* Apply javascript for the page *}
@@ -1653,12 +1718,10 @@
{* open date picker for the date input of check-in checkout dates *}
$(document).on('focus', '.room_status_date', function() {
var dateFrom = $(this).closest('.room_status_info_form').find('[name="date_from"]').val();
dateFrom = dateFrom.split("-");
minDate = new Date($.datepicker.formatDate('yy-mm-dd', new Date(dateFrom[0], dateFrom[1] - 1, dateFrom[2])));
minDate = $.datepicker.parseDate('yy-mm-dd', dateFrom);
var dateTo = $(this).closest('.room_status_info_form').find('[name="date_to"]').val();
dateTo = dateTo.split("-");
maxDate = new Date($.datepicker.formatDate('yy-mm-dd', new Date(dateTo[0], dateTo[1] - 1, dateTo[2])));
maxDate = $.datepicker.parseDate('yy-mm-dd', dateTo);
$(this).datepicker({
dateFormat: 'dd-mm-yy',
@@ -1751,6 +1814,17 @@
$('#room_extra_demand_content #back_to_service_btn').hide();
});
$(document).on('change', '#rooms_type_extra_demands .room_ordered_services .qty', function(e) {
let quantityInputField = this;
let maximumQuantity = parseInt($(quantityInputField).attr('data-max-quantity'));
let currentQuantity = parseInt($(quantityInputField).val());
if (currentQuantity > maximumQuantity) {
$(quantityInputField).siblings('p').show();
} else {
$(quantityInputField).siblings('p').hide();
}
});
$(document).on('focusout', '#rooms_type_extra_demands .room_ordered_services .qty', function(e) {
var qty_wntd = $(this).val();
if (qty_wntd == '' || !$.isNumeric(qty_wntd) || qty_wntd < 1) {
@@ -1766,41 +1840,6 @@
}
});
function updateAdditionalServices(element)
{
var id_room_type_service_product_order_detail = $(element).data('id_room_type_service_product_order_detail');
var qty = $(element).val();
if ($.isNumeric(qty)) {
$.ajax({
type: 'POST',
headers: {
"cache-control": "no-cache"
},
url: "{$link->getAdminLink('AdminOrders')|addslashes}",
dataType: 'JSON',
cache: false,
data: {
id_room_type_service_product_order_detail: id_room_type_service_product_order_detail,
qty: qty,
action: 'updateRoomAdditionalServices',
ajax: true
},
success: function(jsonData) {
if (!jsonData.hasError) {
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
}
showSuccessMessage(txtExtraDemandSucc);
} else {
showErrorMessage(jsonData.errors);
}
}
});
}
}
$(document).on('submit', '#add_room_services_form', function(e) {
e.preventDefault();
var form_data = new FormData(this);
@@ -1964,65 +2003,153 @@
$('#mySwappigModal').on('hidden.bs.modal', function (e)
{
$(".modal_id_order").val('');
$(".modal_date_from").val('');
$(".modal_date_to").val('');
$(".modal_id_room").val('');
$(".modal_id_htl_booking").val('');
$(".modal_curr_room_num").val('');
$(".cust_name").text('');
$(".cust_email").text('');
$(".swp_rm_opts").remove();
$(".realloc_rm_type_opts").remove();
$(".realloc_rm_opts").remove();
});
$('#mySwappigModal').on('shown.bs.modal', function (e)
{
$(".modal_id_order").val(e.relatedTarget.dataset.id_order);
$(".modal_date_from").val(e.relatedTarget.dataset.date_from);
$(".modal_date_to").val(e.relatedTarget.dataset.date_to);
$(".modal_id_room").val(e.relatedTarget.dataset.id_room);
$(".modal_curr_room_num").val(e.relatedTarget.dataset.room_num);
$(".loading_overlay").show();
$(".modal_id_htl_booking").val(e.relatedTarget.dataset.id_htl_booking);
$(".modal_curr_room_num").val(e.relatedTarget.dataset.room_num + ', ' + e.relatedTarget.dataset.room_type_name);
$(".cust_name").text(e.relatedTarget.dataset.cust_name);
$(".cust_email").text(e.relatedTarget.dataset.cust_email);
// For Rooms Swapping
if (e.relatedTarget.dataset.avail_rm_swap != 'false') {
var json_arr_rm_swp = JSON.parse(e.relatedTarget.dataset.avail_rm_swap);
// reset price difference fields
$("#reallocation_price_diff").val(0);
$("#reallocation_price_diff_block").hide();
$(".realloc_roomtype_change_message").hide();
html = '<select class="form-control" name="swap_avail_rooms" id="swap_avail_rooms" style="width:195px;">';
// For Rooms Swapping
var json_arr_rm_swp = JSON.parse(e.relatedTarget.dataset.avail_rm_swap);
if (e.relatedTarget.dataset.avail_rm_swap != 'false' && json_arr_rm_swp.length != 0) {
html = '<select class="form-control" name="swap_avail_rooms" id="swap_avail_rooms">';
$.each(json_arr_rm_swp, function(key,val) {
html += '<option class="swp_rm_opts" value="'+val.id_room+'" >'+val.room_num+'</option>';
html += '<option class="swp_rm_opts" value="'+val.id_hotel_booking+'" >'+val.room_num+'</option>';
});
html += '</select>';
$("#swap_allocated_rooms").removeAttr('disabled');
$(".swap_avail_rooms_container").empty().append(html);
} else {
$(".swap_avail_rooms_container").empty().text(no_rm_avail_txt);
$(".swap_avail_rooms_container").empty().text(no_swap_rm_avail_txt).addClass('text-danger');
$("#swap_allocated_rooms").attr('disabled', 'disabled');
}
// For Rooms Reallocation
if (e.relatedTarget.dataset.avail_rm_realloc != 'false') {
var json_arr_rm_realloc = JSON.parse(e.relatedTarget.dataset.avail_rm_realloc);
html = '<select class="form-control" name="realloc_avail_rooms" id="realloc_avail_rooms" style="width:195px;">';
$.each(json_arr_rm_realloc, function(key,val) {
html += '<option class="realloc_rm_opts" value="'+val.id_room+'" >'+val.room_num+'</option>';
var json_arr_realloc_room_types = JSON.parse(e.relatedTarget.dataset.avail_realloc_room_types);
if (e.relatedTarget.dataset.avail_realloc_room_types != 'false' && json_arr_realloc_room_types.length != 0) {
var idCurrentRoomType = e.relatedTarget.dataset.id_room_type;
var roomsTypesHtml = '<select data-id_htl_booking="' + e.relatedTarget.dataset.id_htl_booking + '" class="form-control" name="realloc_avail_room_type" id="realloc_avail_room_type">';
$.each(json_arr_realloc_room_types, function(key, room_type) {
roomsTypesHtml += "<option rooms_available='" + JSON.stringify(room_type.rooms) + "' class='realloc_rm_type_opts' value='" + room_type.id_product + "'";
if (idCurrentRoomType == room_type.id_product) {
roomsTypesHtml += ' selected="selected"';
}
roomsTypesHtml += '>' + room_type.room_type_name + '</option>';
});
html += '</select>';
$(".realloc_avail_rooms_container").empty().append(html);
roomsTypesHtml += '</select>';
setRoomsForReallocation(json_arr_realloc_room_types[idCurrentRoomType]['rooms']);
$("#realloc_allocated_rooms").removeAttr('disabled');
$(".realloc_avail_room_type_container").empty().append(roomsTypesHtml);
} else {
$(".realloc_avail_rooms_container").empty().text(no_rm_avail_txt);
$(".realloc_avail_rooms_container").empty().text(no_realloc_rm_avail_txt).addClass('text-danger');
$(".realloc_avail_room_type_container").empty().text(no_realloc_rm_type_avail_txt).addClass('text-danger');
$("#realloc_allocated_rooms").attr('disabled', 'disabled');
}
$(".loading_overlay").hide();
});
// change room type for reallocation
$(document).on("change", "#realloc_avail_room_type", function(e) {
$(".loading_overlay").show();
var idHotelBooking = $(this).data('id_htl_booking');
$("#reallocation_price_diff").val(0);
$("#reallocation_price_diff_block").hide();
if (parseInt(idHotelBooking) > 0) {
var optionSelected = $(this).find('option:selected');
var roomsAvailable = JSON.parse(optionSelected.attr('rooms_available'));
// set the rooms of the selceted room type
setRoomsForReallocation(roomsAvailable);
// send an ajax for fetching if price has changes in the new room type seleceted
$.ajax({
type: 'POST',
headers: {
"cache-control": "no-cache"
},
url: "{$link->getAdminLink('AdminOrders')|addslashes}",
dataType: 'JSON',
cache: false,
data: {
id_htl_booking: idHotelBooking,
id_new_room_type: $(this).val(),
action: 'changeRoomTypeToReallocate',
ajax: true
},
success: function(result) {
if (result.success == 1) {
// has room type changed for reallocation
if (result.has_room_type_change == 1) {
$(".realloc_roomtype_change_message").show();
// has room type price changed for reallocation
if (result.has_price_changes == 1) {
$("#reallocation_price_diff").val(result.price_diff);
$("#reallocation_price_diff_block").show();
}
} else {
$(".realloc_roomtype_change_message").hide();
}
$('#room_type_change_info').empty();
if (result.is_changes_present == 1) {
}
} else if (typeof(result.error) != 'undefinded' && result.error) {
showErrorMessage(result.error);
} else {
showErrorMessage(txtSomeErr);
}
$(".loading_overlay").hide();
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$(".loading_overlay").hide();
showErrorMessage(txtSomeErr);
}
});
} else {
$(".loading_overlay").hide();
showErrorMessage(txtSomeErr);
return false;
}
});
/*For reallocating rooms in the modal*/
$("#realloc_allocated_rooms").on('click', function(e){
$(".error_text").text('');
var room_to_reallocate = $('#realloc_avail_rooms').val();
var room_type_to_reallocate = $('#realloc_avail_room_type').val();
if (typeof room_type_to_reallocate == 'undefined' || room_type_to_reallocate == 0) {
$("#realloc_sel_rm_type_err_p").text(slct_rm_type_err);
return false;
}
if (typeof room_to_reallocate == 'undefined' || room_to_reallocate == 0) {
$("#realloc_sel_rm_err_p").text(slct_rm_err);
return false;
}
});
/*For swaping rooms in the modal*/
$("#swap_allocated_rooms").on('click', function(e){
$(".error_text").text('');
@@ -2033,8 +2160,6 @@
}
});
/*END*/
// for updating customer guest details
$('#edit_guest_details').on('click', function(e) {
e.preventDefault();
@@ -2098,9 +2223,61 @@
$('.datepicker').datetimepicker({
prevText: '',
nextText: '',
dateFormat: 'yy-mm-dd ' + hours + ':' + mins + ':' + secs
dateFormat: 'yy-mm-dd',
timeFormat: 'hh:mm:ss',
});
});
function updateAdditionalServices(element)
{
var id_room_type_service_product_order_detail = $(element).data('id_room_type_service_product_order_detail');
var qty = $(element).val();
if ($.isNumeric(qty)) {
$.ajax({
type: 'POST',
headers: {
"cache-control": "no-cache"
},
url: "{$link->getAdminLink('AdminOrders')|addslashes}",
dataType: 'JSON',
cache: false,
data: {
id_room_type_service_product_order_detail: id_room_type_service_product_order_detail,
qty: qty,
action: 'updateRoomAdditionalServices',
ajax: true
},
success: function(jsonData) {
if (!jsonData.hasError) {
if (jsonData.service_panel) {
$('#room_type_service_product_desc').replaceWith(jsonData.service_panel);
}
showSuccessMessage(txtExtraDemandSucc);
} else {
showErrorMessage(jsonData.errors);
}
}
});
}
}
function setRoomsForReallocation(roomsAvailable)
{
if (typeof(roomsAvailable) != 'undefined' && roomsAvailable.length) {
var roomsHtml = '<select class="form-control" name="realloc_avail_rooms" id="realloc_avail_rooms">';
roomsHtml += '<option class="realloc_rm_opts" value="0">---- ' + select_room_txt + ' ----</option>';
$.each(roomsAvailable, function(key, roomInfo) {
roomsHtml += '<option class="realloc_rm_opts" value="' + roomInfo.id_room + '">' + roomInfo.room_num + '</option>';
});
roomsHtml += '</select>';
$(".realloc_avail_rooms_container").empty().append(roomsHtml);
} else {
$(".realloc_avail_rooms_container").empty().text(no_realloc_rm_avail_txt);
}
}
</script>
{/block}
{/block}

View File

@@ -20,7 +20,7 @@
{if isset($product->id)}
<div id="product-configuration" class="panel product-tab">
<input type="hidden" name="submitted_tabs[]" value="Configuration" />
<h3 class="tab"> <i class="icon-AdminAdmin"></i> {l s='Configuration'}</h3>
<h3 class="tab"> <i class="icon-AdminAdmin"></i> {l s='Rooms'}</h3>
<input type="hidden" id="checkConfSubmit" value="0" name="checkConfSubmit">
@@ -101,6 +101,8 @@
</td>
<td class="col-sm-1 center">
{if isset($room_info['id'])}
<input type="hidden" class="booked-dates" name="{$var_name_room_info|cat:'[booked_dates]'}" value="{$room_info['booked_dates']|escape:'html':'UTF-8'}">
<a href="#" class="view_htl_room btn btn-default" data-toggle="modal" data-target="#room-dates-modal" data-id-room="{$room_info['id']}"><i class="icon-info"></i></a>
<a href="#" class="rm_htl_room btn btn-default" data-id-htl-info="{$room_info['id']}"><i class="icon-trash"></i></a>
<input type="hidden" name="{$var_name_room_info|cat:'[id]'}" value="{$room_info['id']}">
{else}
@@ -224,6 +226,36 @@
</div>
{*END*}
<div class="modal fade" id="room-dates-modal" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close margin-right-10" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title"><i class="icon-calendar"></i>&nbsp; {l s='Upcoming bookings'}</h4>
</div>
<div class="room-booked-dates-table modal-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><span>{l s='Order'}</span></th>
<th><span>{l s='Date From'}</span></th>
<th><span>{l s='Date To'}</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-label="Close">{l s='Done'}</button>
</div>
</div>
</div>
</div>
<style>
.deactiveDatesModal {
cursor: pointer;
@@ -400,6 +432,30 @@
});
});
{literal}
$('#room-dates-modal').on('show.bs.modal', function(e) {
const triggerRoom = $(e.relatedTarget);
$('#room-dates-modal tbody').html('');
var bookedDates = JSON.parse($(triggerRoom).closest('tr').find('.booked-dates').val());
if (bookedDates.length) {
if (bookedDates.length) {
$('#room-dates-modal .room-booked-dates-table').show();
$(bookedDates).each(function() {
$('#room-dates-modal .room-booked-dates-table tbody').append(`<tr>
<td><a href="{/literal}{$link->getAdminLink('AdminOrders')|escape:'html':'UTF-8'}{literal}&vieworder&id_order=${this.id_order}" target="_blank">#${this.id_order}</a></td>
<td>${this.date_from_formatted}</td>
<td>${this.date_to_formatted}</td>
</tr>`);
});
}
} else {
$('#room-dates-modal .room-booked-dates-table tbody').append(`<tr>
<td colspan="3" class="center">{/literal}{l s='No Booking for this room'}{literal}</td>
</tr>`);
}
});
{/literal}
// Add new room detail
$('#add-more-rooms-button').on('click',function() {
var lengthRooms = parseInt($('.room_data_values').length);
@@ -444,18 +500,19 @@
$.ajax({
url: prod_link,
type: 'POST',
dataType: 'text',
dataType: 'JSON',
data: {
ajax:true,
action:'deleteHotelRoom',
id: id_htl_info,
},
success: function (result) {
if (parseInt(result) == 1) {
success: function (response) {
if (response.success) {
showSuccessMessage("{l s='Removed successfully'}");
$current.closest(".room_data_values").remove();
} else {
showErrorMessage("{l s='Some error occurred'}");
if (response.errors)
showErrorMessage(response.errors);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
@@ -499,10 +556,10 @@
dateFormat: 'yy-mm-dd',
minDate: 0,
onSelect: function(selectedDate) {
var date_format = selectedDate.split('-');
selectedDate = new Date($.datepicker.formatDate('yy-mm-dd', new Date(date_format[0], date_format[1] - 1, date_format[2])));
selectedDate.setDate(selectedDate.getDate() + 1);
$(this).closest('tr').find('.disabled_date_to').datepicker('option', 'minDate', selectedDate);
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', selectedDate);
objDateToMin.setDate(objDateToMin.getDate() + 1);
$(this).closest('tr').find('.disabled_date_to').datepicker('option', 'minDate', objDateToMin);
},
onClose: function(selectedDate) {
var dateTo = $(this).closest('tr').find('.disabled_date_to').val();
@@ -517,16 +574,17 @@
dateFormat: 'yy-mm-dd',
minDate: 0,
beforeShow: function (input, instance) {
var date_to = $(this).closest('tr').find('.disabled_date_from').val();
if (typeof date_to != 'undefined' && date_to != '') {
var date_format = date_to.split('-');
var selectedDate = new Date($.datepicker.formatDate('yy-mm-dd', new Date(date_format[0], date_format[1] - 1, date_format[2])));
let dateFrom = $(this).closest('tr').find('.disabled_date_from').val();
let objDateToMin = null;
if (typeof dateFrom != 'undefined' && dateFrom != '') {
objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
} else {
var date_format = new Date();
var selectedDate = new Date($.datepicker.formatDate('yy-mm-dd', new Date()));
objDateToMin = new Date();
}
selectedDate.setDate(selectedDate.getDate()+1);
$(this).datepicker('option', 'minDate', selectedDate);
objDateToMin.setDate(objDateToMin.getDate() + 1);
$(this).datepicker('option', 'minDate', objDateToMin);
},
});
});

View File

@@ -0,0 +1,53 @@
{**
* 2010-2024 Webkul.
*
* NOTICE OF LICENSE
*
* All right is reserved,
* Please go through LICENSE.txt file inside our module
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please refer to CustomizationPolicy.txt file inside our module for more information.
*
* @author Webkul IN
* @copyright 2010-2024 Webkul IN
* @license LICENSE.txt
*}
{extends file='helpers/list/list_content.tpl'}
{block name='td_content'}
{if isset($tr.$key) && isset($params.position)}
{if $order_by == 'position' && $order_way != 'DESC'}
{assign var=filters_has_value_no_location_hotel value=false}
{foreach $fields_display AS $key => $params}
{if $key != 'id_category_default' && (isset($params['value']) && $params['value'] !== false && $params['value'] !== '')}
{if is_array($params['value']) && trim(implode('', $params['value'])) == ''}
{continue}
{/if}
{assign var=filters_has_value_no_location_hotel value=true}
{break}
{/if}
{/foreach}
{if !$filters_has_value_no_location_hotel}
<div class="dragGroup">
<div class="positions">
{$tr.$key.position + 1}
</div>
</div>
{else}
{$tr.$key.position + 1}
{/if}
{else}
{$tr.$key.position + 1}
{/if}
{else}
{$smarty.block.parent}
{/if}
{/block}

View File

@@ -25,12 +25,393 @@
{extends file="helpers/list/list_header.tpl"}
{block name=leadin}
{if isset($category_tree)}
<div class="bloc-leadin">
<div id="container_category_tree">
{$category_tree}
{block name="tableFilter"}{/block}
{block name="override_form_extra"}
{if !$simple_header && $show_filters}
<script>
$(function() {
if ($("#list_filters_panel .datepicker").length > 0) {
$("#list_filters_panel .datepicker").datepicker({
prevText: '',
nextText: '',
altFormat: 'yy-mm-dd'
});
}
});
</script>
<div class="list_action_wrapper">
<div class="row">
<div class="col-xs-4 col-sm-3 col-md-2">
<div class="list_availibility_container">
<button type="button" class="btn btn-default btn-left btn-block dropdown-toggle" data-toggle="dropdown">
<span>{l s='Available Fields'}
<i class="icon-caret-down pull-right"></i>
</button>
<ul id="optional-list-toggle" class="dropdown-menu">
{foreach $fields_optional as $key => $field}
<li>
<label>
<input type="checkbox" name="list_fields_visibility" value="{$key}" {if isset($field['selected']) && $field['selected']}checked="checked"{/if}>
{$field['title']}
</label>
</li>
{/foreach}
{assign var="fields_optional" value=array()}
</ul>
</div>
</div>
<div class="col-xs-3 col-xs-offset-5 col-sm-2 col-sm-offset-7 col-md-1 col-md-offset-9">
<div class="list_filter_container">
<button type="button" class="btn btn-default btn-block" data-toggle="collapse" data-target="#list_filters_panel">
<i class="icon-sliders"></i>
<span>{l s='Filters'}
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
{if $filters_has_value}
<div id="selected_filter_container">
{l s='Filters: '}
<span class="selected_filters">
{foreach $fields_display AS $key => $params}
{if (!isset($params.search) || $params.search) && $params.value != ''}
{if ($params.type == 'date' || $params.type == 'datetime') && $params.value|is_array}
{assign var="filter_value" value=''}
{foreach $params.value as $value}
{if ($value|is_string && !empty($value))}
{if empty($filter_value)}
{assign var="filter_value" value=$value}
{else}
{assign var="filter_value" value="`$filter_value` - `$value`"}
{/if}
{/if}
{/foreach}
{if !empty($filter_value)}
<span data-filter_key="{if isset($params.name_date)}{$params.name_date}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$filter_value|escape:'html':'UTF-8'}</span>
<i class="icon-times"></i>
</span>
{/if}
{elseif $params.type == 'range' && $params.value|is_array}
{assign var="filter_value" value=''}
{foreach $params.value as $value}
{if (isset($value) && ($value !== '' || $value === 0))}
{if !(isset($filter_value) && ($filter_value !== '' || $filter_value === 0))}
{assign var="filter_value" value=$value}
{else}
{assign var="filter_value" value="`$filter_value` - `$value`"}
{/if}
{/if}
{/foreach}
{if (isset($filter_value) && ($filter_value !== '' || $filter_value === 0))}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$filter_value|escape:'html':'UTF-8'}</span>
<i class="icon-times"></i>
</span>
{/if}
{elseif $params.type == 'select'}
{if isset($params.multiple) && $params.multiple}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}" data-multiple="{$params.multiple|intval}" data-operator="{$params.operator}">
{$params['title']|escape:'html':'UTF-8'}:
<span class="filter_value">
{foreach from=$params.value item=option name=foreachInfo}
{$params.list[$option]}{if !$smarty.foreach.foreachInfo.last}{if $params.operator == 'or'} | {else}, {/if}{/if}
{/foreach}
</span>
<i class="icon-times"></i>
</span>
{else}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$params['list'][$params['value']]|replace: '&nbsp;' : ''}</span>
<i class="icon-times"></i>
</span>
{/if}
{elseif $params.type == 'bool' && $key == 'advance_payment'}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{if $params['value'] == 1}{l s='Yes'}{elseif $params['value'] == 0}{l s='No'}{/if}</span>
<i class="icon-times"></i>
</span>
{else}
<span data-filter_key="{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" data-filter_type="{$params.type}">
{$params['title']|escape:'html':'UTF-8'}: <span class="filter_value">{$params['value']|escape:'html':'UTF-8'}</span>
<i class="icon-times"></i>
</span>
{/if}
{/if}
{/foreach}
</span>
</div>
{/if}
<div class="panel collapse" id="list_filters_panel">
<div class="row">
<div class="col-sm-12">
<div class="list_filters">
{foreach $fields_display AS $key => $params}
{if !isset($params.search) || $params.search}
<div class="row">
<label class="col-xs-3" for="filter_input_{$key}">{$params['title']|escape:'html':'UTF-8'}</label>
<div class="col-xs-9">
{if $params.type == 'range'}
<div class="input_range">
<input type="text" class="filter form-control" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}[0]" placeholder="{l s='From'}" value="{if isset($params.value.0)}{$params.value.0}{/if}">
<input type="text" class="filter form-control" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}[1]" placeholder="{l s='To'}" value="{if isset($params.value.1)}{$params.value.1}{/if}">
</div>
{else if $params.type == 'bool'}
<select id="filter_input_{$key}" class="filter center" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}">
<option value="">-</option>
<option value="1" {if $params.value == 1} selected="selected" {/if}>{l s='Yes'}</option>
<option value="0" {if $params.value == 0 && $params.value != ''} selected="selected" {/if}>{l s='No'}</option>
</select>
{elseif $params.type == 'date' || $params.type == 'datetime'}
<div class="date_range">
<div class="input-group center">
<input type="text" class="filter datepicker date-input form-control" id="local_{$params.id_date}_0" name="local_{$params.name_date}[0]" placeholder="{l s='From'}" autocomplete="off"/>
<input type="hidden" id="{$params.id_date}_0" name="{$params.name_date}[0]" value="{if isset($params.value.0)}{$params.value.0}{/if}">
<span class="input-group-addon">
<i class="icon-calendar"></i>
</span>
</div>
<div class="input-group center">
<input type="text" class="filter datepicker date-input form-control" id="local_{$params.id_date}_1" name="local_{$params.name_date}[1]" placeholder="{l s='To'}" autocomplete="off"/>
<input type="hidden" id="{$params.id_date}_1" name="{$params.name_date}[1]" value="{if isset($params.value.1)}{$params.value.1}{/if}">
<span class="input-group-addon">
<i class="icon-calendar"></i>
</span>
</div>
<script>
$(function() {
var dateStart = parseDate($("#{$params.id_date}_0").val());
var dateEnd = parseDate($("#{$params.id_date}_1").val());
$("#local_{$params.id_date}_0").datepicker("option", "altField", "#{$params.id_date}_0");
$("#local_{$params.id_date}_1").datepicker("option", "altField", "#{$params.id_date}_1");
if (dateStart !== null){
$("#local_{$params.id_date}_0").datepicker("setDate", dateStart);
}
if (dateEnd !== null){
$("#local_{$params.id_date}_1").datepicker("setDate", dateEnd);
}
$('#local_{$params.id_date}_0').datepicker('option', {
prevText: '',
nextText: '',
dateFormat: 'yy-mm-dd',
beforeShow: function() {
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (typeof dateTo != 'undefined' && dateTo != '') {
let objDateToMax = $.datepicker.parseDate('yy-mm-dd', dateTo);
objDateToMax.setDate(objDateToMax.getDate() - 1);
$('#local_{$params.id_date}_0').datepicker('option', 'maxDate', objDateToMax);
}
},
onClose: function() {
let dateFrom = $('#local_{$params.id_date}_0').val().trim();
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (dateFrom >= dateTo) {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}
},
});
$('#local_{$params.id_date}_1').datepicker('option', {
prevText: '',
nextText: '',
dateFormat: 'yy-mm-dd',
beforeShow: function() {
let dateFrom = $('#local_{$params.id_date}_0').val().trim();
if (typeof dateFrom != 'undefined' && dateFrom != '') {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}
},
});
});
</script>
</div>
{elseif $params.type == 'select'}
{if isset($params.multiple) && $params.multiple}
<select id="filter_input_{$key}" class="filter{if isset($params.align) && $params.align == 'center'}center{/if} select_multiple_{$params.operator} chosen chosen-options-horizontal" multiple name="{$list_id}Filter_{$params.filter_key}[]" {if isset($params.width)} style="width:{$params.width}px"{/if}>
{if isset($params.list) && is_array($params.list)}
{foreach $params.list AS $option_value => $option_display}
<option value="{$option_value}" {if isset($params.value) && $params.value}{if in_array($option_value, $params.value)} selected="selected"{/if}{/if}>{$option_display}</option>
{/foreach}
{/if}
</select>
{else}
{if isset($params.filter_key)}
<select id="filter_input_{$key}" class="filter{if isset($params.align) && $params.align == 'center'}center{/if} {if isset($params.class)}{$params.class}{/if}" {if !isset($params.remove_onchange) || !$params.remove_onchange}onchange="$('#submitFilterButton{$list_id}').focus();$('#submitFilterButton{$list_id}').click();"{/if} name="{$list_id}Filter_{$params.filter_key}" {if isset($params.width)} style="width:{$params.width}px"{/if}>
<option value="" {if $params.value == ''} selected="selected" {/if}>-</option>
{if isset($params.list) && is_array($params.list)}
{foreach $params.list AS $option_value => $option_display}
<option value="{$option_value}" {if (string)$option_display === (string)$params.value || (string)$option_value === (string)$params.value} selected="selected"{/if}>{$option_display}</option>
{/foreach}
{/if}
</select>
{/if}
{/if}
{else}
<input type="text" class="filter" name="{$list_id}Filter_{if isset($params.filter_key)}{$params.filter_key}{else}{$key}{/if}" value="{$params.value|escape:'html':'UTF-8'}" {if isset($params.width) && $params.width != 'auto'} style="width:{$params.width}px"{/if} />
{/if}
</div>
</div>
{/if}
{/foreach}
{if $has_actions || $show_filters}
<div class="actions">
<hr>
{if $show_filters}
<span class="pull-right">
<button type="submit" id="submitFilterButton{$list_id}" name="submitFilter" class="btn btn-default" data-list-id="{$list_id}">
<i class="icon-search"></i> {l s='Search'}
</button>
{if $filters_has_value}
<button type="submit" name="submitReset{$list_id}" class="btn btn-warning">
<i class="icon-eraser"></i> {l s='Reset'}
</button>
{/if}
</span>
{/if}
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$('#selected_filter_container .selected_filters span i').on('click', function() {
let form = $(this).closest('form');
let type = $(this).parent().data('filter_type');
$(this).parent().remove();
if (type == 'date' || type == 'datetime') {
$('#list_filters_panel').find('[name*="'+$(this).parent().data('filter_key')+'"]').val('');
} else if (type == 'range') {
$('#list_filters_panel').find('[name*="productFilter_'+$(this).parent().data('filter_key')+'"]').val('');
} else if (type == 'select') {
$('#list_filters_panel').find('select[name*="productFilter_'+$(this).parent().data('filter_key')+'"] option:selected').prop('selected', false);
} else if (type == 'bool' && $(this).parent().data('filter_key') == 'advance_payment') {
$('#list_filters_panel').find('select[name*="productFilter_'+$(this).parent().data('filter_key')+'"] option:selected').prop('selected', false);
} else {
$('#list_filters_panel').find('input[name*="productFilter_'+$(this).parent().data('filter_key')+'"]').val('');
}
// set post data for empty multi-select filters
$(form).find('select[multiple]').each(function (i, selectElement) {
if ($(selectElement).find('option:selected').length == 0) {
$(form).append('<input type="hidden" name="' + $(selectElement).attr('name').slice(0, -2) + '" value="">');
}
});
form.submit();
});
$('#form-product').submit(function () {
let form = $(this);
$(form).find('select[multiple]').each(function (i, selectElement) {
if ($(selectElement).val() == null) {
$(form).append('<input type="hidden" name="' + $(selectElement).attr('name').slice(0, -2) + '" value="">');
}
});
return true;
});
});
</script>
<style>
.list_action_wrapper {
margin-bottom: 15px;
}
.list_availibility_container {
position: relative;}
.list_availibility_container .dropdown-menu {
right: 0;
padding: 8px 12px;}
.list_availibility_container .dropdown-menu label {
font-weight: 400;}
#selected_filter_container {
background-color: #fff;
padding: 8px 20px;
border: solid 1px #d3d8db;
border-radius: 5px 5px 0 0;
font-size: 14px;
min-height: 52px;
margin-top: 15px;}
#selected_filter_container .selected_filters > span {
font-size: 12px;
padding: 6px 10px;
display: inline-block;
background: #F5F8F9;
border: 1px solid #A0D0EB;
border-radius: 3px;}
#selected_filter_container .selected_filters > span + span {
margin-left: 12px;}
#selected_filter_container .selected_filters > span .filter_value {
font-weight: 700;
}
#selected_filter_container .selected_filters > span i {
cursor: pointer;}
#content.bootstrap #list_filters_panel{
margin-top: 15px;
margin-bottom: 0;
}
#content.bootstrap #selected_filter_container + #list_filters_panel {
margin-top: 0;
}
#content.bootstrap #selected_filter_container + div.panel {
border-top: transparent;
border-radius: 0 0 5px 5px;
}
.list_filters {
padding: 0 30px;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px 40px;}
.list_filters > .row {
display: flex;
align-items: center;}
.list_filters .date_range, .list_filters .input_range {
display: flex;
justify-content: space-between;
gap: 15px;}
.list_filters .date_range .input-group:first-child {
margin-bottom: 0;}
.list_filters label {
text-align: right;
font-weight: 400;}
.list_filters .actions {
grid-column-start: 1;
grid-column-end: 4;}
@media (max-width: 992px) {
.list_filters {
grid-template-columns: repeat(2, 1fr);}
.list_filters .actions {
grid-column-start: 1;
grid-column-end: 3;}
}
@media (max-width: 768px) {
.list_filters {
grid-template-columns: repeat(1, 1fr);}
.list_filters .actions {
grid-column-start: 1;
grid-column-end: 2;}
.list_filters label {
text-align: left;
}
}
</style>
{/if}
{/block}
{/block}

View File

@@ -24,7 +24,7 @@
*}
<div class="form-group">
<div class="col-lg-12">
<input id="{$id|escape:'html':'UTF-8'}" type="file" name="{$name|escape:'html':'UTF-8'}[]"{if isset($url)} data-url="{$url}"{/if}{if isset($multiple) && $multiple} multiple="multiple"{/if} style="width:0px;height:0px;" />
<input id="{$id|escape:'html':'UTF-8'}" type="file" accept="image/gif, image/jpg, image/jpeg, image/png" name="{$name|escape:'html':'UTF-8'}[]"{if isset($url)} data-url="{$url}"{/if}{if isset($multiple) && $multiple} multiple="multiple"{/if} style="width:0px;height:0px;" />
<button class="btn btn-default" data-style="expand-right" data-size="s" type="button" id="{$id|escape:'html':'UTF-8'}-add-button">
<i class="icon-folder-open"></i> {if isset($multiple) && $multiple}{l s='Add files...'}{else}{l s='Add file...'}{/if}
</button>

View File

@@ -137,7 +137,7 @@
{l s='Select Hotel'}
</label>
<div class="col-sm-5">
<select name="id_hotel" id="hotel_place" class="form-control">
<select name="id_hotel" id="hotel_place" class="form-control chosen">
{foreach from=$htl_info item=htl_dtl}
<option value="{$htl_dtl['id']}" >{$htl_dtl['hotel_name']}</option>
{/foreach}
@@ -273,6 +273,27 @@
</div>
</div>
<div class="form-group" id="show_at_front_container">
<label class="control-label col-lg-3">
<span class="label-tooltip" data-toggle="tooltip" title="{l s='Enable if you want this room type to be shown and to be available for booking from front office.'}">
{l s='Show at front office'}
</span>
</label>
<div class="col-lg-3">
<span class="switch prestashop-switch fixed-width-lg">
<input type="radio" name="show_at_front" id="show_at_front_on" value="1" {if $product->show_at_front || !$product->isAssociatedToShop()}checked="checked"{/if}/>
<label for="show_at_front_on" class="radioCheck">
{l s='Yes'}
</label>
<input type="radio" name="show_at_front" id="show_at_front_off" value="0" {if !$product->show_at_front && $product->isAssociatedToShop()}checked="checked"{/if}/>
<label for="show_at_front_off" class="radioCheck">
{l s='No'}
</label>
<a class="slide-button btn"></a>
</span>
</div>
</div>
<div id="product_options" class="form-group hidden">
<div class="col-lg-12">
<div class="form-group">
@@ -422,6 +443,27 @@
</div>
{/if}
{if isset($product->id) && $product->id}
<div class="form-group">
<label class="control-label col-lg-3" id="category_position" for="category_position">
<span class="label-tooltip" data-toggle="tooltip" title="{l s='Set position of the room type when hotel search results are displayed.'}">
{l s='Position'}
</span>
</label>
<div class="col-lg-9">
<input type="text" id="category_position" class="form-control fixed-width-lg" name="category_position" value="{$category_position}" />
<p class="help-block">{l s='Please note that position numbering starts from 0. A position of 0 means room type will be displayed at the topmost.'}</p>
</div>
</div>
{/if}
{if isset($product->id) && $product->id}
<div class="alert alert-info">
{l s='You can change positions of room types of this hotel from '}
<a href="{$link->getAdminLink('AdminProducts')}&id_category={$htl_full_info['id_category']}">{l s='here.'}</a>
</div>
{/if}
{* <div class="form-group">
<label class="control-label col-lg-3" for="tags_{$id_lang}">
<span class="label-tooltip" data-toggle="tooltip"

View File

@@ -494,7 +494,7 @@ $(document).ready(function () {
<div class="col-lg-9">
<div class="row">
{if !$multi_shop}
<input type="hidden" name="sp_id_shop" value="0" />
<input type="hidden" name="sp_id_shop" value="1" />
{else}
<div class="col-lg-3">
<select name="sp_id_shop" id="sp_id_shop">

View File

@@ -3,77 +3,134 @@
<input type="hidden" name="submitted_tabs[]" value="ServiceProduct" />
<h3 class="tab"> <i class="icon-AdminAdmin"></i> {l s='Service Products'}</h3>
{if isset($service_products) && $service_products}
{if (isset($associated_service_products) && $associated_service_products) || (isset($unassociated_service_products) && $unassociated_service_products)}
<div class="from-group table-responsive-row clearfix">
<table class="table tableDnD hotel-roomtype-link-table">
<table class="table hotel-roomtype-link-table">
<thead>
<tr class="nodrag nodrop">
<th class="text-center">
<input type="checkbox" class="bulk-service-products-status">
</th>
<th class="col-sm-1">
<span>{l s='Id Product'}</span>
<span>{l s='ID'}</span>
</th>
<th class="col-sm-3">
<span>{l s='name'}</span>
<th class="col-sm-2">
<span>{l s='Name'}</span>
</th>
<th class="">
<span>{l s='Auto add to cart'}</span>
<th class="text-center">
<span>{l s='Auto Add to Cart'}</span>
</th>
<th>
<span>{l s='Position'}</span>
</th>
<th class="">
<th>
<span>{l s='Price'}</span>
</th>
<th class="">
<th>
<span>{l s='Tax'}</span>
</th>
<th class="text-right">
<span>{l s='Action'}</span>
</th>
</tr>
</thead>
<tbody>
{foreach from=$service_products key=key item=service_product}
<tr id='room_type_service_product_{$service_product.id_room_type_service_product|escape:'html':'UTF-8'}' position='{$service_product.position|escape:'html':'UTF-8'}' id_product='{$service_product.id_product|escape:'html':'UTF-8'}' id_element="{$product->id}" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}">
<td class="col-sm-1">{$service_product.id_product|escape:'html':'UTF-8'} <a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct"><i class="icon-external-link-sign"></i></a></td>
{foreach from=$associated_service_products item=service_product}
<tr id='room_type_service_product_{$service_product.id_product|escape:'html':'UTF-8'}' position="{$service_product.association_info.position|escape:'html':'UTF-8'}" id_product='{$service_product.id_product|escape:'html':'UTF-8'}' id_element="{$product->id}" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}">
{assign var=inputs_prefix value="service_product_`$service_product.id_product`_"}
<input type="hidden" name="available_service_products[]" value="{$service_product.id_product}">
<td class="text-center">
<input type="checkbox" name="{$inputs_prefix}associated" class="is-associated" checked>
</td>
<td class="col-sm-1">
{$service_product.id_product|escape:'html':'UTF-8'}
<a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct">
<i class="icon-external-link-sign"></i>
</a>
</td>
<td>{$service_product.name}</td>
<td><span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}</span></td>
<td class="text-center">
<span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>
{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}
</span>
</td>
<td class="pointer dragHandle center positionImage">
<div class="dragGroup">
<div class="positions">
{$service_product.position + 1}
{$service_product.association_info.position + 1}
</div>
</div>
</td>
<td>
<span class="field-view service-product-price-text">{if isset($service_product.custom_price) && $service_product.custom_price}{displayPrice price=$service_product.custom_price currency=$currency->id}{else}{displayPrice price=$service_product.default_price currency=$currency->id}{/if}</span>
<div class="field-edit" style="display:none">
<div class="fixed-width-xl">
<div class="input-group">
<input type="text" value="{if isset($service_product.custom_price) && $service_product.custom_price}{$service_product.custom_price|escape:'html':'UTF-8'}{else}{$service_product.default_price|escape:'html':'UTF-8'}{/if}" class="service-product-price" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}">
<span class="input-group-addon">{$currency->prefix}{$currency->suffix}</span>
{assign var=price_value value=0}
{if isset($smarty.post["{$inputs_prefix}price"])}
{assign var=price_value value=$smarty.post["{$inputs_prefix}price"]}
{else}
{if isset($service_product.association_info.custom_price)}
{assign var=price_value value=$service_product.association_info.custom_price}
{elseif isset($service_product.association_info.default_price)}
{assign var=price_value value=$service_product.association_info.default_price}
{/if}
{/if}
<input type="text" name="{$inputs_prefix}price" value="{$price_value}" data-id_product="{$service_product.id_product}">
</div>
</div>
<div class="help-block">{l s='Default price: %s' sprintf={displayPrice price=$service_product.default_price currency=$currency->id}}
<div class="help-block">
{l s='Default price: %s' sprintf={displayPrice price=$service_product.association_info.default_price currency=$currency->id}}
</div>
</td>
<td>
<span class="field-view service_product_tax_text">{if isset($service_product.tax_rules_group_name) && $service_product.tax_rules_group_name}{$service_product.tax_rules_group_name}{else}{$service_product.default_tax_rules_group_name}{/if}</span>
<div class="field-edit" style="display:none">
<select class="service_product_id_tax_rules_group">
<div class="fixed-width-xl">
<select class="service_product_id_tax_rules_group" name="{$inputs_prefix}id_tax_rules_group">
<option value="0">{l s='No Tax'}</option>
{foreach from=$tax_rules_groups item=tax_rules_group}
<option value="{$tax_rules_group.id_tax_rules_group}" {if $service_product.id_tax_rules_group == $tax_rules_group.id_tax_rules_group}selected="selected"{/if} >
<option value="{$tax_rules_group.id_tax_rules_group}" {if $service_product.association_info.id_tax_rules_group == $tax_rules_group.id_tax_rules_group}selected="selected"{/if} >
{$tax_rules_group['name']|htmlentitiesUTF8}
</option>
{/foreach}
</select>
</div>
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.default_tax_rules_group_name}
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.association_info.default_tax_rules_group_name}</div>
</td>
<td class="text-right">
<a href="#" class="btn btn-default button-edit-price field-view"><i class="icon-pencil"></i></a>
<span class="field-edit" style="display:none">
<a href="#" class="btn btn-default btn-save" data-roomtype_url="{$link->getAdminLink('AdminProducts', true)|addslashes}" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}"><i class="icon-save"></i> {l s='save'}</a>
<a href="#" class="btn btn-default btn-cancel"><i class="icon-times"></i></a>
</span>
</tr>
{/foreach}
{foreach from=$unassociated_service_products item=service_product}
<tr class="nodrop nodrag">
{assign var=inputs_prefix value="service_product_`$service_product.id_product`_"}
<input type="hidden" name="available_service_products[]" value="{$service_product.id_product}">
<td class="text-center">
<input type="checkbox" name="{$inputs_prefix}associated" class="is-associated" {if isset($smarty.post["{$inputs_prefix}associated"]) && in_array($smarty.post["{$inputs_prefix}associated"], array('on', 'true', '1'))}checked{/if}>
</td>
<td class="col-sm-1">{$service_product.id_product|escape:'html':'UTF-8'} <a target="blank" href="{$link->getAdminLink('AdminNormalProducts')|escape:'html':'UTF-8'}&amp;id_product={$service_product.id_product|escape:'html':'UTF-8'}&amp;updateproduct"><i class="icon-external-link-sign"></i></a></td>
<td>{$service_product.name}</td>
<td class="text-center"><span {if $service_product.auto_add_to_cart}class="badge badge-success"{/if}>{if $service_product.auto_add_to_cart}{l s='Yes'}{else}{l s='No'}{/if}</span></td>
<td>{l s='--'}</td>
<td>
<div class="fixed-width-xl">
<div class="input-group">
<span class="input-group-addon">{$currency->prefix}{$currency->suffix}</span>
<input type="text" name="{$inputs_prefix}price" data-id_product="{$service_product.id_product|escape:'html':'UTF-8'}" value="{if isset($smarty.post["{$inputs_prefix}price"]) && $smarty.post["{$inputs_prefix}price"]}{$smarty.post["{$inputs_prefix}price"]}{else}{$service_product.price}{/if}">
</div>
</div>
<div class="help-block">
{l s='Default price: %s' sprintf={displayPrice price=$service_product.price currency=$currency->id}}
</div>
</td>
<td>
<div class="fixed-width-xl">
<select class="service_product_id_tax_rules_group" name="{$inputs_prefix}id_tax_rules_group">
<option value="0">{l s='No Tax'}</option>
{foreach from=$tax_rules_groups item=tax_rules_group}
<option value="{$tax_rules_group.id_tax_rules_group}" {if isset($smarty.post["{$inputs_prefix}id_tax_rules_group"])}{if $tax_rules_group.id_tax_rules_group == $smarty.post["{$inputs_prefix}id_tax_rules_group"]}{/if}{elseif $tax_rules_group.id_tax_rules_group == $service_product.id_tax_rules_group}selected{/if}>
{$tax_rules_group['name']|htmlentitiesUTF8}
</option>
{/foreach}
</select>
</div>
<div class="help-block">{l s='Default tax rule: %s' sprintf=$service_product.tax_rules_group_name}</div>
</td>
</tr>
{/foreach}

View File

@@ -108,43 +108,160 @@ $(function() {
</div>
{/if}
{if isset($num_hotels) && $num_hotels}
<div class="panel">
<h3>
{if $num_hotels == 1}
{l s='1 Hotel'}
{else}
{l s='%d Hotels' sprintf=$num_hotels}
{/if}
</h3>
{$hotels}
</div>
{/if}
{if isset($num_hotel_features) && $num_hotel_features}
<div class="panel">
<h3>
{if $num_hotel_features == 1}
{l s='1 hotel feature'}
{else}
{l s='%d hotel features' sprintf=$num_hotel_features}
{/if}
</h3>
{$hotel_features}
</div>
{/if}
{if isset($num_products) && $num_products}
<div class="panel">
<h3>
{if $num_products == 1}
{l s='1 product'}
{else}
{l s='%d products' sprintf=$num_products}
{/if}
</h3>
{$products}
</div>
<div class="panel">
<h3>
{if $num_products == 1}
{l s='1 room type'}
{else}
{l s='%d room types' sprintf=$num_products}
{/if}
</h3>
{$products}
</div>
{/if}
{if isset($num_catalog_features) && $num_catalog_features}
<div class="panel">
<h3>
{if $num_catalog_features == 1}
{l s='1 feature'}
{else}
{l s='%d features' sprintf=$num_catalog_features}
{/if}
</h3>
{$catalog_features}
</div>
{/if}
{if isset($num_service_products) && $num_service_products}
<div class="panel">
<h3>
{if $num_service_products == 1}
{l s='1 service product'}
{else}
{l s='%d service products' sprintf=$num_service_products}
{/if}
</h3>
{$service_products}
</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>
{if $num_refund_rules == 1}
{l s='1 refund rule'}
{else}
{l s='%d refund rules' sprintf=$num_refund_rules}
{/if}
</h3>
{$refund_rules}
</div>
{/if}
{if isset($num_customers) && $num_customers}
<div class="panel">
<h3>
{if $num_customers == 1}
{l s='1 customer'}
{else}
{l s='%d customers' sprintf=$num_customers}
{/if}
</h3>
{$customers}
</div>
<div class="panel">
<h3>
{if $num_customers == 1}
{l s='1 customer'}
{else}
{l s='%d customers' sprintf=$num_customers}
{/if}
</h3>
{$customers}
</div>
{/if}
{if isset($num_groups) && $num_groups}
<div class="panel">
<h3>
{if $num_groups == 1}
{l s='1 group'}
{else}
{l s='%d groups' sprintf=$num_groups}
{/if}
</h3>
{$groups}
</div>
{/if}
{if isset($num_customer_address) && $num_customer_address}
<div class="panel">
<h3>
{if $num_customer_address == 1}
{l s='1 customer address'}
{else}
{l s='%d customer addresses' sprintf=$num_customer_address}
{/if}
</h3>
{$customer_address}
</div>
{/if}
{if isset($num_order_messages) && $num_order_messages}
<div class="panel">
<h3>
{if $num_order_messages == 1}
{l s='1 customer service message'}
{else}
{l s='%d customer service messages' sprintf=$num_order_messages}
{/if}
</h3>
{$order_messages}
</div>
{/if}
{if isset($num_orders) && $num_orders}
<div class="panel">
<h3>
{if $num_orders == 1}
{l s='1 order'}
{else}
{l s='%d orders' sprintf=$num_orders}
{/if}
</h3>
{$orders}
</div>
<div class="panel">
<h3>
{if $num_orders == 1}
{l s='1 order'}
{else}
{l s='%d orders' sprintf=$num_orders}
{/if}
</h3>
{$orders}
</div>
{/if}
{if isset($addons) && $addons}

View File

@@ -31,13 +31,17 @@
<tr>
<th class="fixed-width-xs">
<span class="title_box">
<input type="checkbox" name="checkme" id="checkme" onclick="checkDelBoxes(this.form, 'groupBox[]', this.checked)" />
<input type="checkbox" name="checkme" id="checkme" onclick="checkDelBoxes(this.form, '{$input['name']}[]', this.checked)" />
</span>
</th>
<th class="fixed-width-xs">
<span class="title_box">
{if isset($input['groups_id_title']) && $input['groups_id_title']}{$input['groups_id_title']}{else}{l s='ID'}{/if}
</span>
</th>
<th class="fixed-width-xs"><span class="title_box">{l s='ID'}</span></th>
<th>
<span class="title_box">
{l s='Group name'}
{if isset($input['groups_title']) && $input['groups_title']}{$input['groups_title']}{else}{l s='Group name'}{/if}
</span>
</th>
</tr>
@@ -46,8 +50,8 @@
{foreach $groups as $key => $group}
<tr>
<td>
{assign var=id_checkbox value=groupBox|cat:'_'|cat:$group['id_group']}
<input type="checkbox" name="groupBox[]" class="groupBox" id="{$id_checkbox}" value="{$group['id_group']}" {if $fields_value[$id_checkbox]}checked="checked"{/if} />
{assign var=id_checkbox value=$input['name']|cat:'_'|cat:$group['id_group']}
<input type="checkbox" name="{$input['name']}[]" class="groupBox" id="{$id_checkbox}" value="{$group['id_group']}" {if $fields_value[$id_checkbox]}checked="checked"{/if} />
</td>
<td>{$group['id_group']}</td>
<td>

View File

@@ -422,21 +422,13 @@
prevText: '',
nextText: '',
dateFormat: 'yy-mm-dd',
beforeShow: function() {
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (typeof dateTo != 'undefined' && dateTo != '') {
let objDateToMax = $.datepicker.parseDate('yy-mm-dd', dateTo);
objDateToMax.setDate(objDateToMax.getDate() - 1);
$('#local_{$params.id_date}_0').datepicker('option', 'maxDate', objDateToMax);
}
},
onClose: function() {
let dateFrom = $('#local_{$params.id_date}_0').val().trim();
let dateTo = $('#local_{$params.id_date}_1').val().trim();
if (dateFrom >= dateTo) {
if ((dateFrom && dateTo) && (dateFrom >= dateTo)) {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
objDateToMin.setDate(objDateToMin.getDate());
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}
@@ -452,7 +444,7 @@
if (typeof dateFrom != 'undefined' && dateFrom != '') {
let objDateToMin = $.datepicker.parseDate('yy-mm-dd', dateFrom);
objDateToMin.setDate(objDateToMin.getDate() + 1);
objDateToMin.setDate(objDateToMin.getDate());
$('#local_{$params.id_date}_1').datepicker('option', 'minDate', objDateToMin);
}

View File

@@ -83,7 +83,7 @@
<li>
<a id="page-header-desc-{$table}-{if isset($btn.imgclass)}{$btn.imgclass|escape}{else}{$k}{/if}" class="toolbar_btn {if isset($btn.target) && $btn.target} _blank{/if} pointer"{if isset($btn.href)} href="{$btn.href|escape}"{/if} title="{if isset($btn.help)}{$btn.help}{else}{$btn.desc|escape}{/if}"{if isset($btn.js) && $btn.js} onclick="{$btn.js}"{/if}{if isset($btn.modal_target) && $btn.modal_target} data-target="{$btn.modal_target}" data-toggle="modal"{/if}{if isset($btn.help)} data-toggle="tooltip" data-placement="bottom"{/if}>
<i class="{if isset($btn.icon)}{$btn.icon|escape}{else}process-icon-{if isset($btn.imgclass)}{$btn.imgclass|escape}{else}{$k}{/if}{/if}{if isset($btn.class)} {$btn.class|escape}{/if}"></i>
<div{if isset($btn.force_desc) && $btn.force_desc == true } class="locked"{/if}>{$btn.desc|escape}</div>
<span{if isset($btn.force_desc) && $btn.force_desc == true } class="locked"{/if}>{$btn.desc|escape}</span>
</a>
</li>
{/if}
@@ -92,7 +92,7 @@
<li>
<a id="page-header-desc-{$table}-{if isset($toolbar_btn['modules-list'].imgclass)}{$toolbar_btn['modules-list'].imgclass}{else}modules-list{/if}" class="toolbar_btn{if isset($toolbar_btn['modules-list'].class)} {$toolbar_btn['modules-list'].class}{/if}{if isset($toolbar_btn['modules-list'].target) && $toolbar_btn['modules-list'].target} _blank{/if}" {if isset($toolbar_btn['modules-list'].href)}href="{$toolbar_btn['modules-list'].href}"{/if} title="{$toolbar_btn['modules-list'].desc}"{if isset($toolbar_btn['modules-list'].js) && $toolbar_btn['modules-list'].js} onclick="{$toolbar_btn['modules-list'].js}"{/if}>
<i class="{if isset($toolbar_btn['modules-list'].icon)}{$toolbar_btn['modules-list'].icon}{else}process-icon-{if isset($toolbar_btn['modules-list'].imgclass)}{$toolbar_btn['modules-list'].imgclass}{else}modules-list{/if}{/if}"></i>
<div{if isset($toolbar_btn['modules-list'].force_desc) && $toolbar_btn['modules-list'].force_desc == true } class="locked"{/if}>{$toolbar_btn['modules-list'].desc}</div>
<span{if isset($toolbar_btn['modules-list'].force_desc) && $toolbar_btn['modules-list'].force_desc == true } class="locked"{/if}>{$toolbar_btn['modules-list'].desc}</span>
</a>
</li>
{/if}
@@ -115,9 +115,15 @@
});
{/if}
$('.process-icon-modules-list').parent('a').unbind().bind('click', function (){
$('#modules_list_container').modal('show');
openModulesList();
$('.process-icon-modules-list').parent('a').unbind().bind('click', async function (){
let loggedIn = await checkIfEmployeeIsLoggedIn();
if (loggedIn) {
$('#modules_list_container').modal('show');
openModulesList();
} else {
window.location = window.location.pathname;
}
});
//]]>
</script>

View File

@@ -39,36 +39,41 @@
</li>
<li class="divider"></li>
<li class="search-book search-option">
<a href="#" data-value="1" data-placeholder="{l s='Product name, SKU, reference...'}" data-icon="icon-book">
<a href="#" data-value="{$QLO_SEARCH_TYPE_CATELOG}" data-placeholder="{l s='Room Types, Service products...'}" data-icon="icon-book">
<i class="icon-book"></i> {l s='Catalog'}
</a>
</li>
<li class="search-modules search-option">
<a href="#" data-value="{$QLO_SEARCH_TYPE_HOTEL}" data-placeholder="{l s='Hotel'}" data-icon="icon-AdminHotelReservationSystemManagement">
<i class="icon-building"></i> {l s='Hotel'}
</a>
</li>
<li class="search-customers-name search-option">
<a href="#" data-value="2" data-placeholder="{l s='Email, name...'}" data-icon="icon-group">
<a href="#" data-value="{$QLO_SEARCH_TYPE_CUSTOMER_BY_NAME}" data-placeholder="{l s='Email, name...'}" data-icon="icon-group">
<i class="icon-group"></i> {l s='Customers'} {l s='by name'}
</a>
</li>
<li class="search-customers-addresses search-option">
<a href="#" data-value="6" data-placeholder="{l s='123.45.67.89'}" data-icon="icon-desktop">
<a href="#" data-value="{$QLO_SEARCH_TYPE_CUSTOMER_BY_IP}" data-placeholder="{l s='123.45.67.89'}" data-icon="icon-desktop">
<i class="icon-desktop"></i> {l s='Customers'} {l s='by ip address'}</a>
</li>
<li class="search-orders search-option">
<a href="#" data-value="3" data-placeholder="{l s='Order ID'}" data-icon="icon-credit-card">
<a href="#" data-value="{$QLO_SEARCH_TYPE_ORDER}" data-placeholder="{l s='Order ID'}" data-icon="icon-credit-card">
<i class="icon-credit-card"></i> {l s='Orders'}
</a>
</li>
<li class="search-invoices search-option">
<a href="#" data-value="4" data-placeholder="{l s='Invoice Number'}" data-icon="icon-book">
<a href="#" data-value="{$QLO_SEARCH_TYPE_INVOICE}" data-placeholder="{l s='Invoice Number'}" data-icon="icon-book">
<i class="icon-book"></i> {l s='Invoices'}
</a>
</li>
<li class="search-carts search-option">
<a href="#" data-value="5" data-placeholder="{l s='Cart ID'}" data-icon="icon-shopping-cart">
<a href="#" data-value="{$QLO_SEARCH_TYPE_CART}" data-placeholder="{l s='Cart ID'}" data-icon="icon-shopping-cart">
<i class="icon-shopping-cart"></i> {l s='Carts'}
</a>
</li>
<li class="search-modules search-option">
<a href="#" data-value="7" data-placeholder="{l s='Module name'}" data-icon="icon-puzzle-piece">
<a href="#" data-value="{$QLO_SEARCH_TYPE_MODULE}" data-placeholder="{l s='Module name'}" data-icon="icon-puzzle-piece">
<i class="icon-puzzle-piece"></i> {l s='Modules'}
</a>
</li>

View File

@@ -125,8 +125,8 @@ class AddressCore extends ObjectModel
'id_state' => array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId'),
'alias' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
'company' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'size' => 255),
'lastname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'firstname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'lastname' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
'firstname' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
'vat_number' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'address1' => array('type' => self::TYPE_STRING, 'validate' => 'isAddress', 'required' => true, 'size' => 128),
'address2' => array('type' => self::TYPE_STRING, 'validate' => 'isAddress', 'size' => 128),
@@ -180,7 +180,7 @@ class AddressCore extends ObjectModel
{
// for customer address we need to check of customer address already exists.
if ($this->id_customer) {
if ($id_address = Customer::getCustomerIdAddress($this->id_customer)) {
if ($id_address = Customer::getCustomerIdAddress($this->id_customer, false)) {
return false;
}
}
@@ -482,4 +482,32 @@ class AddressCore extends ObjectModel
}
return array();
}
public function searchByName($query, $idLang = false)
{
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
return Db::getInstance()->executeS(
'SELECT a.`id_address`, a.`firstname`, a.`lastname`, a.`address1`, a.`postcode`, a.`city`,
cl.`name` AS `country_name`, s.`name` AS `state_name`
FROM `'._DB_PREFIX_.'address` a
LEFT JOIN `'._DB_PREFIX_.'country_lang` cl
ON cl.`id_country` = a.`id_country`
LEFT JOIN `'._DB_PREFIX_.'state` s
ON s.`id_country` = cl.`id_country`
WHERE id_customer > 0 AND
(a.`address1` LIKE \'%'.$query.'%\' OR
a.`postcode` LIKE \'%'.$query.'%\' OR
a.`city` LIKE \'%'.$query.'%\' OR
a.`phone` LIKE \'%'.$query.'%\' OR
a.`company` LIKE \'%'.$query.'%\' OR
a.`alias` LIKE \'%'.$query.'%\' OR
s.`name` LIKE \'%'.$query.'%\' OR
cl.`name` LIKE \'%'.$query.'%\'
)
');
}
}

View File

@@ -1300,7 +1300,8 @@ class CarrierCore extends ObjectModel
}
$id_address = (int)((!is_null($id_address_delivery) && $id_address_delivery != 0) ? $id_address_delivery : $cart->id_address_delivery);
if ($id_address) {
$obj_address = new Address($id_address);
if (Validate::isLoadedObject($obj_address)) {
$id_zone = Address::getZoneById($id_address);
// Check the country of the address is activated

View File

@@ -532,7 +532,7 @@ class CartCore extends ObjectModel
$sql = new DbQuery();
// Build SELECT
$sql->select('cp.`id_product_attribute`, cp.`id_product`, cp.`quantity` AS cart_quantity, cp.id_shop, pl.`name`, p.`is_virtual`, p.`booking_product`, p.`service_product_type`, p.`auto_add_to_cart`, p.`price_addition_type`, product_shop.`allow_multiple_quantity`, product_shop.`price_calculation_method`,
$sql->select('cp.`id_product_attribute`, cp.`id_product`, cp.`quantity` AS cart_quantity, cp.id_shop, pl.`name`, p.`is_virtual`, p.`booking_product`, p.`service_product_type`, p.`auto_add_to_cart`, p.`price_addition_type`, p.`show_at_front`, product_shop.`allow_multiple_quantity`, product_shop.`price_calculation_method`,
pl.`description_short`, pl.`available_now`, pl.`available_later`, product_shop.`id_category_default`, p.`id_supplier`,
p.`id_manufacturer`, product_shop.`on_sale`, product_shop.`ecotax`, product_shop.`additional_shipping_cost`,
product_shop.`available_for_order`, product_shop.`price`, product_shop.`active`, product_shop.`unity`, product_shop.`unit_price_ratio`,
@@ -781,8 +781,8 @@ class CartCore extends ObjectModel
case Order::ROUND_ITEM:
default:
$row['total'] = Tools::ps_round($totalPriceByProductTaxExcl, _PS_PRICE_COMPUTE_PRECISION_) * (int)$row['cart_quantity'];
$row['total_wt'] = Tools::ps_round($totalPriceByProductTaxIncl, _PS_PRICE_COMPUTE_PRECISION_) * (int)$row['cart_quantity'];
$row['total'] = Tools::ps_round($totalPriceByProductTaxExcl, _PS_PRICE_COMPUTE_PRECISION_);
$row['total_wt'] = Tools::ps_round($totalPriceByProductTaxIncl, _PS_PRICE_COMPUTE_PRECISION_);
break;
}
}
@@ -804,8 +804,8 @@ class CartCore extends ObjectModel
case Order::ROUND_ITEM:
default:
$row['total'] = Tools::ps_round($totalPriceByProductTaxExcl, _PS_PRICE_COMPUTE_PRECISION_) * (int)$row['cart_quantity'];
$row['total_wt'] = Tools::ps_round($totalPriceByProductTaxIncl, _PS_PRICE_COMPUTE_PRECISION_) * (int)$row['cart_quantity'];
$row['total'] = Tools::ps_round($totalPriceByProductTaxExcl, _PS_PRICE_COMPUTE_PRECISION_);
$row['total_wt'] = Tools::ps_round($totalPriceByProductTaxIncl, _PS_PRICE_COMPUTE_PRECISION_);
break;
}
} else {
@@ -2387,7 +2387,6 @@ class CartCore extends ObjectModel
$array[$selectedProduct['id_hotel']] = array(
'quantity' => $selectedProduct['quantity'],
'id_hotel' => $selectedProduct['id_hotel'],
'unit_price_tax_incl' => $selectedProduct['unit_price_tax_incl'],
'total_price_tax_excl' => $selectedProduct['total_price_tax_excl'],
'total_price_tax_incl' => $selectedProduct['total_price_tax_incl'],
);
@@ -2397,7 +2396,8 @@ class CartCore extends ObjectModel
$product['cart_quantity'] = $selectedProduct['quantity'];
$product['total'] = $selectedProduct['total_price_tax_excl'];
$product['total_wt'] = $selectedProduct['total_price_tax_incl'];
$product['price_wt'] = $selectedProduct['unit_price_tax_incl'];
$product['price_wt'] = $selectedProduct['total_price_tax_incl'] / $product['cart_quantity'];
$product['price'] = $selectedProduct['total_price_tax_excl'] / $product['cart_quantity'];
$product['id_hotel'] = $selectedProduct['id_hotel'];
$orderPackage[$id_address][$selectedProduct['id_hotel']]['product_list'][] = $product;
if (!isset($orderPackage[$id_address][$selectedProduct['id_hotel']]['id_hotel'])) {
@@ -2431,6 +2431,7 @@ class CartCore extends ObjectModel
$unitPriceWt = $objHotelServiceProductCartDetail->getHotelProductUnitPrice($this->id, $product['id_product'], $hotelProduct['id_hotel'], true);
$serviceProduct['total'] = $unitPrice * $hotelProduct['quantity'];
$serviceProduct['total_wt'] = $unitPriceWt * $hotelProduct['quantity'];
$serviceProduct['price'] = $unitPrice;
$serviceProduct['price_wt'] = $unitPriceWt;
// if (!empty($hotelProducts['products'])) {
// foreach($hotelProducts['products'] as $hotelProduct) {

View File

@@ -421,7 +421,7 @@ class CartRuleCore extends ObjectModel
* @param $name
* @return bool
*/
public static function cartRuleExists($name)
public static function cartRuleExists($code, $id_customer = 0)
{
if (!CartRule::isFeatureActive()) {
return false;
@@ -430,7 +430,8 @@ class CartRuleCore extends ObjectModel
return (bool)Db::getInstance()->getValue('
SELECT `id_cart_rule`
FROM `'._DB_PREFIX_.'cart_rule`
WHERE `code` = \''.pSQL($name).'\'');
WHERE `code` = \''.pSQL($code).'\''.
($id_customer ? 'AND `id_customer` = '.(int) $id_customer : ''));
}
/**
@@ -601,7 +602,7 @@ class CartRuleCore extends ObjectModel
// Check if the cart rule is only usable by a specific customer, and if the current customer is the right one
if ($this->id_customer && $context->cart->id_customer != $this->id_customer) {
if (!Context::getContext()->customer->isLogged()) {
if (!defined('_PS_ADMIN_DIR_') && !Context::getContext()->customer->isLogged()) {
return (!$display_error) ? false : (Tools::displayError('You cannot use this voucher').' - '.Tools::displayError('Please log in first'));
}
return (!$display_error) ? false : Tools::displayError('You cannot use this voucher');
@@ -1466,15 +1467,16 @@ class CartRuleCore extends ObjectModel
* @param $id_lang
* @return array
*/
public static function getCartsRuleByCode($name, $id_lang, $extended = false)
public static function getCartsRuleByCode($name, $id_lang, $extended = false, $id_customer = 0)
{
$sql_base = 'SELECT cr.*, crl.*
FROM '._DB_PREFIX_.'cart_rule cr
LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)$id_lang.')';
FROM '._DB_PREFIX_.'cart_rule cr
LEFT JOIN '._DB_PREFIX_.'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = '.(int)$id_lang.')
WHERE 1'.($id_customer ? ' AND (cr.`id_customer` = 0 OR cr.`id_customer` = '.(int) $id_customer.')' : '');
if ($extended) {
return Db::getInstance()->executeS('('.$sql_base.' WHERE code LIKE \'%'.pSQL($name).'%\') UNION ('.$sql_base.' WHERE name LIKE \'%'.pSQL($name).'%\')');
return Db::getInstance()->executeS('('.$sql_base.' AND code LIKE \'%'.pSQL($name).'%\') UNION ('.$sql_base.' AND name LIKE \'%'.pSQL($name).'%\')');
} else {
return Db::getInstance()->executeS($sql_base.' WHERE code LIKE \'%'.pSQL($name).'%\'');
return Db::getInstance()->executeS($sql_base.' AND code LIKE \'%'.pSQL($name).'%\'');
}
}
}

View File

@@ -115,7 +115,6 @@ class ConfigurationTestCore
'register_globals' => false,
'gz' => false,
'mbstring' => false,
'magicquotes' => false,
'dom' => false,
);
}
@@ -181,11 +180,6 @@ class ConfigurationTestCore
return extension_loaded('simplexml');
}
public static function test_magicquotes()
{
return function_exists('get_magic_quotes_gpc') ? !get_magic_quotes_gpc() : true;
}
public static function test_upload()
{
return ini_get('file_uploads');

View File

@@ -93,7 +93,7 @@ class CookieCore
$this->_path = str_replace('%7E', '~', $this->_path);
$this->_domain = $this->getDomain($shared_urls);
$this->_sameSite = Configuration::get('PS_COOKIE_SAMESITE');
$this->_name = 'PrestaShop-'.md5(($this->_standalone ? '' : _PS_VERSION_).$name.$this->_domain);
$this->_name = 'QloApps-'.md5(($this->_standalone ? '' : _PS_VERSION_).$name.$this->_domain);
$this->_allow_writing = true;
$this->_salt = $this->_standalone ? str_pad('', 8, md5('ps'.__FILE__)) : _COOKIE_IV_;
if ($this->_standalone) {

View File

@@ -465,10 +465,10 @@ class CustomerCore extends ObjectModel
return Cache::retrieve($cache_id);
}
public static function getCustomerIdAddress($id_customer)
public static function getCustomerIdAddress($id_customer, $use_cache = true)
{
$cache_id = 'Customer::getCustomerIdAddress'.(int)$id_customer;
if (!Cache::isStored($cache_id)) {
if (!$use_cache || !Cache::isStored($cache_id)) {
$sql = 'SELECT id_address
FROM `'._DB_PREFIX_.'address` a
WHERE `id_customer` = '.(int)$id_customer.' AND a.`deleted` = 0';
@@ -528,14 +528,16 @@ class CustomerCore extends ObjectModel
* @return array|false|mysqli_result|null|PDOStatement|resource Corresponding customers
* @throws PrestaShopDatabaseException
*/
public static function searchByName($query, $limit = null)
public static function searchByName($query, $limit = null, $skip_deleted = false)
{
$sql_base = 'SELECT *
FROM `'._DB_PREFIX_.'customer`';
$sql = '('.$sql_base.' WHERE `email` LIKE \'%'.pSQL($query).'%\' '.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `id_customer` = '.(int)$query.' '.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `lastname` LIKE \'%'.pSQL($query).'%\' '.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `firstname` LIKE \'%'.pSQL($query).'%\' '.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
FROM `'._DB_PREFIX_.'customer`';
$where_deleted = $skip_deleted ? ' AND `deleted` = 0' : '';
$sql = '('.$sql_base.' WHERE `email` LIKE \'%'.pSQL($query).'%\' '.$where_deleted.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `id_customer` = '.(int)$query.' '.$where_deleted.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `lastname` LIKE \'%'.pSQL($query).'%\' '.$where_deleted.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
$sql .= ' UNION ('.$sql_base.' WHERE `firstname` LIKE \'%'.pSQL($query).'%\' '.$where_deleted.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).')';
if ($limit) {
$sql .= ' LIMIT 0, '.(int)$limit;
@@ -796,6 +798,7 @@ class CustomerCore extends ObjectModel
$this->passwd = Tools::encrypt($password);
$this->cleanGroups();
$this->addGroups(array(Configuration::get('PS_CUSTOMER_GROUP'))); // add default customer group
$this->id_default_group = (int) Configuration::get('PS_CUSTOMER_GROUP');
if ($this->update()) {
$vars = array(
'{firstname}' => $this->firstname,

View File

@@ -118,7 +118,7 @@ class CustomerMessageCore extends ObjectModel
}
return parent::delete();
}
public static function getMessagesByDate($date)
{
return Db::getInstance()->getValue(
@@ -127,4 +127,18 @@ class CustomerMessageCore extends ObjectModel
WHERE cm.`date_add` BETWEEN "'.pSQL($date).' 00:00:00" AND "'.pSQL($date).' 23:59:59"'
);
}
public function searchByName($query)
{
return Db::getInstance()->executeS('
SELECT cm.*, ct.*, CONCAT(c.`firstname`, \' \', c.`lastname`) `customer_name`
FROM `'._DB_PREFIX_.'customer_message` cm
LEFT JOIN '._DB_PREFIX_.'customer_thread ct
ON (ct.`id_customer_thread` = cm.`id_customer_thread`)
LEFT JOIN '._DB_PREFIX_.'customer c
ON (IFNULL(ct.`id_customer`, ct.`email`) = IFNULL(c.`id_customer`, c.`email`))
WHERE `message` LIKE \'%'.$query.'%\'
');
}
}

View File

@@ -279,7 +279,12 @@ class DispatcherCore
$controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$module_name.'/controllers/front/');
if (isset($controllers[strtolower($this->controller)])) {
include_once(_PS_MODULE_DIR_.$module_name.'/controllers/front/'.$this->controller.'.php');
$controller_class = $module_name.$this->controller.'ModuleFrontController';
if (file_exists(_PS_OVERRIDE_DIR_.'modules/'.$module_name.'/controllers/front/'.$this->controller.'.php')) {
include_once(_PS_OVERRIDE_DIR_.'modules/'.$module_name.'/controllers/front/'.$this->controller.'.php');
$controller_class = $module_name.$this->controller.'ModuleFrontControllerOverride';
} else {
$controller_class = $module_name.$this->controller.'ModuleFrontController';
}
}
}
$params_hook_action_dispatcher = array('controller_type' => self::FC_FRONT, 'controller_class' => $controller_class, 'is_module' => 1);
@@ -300,12 +305,22 @@ class DispatcherCore
} else {
$controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$tab->module.'/controllers/admin/');
if (!isset($controllers[strtolower($this->controller)])) {
// If this is a parent tab, load the first child
if (Validate::isLoadedObject($tab) && $tab->id_parent == 0 && ($tabs = Tab::getTabs(Context::getContext()->language->id, $tab->id)) && isset($tabs[0])) {
Tools::redirectAdmin(Context::getContext()->link->getAdminLink($tabs[0]['class_name']));
}
$this->controller = $this->controller_not_found;
$controller_class = 'AdminNotFoundController';
} else {
// Controllers in modules can be named AdminXXX.php or AdminXXXController.php
include_once(_PS_MODULE_DIR_.$tab->module.'/controllers/admin/'.$controllers[strtolower($this->controller)].'.php');
$controller_class = $controllers[strtolower($this->controller)].(strpos($controllers[strtolower($this->controller)], 'Controller') ? '' : 'Controller');
if (file_exists(_PS_OVERRIDE_DIR_ . 'modules/' . $tab->module . '/controllers/admin/' . $controllers[strtolower($this->controller)] . '.php')) {
include_once(_PS_OVERRIDE_DIR_ . 'modules/' . $tab->module . '/controllers/admin/' . $controllers[strtolower($this->controller)] . '.php');
$controller_class = $controllers[strtolower($this->controller)] . (strpos($controllers[strtolower($this->controller)], 'Controller') ? 'Override' : 'ControllerOverride');
} else {
$controller_class = $controllers[strtolower($this->controller)] . (strpos($controllers[strtolower($this->controller)], 'Controller') ? '' : 'Controller');
}
}
}
$params_hook_action_dispatcher = array('controller_type' => self::FC_ADMIN, 'controller_class' => $controller_class, 'is_module' => 1);

View File

@@ -361,4 +361,18 @@ class FeatureCore extends ObjectModel
{
return $this->id;
}
public static function searchByName($name, $idLang = false)
{
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
return Db::getInstance()->executeS('
SELECT *
FROM '._DB_PREFIX_.'feature_lang
WHERE `name` LIKE \'%'.pSQL($name).'%\'
AND `id_lang`='.(int)$idLang
);
}
}

View File

@@ -372,4 +372,16 @@ class GroupCore extends ObjectModel
WHERE `name` = \''.pSQL($query).'\'
');
}
public function searchGroupsByName($query)
{
return Db::getInstance()->executeS('
SELECT g.*, gl.*
FROM `'._DB_PREFIX_.'group` g
LEFT JOIN `'._DB_PREFIX_.'group_lang` gl
ON (g.`id_group` = gl.`id_group`)
WHERE `name` LIKE \'%'.pSQL($query).'%\'
');
}
}

View File

@@ -211,7 +211,9 @@ abstract class ObjectModelCore implements Core_Foundation_Database_EntityInterfa
throw new PrestaShopException('Identifier or table format not valid for class '.$class_name);
}
ObjectModel::$loaded_classes[$class_name] = get_object_vars($this);
$objProperties = get_object_vars($this);
Hook::exec('actionObject'.$class_name.'PropertiesModifier', array('obj_properties' => &$objProperties));
ObjectModel::$loaded_classes[$class_name] = $objProperties;
} else {
foreach (ObjectModel::$loaded_classes[$class_name] as $key => $value) {
$this->{$key} = $value;
@@ -1885,6 +1887,8 @@ abstract class ObjectModelCore implements Core_Foundation_Database_EntityInterfa
);
}
Hook::exec('actionObject'.$class.'DefinitionModifier', array('definition' => &$definition));
if ($field) {
return isset($definition['fields'][$field]) ? $definition['fields'][$field] : null;
}

View File

@@ -277,7 +277,7 @@ abstract class PaymentModuleCore extends Module
if (Configuration::get('PS_TAX_ADDRESS_TYPE') == 'id_address_delivery') {
$address = new Address((int)$id_address);
$this->context->country = new Country((int)$address->id_country, (int)$this->context->cart->id_lang);
if (!$this->context->country->active) {
if (!$this->context->country->active && $this->name != 'wsorder') {
throw new PrestaShopException('The delivery address country is not active.');
}
}
@@ -468,7 +468,7 @@ abstract class PaymentModuleCore extends Module
$this->context->country = $context_country;
}
if (!$this->context->country->active) {
if (!$this->context->country->active && $this->name != 'wsorder') {
PrestaShopLogger::addLog('PaymentModule::validateOrder - Country is not active', 3, null, 'Cart', (int)$id_cart, true);
throw new PrestaShopException('The order address country is not active.');
}
@@ -646,17 +646,17 @@ abstract class PaymentModuleCore extends Module
// THEN
// The voucher is cloned with a new value corresponding to the remainder
$reduction_amount_converted = $cart_rule['obj']->reduction_amount;
if ((int) $cart_rule['obj']->reduction_currency !== (int) $cart->id_currency) {
if ((int) $cart_rule['obj']->reduction_currency !== (int) $this->context->cart->id_currency) {
$reduction_amount_converted = Tools::convertPriceFull(
$cart_rule['obj']->reduction_amount,
new Currency($cart_rule['obj']->reduction_currency),
new Currency($cart->id_currency)
new Currency($this->context->cart->id_currency)
);
}
if ($cart_rule['obj']->reduction_tax) {
$remaining_amount = $reduction_amount_converted - $values['tax_incl'];
$remaining_amount = $values['tax_incl'] - $order->total_products_wt;
} else {
$remaining_amount = $reduction_amount_converted - $values['tax_excl'];
$remaining_amount = $values['tax_excl'] - $order->total_products;
}
if ($remaining_amount > 0 && $cart_rule['obj']->partial_use == 1 && $reduction_amount_converted > 0) {
// Create a new voucher from the original
@@ -664,9 +664,13 @@ abstract class PaymentModuleCore extends Module
unset($voucher->id);
// Set a new voucher code
// For a customer, applying voucher ABCD will create partial vouchers ABCD-2, ABCD-3 and so on, and
// applying voucher ABCD-2 will create vouchers ABCD-2-2, ABCD-2-3 and so on
$voucher->code = empty($voucher->code) ? substr(md5($order->id.'-'.$order->id_customer.'-'.$cart_rule['obj']->id), 0, 16) : $voucher->code.'-2';
if (preg_match('/\-([0-9]{1,2})\-([0-9]{1,2})$/', $voucher->code, $matches) && $matches[1] == $matches[2]) {
$voucher->code = preg_replace('/'.$matches[0].'$/', '-'.(intval($matches[1]) + 1), $voucher->code);
while (CartRule::cartRuleExists($voucher->code, $order->id_customer)) {
if (preg_match('/\-([0-9]{1,2})$/', $voucher->code, $matches)) {
$voucher->code = preg_replace('/'.$matches[1].'$/', (intval($matches[1]) + 1), $voucher->code);
}
}
// Set the new voucher value
@@ -862,7 +866,11 @@ abstract class PaymentModuleCore extends Module
$objBookingDetail->total_paid_amount = $objAdvancedPayment->getRoomMinAdvPaymentAmount(
$idProduct,
$objCartBookingData->date_from,
$objCartBookingData->date_to
$objCartBookingData->date_to,
1,
$objCartBookingData->id_room,
$objCartBookingData->id_cart,
$objCartBookingData->id_guest
);
}
}
@@ -920,7 +928,6 @@ abstract class PaymentModuleCore extends Module
$objBookingDemand->tax_computation_method = (int)$taxCalc->computation_method;
if ($objBookingDemand->save()) {
$objBookingDemand->tax_calculator = $taxCalc;
$objBookingDemand->id_global_demand = $idGlobalDemand;
// Now save tax details of the extra demand
$objBookingDemand->setBookingDemandTaxDetails();
}
@@ -1005,11 +1012,9 @@ abstract class PaymentModuleCore extends Module
// Set the order status
$new_history = new OrderHistory();
$new_history->id_order = (int)$order->id;
if ($order_status->logable && $order->is_advance_payment && $order->advance_paid_amount < $order->total_paid_tax_incl) {
$new_history->changeIdOrderState((int)Configuration::get('PS_OS_PARTIAL_PAYMENT'), $order, true);
} else {
$new_history->changeIdOrderState((int)$id_order_state, $order, true);
}
$new_history->changeIdOrderState((int)$id_order_state, $order, true);
$new_history->addWithemail(true, $extra_vars);
// Switch to back order if needed
@@ -1044,47 +1049,19 @@ abstract class PaymentModuleCore extends Module
$normal_products_data_txt = $this->getEmailTemplateContent('hotel-service-product-data-text.tpl', Mail::TYPE_TEXT, $orderServiceProducts);
// total room price
$room_price_tax_excl = $order->getTotalProductsWithoutTaxes(false, true);
$room_price_tax_incl = $order->getTotalProductsWithTaxes(false, true);
$room_tax = ($order->getTotalProductsWithTaxes(false, true) - $order->getTotalProductsWithoutTaxes(false, true));
$room_price_tax_excl = $order->getTotalProductsWithoutTaxes(false, true) + $order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM);
$room_price_tax_incl = $order->getTotalProductsWithTaxes(false, true) + $order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM);
$room_tax = ($room_price_tax_incl - $room_price_tax_excl);
// extra services
$additional_service_price_tax_excl = ($order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE) + $cart_booking_data['total_extra_demands_te']);
$additional_service_price_tax_incl = ($order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE) + $cart_booking_data['total_extra_demands_ti']);
$additional_service_tax = (($order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE) + $cart_booking_data['total_extra_demands_ti']) - ($order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE) + $cart_booking_data['total_extra_demands_te']));
$additional_service_price_tax_excl = ($order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0) + $cart_booking_data['total_extra_demands_te']);
$additional_service_price_tax_incl = ($order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0) + $cart_booking_data['total_extra_demands_ti']);
$additional_service_tax = ($additional_service_price_tax_incl - $additional_service_price_tax_excl);
// convenience fee price
$objRoomTypeServiceProductOrderDetail = new RoomTypeServiceProductOrderDetail();
$total_convenience_fee_ti = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts(
$order->id,
0,
0,
0,
0,
0,
0,
1,
1,
1,
Product::PRICE_ADDITION_TYPE_INDEPENDENT
);
$total_convenience_fee_te = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts(
$order->id,
0,
0,
0,
0,
0,
0,
1,
0,
1,
Product::PRICE_ADDITION_TYPE_INDEPENDENT
);
$additional_service_price_tax_excl = $additional_service_price_tax_excl - $total_convenience_fee_te;
$additional_service_price_tax_incl = $additional_service_price_tax_incl - $total_convenience_fee_ti;
$room_price_tax_excl = $room_price_tax_excl + $additional_service_price_tax_excl;
$room_price_tax_incl = $room_price_tax_incl + $additional_service_price_tax_incl;
$total_convenience_fee_ti = $order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT);
$total_convenience_fee_te = $order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT);
// service products
// $service_products_price_tax_excl = $order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE);
@@ -1237,25 +1214,27 @@ abstract class PaymentModuleCore extends Module
}
if (Configuration::get('PS_ORDER_CONF_MAIL_TO_SUPERADMIN')){
// send superadmin information
if (Validate::isLoadedObject($superAdmin = new Employee(_PS_ADMIN_PROFILE_))) {
if (Validate::isEmail($superAdmin->email)) {
$data['{customer_name}'] = $this->context->customer->firstname.' '.$this->context->customer->lastname;
$data['{customer_email}'] = $this->context->customer->email;
$data['{firstname}'] = $superAdmin->firstname;
$data['{lastname}'] = $superAdmin->lastname;
$data['{email}'] = $superAdmin->email;
Mail::Send(
(int)$order->id_lang,
'order_conf_admin',
Mail::l('Order confirmation', (int)$order->id_lang),
$data,
$superAdmin->email,
$superAdmin->firstname.' '.$superAdmin->lastname,
null,
null,
$file_attachement,
null, _PS_MAIL_DIR_, false, (int)$order->id_shop
);
if ($superAdminEmployees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true)) {
foreach ($superAdminEmployees as $superAdminEmployee) {
if (Validate::isEmail($superAdminEmployee['email'])) {
$data['{customer_name}'] = $this->context->customer->firstname.' '.$this->context->customer->lastname;
$data['{customer_email}'] = $this->context->customer->email;
$data['{firstname}'] = $superAdminEmployee['firstname'];
$data['{lastname}'] = $superAdminEmployee['lastname'];
$data['{email}'] = $superAdminEmployee['email'];
Mail::Send(
(int)$order->id_lang,
'order_conf_admin',
Mail::l('Order confirmation', (int)$order->id_lang),
$data,
$superAdminEmployee['email'],
$superAdminEmployee['firstname'].' '.$superAdminEmployee['lastname'],
null,
null,
$file_attachement,
null, _PS_MAIL_DIR_, false, (int)$order->id_shop
);
}
}
}
}
@@ -1289,7 +1268,7 @@ abstract class PaymentModuleCore extends Module
$data['{customer_name}'] = $this->context->customer->firstname.' '.$this->context->customer->lastname;
$data['{customer_email}'] = $this->context->customer->email;
foreach ($htlAccesses as $access) {
if ($access['id_profile'] != _PS_ADMIN_PROFILE_) {
if ($access['access'] && $access['id_profile'] != _PS_ADMIN_PROFILE_) {
if ($htlEmployees = Employee::getEmployeesByProfile($access['id_profile'])) {
foreach ($htlEmployees as $empl) {
if (Validate::isEmail($empl['email'])) {
@@ -1659,8 +1638,11 @@ abstract class PaymentModuleCore extends Module
);
$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]['avg_paid_unit_price_tax_incl'] += ($cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] + $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te']);
$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]['avg_paid_unit_price_tax_incl'] += ($cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_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]['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_te']);
$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']);
} else {
$num_days = $obj_htl_bk_dtl->getNumberOfDays($data_v['date_from'], $data_v['date_to']);
@@ -1762,8 +1744,11 @@ abstract class PaymentModuleCore extends Module
);
$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]['avg_paid_unit_price_tax_incl'] = ($cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_price_tax_incl'] + $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_te']);
$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]['avg_paid_unit_price_tax_incl'] = ($cart_htl_data[$type_key]['date_diff'][$date_join]['paid_unit_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]['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'];
@@ -1771,10 +1756,10 @@ abstract class PaymentModuleCore extends Module
$result['total_additional_services_ti'] += $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'];
}
}
}
// calculate averages now
foreach ($cart_htl_data[$type_key]['date_diff'] as $key => &$value) {
$value['avg_paid_unit_price_tax_incl'] = Tools::ps_round($value['avg_paid_unit_price_tax_incl'] / $value['num_rm'], 6);
// calculate averages now
foreach ($cart_htl_data[$type_key]['date_diff'] as $key => &$value) {
$value['avg_paid_unit_price_tax_incl'] = Tools::ps_round($value['avg_paid_unit_price_tax_incl'] / $value['num_rm'], 6);
}
}
}
}

View File

@@ -649,12 +649,12 @@ class ProductCore extends ObjectModel
* @param int $position
* return boolean Update result
*/
public function updatePosition($way, $position)
public function updatePosition($way, $position, $id_category = null)
{
if (!$res = Db::getInstance()->executeS('
SELECT cp.`id_product`, cp.`position`, cp.`id_category`
FROM `'._DB_PREFIX_.'category_product` cp
WHERE cp.`id_category` = '.(int)Tools::getValue('id_category', 1).'
WHERE cp.`id_category` = '.(int) ($id_category ? $id_category: Tools::getValue('id_category', 1)).'
ORDER BY cp.`position` ASC')
) {
return false;
@@ -1454,23 +1454,25 @@ class ProductCore extends ObjectModel
return $result;
}
public function getServiceProducts($idLang, $front = false, $context = false)
public function getServiceProducts($active = null, $serviceProductType = null, $idLang = null, $orderBy = 'pl.name', $orderWay = 'ASC')
{
if (!$context) {
$context = Context::getContext();
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
$sql = 'SELECT p.*, product_shop.*, pl.*, image_shop.`id_image` id_image, il.`legend` as legend
FROM `'._DB_PREFIX_.'product` p
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` '.Shop::addSqlRestrictionOnLang('pl').')
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
LEFT JOIN `'._DB_PREFIX_.'image_lang` il
ON (image_shop.`id_image` = il.`id_image`
AND il.`id_lang` = '.(int)$idLang.')';
$sql .= 'WHERE pl.`id_lang` = '.(int)$idLang.' AND p.`booking_product` = 0
AND p.`service_product_type` = '.Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE.'
ORDER BY pl.`name`';
$sql = 'SELECT p.*, pl.*, i.`id_image`, il.`legend` AS legend
FROM `'._DB_PREFIX_.'product` p
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (pl.`id_product` = p.`id_product` AND pl.`id_lang` = '.(int) $idLang.')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1)
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (il.`id_image` = i.`id_image` AND il.`id_lang` = '.(int) $idLang.')
WHERE p.`booking_product` = 0'.
(!is_null($active) ? ' AND p.`active` = '.(int) $active : '').
($serviceProductType ? ' AND p.`service_product_type` = '.(int) $serviceProductType : '');
if (Validate::isOrderBy($orderBy) && Validate::isOrderBy($orderWay)) {
$sql .= ' ORDER BY '.$orderBy.' '.$orderWay;
}
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
}
@@ -2580,9 +2582,15 @@ class ProductCore extends ObjectModel
$id_address = $context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')};
$ids = Address::getCountryAndState($id_address);
$id_country = $ids['id_country'] ? (int) $ids['id_country'] : (int) Configuration::get('PS_COUNTRY_DEFAULT');
return SpecificPrice::getProductIdByDate(
$id_country = null;
if (isset($ids['id_country']) && (int) $ids['id_country']) {
$id_country = (int) $ids['id_country'];
} else {
$id_country = (int) Configuration::get('PS_COUNTRY_DEFAULT');
}
return SpecificPrice::getProductIdByDate(
$context->shop->id,
$context->currency->id,
$id_country,
@@ -3473,9 +3481,18 @@ class ProductCore extends ObjectModel
);
}
public function getPriceWithoutReduct($notax = false, $id_product_attribute = false, $decimals = 6)
public function getPriceWithoutReduct($notax = false, $id_product_attribute = false, $decimals = 6, $with_auto_add_services = 0)
{
return Product::getPriceStatic((int)$this->id, !$notax, $id_product_attribute, $decimals, null, false, false);
$price = Product::getPriceStatic((int)$this->id, !$notax, $id_product_attribute, $decimals, null, false, false);
if ($with_auto_add_services) {
if ($services = RoomTypeServiceProduct::getAutoAddServices((int) $this->id, null, null, Product::PRICE_ADDITION_TYPE_WITH_ROOM, !$notax)) {
foreach($services as $service) {
$price += $service['price'];
}
}
}
return $price;
}
/**
@@ -5320,6 +5337,68 @@ class ProductCore extends ObjectModel
return $tax_calculator->getTotalRate();
}
public function getPositionInCategory()
{
return Db::getInstance()->getValue(
'SELECT position
FROM `'._DB_PREFIX_.'category_product`
WHERE id_category = '.(int) $this->id_category_default.'
AND id_product = '.(int) $this->id
);
}
public function setPositionInCategory($position)
{
if ($position < 0) {
die(Tools::displayError('You cannot set a negative position, the minimum for a position is 0.'));
}
$result = Db::getInstance()->executeS(
'SELECT `id_product`
FROM `'._DB_PREFIX_.'category_product`
WHERE `id_category` = '.(int) $this->id_category_default.'
ORDER BY `position`'
);
if (($position > 0) && ($position + 1 > count($result))) {
die(Tools::displayError('You cannot set a position greater than the total number of room types in the hotel, minus 1 (position numbering starts at 0).'));
}
foreach ($result as &$value) {
$value = $value['id_product'];
}
$currentPosition = $this->getPositionInCategory();
if ($currentPosition && isset($result[$currentPosition])) {
$save = $result[$currentPosition];
unset($result[$currentPosition]);
array_splice($result, (int)$position, 0, $save);
}
$return = true;
foreach ($result as $position => $id_product) {
$return &= Db::getInstance()->update(
'category_product',
array('position' => $position),
'(`id_category` = '.(int) $this->id_category_default.' AND `id_product` = '.(int) $id_product.')'
);
}
return $return;
}
public static function getHighestPositionInCategory($idCategory)
{
$position = Db::getInstance()->getValue(
'SELECT MAX(`position`)
FROM `'._DB_PREFIX_.'category_product`
WHERE `id_category` = '.(int) $idCategory
);
return (is_numeric($position)) ? $position : -1;
}
/**
* Webservice getter : get product features association
* @return array
@@ -5568,14 +5647,7 @@ class ProductCore extends ObjectModel
*/
public function getWsPositionInCategory()
{
$result = Db::getInstance()->executeS('SELECT position
FROM `'._DB_PREFIX_.'category_product`
WHERE id_category = '.(int)$this->id_category_default.'
AND id_product = '.(int)$this->id);
if (count($result) > 0) {
return $result[0]['position'];
}
return '';
return $this->getPositionInCategory();
}
/**

View File

@@ -145,7 +145,12 @@ class SpecificPriceCore extends ObjectModel
FROM `'._DB_PREFIX_.'specific_price`
WHERE 1 '.self::filterOutField('id_product', $id_product).
($id_product_attribute ? ' AND id_product_attribute = '.(int) $id_product_attribute : '').'
AND id_cart = '.(int) $id_cart
AND id_cart = '.(int) $id_cart.'
GROUP BY
case when id_specific_price_rule <> 0
then id_specific_price_rule
else id_specific_price
end'
);
}
@@ -175,6 +180,12 @@ class SpecificPriceCore extends ObjectModel
$select = '(';
$priority = SpecificPrice::getPriority($id_product);
if (!Group::isFeatureActive()) {
if (($key = array_search('id_group', $priority)) !== false) {
unset($priority[$key]);
}
}
foreach (array_reverse($priority) as $k => $field) {
if (!empty($field)) {
$select .= ' IF (`'.bqSQL($field).'` = '.(int)$$field.', '.pow(2, $k + 1).', 0) + ';
@@ -353,8 +364,8 @@ class SpecificPriceCore extends ObjectModel
WHERE
`id_shop` '.self::formatIntInQuery(0, $id_shop).' AND
`id_currency` '.self::formatIntInQuery(0, $id_currency).' AND
`id_country` '.self::formatIntInQuery(0, $id_country).' AND
`id_group` '.self::formatIntInQuery(0, $id_group).' '.$query_extra.'
`id_country` '.self::formatIntInQuery(0, $id_country).
(Group::isFeatureActive() ? ' AND `id_group` '.self::formatIntInQuery(0, $id_group) : '').' '.$query_extra.'
AND IF(`from_quantity` > 1, `from_quantity`, 0) <= ';
$query .= (Configuration::get('PS_QTY_DISCOUNT_ON_COMBINATION') || !$id_cart || !$real_quantity) ? (int)$quantity : max(1, (int)$real_quantity);

View File

@@ -80,6 +80,39 @@ class ToolsCore
return $result;
}
public static function generateRandomZipcode($idCountry)
{
$randomZipCode = '';
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$alphabetLength = Tools::strlen($alphabet);
if (Validate::isLoadedObject($objCountry = new Country($idCountry))
&& $objCountry->need_zip_code
) {
if ($zipCodeFormat = $objCountry->zip_code_format) {
for ($i = 0; $i < Tools::strlen($zipCodeFormat); $i++) {
$formatCharacter = $zipCodeFormat[$i];
if (in_array($formatCharacter, array('N', 'L', 'C'))) {
if ($formatCharacter == 'N') {
$randomZipCode .= mt_rand(0, 9);
} elseif ($formatCharacter == 'L') {
$randomZipCode .= $alphabet[mt_rand(0, $alphabetLength - 1)];
} elseif ($formatCharacter == 'C') {
$randomZipCode .= $objCountry->iso_code;
}
} else {
$randomZipCode .= $formatCharacter;
}
}
} else {
for ($i = 1; $i <= 5; $i++) {
$randomZipCode .= mt_rand(0, 9);
}
}
}
return $randomZipCode;
}
/**
* Random bytes generator
*
@@ -3023,6 +3056,8 @@ exit;
$smarty = Context::getContext()->smarty;
Tools::clearCache($smarty);
Tools::clearCompile($smarty);
@copy(_PS_CACHE_DIR_.'smarty/index.php', _PS_CACHE_DIR_.'smarty/cache/index.php');
@copy(_PS_CACHE_DIR_.'smarty/index.php', _PS_CACHE_DIR_.'smarty/compile/index.php');
}
public static function clearColorListCache($id_product = false)
@@ -3603,6 +3638,8 @@ exit;
public static function purifyHTML($html, $uri_unescape = null, $allow_style = false)
{
require_once(_PS_TOOL_DIR_.'htmlpurifier/HTMLPurifier.auto.php');
static $use_html_purifier = null;
static $purifier = null;

View File

@@ -397,6 +397,14 @@ class AdminControllerCore extends Controller
/** @var int level for permissions View/read */
const LEVEL_VIEW = 1;
const QLO_SEARCH_TYPE_CATELOG = 1;
const QLO_SEARCH_TYPE_CUSTOMER_BY_NAME = 2;
const QLO_SEARCH_TYPE_ORDER = 3;
const QLO_SEARCH_TYPE_INVOICE = 4;
const QLO_SEARCH_TYPE_CART = 5;
const QLO_SEARCH_TYPE_CUSTOMER_BY_IP = 6;
const QLO_SEARCH_TYPE_MODULE = 7;
const QLO_SEARCH_TYPE_HOTEL = 8;
public function __construct()
{
@@ -407,6 +415,9 @@ class AdminControllerCore extends Controller
$this->controller_type = 'admin';
$this->controller_name = get_class($this);
if (strpos($this->controller_name, 'ControllerOverride')) {
$this->controller_name = substr($this->controller_name, 0, -18);
}
if (strpos($this->controller_name, 'Controller')) {
$this->controller_name = substr($this->controller_name, 0, -10);
}
@@ -875,13 +886,15 @@ class AdminControllerCore extends Controller
if ($field = $this->filterToField($key, $filter)) {
$type = (array_key_exists('filter_type', $field) ? $field['filter_type'] : (array_key_exists('type', $field) ? $field['type'] : false));
if (($type == 'date' || $type == 'datetime' || $type == 'range') && is_string($value)) {
if ((($type == 'date' || $type == 'datetime' || $type == 'range') || ($type == 'select' && (isset($field['multiple']) && $field['multiple'])))
&& is_string($value)
) {
$value = json_decode($value, true);
}
$key = isset($tmp_tab[1]) ? $tmp_tab[0].'.`'.$tmp_tab[1].'`' : '`'.$tmp_tab[0].'`';
// as in database 0 means position 1 in the renderlist
if (isset($field['position'])) {
if (isset($field['position']) && Validate::isInt($value)) {
$value -= 1;
}
@@ -893,21 +906,35 @@ class AdminControllerCore extends Controller
} else {
$sql_filter = & $this->_filter;
}
/* Only for date filtering (from, to) */
if (is_array($value)) {
if ($type == 'range') {
if (isset($value[0]) && !empty($value[0])) {
if (!Validate::isUnsignedInt($value[0])) {
if ($type == 'select' && (isset($field['multiple']) && $field['multiple']) && isset($field['operator'])) {
if ($field['operator'] == 'and') {
$sql_filter .= ' AND '.pSQL($key).' IN ('.pSQL(implode(',', $value)).')';
$this->_filterHaving .= ' AND COUNT(DISTINCT '.pSQL($key).') = '.(int) count($value);
} elseif ($field['operator'] == 'or') {
$sql_filter .= ' AND '.pSQL($key).' IN ('.pSQL(implode(',', $value)).')';
}
} elseif ($type == 'range') {
// set validation type
if (isset($field['validation']) && $field['validation'] && method_exists('Validate', $field['validation'])) {
$validation = $field['validation'];
} else {
$validation = 'isUnsignedInt';
}
if (isset($value[0]) && ($value[0] !== '' || $value[0] === 0)) {
if (!Validate::$validation($value[0])) {
$this->errors[] = Tools::displayError('The \'From\' value is invalid');
} else {
$sql_filter .= ' AND '.pSQL($key).' >= '.pSQL($value[0]);
}
}
if (isset($value[1]) && !empty($value[1])) {
if (!Validate::isUnsignedInt($value[1])) {
$this->errors[] = Tools::displayError('The \'From\' value is invalid');
} elseif (isset($value[0]) && !empty($value[0]) && $value[0] > $value[1]) {
$this->errors[] = Tools::displayError('The \'To\' value cannot be less than from value');
if (isset($value[1]) && ($value[1] !== '' || $value[1] === 0)) {
if (!Validate::$validation($value[1])) {
$this->errors[] = Tools::displayError('The \'To\' value is invalid');
} elseif ((isset($value[0]) && ($value[0] !== '' || $value[0] === 0)) && $value[0] > $value[1]) {
$this->errors[] = Tools::displayError('The \'To\' value cannot be less than \'From\' value');
} else {
$sql_filter .= ' AND '.pSQL($key).' <= '.pSQL($value[1]);
}
@@ -925,7 +952,7 @@ class AdminControllerCore extends Controller
if (!Validate::isDate($value[1])) {
$this->errors[] = Tools::displayError('The \'To\' date format is invalid (YYYY-MM-DD)');
} elseif (isset($value[0]) && !empty($value[0]) && strtotime($value[0]) > strtotime($value[1])) {
$this->errors[] = Tools::displayError('The \'To\' date cannot be before than from date');
$this->errors[] = Tools::displayError('The \'To\' date cannot be earlier than \'From\' date');
} else {
$sql_filter .= ' AND '.pSQL($key).' <= \''.pSQL(Tools::dateTo($value[1])).'\'';
}
@@ -2030,6 +2057,14 @@ class AdminControllerCore extends Controller
'employee' => $this->context->employee,
'search_type' => Tools::getValue('bo_search_type'),
'bo_query' => Tools::safeOutput(Tools::stripslashes(Tools::getValue('bo_query'))),
'QLO_SEARCH_TYPE_CATELOG' => self::QLO_SEARCH_TYPE_CATELOG,
'QLO_SEARCH_TYPE_CUSTOMER_BY_NAME' => self::QLO_SEARCH_TYPE_CUSTOMER_BY_NAME,
'QLO_SEARCH_TYPE_CUSTOMER_BY_IP' => self::QLO_SEARCH_TYPE_CUSTOMER_BY_IP,
'QLO_SEARCH_TYPE_ORDER' => self::QLO_SEARCH_TYPE_ORDER,
'QLO_SEARCH_TYPE_INVOICE' => self::QLO_SEARCH_TYPE_INVOICE,
'QLO_SEARCH_TYPE_CART' => self::QLO_SEARCH_TYPE_CART,
'QLO_SEARCH_TYPE_MODULE' => self::QLO_SEARCH_TYPE_MODULE,
'QLO_SEARCH_TYPE_HOTEL' => self::QLO_SEARCH_TYPE_HOTEL,
'quick_access' => $quick_access,
'multi_shop' => Shop::isFeatureActive(),
'shop_list' => $helperShop->getRenderedShopList(),
@@ -2171,6 +2206,8 @@ class AdminControllerCore extends Controller
*/
protected function initTabModuleList()
{
$this->tab_modules_list = Tab::getTabModulesList($this->id);
if (is_array($this->tab_modules_list['default_list']) && count($this->tab_modules_list['default_list'])) {
$this->filter_modules_list = $this->tab_modules_list['default_list'];
} elseif (is_array($this->tab_modules_list['slider_list']) && count($this->tab_modules_list['slider_list'])) {
@@ -2344,16 +2381,6 @@ class AdminControllerCore extends Controller
//Force override translation key
Context::getContext()->override_controller_name_for_translations = 'AdminModules';
$this->modals[] = array(
'modal_id' => 'modal_addons_connect',
'modal_class' => 'modal-md',
'modal_title' => '<i class="icon-puzzle-piece"></i> <a target="_blank" href="http://addons.prestashop.com/'
.'?utm_source=back-office&utm_medium=modules'
.'&utm_campaign=back-office-'.Tools::strtoupper($this->context->language->iso_code)
.'&utm_content='.(defined('_PS_HOST_MODE_') ? 'cloud' : 'download').'">PrestaShop Addons</a>',
'modal_content' => $this->context->smarty->fetch('controllers/modules/login_addons.tpl'),
);
//After override translation, remove it
Context::getContext()->override_controller_name_for_translations = null;
}
@@ -4018,9 +4045,23 @@ class AdminControllerCore extends Controller
$object = new $this->className((int)$id);
$object->setFieldsToUpdate(array('active' => true));
$object->active = (int)$status;
$result &= $object->update();
$isUpdated = (bool) $object->update();
$result &= $isUpdated;
if (!$isUpdated) {
$this->errors[] = sprintf($this->l('Can\'t update #%d status.'), (int) $id);
}
}
if ($result) {
$this->redirect_after = self::$currentIndex.'&conf=5&token='.$this->token;
} else {
$this->errors[] = $this->l('An error occurred while updating the status.');
}
} else {
$this->errors[] = $this->l('You must select at least one item to perform a bulk action.');
}
return $result;
}

View File

@@ -221,6 +221,7 @@ class FrontControllerCore extends Controller
'js_dir' => _THEME_JS_DIR_,
'base_dir' => __PS_BASE_URI__,
'language_code' => $this->context->language->language_code ? $this->context->language->language_code : $this->context->language->iso_code,
'language_is_rtl' => $this->context->language->is_rtl,
]);
/* get page name to display it in body id */
@@ -795,6 +796,9 @@ class FrontControllerCore extends Controller
'HOOK_MAINTENANCE' => Hook::exec('displayMaintenance', array()),
'allowEmployee' => Configuration::get('PS_ALLOW_EMP'),
'maintenance' => $this->context->link->getAdminLink('AdminMaintenance', false),
'languages' => Language::getLanguages(true, $this->context->shop->id),
'lang_iso' => $this->context->language->iso_code,
'link' => $this->context->link,
));
// If the controller is a module, then getTemplatePath will try to find the template in the modules, so we need to instanciate a real frontcontroller
$front_controller = preg_match('/ModuleFrontController$/', get_class($this)) ? new FrontController() : $this;
@@ -917,8 +921,16 @@ class FrontControllerCore extends Controller
}
$excluded_key = array('isolang', 'id_lang', 'controller', 'fc', 'id_product', 'id_category', 'id_manufacturer', 'id_supplier', 'id_cms');
foreach ($_GET as $key => $value) {
if (!in_array($key, $excluded_key) && Validate::isUrl($key) && Validate::isUrl($value)) {
$params[Tools::safeOutput($key)] = Tools::safeOutput($value);
if (!in_array($key, $excluded_key)) {
if (is_array($value)) {
if (Validate::isUrl($key)) {
$params[Tools::safeOutput($key)] = $this->sanitizeQueryOutput($value);
}
} else {
if (Validate::isUrl($key) && Validate::isUrl($value)) {
$params[Tools::safeOutput($key)] = Tools::safeOutput($value);
}
}
}
}
@@ -943,6 +955,24 @@ class FrontControllerCore extends Controller
}
}
protected function sanitizeQueryOutput($query)
{
$params = array();
foreach ($query as $key => $value) {
if (Validate::isUrl($key)) {
if (is_array($value)) {
$params[Tools::safeOutput($key)] = $this->sanitizeQueryOutput($value);
} else {
if (Validate::isUrl($value)) {
$params[Tools::safeOutput($key)] = Tools::safeOutput($value);
}
}
}
}
return $params;
}
/**
* Geolocation management
*

View File

@@ -660,23 +660,41 @@ class HelperListCore extends Helper
$value = json_decode($value, true);
}
if (isset($value[0]) && !Validate::isUnsignedInt($value[0])) {
// set validation type
if (isset($params['validation']) && $params['validation'] && method_exists('Validate', $params['validation'])) {
$validation = $params['validation'];
} else {
$validation = 'isUnsignedInt';
}
$hasValueFrom = isset($value[0]) && ($value[0] !== '' || $value[0] === 0);
if ($hasValueFrom && !Validate::$validation($value[0])) {
$value[0] = '';
}
if (isset($value[1]) && !Validate::isUnsignedInt($value[1])) {
$hasValueTo = isset($value[1]) && ($value[1] !== '' || $value[1] === 0);
if ($hasValueTo && !Validate::$validation($value[1])) {
$value[1] = '';
}
if (isset($value[0]) && isset($value[1]) && $value[0] > $value[1]) {
if ($hasValueFrom && $hasValueTo && $value[0] > $value[1]) {
$value[1] = '';
}
break;
case 'select':
foreach ($params['list'] as $option_value => $option_display) {
if (isset(Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']})
&& Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']} == $option_value
&& Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']} != '') {
$this->fields_list[$key]['select'][$option_value]['selected'] = 'selected';
if (isset($params['multiple']) && $params['multiple']) {
if (!isset($params['operator'])) {
$params['operator'] = 'or';
}
$value = json_decode($value, true);
} else {
foreach ($params['list'] as $option_value => $option_display) {
if (isset(Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']})
&& Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']} == $option_value
&& Context::getContext()->cookie->{$prefix.$this->list_id.'Filter_'.$params['filter_key']} != '') {
$this->fields_list[$key]['select'][$option_value]['selected'] = 'selected';
}
}
}
break;

View File

@@ -185,6 +185,10 @@ abstract class ModuleCore
public static $hosted_modules_blacklist = array('autoupgrade');
const OVERRIDE_TYPE_CORE = 1;
const OVERRIDE_TYPE_MODULE = 2;
const OVERRIDE_TYPE_MODULE_CONTROLLER = 3;
/**
* Set the flag to indicate we are doing an import
*
@@ -2873,6 +2877,34 @@ abstract class ModuleCore
return true;
}
public function getOverrides()
{
if (!is_dir($this->getLocalPath().'override')) {
return array();
}
$overrides = array();
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file) {
$class = basename($file, '.php');
$classInfo = array('class' => $class, 'file' => $file, 'type' => null);
if (PrestaShopAutoload::getInstance()->getClassPath($class.'Core')) {
$classInfo['type'] = self::OVERRIDE_TYPE_CORE;
} elseif (Module::getModuleIdByName($class)) {
$classInfo['type'] = self::OVERRIDE_TYPE_MODULE;
} elseif (preg_match('#^modules/([a-zA-Z0-9_-]+)/controllers/(admin|front)/([0-9a-zA-Z-_]+).php#', $file, $matches)) {
$classInfo['type'] = self::OVERRIDE_TYPE_MODULE_CONTROLLER;
$classInfo['module'] = $matches[1];
$classInfo['controller_type'] = $matches[2];
}
if ($classInfo['type']) {
$overrides[] = $classInfo;
}
}
return $overrides;
}
/**
* Install overrides files for the module
*
@@ -2885,10 +2917,9 @@ abstract class ModuleCore
}
$result = true;
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file) {
$class = basename($file, '.php');
if (PrestaShopAutoload::getInstance()->getClassPath($class.'Core') || Module::getModuleIdByName($class)) {
$result &= $this->addOverride($class);
if ($overrideClassInfos = $this->getOverrides()) {
foreach ($overrideClassInfos as $classInfo) {
$result &= $this->addOverride($classInfo);
}
}
@@ -2907,10 +2938,9 @@ abstract class ModuleCore
}
$result = true;
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file) {
$class = basename($file, '.php');
if (PrestaShopAutoload::getInstance()->getClassPath($class.'Core') || Module::getModuleIdByName($class)) {
$result &= $this->removeOverride($class);
if ($overrideClassInfos = $this->getOverrides()) {
foreach ($overrideClassInfos as $classInfo) {
$result &= $this->removeOverride($classInfo);
}
}
@@ -2923,28 +2953,50 @@ abstract class ModuleCore
* @param string $classname
* @return bool
*/
public function addOverride($classname)
public function addOverride($classInfo)
{
$orig_path = $path = PrestaShopAutoload::getInstance()->getClassPath($classname.'Core');
if (!$path) {
$path = 'modules'.DIRECTORY_SEPARATOR.$classname.DIRECTORY_SEPARATOR.$classname.'.php';
}
$path_override = $this->getLocalPath().'override'.DIRECTORY_SEPARATOR.$path;
$classname = $classInfo['class'];
if (!file_exists($path_override)) {
$parentClassFilePath = '';
$overrideClassName = $classname;
if ($classInfo['type'] == self::OVERRIDE_TYPE_CORE) {
$parentClassFilePath = PrestaShopAutoload::getInstance()->getClassPath($classname.'Core');
} elseif ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE) {
$parentClassFilePath = 'modules/'.$classname.'/'.$classname.'.php';
// require module main file
require_once _PS_ROOT_DIR_.'/'.$parentClassFilePath;
$overrideClassName = Tools::ucfirst($classname).'Override';
} elseif ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE_CONTROLLER) {
$parentClassFilePath = $classInfo['file'];
// require module controller file
require_once _PS_ROOT_DIR_.'/'.$parentClassFilePath;
if ($classInfo['controller_type'] == 'admin') {
$overrideClassName = $classname.((strpos($classname, 'Controller') === false) ? 'Controller' : '').'Override';
} else {
$overrideClassName = Tools::ucfirst($classInfo['module']).Tools::ucfirst($classInfo['class']).'ModuleFrontControllerOverride';
}
}
// the file in module which contains override information (methods, properties and constants)
$moduleClassFilePath = $this->getLocalPath().'override/'.$parentClassFilePath;
if (!file_exists($moduleClassFilePath)) {
return false;
} else {
file_put_contents($path_override, preg_replace('#(\r\n|\r)#ism', "\n", file_get_contents($path_override)));
// save $moduleClassFilePath file with consistent newline character, "\n"
file_put_contents($moduleClassFilePath, preg_replace('#(\r\n|\r)#ism', "\n", file_get_contents($moduleClassFilePath)));
}
$pattern_escape_com = '#(^\s*?\/\/.*?\n|\/\*(?!\n\s+\* module:.*?\* date:.*?\* version:.*?\*\/).*?\*\/)#ism';
// Check if there is already an override file, if not, we just need to copy the file
if ($file = PrestaShopAutoload::getInstance()->getClassPath($classname)) {
// Check if override file is writable
$override_path = _PS_ROOT_DIR_.'/'.$file;
$patternEscapeCommon = '#(^\s*?\/\/.*?\n|\/\*(?!\n\s+\* module:.*?\* date:.*?\* version:.*?\*\/).*?\*\/)#ism';
if ((!file_exists($override_path) && !is_writable(dirname($override_path))) || (file_exists($override_path) && !is_writable($override_path))) {
throw new Exception(sprintf(Tools::displayError('file (%s) not writable'), $override_path));
$overrideClassFilePath = _PS_ROOT_DIR_.'/override/'.$parentClassFilePath;
// Case 1: Check if there is already an override file, if so, merge override information otherwise just copy it
if (file_exists($overrideClassFilePath)) {
// Check if override file is writable
if (!is_writable(dirname($overrideClassFilePath)) || !is_writable($overrideClassFilePath)) {
throw new Exception(sprintf(Tools::displayError('file (%s) not writable'), $overrideClassFilePath));
}
// Get a uniq id for the class, because you can override a class (or remove the override) twice in the same session and we need to avoid redeclaration
@@ -2953,262 +3005,340 @@ abstract class ModuleCore
} while (class_exists($classname.'OverrideOriginal_remove', false));
// Make a reflection of the override class and the module override class
$override_file = file($override_path);
$override_file = array_diff($override_file, array("\n"));
eval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+'.$classname.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'), array(' ', 'class '.$classname.'OverrideOriginal'.$uniq), implode('', $override_file)));
$override_class = new ReflectionClass($classname.'OverrideOriginal'.$uniq);
$overrideClassFileArray = file($overrideClassFilePath);
$overrideClassFileArray = array_diff($overrideClassFileArray, array("\n")); // remove empty lines from array
$module_file = file($path_override);
$module_file = array_diff($module_file, array("\n"));
eval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+'.$classname.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array(' ', 'class '.$classname.'Override'.$uniq), implode('', $module_file)));
$module_class = new ReflectionClass($classname.'Override'.$uniq);
eval(
preg_replace(
array(
'#^\s*<\?(?:php)?#',
'#class\s+'.$overrideClassName.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'
),
array(
' ',
'class '.$overrideClassName.'OverrideOriginal'.$uniq
),
implode('', $overrideClassFileArray)
)
);
$reflectionClassOverride = new ReflectionClass($overrideClassName.'OverrideOriginal'.$uniq);
// Check if none of the methods already exists in the override class
foreach ($module_class->getMethods() as $method) {
if ($override_class->hasMethod($method->getName())) {
$method_override = $override_class->getMethod($method->getName());
if (preg_match('/module: (.*)/ism', $override_file[$method_override->getStartLine() - 5], $name) && preg_match('/date: (.*)/ism', $override_file[$method_override->getStartLine() - 4], $date) && preg_match('/version: ([0-9.]+)/ism', $override_file[$method_override->getStartLine() - 3], $version)) {
throw new Exception(sprintf(Tools::displayError('The method %1$s in the class %2$s is already overridden by the module %3$s version %4$s at %5$s.'), $method->getName(), $classname, $name[1], $version[1], $date[1]));
}
throw new Exception(sprintf(Tools::displayError('The method %1$s in the class %2$s is already overridden.'), $method->getName(), $classname));
}
$moduleClassFileArray = file($moduleClassFilePath);
$moduleClassFileArray = array_diff($moduleClassFileArray, array("\n")); // remove empty lines from array
$module_file = preg_replace('/((:?public|private|protected)\s+(static\s+)?function\s+(?:\b'.$method->getName().'\b))/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override method %1$s in class %2$s.'), $method->getName(), $classname));
}
}
eval(
preg_replace(
array(
'#^\s*<\?(?:php)?#',
'#class\s+'.$overrideClassName.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'
),
array(
' ',
'class '.$overrideClassName.'Override'.$uniq
),
implode('', $moduleClassFileArray)
)
);
$reflectionClassModule = new ReflectionClass($overrideClassName.'Override'.$uniq);
// Check if none of the properties already exists in the override class
foreach ($module_class->getProperties() as $property) {
if ($override_class->hasProperty($property->getName())) {
throw new Exception(sprintf(Tools::displayError('The property %1$s in the class %2$s is already defined.'), $property->getName(), $classname));
}
$module_file = preg_replace('/((?:public|private|protected)\s)\s*(static\s)?\s*(\$\b'.$property->getName().'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2$3", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override property %1$s in class %2$s.'), $property->getName(), $classname));
}
}
foreach ($module_class->getConstants() as $constant => $value) {
if ($override_class->hasConstant($constant)) {
throw new Exception(sprintf(Tools::displayError('The constant %1$s in the class %2$s is already defined.'), $constant, $classname));
}
$module_file = preg_replace('/(const\s)\s*(\b'.$constant.'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override constant %1$s in class %2$s.'), $constant, $classname));
}
}
$moduleClassFileArray = $this->getCommentedClass($moduleClassFileArray, $reflectionClassModule, $reflectionClassOverride, $overrideClassFileArray);
// Insert the methods from module override in override
$copy_from = array_slice($module_file, $module_class->getStartLine() + 1, $module_class->getEndLine() - $module_class->getStartLine() - 2);
array_splice($override_file, $override_class->getEndLine() - 1, 0, $copy_from);
$code = implode('', $override_file);
$generatedCodeToCopy = array_slice($moduleClassFileArray, $reflectionClassModule->getStartLine() + 1, $reflectionClassModule->getEndLine() - $reflectionClassModule->getStartLine() - 2);
file_put_contents($override_path, preg_replace($pattern_escape_com, '', $code));
// Merge code with that in destination override file
array_splice($overrideClassFileArray, $reflectionClassOverride->getEndLine() - 1, 0, $generatedCodeToCopy);
$code = implode('', $overrideClassFileArray);
file_put_contents($overrideClassFilePath, preg_replace($patternEscapeCommon, '', $code));
} else {
$override_src = $path_override;
// Case 2: Override file does not exist just copy override information (methods, properties and constants)
$baseDirectoryPath = dirname($overrideClassFilePath);
$override_dest = _PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'override'.DIRECTORY_SEPARATOR.$path;
$dir_name = dirname($override_dest);
if (!$orig_path && !is_dir($dir_name)) {
// Check if directory exists, if not, create
if (!is_dir($baseDirectoryPath)) {
$oldumask = umask(0000);
@mkdir($dir_name, 0777);
@mkdir($baseDirectoryPath, 0777, true); // create subdirectories if needed
umask($oldumask);
}
if (!is_writable($dir_name)) {
throw new Exception(sprintf(Tools::displayError('directory (%s) not writable'), $dir_name));
}
$module_file = file($override_src);
$module_file = array_diff($module_file, array("\n"));
if ($orig_path) {
do {
$uniq = uniqid();
} while (class_exists($classname.'OverrideOriginal_remove', false));
eval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+'.$classname.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array(' ', 'class '.$classname.'Override'.$uniq), implode('', $module_file)));
$module_class = new ReflectionClass($classname.'Override'.$uniq);
// For each method found in the override, prepend a comment with the module name and version
foreach ($module_class->getMethods() as $method) {
$module_file = preg_replace('/((:?public|private|protected)\s+(static\s+)?function\s+(?:\b'.$method->getName().'\b))/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override method %1$s in class %2$s.'), $method->getName(), $classname));
}
}
// Same loop for properties
foreach ($module_class->getProperties() as $property) {
$module_file = preg_replace('/((?:public|private|protected)\s)\s*(static\s)?\s*(\$\b'.$property->getName().'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2$3", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override property %1$s in class %2$s.'), $property->getName(), $classname));
}
}
// Same loop for constants
foreach ($module_class->getConstants() as $constant => $value) {
$module_file = preg_replace('/(const\s)\s*(\b'.$constant.'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2", $module_file);
if ($module_file === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override constant %1$s in class %2$s.'), $constant, $classname));
}
}
if (!is_writable($baseDirectoryPath)) {
throw new Exception(sprintf(Tools::displayError('directory (%s) not writable'), $baseDirectoryPath));
}
file_put_contents($override_dest, preg_replace($pattern_escape_com, '', $module_file));
$moduleClassFileArray = file($moduleClassFilePath); // read file as array
$moduleClassFileArray = array_diff($moduleClassFileArray, array("\n")); // remove empty lines from array
do {
$uniq = uniqid();
} while (class_exists($classname.'OverrideOriginal_remove', false));
eval(
preg_replace(
array(
'#^\s*<\?(?:php)?#',
'#class\s+'.$overrideClassName.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'
),
array(
' ',
'class '.$overrideClassName.'Override'.$uniq
),
implode('', $moduleClassFileArray)
)
);
$reflectionClassModule = new ReflectionClass($overrideClassName.'Override'.$uniq);
$moduleClassFileArray = $this->getCommentedClass($moduleClassFileArray, $reflectionClassModule);
file_put_contents($overrideClassFilePath, preg_replace($patternEscapeCommon, '', $moduleClassFileArray));
// Re-generate the class index
Tools::generateIndex();
}
return true;
}
private function getCommentedClass($moduleClassFileArray, $reflectionClassModule, $reflectionClassOverride = null, $overrideClassFileArray = null)
{
// Check if none of the methods already exists in the override class
foreach ($reflectionClassModule->getMethods() as $method) {
if ($reflectionClassOverride) {
if ($reflectionClassOverride->hasMethod($method->getName())) {
$overrideMethodInfo = $reflectionClassOverride->getMethod($method->getName());
if (preg_match('/module: (.*)/ism', $overrideClassFileArray[$overrideMethodInfo->getStartLine() - 5], $name) && preg_match('/date: (.*)/ism', $overrideClassFileArray[$overrideMethodInfo->getStartLine() - 4], $date) && preg_match('/version: ([0-9.]+)/ism', $overrideClassFileArray[$overrideMethodInfo->getStartLine() - 3], $version)) {
throw new Exception(sprintf(Tools::displayError('The method %1$s in the class %2$s is already overridden by the module %3$s version %4$s at %5$s.'), $method->getName(), $classname, $name[1], $version[1], $date[1]));
}
throw new Exception(sprintf(Tools::displayError('The method %1$s in the class %2$s is already overridden.'), $method->getName(), $classname));
}
}
$moduleClassFileArray = preg_replace('/((:?public|private|protected)\s+(static\s+)?function\s+(?:\b'.$method->getName().'\b))/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1", $moduleClassFileArray);
if ($moduleClassFileArray === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override method %1$s in class %2$s.'), $method->getName(), $classname));
}
}
// Check if none of the properties already exists in the override class
foreach ($reflectionClassModule->getProperties() as $property) {
if ($reflectionClassOverride) {
if ($reflectionClassOverride->hasProperty($property->getName())) {
throw new Exception(sprintf(Tools::displayError('The property %1$s in the class %2$s is already defined.'), $property->getName(), $classname));
}
}
$moduleClassFileArray = preg_replace('/((?:public|private|protected)\s)\s*(static\s)?\s*(\$\b'.$property->getName().'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2$3", $moduleClassFileArray);
if ($moduleClassFileArray === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override property %1$s in class %2$s.'), $property->getName(), $classname));
}
}
// Check if none of the constants already exists in the override class
foreach ($reflectionClassModule->getConstants() as $constant => $value) {
if ($reflectionClassOverride) {
if ($reflectionClassOverride->hasConstant($constant)) {
throw new Exception(sprintf(Tools::displayError('The constant %1$s in the class %2$s is already defined.'), $constant, $classname));
}
}
$moduleClassFileArray = preg_replace('/(const\s)\s*(\b'.$constant.'\b)/ism', "/*\n * module: ".$this->name."\n * date: ".date('Y-m-d H:i:s')."\n * version: ".$this->version."\n */\n $1$2", $moduleClassFileArray);
if ($moduleClassFileArray === null) {
throw new Exception(sprintf(Tools::displayError('Failed to override constant %1$s in class %2$s.'), $constant, $classname));
}
}
return $moduleClassFileArray;
}
/**
* Remove all methods in a module override from the override class
*
* @param string $classname
* @return bool
*/
public function removeOverride($classname)
public function removeOverride($classInfo)
{
$orig_path = $path = PrestaShopAutoload::getInstance()->getClassPath($classname.'Core');
$classname = $classInfo['class'];
if ($orig_path && !$file = PrestaShopAutoload::getInstance()->getClassPath($classname)) {
$parentClassFilePath = '';
$overrideClassName = $classname;
if ($classInfo['type'] == self::OVERRIDE_TYPE_CORE) {
$parentClassFilePath = PrestaShopAutoload::getInstance()->getClassPath($classname.'Core');
} elseif ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE) {
$parentClassFilePath = 'modules/'.$classname.'/'.$classname.'.php';
require_once _PS_ROOT_DIR_.'/'.$parentClassFilePath;
$overrideClassName = Tools::ucfirst($classname).'Override';
} elseif ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE_CONTROLLER) {
$parentClassFilePath = $classInfo['file'];
require_once _PS_ROOT_DIR_.'/'.$parentClassFilePath;
if ($classInfo['controller_type'] == 'admin') {
$overrideClassName = $classname.((strpos($classname, 'Controller') === false) ? 'Controller' : '').'Override';
} else {
$overrideClassName = Tools::ucfirst($classInfo['module']).Tools::ucfirst($classInfo['class']).'ModuleFrontControllerOverride';
}
}
$overrideClassFilePath = _PS_ROOT_DIR_.'/override/'.$parentClassFilePath;
// if override file does not exist return true
if (!file_exists($overrideClassFilePath)) {
return true;
} elseif (!$orig_path && Module::getModuleIdByName($classname)) {
$path = 'modules'.DIRECTORY_SEPARATOR.$classname.DIRECTORY_SEPARATOR.$classname.'.php';
}
// Check if override file is writable
if ($orig_path) {
$override_path = _PS_ROOT_DIR_.'/'.$file;
} else {
$override_path = _PS_OVERRIDE_DIR_.$path;
}
if (!is_file($override_path) || !is_writable($override_path)) {
if (!is_file($overrideClassFilePath) || !is_writable($overrideClassFilePath)) {
return false;
}
file_put_contents($override_path, preg_replace('#(\r\n|\r)#ism', "\n", file_get_contents($override_path)));
// save $overrideClassFilePath file with consistent newline character, "\n"
file_put_contents($overrideClassFilePath, preg_replace('#(\r\n|\r)#ism', "\n", file_get_contents($overrideClassFilePath)));
if ($orig_path) {
// Get a uniq id for the class, because you can override a class (or remove the override) twice in the same session and we need to avoid redeclaration
do {
$uniq = uniqid();
} while (class_exists($classname.'OverrideOriginal_remove', false));
// Get a uniq id for the class, because you can override a class (or remove the override) twice in the same session and we need to avoid redeclaration
do {
$uniq = uniqid();
} while (class_exists($classname.'OverrideOriginal_remove', false));
// Make a reflection of the override class and the module override class
$override_file = file($override_path);
// Make a reflection of the override class and the module override class
$overrideClassFileArray = file($overrideClassFilePath);
$moduleClassFileArray = array_diff($moduleClassFileArray, array("\n")); // remove empty lines from array
eval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+'.$classname.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'), array(' ', 'class '.$classname.'OverrideOriginal_remove'.$uniq), implode('', $override_file)));
$override_class = new ReflectionClass($classname.'OverrideOriginal_remove'.$uniq);
eval(
preg_replace(
array(
'#^\s*<\?(?:php)?#',
'#class\s+'.$overrideClassName.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'
),
array(
' ',
'class '.$overrideClassName.'Original_remove'.$uniq
),
implode('', $overrideClassFileArray)
)
);
$reflectionClassOverride = new ReflectionClass($overrideClassName.'Original_remove'.$uniq);
$module_file = file($this->getLocalPath().'override/'.$path);
eval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+'.$classname.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array(' ', 'class '.$classname.'Override_remove'.$uniq), implode('', $module_file)));
$module_class = new ReflectionClass($classname.'Override_remove'.$uniq);
$moduleClassFileArray = file($this->getLocalPath().'override/'.$parentClassFilePath);
eval(
preg_replace(
array(
'#^\s*<\?(?:php)?#',
'#class\s+'.$overrideClassName.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'
),
array(
' ',
'class '.$overrideClassName.'Override_remove'.$uniq
),
implode('', $moduleClassFileArray)
)
);
$reflectionClassModule = new ReflectionClass($overrideClassName.'Override_remove'.$uniq);
// Remove methods from override file
foreach ($module_class->getMethods() as $method) {
if (!$override_class->hasMethod($method->getName())) {
continue;
}
$method = $override_class->getMethod($method->getName());
$length = $method->getEndLine() - $method->getStartLine() + 1;
$module_method = $module_class->getMethod($method->getName());
$module_length = $module_method->getEndLine() - $module_method->getStartLine() + 1;
$override_file_orig = $override_file;
$orig_content = preg_replace('/\s/', '', implode('', array_splice($override_file, $method->getStartLine() - 1, $length, array_pad(array(), $length, '#--remove--#'))));
$module_content = preg_replace('/\s/', '', implode('', array_splice($module_file, $module_method->getStartLine() - 1, $length, array_pad(array(), $length, '#--remove--#'))));
$replace = true;
if (preg_match('/\* module: ('.$this->name.')/ism', $override_file[$method->getStartLine() - 5])) {
$override_file[$method->getStartLine() - 6] = $override_file[$method->getStartLine() - 5] = $override_file[$method->getStartLine() - 4] = $override_file[$method->getStartLine() - 3] = $override_file[$method->getStartLine() - 2] = '#--remove--#';
$replace = false;
}
if (md5($module_content) != md5($orig_content) && $replace) {
$override_file = $override_file_orig;
}
// Remove methods from override file
foreach ($reflectionClassModule->getMethods() as $method) {
if (!$reflectionClassOverride->hasMethod($method->getName())) {
continue;
}
// Remove properties from override file
foreach ($module_class->getProperties() as $property) {
if (!$override_class->hasProperty($property->getName())) {
continue;
}
$method = $reflectionClassOverride->getMethod($method->getName());
$length = $method->getEndLine() - $method->getStartLine() + 1;
// Replace the declaration line by #--remove--#
foreach ($override_file as $line_number => &$line_content) {
if (preg_match('/(public|private|protected)\s+(static\s+)?(\$)?'.$property->getName().'/i', $line_content)) {
if (preg_match('/\* module: ('.$this->name.')/ism', $override_file[$line_number - 4])) {
$override_file[$line_number - 5] = $override_file[$line_number - 4] = $override_file[$line_number - 3] = $override_file[$line_number - 2] = $override_file[$line_number - 1] = '#--remove--#';
}
$line_content = '#--remove--#';
break;
}
}
$moduleMethodInfo = $reflectionClassModule->getMethod($method->getName());
$overrideClassFileArrayOriginal = $overrideClassFileArray;
$overrideFileContent = preg_replace('/\s/', '', implode('', array_splice($overrideClassFileArray, $method->getStartLine() - 1, $length, array_pad(array(), $length, '#--remove--#'))));
$moduleFileContent = preg_replace('/\s/', '', implode('', array_splice($moduleClassFileArray, $moduleMethodInfo->getStartLine() - 1, $length, array_pad(array(), $length, '#--remove--#'))));
$replace = true;
if (preg_match('/\* module: ('.$this->name.')/ism', $overrideClassFileArray[$method->getStartLine() - 5])) {
$overrideClassFileArray[$method->getStartLine() - 6] = $overrideClassFileArray[$method->getStartLine() - 5] = $overrideClassFileArray[$method->getStartLine() - 4] = $overrideClassFileArray[$method->getStartLine() - 3] = $overrideClassFileArray[$method->getStartLine() - 2] = '#--remove--#';
$replace = false;
}
// Remove properties from override file
foreach ($module_class->getConstants() as $constant => $value) {
if (!$override_class->hasConstant($constant)) {
continue;
}
// Replace the declaration line by #--remove--#
foreach ($override_file as $line_number => &$line_content) {
if (preg_match('/(const)\s+(static\s+)?(\$)?'.$constant.'/i', $line_content)) {
if (preg_match('/\* module: ('.$this->name.')/ism', $override_file[$line_number - 4])) {
$override_file[$line_number - 5] = $override_file[$line_number - 4] = $override_file[$line_number - 3] = $override_file[$line_number - 2] = $override_file[$line_number - 1] = '#--remove--#';
}
$line_content = '#--remove--#';
break;
}
}
if (md5($moduleFileContent) != md5($overrideFileContent) && $replace) {
$overrideClassFileArray = $overrideClassFileArrayOriginal;
}
$count = count($override_file);
for ($i = 0; $i < $count; ++$i) {
if (preg_match('/(^\s*\/\/.*)/i', $override_file[$i])) {
$override_file[$i] = '#--remove--#';
} elseif (preg_match('/(^\s*\/\*)/i', $override_file[$i])) {
if (!preg_match('/(^\s*\* module:)/i', $override_file[$i + 1])
&& !preg_match('/(^\s*\* date:)/i', $override_file[$i + 2])
&& !preg_match('/(^\s*\* version:)/i', $override_file[$i + 3])
&& !preg_match('/(^\s*\*\/)/i', $override_file[$i + 4])) {
for (; $override_file[$i] && !preg_match('/(.*?\*\/)/i', $override_file[$i]); ++$i) {
$override_file[$i] = '#--remove--#';
}
$override_file[$i] = '#--remove--#';
}
}
}
// Rewrite nice code
$code = '';
foreach ($override_file as $line) {
if ($line == '#--remove--#') {
continue;
}
$code .= $line;
}
$to_delete = preg_match('/<\?(?:php)?\s+(?:abstract|interface)?\s*?class\s+'.$classname.'\s+extends\s+'.$classname.'Core\s*?[{]\s*?[}]/ism', $code);
}
if (!isset($to_delete) || $to_delete) {
unlink($override_path);
// Remove properties from override file
foreach ($reflectionClassModule->getProperties() as $property) {
if (!$reflectionClassOverride->hasProperty($property->getName())) {
continue;
}
// Replace the declaration line by #--remove--#
foreach ($overrideClassFileArray as $lineNumber => &$line_content) {
if (preg_match('/(public|private|protected)\s+(static\s+)?(\$)?'.$property->getName().'/i', $line_content)) {
if (preg_match('/\* module: ('.$this->name.')/ism', $overrideClassFileArray[$lineNumber - 4])) {
$overrideClassFileArray[$lineNumber - 5] = $overrideClassFileArray[$lineNumber - 4] = $overrideClassFileArray[$lineNumber - 3] = $overrideClassFileArray[$lineNumber - 2] = $overrideClassFileArray[$lineNumber - 1] = '#--remove--#';
}
$line_content = '#--remove--#';
break;
}
}
}
// Remove constants from override file
foreach ($reflectionClassModule->getConstants() as $constant => $value) {
if (!$reflectionClassOverride->hasConstant($constant)) {
continue;
}
// Replace the declaration line by #--remove--#
foreach ($overrideClassFileArray as $lineNumber => &$line_content) {
if (preg_match('/(const)\s+(static\s+)?(\$)?'.$constant.'/i', $line_content)) {
if (preg_match('/\* module: ('.$this->name.')/ism', $overrideClassFileArray[$lineNumber - 4])) {
$overrideClassFileArray[$lineNumber - 5] = $overrideClassFileArray[$lineNumber - 4] = $overrideClassFileArray[$lineNumber - 3] = $overrideClassFileArray[$lineNumber - 2] = $overrideClassFileArray[$lineNumber - 1] = '#--remove--#';
}
$line_content = '#--remove--#';
break;
}
}
}
$count = count($overrideClassFileArray);
for ($i = 0; $i < $count; ++$i) {
if (preg_match('/(^\s*\/\/.*)/i', $overrideClassFileArray[$i])) {
$overrideClassFileArray[$i] = '#--remove--#';
} elseif (preg_match('/(^\s*\/\*)/i', $overrideClassFileArray[$i])) {
if (!preg_match('/(^\s*\* module:)/i', $overrideClassFileArray[$i + 1])
&& !preg_match('/(^\s*\* date:)/i', $overrideClassFileArray[$i + 2])
&& !preg_match('/(^\s*\* version:)/i', $overrideClassFileArray[$i + 3])
&& !preg_match('/(^\s*\*\/)/i', $overrideClassFileArray[$i + 4])) {
for (; $overrideClassFileArray[$i] && !preg_match('/(.*?\*\/)/i', $overrideClassFileArray[$i]); ++$i) {
$overrideClassFileArray[$i] = '#--remove--#';
}
$overrideClassFileArray[$i] = '#--remove--#';
}
}
}
// Rewrite nice code
$code = '';
foreach ($overrideClassFileArray as $line) {
if ($line == '#--remove--#') {
continue;
}
$code .= $line;
}
// set regex for empty class to decide if override class must be deleted
$emptyClassRegex = '/<\?(?:php)?\s+(?:abstract|interface)?\s*?class\s+'.$overrideClassName.'\s+extends\s+'.$classname.(($classInfo['type'] == self::OVERRIDE_TYPE_CORE) ? 'Core' : '').'\s*?[{]\s*?[}]/ism';
if ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE_CONTROLLER) {
$emptyClassRegex = '/<\?(?:php)?\s+(?:abstract|interface)?\s*?class\s+'.$overrideClassName.'\s+extends\s+'.substr($overrideClassName, 0, -8).'\s*?[{]\s*?[}]/ism';
}
$toDelete = preg_match($emptyClassRegex, $code);
if (!isset($toDelete) || $toDelete) {
unlink($overrideClassFilePath);
if ($classInfo['type'] == self::OVERRIDE_TYPE_MODULE_CONTROLLER) {
$this->cleanModulesOverrideDir($overrideClassFilePath);
}
} else {
file_put_contents($override_path, $code);
file_put_contents($overrideClassFilePath, $code);
}
// Re-generate the class index
@@ -3217,6 +3347,21 @@ abstract class ModuleCore
return true;
}
private function cleanModulesOverrideDir($dir)
{
if (rtrim($dir, '/') == _PS_ROOT_DIR_.'/override/modules') {
return;
}
$files = Tools::scandir($dir, '');
$diffResult = array_diff($files, array('.', '..', 'index.php'));
if (!count($diffResult)) {
Tools::deleteDirectory($dir);
$this->cleanModulesOverrideDir(dirname($dir));
}
}
/**
* Return the hooks list where this module can be hooked.
*

View File

@@ -37,6 +37,8 @@ abstract class ModuleGraphCore extends Module
/**@var array string graph titles */
protected $_titles = array('main' => null, 'x' => null, 'y' => null);
protected $_formats = array('x' => null, 'y' => null);
/** @var ModuleGraphEngine graph engine */
protected $_render;
@@ -258,6 +260,7 @@ abstract class ModuleGraphCore extends Module
$this->_render->setSize($width, $height);
$this->_render->setLegend($this->_legend);
$this->_render->setTitles($this->_titles);
$this->_render->setFormat($this->_formats);
}
public function draw()

View File

@@ -34,6 +34,14 @@ class OrderCore extends ObjectModel
const ORDER_PAYMENT_TYPE_FULL = 1;
const ORDER_PAYMENT_TYPE_ADVANCE = 2;
//Consts for: In the order list in which currency prices should be displayed
const ORDER_LIST_PRICE_DISPLAY_IN_PAYMENT_CURRENCY = 1;
const ORDER_LIST_PRICE_DISPLAY_IN_DEFAULT_CURRENCY = 2;
const ORDER_COMPLETE_REFUND_FLAG = 1;
const ORDER_COMPLETE_CANCELLATION_FLAG = 2;
const ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG = 3;
/** @var int Delivery address id */
public $id_address_delivery;
@@ -1835,6 +1843,12 @@ class OrderCore extends ObjectModel
}
}
// Whenever payment is adding in any order then set a cumulative conversion rate for the payment currency in the order
if ($avgConversionRate = $order_payment->getAverageConversionRate($this->reference, $this->id_currency)) {
$this->conversion_rate = $avgConversionRate;
}
$this->save();
return $res;
}
@@ -1852,7 +1866,10 @@ class OrderCore extends ObjectModel
if ($payment->id_currency == $this->id_currency) {
$this->total_paid_real += $order_payment_detail->amount;
} else {
$this->total_paid_real += Tools::ps_round(Tools::convertPrice($order_payment_detail->amount, $payment->id_currency, false), 2);
$this->total_paid_real += Tools::ps_round(
Tools::convertPriceFull($order_payment_detail->amount, new Currency($payment->id_currency), new Currency($this->id_currency)),
6
);
}
if (!validate::isPrice($this->total_paid_real)) {
@@ -1891,18 +1908,18 @@ class OrderCore extends ObjectModel
unset($invoices[$key]);
}
}
$delivery_slips = $this->getDeliverySlipsCollection()->getResults();
// @TODO review
foreach ($delivery_slips as $key => $delivery) {
$delivery->is_delivery = true;
$delivery->date_add = $delivery->delivery_date;
if (!$invoice->delivery_number) {
unset($delivery_slips[$key]);
}
}
// $delivery_slips = $this->getDeliverySlipsCollection()->getResults();
// // @TODO review
// foreach ($delivery_slips as $key => $delivery) {
// $delivery->is_delivery = true;
// $delivery->date_add = $delivery->delivery_date;
// if (!$invoice->delivery_number) {
// unset($delivery_slips[$key]);
// }
// }
$order_slips = $this->getOrderSlipsCollection()->getResults();
$documents = array_merge($invoices, $order_slips, $delivery_slips);
$documents = array_merge($invoices, $order_slips);
usort($documents, array('Order', 'sortDocuments'));
return $documents;
@@ -2534,12 +2551,12 @@ class OrderCore extends ObjectModel
$order_ecotax_tax = Tools::ps_round($order_ecotax_tax, _PS_PRICE_COMPUTE_PRECISION_, $this->round_mode);
$tax_rounding_error = $expected_total_tax - $actual_total_tax - $order_ecotax_tax;
if ($tax_rounding_error !== 0) {
if ($tax_rounding_error != 0) {
Tools::spreadAmount($tax_rounding_error, _PS_PRICE_COMPUTE_PRECISION_, $order_detail_tax_rows, 'total_amount');
}
$base_rounding_error = $expected_total_base - $actual_total_base;
if ($base_rounding_error !== 0) {
if ($base_rounding_error != 0) {
Tools::spreadAmount($base_rounding_error, _PS_PRICE_COMPUTE_PRECISION_, $order_detail_tax_rows, 'total_tax_base');
}
}
@@ -2599,51 +2616,53 @@ class OrderCore extends ObjectModel
return Db::getInstance()->executeS('SELECT * FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$id_cart);
}
// Order is considered as refunded if all bookings are requested for refund and all are with refunded status
// $refundFlag [ORDER_RETURN_STATE_FLAG_REFUNDED || ORDER_RETURN_STATE_FLAG_DENIED]
public function hasCompletelyRefunded($refundFlag = 0)
/**
* Function to check if order has been completely refunded
* @param integer action: can have 3 values as below
* Order::ORDER_COMPLETE_REFUND_FLAG for complete refunded and
* Order::ORDER_COMPLETE_CANCELLATION_FLAG for completely cancelled and
* Order::ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG for all rooms are either cancelled or requested for refunded
* @return boolean: true if order has been completely refunded as per requested parameters or false
*/
public function hasCompletelyRefunded($action = 0)
{
$objHotelBooking = new HotelBookingdetail();
if ($refundBookings = OrderReturn::getOrdersReturnDetail($this->id)) {
if ($orderBookings = $objHotelBooking->getOrderCurrentDataByOrderId($this->id)) {
if (count($refundBookings) == count($orderBookings)) {
if ($refundFlag) {
foreach ($refundBookings as $refundRow) {
if (Validate::isLoadedObject(
$objReturnState = new OrderReturnState($refundRow['state']
))) {
if ($refundFlag == OrderReturnState::ORDER_RETURN_STATE_FLAG_REFUNDED
&& !$objReturnState->refunded
) {
return false;
}
if ($refundFlag == OrderReturnState::ORDER_RETURN_STATE_FLAG_DENIED
&& !$objReturnState->denied
) {
return false;
}
}
if ($orderBookings = $objHotelBooking->getOrderCurrentDataByOrderId($this->id)) {
// If action is Order::ORDER_COMPLETE_REFUND_FLAG (for refunded) then we will check
// that all rooms must be refunded and at least one booking is not cancelled
if ($action == Order::ORDER_COMPLETE_REFUND_FLAG) {
$uniqueRefundedBookings = array_unique(array_column($orderBookings, 'is_refunded'));
if (count($uniqueRefundedBookings) == 1 && $uniqueRefundedBookings[0] == 1) {
foreach ($orderBookings as $booking) {
if ($booking['is_cancelled'] == 0) {
return true;
}
}
}
// If action is Order::ORDER_COMPLETE_CANCELLATION_FLAG (for cancelled) then we will check that all rooms must be cancelled
} elseif ($action == Order::ORDER_COMPLETE_CANCELLATION_FLAG) {
$uniqueRefundedBookings = array_unique(array_column($orderBookings, 'is_cancelled'));
if (count($uniqueRefundedBookings) == 1 && $uniqueRefundedBookings[0] == 1) {
return true;
}
// If action is Order::ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG (for cancelled and refund requests) then we will check that all rooms are either cancelled or requested for refund
} elseif ($action == Order::ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG) {
foreach ($orderBookings as $booking) {
if (!$booking['is_refunded']) {
if (!OrderReturn::getOrdersReturnDetail($this->id, 0, $booking['id'])) {
return false;
}
}
}
return true;
// Default process to check if order is fully refunded or cancelled or not
} else {
// if is_refunded is 1 means booking either is cancelled or refunded. So check all bookings must have is_refunded = 1
$uniqueRefundedBookings = array_unique(array_column($orderBookings, 'is_refunded'));
if (count($uniqueRefundedBookings) == 1 && $uniqueRefundedBookings[0] == 1) {
return true;
}
}
} elseif ($orderBookings = $objHotelBooking->getOrderCurrentDataByOrderId($this->id)) {
if (count(array_unique(array_column($orderBookings, 'is_cancelled'))) === 1
&& array_unique(array_column($orderBookings, 'is_cancelled'))[0] != 0
) {
return true;
}
}
return false;
}
// Order is considered as denied if all bookings are requested for refund and all are with denied status
public function orderRefundHasBeenDenied()
{
if (OrderReturn::getOrdersReturn($this->id_customer, $this->id)) {
}
return false;
@@ -2660,4 +2679,4 @@ class OrderCore extends ObjectModel
{
$this->transaction_id = $transactionId;
}
}
}

View File

@@ -313,7 +313,6 @@ class OrderHistoryCore extends ObjectModel
// set orders as paid
if ($new_os->paid == 1) {
$invoices = $order->getInvoicesCollection();
if ($order->total_paid != 0) {
// if order is created by API then create a direct object instead of creating an object from module
if ($order->module == 'wsorder') {
@@ -323,22 +322,43 @@ class OrderHistoryCore extends ObjectModel
}
}
foreach ($invoices as $invoice) {
/** @var OrderInvoice $invoice */
$rest_paid = $invoice->getRestPaid();
// if order has invoices then create payment entry for all the invoices
if ($invoices = $order->getInvoicesCollection()->getResults()) {
foreach ($invoices as $invoice) {
/** @var OrderInvoice $invoice */
$rest_paid = $invoice->getRestPaid();
if ($rest_paid > 0) {
if ($order->total_paid != 0) {
$payment_method = $payment_method->displayName;
} else {
$payment_method = null;
}
$order->addOrderPayment(
$rest_paid,
$payment_method,
null,
null,
null,
$invoice
);
}
}
} else {
$rest_paid = $order->total_paid_tax_incl - $order->total_paid_real;
if ($rest_paid > 0) {
if ($order->total_paid != 0) {
$payment_method = $payment_method->displayName;
} else {
$payment_method = null;
}
$order->addOrderPayment(
$rest_paid,
$payment_method,
null,
null,
null,
$invoice
null
);
}
}
@@ -420,11 +440,29 @@ class OrderHistoryCore extends ObjectModel
'{firstname}' => $result['firstname'],
'{id_order}' => (int)$this->id_order,
'{order_name}' => $order->getUniqReference(),
'{total_paid_real}' => Tools::displayPrice($order->total_paid_real, (int)$order->id_currency),
'{is_advance_payment}' => $order->is_advance_payment,
'{advance_paid_amount}' => Tools::displayPrice($order->advance_paid_amount, (int)$order->id_currency),
'{extra_mail_content_html}' => '',
'{extra_mail_content_txt}' => '',
'{payment_method}' => '',
);
if ($idHotel = HotelBookingDetail::getIdHotelByIdOrder($order->id)) {
$objHotelBranchInformation = new HotelBranchInformation($idHotel, $order->id_lang);
$fields = array_merge(
$objHotelBranchInformation->getFields(),
$objHotelBranchInformation->getFieldsLang()[$order->id_lang],
$objHotelBranchInformation->getAddress($idHotel, $order->id_lang)
);
foreach ($fields as $key => $value) {
$data['{hotel_'.$key.'}'] = $value;
}
$objHotelBookingDetail = new HotelBookingDetail();
$hotelBookingDetail = $objHotelBookingDetail->getBookingDataByOrderId($order->id);
$data['{num_rooms}'] = count($hotelBookingDetail);
}
if ($result['module_name']) {
if (Validate::isLoadedObject($module = Module::getInstanceByName($result['module_name']))) {
$data['{payment_method}'] = $module->displayName;

View File

@@ -443,23 +443,27 @@ class OrderInvoiceCore extends ObjectModel
$details = $grouped_details;
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!$sum_composite_taxes) {
$key = $row['id_tax'];
} else {
$key = sprintf('%.3f', $row['tax_rate']);
}
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
'rate' => sprintf('%.3f', $row['tax_rate']),
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$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);
foreach ($breakdown as $key => $data) {
$breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
ksort($breakdown);
@@ -503,23 +507,27 @@ class OrderInvoiceCore extends ObjectModel
$details = $grouped_details;
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!$sum_composite_taxes) {
$key = $row['id_tax'];
} else {
$key = sprintf('%.3f', $row['tax_rate']);
}
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
'rate' => sprintf('%.3f', $row['tax_rate']),
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$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);
foreach ($breakdown as $key => $data) {
$breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
ksort($breakdown);
@@ -569,23 +577,27 @@ class OrderInvoiceCore extends ObjectModel
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!$sum_composite_taxes) {
$key = $row['id_tax'];
} else {
$key = sprintf('%.3f', $row['tax_rate']);
}
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
'rate' => sprintf('%.3f', $row['tax_rate']),
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$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);
foreach ($breakdown as $key => $data) {
$breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
ksort($breakdown);
@@ -629,23 +641,27 @@ class OrderInvoiceCore extends ObjectModel
$details = $grouped_details;
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!$sum_composite_taxes) {
$key = $row['id_tax'];
} else {
$key = sprintf('%.3f', $row['tax_rate']);
}
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
'rate' => $key,
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$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);
foreach ($breakdown as $key => $data) {
$breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
ksort($breakdown);
@@ -693,17 +709,18 @@ class OrderInvoiceCore extends ObjectModel
}
} else {
foreach ($details as $row) {
$key = $row['id_tax'];
$rate = sprintf('%.3f', $row['rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' =>$rate,
'rate' => $rate,
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$breakdown[$key]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$key]['total_amount'] += $row['total_amount'];
}
}
foreach ($breakdown as $rate => $data) {
@@ -887,9 +904,11 @@ class OrderInvoiceCore extends ObjectModel
SELECT oi.*
FROM `'._DB_PREFIX_.'order_invoice` oi
LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = oi.`id_order`)
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd ON (oi.id_order = hbd.id_order)
WHERE DATE_ADD(oi.date_add, INTERVAL -1 DAY) <= \''.pSQL($date_to).'\'
AND oi.date_add >= \''.pSQL($date_from).'\'
'.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').'
'.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o')
.HotelBranchInformation::addHotelRestriction(false, 'hbd').'
AND oi.number > 0
ORDER BY oi.date_add ASC
');
@@ -908,8 +927,10 @@ class OrderInvoiceCore extends ObjectModel
SELECT oi.*
FROM `'._DB_PREFIX_.'order_invoice` oi
LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = oi.`id_order`)
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd ON (oi.id_order = hbd.id_order)
WHERE '.(int)$id_order_state.' = o.current_state
'.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').'
'.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o')
.HotelBranchInformation::addHotelRestriction(false, 'hbd').'
AND oi.number > 0
ORDER BY oi.`date_add` ASC
');

View File

@@ -148,4 +148,15 @@ class OrderPaymentCore extends ObjectModel
return new OrderInvoice((int)$res);
}
/**
* Provides the average conversion rate for a given order in any currency
* @param [string] $order_reference
* @param [int] $idCurrency
* @return float
*/
public function getAverageConversionRate($order_reference, $idCurrency)
{
return Db::getInstance()->getValue('SELECT (SUM(`amount` * `conversion_rate`) / SUM(`amount`)) FROM `'._DB_PREFIX_.'order_payment` WHERE `order_reference` = \''.pSQL($order_reference).'\' AND `id_currency` = '.(int)$idCurrency);
}
}

View File

@@ -158,7 +158,8 @@ class OrderReturnCore extends ObjectModel
public function hasBeenCompleted()
{
if (Validate::isLoadedObject($objReturnState = new OrderReturnState($this->state))) {
if ($objReturnState->denied || $objReturnState->refunded) {
// refund process will be considered as completed when the state is "Refunded"
if ($objReturnState->refunded) {
return true;
}
}
@@ -510,29 +511,31 @@ class OrderReturnCore extends ObjectModel
// send mail to the super admin
if ($objOrderReturnState->send_email_to_superadmin) {
// send superadmin information
if (Validate::isLoadedObject($superAdmin = new Employee(_PS_ADMIN_PROFILE_))) {
if (Validate::isEmail($superAdmin->email)) {
$data['{customer_name}'] = $objCustomer->firstname.' '.$objCustomer->lastname;
$data['{customer_email}'] = $objCustomer->email;
$data['{firstname}'] = $superAdmin->firstname;
$data['{lastname}'] = $superAdmin->lastname;
// Get all the employees with super admin profile
if ($superAdminEmployees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true)) {
foreach ($superAdminEmployees as $superAdminEmployee) {
if (Validate::isEmail($superAdminEmployee['email'])) {
$data['{customer_name}'] = $objCustomer->firstname.' '.$objCustomer->lastname;
$data['{customer_email}'] = $objCustomer->email;
$data['{firstname}'] = $superAdminEmployee['firstname'];
$data['{lastname}'] = $superAdminEmployee['lastname'];
Mail::Send(
(int)$idLang,
$objOrderReturnState->admin_template,
$objOrderReturnState->name,
$data,
$superAdmin->email,
$superAdmin->firstname.' '.$superAdmin->lastname,
null,
null,
null,
null,
_PS_MAIL_DIR_,
false,
(int)$objOrder->id_shop
);
Mail::Send(
(int)$idLang,
$objOrderReturnState->admin_template,
$objOrderReturnState->name,
$data,
$superAdminEmployee['email'],
$superAdminEmployee['firstname'].' '.$superAdminEmployee['lastname'],
null,
null,
null,
null,
_PS_MAIL_DIR_,
false,
(int)$objOrder->id_shop
);
}
}
}
}
@@ -570,7 +573,7 @@ class OrderReturnCore extends ObjectModel
$data['{customer_name}'] = $objCustomer->firstname.' '.$objCustomer->lastname;
$data['{customer_email}'] = $objCustomer->email;
foreach ($htlAccesses as $access) {
if ($access['id_profile'] != _PS_ADMIN_PROFILE_) {
if ($access['access'] && $access['id_profile'] != _PS_ADMIN_PROFILE_) {
if ($htlEmployees = Employee::getEmployeesByProfile($access['id_profile'])) {
foreach ($htlEmployees as $empl) {
if (Validate::isEmail($empl['email'])) {

View File

@@ -100,10 +100,10 @@ abstract class HTMLTemplateCore
$id_shop = (int)$this->shop->id;
if (Configuration::get('PS_LOGO_INVOICE', null, null, $id_shop) != false && file_exists(_PS_IMG_DIR_.Configuration::get('PS_LOGO_INVOICE', null, null, $id_shop))) {
$logo = _PS_IMG_DIR_.Configuration::get('PS_LOGO_INVOICE', null, null, $id_shop);
} elseif (Configuration::get('PS_LOGO', null, null, $id_shop) != false && file_exists(_PS_IMG_DIR_.Configuration::get('PS_LOGO', null, null, $id_shop))) {
$logo = _PS_IMG_DIR_.Configuration::get('PS_LOGO', null, null, $id_shop);
if (Configuration::get('PS_LOGO_INVOICE', null, null, $id_shop) != false) {
$logo = Context::getContext()->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO_INVOICE', null, null, $id_shop));
} elseif (Configuration::get('PS_LOGO', null, null, $id_shop) != false) {
$logo = Context::getContext()->link->getMediaLink(_PS_IMG_.Configuration::get('PS_LOGO', null, null, $id_shop));
}
return $logo;
}

View File

@@ -353,10 +353,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
} else {
$order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, $customer->id_guest, $type_value['product_id']);
}
$rm_dtl = $obj_rm_type->getRoomTypeInfoByIdProduct($type_value['product_id']);
$cart_htl_data[$type_key]['id_product'] = $type_value['product_id'];
$cart_htl_data[$type_key]['hotel_name'] = $rm_dtl['hotel_name'];
$objBookingDemand = new HotelBookingDemands();
foreach ($order_bk_data as $data_k => $data_v) {
$date_join = strtotime($data_v['date_from']).strtotime($data_v['date_to']);
@@ -368,6 +366,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
$unit_price_tax_excl = $order_details_obj->unit_price_tax_excl;
$unit_price_tax_incl = $order_details_obj->unit_price_tax_incl;
$cart_htl_data[$type_key]['hotel_name'] = $data_v['hotel_name'];
$cart_htl_data[$type_key]['name'] = $order_details_obj->product_name;
$cart_htl_data[$type_key]['unit_price_tax_excl'] = $unit_price_tax_excl;
$cart_htl_data[$type_key]['unit_price_tax_incl'] = $unit_price_tax_incl;
@@ -634,7 +633,6 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate
'tax_excluded_display' => $tax_excluded_display,
'display_product_images' => $display_product_images,
'layout' => $layout,
'tax_tab' => $this->getTaxTabContent(),
'customer' => $customer,
'footer' => $footer,
'ps_price_compute_precision' => _PS_PRICE_COMPUTE_PRECISION_,

View File

@@ -200,8 +200,6 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice
{
$address = new Address((int)$this->order->id_address_tax);
$this->smarty->assign(array(
'product_tax_breakdown' => $this->getProductTaxesBreakdown(),
'shipping_tax_breakdown' => $this->getShippingTaxesBreakdown(),
'order' => $this->order,
'ecotax_tax_breakdown' => $this->order_slip->getEcoTaxTaxesBreakdown(),
'is_order_slip' => true,
@@ -220,7 +218,7 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice
protected function getTaxBreakdown()
{
$breakdowns = array(
'product_tax' => $this->getProductTaxesBreakdown(),
'room_tax' => $this->getRoomTypeTaxesBreakdown(),
'shipping_tax' => $this->getShippingTaxesBreakdown(),
'ecotax_tax' => $this->order_slip->getEcoTaxTaxesBreakdown(),
);
@@ -251,33 +249,78 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice
return $breakdowns;
}
public function getProductTaxesBreakdown()
public function useOneAfterAnotherTaxComputationMethod()
{
// 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
LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = ' . (int) $this->order->id_order . '
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|| Configuration::get('PS_INVOICE_TAXES_BREAKDOWN');
}
public function getRoomTypeTaxesBreakdown()
{
$sum_composite_taxes = !$this->useOneAfterAnotherTaxComputationMethod();
// $breakdown will be an array with tax rates as keys and at least the columns:
// - 'total_price_tax_excl'
// - 'total_amount'
$breakdown = array();
$details = $this->order->getProductTaxesDetails($this->order->products);
$order_detail = array_filter($this->order->products, function($v) {
return ($v['is_booking_product']
|| ($v['product_auto_add']
&& $v['product_service_type'] == Product::SERVICE_PRODUCT_WITH_ROOMTYPE
&& $v['product_price_addition_type'] == ProductCore::PRICE_ADDITION_TYPE_WITH_ROOM)
);
});
$details = $this->order->getProductTaxesDetails($order_detail);
if ($sum_composite_taxes) {
$grouped_details = array();
foreach ($details as $row) {
if (!isset($grouped_details[$row['id_order_detail']])) {
$grouped_details[$row['id_order_detail']] = array(
'tax_rate' => 0,
'total_tax_base' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
);
}
$grouped_details[$row['id_order_detail']]['tax_rate'] += $row['tax_rate'];
$grouped_details[$row['id_order_detail']]['total_tax_base'] += $row['total_tax_base'];
$grouped_details[$row['id_order_detail']]['total_amount'] += $row['total_amount'];
}
$details = $grouped_details;
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
if (!$sum_composite_taxes) {
$key = $row['id_tax'];
} else {
$key = sprintf('%.3f', $row['tax_rate']);
}
if (!isset($breakdown[$key])) {
$breakdown[$key] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' =>$rate,
'rate' => sprintf('%.3f', $row['tax_rate']),
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
$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_, $this->order->round_mode);
$breakdown[$rate]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $this->order->round_mode);
foreach ($breakdown as $key => $data) {
$breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $this->order->round_mode);
$breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $this->order->round_mode);
}
ksort($breakdown);

View File

@@ -521,6 +521,7 @@ class WebserviceSpecificManagementImagesCore implements WebserviceSpecificManage
$ids[] = $image['id_hotel'];
}
$ids = array_unique($ids, SORT_NUMERIC);
asort($ids);
foreach ($ids as $id) {
$this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('image', array(), array('id' => $id, 'xlink_resource'=>$this->wsObject->wsUrl.'images/'.'hotels'.'/'.$id), false);
}

View File

@@ -68,7 +68,8 @@ function smartyTranslate($params, $smarty)
}
// If the tpl is used by a Helper
if (strpos($filename, 'helpers') === 0) {
$className = isset(Context::getContext()->controller->controller_name) ? Tools::toUnderscoreCase(substr(Context::getContext()->controller->controller_name, 5)) : '';
if (strpos($filename, 'helpers') === 0 && $className && strpos($smarty->source->name, '/template/controllers/'.$className.'/') === false) {
$class = 'Helper';
}
// If the tpl is used by a Controller

View File

@@ -74,16 +74,6 @@ class AdminAddressesControllerCore extends AdminController
'city' => array('title' => $this->l('City')),
'country' => array('title' => $this->l('Country'), 'type' => 'select', 'list' => $this->countries_array, 'filter_key' => 'cl!id_country'));
// START send access query information to the admin controller
$this->access_select = ' SELECT a.`id_address` FROM '._DB_PREFIX_.'address a';
$this->access_join = ' INNER JOIN '._DB_PREFIX_.'customer cust ON (cust.id_customer = a.id_customer)';
$this->access_join .= ' INNER JOIN '._DB_PREFIX_.'orders ord ON (cust.id_customer = ord.id_customer)';
$this->access_join .= ' INNER JOIN '._DB_PREFIX_.'htl_booking_detail hbd ON (hbd.id_order = ord.id_order)';
if ($acsHtls = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1, 1)) {
$this->access_where = ' WHERE hbd.id_hotel IN ('.implode(',', $acsHtls).')';
}
parent::__construct();
$this->_select = 'cl.`name` as country';
@@ -177,6 +167,18 @@ class AdminAddressesControllerCore extends AdminController
)
);
if (!Tools::getValue('liteDisplaying')) {
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
}
$this->fields_value['address_type'] = (int)Tools::getValue('address_type', 1);
$id_customer = (int)Tools::getValue('id_customer');

View File

@@ -768,7 +768,12 @@ class AdminCartRulesControllerCore extends AdminController
public function displayAjaxSearchCartRuleVouchers()
{
$found = false;
if ($vouchers = CartRule::getCartsRuleByCode(Tools::getValue('q'), (int)$this->context->language->id, true)) {
if ($vouchers = CartRule::getCartsRuleByCode(
Tools::getValue('q'),
(int)$this->context->language->id,
true,
(int) Tools::getValue('id_customer')
)) {
$found = true;
}
echo json_encode(array('found' => $found, 'vouchers' => $vouchers));

View File

@@ -54,7 +54,7 @@ class AdminCartsControllerCore extends AdminController
LEFT JOIN `'._DB_PREFIX_.'connections` co ON (a.id_guest = co.id_guest AND TIME_TO_SEC(TIMEDIFF(\''.pSQL(date('Y-m-d H:i:00', time())).'\', co.`date_add`)) < 1800)';
$this->_group = ' GROUP BY a.`id_cart`';
if (Tools::getValue('action') == 'filterAbandonedCarts') {
if (Tools::getValue('action') == 'filterOnlyAbandonedCarts') {
$this->_filterHaving = ' AND `ids_order` = 0 AND `time_diff` > 86400';
}
@@ -333,6 +333,9 @@ class AdminCartsControllerCore extends AdminController
}
$this->context->cart = new Cart((int)$id_cart);
CartRule::autoRemoveFromCart($this->context);
CartRule::autoAddToCart($this->context);
if (!$this->context->cart->id) {
$this->context->cart->recyclable = 0;
$this->context->cart->gift = 0;

View File

@@ -105,7 +105,19 @@ class AdminCmsCategoriesControllerCore extends AdminController
$object = parent::postProcess();
$this->updateAssoShop((int)Tools::getValue('id_cms_category'));
if ($object !== false) {
Tools::redirectAdmin(self::$currentIndex.'&conf=3&id_cms_category='.(int)$object->id.'&token='.Tools::getValue('token'));
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) {
if ($this->id_object) {
Tools::redirectAdmin(self::$currentIndex.'&update'.$this->table.'&conf=4&id_cms_category='.(int)$object->id.'&token='.Tools::getValue('token'));
} else {
Tools::redirectAdmin(self::$currentIndex.'&update'.$this->table.'&conf=3&id_cms_category='.(int)$object->id.'&token='.Tools::getValue('token'));
}
} else {
if ($this->id_object) {
Tools::redirectAdmin(self::$currentIndex.'&conf=4&id_cms_category='.(int)$object->id.'&token='.Tools::getValue('token'));
} else {
Tools::redirectAdmin(self::$currentIndex.'&conf=3&id_cms_category='.(int)$object->id.'&token='.Tools::getValue('token'));
}
}
}
return $object;
}
@@ -289,7 +301,16 @@ class AdminCmsCategoriesControllerCore extends AdminController
),
'submit' => array(
'title' => $this->l('Save'),
)
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
if (Shop::isFeatureActive()) {

View File

@@ -218,6 +218,13 @@ class AdminCmsControllerCore extends AdminController
'title' => $this->l('Save'),
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
'save_and_preview' => array(
'name' => 'viewcms',
'type' => 'submit',

View File

@@ -113,7 +113,16 @@ class AdminContactsControllerCore extends AdminController
),
'submit' => array(
'title' => $this->l('Save'),
)
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
if (Shop::isFeatureActive()) {

View File

@@ -54,20 +54,20 @@ class AdminCountriesControllerCore extends AdminController
'dir' => 'st'
);
$this->fields_options = array(
'general' => array(
'title' => $this->l('Country options'),
'fields' => array(
'PS_RESTRICT_DELIVERED_COUNTRIES' => array(
'title' => $this->l('Restrict country selections in front office to those covered by active carriers'),
'cast' => 'intval',
'type' => 'bool',
'default' => '0'
)
),
'submit' => array('title' => $this->l('Save'))
)
);
// $this->fields_options = array(
// 'general' => array(
// 'title' => $this->l('Country options'),
// 'fields' => array(
// 'PS_RESTRICT_DELIVERED_COUNTRIES' => array(
// 'title' => $this->l('Restrict country selections in front office to those covered by active carriers'),
// 'cast' => 'intval',
// 'type' => 'bool',
// 'default' => '0'
// )
// ),
// 'submit' => array('title' => $this->l('Save'))
// )
// );
$zones_array = array();
$this->zones = Zone::getZones();
@@ -368,6 +368,16 @@ class AdminCountriesControllerCore extends AdminController
'title' => $this->l('Save')
);
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
return parent::renderForm();
}

View File

@@ -231,6 +231,16 @@ class AdminCurrenciesControllerCore extends AdminController
'title' => $this->l('Save'),
);
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
return parent::renderForm();
}

View File

@@ -99,6 +99,13 @@ class AdminCustomerPreferencesControllerCore extends AdminController
'cast' => 'intval',
'type' => 'bool'
),
'PS_CUSTOMER_BIRTHDATE' => array(
'title' => $this->l('Enable date of birth'),
'hint' => $this->l('Display or not the date of birth field.'),
'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.'),
@@ -108,7 +115,7 @@ class AdminCustomerPreferencesControllerCore extends AdminController
),
'PS_CUSTOMER_OPTIN' => array(
'title' => $this->l('Enable opt-in'),
'hint' => $this->l('Display or not the opt-in tick box, to receive offers from the store\'s partners.'),
'hint' => $this->l('Display or not the opt-in tick box, to receive offers from your hotel partners.'),
'validation' => 'isBool',
'cast' => 'intval',
'type' => 'bool'

View File

@@ -62,6 +62,15 @@ class AdminCustomerThreadsControllerCore extends AdminController
$status_array[$k] = $v['alt'];
}
// START send access query information to the admin controller
$this->access_select = ' SELECT a.`id_customer_thread` FROM '._DB_PREFIX_.'customer_thread a';
$this->access_join = ' LEFT JOIN '._DB_PREFIX_.'orders ord ON (a.id_order = ord.id_order)';
$this->access_join .= ' LEFT JOIN '._DB_PREFIX_.'htl_booking_detail hbd ON (hbd.id_order = ord.id_order)';
$this->access_where = ' WHERE 1 ';
if ($acsHtls = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1, 1)) {
$this->access_where .= ' AND IF(a.`id_order`, hbd.`id_hotel` IN ('.implode(',', $acsHtls).'), 1)';
}
$this->fields_list = array(
'id_customer_thread' => array(
'title' => $this->l('ID'),

View File

@@ -39,8 +39,8 @@ class AdminCustomersControllerCore extends AdminController
public function __construct()
{
$this->bootstrap = true;
$this->required_database = true;
$this->required_fields = array('newsletter','optin');
// $this->required_database = true;
// $this->required_fields = array('newsletter','optin');
$this->table = 'customer';
$this->className = 'Customer';
$this->lang = false;
@@ -152,16 +152,6 @@ class AdminCustomersControllerCore extends AdminController
$this->shopLinkType = 'shop';
$this->shopShareDatas = Shop::SHARE_CUSTOMER;
// START send access query information to the admin controller
$this->access_select = ' SELECT a.`id_customer` FROM '._DB_PREFIX_.'customer a';
$this->access_join = ' INNER JOIN '._DB_PREFIX_.'orders ord ON (a.id_customer = ord.id_customer)';
$this->access_join .= ' INNER JOIN '._DB_PREFIX_.'htl_booking_detail hbd ON (hbd.id_order = ord.id_order)';
if ($acsHtls = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1, 1)) {
$this->access_where = ' WHERE hbd.id_hotel IN ('.implode(',', $acsHtls).')';
}
parent::__construct();
$this->_select = '
@@ -458,8 +448,9 @@ class AdminCustomersControllerCore extends AdminController
'label' => $this->l('Disabled')
)
),
'disabled' => (bool)!Configuration::get('PS_CUSTOMER_NWSL'),
'hint' => $this->l('This customer will receive your newsletter via email.')
'disabled' => (bool)!Configuration::get('PS_CUSTOMER_NWSL'),
'hint' => $this->l('This customer will receive your newsletter via email.'),
'desc' => (bool)!Configuration::get('PS_CUSTOMER_NWSL') ? sprintf($this->l('This field is disabled as option \'Enable newsletter registration\' is disabled. You can change it from %sPreferences > Customers%s page.'), '<a href="'.$this->context->link->getAdminLink('AdminCustomerPreferences').'" target="_blank">', '</a>') : '',
),
array(
'type' => 'switch',
@@ -597,6 +588,18 @@ class AdminCustomersControllerCore extends AdminController
'title' => $this->l('Save'),
);
if (!Tools::getValue('liteDisplaying')) {
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
}
$birthday = explode('-', $this->getFieldValue($obj, 'birthday'));
$this->fields_value = array(
@@ -630,6 +633,10 @@ class AdminCustomersControllerCore extends AdminController
Tools::getValue('groupBox_'.$group['id_group'], in_array($group['id_group'], $customer_groups_ids));
}
if ($back = Tools::getValue('back')) {
$this->tpl_form_vars['back_url'] = Tools::htmlentitiesDecodeUTF8(Tools::safeOutput(urldecode($back)));
}
return parent::renderForm();
}
@@ -866,6 +873,25 @@ class AdminCustomersControllerCore extends AdminController
public function processDelete()
{
// If customer is going to be deleted permanently then if customer has orders the change this customer as an anonymous customer
if (Validate::isLoadedObject($objCustomer = $this->loadObject())) {
if ($this->delete_mode == 'real' && Order::getCustomerOrders($objCustomer->id, true)) {
$objCustomer->email = 'anonymous'.'-'.$objCustomer->id.'@'.Tools::getShopDomain();
$objCustomer->deleted = 1;
if (!$objCustomer->update()) {
$this->errors[] = Tools::displayError('Some error ocurred while deleting the Customer');
return;
}
$this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token;
return;
}
} else {
$this->errors[] = Tools::displayError('Customer not found.');
return;
}
$this->_setDeletedMode();
parent::processDelete();
}
@@ -884,6 +910,44 @@ class AdminCustomersControllerCore extends AdminController
protected function processBulkDelete()
{
// If customer is going to be deleted permanently then if customer has orders the change this customer as an anonymous customer
if ($this->delete_mode == 'real') {
if (is_array($this->boxes) && !empty($this->boxes)) {
foreach ($this->boxes as $key => $idCustomer) {
if (Validate::isLoadedObject($objCustomer = new Customer($idCustomer))) {
// check if customer has orders for email change else customer will be deleted
if (Order::getCustomerOrders($objCustomer->id, true)) {
$objCustomer->email = 'anonymous'.'-'.$objCustomer->id.'@'.Tools::getShopDomain();
$objCustomer->deleted = 1;
if ($objCustomer->update()) {
// unset the customer which is processed
// not processed customers will be deleted with default process if no errors are there
unset($this->boxes[$key]);
} else {
$this->errors[] = Tools::displayError('Some error ocurred while deleting the Customer with id').': '.$idCustomer;
}
}
} else {
$this->errors[] = Tools::displayError('Customer id').': '.$idCustomer.' '.Tools::displayError('not found.');
}
}
// if all the customers are process above then redirect with success
if (!count($this->boxes)) {
$this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token;
return;
}
} else {
$this->errors[] = Tools::displayError('Customers not found.');
return;
}
// if errors are there then do not proceed for default process
if (count($this->errors)) {
return;
}
}
$this->_setDeletedMode();
parent::processBulkDelete();
}
@@ -966,6 +1030,21 @@ class AdminCustomersControllerCore extends AdminController
return parent::processSave();
}
protected function copyFromPost(&$object, $table)
{
parent::copyFromPost($object, $table);
$years = Tools::getValue('years');
$months = Tools::getValue('months');
$days = Tools::getValue('days');
if ($years != '' && $months != '' && $days != '') {
$object->birthday = (int) $years.'-'.(int) $months.'-'.(int) $days;
} else {
$object->birthday = '0000-00-00';
}
}
protected function afterDelete($object, $old_id)
{
$customer = new Customer($old_id);
@@ -1080,10 +1159,11 @@ class AdminCustomersControllerCore extends AdminController
public function ajaxProcessSearchCustomers()
{
$searches = explode(' ', Tools::getValue('customer_search'));
$skip_deleted = Tools::getValue('skip_deleted');
$customers = array();
$searches = array_unique($searches);
foreach ($searches as $search) {
if (!empty($search) && $results = Customer::searchByName($search, 50)) {
if (!empty($search) && $results = Customer::searchByName($search, 50, $skip_deleted)) {
foreach ($results as $result) {
if ($result['active']) {
$customers[$result['id_customer']] = $result;

View File

@@ -135,8 +135,8 @@ class AdminDashboardControllerCore extends AdminController
}
$forms['net_profit']['fields']['CONF_AVERAGE_PRODUCT_MARGIN'] = array(
'title' => $this->l('Average gross margin percentage'),
'desc' => $this->l('You should calculate this percentage as follows: ((total sales revenue) - (total operating cost)) / (total sales revenue) * 100. This value is only used to calculate Dashboard approximate gross margin, if you do not specify operating cost for each room type.'),
'title' => $this->l('Average gross operating cost percentage'),
'desc' => $this->l('This value is only used to calculate Dashboard approximate gross operating cost, if you do not specify operating cost for each room type.'),
'validation' => 'isPercentage',
'cast' => 'intval',
'type' => 'text',
@@ -386,7 +386,16 @@ class AdminDashboardControllerCore extends AdminController
'extra' => Tools::getValue('extra')
);
die(json_encode(Hook::exec('dashboardData', $params, $id_module, true, true, (int)Tools::getValue('dashboard_use_push'))));
// code to be added.
$data = Hook::exec('dashboardData', $params, $id_module, true, true, (int)Tools::getValue('dashboard_use_push'));
Hook::exec('actionDashboardDataModifier', array(
'data' => &$data,
'params' => $params,
'id_module' => $id_module,
'dashboard_use_push' => (int)Tools::getValue('dashboard_use_push')
));
$this->ajaxDie(json_encode($data));
}
public function ajaxProcessSetSimulationMode()

View File

@@ -403,6 +403,16 @@ class AdminEmployeesControllerCore extends AdminController
'title' => $this->l('Save'),
);
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
$this->fields_value['passwd'] = false;
$this->fields_value['bo_theme_css'] = $obj->bo_theme.'|'.$obj->bo_css;

View File

@@ -216,6 +216,16 @@ class AdminFeaturesControllerCore extends AdminController
'title' => $this->l('Save'),
);
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
)
);
return parent::renderForm();
}
@@ -544,9 +554,9 @@ class AdminFeaturesControllerCore extends AdminController
if ($this->table == 'feature_value' && ($this->display == 'edit' || $this->display == 'add')) {
$this->redirect_after = self::$currentIndex.'&addfeature_value&id_feature='.(int)Tools::getValue('id_feature').'&token='.$this->token;
} else {
$this->redirect_after = self::$currentIndex.'&'.$this->identifier.'=&conf=3&update'.$this->table.'&token='.$this->token;
$this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.(int) $object->id.'&conf=3&update'.$this->table.'&token='.$this->token;
}
} elseif (Tools::isSubmit('submitAdd'.$this->table.'AndStay') && count($this->errors)) {
} elseif (Tools::isSubmit('submitAdd'.$this->table.'AndStay') && count($this->errors) && $this->table == 'feature_value') { // enter only if feature is submitted
$this->display = 'editFeatureValue';
}
@@ -562,7 +572,7 @@ class AdminFeaturesControllerCore extends AdminController
$object = parent::processUpdate();
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay') && !count($this->errors)) {
$this->redirect_after = self::$currentIndex.'&'.$this->identifier.'=&conf=3&update'.$this->table.'&token='.$this->token;
$this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.(int) Tools::getValue('id_feature').'&conf=4&update'.$this->table.'&token='.$this->token;
}
return $object;

View File

@@ -173,7 +173,16 @@ class AdminGendersControllerCore extends AdminController
),
'submit' => array(
'title' => $this->l('Save'),
)
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
/** @var Gender $obj */

View File

@@ -126,7 +126,7 @@ class AdminGroupsControllerCore extends AdminController
public function initPageHeaderToolbar()
{
if (empty($this->display)) {
if (empty($this->display) && Group::isFeatureActive()) {
$this->page_header_toolbar_btn['new_group'] = array(
'href' => self::$currentIndex.'&addgroup&token='.$this->token,
'desc' => $this->l('Add new group', null, null, false),
@@ -148,8 +148,32 @@ class AdminGroupsControllerCore extends AdminController
parent::initProcess();
}
public function initContent()
{
if (!Group::isFeatureActive()) {
parent::initContent();
$content = $this->displayWarning(sprintf(
$this->l('The feature Customer Groups has been disabled. You can enable it from %s page.'),
'<a href="'.$this->context->link->getAdminLink('AdminPerformance').'#fieldset_2_2" target="_blank">'.$this->l('Advanced Parameters > Performance').'</a>'
));
$this->context->smarty->assign(array(
'content' => $content,
));
return;
}
parent::initContent();
}
public function postProcess()
{
if (!Group::isFeatureActive()) {
return;
}
if (isset($_POST['submitResetcustomer_group'])) {
$this->processResetFilters('customer_group');
}
@@ -175,13 +199,12 @@ class AdminGroupsControllerCore extends AdminController
protected function renderCustomersList($group)
{
$genders = array(0 => '?');
$genders_icon = array('default' => 'unknown.gif');
foreach (Gender::getGenders() as $gender) {
/** @var Gender $gender */
$genders_icon[$gender->id] = '../genders/'.(int)$gender->id.'.jpg';
$genders[$gender->id] = $gender->name;
$titles_array = array();
$genders = Gender::getGenders($this->context->language->id);
foreach ($genders as $gender) {
$titles_array[$gender->id_gender] = $gender->name;
}
$this->table = 'customer_group';
$this->lang = false;
$this->list_id = 'customer_group';
@@ -194,7 +217,7 @@ class AdminGroupsControllerCore extends AdminController
$this->fields_list = (array(
'id_customer' => array('title' => $this->l('ID'), 'align' => 'center', 'filter_key' => 'c!id_customer', 'class' => 'fixed-width-xs'),
'id_gender' => array('title' => $this->l('Social title'), 'icon' => $genders_icon, 'list' => $genders),
'title' => array('title' => $this->l('Social title'), 'filter_key' => 'c!id_gender', 'type' => 'select', 'list' => $titles_array),
'firstname' => array('title' => $this->l('First name')),
'lastname' => array('title' => $this->l('Last name')),
'email' => array('title' => $this->l('Email address'), 'filter_key' => 'c!email', 'orderby' => true),
@@ -202,8 +225,9 @@ class AdminGroupsControllerCore extends AdminController
'date_add' => array('title' => $this->l('Registration date'), 'type' => 'date', 'class' => 'fixed-width-md', 'align' => 'center'),
'active' => array('title' => $this->l('Enabled'), 'align' => 'center', 'class' => 'fixed-width-sm', 'type' => 'bool', 'search' => false, 'orderby' => false, 'filter_key' => 'c!active', 'callback' => 'printOptinIcon')
));
$this->_select = 'c.*, a.id_group';
$this->_select = 'c.*, a.id_group, gl.`name` AS title';
$this->_join = 'LEFT JOIN `'._DB_PREFIX_.'customer` c ON (a.`id_customer` = c.`id_customer`)';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'gender_lang gl ON (gl.`id_gender` = c.`id_gender` AND gl.`id_lang` = '.(int) $this->context->language->id.')';
$this->_where = 'AND a.`id_group` = '.(int)$group->id.' AND c.`deleted` != 1';
$this->_where .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'c');
self::$currentIndex = self::$currentIndex.'&id_group='.(int)$group->id.'&viewgroup';
@@ -232,6 +256,15 @@ class AdminGroupsControllerCore extends AdminController
'submit' => array(
'title' => $this->l('Save'),
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
'input' => array(
array(
'type' => 'text',

View File

@@ -403,7 +403,16 @@ class AdminImagesControllerCore extends AdminController
),
'submit' => array(
'title' => $this->l('Save')
)
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
parent::__construct();

View File

@@ -140,7 +140,6 @@ class AdminInformationControllerCore extends AdminController
'upload_max_filesize' => $this->l('In PHP configuration set upload_max_filesize to minimum 16M.'),
'max_execution_time' => $this->l('In PHP configuration set max_execution_time to minimum 500.'),
'mbstring' => $this->l('PHP Mbstring extension is not enabled.'),
'magicquotes' => $this->l('PHP magic quotes option is enabled.'),
'dom' => $this->l('PHP DOM extension is not loaded.'),
);

View File

@@ -195,10 +195,12 @@ class AdminInvoicesControllerCore extends AdminController
);
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT COUNT( o.id_order ) AS nbOrders, o.current_state as id_order_state
SELECT COUNT(DISTINCT(o.id_order)) AS nbOrders, o.current_state as id_order_state
FROM `'._DB_PREFIX_.'order_invoice` oi
LEFT JOIN `'._DB_PREFIX_.'orders` o ON oi.id_order = o.id_order
INNER JOIN `'._DB_PREFIX_.'htl_booking_detail` hbd ON (oi.id_order = hbd.id_order)
WHERE o.id_shop IN('.implode(', ', Shop::getContextListShopID()).')
'.HotelBranchInformation::addHotelRestriction(false, 'hbd').'
AND oi.number > 0
GROUP BY o.current_state
');
@@ -324,4 +326,11 @@ class AdminInvoicesControllerCore extends AdminController
return $templates;
}
public function setMedia()
{
parent::setMedia();
$this->addJS(_PS_JS_DIR_.'admin/invoices.js');
}
}

View File

@@ -262,6 +262,16 @@ class AdminLanguagesControllerCore extends AdminController
'title' => $this->l('Save'),
);
$this->fields_form['buttons'] = array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
);
/** @var Language $obj */
if (!($obj = $this->loadObject(true))) {
return;

View File

@@ -45,6 +45,17 @@ class AdminLoginControllerCore extends AdminController
}
}
public function init()
{
parent::init();
if ($this->ajax && Tools::getValue('action') == 'checkLoginStatus') {
$this->ajaxDie(json_encode(array(
'is_logged_in' => $this->context->employee->isLoggedBack(),
)));
}
}
public function setMedia()
{
$this->addJquery();

View File

@@ -97,6 +97,8 @@ class AdminLogsControllerCore extends AdminController
$this->list_no_link = true;
$this->_select .= 'CONCAT(e.firstname, \' \', e.lastname) employee';
$this->_join .= ' LEFT JOIN '._DB_PREFIX_.'employee e ON (a.id_employee = e.id_employee)';
$this->_orderBy = 'a.date_add';
$this->_orderWay = 'DESC';
$this->_use_found_rows = false;
parent::__construct();
}

View File

@@ -381,7 +381,16 @@ class AdminMetaControllerCore extends AdminController
),
'submit' => array(
'title' => $this->l('Save')
)
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save and stay'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save',
),
),
);
return parent::renderForm();
}

View File

@@ -235,7 +235,7 @@ class AdminModulesCatalogControllerCore extends AdminController
$this->page_header_toolbar_btn['addons'] = array(
'href' => 'https://qloapps.com/addons/',
'desc' => $this->l('Explore all Addons'),
'imgclass' => 'modules-list',
'imgclass' => 'puzzle-piece',
'target' => true
);
}

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