PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.13
VikBooking Hotel Booking Engine & PMS v1.8.13
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 / guests_registration_data.php

guests_registration_data.php in VikBooking Hotel Booking Engine & PMS 1.8.13, at admin/helpers/report/guests_registration_data.php

397 lines 12.9 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 srl
6 * @copyright Copyright (C) 2024 E4J srl. 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 * Guests Registration (raw) Data child Class of VikBookingReport.
15 *
16 * @since 1.18.3 (J) - 1.8.3 (WP)
17 */
18 class VikBookingReportGuestsRegistrationData extends VikBookingReport
19 {
20 /**
21 * Property 'defaultKeySort' is used by the View that renders the report.
22 */
23 public $defaultKeySort = 'idbooking';
24
25 /**
26 * Property 'defaultKeyOrder' is used by the View that renders the report.
27 */
28 public $defaultKeyOrder = 'ASC';
29
30 /**
31 * Property 'exportAllowed' is used by the View to display the export button.
32 */
33 public $exportAllowed = 1;
34
35 /**
36 * Class constructor should define the name of the report and
37 * other vars. Call the parent constructor to define the DB object.
38 */
39 public function __construct()
40 {
41 $this->reportFile = basename(__FILE__, '.php');
42 $this->reportName = JText::translate('VBO_GUESTS_REGISTRATION_DATA');
43 $this->reportFilters = [];
44
45 $this->cols = [];
46 $this->rows = [];
47 $this->footerRow = [];
48
49 $this->registerExportCSVFileName();
50
51 parent::__construct();
52 }
53
54 /**
55 * Returns the name of this report.
56 *
57 * @return string
58 */
59 public function getName()
60 {
61 return $this->reportName;
62 }
63
64 /**
65 * Returns the name of this file without .php.
66 *
67 * @return string
68 */
69 public function getFileName()
70 {
71 return $this->reportFile;
72 }
73
74 /**
75 * Returns the filters of this report.
76 *
77 * @return array
78 */
79 public function getFilters()
80 {
81 if ($this->reportFilters) {
82 //do not run this method twice, as it could load JS and CSS files.
83 return $this->reportFilters;
84 }
85
86 // get VBO Application Object
87 $vbo_app = VikBooking::getVboApplication();
88
89 // load the jQuery UI Datepicker
90 $this->loadDatePicker();
91
92 // From Date Filter
93 $filter_opt = array(
94 'label' => '<label for="fromdate">'.JText::translate('VBOREPORTSDATEFROM').'</label>',
95 'html' => '<input type="text" id="fromdate" name="fromdate" value="" class="vbo-report-datepicker vbo-report-datepicker-from" />',
96 'type' => 'calendar',
97 'name' => 'fromdate'
98 );
99 array_push($this->reportFilters, $filter_opt);
100
101 // To Date Filter
102 $filter_opt = array(
103 'label' => '<label for="todate">'.JText::translate('VBOREPORTSDATETO').'</label>',
104 'html' => '<input type="text" id="todate" name="todate" value="" class="vbo-report-datepicker vbo-report-datepicker-to" />',
105 'type' => 'calendar',
106 'name' => 'todate'
107 );
108 array_push($this->reportFilters, $filter_opt);
109
110 // Listings Filter
111 $filter_opt = array(
112 'label' => '<label for="listingsfilt">' . JText::translate('VBO_LISTINGS') . '</label>',
113 'html' => '<span class="vbo-toolbar-multiselect-wrap">' . $vbo_app->renderElementsDropDown([
114 'id' => 'listingsfilt',
115 'elements' => 'listings',
116 'placeholder' => JText::translate('VBO_LISTINGS'),
117 'allow_clear' => 1,
118 'attributes' => [
119 'name' => 'listings[]',
120 'multiple' => 'multiple',
121 ],
122 'selected_values' => (array) JFactory::getApplication()->input->get('listings', [], 'array'),
123 ]) . '</span>',
124 'type' => 'select',
125 'multiple' => true,
126 'name' => 'listings',
127 );
128 array_push($this->reportFilters, $filter_opt);
129
130 // get minimum check-in and maximum check-out for dates filters
131 $df = $this->getDateFormat();
132 $mincheckin = 0;
133 $maxcheckout = 0;
134 $q = "SELECT MIN(`checkin`) AS `mincheckin`, MAX(`checkout`) AS `maxcheckout` FROM `#__vikbooking_orders` WHERE `status`='confirmed' AND `closure`=0;";
135 $this->dbo->setQuery($q);
136 $this->dbo->execute();
137 if ($this->dbo->getNumRows()) {
138 $data = $this->dbo->loadAssoc();
139 if (!empty($data['mincheckin']) && !empty($data['maxcheckout'])) {
140 $mincheckin = $data['mincheckin'];
141 $maxcheckout = $data['maxcheckout'];
142 }
143 }
144
145 // calendars setup
146 $pfromdate = VikRequest::getString('fromdate', '', 'request');
147 $ptodate = VikRequest::getString('todate', '', 'request');
148 $js = 'jQuery(function() {
149 jQuery(".vbo-report-datepicker:input").datepicker({
150 '.(!empty($mincheckin) ? 'minDate: "'.date($df, $mincheckin).'", ' : '').'
151 '.(!empty($maxcheckout) ? 'maxDate: "'.date($df, $maxcheckout).'", ' : '').'
152 '.(!empty($mincheckin) && !empty($maxcheckout) ? 'yearRange: "'.(date('Y', $mincheckin)).':'.date('Y', $maxcheckout).'", changeMonth: true, changeYear: true, ' : '').'
153 dateFormat: "'.$this->getDateFormat('jui').'",
154 onSelect: vboReportCheckDates
155 });
156 '.(!empty($pfromdate) ? 'jQuery(".vbo-report-datepicker-from").datepicker("setDate", "'.$pfromdate.'");' : '').'
157 '.(!empty($ptodate) ? 'jQuery(".vbo-report-datepicker-to").datepicker("setDate", "'.$ptodate.'");' : '').'
158 });
159 function vboReportCheckDates(selectedDate, inst) {
160 if (selectedDate === null || inst === null) {
161 return;
162 }
163 var cur_from_date = jQuery(this).val();
164 if (jQuery(this).hasClass("vbo-report-datepicker-from") && cur_from_date.length) {
165 var nowstart = jQuery(this).datepicker("getDate");
166 var nowstartdate = new Date(nowstart.getTime());
167 jQuery(".vbo-report-datepicker-to").datepicker("option", {minDate: nowstartdate});
168 }
169 }';
170 $this->setScript($js);
171
172 return $this->reportFilters;
173 }
174
175 /**
176 * Loads the report data from the DB.
177 * Returns true in case of success, false otherwise.
178 * Sets the columns and rows for the report to be displayed.
179 *
180 * @return boolean
181 */
182 public function getReportData()
183 {
184 if ($this->getError()) {
185 // export functions may set errors rather than exiting the process, and the View may continue the execution to attempt to render the report.
186 return false;
187 }
188
189 if ($this->rows) {
190 // method must have run already
191 return true;
192 }
193
194 // get the possibly injected report options
195 $options = $this->getReportOptions();
196
197 // injected options will replace request variables, if any
198 $opt_fromdate = $options->get('fromdate', '');
199 $opt_todate = $options->get('todate', '');
200
201 // input fields and other vars
202 $pfromdate = $opt_fromdate ?: VikRequest::getString('fromdate', '', 'request');
203 $ptodate = $opt_todate ?: VikRequest::getString('todate', '', 'request');
204
205 $pkrsort = VikRequest::getString('krsort', $this->defaultKeySort, 'request');
206 $pkrsort = empty($pkrsort) ? $this->defaultKeySort : $pkrsort;
207 $pkrorder = VikRequest::getString('krorder', $this->defaultKeyOrder, 'request');
208 $pkrorder = empty($pkrorder) ? $this->defaultKeyOrder : $pkrorder;
209 $pkrorder = $pkrorder == 'DESC' ? 'DESC' : 'ASC';
210 $plistings = ((array) VikRequest::getVar('listings', array())) ?: ((array) $options->get('listings', []));
211 $plistings = array_filter(array_map('intval', $plistings));
212
213 $currency_symb = VikBooking::getCurrencySymb();
214 $df = $this->getDateFormat();
215 $datesep = VikBooking::getDateSeparator();
216 if (empty($ptodate)) {
217 $ptodate = $pfromdate;
218 }
219
220 // get date timestamps
221 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
222 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59, 59);
223 if (empty($pfromdate) || empty($from_ts) || empty($to_ts) || $from_ts > $to_ts) {
224 $this->setError(JText::translate('VBOREPORTSERRNODATES'));
225 return false;
226 }
227
228 // query to obtain the records (all check-ins within the dates filter)
229 $q = $this->dbo->getQuery(true)
230 ->select([
231 $this->dbo->qn('o.id'),
232 $this->dbo->qn('o.custdata'),
233 $this->dbo->qn('o.ts'),
234 $this->dbo->qn('o.days'),
235 $this->dbo->qn('o.checkin'),
236 $this->dbo->qn('o.checkout'),
237 $this->dbo->qn('o.totpaid'),
238 $this->dbo->qn('o.roomsnum'),
239 $this->dbo->qn('o.total'),
240 $this->dbo->qn('o.idorderota'),
241 $this->dbo->qn('o.channel'),
242 $this->dbo->qn('o.country'),
243 $this->dbo->qn('o.custmail'),
244 $this->dbo->qn('o.phone'),
245 $this->dbo->qn('or.idorder'),
246 $this->dbo->qn('or.idroom'),
247 $this->dbo->qn('or.adults'),
248 $this->dbo->qn('or.children'),
249 $this->dbo->qn('or.t_first_name'),
250 $this->dbo->qn('or.t_last_name'),
251 $this->dbo->qn('or.cust_cost'),
252 $this->dbo->qn('or.cust_idiva'),
253 $this->dbo->qn('or.extracosts'),
254 $this->dbo->qn('or.room_cost'),
255 $this->dbo->qn('co.idcustomer'),
256 $this->dbo->qn('co.pax_data'),
257 $this->dbo->qn('c.first_name'),
258 $this->dbo->qn('c.last_name'),
259 $this->dbo->qn('c.country', 'customer_country'),
260 $this->dbo->qn('c.address'),
261 $this->dbo->qn('c.doctype'),
262 $this->dbo->qn('c.docnum'),
263 $this->dbo->qn('c.gender'),
264 $this->dbo->qn('c.bdate'),
265 $this->dbo->qn('c.pbirth'),
266 ])
267 ->from($this->dbo->qn('#__vikbooking_orders', 'o'))
268 ->leftJoin($this->dbo->qn('#__vikbooking_ordersrooms', 'or') . ' ON ' . $this->dbo->qn('or.idorder') . ' = ' . $this->dbo->qn('o.id'))
269 ->leftJoin($this->dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $this->dbo->qn('co.idorder') . ' = ' . $this->dbo->qn('o.id'))
270 ->leftJoin($this->dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $this->dbo->qn('c.id') . ' = ' . $this->dbo->qn('co.idcustomer'))
271 ->where($this->dbo->qn('o.status') . ' = ' . $this->dbo->q('confirmed'))
272 ->where($this->dbo->qn('o.closure') . ' = 0')
273 // fetch all bookings with check-in, check-out or reservation date within date filters
274 ->where('(' . $this->dbo->qn('o.checkin') . ' BETWEEN ' . $from_ts . ' AND ' . $to_ts . ')')
275 // fetch all bookings with pre-check-in information available
276 ->where($this->dbo->qn('co.pax_data') . ' IS NOT NULL')
277 ->order($this->dbo->qn('o.checkin') . ' ASC')
278 ->order($this->dbo->qn('o.id') . ' ASC')
279 ->order($this->dbo->qn('or.id') . ' ASC');
280
281 if ($plistings) {
282 $q->where($this->dbo->qn('or.idroom') . ' IN (' . implode(', ', $plistings) . ')');
283 }
284
285 $this->dbo->setQuery($q);
286 $records = $this->dbo->loadAssocList();
287 if (!$records) {
288 // set error message
289 $this->setError(JText::translate('VBOREPORTSERRNORESERV'));
290
291 // abort
292 return false;
293 }
294
295 // nest records with multiple rooms booked inside sub-array, and build all registration keys
296 $bookings = [];
297 $registration_keys = [];
298 foreach ($records as $v) {
299 $v['pax_data'] = (array) json_decode($v['pax_data'], true);
300 foreach ($v['pax_data'] as $pax_room) {
301 foreach ($pax_room as $pax_guest) {
302 $registration_keys = array_merge($registration_keys, array_keys((array) $pax_guest));
303 }
304 }
305 if (!isset($bookings[$v['id']])) {
306 $bookings[$v['id']] = [];
307 }
308 array_push($bookings[$v['id']], $v);
309 }
310
311 // make the registration keys unique
312 $registration_keys = array_values(array_unique(array_filter($registration_keys)));
313
314 // free memory up
315 unset($records);
316
317 // define the columns of the report
318 $this->cols = [
319 // id booking
320 [
321 'key' => 'idbooking',
322 'label' => 'ID',
323 ],
324 ];
325
326 foreach ($registration_keys as $registration_key) {
327 $this->cols[] = [
328 'key' => $registration_key,
329 'label' => ucwords(str_replace('_', ' ', $registration_key)),
330 ];
331 }
332
333 // loop over the dates of the report to build the rows
334 foreach ($bookings as $gbook) {
335 if (!is_array($gbook[0]['pax_data'] ?? null)) {
336 continue;
337 }
338
339 foreach ($gbook[0]['pax_data'] as $pax_room) {
340 foreach ($pax_room as $pax_guest) {
341 // prepare row record for this room-guest
342 $insert_row = [];
343
344 // ID booking
345 $insert_row[] = [
346 'key' => 'idbooking',
347 'callback' => function($val) {
348 return '<a data-bid="' . $val . '" href="index.php?option=com_vikbooking&task=editorder&cid[]=' . $val . '" target="_blank"><i class="' . VikBookingIcons::i('external-link') . '"></i> ' . $val . '</a>';
349 },
350 'no_export_callback' => 1,
351 'value' => $gbook[0]['id'],
352 ];
353
354 foreach ($registration_keys as $registration_key) {
355 // build guest key value
356 $guest_value = is_scalar($pax_guest[$registration_key] ?? null) ? $pax_guest[$registration_key] : null;
357 if (is_object($pax_guest[$registration_key] ?? null) || is_array($pax_guest[$registration_key] ?? null)) {
358 $guest_value = json_encode($pax_guest[$registration_key]);
359 }
360
361 // push guest registration key value
362 $insert_row[] = [
363 'key' => $registration_key,
364 'callback' => function($val) {
365 if (is_string($val) && strlen($val) > 24) {
366 return mb_substr($val, 0, 24, 'UTF-8') . '...';
367 }
368 return $val;
369 },
370 'no_export_callback' => 1,
371 'value' => $guest_value,
372 ];
373 }
374
375 // push fields in the rows array as a new row
376 $this->rows[] = $insert_row;
377 }
378 }
379 }
380
381 return true;
382 }
383
384 /**
385 * Registers the name to give to the CSV file being exported.
386 *
387 * @return void
388 */
389 private function registerExportCSVFileName()
390 {
391 $pfromdate = VikRequest::getString('fromdate', '', 'request');
392 $ptodate = VikRequest::getString('todate', '', 'request');
393
394 $this->setExportCSVFileName($this->reportName . '-' . str_replace('/', '_', $pfromdate) . '-' . str_replace('/', '_', $ptodate) . '.csv');
395 }
396 }
397