PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / views / ratesoverv / view.html.php

view.html.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/views/ratesoverv/view.html.php

457 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 // import Joomla view library
14 jimport('joomla.application.component.view');
15
16 class VikBookingViewRatesoverv extends JViewVikBooking
17 {
18 public function display($tpl = null)
19 {
20 // Set the toolbar
21 $this->addToolBar();
22
23 if (!JFactory::getUser()->authorise('core.vbo.pricing', 'com_vikbooking')) {
24 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
25 }
26
27 /**
28 * Check the next festivities periodically
29 *
30 * @since 1.12.0 (J) - 1.2.0 (WP)
31 */
32 $fests = VikBooking::getFestivitiesInstance();
33 if ($fests->shouldCheckFestivities()) {
34 $fests->storeNextFestivities();
35 }
36 $festivities = $fests->loadFestDates();
37
38 $dbo = JFactory::getDbo();
39 $app = JFactory::getApplication();
40 $session = JFactory::getSession();
41
42 // define the maximum number of days
43 $MAX_DAYS = VBOFactory::getConfig()->getInt('roverv_max_days', 60);
44
45 $cid = VikRequest::getVar('cid', array(0));
46 $sesscids = $session->get('vbRatesOviewCids', array());
47 if (empty($cid[0]) && is_array($sesscids) && count($sesscids)) {
48 // load rooms from session only if no room IDs requested
49 $cid = $sesscids;
50 }
51
52 // first room ID
53 $roomid = (int)$cid[0];
54
55 if (empty($roomid)) {
56 $q = "SELECT `id` FROM `#__vikbooking_rooms` WHERE `avail`=1 ORDER BY `#__vikbooking_rooms`.`name` ASC LIMIT 1";
57 $dbo->setQuery($q);
58 $roomid = $dbo->loadResult();
59 if (!$roomid) {
60 $q = "SELECT `id` FROM `#__vikbooking_rooms` ORDER BY `#__vikbooking_rooms`.`name` ASC LIMIT 1";
61 $dbo->setQuery($q);
62 $roomid = $dbo->loadResult();
63 }
64 }
65 if (empty($roomid)) {
66 $app->redirect("index.php?option=com_vikbooking&task=rooms");
67 exit;
68 }
69 // make sure to set at least the first index of cid[]
70 $cid[0] = $roomid;
71 //
72 $q = "SELECT `id`,`name`,`img` FROM `#__vikbooking_rooms` ORDER BY `#__vikbooking_rooms`.`name` ASC;";
73 $dbo->setQuery($q);
74 $all_rooms = $dbo->loadAssocList();
75
76 /**
77 * Load categories to be used for group filter.
78 *
79 * @since 1.13 (J) - 1.3.0 (WP)
80 */
81 $q = "SELECT `id`,`name` FROM `#__vikbooking_categories` ORDER BY `#__vikbooking_categories`.`name` ASC;";
82 $dbo->setQuery($q);
83 $categories = $dbo->loadAssocList();
84
85 // load rooms rows for all requested rooms
86 $roomrows = [];
87 $reqids = [];
88 $reqcats = [];
89 foreach ($cid as $rid) {
90 if (empty($rid)) {
91 continue;
92 }
93 $rid = (int)$rid;
94 if ($rid < 0) {
95 // category
96 array_push($reqcats, ($rid + (abs($rid) * 2)));
97 } else {
98 // room
99 array_push($reqids, $rid);
100 }
101 }
102 if (!$reqcats && !$reqids) {
103 $app->redirect("index.php?option=com_vikbooking&task=rooms");
104 exit;
105 }
106
107 if (!$reqcats && empty($sesscids) && count($reqids) === 1 && count($all_rooms) > 1) {
108 // push the first 5 rooms by default
109 $max_def_rooms = VBOFactory::getConfig()->getInt('roverv_def_max_rooms', 5);
110 $def_rooms_count = 0;
111 $reqids = [];
112 foreach ($all_rooms as $aroom) {
113 $reqids[] = $aroom['id'];
114 $def_rooms_count++;
115 if ($def_rooms_count >= $max_def_rooms) {
116 break;
117 }
118 }
119 }
120
121 $clauses = [];
122 if (count($reqids)) {
123 array_push($clauses, "`id` IN (" . implode(', ', $reqids) . ")");
124 }
125 foreach ($reqcats as $cat_id) {
126 array_push($clauses, "(`idcat`='" . $cat_id . ";' OR `idcat` LIKE '" . $cat_id . ";%' OR `idcat` LIKE '%;" . $cat_id . ";%' OR `idcat` LIKE '%;" . $cat_id . ";')");
127 }
128 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE ".implode(' OR ', $clauses)." ORDER BY `name` ASC;";
129 $dbo->setQuery($q);
130 $rows = $dbo->loadAssocList();
131 if ($rows) {
132 foreach ($rows as $row) {
133 $roomrows[$row['id']] = $row;
134 }
135 }
136 if (!$roomrows) {
137 $app->redirect("index.php?option=com_vikbooking&task=rooms");
138 exit;
139 }
140 if (!$reqids) {
141 // in case of just a category filter we need to restore the requested room IDs for later actions
142 $reqids = array_keys($roomrows);
143 }
144 // get all requested and valid room IDs
145 $req_room_ids = array_keys($roomrows);
146 $session->set('vbRatesOviewCids', $req_room_ids);
147 // Restrictions
148 $all_restrictions = [];
149 foreach ($req_room_ids as $rid) {
150 $all_restrictions[(int)$rid] = VikBooking::loadRestrictions(true, array($rid));
151 }
152 // length of stay pricing overview (only if one single room requested)
153 $first_roomrestr = isset($all_restrictions[(int)$roomid]) ? $all_restrictions[(int)$roomid] : array();
154 $pnights_cal = VikRequest::getVar('nights_cal', array());
155 $pnights_cal = VikBooking::filterNightsSeasonsCal($pnights_cal);
156 $room_nights_cal = isset($roomrows[(int)$roomid]) ? explode(',', VikBooking::getRoomParam('seasoncal_nights', $roomrows[(int)$roomid]['params'])) : [];
157 $room_nights_cal = VikBooking::filterNightsSeasonsCal($room_nights_cal);
158 $seasons_cal = [];
159 $seasons_cal_nights = [];
160 if ($pnights_cal) {
161 $seasons_cal_nights = $pnights_cal;
162 } elseif ($room_nights_cal) {
163 $seasons_cal_nights = $room_nights_cal;
164 } else {
165 $q = "SELECT `days` FROM `#__vikbooking_dispcost` WHERE `idroom`=".intval($roomid)." ORDER BY `#__vikbooking_dispcost`.`days` ASC LIMIT 7;";
166 $dbo->setQuery($q);
167 $nights_vals = $dbo->loadAssocList();
168 if ($nights_vals) {
169 $nights_got = [];
170 foreach ($nights_vals as $night) {
171 $nights_got[] = $night['days'];
172 }
173 $seasons_cal_nights = VikBooking::filterNightsSeasonsCal($nights_got);
174 }
175 }
176 if (count($req_room_ids) > 1) {
177 // it's useless to spend server resources to calculate the seasons calendar nights (LOS Pricing Overview) since it won't be displayed when more than 1 room
178 $seasons_cal_nights = [];
179 }
180 if ($seasons_cal_nights) {
181 $q = "SELECT `p`.*,`tp`.`name`,`tp`.`attr`,`tp`.`idiva`,`tp`.`breakfast_included`,`tp`.`free_cancellation`,`tp`.`canc_deadline` FROM `#__vikbooking_dispcost` AS `p` LEFT JOIN `#__vikbooking_prices` `tp` ON `p`.`idprice`=`tp`.`id` WHERE `p`.`days` IN (".implode(',', $seasons_cal_nights).") AND `p`.`idroom`=".(int)$roomid." ORDER BY `p`.`days` ASC, `p`.`cost` ASC;";
182 $dbo->setQuery($q);
183 $tars = $dbo->loadAssocList();
184 if ($tars) {
185 $arrtar = [];
186 foreach ($tars as $tar) {
187 $arrtar[$tar['days']][] = $tar;
188 }
189 $seasons_cal['nights'] = $seasons_cal_nights;
190 $seasons_cal['offseason'] = $arrtar;
191 $q = "SELECT * FROM `#__vikbooking_seasons` WHERE `idrooms` LIKE '%-".$roomid."-%';";
192 $dbo->setQuery($q);
193 $seasons = $dbo->loadAssocList();
194 if ($seasons) {
195 //Restrictions
196 $all_seasons = [];
197 $curtime = time();
198 foreach ($seasons as $sk => $s) {
199 if (empty($s['from']) && empty($s['to'])) {
200 continue;
201 }
202 $now_year = !empty($s['year']) ? $s['year'] : date('Y');
203 list($sfrom, $sto) = VikBooking::getSeasonRangeTs($s['from'], $s['to'], $now_year);
204 if ($sto < $curtime && empty($s['year'])) {
205 $now_year += 1;
206 list($sfrom, $sto) = VikBooking::getSeasonRangeTs($s['from'], $s['to'], $now_year);
207 }
208 if ($sto >= $curtime) {
209 $s['from_ts'] = $sfrom;
210 $s['to_ts'] = $sto;
211 $all_seasons[] = $s;
212 }
213 }
214 if (count($all_seasons) > 0) {
215 $vbo_df = VikBooking::getDateFormat();
216 $vbo_df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
217 $hcheckin = 0;
218 $mcheckin = 0;
219 $hcheckout = 0;
220 $mcheckout = 0;
221 $timeopst = VikBooking::getTimeOpenStore();
222 if (is_array($timeopst)) {
223 $opent = VikBooking::getHoursMinutes($timeopst[0]);
224 $closet = VikBooking::getHoursMinutes($timeopst[1]);
225 $hcheckin = $opent[0];
226 $mcheckin = $opent[1];
227 $hcheckout = $closet[0];
228 $mcheckout = $closet[1];
229 }
230 $all_seasons = VikBooking::sortSeasonsRangeTs($all_seasons);
231 $seasons_cal['seasons'] = $all_seasons;
232 $seasons_cal['season_prices'] = [];
233 $seasons_cal['restrictions'] = [];
234 //calc price changes for each season and for each num-night
235 foreach ($all_seasons as $sk => $s) {
236 $checkin_base_ts = $s['from_ts'];
237 $is_dst = date('I', $checkin_base_ts);
238 foreach ($arrtar as $numnights => $tar) {
239 $checkout_base_ts = $s['to_ts'];
240 for($i = 1; $i <= $numnights; $i++) {
241 $checkout_base_ts += 86400;
242 $is_now_dst = date('I', $checkout_base_ts);
243 if ($is_dst != $is_now_dst) {
244 if ((int)$is_dst == 1) {
245 $checkout_base_ts += 3600;
246 } else {
247 $checkout_base_ts -= 3600;
248 }
249 $is_dst = $is_now_dst;
250 }
251 }
252 //calc check-in and check-out ts for the two dates
253 $first = VikBooking::getDateTimestamp(date($vbo_df, $checkin_base_ts), $hcheckin, $mcheckin);
254 $second = VikBooking::getDateTimestamp(date($vbo_df, $checkout_base_ts), $hcheckout, $mcheckout);
255 $tar = VikBooking::applySeasonsRoom($tar, $first, $second, $s);
256 $seasons_cal['season_prices'][$sk][$numnights] = $tar;
257 //Restrictions
258 if (count($first_roomrestr)) {
259 $season_restr = VikBooking::parseSeasonRestrictions($first, $second, $numnights, $first_roomrestr);
260 if (count($season_restr) > 0) {
261 $seasons_cal['restrictions'][$sk][$numnights] = $season_restr;
262 }
263 }
264 }
265 }
266 }
267 }
268 }
269 }
270 //calendar rates
271 $todayd = getdate();
272 $tsstart = mktime(0, 0, 0, $todayd['mon'], $todayd['mday'], $todayd['year']);
273 $startdate = VikRequest::getString('startdate', '', 'request');
274 if (!empty($startdate)) {
275 $startts = VikBooking::getDateTimestamp($startdate, 0, 0);
276 if (!empty($startts)) {
277 $session->set('vbRatesOviewTs', $startts);
278 $tsstart = $startts;
279 }
280 } else {
281 $prevts = $session->get('vbRatesOviewTs', '');
282 if (!empty($prevts)) {
283 $tsstart = $prevts;
284 }
285 }
286
287 // read the rates for the lowest number of nights for each room requested
288 $roomrates = [];
289 foreach ($req_room_ids as $rid) {
290 /**
291 * Some types of price may not have a cost for 1 or 2 nights,
292 * so joining by MIN(`days`) may exclude certain types of price.
293 * We need to manually get via PHP all types of price.
294 * Old query below is no longer in use, even though it was
295 * compatible with the SQL strict mode (only_full_group_by).
296 * $q = "SELECT `r`.`id`,`r`.`idroom`,`r`.`days`,`r`.`idprice`,`r`.`cost`,`p`.`name` FROM `#__vikbooking_dispcost` AS `r` INNER JOIN (SELECT MIN(`days`) AS `min_days` FROM `#__vikbooking_dispcost` WHERE `idroom`=".(int)$rid." GROUP BY `idroom`) AS `r2` ON `r`.`days`=`r2`.`min_days` LEFT JOIN `#__vikbooking_prices` `p` ON `p`.`id`=`r`.`idprice` WHERE `r`.`idroom`=".(int)$rid." GROUP BY `r`.`id`,`r`.`idroom`,`r`.`days`,`r`.`idprice`,`r`.`cost`,`p`.`name` ORDER BY `r`.`days` ASC, `r`.`cost` ASC;";
297 *
298 * @since 1.10 (J) - 1.0.14 (WP)
299 */
300 $q = "SELECT `r`.`id`,`r`.`idroom`,`r`.`days`,`r`.`idprice`,`r`.`cost`,`p`.`name`,`p`.`minlos`,`p`.`derived_id`
301 FROM `#__vikbooking_dispcost` AS `r`
302 LEFT JOIN `#__vikbooking_prices` `p` ON `p`.`id`=`r`.`idprice`
303 WHERE `r`.`idroom`=".(int)$rid."
304 ORDER BY `r`.`days` ASC, `r`.`cost` ASC";
305 $dbo->setQuery($q, 0, 50);
306 $nowroomrates = $dbo->loadAssocList();
307
308 if ($nowroomrates) {
309 $parsed_room_prices = [];
310 foreach ($nowroomrates as $rrk => $rrv) {
311 if (isset($parsed_room_prices[$rrv['idprice']])) {
312 unset($nowroomrates[$rrk]);
313 continue;
314 }
315 $nowroomrates[$rrk]['cost'] = round(($rrv['cost'] / $rrv['days']), 2);
316 $nowroomrates[$rrk]['days'] = 1;
317 $parsed_room_prices[$rrv['idprice']] = 1;
318 }
319 }
320
321 $nowroomrates = array_values($nowroomrates);
322
323 // push rates for this room
324 $roomrates[(int)$rid] = $nowroomrates;
325 }
326
327 // sort room rates by the best rate plan name
328 foreach ($roomrates as $rid => $roomrplans) {
329 $roomrates[$rid] = VikBooking::sortRatePlans($roomrplans);
330 }
331
332 // read all the bookings between these dates for all rooms
333 $booked_dates = [];
334 $info_start = getdate($tsstart);
335 $endts = mktime(23, 59, 59, $info_start['mon'], ($info_start['mday'] + $MAX_DAYS), $info_start['year']);
336
337 $q = "SELECT `b`.*,`ob`.`idorder`,`o`.`custdata`,`o`.`status`,`o`.`days`,`o`.`roomsnum`,`o`.`idorderota`,`o`.`channel`,`o`.`colortag`,`o`.`closure`,`o`.`total`,`o`.`totpaid`,`o`.`paymentlog`
338 FROM `#__vikbooking_busy` AS `b`
339 LEFT JOIN `#__vikbooking_ordersbusy` AS `ob` ON `b`.`id`=`ob`.`idbusy`
340 LEFT JOIN `#__vikbooking_orders` AS `o` ON `ob`.`idorder`=`o`.`id`
341 WHERE `b`.`idroom` IN (" . implode(', ', $reqids) . ") AND (`b`.`checkin`>=" . $tsstart . " OR `b`.`checkout`>=" . $tsstart . ") AND (`b`.`checkin`<=" . $endts . " OR `b`.`checkout`<=" . $tsstart . ");";
342 $dbo->setQuery($q);
343 $rbusy = $dbo->loadAssocList();
344
345 $ridbusy = [];
346 foreach ($rbusy as $rb) {
347 if (!isset($ridbusy[$rb['idroom']])) {
348 $ridbusy[$rb['idroom']] = [];
349 }
350 $ridbusy[$rb['idroom']][] = $rb;
351 }
352
353 // collect additional information for each booking
354 $extra_info_map = [];
355 foreach ($ridbusy as $rid => $roomres) {
356 foreach ($roomres as $k => $res) {
357 if (empty($res['idorder'])) {
358 continue;
359 }
360 if (isset($extra_info_map[$res['idorder']])) {
361 // merge existing extra information
362 $ridbusy[$rid][$k] = array_merge($res, $extra_info_map[$res['idorder']]);
363 continue;
364 }
365 // get booking extra information
366 $q = "SELECT `oc`.`idcustomer`,`c`.`first_name`,`c`.`last_name`,`c`.`pic`
367 FROM `#__vikbooking_customers_orders` AS `oc`
368 LEFT JOIN `#__vikbooking_customers` AS `c` ON `oc`.`idcustomer`=`c`.`id`
369 WHERE `oc`.`idorder`={$res['idorder']}";
370 $dbo->setQuery($q, 0, 1);
371 $extra_info = $dbo->loadAssoc();
372 $extra_info = $extra_info ?: [];
373 // merge and map booking extra information
374 $ridbusy[$rid][$k] = array_merge($res, $extra_info);
375 $extra_info_map[$res['idorder']] = $extra_info;
376 }
377 }
378
379 foreach ($req_room_ids as $rid) {
380 $booked_dates[$rid] = $ridbusy[$rid] ?? [];
381 }
382
383 // free memory up
384 unset($ridbusy, $rbusy);
385
386 /**
387 * Load room day notes for the requested dates
388 *
389 * @since 1.13.5
390 */
391 $rdaynotes = VikBooking::getCriticalDatesInstance()->loadRoomDayNotes(date('Y-m-d', $tsstart), date('Y-m-d', $endts));
392
393 /**
394 * Build room-ota relations for pricing alterations, if any.
395 *
396 * @since 1.17.2 (J) - 1.7.2 (WP)
397 */
398 $room_ota_relations = [];
399 foreach ($req_room_ids as $rid) {
400 // always get a new instance of the VikChannelManagerLogos class
401 $vcm_logos = VikBooking::getVcmChannelsLogo('', true);
402 // load channels (firsr) and accounts (after) for this listing
403 $room_ota_channels = is_object($vcm_logos) && method_exists($vcm_logos, 'getVboRoomLogosMapped') ? $vcm_logos->getVboRoomLogosMapped($rid) : [];
404 $room_ota_accounts = is_object($vcm_logos) && method_exists($vcm_logos, 'getRoomOtaAccounts') ? $vcm_logos->getRoomOtaAccounts() : [];
405 // filter channels not available as accounts (i.e. iCal)
406 if (count($room_ota_channels) != count(($room_ota_accounts[$rid] ?? []))) {
407 $ota_account_names = array_map('strtolower', array_column(($room_ota_accounts[$rid] ?? []), 'channel'));
408 $room_ota_channels = array_filter($room_ota_channels, function($chid) use ($ota_account_names) {
409 return in_array(strtolower($chid), $ota_account_names);
410 }, ARRAY_FILTER_USE_KEY);
411 }
412 if ($room_ota_channels && ($room_ota_accounts[$rid] ?? [])) {
413 $room_ota_relations[$rid] = [
414 'channels' => $room_ota_channels,
415 'accounts' => $room_ota_accounts[$rid],
416 ];
417 }
418 }
419
420 $this->all_rooms = $all_rooms;
421 $this->categories = $categories;
422 $this->reqcats = $reqcats;
423 $this->all_restrictions = $all_restrictions;
424 $this->roomrows = $roomrows;
425 $this->seasons_cal_nights = $seasons_cal_nights;
426 $this->seasons_cal = $seasons_cal;
427 $this->tsstart = $tsstart;
428 $this->roomrates = $roomrates;
429 $this->booked_dates = $booked_dates;
430 $this->req_room_ids = $req_room_ids;
431 $this->firstroom = $roomid;
432 $this->festivities = $festivities;
433 $this->rdaynotes = $rdaynotes;
434 $this->room_ota_relations = $room_ota_relations;
435 $this->max_days = $MAX_DAYS;
436
437 // Display the template
438 parent::display($tpl);
439 }
440
441 /**
442 * Sets the toolbar
443 */
444 protected function addToolBar()
445 {
446 JToolBarHelper::title(JText::translate('VBMAINRATESOVERVIEWTITLE'), 'vikbooking');
447 if (JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
448 JToolBarHelper::addNew('newseason', JText::translate('VBMAINSEASONSNEW'));
449 JToolBarHelper::spacer();
450 JToolBarHelper::addNew('newrestriction', JText::translate('VBMAINRESTRICTIONNEW'));
451 JToolBarHelper::spacer();
452 }
453 JToolBarHelper::cancel( 'cancel', JText::translate('VBBACK'));
454 JToolBarHelper::spacer();
455 }
456 }
457