diff --git a/admin/themes/default/sass/controllers/_order.sass b/admin/themes/default/sass/controllers/_order.sass index 246660d86..f7f30d0d2 100644 --- a/admin/themes/default/sass/controllers/_order.sass +++ b/admin/themes/default/sass/controllers/_order.sass @@ -42,6 +42,12 @@ right: 0 margin: 0 auto +#customer_cart_details .overbooked_room + background-color: #FF69B4 + color: #FFF + padding: 2px 5px + border-radius: 2px + font-weight: 600 .room_status_info_form .room_status diff --git a/admin/themes/default/sass/modules/_variables.sass b/admin/themes/default/sass/modules/_variables.sass index 4db90b44f..99b590b6d 100644 --- a/admin/themes/default/sass/modules/_variables.sass +++ b/admin/themes/default/sass/modules/_variables.sass @@ -11,7 +11,7 @@ $contrasted-lightness-threshold: 10% $bg-page-head-color : $secondary-color $bg-panel-heading-color: hsl(hue($secondary-color), 10, 90) -$badge-notif-color: $greenPrestashop +$badge-notif-color: #D27C82 $brand-addons: $pinkPrestashop $font-family-mono: 'Droid Sans Mono', Helvetica, Arial, sans-serif diff --git a/admin/themes/default/sass/partials/_content.sass b/admin/themes/default/sass/partials/_content.sass index 860ae4a67..94328c025 100644 --- a/admin/themes/default/sass/partials/_content.sass +++ b/admin/themes/default/sass/partials/_content.sass @@ -109,7 +109,11 @@ body .dropdown-menu line-height: normal .panel-danger .panel-heading - background-color: $badge-notif-color!important + background-color: #DC143C + color: #FFF + margin: -20px -20px 15px -20px + padding: 0px 10px 0px 10px + form .alert clear: both @media (max-width: $screen-phone) diff --git a/admin/themes/default/template/controllers/order_preferences/helpers/options/options.tpl b/admin/themes/default/template/controllers/order_preferences/helpers/options/options.tpl index 23b7ffc5e..eba33ee11 100644 --- a/admin/themes/default/template/controllers/order_preferences/helpers/options/options.tpl +++ b/admin/themes/default/template/controllers/order_preferences/helpers/options/options.tpl @@ -24,4 +24,9 @@ *} {extends file="helpers/options/options.tpl"} -{block name="after"}{/block} +{block name="after"} + +{/block} diff --git a/admin/themes/default/template/controllers/orders/_overbookings.tpl b/admin/themes/default/template/controllers/orders/_overbookings.tpl new file mode 100644 index 000000000..b2b89fa6c --- /dev/null +++ b/admin/themes/default/template/controllers/orders/_overbookings.tpl @@ -0,0 +1,93 @@ +{* +* 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 +* @copyright 2010-2023 Webkul IN +* @license https://store.webkul.com/license.html +*} + +{if isset($orderOverBookings) && $orderOverBookings} +
+
+ {l s='Overbookings found in this order !!'} +
+
+
+ + + + + + + + + + + {foreach from=$orderOverBookings item=data} + {if !$data.is_refunded} + + + + + + + + + + {/if} + {/foreach} +
{l s='Room No.'}{l s='Room type.'}{l s='Duration'}{l s='Occupancy'}{l s='Confirmed booking order'}{l s='Reallocate/Swap'}{l s='Resolve'}
{$data['room_num']}{$data['room_type_name']}{dateFormat date=$data['date_from']} {l s='To'} {dateFormat date=$data['date_to']} + {if $order->with_occupancy && $data['children']} + + {else} + {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} + {/if} + + {if isset($data['booked_room_info']['id_order']) && $data['booked_room_info']['id_order']} + #{$data['booked_room_info']['id_order']} + {else} + {l s='N/A'} + {/if} + + {l s='Reallocate/Swap Room'} + + {if isset($data['booked_room_info']) && $data['booked_room_info']} + {l s='Already booked'} + {else} + {l s='Resolve'} + {/if} +
+
+ +
+

