PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.4
VikBooking Hotel Booking Engine & PMS v1.6.4
1.8.16 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 All 37 releases
vikbooking / admin / helpers / report / options_extras.php

options_extras.php in VikBooking Hotel Booking Engine & PMS 1.6.4, at admin/helpers/report/options_extras.php

480 lines 16.4 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 /**
14 * Options/Extras child Class of VikBookingReport
15 */
16 class VikBookingReportOptionsExtras extends VikBookingReport
17 {
18 /**
19 * Property 'defaultKeySort' is used by the View that renders the report.
20 */
21 public $defaultKeySort = 'day';
22
23 /**
24 * Property 'defaultKeyOrder' is used by the View that renders the report.
25 */
26 public $defaultKeyOrder = 'ASC';
27
28 /**
29 * Property 'exportAllowed' is used by the View to display the export button.
30 */
31 public $exportAllowed = 1;
32
33 /**
34 * Debug mode is activated by passing the value 'e4j_debug' > 0
35 */
36 private $debug;
37
38 /**
39 * Class constructor should define the name of the report and
40 * other vars. Call the parent constructor to define the DB object.
41 */
42 public function __construct()
43 {
44 $this->reportFile = basename(__FILE__, '.php');
45 $this->reportName = JText::translate('VBOREPORT'.strtoupper(str_replace('_', '', $this->reportFile)));
46 $this->reportFilters = array();
47
48 $this->cols = array();
49 $this->rows = array();
50 $this->footerRow = array();
51
52 $this->debug = (VikRequest::getInt('e4j_debug', 0, 'request') > 0);
53
54 $this->registerExportCSVFileName();
55
56 parent::__construct();
57 }
58
59 /**
60 * Returns the name of this report.
61 *
62 * @return string
63 */
64 public function getName()
65 {
66 return $this->reportName;
67 }
68
69 /**
70 * Returns the name of this file without .php.
71 *
72 * @return string
73 */
74 public function getFileName()
75 {
76 return $this->reportFile;
77 }
78
79 /**
80 * Returns the filters of this report.
81 *
82 * @return array
83 */
84 public function getFilters()
85 {
86 if (count($this->reportFilters)) {
87 //do not run this method twice, as it could load JS and CSS files.
88 return $this->reportFilters;
89 }
90
91 //get VBO Application Object
92 $vbo_app = VikBooking::getVboApplication();
93
94 //load the jQuery UI Datepicker
95 $this->loadDatePicker();
96
97 //From Date Filter
98 $filter_opt = array(
99 'label' => '<label for="fromdate">'.JText::translate('VBOREPORTSDATEFROM').'</label>',
100 'html' => '<input type="text" id="fromdate" name="fromdate" value="" class="vbo-report-datepicker vbo-report-datepicker-from" />',
101 'type' => 'calendar',
102 'name' => 'fromdate'
103 );
104 array_push($this->reportFilters, $filter_opt);
105
106 //To Date Filter
107 $filter_opt = array(
108 'label' => '<label for="todate">'.JText::translate('VBOREPORTSDATETO').'</label>',
109 'html' => '<input type="text" id="todate" name="todate" value="" class="vbo-report-datepicker vbo-report-datepicker-to" />',
110 'type' => 'calendar',
111 'name' => 'todate'
112 );
113 array_push($this->reportFilters, $filter_opt);
114
115 //Option ID filter
116 $pidoptional = VikRequest::getInt('idoptional', '', 'request');
117 $options = $this->getAllOptions();
118 if (count($options)) {
119 $opts_sel_html = $vbo_app->getNiceSelect($options, $pidoptional, 'idoptional', JText::translate('VBOREPORTFILTALLOPTS'), JText::translate('VBOREPORTFILTALLOPTS'), '', '', 'idoptional');
120 $filter_opt = array(
121 'label' => '<label for="idoptional">'.JText::translate('VBOREPORTOPTIONSEXTRAS').'</label>',
122 'html' => $opts_sel_html,
123 'type' => 'select',
124 'name' => 'idoptional'
125 );
126 array_push($this->reportFilters, $filter_opt);
127 }
128
129 //jQuery code for the datepicker calendars and select2
130 $pfromdate = VikRequest::getString('fromdate', '', 'request');
131 $ptodate = VikRequest::getString('todate', '', 'request');
132 $js = 'jQuery(document).ready(function() {
133 jQuery(".vbo-report-datepicker:input").datepicker({
134 maxDate: 0,
135 dateFormat: "'.$this->getDateFormat('jui').'",
136 onSelect: vboReportCheckDates
137 });
138 '.(!empty($pfromdate) ? 'jQuery(".vbo-report-datepicker-from").datepicker("setDate", "'.$pfromdate.'");' : '').'
139 '.(!empty($ptodate) ? 'jQuery(".vbo-report-datepicker-to").datepicker("setDate", "'.$ptodate.'");' : '').'
140 });
141 function vboReportCheckDates(selectedDate, inst) {
142 if (selectedDate === null || inst === null) {
143 return;
144 }
145 var cur_from_date = jQuery(this).val();
146 if (jQuery(this).hasClass("vbo-report-datepicker-from") && cur_from_date.length) {
147 var nowstart = jQuery(this).datepicker("getDate");
148 var nowstartdate = new Date(nowstart.getTime());
149 jQuery(".vbo-report-datepicker-to").datepicker("option", {minDate: nowstartdate});
150 }
151 }';
152 $this->setScript($js);
153
154 return $this->reportFilters;
155 }
156
157 /**
158 * Loads the report data from the DB.
159 * Returns true in case of success, false otherwise.
160 * Sets the columns and rows for the report to be displayed.
161 *
162 * @return boolean
163 */
164 public function getReportData()
165 {
166 if (strlen($this->getError())) {
167 //Export functions may set errors rather than exiting the process, and the View may continue the execution to attempt to render the report.
168 return false;
169 }
170 $options = $this->getAllOptions(true);
171 if (!count($options)) {
172 $this->setError('No Options configured in the system.');
173 return false;
174 }
175 //Input fields and other vars
176 $pfromdate = VikRequest::getString('fromdate', '', 'request');
177 $ptodate = VikRequest::getString('todate', '', 'request');
178 $pidoptional = VikRequest::getInt('idoptional', '', 'request');
179 $pkrsort = VikRequest::getString('krsort', $this->defaultKeySort, 'request');
180 $pkrsort = empty($pkrsort) ? $this->defaultKeySort : $pkrsort;
181 $pkrorder = VikRequest::getString('krorder', $this->defaultKeyOrder, 'request');
182 $pkrorder = empty($pkrorder) ? $this->defaultKeyOrder : $pkrorder;
183 $pkrorder = $pkrorder == 'DESC' ? 'DESC' : 'ASC';
184 $currency_symb = VikBooking::getCurrencySymb();
185 $df = $this->getDateFormat();
186 $datesep = VikBooking::getDateSeparator();
187 if (empty($ptodate)) {
188 $ptodate = $pfromdate;
189 }
190 //Get dates timestamps
191 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
192 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59, 59);
193 if (empty($pfromdate) || empty($from_ts) || empty($to_ts)) {
194 $this->setError(JText::translate('VBOREPORTSERRNODATES'));
195 return false;
196 }
197
198 //Query to obtain the records
199 $records = array();
200 $q = "SELECT `o`.`id`,`o`.`ts`,`o`.`days`,`o`.`checkin`,`o`.`checkout`,`o`.`totpaid`,`o`.`roomsnum`,`o`.`total`,`o`.`idorderota`,`o`.`channel`,`o`.`country`,`o`.`tot_taxes`,`o`.`tot_city_taxes`,".
201 "`o`.`tot_fees`,`o`.`cmms`,`or`.`idorder`,`or`.`idroom`,`or`.`adults`,`or`.`children`,`or`.`optionals`,`or`.`childrenage`,`or`.`cust_cost`,`or`.`cust_idiva`,`or`.`extracosts`,`or`.`room_cost` ".
202 "FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_ordersrooms` AS `or` ON `or`.`idorder`=`o`.`id` ".
203 "WHERE `o`.`status`='confirmed' AND `o`.`closure`=0 AND `o`.`checkout`>=".$from_ts." AND `o`.`checkin`<=".$to_ts." ".
204 "ORDER BY `o`.`checkin` ASC, `o`.`id` ASC;";
205 $this->dbo->setQuery($q);
206 $this->dbo->execute();
207 if ($this->dbo->getNumRows() > 0) {
208 $records = $this->dbo->loadAssocList();
209 }
210 if (!count($records)) {
211 $this->setError(JText::translate('VBOREPORTSERRNORESERV'));
212 return false;
213 }
214
215 $valid_opt_ids = array_keys($options);
216
217 //nest records with multiple rooms booked inside sub-array
218 $bookings = array();
219 foreach ($records as $v) {
220 if (empty($v['optionals'])) {
221 continue;
222 }
223 if (!empty($pidoptional) && strpos($v['optionals'], $pidoptional.':') === false) {
224 //this booking does not contain the filtered option
225 continue;
226 }
227 $has_valid_options = false;
228 foreach ($valid_opt_ids as $optid) {
229 if (strpos($v['optionals'], $optid.':') !== false) {
230 $has_valid_options = true;
231 break;
232 }
233 }
234 if (!$has_valid_options) {
235 //maybe this booking has only city taxes as options, not real ones, so we don't take it
236 continue;
237 }
238 if (!isset($bookings[$v['id']])) {
239 $bookings[$v['id']] = array();
240 }
241 //calculate the from_ts and to_ts values for later comparison
242 $in_info = getdate($v['checkin']);
243 $out_info = getdate($v['checkout']);
244 $v['from_ts'] = mktime(0, 0, 0, $in_info['mon'], $in_info['mday'], $in_info['year']);
245 $v['to_ts'] = mktime(23, 59, 59, $out_info['mon'], ($out_info['mday'] - 1), $out_info['year']);
246 //
247 array_push($bookings[$v['id']], $v);
248 }
249
250 //define the columns of the report and the Option IDs for the rows
251 $option_rows = array();
252 $this->cols = array(
253 //date
254 array(
255 'key' => 'day',
256 'sortable' => 1,
257 'label' => JText::translate('VBOREPORTREVENUEDAY')
258 )
259 );
260 foreach ($options as $opt) {
261 if (!empty($pidoptional) && $pidoptional != $opt['id']) {
262 continue;
263 }
264 $opt['row_value_net'] = 0;
265 $opt['row_value_tax'] = 0;
266 $option_rows[$opt['id']] = $opt;
267 array_push($this->cols, array(
268 'key' => 'optid'.$opt['id'],
269 'attr' => array(
270 'class="center"'
271 ),
272 'sortable' => 1,
273 'label' => $opt['name']
274 ));
275 }
276
277 //loop over the dates of the report to build the rows
278 $from_info = getdate($from_ts);
279 $to_info = getdate($to_ts);
280 while ($from_info[0] <= $to_info[0]) {
281 //prepare default fields for this row
282 $day_ts = $from_info[0];
283 $curwday = $this->getWdayString($from_info['wday'], 'short');
284 $option_day_row = $option_rows;
285 //calculate the report details for this day
286 foreach ($bookings as $gbook) {
287 if ($from_info[0] >= $gbook[0]['from_ts'] && $from_info[0] <= $gbook[0]['to_ts']) {
288 //this booking affects the current day
289 foreach ($gbook as $or) {
290 $stepo = explode(";", $or['optionals']);
291 foreach ($stepo as $roptkey => $one) {
292 if (empty($one)) {
293 continue;
294 }
295 $stept = explode(":", $one);
296 if (!isset($option_rows[(int)$stept[0]])) {
297 //we don't need this option
298 continue;
299 }
300 $actopt = $option_rows[(int)$stept[0]];
301 //calculate the cost of this option
302 if (!empty($actopt['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
303 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
304 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
305 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $or['adults'], $or['children']);
306 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt['id'], $roptkey, $or['children']);
307 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
308 $agestept = explode('-', $stept[1]);
309 $stept[1] = $agestept[0];
310 $chvar = $agestept[1];
311 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
312 //percentage value of the adults tariff
313 if (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
314 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
315 } else {
316 //we ignore the room base cost (tars) as it's not available here
317 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : 0;
318 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
319 }
320 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
321 //VBO 1.10 - percentage value of room base cost
322 if (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
323 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
324 } else {
325 //we ignore the room base cost (tars) as it's not available here
326 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : 0;
327 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
328 }
329 }
330 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $gbook[0]['days'] * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
331 } else {
332 // VBO 1.11 - options percentage cost of the room total fee
333 if (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
334 $deftar_basecosts = $or['cust_cost'];
335 } else {
336 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : 0;
337 }
338 $actopt['cost'] = (int)$actopt['pcentroom'] ? ($deftar_basecosts * $actopt['cost'] / 100) : $actopt['cost'];
339 //
340 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $gbook[0]['days'] * $stept[1]) : ($actopt['cost'] * $stept[1]));
341 }
342 if (!empty ($actopt['maxprice']) && $actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
343 $realcost = $actopt['maxprice'];
344 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
345 $realcost = $actopt['maxprice'] * $stept[1];
346 }
347 }
348 if ($actopt['perperson'] == 1) {
349 $realcost = $realcost * $or['adults'];
350 }
351 $with_tax = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
352 $with_tax_daily = $with_tax / (int)$gbook[0]['days'];
353 $without_tax = VikBooking::sayOptionalsMinusIva($realcost, $actopt['idiva']);
354 $without_tax_daily = $without_tax / (int)$gbook[0]['days'];
355 //update values for this option, for this day
356 $option_day_row[(int)$stept[0]]['row_value_net'] += $without_tax_daily;
357 $option_day_row[(int)$stept[0]]['row_value_tax'] += $with_tax_daily - $without_tax_daily;
358
359 }
360 }
361 }
362 }
363
364 //push fields in the rows array as a new row
365 array_push($this->rows, array(
366 array(
367 'key' => 'day',
368 'callback' => function ($val) use ($df, $datesep, $curwday) {
369 return $curwday.', '.date(str_replace("/", $datesep, $df), $val);
370 },
371 'value' => $day_ts
372 )
373 ));
374 $row_key = count($this->rows) - 1;
375 foreach ($option_day_row as $idopt => $v) {
376 array_push($this->rows[$row_key], array(
377 'key' => 'optid'.$idopt,
378 'attr' => array(
379 'class="center"'
380 ),
381 'callback' => function ($val) use ($currency_symb) {
382 return $currency_symb.' '.VikBooking::numberFormat($val);
383 },
384 'value' => $v['row_value_net']
385 ));
386 }
387
388 //next day iteration
389 $from_info = getdate(mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] + 1), $from_info['year']));
390 }
391
392 //sort rows
393 $this->sortRows($pkrsort, $pkrorder);
394
395 //loop over the rows to build the footer row with the totals
396 $foot_tots = array();
397 foreach ($this->rows as $row) {
398 foreach ($row as $k => $v) {
399 if ($k < 1) {
400 continue;
401 }
402 if (!isset($foot_tots[$k])) {
403 $foot_tots[$k] = 0;
404 }
405 $foot_tots[$k] += $v['value'];
406 }
407 }
408 array_push($this->footerRow, array(
409 array(
410 'attr' => array(
411 'class="vbo-report-total"'
412 ),
413 'value' => '<h3>'.JText::translate('VBOREPORTSTOTALROW').'</h3>'
414 )
415 ));
416 foreach ($foot_tots as $v) {
417 array_push($this->footerRow[0], array(
418 'attr' => array(
419 'class="center"'
420 ),
421 'callback' => function ($val) use ($currency_symb) {
422 return $currency_symb.' '.VikBooking::numberFormat($val);
423 },
424 'value' => $v
425 ));
426 }
427
428 //Debug
429 if ($this->debug) {
430 $this->setWarning('path to report file = '.urlencode(dirname(__FILE__)).'<br/>');
431 $this->setWarning('$total_rooms_units = '.$total_rooms_units.'<br/>');
432 $this->setWarning('$bookings:<pre>'.print_r($bookings, true).'</pre><br/>');
433 }
434 //
435
436 return true;
437 }
438
439 /**
440 * Registers the name to give to the CSV file being exported.
441 *
442 * @return void
443 *
444 * @since 1.16.1 (J) - 1.6.1 (WP)
445 */
446 private function registerExportCSVFileName()
447 {
448 $pfromdate = VikRequest::getString('fromdate', '', 'request');
449 $ptodate = VikRequest::getString('todate', '', 'request');
450
451 $this->setExportCSVFileName($this->reportName . '-' . str_replace('/', '_', $pfromdate) . '-' . str_replace('/', '_', $ptodate) . '.csv');
452 }
453
454 /**
455 * Reads from the DB all the Options that are not
456 * tourist taxes, and returns an associative array
457 * with the ID of the Option as key.
458 *
459 * @param boolean $return_all return the whole array record
460 *
461 * @return array
462 */
463 private function getAllOptions($return_all = false)
464 {
465 $all_options = array();
466 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `is_citytax`=0 ORDER BY `name` ASC;";
467 $this->dbo->setQuery($q);
468 $this->dbo->execute();
469 if ($this->dbo->getNumRows()) {
470 $all_options = $this->dbo->loadAssocList();
471 }
472 $options = array();
473 foreach ($all_options as $opt) {
474 $options[$opt['id']] = $return_all ? $opt : $opt['name'];
475 }
476
477 return $options;
478 }
479 }
480