From 38d8bb2b94932b3dbc98cbaff075e18ea8fba194 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Thu, 29 Jun 2023 15:30:23 +0530 Subject: [PATCH 01/16] Date wise breakdown added in Availability and rates search API --- .../WebserviceSpecificManagementHotelAri.php | 597 ++++++++++-------- 1 file changed, 332 insertions(+), 265 deletions(-) diff --git a/modules/hotelreservationsystem/classes/WebserviceSpecificManagementHotelAri.php b/modules/hotelreservationsystem/classes/WebserviceSpecificManagementHotelAri.php index bfdbfdce8..bc4b33dce 100644 --- a/modules/hotelreservationsystem/classes/WebserviceSpecificManagementHotelAri.php +++ b/modules/hotelreservationsystem/classes/WebserviceSpecificManagementHotelAri.php @@ -29,7 +29,7 @@ class WebserviceSpecificManagementHotelAri extends ObjectModel implements Webser public $get_booked_rooms; public $get_partial_available_rooms; public $get_unavailable_rooms; - + public $date_wise_breakdown; /** @var WebserviceOutputBuilder */ protected $objOutput; @@ -51,6 +51,7 @@ class WebserviceSpecificManagementHotelAri extends ObjectModel implements Webser 'get_booked_rooms' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'get_partial_available_rooms' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'get_unavailable_rooms' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), + 'date_wise_breakdown' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), ), ); @@ -225,21 +226,59 @@ class WebserviceSpecificManagementHotelAri extends ObjectModel implements Webser } // now call the function - $obBookingDtl = new HotelBookingDetail(); - $ariInfo = $obBookingDtl->getBookingData($bookingParams); + $objBookingDtl = new HotelBookingDetail(); - // append request fields also. will be attached in the response xml - $ariInfo['id_hotel'] = $ariParams['id_hotel']; - $ariInfo['date_from'] = $bookingParams['date_from']; - $ariInfo['date_to'] = $bookingParams['date_to']; - $ariInfo['num_rooms'] = $totalRooms; + $searchAriData = []; + + // If api is called for getting ari info for all the dates in the provided date range + if (isset($ariParams['date_wise_breakdown']) && $ariParams['date_wise_breakdown'] && $bookingParams['search_available']) { + $dateWiseBreakdown = 1; + + $datesAriInfo = []; + + $dateFrom = $bookingParams['date_from']; + $dateTo = $bookingParams['date_to']; + + // Lets get data date by date (Every date in the date range) + $dateBookingParams = $bookingParams; + // for a single date there is no use of partial available rooms + $dateBookingParams['search_partial'] = 0; + + for ($currentDate = $dateFrom; $currentDate < $dateTo; $currentDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate)))) { + $dateBookingParams['date_from'] = $currentDate; + $dateBookingParams['date_to'] = date('Y-m-d', strtotime('+1 day', strtotime($currentDate))); + + // get inventories for every date + $ariInfo = $objBookingDtl->getBookingData($dateBookingParams); + // append request fields also. will be attached in the response xml + $ariInfo['id_hotel'] = $ariParams['id_hotel']; + $ariInfo['date_from'] = $dateBookingParams['date_from']; + $ariInfo['date_to'] = $dateBookingParams['date_to']; + $ariInfo['num_rooms'] = $totalRooms; + + $searchAriData[] = $ariInfo; + } + } else { // If api is called for getting ari info for a particular date range + $dateWiseBreakdown = 0; + + // If api is called for getting ari info for a particular date range + $ariInfo = $objBookingDtl->getBookingData($bookingParams); + + // append request fields also. will be attached in the response xml + $ariInfo['id_hotel'] = $ariParams['id_hotel']; + $ariInfo['date_from'] = $bookingParams['date_from']; + $ariInfo['date_to'] = $bookingParams['date_to']; + $ariInfo['num_rooms'] = $totalRooms; + + $searchAriData[] = $ariInfo; + } // We have to create the json and xml response for request by ourself. So we need to check if data to be sent in xml or json // We have no way to check the output format from parent classed. So we used below code if (get_class($this->objOutput->getObjectRender()) == 'WebserviceOutputJSON') { - $this->getResponseJson($ariInfo); + $this->getResponseJson($searchAriData, $dateWiseBreakdown); } else { - $this->getResponseXml($ariInfo); + $this->getResponseXml($searchAriData, $dateWiseBreakdown); } } @@ -392,167 +431,180 @@ class WebserviceSpecificManagementHotelAri extends ObjectModel implements Webser } // create xml for the response of the ari request - private function getResponseXml($ariInfo) + private function getResponseXml($ariInfoArray, $dateWiseBreakdown = 0) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('hotel_ari', array()); - - $field = array('sqlId' => 'id_hotel', 'value' => $ariInfo['id_hotel'], 'xlink_resource' => 'hotels'); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $field = array('sqlId' => 'date_from', 'value' => $ariInfo['date_from']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $field = array('sqlId' => 'date_to', 'value' => $ariInfo['date_to']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); - $field = array('sqlId' => 'currency', 'value' => $objCurrency->iso_code); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - // check if availability stats are available then only process further - if (isset($ariInfo['stats']) && $ariInfo['stats']) { - $field = array('sqlId' => 'total_rooms', 'value' => $ariInfo['stats']['total_rooms']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - if (isset($ariInfo['stats']['num_avail'])) { - $field = array('sqlId' => 'total_available_rooms', 'value' => $ariInfo['stats']['num_avail']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); + if ($ariInfoArray) { + // if date wise breakup is requested the parent node will be 'hotel_aris' as per other APIs in QloApps (orders > order) + if ($dateWiseBreakdown) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('hotel_aris', array()); } + foreach ($ariInfoArray as $ariInfo) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('hotel_ari', array()); - if (isset($ariInfo['stats']['num_unavail'])) { - $field = array('sqlId' => 'total_unavailable_rooms', 'value' => $ariInfo['stats']['num_unavail']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - } - - if (isset($ariInfo['stats']['num_part_avai'])) { - $field = array('sqlId' => 'total_partial_available_rooms', 'value' => $ariInfo['stats']['num_part_avai']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - } - - if (isset($ariInfo['stats']['num_booked'])) { - $field = array('sqlId' => 'total_booked_rooms', 'value' => $ariInfo['stats']['num_booked']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - } - } - - // check if room type data is available then only process further - if (isset($ariInfo['rm_data']) && $ariInfo['rm_data']) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room_types', array()); - - foreach ($ariInfo['rm_data'] as $roomTypeInfo) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room_type', array(), array('id' => $roomTypeInfo['id_product'], 'xlink_resource' => $this->wsObject->wsUrl.'room_types'.'/'.$roomTypeInfo['id_product'])); - - $field = array('sqlId' => 'id_room_type', 'value' => $roomTypeInfo['id_product'], 'xlink_resource' => 'room_types'); + $field = array('sqlId' => 'id_hotel', 'value' => $ariInfo['id_hotel'], 'xlink_resource' => 'hotels'); $this->output .= $this->objOutput->getObjectRender()->renderField($field); - // get feature price of room type - $roomTypePrice = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - 0 - ); - $field = array('sqlId' => 'base_price', 'value' => $roomTypePrice); + $field = array('sqlId' => 'date_from', 'value' => $ariInfo['date_from']); $this->output .= $this->objOutput->getObjectRender()->renderField($field); - // get feature price of room type - $roomTypePrice = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - 1 - ); - $field = array('sqlId' => 'base_price_with_tax', 'value' => $roomTypePrice); + $field = array('sqlId' => 'date_to', 'value' => $ariInfo['date_to']); $this->output .= $this->objOutput->getObjectRender()->renderField($field); - $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - $ariInfo['num_rooms'] - ); - $field = array('sqlId' => 'total_price', 'value' => $totalBookingPrice['total_price_tax_excl']); + $objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); + $field = array('sqlId' => 'currency', 'value' => $objCurrency->iso_code); $this->output .= $this->objOutput->getObjectRender()->renderField($field); - $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - $ariInfo['num_rooms'] - ); - $field = array('sqlId' => 'total_price_with_tax', 'value' => $totalBookingPrice['total_price_tax_incl']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); + // check if availability stats are available then only process further + if (isset($ariInfo['stats']) && $ariInfo['stats']) { + $field = array('sqlId' => 'total_rooms', 'value' => $ariInfo['stats']['total_rooms']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); - $objRoomType = new Product($roomTypeInfo['id_product']); - $field = array('sqlId' => 'name', 'value' => $objRoomType->name, 'i18n' => true); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - // rooms info of the room type - if (isset($roomTypeInfo['data']) && $roomTypeInfo['data']) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('rooms', array()); - foreach ($roomTypeInfo['data'] as $key => $roomsInfo) { - if ($key == 'available') { - $nodeRoomAvailability = 'available'; - } elseif ($key == 'unavailable') { - $nodeRoomAvailability = 'unavailable'; - } elseif ($key == 'booked') { - $nodeRoomAvailability = 'booked'; - } elseif ($key == 'partially_available') { - $nodeRoomAvailability = 'partial_available'; - } - - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader($nodeRoomAvailability, array()); - if ($key == 'partially_available') { - foreach ($roomsInfo as $dateIndex => $partialRoomsInfo) { - if (isset($partialRoomsInfo['rooms']) && $partialRoomsInfo['rooms']) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('rooms', array(), array('date_from' => $partialRoomsInfo['date_from'], 'date_to' => $partialRoomsInfo['date_to'])); - - foreach ($partialRoomsInfo['rooms'] as $roomInfo) { - $roomDetail = array(); - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room', array(), array('id' => $roomInfo['id_room'])); - - $field = array('sqlId' => 'id_room', 'value' => $roomInfo['id_room']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $field = array('sqlId' => 'room_number', 'value' => $roomInfo['room_num']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room', array()); - } - - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('rooms', array()); - } - } - } else { - if ($roomsInfo) { - foreach ($roomsInfo as $roomInfo) { - $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room', array(), array('id' => $roomInfo['id_room'])); - - $field = array('sqlId' => 'id_room', 'value' => $roomInfo['id_room']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $field = array('sqlId' => 'room_number', 'value' => $roomInfo['room_num']); - $this->output .= $this->objOutput->getObjectRender()->renderField($field); - - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room', array()); - } - } - } - - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter($nodeRoomAvailability, array()); + if (isset($ariInfo['stats']['num_avail'])) { + $field = array('sqlId' => 'total_available_rooms', 'value' => $ariInfo['stats']['num_avail']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); } - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('rooms', array()); + if (isset($ariInfo['stats']['num_unavail'])) { + $field = array('sqlId' => 'total_unavailable_rooms', 'value' => $ariInfo['stats']['num_unavail']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + } + + if (isset($ariInfo['stats']['num_part_avai'])) { + $field = array('sqlId' => 'total_partial_available_rooms', 'value' => $ariInfo['stats']['num_part_avai']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + } + + if (isset($ariInfo['stats']['num_booked'])) { + $field = array('sqlId' => 'total_booked_rooms', 'value' => $ariInfo['stats']['num_booked']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + } } - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room_type', array()); + // check if room type data is available then only process further + if (isset($ariInfo['rm_data']) && $ariInfo['rm_data']) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room_types', array()); + + foreach ($ariInfo['rm_data'] as $roomTypeInfo) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room_type', array(), array('id' => $roomTypeInfo['id_product'], 'xlink_resource' => $this->wsObject->wsUrl.'room_types'.'/'.$roomTypeInfo['id_product'])); + + $field = array('sqlId' => 'id_room_type', 'value' => $roomTypeInfo['id_product'], 'xlink_resource' => 'room_types'); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + // get feature price of room type + $roomTypePrice = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + 0 + ); + $field = array('sqlId' => 'base_price', 'value' => $roomTypePrice); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + // get feature price of room type + $roomTypePrice = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + 1 + ); + $field = array('sqlId' => 'base_price_with_tax', 'value' => $roomTypePrice); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + $ariInfo['num_rooms'] + ); + $field = array('sqlId' => 'total_price', 'value' => $totalBookingPrice['total_price_tax_excl']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + $ariInfo['num_rooms'] + ); + $field = array('sqlId' => 'total_price_with_tax', 'value' => $totalBookingPrice['total_price_tax_incl']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $objRoomType = new Product($roomTypeInfo['id_product']); + $field = array('sqlId' => 'name', 'value' => $objRoomType->name, 'i18n' => true); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + // rooms info of the room type + if (isset($roomTypeInfo['data']) && $roomTypeInfo['data']) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('rooms', array()); + foreach ($roomTypeInfo['data'] as $key => $roomsInfo) { + if ($key == 'available') { + $nodeRoomAvailability = 'available'; + } elseif ($key == 'unavailable') { + $nodeRoomAvailability = 'unavailable'; + } elseif ($key == 'booked') { + $nodeRoomAvailability = 'booked'; + } elseif ($key == 'partially_available') { + $nodeRoomAvailability = 'partial_available'; + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader($nodeRoomAvailability, array()); + if ($key == 'partially_available') { + foreach ($roomsInfo as $dateIndex => $partialRoomsInfo) { + if (isset($partialRoomsInfo['rooms']) && $partialRoomsInfo['rooms']) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('rooms', array(), array('date_from' => $partialRoomsInfo['date_from'], 'date_to' => $partialRoomsInfo['date_to'])); + + foreach ($partialRoomsInfo['rooms'] as $roomInfo) { + $roomDetail = array(); + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room', array(), array('id' => $roomInfo['id_room'])); + + $field = array('sqlId' => 'id_room', 'value' => $roomInfo['id_room']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $field = array('sqlId' => 'room_number', 'value' => $roomInfo['room_num']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room', array()); + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('rooms', array()); + } + } + } else { + if ($roomsInfo) { + foreach ($roomsInfo as $roomInfo) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeHeader('room', array(), array('id' => $roomInfo['id_room'])); + + $field = array('sqlId' => 'id_room', 'value' => $roomInfo['id_room']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $field = array('sqlId' => 'room_number', 'value' => $roomInfo['room_num']); + $this->output .= $this->objOutput->getObjectRender()->renderField($field); + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room', array()); + } + } + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter($nodeRoomAvailability, array()); + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('rooms', array()); + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room_type', array()); + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room_types', array()); + } + + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('hotel_ari', array()); } - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('room_types', array()); + // if date wise breakup is requested the parent node will be 'hotel_aris' as per other APIs in QloApps (orders > order) + if ($dateWiseBreakdown) { + $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('hotel_aris', array()); + } } - $this->output .= $this->objOutput->getObjectRender()->renderNodeFooter('hotel_ari', array()); - // wrap with the common parent header of QloApps xml api responses $this->output = $this->objOutput->getObjectRender()->overrideContent($this->output); @@ -560,131 +612,146 @@ class WebserviceSpecificManagementHotelAri extends ObjectModel implements Webser } // create json for the response of the ari request - private function getResponseJson($ariInfo) + private function getResponseJson($ariInfoArray, $dateWiseBreakdown = 0) { $ariFormatted = array(); - $ariFormatted['hotel_ari'] = array(); - $ariFormatted['hotel_ari']['id_hotel'] = $ariInfo['id_hotel']; - $ariFormatted['hotel_ari']['date_from'] = $ariInfo['date_from']; - $ariFormatted['hotel_ari']['date_to'] = $ariInfo['date_to']; + if ($ariInfoArray) { + foreach ($ariInfoArray as $ariInfo) { + $dateAriInfo = array(); + $dateAriInfo = array(); + $dateAriInfo['id_hotel'] = $ariInfo['id_hotel']; + $dateAriInfo['date_from'] = $ariInfo['date_from']; + $dateAriInfo['date_to'] = $ariInfo['date_to']; - $objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); - $ariFormatted['hotel_ari']['currency'] = $objCurrency->iso_code; + $objCurrency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); + $dateAriInfo['currency'] = $objCurrency->iso_code; - // check if availability stats are available then only process further - if (isset($ariInfo['stats']) && $ariInfo['stats']) { - $ariFormatted['hotel_ari']['total_rooms'] = $ariInfo['stats']['total_rooms']; - if (isset($ariInfo['stats']['num_avail'])) { - $ariFormatted['hotel_ari']['total_available_rooms'] = $ariInfo['stats']['num_avail']; - } - if (isset($ariInfo['stats']['num_unavail'])) { - $ariFormatted['hotel_ari']['total_unavailable_rooms'] = $ariInfo['stats']['num_unavail']; - } - if (isset($ariInfo['stats']['num_part_avai'])) { - $ariFormatted['hotel_ari']['total_partial_available_rooms'] = $ariInfo['stats']['num_part_avai']; - } - if (isset($ariInfo['stats']['num_booked'])) { - $ariFormatted['hotel_ari']['total_booked_rooms'] = $ariInfo['stats']['num_booked']; - } - } - - // check if room type data is available then only process further - if (isset($ariInfo['rm_data']) && $ariInfo['rm_data']) { - $ariFormatted['hotel_ari']['room_types'] = array(); - - foreach ($ariInfo['rm_data'] as $roomTypeIndex => $roomTypeInfo) { - // get feature price of room type - $roomTypePriceTE = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - 0 - ); - $roomTypePriceTI = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - 1 - ); - $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( - $roomTypeInfo['id_product'], - $ariInfo['date_from'], - $ariInfo['date_to'], - $ariInfo['num_rooms'] - ); - - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex] = array( - 'id_room_type' => $roomTypeInfo['id_product'], - 'base_price' => $roomTypePriceTE, - 'base_price_with_tax' => $roomTypePriceTI, - 'total_price' => $totalBookingPrice['total_price_tax_excl'], - 'total_price_with_tax' => $totalBookingPrice['total_price_tax_incl'] - ); - - $objRoomType = new Product($roomTypeInfo['id_product']); - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['name'] = array(); - foreach ($this->objOutput->getObjectRender()->languages as $idLang) { - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['name'][] = array( - 'id' => $idLang, - 'value' => $objRoomType->name[$idLang] - ); - } - // if only one lang than do not set name as array and set only value of the room - if (count($ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['name']) == 1) { - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['name'] = $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['name'][0]['value']; - } - - // rooms info of the room type - if (isset($roomTypeInfo['data']) && $roomTypeInfo['data']) { - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['rooms'] = array(); - - foreach ($roomTypeInfo['data'] as $key => $roomsInfo) { - $roomsAriInfo = array(); - if ($key == 'available') { - $keyRoomAvailability = 'available'; - } elseif ($key == 'unavailable') { - $keyRoomAvailability = 'unavailable'; - } elseif ($key == 'booked') { - $keyRoomAvailability = 'booked'; - } elseif ($key == 'partially_available') { - $keyRoomAvailability = 'partially_available'; - } - - if ($roomsInfo) { - if ($key == 'partially_available') { - foreach ($roomsInfo as $dateIndex => $partialRoomsInfo) { - if (isset($partialRoomsInfo['rooms']) && $partialRoomsInfo['rooms']) { - $roomsAriInfo[$dateIndex]['date_from'] = $partialRoomsInfo['date_from']; - $roomsAriInfo[$dateIndex]['date_to'] = $partialRoomsInfo['date_to']; - - $roomsAriInfo[$dateIndex]['rooms'] = array(); - foreach ($partialRoomsInfo['rooms'] as $roomInfo) { - $roomDetail = array(); - $roomDetail['id_room'] = $roomInfo['id_room']; - $roomDetail['room_number'] = $roomInfo['room_num']; - - $roomsAriInfo[$dateIndex]['rooms'][] = $roomDetail; - } - } - } - } else { - foreach ($roomsInfo as $roomIndex => $roomInfo) { - $roomsAriInfo[$roomIndex]['id_room'] = $roomInfo['id_room']; - $roomsAriInfo[$roomIndex]['room_number'] = $roomInfo['room_num']; - } - } - } - - $ariFormatted['hotel_ari']['room_types'][$roomTypeIndex]['rooms'][$keyRoomAvailability] = array_values($roomsAriInfo); + // check if availability stats are available then only process further + if (isset($ariInfo['stats']) && $ariInfo['stats']) { + $dateAriInfo['total_rooms'] = $ariInfo['stats']['total_rooms']; + if (isset($ariInfo['stats']['num_avail'])) { + $dateAriInfo['total_available_rooms'] = $ariInfo['stats']['num_avail']; + } + if (isset($ariInfo['stats']['num_unavail'])) { + $dateAriInfo['total_unavailable_rooms'] = $ariInfo['stats']['num_unavail']; + } + if (isset($ariInfo['stats']['num_part_avai'])) { + $dateAriInfo['total_partial_available_rooms'] = $ariInfo['stats']['num_part_avai']; + } + if (isset($ariInfo['stats']['num_booked'])) { + $dateAriInfo['total_booked_rooms'] = $ariInfo['stats']['num_booked']; } } - $ariFormatted['hotel_ari']['room_types'] = array_values($ariFormatted['hotel_ari']['room_types']); + // check if room type data is available then only process further + if (isset($ariInfo['rm_data']) && $ariInfo['rm_data']) { + $dateAriInfo['room_types'] = array(); + + foreach ($ariInfo['rm_data'] as $roomTypeIndex => $roomTypeInfo) { + // get feature price of room type + $roomTypePriceTE = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + 0 + ); + $roomTypePriceTI = HotelRoomTypeFeaturePricing::getRoomTypeFeaturePricesPerDay( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + 1 + ); + $totalBookingPrice = HotelRoomTypeFeaturePricing::getRoomTypeTotalPrice( + $roomTypeInfo['id_product'], + $ariInfo['date_from'], + $ariInfo['date_to'], + $ariInfo['num_rooms'] + ); + + $dateAriInfo['room_types'][$roomTypeIndex] = array( + 'id_room_type' => $roomTypeInfo['id_product'], + 'base_price' => $roomTypePriceTE, + 'base_price_with_tax' => $roomTypePriceTI, + 'total_price' => $totalBookingPrice['total_price_tax_excl'], + 'total_price_with_tax' => $totalBookingPrice['total_price_tax_incl'] + ); + + $objRoomType = new Product($roomTypeInfo['id_product']); + $dateAriInfo['room_types'][$roomTypeIndex]['name'] = array(); + foreach ($this->objOutput->getObjectRender()->languages as $idLang) { + $dateAriInfo['room_types'][$roomTypeIndex]['name'][] = array( + 'id' => $idLang, + 'value' => $objRoomType->name[$idLang] + ); + } + // if only one lang than do not set name as array and set only value of the room + if (count($dateAriInfo['room_types'][$roomTypeIndex]['name']) == 1) { + $dateAriInfo['room_types'][$roomTypeIndex]['name'] = $dateAriInfo['room_types'][$roomTypeIndex]['name'][0]['value']; + } + + // rooms info of the room type + if (isset($roomTypeInfo['data']) && $roomTypeInfo['data']) { + $dateAriInfo['room_types'][$roomTypeIndex]['rooms'] = array(); + + foreach ($roomTypeInfo['data'] as $key => $roomsInfo) { + $roomsAriInfo = array(); + if ($key == 'available') { + $keyRoomAvailability = 'available'; + } elseif ($key == 'unavailable') { + $keyRoomAvailability = 'unavailable'; + } elseif ($key == 'booked') { + $keyRoomAvailability = 'booked'; + } elseif ($key == 'partially_available') { + $keyRoomAvailability = 'partially_available'; + } + + if ($roomsInfo) { + if ($key == 'partially_available') { + foreach ($roomsInfo as $dateIndex => $partialRoomsInfo) { + if (isset($partialRoomsInfo['rooms']) && $partialRoomsInfo['rooms']) { + $roomsAriInfo[$dateIndex]['date_from'] = $partialRoomsInfo['date_from']; + $roomsAriInfo[$dateIndex]['date_to'] = $partialRoomsInfo['date_to']; + + $roomsAriInfo[$dateIndex]['rooms'] = array(); + foreach ($partialRoomsInfo['rooms'] as $roomInfo) { + $roomDetail = array(); + $roomDetail['id_room'] = $roomInfo['id_room']; + $roomDetail['room_number'] = $roomInfo['room_num']; + + $roomsAriInfo[$dateIndex]['rooms'][] = $roomDetail; + } + } + } + } else { + foreach ($roomsInfo as $roomIndex => $roomInfo) { + $roomsAriInfo[$roomIndex]['id_room'] = $roomInfo['id_room']; + $roomsAriInfo[$roomIndex]['room_number'] = $roomInfo['room_num']; + } + } + } + + $dateAriInfo['room_types'][$roomTypeIndex]['rooms'][$keyRoomAvailability] = array_values($roomsAriInfo); + } + } + + $dateAriInfo['room_types'] = array_values($dateAriInfo['room_types']); + } + } + + $ariFormatted[] = $dateAriInfo; } } // change the content to the json form for api response - $this->output .= json_encode($ariFormatted); + $ariReponse = []; + if ($dateWiseBreakdown) { + // if date wise breakup is requested the parent node will be 'hotel_aris' as per other APIs in QloApps (orders > order) + $ariReponse['hotel_aris'] = array_values($ariFormatted); + } else { + $ariReponse['hotel_ari'] = $ariFormatted[0]; + } + + $this->output .= json_encode($ariReponse); $this->output = preg_replace_callback("/\\\\u([a-f0-9]{4})/", function ($matches) { return iconv('UCS-4LE','UTF-8', pack('V', hexdec('U' . $matches[1]))); }, $this->output); From fd62951fe75d3da980fa8e68a052e28910ea7291 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Tue, 21 May 2024 10:34:14 +0530 Subject: [PATCH 02/16] Added: option to view frequent customer in backoffice customer page --- .../admin/AdminCustomersController.php | 34 +++++++++++-------- controllers/admin/AdminStatsController.php | 11 ++++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/controllers/admin/AdminCustomersController.php b/controllers/admin/AdminCustomersController.php index 6c763f10c..206552a6a 100644 --- a/controllers/admin/AdminCustomersController.php +++ b/controllers/admin/AdminCustomersController.php @@ -79,6 +79,9 @@ class AdminCustomersControllerCore extends AdminController $this->_join = 'LEFT JOIN '._DB_PREFIX_.'gender_lang gl ON (a.id_gender = gl.id_gender AND gl.id_lang = '.(int)$this->context->language->id.')'; $this->_join .= ' LEFT JOIN '._DB_PREFIX_.'group_lang grl ON (a.id_default_group = grl.id_group AND grl.id_lang = '.(int)$this->context->language->id.')'; + $this->_join .= ' LEFT JOIN '._DB_PREFIX_.'orders o ON (a.id_customer = o.id_customer)'; + $this->_group = 'GROUP BY a.`id_customer`'; + $this->_use_found_rows = false; $this->fields_list = array( 'id_customer' => array( @@ -123,6 +126,7 @@ class AdminCustomersControllerCore extends AdminController ), 'total_orders' => array( 'title' => $this->l('Number of orders'), + 'type' => 'range', 'optional' => true, 'visible_default' => true, 'havingFilter' => true, @@ -170,6 +174,12 @@ class AdminCustomersControllerCore extends AdminController 'type' => 'datetime', 'search' => false, 'havingFilter' => true + ), + 'order_date' => array( + 'title' => $this->l('Order date'), + 'type' => 'date', + 'filter_key' => 'o!date_add', + 'displayed' => false ) )); @@ -178,19 +188,8 @@ class AdminCustomersControllerCore extends AdminController parent::__construct(); $this->_select = ' - a.date_add, gl.name as title, grl.name as default_group_name, ( - SELECT SUM(total_paid_real / conversion_rate) - FROM '._DB_PREFIX_.'orders o - WHERE o.id_customer = a.id_customer - '.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').' - AND o.valid = 1 - ) as total_spent, ( - SELECT COUNT(o.`id_order`) - FROM '._DB_PREFIX_.'orders o - WHERE o.id_customer = a.id_customer - '.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').' - AND o.valid = 1 - ) as total_orders, ( + a.date_add, gl.name as title, grl.name as default_group_name, COUNT(o.`id_order`) as total_orders, + o.`date_add` as order_date, SUM(total_paid_real / conversion_rate) as total_spent, ( SELECT c.date_add FROM '._DB_PREFIX_.'guest g LEFT JOIN '._DB_PREFIX_.'connections c ON c.id_guest = g.id_guest WHERE g.id_customer = a.id_customer @@ -217,6 +216,12 @@ class AdminCustomersControllerCore extends AdminController $this->redirect_after = $this->context->link->getAdminLink('AdminCustomers'); } + if (Tools::getValue('frequent_customers')) { + $this->context->cookie->{'customerscustomerFilter_total_orders'} = json_encode(array(Configuration::get('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS'), '')); + $this->context->cookie->{'customerscustomerFilter_o!date_add'} = json_encode(array(date('Y-m-d', strtotime('-365 day')), date('Y-m-d'))); + $this->redirect_after = $this->context->link->getAdminLink('AdminCustomers'); + } + parent::postProcess(); } @@ -696,7 +701,8 @@ class AdminCustomersControllerCore extends AdminController $helper->icon = 'icon-star'; $helper->color = 'color2'; $helper->title = $this->l('Total Frequent Customers', null, null, false); - $helper->subtitle = $this->l('All Time', null, null, false); + $helper->subtitle = $this->l('1 year', null, null, false); + $helper->href = $this->context->link->getAdminLink('AdminCustomers').'&frequent_customers=1'; $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_frequent_customers'; $helper->tooltip = $this->l('The total number of frequent customers in given period of time.', null, null, false); $kpis[] = $helper; diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php index 2de11a362..33d50d0f8 100644 --- a/controllers/admin/AdminStatsController.php +++ b/controllers/admin/AdminStatsController.php @@ -888,7 +888,12 @@ class AdminStatsControllerCore extends AdminStatsTabController case 'total_frequent_customers': $nbOrdersFrequentCustomers = Configuration::get('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS'); - $value = AdminStatsController::getTotalFrequentCustomers($nbOrdersFrequentCustomers, 0); + $value = AdminStatsController::getTotalFrequentCustomers( + date('Y-m-d', strtotime('-365 day')), + date('Y-m-d'), + $nbOrdersFrequentCustomers, + 0 + ); break; @@ -1829,7 +1834,7 @@ class AdminStatsControllerCore extends AdminStatsTabController return $result; } - public static function getTotalFrequentCustomers($nbOrders = 5, $idHotel = null) + public static function getTotalFrequentCustomers($dateFrom, $dateTo, $nbOrders = 5, $idHotel = null) { $sql = 'SELECT COUNT(t.`id_customer`) FROM ( @@ -1840,7 +1845,7 @@ class AdminStatsControllerCore extends AdminStatsTabController WHERE hbd.`id_order` = o.`id_order` LIMIT 1 ) AS id_hotel FROM `'._DB_PREFIX_.'orders` o - WHERE o.`valid` = 1 + WHERE o.`valid` = 1 AND o.`invoice_date` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" GROUP BY o.`id_customer` HAVING 1 '.(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel) : '').' ) AS t From e7bf671333fda0f7cc3cba41779c334362419cc7 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Fri, 31 May 2024 17:15:49 +0530 Subject: [PATCH 03/16] updated process of getting frequent customers and frequent customers filter --- controllers/admin/AdminCustomersController.php | 9 ++------- controllers/admin/AdminStatsController.php | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/controllers/admin/AdminCustomersController.php b/controllers/admin/AdminCustomersController.php index 206552a6a..6ca676e30 100644 --- a/controllers/admin/AdminCustomersController.php +++ b/controllers/admin/AdminCustomersController.php @@ -167,6 +167,7 @@ class AdminCustomersControllerCore extends AdminController 'date_add' => array( 'title' => $this->l('Registration'), 'type' => 'date', + 'filter_key' => 'a!date_add', 'align' => 'text-right' ), 'connect' => array( @@ -216,12 +217,6 @@ class AdminCustomersControllerCore extends AdminController $this->redirect_after = $this->context->link->getAdminLink('AdminCustomers'); } - if (Tools::getValue('frequent_customers')) { - $this->context->cookie->{'customerscustomerFilter_total_orders'} = json_encode(array(Configuration::get('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS'), '')); - $this->context->cookie->{'customerscustomerFilter_o!date_add'} = json_encode(array(date('Y-m-d', strtotime('-365 day')), date('Y-m-d'))); - $this->redirect_after = $this->context->link->getAdminLink('AdminCustomers'); - } - parent::postProcess(); } @@ -702,7 +697,7 @@ class AdminCustomersControllerCore extends AdminController $helper->color = 'color2'; $helper->title = $this->l('Total Frequent Customers', null, null, false); $helper->subtitle = $this->l('1 year', null, null, false); - $helper->href = $this->context->link->getAdminLink('AdminCustomers').'&frequent_customers=1'; + $helper->href = $this->context->link->getAdminLink('AdminCustomers').'&submitFiltercustomer=1&customerFilter_total_orders%5B0%5D='.Configuration::get('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS').'&customerFilter_o%21date_add%5B0%5D='.date('Y-m-d', strtotime('-365 day')).'&customerFilter_o%21date_add%5B1%5D='.date('Y-m-d'); $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_frequent_customers'; $helper->tooltip = $this->l('The total number of frequent customers in given period of time.', null, null, false); $kpis[] = $helper; diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php index 33d50d0f8..84bf64435 100644 --- a/controllers/admin/AdminStatsController.php +++ b/controllers/admin/AdminStatsController.php @@ -1845,7 +1845,7 @@ class AdminStatsControllerCore extends AdminStatsTabController WHERE hbd.`id_order` = o.`id_order` LIMIT 1 ) AS id_hotel FROM `'._DB_PREFIX_.'orders` o - WHERE o.`valid` = 1 AND o.`invoice_date` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" + WHERE o.`valid` = 1 AND o.`invoice_add` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" GROUP BY o.`id_customer` HAVING 1 '.(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel) : '').' ) AS t From b5925817de8741de4e41bb54a3392010a75fead6 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 8 Jun 2024 16:16:49 +0530 Subject: [PATCH 04/16] Fixed: Invoice data is not correct when multiple invoices created in an order --- classes/order/Order.php | 18 +++-- classes/order/OrderInvoice.php | 12 +-- classes/pdf/HTMLTemplateInvoice.php | 75 +++++++++++++------ controllers/admin/AdminOrdersController.php | 26 +++++-- .../classes/HotelBookingDemands.php | 30 +++++--- .../classes/HotelBookingDetail.php | 6 +- .../RoomTypeServiceProductOrderDetail.php | 7 +- 7 files changed, 125 insertions(+), 49 deletions(-) diff --git a/classes/order/Order.php b/classes/order/Order.php index 74fc0a450..5da28cfa7 100644 --- a/classes/order/Order.php +++ b/classes/order/Order.php @@ -602,13 +602,19 @@ class OrderCore extends ObjectModel $is_booking = null, $product_service_type = null, $product_auto_add = null, - $product_price_addition_type = null + $product_price_addition_type = null, + $ids_order_detail = [] ) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'order_detail` od LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.id_product = od.product_id) LEFT JOIN `'._DB_PREFIX_.'product_shop` ps ON (ps.id_product = p.id_product AND ps.id_shop = od.id_shop) WHERE od.`id_order` = '.(int)$this->id; + + if ($ids_order_detail) { + $sql .= ' AND od.`id_order_detail` IN ('.implode(',', $ids_order_detail).')'; + } + if ($is_booking !== null) { $sql .= ' AND od.`is_booking_product` = '. (int)$is_booking; if (!$is_booking && $product_service_type !== null) { @@ -1091,11 +1097,12 @@ class OrderCore extends ObjectModel $bookingProducts = null, $product_service_type = null, $product_auto_add = null, - $product_price_addition_type = null + $product_price_addition_type = null, + $ids_order_detail = [] ) { // update if (!$products) { - $products = $this->getProductsDetail($bookingProducts, $product_service_type, $product_auto_add, $product_price_addition_type); + $products = $this->getProductsDetail($bookingProducts, $product_service_type, $product_auto_add, $product_price_addition_type, $ids_order_detail); } $return = 0; @@ -1116,11 +1123,12 @@ class OrderCore extends ObjectModel $bookingProducts = null, $product_service_type = null, $product_auto_add = null, - $product_price_addition_type = null + $product_price_addition_type = null, + $ids_order_detail = [] ) { /* Retro-compatibility (now set directly on the validateOrder() method) */ if (!$products) { - $products = $this->getProductsDetail($bookingProducts, $product_service_type, $product_auto_add, $product_price_addition_type); + $products = $this->getProductsDetail($bookingProducts, $product_service_type, $product_auto_add, $product_price_addition_type, $ids_order_detail); } $return = 0; diff --git a/classes/order/OrderInvoice.php b/classes/order/OrderInvoice.php index b1f8d1ce9..ba07dbe72 100644 --- a/classes/order/OrderInvoice.php +++ b/classes/order/OrderInvoice.php @@ -413,7 +413,7 @@ class OrderInvoiceCore extends ObjectModel // - 'total_price_tax_excl' // - 'total_amount' $breakdown = array(); - $order_detail = $order->getOrderDetailList(); + $order_detail = $this->getProducts(); $order_detail = array_filter($order_detail, function($v) { return ($v['is_booking_product'] || ($v['product_auto_add'] @@ -482,7 +482,7 @@ class OrderInvoiceCore extends ObjectModel // - 'total_price_tax_excl' // - 'total_amount' $breakdown = array(); - $order_detail = $order->getOrderDetailList(); + $order_detail = $this->getProducts(); $order_detail = array_filter($order_detail, function($v) { return (!$v['is_booking_product'] && !$v['product_auto_add'] && $v['product_service_type'] == Product::SERVICE_PRODUCT_WITH_ROOMTYPE); }); @@ -546,7 +546,7 @@ class OrderInvoiceCore extends ObjectModel // - 'total_price_tax_excl' // - 'total_amount' $breakdown = array(); - $order_detail = $order->getOrderDetailList(); + $order_detail = $this->getProducts(); $order_detail = array_filter($order_detail, function($v) { return (!$v['is_booking_product'] && $v['product_auto_add'] @@ -616,7 +616,7 @@ class OrderInvoiceCore extends ObjectModel // - 'total_price_tax_excl' // - 'total_amount' $breakdown = array(); - $order_detail = $order->getOrderDetailList(); + $order_detail = $this->getProducts(); $order_detail = array_filter($order_detail, function($v) { return (!$v['is_booking_product'] && $v['product_service_type'] == Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); }); @@ -674,8 +674,10 @@ class OrderInvoiceCore extends ObjectModel $order = $this->getOrder(); } $breakdown = array(); + $order_details = $this->getProducts(); $objBookingDemand = new HotelBookingDemands(); - $details = $objBookingDemand->getExtraDemandsTaxesDetails($order->id); + $order_details = array_column($order_details, 'id_order_detail'); + $details = $objBookingDemand->getExtraDemandsTaxesDetails($order->id, $order_details); if (!$this->useOneAfterAnotherTaxComputationMethod()) { $grouped_details = array(); foreach ($details as $row) { diff --git a/classes/pdf/HTMLTemplateInvoice.php b/classes/pdf/HTMLTemplateInvoice.php index 3d28fca40..3dd144161 100644 --- a/classes/pdf/HTMLTemplateInvoice.php +++ b/classes/pdf/HTMLTemplateInvoice.php @@ -349,9 +349,9 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate if ($type_value) if (isset($customer->id)) { $cart_obj = new Cart($this->order->id_cart); - $order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, $cart_obj->id_guest, $type_value['product_id'], $customer->id); + $order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, $cart_obj->id_guest, $type_value['product_id'], $customer->id, $type_value['id_order_detail']); } else { - $order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, $customer->id_guest, $type_value['product_id']); + $order_bk_data = $obj_htl_bk_dtl->getOnlyOrderBookingData($this->order->id, $customer->id_guest, $type_value['product_id'], 0, $type_value['id_order_detail']); } $cart_htl_data[$type_key]['id_product'] = $type_value['product_id']; @@ -387,7 +387,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 0 + 0, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = $objBookingDemand->getRoomTypeBookingExtraDemands( $order_obj->id, @@ -397,7 +398,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 1 + 1, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_ti'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -410,7 +412,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 1, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM + Product::PRICE_ADDITION_TYPE_WITH_ROOM, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -423,7 +426,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 0, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM + Product::PRICE_ADDITION_TYPE_WITH_ROOM, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['num_rm'] += 1; @@ -457,7 +461,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 0 + 0, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['extra_demands_price_ti'] = $objBookingDemand->getRoomTypeBookingExtraDemands( $order_obj->id, @@ -467,7 +472,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 1 + 1, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -476,7 +482,12 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['id_product'], $data_v['date_from'], $data_v['date_to'], - 0 + 0, + 0, + null, + 0, + null, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( @@ -488,7 +499,10 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 1 + 1, + 0, + null, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -499,7 +513,10 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 0 + 0, + 0, + null, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_ti'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( @@ -513,7 +530,9 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 1, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM + Product::PRICE_ADDITION_TYPE_WITH_ROOM, + null, + $type_value['id_order_detail'] ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -526,7 +545,9 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 0, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM + Product::PRICE_ADDITION_TYPE_WITH_ROOM, + null, + $type_value['id_order_detail'] ); $num_days = $obj_htl_bk_dtl->getNumberOfDays($data_v['date_from'], $data_v['date_to']); @@ -555,7 +576,11 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $type_value['product_id'], $data_v['id_room'], $data_v['date_from'], - $data_v['date_to'] + $data_v['date_to'], + 1, + 0, + 1, + $type_value['id_order_detail'] )) { $extraDemands = array_shift($extraDemands); $extraDemands['product_id'] = $type_value['product_id']; @@ -572,7 +597,12 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $type_value['product_id'], $data_v['date_from'], $data_v['date_to'], - $data_v['id_room'] + $data_v['id_room'], + 0, + null, + 0, + null, + $type_value['id_order_detail'] )) { $additionalServices = array_shift($additionalServices); $additionalServices['product_id'] = $type_value['product_id']; @@ -610,14 +640,16 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $footer['total_extra_demands_te'] = $totalDemandsPriceTE; } } - $footer['room_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, true) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM); - $footer['room_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, true) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM); + + $idsOrderDetail = array_column($order_details, 'id_order_detail'); + $footer['room_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); + $footer['room_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); // $footer['service_products_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); // $footer['service_products_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); - $footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0) + $totalDemandsPriceTE; - $footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0) + $totalDemandsPriceTI; - $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT); - $footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT); + $footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTE; + $footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI; + $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); + $footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); $data = array( 'cart_htl_data' => $cart_htl_data, 'service_product_data' => $service_product_data, @@ -737,6 +769,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 'ecotax_tax' => $this->order_invoice->getEcoTaxTaxesBreakdown(), 'wrapping_tax' => $this->order_invoice->getWrappingTaxesBreakdown(), ); + foreach ($breakdowns as $type => $bd) { if (empty($bd)) { unset($breakdowns[$type]); diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index d56966e0c..c1b3a4592 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -6240,6 +6240,14 @@ class AdminOrdersControllerCore extends AdminController $res &= $objOrderDetail->update(); } + if ($objOrderDetail->id_order_invoice != 0) { + // values changes as values are calculated + $objOrderInvoice = new OrderInvoice($objOrderDetail->id_order_invoice); + $objOrderInvoice->total_paid_tax_excl -= $priceTaxExcl; + $objOrderInvoice->total_paid_tax_incl -= $priceTaxIncl; + $res &= $objOrderInvoice->update(); + } + $order->total_paid_tax_excl -= $priceTaxExcl; $order->total_paid_tax_incl -= $priceTaxIncl; $order->total_paid -= $priceTaxIncl; @@ -6272,6 +6280,9 @@ class AdminOrdersControllerCore extends AdminController // valiadate services being added if (Validate::isLoadedObject($objHotelBookingDetail = new HotelBookingDetail($idBookingDetail))) { $objOrder = new Order($objHotelBookingDetail->id_order); + $objOrderDetail = new OrderDetail($objHotelBookingDetail->id_order_detail); + $objOrderInvoice = new OrderInvoice($objOrderDetail->id_order_invoice); + // set context currency So that we can get prices in the order currency $this->context->currency = new Currency($objOrder->id_currency); @@ -6453,7 +6464,7 @@ class AdminOrdersControllerCore extends AdminController } $order_detail = new OrderDetail(); - $order_detail->createList($order, $cart, $order->getCurrentOrderState(), $productList, (isset($order_invoice) ? $order_invoice->id : 0), true); + $order_detail->createList($order, $cart, $order->getCurrentOrderState(), $productList, (isset($objOrderInvoice) ? $objOrderInvoice->id : 0), true); $objRoomTypeServiceProductOrderDetail = new RoomTypeServiceProductOrderDetail(); $objRoomTypeServiceProductOrderDetail->id_product = $product['id_product']; @@ -6477,16 +6488,18 @@ class AdminOrdersControllerCore extends AdminController $order->total_paid_tax_excl += Tools::ps_round((float)($totalPriceChangeTaxExcl), 2); $order->total_paid_tax_incl += Tools::ps_round((float)($totalPriceChangeTaxIncl), 2); - if (isset($order_invoice) && Validate::isLoadedObject($order_invoice)) { - $order->total_shipping = $order_invoice->total_shipping_tax_incl; - $order->total_shipping_tax_incl = $order_invoice->total_shipping_tax_incl; - $order->total_shipping_tax_excl = $order_invoice->total_shipping_tax_excl; + // update invoice total + if (isset($objOrderInvoice) && Validate::isLoadedObject($objOrderInvoice)) { + $objOrderInvoice->total_paid_tax_excl += Tools::ps_round((float)($totalPriceChangeTaxExcl), 2); + $objOrderInvoice->total_paid_tax_incl += Tools::ps_round((float)($totalPriceChangeTaxIncl), 2); + $objOrderInvoice->save(); } // discount $order->total_discounts += (float)abs($cart->getOrderTotal(true, Cart::ONLY_DISCOUNTS)); $order->total_discounts_tax_excl += (float)abs($cart->getOrderTotal(false, Cart::ONLY_DISCOUNTS)); $order->total_discounts_tax_incl += (float)abs($cart->getOrderTotal(true, Cart::ONLY_DISCOUNTS)); + // Save changes of order $order->update(); if (Validate::isLoadedObject($specific_price)) { @@ -6685,8 +6698,9 @@ class AdminOrdersControllerCore extends AdminController $order_invoice = new OrderInvoice($order_detail->id_order_invoice); $order_invoice->total_paid_tax_excl += $priceDiffTaxExcl; $order_invoice->total_paid_tax_incl += $priceDiffTaxIncl; - $res &= $order_invoice->update(); + $order_invoice->update(); } + $order = new Order($objBookingDetail->id_order); $order->total_paid_tax_excl += $priceDiffTaxExcl; $order->total_paid_tax_incl += $priceDiffTaxIncl; diff --git a/modules/hotelreservationsystem/classes/HotelBookingDemands.php b/modules/hotelreservationsystem/classes/HotelBookingDemands.php index 8b98d69f4..c105907ea 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDemands.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDemands.php @@ -74,7 +74,8 @@ class HotelBookingDemands extends ObjectModel $dateTo = 0, $groupByRoom = 1, $getTotalPrice = 0, - $useTax = 1 + $useTax = 1, + $idOrderDetail = 0 ) { $moduleObj = Module::getInstanceByName('hotelreservationsystem'); $context = Context::getContext(); @@ -91,6 +92,10 @@ class HotelBookingDemands extends ObjectModel WHERE hd.`id_htl_booking` IN (SELECT `id` FROM `'._DB_PREFIX_.'htl_booking_detail` WHERE `id_order`='.(int) $idOrder; + + if ($idOrderDetail) { + $sql .= ' AND `id_order_detail`='.(int)$idOrderDetail; + } if ($idProduct) { $sql .= ' AND `id_product`='.(int)$idProduct; } @@ -247,16 +252,21 @@ class HotelBookingDemands extends ObjectModel || Configuration::get('PS_INVOICE_TAXES_BREAKDOWN'); } - public function getExtraDemandsTaxesDetails($idOrder) + public function getExtraDemandsTaxesDetails($idOrder, $idsOrderDetail = []) { - $taxDetails = Db::getInstance()->executeS( - 'SELECT hb.`id` as id_htl_booking, hbd.`unit_price_tax_excl`, hbd.`total_price_tax_excl`, hb.`id_order_detail`, hdt.*, t.* FROM '._DB_PREFIX_.'orders o '. - 'INNER JOIN '._DB_PREFIX_.'htl_booking_detail hb ON hb.id_order = o.id_order '. - 'INNER JOIN '._DB_PREFIX_.'htl_booking_demands hbd ON hbd.id_htl_booking = hb.id '. - 'INNER JOIN '._DB_PREFIX_.'htl_booking_demands_tax hdt ON hbd.id_booking_demand = hdt.id_booking_demand '. - 'INNER JOIN '._DB_PREFIX_.'tax t ON t.id_tax = hdt.id_tax '. - 'WHERE o.id_order = '.(int)$idOrder - ); + $sql = 'SELECT hb.`id` as id_htl_booking, hbd.`unit_price_tax_excl`, hbd.`total_price_tax_excl`, hb.`id_order_detail`, hdt.*, t.* FROM '._DB_PREFIX_.'orders o '. + 'INNER JOIN '._DB_PREFIX_.'htl_booking_detail hb ON hb.id_order = o.id_order '. + 'INNER JOIN '._DB_PREFIX_.'htl_booking_demands hbd ON hbd.id_htl_booking = hb.id '. + 'INNER JOIN '._DB_PREFIX_.'htl_booking_demands_tax hdt ON hbd.id_booking_demand = hdt.id_booking_demand '. + 'INNER JOIN '._DB_PREFIX_.'tax t ON t.id_tax = hdt.id_tax '. + 'WHERE o.id_order = '.(int)$idOrder; + + if ($idsOrderDetail) { + $sql .= ' AND hb.`id_order_detail` IN ('.implode(',', $idsOrderDetail).')'; + } + + $taxDetails = Db::getInstance()->executeS($sql); + if ($taxDetails) { foreach ($taxDetails as &$detail) { $priceTaxExcl = $detail['unit_price_tax_excl']; diff --git a/modules/hotelreservationsystem/classes/HotelBookingDetail.php b/modules/hotelreservationsystem/classes/HotelBookingDetail.php index 047e1de46..4240baaa8 100644 --- a/modules/hotelreservationsystem/classes/HotelBookingDetail.php +++ b/modules/hotelreservationsystem/classes/HotelBookingDetail.php @@ -2242,13 +2242,17 @@ class HotelBookingDetail extends ObjectModel * @param int $id_customer [description] * @return [type] [description] */ - public function getOnlyOrderBookingData($id_order, $id_guest, $id_product, $id_customer = 0) + public function getOnlyOrderBookingData($id_order, $id_guest, $id_product, $id_customer = 0, $id_order_detail = 0) { $sql = 'SELECT hbd.*, od.`unit_price_tax_incl`, od.`unit_price_tax_excl`, od.`reduction_amount_tax_excl`, od.`reduction_amount_tax_incl` FROM `'._DB_PREFIX_.'htl_booking_detail` hbd INNER JOIN `'._DB_PREFIX_.'order_detail` od ON (od.`id_order_detail` = hbd.`id_order_detail`) WHERE hbd.`id_order` = '.(int)$id_order.' AND hbd.`id_product` = '.(int)$id_product; + if ($id_order_detail) { + $sql .= ' AND hbd.`id_order_detail` = '.(int)$id_order_detail; + } + if ($id_customer) { $sql .= ' AND hbd.`id_customer` = '.(int)$id_customer; } diff --git a/modules/hotelreservationsystem/classes/RoomTypeServiceProductOrderDetail.php b/modules/hotelreservationsystem/classes/RoomTypeServiceProductOrderDetail.php index b26cf751d..949e93dc8 100644 --- a/modules/hotelreservationsystem/classes/RoomTypeServiceProductOrderDetail.php +++ b/modules/hotelreservationsystem/classes/RoomTypeServiceProductOrderDetail.php @@ -68,7 +68,8 @@ class RoomTypeServiceProductOrderDetail extends ObjectModel $getTotalPrice = 0, $useTax = null, $autoAddToCart = 0, - $priceAdditionType = null + $priceAdditionType = null, + $idOrderDetail = 0 ) { if ($useTax === null) { @@ -85,6 +86,10 @@ class RoomTypeServiceProductOrderDetail extends ObjectModel $sql .= ' LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON(od.`id_order_detail` = rsod.`id_order_detail`)'; $sql .= ' WHERE rsod.`id_order` = '.(int)$idOrder; + if ($idOrderDetail) { + $sql .= ' AND rsod.`id_order_detail` = '.(int)$idOrderDetail; + } + if (!is_null($autoAddToCart)) { $sql .= ' AND od.`product_auto_add` = '. (int)$autoAddToCart; if ($autoAddToCart == 1 && !is_null($priceAdditionType)) { From 0f4abcaeb4a216bcbe4bc4e42468958b590c7a74 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 8 Jun 2024 17:12:48 +0530 Subject: [PATCH 05/16] Total Invoice Payment for Order and Due amount is calculated for the specific invoice --- classes/order/OrderInvoice.php | 2 +- classes/pdf/HTMLTemplateInvoice.php | 2 ++ config/defines.inc.php | 2 +- pdf/invoice.total-tab.tpl | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/classes/order/OrderInvoice.php b/classes/order/OrderInvoice.php index ba07dbe72..509d77d3b 100644 --- a/classes/order/OrderInvoice.php +++ b/classes/order/OrderInvoice.php @@ -1015,7 +1015,7 @@ class OrderInvoiceCore extends ObjectModel $payments = OrderPaymentDetail::getByInvoiceId($this->id); foreach ($payments as $payment) { /** @var OrderPayment $payment */ - $amount += $payment['amount']; + $amount += ($payment['amount'] / $payment['conversion_rate']); } Cache::store($cache_id, $amount); return $amount; diff --git a/classes/pdf/HTMLTemplateInvoice.php b/classes/pdf/HTMLTemplateInvoice.php index 3dd144161..c071404f0 100644 --- a/classes/pdf/HTMLTemplateInvoice.php +++ b/classes/pdf/HTMLTemplateInvoice.php @@ -650,6 +650,8 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI; $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); $footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); + $footer['total_paid_real'] = $this->order_invoice->getTotalPaid(); + $data = array( 'cart_htl_data' => $cart_htl_data, 'service_product_data' => $service_product_data, diff --git a/config/defines.inc.php b/config/defines.inc.php index 4a86b1930..3e319225f 100644 --- a/config/defines.inc.php +++ b/config/defines.inc.php @@ -26,7 +26,7 @@ /* Debug only */ if (!defined('_PS_MODE_DEV_')) { - define('_PS_MODE_DEV_', false); + define('_PS_MODE_DEV_', true); } /* Compatibility warning */ define('_PS_DISPLAY_COMPATIBILITY_WARNING_', false); diff --git a/pdf/invoice.total-tab.tpl b/pdf/invoice.total-tab.tpl index 2f70c1267..4de340a56 100644 --- a/pdf/invoice.total-tab.tpl +++ b/pdf/invoice.total-tab.tpl @@ -138,7 +138,7 @@ {l s='Due Amount' pdf='true'} - {displayPrice currency=$order->id_currency price=($order->total_paid - $order->total_paid_real)} + {displayPrice currency=$order->id_currency price=($footer.total_paid_tax_incl - $footer.total_paid_real)} {/if} From adbc64d68e7bd24fe68d690f431011c43a7fc651 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 8 Jun 2024 17:13:33 +0530 Subject: [PATCH 06/16] Debug mode value is set to false --- config/defines.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/defines.inc.php b/config/defines.inc.php index 3e319225f..4a86b1930 100644 --- a/config/defines.inc.php +++ b/config/defines.inc.php @@ -26,7 +26,7 @@ /* Debug only */ if (!defined('_PS_MODE_DEV_')) { - define('_PS_MODE_DEV_', true); + define('_PS_MODE_DEV_', false); } /* Compatibility warning */ define('_PS_DISPLAY_COMPATIBILITY_WARNING_', false); From 600f4d5b6734dac862630c5bb1aaa263c7f1aff5 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Mon, 1 Jul 2024 20:34:24 +0530 Subject: [PATCH 07/16] Fixed: Wrong prices in total if invoice has no rooms --- classes/pdf/HTMLTemplateInvoice.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/classes/pdf/HTMLTemplateInvoice.php b/classes/pdf/HTMLTemplateInvoice.php index c071404f0..64739a769 100644 --- a/classes/pdf/HTMLTemplateInvoice.php +++ b/classes/pdf/HTMLTemplateInvoice.php @@ -641,15 +641,22 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate } } - $idsOrderDetail = array_column($order_details, 'id_order_detail'); - $footer['room_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); - $footer['room_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); - // $footer['service_products_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); - // $footer['service_products_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); - $footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTE; - $footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI; - $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); - $footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); + $footer['room_price_tax_excl'] = 0; + $footer['room_price_tax_incl'] = 0; + $footer['additional_service_price_tax_excl'] = 0; + $footer['additional_service_price_tax_incl'] =0; + $footer['total_convenience_fee_te'] = 0; + $footer['total_convenience_fee_ti'] = 0; + if ($idsOrderDetail = array_column($order_details, 'id_order_detail')) { + $footer['room_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); + $footer['room_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, true, null, null, null, $idsOrderDetail) + $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_WITH_ROOM, $idsOrderDetail); + // $footer['service_products_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); + // $footer['service_products_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITHOUT_ROOMTYPE); + $footer['additional_service_price_tax_excl'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTE; + $footer['additional_service_price_tax_incl'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 0, null, $idsOrderDetail) + $totalDemandsPriceTI; + $footer['total_convenience_fee_te'] = $this->order->getTotalProductsWithoutTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); + $footer['total_convenience_fee_ti'] = $this->order->getTotalProductsWithTaxes(false, false, Product::SERVICE_PRODUCT_WITH_ROOMTYPE, 1, Product::PRICE_ADDITION_TYPE_INDEPENDENT, $idsOrderDetail); + } $footer['total_paid_real'] = $this->order_invoice->getTotalPaid(); $data = array( From d8758dd6afdcec50fedeea1908e1a24e5cd44ba3 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Tue, 2 Jul 2024 19:07:06 +0530 Subject: [PATCH 08/16] Fixed: Services are not showing in the invoices --- classes/pdf/HTMLTemplateInvoice.php | 44 ++++++----------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/classes/pdf/HTMLTemplateInvoice.php b/classes/pdf/HTMLTemplateInvoice.php index 64739a769..c394da36a 100644 --- a/classes/pdf/HTMLTemplateInvoice.php +++ b/classes/pdf/HTMLTemplateInvoice.php @@ -412,8 +412,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 1, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM, - $type_value['id_order_detail'] + Product::PRICE_ADDITION_TYPE_WITH_ROOM ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -426,8 +425,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 0, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM, - $type_value['id_order_detail'] + Product::PRICE_ADDITION_TYPE_WITH_ROOM ); $cart_htl_data[$type_key]['date_diff'][$date_join]['num_rm'] += 1; @@ -482,12 +480,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['id_product'], $data_v['date_from'], $data_v['date_to'], - 0, - 0, - null, - 0, - null, - $type_value['id_order_detail'] + 0 ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_ti'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( @@ -499,10 +492,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 1, - 0, - null, - $type_value['id_order_detail'] + 1 ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -513,10 +503,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $data_v['date_to'], 0, 1, - 0, - 0, - null, - $type_value['id_order_detail'] + 0 ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_ti'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( @@ -530,9 +517,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 1, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM, - null, - $type_value['id_order_detail'] + Product::PRICE_ADDITION_TYPE_WITH_ROOM ); $cart_htl_data[$type_key]['date_diff'][$date_join]['additional_services_price_auto_add_te'] = $objRoomTypeServiceProductOrderDetail->getroomTypeServiceProducts( $order_obj->id, @@ -545,9 +530,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate 1, 0, 1, - Product::PRICE_ADDITION_TYPE_WITH_ROOM, - null, - $type_value['id_order_detail'] + Product::PRICE_ADDITION_TYPE_WITH_ROOM ); $num_days = $obj_htl_bk_dtl->getNumberOfDays($data_v['date_from'], $data_v['date_to']); @@ -576,11 +559,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $type_value['product_id'], $data_v['id_room'], $data_v['date_from'], - $data_v['date_to'], - 1, - 0, - 1, - $type_value['id_order_detail'] + $data_v['date_to'] )) { $extraDemands = array_shift($extraDemands); $extraDemands['product_id'] = $type_value['product_id']; @@ -597,12 +576,7 @@ class HTMLTemplateInvoiceCore extends HTMLTemplate $type_value['product_id'], $data_v['date_from'], $data_v['date_to'], - $data_v['id_room'], - 0, - null, - 0, - null, - $type_value['id_order_detail'] + $data_v['id_room'] )) { $additionalServices = array_shift($additionalServices); $additionalServices['product_id'] = $type_value['product_id']; From d1cc65372222c4bcdb7aaf2cc079f98f24870e64 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Thu, 4 Jul 2024 14:56:05 +0530 Subject: [PATCH 09/16] updated date interval reference from order date to invoice date --- controllers/admin/AdminStatsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php index 96547781f..926e29a97 100644 --- a/controllers/admin/AdminStatsController.php +++ b/controllers/admin/AdminStatsController.php @@ -1851,7 +1851,7 @@ class AdminStatsControllerCore extends AdminStatsTabController WHERE hbd.`id_order` = o.`id_order` LIMIT 1 ) AS id_hotel FROM `'._DB_PREFIX_.'orders` o - WHERE o.`valid` = 1 AND o.`invoice_add` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" + WHERE o.`valid` = 1 AND o.`invoice_date` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" GROUP BY o.`id_customer` HAVING 1 '.(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel) : '').' ) AS t From 14792dbe66baaa1698bf074a14896f840e5c31eb Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Tue, 9 Jul 2024 14:48:12 +0530 Subject: [PATCH 10/16] Added: option to add/edit customer address from order detail page of BO --- .../controllers/orders/helpers/view/view.tpl | 29 +++++++++++++++++++ controllers/admin/AdminOrdersController.php | 7 +++++ js/admin/orders.js | 16 ++++++++++ 3 files changed, 52 insertions(+) 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 8c026b68b..cc8e561d0 100644 --- a/admin/themes/default/template/controllers/orders/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/orders/helpers/view/view.tpl @@ -749,6 +749,35 @@ +
+
+  {l s='Guest Address'} + {if $can_edit} + {if $idGuestAddress} + + {l s='Edit'} + + {else} + + {l s='Add Address'} + + {/if} + {/if} +
+
+ {if $guestFormatedAddress} + {$guestFormatedAddress} + {else} +
+
+ + {l s='Guest address not found.'} +
+
+ {/if} +
+
+ {* Order Internal notes *} {if (sizeof($messages))}
diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index 0c0af163a..56580527f 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -2853,7 +2853,14 @@ class AdminOrdersControllerCore extends AdminController // Overbookings information of the order $orderOverBookings = $objHotelBookingDetail->getOverbookedRooms($order->id, 0, '', '', 0, 0, 1); + // Guest address info + $guestFormatedAddress = ''; + if ($idGuestAddress = Customer::getCustomerIdAddress($order->id_customer)) { + $guestFormatedAddress = AddressFormat::generateAddress(new Address($idGuestAddress), array(), "
"); + } $this->tpl_view_vars = array( + 'guestFormatedAddress' => $guestFormatedAddress, + 'idGuestAddress' => $idGuestAddress, 'totalRefundedRooms' => $totalRefundedRooms, 'orderOverBookings' => $orderOverBookings, 'refund_allowed' => (int) $order->isReturnable(), diff --git a/js/admin/orders.js b/js/admin/orders.js index ae5dd844a..16e1331bd 100644 --- a/js/admin/orders.js +++ b/js/admin/orders.js @@ -1232,7 +1232,23 @@ function setRoomTypeGuestOccupancy(booking_occupancy_wrapper) /* Refund system script */ var flagRefund = ''; +// when submit from ajax from guest address controller the function will be called from the controller header +function getSummary() +{ + return; +} + $(document).ready(function() { + // when click edit/add guest address we have to initialize fancybox + $('.fancybox').fancybox({ + 'type': 'iframe', + 'width': '90%', + 'height': '90%', + afterClose: function() { + location.reload(); + }, + }); + // when change order state to cancel or refund then show modal of bookings cancellation $(document).on('change', '#id_order_state', function(e) { if ($(this).val() == PS_OS_CANCELED || $(this).val() == PS_OS_REFUND) { From 14e2592fe1f8fec575a76604c1a6ab3f5b274f23 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Thu, 11 Jul 2024 13:23:15 +0530 Subject: [PATCH 11/16] update get frequest customer accoding to order date instead of invoice date --- controllers/admin/AdminStatsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/admin/AdminStatsController.php b/controllers/admin/AdminStatsController.php index 926e29a97..7a9510ffa 100644 --- a/controllers/admin/AdminStatsController.php +++ b/controllers/admin/AdminStatsController.php @@ -1851,7 +1851,7 @@ class AdminStatsControllerCore extends AdminStatsTabController WHERE hbd.`id_order` = o.`id_order` LIMIT 1 ) AS id_hotel FROM `'._DB_PREFIX_.'orders` o - WHERE o.`valid` = 1 AND o.`invoice_date` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" + WHERE o.`valid` = 1 AND o.`date_add` BETWEEN "'.pSQL($dateFrom).' 00:00:00" AND "'.pSQL($dateTo).' 23:59:59" GROUP BY o.`id_customer` HAVING 1 '.(!is_null($idHotel) ? HotelBranchInformation::addHotelRestriction($idHotel) : '').' ) AS t From c39b97d4086ce517389799df03b023eb70555c67 Mon Sep 17 00:00:00 2001 From: Shreesh Arora Date: Fri, 19 Jul 2024 15:40:41 +0530 Subject: [PATCH 12/16] fix num orders for frequent customers can be set to 0 --- .../admin/AdminCustomerPreferencesController.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/controllers/admin/AdminCustomerPreferencesController.php b/controllers/admin/AdminCustomerPreferencesController.php index 5f81339a4..c9677499a 100644 --- a/controllers/admin/AdminCustomerPreferencesController.php +++ b/controllers/admin/AdminCustomerPreferencesController.php @@ -133,7 +133,7 @@ class AdminCustomerPreferencesControllerCore extends AdminController 'PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS' => array( 'title' => $this->l('Number of orders to use to calculate frequent customers'), 'hint' => $this->l('Set the number of orders to use to calculate frequent customers.'), - 'validation' => 'isUnsignedInt', + 'validation' => 'isInt', 'cast' => 'intval', 'type' => 'text', 'class' => 'fixed-width-xxl', @@ -173,6 +173,14 @@ class AdminCustomerPreferencesControllerCore extends AdminController ); } + public function beforeUpdateOptions() + { + $fieldData = $this->fields_options['customer_kpi']['fields']['PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS']; + if (!Tools::getValue('PS_KPI_FREQUENT_CUSTOMER_NB_ORDERS')) { + $this->errors[] = sprintf(Tools::displayError('field %s must be greater than 0.'), $fieldData['title']);; + } + } + /** * Update PS_B2B_ENABLE and enables / disables the associated tabs * @param $value integer Value of option From 26703f77706193e5e5435e80aae64a6356d4363b Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 27 Jul 2024 15:52:21 +0530 Subject: [PATCH 13/16] Added: Panel to add/update customer address from order detail page of Back office --- .../default/sass/controllers/_order.sass | 13 ++ .../controllers/orders/helpers/view/view.tpl | 165 ++++-------------- classes/Address.php | 46 ++++- classes/order/Order.php | 21 ++- .../admin/AdminAddressesController.php | 18 +- controllers/admin/AdminOrdersController.php | 108 +++++++++++- 6 files changed, 217 insertions(+), 154 deletions(-) diff --git a/admin/themes/default/sass/controllers/_order.sass b/admin/themes/default/sass/controllers/_order.sass index c5315218e..773defb8c 100644 --- a/admin/themes/default/sass/controllers/_order.sass +++ b/admin/themes/default/sass/controllers/_order.sass @@ -77,3 +77,16 @@ .room_status_info_form .room_status white-space: normal + +.panel-guest_address + .panel-heading + align-items: center + display: flex + gap: 10px + justify-content: space-between + .panel-title + width: 100% + .dropdown-menu + right: 0 + left: unset + font-size: 14px 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 cc8e561d0..4fcd07c15 100644 --- a/admin/themes/default/template/controllers/orders/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/orders/helpers/view/view.tpl @@ -625,148 +625,51 @@
{/if} - - - -
+
-  {l s='Guest Address'} +  {l s='Guest Address'} {if $can_edit} - {if $idGuestAddress} - + {if $idOrderAddressInvoice} + + {if (!$idCurrentAddress || ($idCurrentAddress != $idOrderAddressInvoice)) || $ordersWithDiffInvAddr} + + {/if} {else} - + + {if $idCurrentAddress} + + {/if} {/if} {/if}
- {if $guestFormatedAddress} - {$guestFormatedAddress} + {if $guestFormattedAddress} + {$guestFormattedAddress} {else}
diff --git a/classes/Address.php b/classes/Address.php index 10c3cf0c4..f6d82e8ad 100644 --- a/classes/Address.php +++ b/classes/Address.php @@ -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, false)) { + if ($this->deleted == 0 && $id_address = Customer::getCustomerIdAddress($this->id_customer, false)) { return false; } } @@ -196,6 +196,8 @@ class AddressCore extends ObjectModel public function update($null_values = false) { + + $context = Context::getContext(); // Empty related caches if (isset(self::$_idCountries[$this->id])) { unset(self::$_idCountries[$this->id]); @@ -208,9 +210,42 @@ class AddressCore extends ObjectModel Customer::resetAddressCache($this->id_customer, $this->id); } + // If address is already used in any order, it will not be edited directly, set address to "deleted" and create a new address + if ($this->isUsed() && $this->deleted == 0) { + return $this->updateUsedAddress($this); + } + return parent::update($null_values); } + /** + * If address is already used in any order + * set address to "deleted" and create a new address + * @param Address $address + * @return bool + */ + public function updateUsedAddress(Address $address) + { + $objOldAddress = new Address($address->id); + $address->id = $address->id_address = null; + + if ($objOldAddress->delete() && $address->save()) { + // we need to change the address id in the current cart as the deleted ID can assigned in context->cart. + if ($customerCarts = Cart::getCustomerCarts($objOldAddress->id_customer, false)) { + foreach ($customerCarts as $cart) { + $objCart = new Cart($cart['id_cart']); + if ($cart['id_address_invoice'] == $objOldAddress->id) { + $objCart->updateAddressId($objOldAddress->id, $address->id); + } + } + } + + return true; + } + + return false; + } + /** * @see ObjectModel::delete() */ @@ -222,12 +257,12 @@ class AddressCore extends ObjectModel // reset checkout process if addresses deletes CheckoutProcess::refreshCheckoutProcess(); - if (!$this->isUsed()) { - return parent::delete(); - } else { + if ($this->isUsed()) { $this->deleted = true; return $this->update(); } + + return parent::delete(); } /** @@ -252,10 +287,9 @@ class AddressCore extends ObjectModel // for customer address we need to check of customer address already exists. // if we are editing an address we do not need to validate already created address. - if (!Validate::isLoadedObject($this)) { + if (!Validate::isLoadedObject($this) && $this->deleted != 0) { if ($idCustomer = Tools::getValue('id_customer')) { if ($id_address = Customer::getCustomerIdAddress($idCustomer)) { - $errors[] = sprintf(Tools::displayError('Customer address already exists. Id address: #%d'), $id_address); } } diff --git a/classes/order/Order.php b/classes/order/Order.php index 72e19deff..d6393d07e 100644 --- a/classes/order/Order.php +++ b/classes/order/Order.php @@ -954,21 +954,30 @@ class OrderCore extends ObjectModel * * @param int $id_customer Customer id * @param bool $show_hidden_status Display or not hidden order statuses + * @param bool $skip_id_address_invoice Skip orders from this id_address_invoice * @return array Customer orders */ - public static function getCustomerOrders($id_customer, $show_hidden_status = false, Context $context = null) + public static function getCustomerOrders($id_customer, $show_hidden_status = false, Context $context = null, $id_address_invoice = null, $skip_address = 0) { if (!$context) { $context = Context::getContext(); } - $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' - SELECT o.*, (SELECT SUM(od.`product_quantity`) FROM `'._DB_PREFIX_.'order_detail` od WHERE od.`id_order` = o.`id_order`) nb_products + $sql = 'SELECT o.*, (SELECT SUM(od.`product_quantity`) FROM `'._DB_PREFIX_.'order_detail` od WHERE od.`id_order` = o.`id_order`) nb_products FROM `'._DB_PREFIX_.'orders` o - WHERE o.`id_customer` = '.(int)$id_customer. - Shop::addSqlRestriction(Shop::SHARE_ORDER).' + WHERE o.`id_customer` = '.(int)$id_customer; + + // if you want orders from / not from a specific id_address_invoice + if (!is_null($id_address_invoice)) { + $sql .= ' AND o.`id_address_invoice`'; + $sql .= ($skip_address ? ' != ' : ' = ').(int)$id_address_invoice; + } + + $sql .= Shop::addSqlRestriction(Shop::SHARE_ORDER).' GROUP BY o.`id_order` - ORDER BY o.`date_add` DESC'); + ORDER BY o.`date_add` DESC'; + + $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); if (!$res) { return array(); } diff --git a/controllers/admin/AdminAddressesController.php b/controllers/admin/AdminAddressesController.php index 83a646cb6..8e2b334e3 100644 --- a/controllers/admin/AdminAddressesController.php +++ b/controllers/admin/AdminAddressesController.php @@ -430,10 +430,8 @@ class AdminAddressesControllerCore extends AdminController ** we delete its id_address to force the creation of a new one */ if ((int)Tools::getValue('id_order')) { $this->_redirect = false; - if (isset($_POST['address_type'])) { - $_POST['id_address'] = ''; - $this->id_object = null; - } + // set deleted=1 as customer can have only one address and this address is for an order only + $_POST['deleted'] = 1; } // Check the requires fields which are settings in the BO @@ -454,10 +452,18 @@ class AdminAddressesControllerCore extends AdminController if ($this->action == 'save' && ($id_order = (int)Tools::getValue('id_order')) && !count($this->errors) && !empty($address_type)) { if (!Db::getInstance()->Execute('UPDATE '._DB_PREFIX_.'orders SET `id_address_'.bqSQL($address_type).'` = '.(int)$this->object->id.' WHERE `id_order` = '.(int)$id_order)) { $this->errors[] = Tools::displayError('An error occurred while linking this address to its order.'); - } else { - Tools::redirectAdmin(urldecode(Tools::getValue('back')).'&conf=4'); } } + + // in case of save and stay, redirect after save with current address. + // Because the current address can not be same as the current one(We have to delete it and create a new one in case address is used in orders) + if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { + $idCurrentAddress = Customer::getCustomerIdAddress($this->object->id_customer, false); + if ($idCurrentAddress != $this->object->id) { + $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$idCurrentAddress.'&conf=4&update'.$this->table.'&token='.$this->token; + } + } + return $return; } diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index 56580527f..38d067b6e 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -2236,6 +2236,91 @@ class AdminOrdersControllerCore extends AdminController } else { $this->errors = Tools::displayError('An error occurred while resolving overbooking.'); } + // Set old orders address as current order address + } elseif (Tools::getValue('action') && Tools::getValue('action') == 'set_old_orders_address') { + if ($idOrder = Tools::getValue('id_order')) { + if (Validate::isLoadedObject($objOrder = new Order($idOrder))) { + $idAddressInvoice = $objOrder->id_address_invoice; + if ($idAddressInvoice && Validate::isLoadedObject(new Address($idAddressInvoice))) { + // get all customer orders and set old orders address as current order address + if ($customerOrders = Order::getCustomerOrders($objOrder->id_customer)) { + foreach ($customerOrders as $order) { + $objOrder = new Order($order['id_order']); + $objOrder->id_address_invoice = $idAddressInvoice; + $objOrder->update(); + } + } + Tools::redirectAdmin(self::$currentIndex.'&id_order='.$idOrder.'&vieworder&conf=6&token='.$this->token); + } else { + $this->errors = Tools::displayError('Address not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } + // Set customer current active address as current order address + } elseif (Tools::getValue('action') && Tools::getValue('action') == 'set_address_current_address') { + if ($idOrder = Tools::getValue('id_order')) { + if (Validate::isLoadedObject($objOrder = new Order($idOrder))) { + $idAddressInvoice = $objOrder->id_address_invoice; + if ($idAddressInvoice && Validate::isLoadedObject($objOrderAddress = new Address($idAddressInvoice))) { + $updateAddress = 1; + if ($idCustomerAddress = Customer::getCustomerIdAddress($objOrder->id_customer)) { + // only proceed if current active address and current order address are different + if ($idCustomerAddress != $idAddressInvoice) { + if (Validate::isLoadedObject($objActiveAddress = new Address($idCustomerAddress))) { + // Call delete as it will manage to delete current active address if it has no orders associated + // else it will just update deleted = 1 to the current active address + $objActiveAddress->delete(); + } else { + $this->errors = Tools::displayError('Guest address not found. Please try again.'); + } + } else { + // if current active address and current order address are same then no need to update + $updateAddress = 0; + } + } + + if ($updateAddress && !count($this->errors)) { + // set current order address as current active address + $objOrderAddress->deleted = 0; + if ($objOrderAddress->update()) { + Tools::redirectAdmin(self::$currentIndex.'&id_order='.$idOrder.'&vieworder&conf=6&token='.$this->token); + } else { + $this->errors = Tools::displayError('Some error occurred while updating address detail. Please try again.'); + } + } + } else { + $this->errors = Tools::displayError('Address not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } + } elseif (Tools::getValue('action') && Tools::getValue('action') == 'set_order_active_address') { + if ($idOrder = Tools::getValue('id_order')) { + if (Validate::isLoadedObject($objOrder = new Order($idOrder))) { + // get currenct active address of the customer + if ($idCustomerAddress = Customer::getCustomerIdAddress($objOrder->id_customer)) { + $objOrder->id_address_invoice = $idCustomerAddress; + if ($objOrder->update()) { + Tools::redirectAdmin(self::$currentIndex.'&id_order='.$idOrder.'&vieworder&conf=6&token='.$this->token); + } else { + $this->errors[] = Tools::displayError('Some error occurred while updating address detail. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Guest address not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } + } else { + $this->errors = Tools::displayError('Order not found. Please try again.'); + } } // Sending loader image for the modals to be used for all the modals ajax processes @@ -2854,13 +2939,26 @@ class AdminOrdersControllerCore extends AdminController $orderOverBookings = $objHotelBookingDetail->getOverbookedRooms($order->id, 0, '', '', 0, 0, 1); // Guest address info - $guestFormatedAddress = ''; - if ($idGuestAddress = Customer::getCustomerIdAddress($order->id_customer)) { - $guestFormatedAddress = AddressFormat::generateAddress(new Address($idGuestAddress), array(), "
"); + $guestFormattedAddress = ''; + $idOrderAddressInvoice = 0; + $ordersWithDiffInvAddr = 0; + $idCurrentAddress = Customer::getCustomerIdAddress($order->id_customer); + if ($order->id_address_invoice && Validate::isLoadedObject($objGuestAddress = new Address($order->id_address_invoice))) { + $idOrderAddressInvoice = $order->id_address_invoice; + $guestFormattedAddress = AddressFormat::generateAddress($objGuestAddress, array(), "
"); + + // get customer orders without same id_address_invoice + if ($customerOrders = Order::getCustomerOrders($order->id_customer, false, null, $idOrderAddressInvoice, 1)) { + if ($customerOrders > 1) { + $ordersWithDiffInvAddr = 1; + } + } } $this->tpl_view_vars = array( - 'guestFormatedAddress' => $guestFormatedAddress, - 'idGuestAddress' => $idGuestAddress, + 'guestFormattedAddress' => $guestFormattedAddress, + 'idOrderAddressInvoice' => $idOrderAddressInvoice, + 'ordersWithDiffInvAddr' => $ordersWithDiffInvAddr, + 'idCurrentAddress' => $idCurrentAddress, 'totalRefundedRooms' => $totalRefundedRooms, 'orderOverBookings' => $orderOverBookings, 'refund_allowed' => (int) $order->isReturnable(), From dfaf5c3fc9656edde4cc095d63febd16ad535773 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Tue, 30 Jul 2024 13:23:01 +0530 Subject: [PATCH 14/16] Fixed: Undefined indexes issues on GuestTracking Controller --- controllers/front/GuestTrackingController.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/controllers/front/GuestTrackingController.php b/controllers/front/GuestTrackingController.php index 79ec067c2..f43014df8 100644 --- a/controllers/front/GuestTrackingController.php +++ b/controllers/front/GuestTrackingController.php @@ -250,6 +250,9 @@ class GuestTrackingControllerCore extends FrontController $total_convenience_fee_te = 0; $total_convenience_fee_ti = 0; + $objOrderReturn = new OrderReturn(); + $refundReqBookings = $objOrderReturn->getOrderRefundRequestedBookings($order->id, 0, 1); + foreach ($orderProducts as $type_key => $type_value) { if (in_array($type_value['product_id'], $processedProducts)) { continue; @@ -307,6 +310,14 @@ class GuestTrackingControllerCore extends FrontController if ($data_v['is_back_order']) { $anyBackOrder = 1; } + + if ($refundReqBookings && in_array($data_v['id'], $refundReqBookings) && $data_v['is_refunded']) { + if ($data_v['is_cancelled']) { + $cartHotelData[$type_key]['date_diff'][$date_join]['count_cancelled'] += 1; + } else { + $cartHotelData[$type_key]['date_diff'][$date_join]['count_refunded'] += 1; + } + } } else { $num_days = $objBookingDetail->getNumberOfDays($data_v['date_from'], $data_v['date_to']); $cartHotelData[$type_key]['date_diff'][$date_join]['num_rm'] = 1; @@ -326,6 +337,16 @@ class GuestTrackingControllerCore extends FrontController if ($data_v['is_back_order']) { $anyBackOrder = 1; } + + $cartHotelData[$type_key]['date_diff'][$date_join]['count_cancelled'] = 0; + $cartHotelData[$type_key]['date_diff'][$date_join]['count_refunded'] = 0; + if ($refundReqBookings && in_array($data_v['id'], $refundReqBookings) && $data_v['is_refunded']) { + if ($data_v['is_cancelled']) { + $cartHotelData[$type_key]['date_diff'][$date_join]['count_cancelled'] += 1; + } else { + $cartHotelData[$type_key]['date_diff'][$date_join]['count_refunded'] += 1; + } + } } $cartHotelData[$type_key]['date_diff'][$date_join]['is_refunded'] = $data_v['is_refunded']; @@ -583,6 +604,7 @@ class GuestTrackingControllerCore extends FrontController 'CUSTOMIZE_TEXTFIELD' => Product::CUSTOMIZE_TEXTFIELD, 'use_tax' => Configuration::get('PS_TAX'), 'guestInformations' => (array)$customer, + 'view_on_map' => Configuration::get('WK_GOOGLE_ACTIVE_MAP'), )); } @@ -627,6 +649,7 @@ class GuestTrackingControllerCore extends FrontController 'map_input_text' => $objHotelBranchInformation->map_input_text, ), 'hotel_name' => $objHotelBranchInformation->hotel_name, + 'PS_STORES_ICON' => $this->context->link->getMediaLink(_PS_IMG_.Configuration::get('PS_STORES_ICON')) )); $this->addJS( From 026d7cdb27f57dce05d64a3dc4c90fd5441d84ae Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 3 Aug 2024 10:58:41 +0530 Subject: [PATCH 15/16] Fixed:After making fields as required and clicking on save and stay, customer eamail is not showing on customer detail page. --- controllers/admin/AdminAddressesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/admin/AdminAddressesController.php b/controllers/admin/AdminAddressesController.php index 5005b269b..1d4b32e9e 100644 --- a/controllers/admin/AdminAddressesController.php +++ b/controllers/admin/AdminAddressesController.php @@ -481,7 +481,7 @@ class AdminAddressesControllerCore extends AdminController // in case of save and stay, redirect after save with current address. // Because the current address can not be same as the current one(We have to delete it and create a new one in case address is used in orders) - if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { + if (empty($this->errors) && Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { $idCurrentAddress = Customer::getCustomerIdAddress($this->object->id_customer, false); if ($idCurrentAddress != $this->object->id) { $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$idCurrentAddress.'&conf=4&update'.$this->table.'&token='.$this->token; From 154a7689c2c872bd8b66825fa275d1b52015e9b7 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Sat, 3 Aug 2024 17:41:24 +0530 Subject: [PATCH 16/16] Fixed: Issues in customer address update from the order address --- .../controllers/orders/helpers/view/view.tpl | 2 +- controllers/admin/AdminOrdersController.php | 29 +++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) 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 e83f58b49..e8c21dfc3 100644 --- a/admin/themes/default/template/controllers/orders/helpers/view/view.tpl +++ b/admin/themes/default/template/controllers/orders/helpers/view/view.tpl @@ -638,7 +638,7 @@
-  {l s='Guest Address'} +  {l s='Customer Address'} {if $can_edit} {if $idOrderAddressInvoice}