- {l s='You can resolve room overbooking with \'Resolve\' column only when the overbooked room is now free for booked duration.'}

+

- {l s='You can also reallocate an overbooked room with an available room to resolve room\'s overbooking.'}

+
+
+
+{/if} \ No newline at end of file diff --git a/admin/themes/default/template/controllers/orders/_product_line.tpl b/admin/themes/default/template/controllers/orders/_product_line.tpl index ce198686e..4685230f5 100644 --- a/admin/themes/default/template/controllers/orders/_product_line.tpl +++ b/admin/themes/default/template/controllers/orders/_product_line.tpl @@ -30,7 +30,10 @@ {/if} - {$data.room_num} +

{$data.room_num}

+ {if $data.is_back_order} + {l s='overbooked'} + {/if} diff --git a/admin/themes/default/template/controllers/orders/_resolvable_overbookings.tpl b/admin/themes/default/template/controllers/orders/_resolvable_overbookings.tpl new file mode 100644 index 000000000..b2f5cba79 --- /dev/null +++ b/admin/themes/default/template/controllers/orders/_resolvable_overbookings.tpl @@ -0,0 +1,77 @@ +{* +* 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 +* @copyright 2010-2023 Webkul IN +* @license https://store.webkul.com/license.html +*} + +{if isset($resolvableOverBookings) && $resolvableOverBookings} +
+
+ {l s='Resolvable Overbookings'} +
+
+ {if isset($smarty.get.resolvable_overbooked_orders) && $smarty.get.resolvable_overbooked_orders} +
+ {l s='Orders with resolvable overbookings are filtered.'} {l s='See all orders'} +
+ {/if} +
+

{l s='Some overbookings are now available to be resolved. You can directly resolve overbookings from below list as per your choice.'}

+ {if !isset($smarty.get.resolvable_overbooked_orders) || !$smarty.get.resolvable_overbooked_orders} +
+

{l s='You can also filter orders which overbookings are now available to be resolved.'} {l s='Filter orders with resolvable overbookings'}

+ {/if} +
+
+ + + + + + + + + + {foreach from=$resolvableOverBookings item=data} + {if !$data.is_refunded} + + + + + + + + + {/if} + {/foreach} +
{l s='Room No.'}{l s='Room type'}{l s='Hotel'}{l s='Duration'}{l s='Order'}{l s='Resolve'}
{$data['room_num']} + {$data['room_type_name']|escape:'html':'UTF-8'} + + {$data['hotel_name']} + {dateFormat date=$data['date_from']|escape:'html':'UTF-8'} {l s='To'} {dateFormat date=$data['date_to']|escape:'html':'UTF-8'} + #{$data['id_order']|escape:'html':'UTF-8'} + + {if isset($data['booked_room_info']) && $data['booked_room_info']} + {l s='Already booked'} + {else} + {l s='Resolve'} + {/if} +
+
+
+
+ +{/if} diff --git a/admin/themes/default/template/controllers/orders/helpers/view/view.tpl b/admin/themes/default/template/controllers/orders/helpers/view/view.tpl index 480b84455..7dd73d353 100644 --- a/admin/themes/default/template/controllers/orders/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/orders/helpers/view/view.tpl @@ -105,6 +105,10 @@ + + {* Overbookings information of the order *} + {include file='controllers/orders/_overbookings.tpl'} +
diff --git a/classes/PaymentModule.php b/classes/PaymentModule.php index 0e30ce63b..7add9d744 100644 --- a/classes/PaymentModule.php +++ b/classes/PaymentModule.php @@ -760,15 +760,16 @@ abstract class PaymentModuleCore extends Module // update order in htl tables $objRoomType = new HotelRoomType(); - $objAdvancedPayment = new HotelAdvancedPayment(); - + $objCartBookingData = new HotelCartBookingData(); + $objBookingDetail = new HotelBookingDetail(); $vatAddress = new Address((int)$order->id_address_tax); $idLang = (int)$this->context->cart->id_lang; $normalProducts = array(); + // variable to check max overbookings are created in the room in any date of the booking duration + $maxOverbookingCount = 0; foreach ($order->product_list as $product) { - $objCartBookingData = new HotelCartBookingData(); $idProduct = $product['id_product']; $cartBookingData = $objCartBookingData->getOnlyCartBookingData($this->context->cart->id, $this->context->cart->id_guest, $idProduct); if ($cartBookingData) { @@ -776,8 +777,67 @@ abstract class PaymentModuleCore extends Module $objCartBookingData = new HotelCartBookingData($bookingInfo['id']); $objCartBookingData->id_order = $order->id; $objCartBookingData->id_customer = $this->context->customer->id; + + // check if still room available for this booking or not + $isRoomOverBooked = 1; + + // get all the available rooms right now + $bookingParams = array( + 'date_from' => $objCartBookingData->date_from, + 'date_to' => $objCartBookingData->date_to, + 'hotel_id' => $objCartBookingData->id_hotel, + 'id_room_type' => $idProduct, + 'only_search_data' => 1 + ); + + if ($searchRoomsInfo = $objBookingDetail->getBookingData($bookingParams)) { + if (isset($searchRoomsInfo['rm_data'][$idProduct]['data']['available']) + && $searchRoomsInfo['rm_data'][$idProduct]['data']['available'] + ) { + $availableRoomsInfo = $searchRoomsInfo['rm_data'][$idProduct]['data']['available']; + if ($roomIdsAvailable = array_column($availableRoomsInfo, 'id_room')) { + // If room is still there in the available rooms list then it is not in back order + if (in_array($objCartBookingData->id_room, $roomIdsAvailable)) { + $isRoomOverBooked = 0; + } else { + $isRoomOverBooked = 1; + foreach ($roomIdsAvailable as $idRoom) { + if ($idRoom != $objCartBookingData->id_room) { + $objCartBookingData->id_room = $idRoom; + $isRoomOverBooked = 0; + break; + } + } + } + } + } + } + + // if room is not available right now the set it to back order + if ($isRoomOverBooked) { + $objCartBookingData->is_back_order = 1; + + // max overbookings in a room datewise breakup. So that we can know no. of overbookings in every date + if ($roomOverBookings = $objBookingDetail->getOverbookedRooms( + 0, + $objCartBookingData->id_hotel, + $objCartBookingData->date_from, + $objCartBookingData->date_to, + 0, + 1 + )) { + // check in the bokking duration what is the max overbookings in ay date in the date range + // replace $maxOverbookingCount with $maxOverbookingsInDate if it is greater + if ($maxOverbookingCount < $roomOverBookings) { + $maxOverbookingCount = $roomOverBookings; + } + } + } else { + $objCartBookingData->is_back_order = 0; + } $objCartBookingData->save(); + // Lets set data to the hotel booking detail table $objBookingDetail = new HotelBookingDetail(); $id_order_detail = $objBookingDetail->getPsOrderDetailIdByIdProduct($idProduct, $order->id); $objBookingDetail->id_product = $idProduct; @@ -789,12 +849,9 @@ abstract class PaymentModuleCore extends Module $objBookingDetail->id_customer = $this->context->customer->id; $objBookingDetail->booking_type = $objCartBookingData->booking_type; $objBookingDetail->id_status = 1; + $objBookingDetail->is_back_order = $objCartBookingData->is_back_order; $objBookingDetail->comment = $objCartBookingData->comment; - // For Back Order(Because of cart lock) - if ($objCartBookingData->is_back_order) { - $objBookingDetail->is_back_order = 1; - } $total_price = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( $idProduct, $objCartBookingData->date_from, @@ -998,10 +1055,39 @@ abstract class PaymentModuleCore extends Module $new_history->addWithemail(true, $extra_vars); // Switch to back order if needed - if (Configuration::get('PS_STOCK_MANAGEMENT') && ($order_detail->getStockState() || $order_detail->product_quantity_in_stock <= 0)) { + $objHotelBookingDetail = new HotelBookingDetail(); + if ($objHotelBookingDetail->getOverbookedRooms($order->id)) { + $cancelOrder = 0; + // Take overbooking action as per order->overbooking Preferences else set order for cancellation + if (Configuration::get('PS_OVERBOOKING_ORDER_ACTION') == Order::OVERBOOKING_ORDER_CANCEL_ACTION) { + $cancelOrder = 1; + } else { + // check conditions for maximun overbookings allowed for the hotel else set order for cancellation + $maxAllowedOverbookings = Configuration::get('PS_MAX_OVERBOOKING_PER_HOTEL_PER_DAY'); + // >= condition applied because equal case means already overbooked rooms limit exceeded before this booking + if ($maxAllowedOverbookings && ($maxOverbookingCount >= $maxAllowedOverbookings)) { + $cancelOrder = 1; + } + } + + // set order status after all conditions checks + if ($cancelOrder) { + $id_order_state = Configuration::get('PS_OS_CANCELED'); + } else { + if ($order->valid) { + if ($order->is_advance_payment && $order->advance_paid_amount < $order->total_paid_tax_incl) { + $id_order_state = Configuration::get('PS_OS_OVERBOOKING_PARTIAL_PAID'); + } else { + $id_order_state = Configuration::get('PS_OS_OVERBOOKING_PAID'); + } + } else { + $id_order_state = Configuration::get('PS_OS_OVERBOOKING_UNPAID'); + } + } + $history = new OrderHistory(); $history->id_order = (int)$order->id; - $history->changeIdOrderState(Configuration::get($order->valid ? 'PS_OS_OUTOFSTOCK_PAID' : 'PS_OS_OUTOFSTOCK_UNPAID'), $order, true); + $history->changeIdOrderState($id_order_state, $order, true); $history->addWithemail(); } @@ -1147,8 +1233,21 @@ abstract class PaymentModuleCore extends Module PrestaShopLogger::addLog('PaymentModule::validateOrder - Mail is about to be sent', 1, null, 'Cart', (int)$id_cart, true); } - // Send order confirmation mails to the reciepients according to the order mail configuration + $orderStatusObj = new OrderState((int)$id_order_state, (int)$this->context->language->id); + $data['{order_status}'] = $orderStatusObj->name; + $data['{order_status_color}'] = $orderStatusObj->color; + // Send order confirmation/overbooking mails to the reciepients according to the order mail configuration + $overBookingStates = OrderState::getOverBookingStates(); + $isOverBookingStatus = in_array($id_order_state, $overBookingStates); if (Configuration::get('PS_ORDER_CONF_MAIL_TO_CUSTOMER')){ + // If order currenct state is overbooking, the send overbooking email or send order confirmation email + if ($isOverBookingStatus) { + $subject = Mail::l('Order Not Confirmed', (int)$order->id_lang); + $template = 'overbooking'; + } else { + $subject = Mail::l('Order confirmation', (int)$order->id_lang); + $template = 'order_conf'; + } if (Validate::isEmail($this->context->customer->email)) { // send customer information $data['{firstname}'] = $this->context->customer->firstname; @@ -1156,8 +1255,8 @@ abstract class PaymentModuleCore extends Module $data['{email}'] = $this->context->customer->email; Mail::Send( (int)$order->id_lang, - 'order_conf', - Mail::l('Order confirmation', (int)$order->id_lang), + $template, + $subject, $data, $this->context->customer->email, $this->context->customer->firstname.' '.$this->context->customer->lastname, @@ -1178,8 +1277,8 @@ abstract class PaymentModuleCore extends Module $data['{email}'] = $objOrderCustomerGuestDetail->email; Mail::Send( (int)$order->id_lang, - 'order_conf', - Mail::l('Order confirmation', (int)$order->id_lang), + $template, + $subject, $data, $objOrderCustomerGuestDetail->email, $objOrderCustomerGuestDetail->firstname.' '.$objOrderCustomerGuestDetail->lastname, @@ -1193,8 +1292,17 @@ abstract class PaymentModuleCore extends Module } } if (Configuration::get('PS_ORDER_CONF_MAIL_TO_SUPERADMIN')){ - // send superadmin information + // get superadmin employees if ($superAdminEmployees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true)) { + // If order currenct state is overbooking, the send overbooking email or send order confirmation email + if ($isOverBookingStatus) { + $subject = Mail::l('Order Not Confirmed', (int)$order->id_lang); + $template = 'overbooking_admin'; + } else { + $subject = Mail::l('Order confirmation', (int)$order->id_lang); + $template = 'order_conf_admin'; + } + foreach ($superAdminEmployees as $superAdminEmployee) { if (Validate::isEmail($superAdminEmployee['email'])) { $data['{customer_name}'] = $this->context->customer->firstname.' '.$this->context->customer->lastname; @@ -1204,8 +1312,8 @@ abstract class PaymentModuleCore extends Module $data['{email}'] = $superAdminEmployee['email']; Mail::Send( (int)$order->id_lang, - 'order_conf_admin', - Mail::l('Order confirmation', (int)$order->id_lang), + $template, + $subject, $data, $superAdminEmployee['email'], $superAdminEmployee['firstname'].' '.$superAdminEmployee['lastname'], @@ -1222,6 +1330,14 @@ abstract class PaymentModuleCore extends Module && Validate::isLoadedObject($objHotel = new HotelBranchInformation($idHotel)) ) { if (Configuration::get('PS_ORDER_CONF_MAIL_TO_HOTEL_MANAGER')){ + // If order currenct state is overbooking, the send overbooking email or send order confirmation email + if ($isOverBookingStatus) { + $subject = Mail::l('Order Not Confirmed', (int)$order->id_lang); + $template = 'overbooking_admin'; + } else { + $subject = Mail::l('Order confirmation', (int)$order->id_lang); + $template = 'order_conf_admin'; + } // send hotel information $data['{firstname}'] = ''; $data['{lastname}'] = ''; @@ -1231,8 +1347,8 @@ abstract class PaymentModuleCore extends Module if (Validate::isEmail($objHotel->email)) { Mail::Send( (int)$order->id_lang, - 'order_conf_admin', - Mail::l('Order confirmation', (int)$order->id_lang), + $template, + $subject, $data, $objHotel->email, null, @@ -1247,6 +1363,16 @@ abstract class PaymentModuleCore extends Module if ($htlAccesses = $objHotel->getHotelAccess($idHotel)) { $data['{customer_name}'] = $this->context->customer->firstname.' '.$this->context->customer->lastname; $data['{customer_email}'] = $this->context->customer->email; + + // If order currenct state is overbooking, the send overbooking email or send order confirmation email + if ($isOverBookingStatus) { + $subject = Mail::l('Order Not Confirmed', (int)$order->id_lang); + $template = 'overbooking_admin'; + } else { + $subject = Mail::l('Order confirmation', (int)$order->id_lang); + $template = 'order_conf_admin'; + } + foreach ($htlAccesses as $access) { if ($access['access'] && $access['id_profile'] != _PS_ADMIN_PROFILE_) { if ($htlEmployees = Employee::getEmployeesByProfile($access['id_profile'])) { @@ -1258,8 +1384,8 @@ abstract class PaymentModuleCore extends Module $data['{email}'] = $empl['email']; Mail::Send( (int)$order->id_lang, - 'order_conf_admin', - Mail::l('Order confirmation', (int)$order->id_lang), + $template, + $subject, $data, $empl['email'], $empl['firstname'].' '.$empl['lastname'], @@ -1277,7 +1403,6 @@ abstract class PaymentModuleCore extends Module } } } - // updates stock in shops if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) { $product_list = $order->getProducts(); diff --git a/classes/order/Order.php b/classes/order/Order.php index bf9a33801..a4e7a5e6b 100644 --- a/classes/order/Order.php +++ b/classes/order/Order.php @@ -34,6 +34,10 @@ class OrderCore extends ObjectModel const ORDER_PAYMENT_TYPE_FULL = 1; const ORDER_PAYMENT_TYPE_ADVANCE = 2; + // actions when overbooking will be created + const OVERBOOKING_ORDER_CANCEL_ACTION = 1; + const OVERBOOKING_ORDER_NO_ACTION = 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; diff --git a/classes/order/OrderState.php b/classes/order/OrderState.php index 22e3d8db4..cd14adbf3 100644 --- a/classes/order/OrderState.php +++ b/classes/order/OrderState.php @@ -155,4 +155,13 @@ class OrderStateCore extends ObjectModel { return !($this->unremovable); } + + public static function getOverBookingStates() + { + return array( + Configuration::get('PS_OS_OVERBOOKING_PARTIAL_PAID'), + Configuration::get('PS_OS_OVERBOOKING_PAID'), + Configuration::get('PS_OS_OVERBOOKING_UNPAID'), + ); + } } diff --git a/controllers/admin/AdminOrderPreferencesController.php b/controllers/admin/AdminOrderPreferencesController.php index 52c131480..5f8622503 100644 --- a/controllers/admin/AdminOrderPreferencesController.php +++ b/controllers/admin/AdminOrderPreferencesController.php @@ -58,6 +58,18 @@ class AdminOrderPreferencesControllerCore extends AdminController ) ); + // actions when overbooking will be created + $overbookingAction = array( + array( + 'value' => Order::OVERBOOKING_ORDER_CANCEL_ACTION, + 'name' => $this->l('Cancel the booking') + ), + array( + 'value' => Order::OVERBOOKING_ORDER_NO_ACTION, + 'name' => $this->l('Take the overbooking') + ) + ); + // Options to display currency in order list $displayCurrencyOptions = array( array( @@ -195,33 +207,83 @@ class AdminOrderPreferencesControllerCore extends AdminController 'submit' => array('title' => $this->l('Save')) ), 'email' => array( - 'title' => $this->l('Email'), + 'title' => $this->l('Order Confirmation / Overbooking Email'), 'icon' => 'icon-cogs', 'fields' => array( 'PS_ORDER_CONF_MAIL_TO_CUSTOMER' => array( - 'title' => $this->l('Order confirmation mail to customer'), - 'hint' => $this->l('Enable, if you want to send order confirmation email to the customer.'), + 'title' => $this->l('Send email to customer'), + 'hint' => $this->l('Enable, if you want to send order confirmation or overbooking or overbooking email to the customer.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool' ), 'PS_ORDER_CONF_MAIL_TO_SUPERADMIN' => array( - 'title' => $this->l('Order confirmation mail to super admin'), - 'hint' => $this->l('Enable, if you want to send order confirmation email to the super admin.'), + 'title' => $this->l('Send email to super admin'), + 'hint' => $this->l('Enable, if you want to send order confirmation or overbooking email to the super admin.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool' ), 'PS_ORDER_CONF_MAIL_TO_HOTEL_MANAGER' => array( - 'title' => $this->l('Order confirmation mail to hotelier'), - 'hint' => $this->l('Enable, if you want to send order confirmation email to the hotelier. Mail will be sent to the email saved while creating the hotel.'), + 'title' => $this->l('Send email to hotelier'), + 'hint' => $this->l('Enable, if you want to send order confirmation or overbooking email to the hotelier. Mail will be sent to the email saved while creating the hotel.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool' ), 'PS_ORDER_CONF_MAIL_TO_EMPLOYEE' => array( - 'title' => $this->l('Order confirmation mail to employees'), - 'hint' => $this->l('Enable, if you want to send order confirmation email to employees having permission to manage the hotel.'), + 'title' => $this->l('Send email to employees'), + 'hint' => $this->l('Enable, if you want to send order confirmation or overbooking email to employees having permission to manage the hotel.'), + 'validation' => 'isBool', + 'cast' => 'intval', + 'type' => 'bool' + ), + ), + 'submit' => array('title' => $this->l('Save')) + ), + 'overbooking' => array( + 'title' => $this->l('Overbooking'), + 'icon' => 'icon-cogs', + 'fields' => array( + 'PS_OVERBOOKING_ORDER_ACTION' => array( + 'title' => $this->l('Overbooking order action'), + 'hint' => $this->l('Please choose the action to take when overbooking is created in any order.'), + 'validation' => 'isInt', + 'type' => 'select', + 'cast' => 'intval', + 'validation' => 'isInt', + 'list' => $overbookingAction, + 'identifier' => 'value', + 'js' => "changeOverbookingOrderAction()" + ), + 'PS_MAX_OVERBOOKING_PER_HOTEL_PER_DAY' => array( + 'title' => $this->l('Maximun hotel overbookings per date'), + 'hint' => $this->l('Enter the maximum number of the overbookings on any date can be created for a hotel.(Set 0 for no limit)'), + 'desc' => $this->l('When maximun number of the overbookings on any date in the booking duration is reached, then the new overbooking order will be cancelled.(Set 0 for no limit)'), + 'validation' => 'isInt', + 'type' => 'text', + 'class' => 'fixed-width-xxl', + 'validation' => 'isInt', + 'id' => 'PS_MAX_OVERBOOKING_PER_HOTEL_PER_DAY', + ), + 'OVERBOOKING_ORDER_CANCEL_ACTION' => array( + 'title' => $this->l('Overbooking order cancel action value'), + 'type' => 'hidden', + 'value' => Order::OVERBOOKING_ORDER_CANCEL_ACTION, + 'auto_value' => false, + ), + 'OVERBOOKING_ORDER_NO_ACTION' => array( + 'title' => $this->l('Overbooking order no action value'), + 'validation' => 'isInt', + 'cast' => 'intval', + 'type' => 'hidden', + 'value' => Order::OVERBOOKING_ORDER_NO_ACTION, + 'auto_value' => false + ), + 'PS_OVERBOOKING_AUTO_RESOLVE' => array( + 'title' => $this->l('Resolve overbooking automatically'), + 'hint' => $this->l('Enable, if you want to resolve overbooking automatically when rooms are available to be replaced with overbooked rooms.'), + 'desc' => $this->l('If enabled, the overbookings in the order will be resolved automatically when rooms are available to be replaced with all overbooked rooms in the order.'), 'validation' => 'isBool', 'cast' => 'intval', 'type' => 'bool' diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index b58c17844..52769f958 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -96,6 +96,22 @@ class AdminOrdersControllerCore extends AdminController $this->_group = ' GROUP BY hbd.`id_order`'; + // if request for resolvable overbooked orders filter comes the set condition for this + if (Tools::getIsset('resolvable_overbooked_orders') && Tools::getValue('resolvable_overbooked_orders')) { + $objHotelBookingDetail = new HotelBookingDetail(); + $resolvableOrders = array(); + // Overbookings information of the order + if ($orderOverBookings = $objHotelBookingDetail->getOverbookedRooms()) { + foreach ($orderOverBookings as $overBookedRoom) { + if (!in_array($overBookedRoom['id_order'], $resolvableOrders)) { + $resolvableOrders[$overBookedRoom['id_order']] = $overBookedRoom['id_order']; + } + } + } + $this->_where = ' AND a.`id_order` IN ('.implode(',', $resolvableOrders).')'; + } + + $statuses = OrderState::getOrderStates((int)$this->context->language->id); foreach ($statuses as $status) { $this->statuses_array[$status['id_order_state']] = $status['name']; @@ -326,6 +342,8 @@ class AdminOrdersControllerCore extends AdminController parent::__construct(); + // overbooking success status + $this->_conf[51] = $this->l('Overbooking is successfully resolved'); $this->_conf[52] = $this->l('Room in the booking is successfully reallocated'); $this->_conf[53] = $this->l('Room in the booking is successfully swapped'); } @@ -610,6 +628,13 @@ class AdminOrdersControllerCore extends AdminController public function renderList() { + // Show all resolvable overbookings if available + $objHotelBookingDetail = new HotelBookingDetail(); + if ($resolvableOverBookings = $objHotelBookingDetail->getOverbookedRooms(0, 0, '', '', 0, 0, 2)) { + $this->context->smarty->assign('resolvableOverBookings', $resolvableOverBookings); + $this->content .= $this->context->smarty->fetch('controllers/orders/_resolvable_overbookings.tpl'); + } + if (Tools::isSubmit('submitBulkupdateOrderStatus'.$this->table)) { if (Tools::getIsset('cancel')) { Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token); @@ -1701,7 +1726,20 @@ class AdminOrdersControllerCore extends AdminController } else { $this->errors[] = Tools::displayError('You do not have permission to edit this.'); } + } elseif(Tools::getIsset('resolve_overbooking') && Tools::getValue('resolve_overbooking')) { + $objHotelBookingDetail = new HotelBookingDetail(); + // resolve an overbooking manually + if ($objHotelBookingDetail->resolveOverbookings(Tools::getValue('resolve_overbooking'))) { + if (Tools::getValue('id_order')) { + Tools::redirectAdmin(self::$currentIndex.'&id_order='.$order->id.'&vieworder&conf=51&token='.$this->token); + } else { + Tools::redirectAdmin(self::$currentIndex.'&conf=51&token='.$this->token); + } + } else { + $this->errors = Tools::displayError('An error occurred while resolving overbooking.'); + } } + parent::postProcess(); } @@ -2111,8 +2149,12 @@ class AdminOrdersControllerCore extends AdminController // applicable refund policies $applicableRefundPolicies = HotelOrderRefundRules::getApplicableRefundRules($order->id); + // Overbookings information of the order + $orderOverBookings = $objHotelBookingDetail->getOverbookedRooms($order->id, 0, '', '', 0, 0, 1); + $this->tpl_view_vars = array( // refund info + 'orderOverBookings' => $orderOverBookings, 'refund_allowed' => (int) $order->isReturnable(), 'applicable_refund_policies' => $applicableRefundPolicies, 'returns' => OrderReturn::getOrdersReturn($order->id_customer, $order->id), diff --git a/controllers/front/HistoryController.php b/controllers/front/HistoryController.php index e3a8210e4..8e41935c8 100644 --- a/controllers/front/HistoryController.php +++ b/controllers/front/HistoryController.php @@ -66,6 +66,7 @@ class HistoryControllerCore extends FrontController } $this->context->smarty->assign(array( 'orders' => $orders, + 'overbooking_order_states' => OrderState::getOverBookingStates(), 'invoiceAllowed' => (int)Configuration::get('PS_INVOICE'), 'reorderingAllowed' => !(bool)Configuration::get('PS_DISALLOW_HISTORY_REORDERING'), 'slowValidation' => Tools::isSubmit('slowvalidation') diff --git a/controllers/front/OrderDetailController.php b/controllers/front/OrderDetailController.php index 96a3656f3..3f9f89187 100644 --- a/controllers/front/OrderDetailController.php +++ b/controllers/front/OrderDetailController.php @@ -679,6 +679,7 @@ class OrderDetailControllerCore extends FrontController 'invoice' => (OrderState::invoiceAvailable($id_order_state) && count($order->getInvoicesCollection())), 'logable' => (bool) $order_status->logable, 'order_history' => $order->getHistory($this->context->language->id, false, true), + 'overbooking_order_states' => OrderState::getOverBookingStates(), 'products' => $products, 'discounts' => $order->getCartRules(), 'carrier' => $carrier, diff --git a/install/data/img/os/Overbooking_partial_paid.gif b/install/data/img/os/Overbooking_partial_paid.gif new file mode 100644 index 000000000..7a8f831fc Binary files /dev/null and b/install/data/img/os/Overbooking_partial_paid.gif differ diff --git a/install/data/xml/configuration.xml b/install/data/xml/configuration.xml index 67b8602c1..984a749f4 100644 --- a/install/data/xml/configuration.xml +++ b/install/data/xml/configuration.xml @@ -332,6 +332,12 @@ 0 + + 1 + + + 0 + 1 @@ -431,6 +437,9 @@ 11 + + 12 + diff --git a/install/data/xml/order_state.xml b/install/data/xml/order_state.xml index a1f70e4ec..cc016ffcd 100644 --- a/install/data/xml/order_state.xml +++ b/install/data/xml/order_state.xml @@ -26,7 +26,7 @@ - -