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 / istat_sired.php

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

1,718 lines 55.3 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 * ISTAT SIRED child Class of VikBookingReport
15 *
16 * @see https://sired.sardegnaturismo.it/IW_OT/Downloads/TracciatoGiornaliero.pdf
17 */
18 class VikBookingReportIstatSired extends VikBookingReport
19 {
20 /**
21 * Property 'defaultKeySort' is used by the View that renders the report.
22 */
23 public $defaultKeySort = 'checkin';
24 /**
25 * Property 'defaultKeyOrder' is used by the View that renders the report.
26 */
27 public $defaultKeyOrder = 'ASC';
28 /**
29 * Property 'customExport' is used by the View to display custom export buttons.
30 * We should not define the property $exportAllowed.
31 */
32 public $customExport = '';
33 /**
34 * Debug mode is activated by passing the value 'e4j_debug' > 0
35 */
36 private $debug;
37 /**
38 * An associative array of regions (keys) and provinces (sub-arrays)
39 *
40 * @var array
41 */
42
43 /**
44 * Class constructor should define the name of the report and
45 * other vars. Call the parent constructor to define the DB object.
46 */
47 public function __construct()
48 {
49 $this->reportFile = basename(__FILE__, '.php');
50 $this->reportName = 'ISTAT SIRED';
51 $this->reportFilters = array();
52
53 $this->cols = array();
54 $this->rows = array();
55 $this->footerRow = array();
56
57 $this->comuniProvince = $this->loadComuniProvince();
58 $this->nazioni = $this->loadNazioni();
59
60 $this->debug = (VikRequest::getInt('e4j_debug', 0, 'request') > 0);
61
62 $this->registerExportFileName();
63
64 parent::__construct();
65 }
66
67 /**
68 * Returns the name of this report.
69 *
70 * @return string
71 */
72 public function getName()
73 {
74 return $this->reportName;
75 }
76
77 /**
78 * Returns the name of this file without .php.
79 *
80 * @return string
81 */
82 public function getFileName()
83 {
84 return $this->reportFile;
85 }
86
87 /**
88 * Returns the filters of this report.
89 *
90 * @return array
91 */
92 public function getFilters()
93 {
94 if (count($this->reportFilters)) {
95 //do not run this method twice, as it could load JS and CSS files.
96 return $this->reportFilters;
97 }
98 $this->loadCss();
99
100 //load the jQuery UI Datepicker
101 $this->loadDatePicker();
102
103
104 //custom export button
105 $this->customExport = '<a href="JavaScript: void(0);" onclick="vboDownloadIstatDoc();" class="vbcsvexport"><i class="'.VikBookingIcons::i('download').'"></i> <span>Genera Documento Dati ISTAT</span></a>';
106
107 // helper filters
108 $hidden_vals = '<div id="vbo-report-istat-hidden" style="display: none;">';
109 // Filtro nazione nascita
110 $hidden_vals .= ' <div id="vbo-report-istat-nazione" class="vbo-report-istat-selcont" style="display: none;">';
111 $hidden_vals .= ' <select id="choose-nazione" onchange="vboReportChosenNazione(this);"><option value=""></option>';
112 // sort all foreign countries in a clone to not lose keys. We add also Liechtenstein which equals to 'Svizzera'
113
114 //
115 $hidden_vals .= ' <optgroup label=" Nazioni ">';
116 foreach ($this->nazioni as $countrytipo => $name) {
117 $hidden_vals .= ' <option value="'.$countrytipo.'">'.$name['name'].'</option>';
118 }
119 $hidden_vals .= ' </optgroup>';
120 $hidden_vals .= ' </select>';
121
122 $hidden_vals .= ' </div>';
123
124 // comune
125 $hidden_vals .= ' <div id="vbo-report-istat-comune" class="vbo-report-istat-selcont" style="display: none;">';
126 $hidden_vals .= ' <select id="choose-comune" onchange="vboReportChosenComune(this);"><option value=""></option>';
127 if (isset($this->comuniProvince['comuni']) && count($this->comuniProvince['comuni'])) {
128 foreach ($this->comuniProvince['comuni'] as $code => $comune) {
129 $hidden_vals .= ' <option value="'.$code.'">' . (is_array($comune) ? $comune['name'] : $comune) . '</option>'."\n";
130 }
131 }
132 $hidden_vals .= ' </select>';
133 $hidden_vals .= ' </div>';
134
135 //Sesso
136 $hidden_vals .= ' <div id="vbo-report-istat-sesso" class="vbo-report-istat-selcont" style="display: none;">';
137 $hidden_vals .= ' <select id="choose-sesso" onchange="vboReportChosenSesso(this);"><option value=""></option>';
138 $sessos = array(
139 1 => 'M',
140 2 => 'F'
141 );
142 foreach ($sessos as $code => $ses) {
143 $hidden_vals .= ' <option value="'.$code.'">'.$ses.'</option>'."\n";
144 }
145 $hidden_vals .= ' </select>';
146 $hidden_vals .= ' </div>';
147 //data di nascita
148 $hidden_vals .= ' <div id="vbo-report-istat-dbirth" class="vbo-report-istat-selcont" style="display: none;">';
149 $hidden_vals .= ' <input type="text" size="40" id="choose-dbirth" placeholder="Data di Nascita" value="" /><br/>';
150 $hidden_vals .= ' <button type="button" class="btn" onclick="vboReportChosenDbirth(document.getElementById(\'choose-dbirth\').value);">'.JText::translate('VBAPPLY').'</button>';
151 $hidden_vals .= ' </div>';
152 //
153 $hidden_vals .= '</div>';
154
155 //From Date Filter
156 $filter_opt = array(
157 'label' => '<label for="fromdate">'.JText::translate('VBOREPORTSDATEFROM').'</label>',
158 'html' => '<input type="text" id="fromdate" name="fromdate" value="" class="vbo-report-datepicker vbo-report-datepicker-from" />'.$hidden_vals,
159 'type' => 'calendar',
160 'name' => 'fromdate'
161 );
162 array_push($this->reportFilters, $filter_opt);
163
164 //To Date Filter
165 $filter_opt = array(
166 'label' => '<label for="todate">'.JText::translate('VBOREPORTSDATETO').'</label>',
167 'html' => '<input type="text" id="todate" name="todate" value="" class="vbo-report-datepicker vbo-report-datepicker-to" />',
168 'type' => 'calendar',
169 'name' => 'todate'
170 );
171 array_push($this->reportFilters, $filter_opt);
172
173 // Filtro Codice Struttura
174 $pcodstru = VikRequest::getString('codstru', '', 'request');
175 $filter_opt = array(
176 'label' => '<label for="codstru">Codice Struttura</label>',
177 'html' => '<input type="text" id="codstru" name="codstru" value="'.$pcodstru.'" size="10" />',
178 'type' => 'text',
179 'name' => 'codstru'
180 );
181 array_push($this->reportFilters, $filter_opt);
182
183 // Filtro Numero Letti
184 $pletti = VikRequest::getInt('numletti', 0, 'request');
185 $filter_opt = array(
186 'label' => '<label for="numletti">Numero Letti Disponibili</label>',
187 'html' => '<input type="number" id="numletti" name="numletti" value="'.$pletti.'" size="10" />',
188 'type' => 'text',
189 'name' => 'numletti'
190 );
191 array_push($this->reportFilters, $filter_opt);
192
193 //jQuery code for the datepicker calendars and select2
194 $pfromdate = VikRequest::getString('fromdate', '', 'request');
195 $ptodate = VikRequest::getString('todate', '', 'request');
196 $js = 'var reportActiveCell = null, reportObj = {};
197 jQuery(document).ready(function() {
198 jQuery(".vbo-report-datepicker:input").datepicker({
199 maxDate: 0,
200 dateFormat: "'.$this->getDateFormat('jui').'",
201 onSelect: vboReportCheckDates
202 });
203 '.(!empty($pfromdate) ? 'jQuery(".vbo-report-datepicker-from").datepicker("setDate", "'.$pfromdate.'");' : '').'
204 '.(!empty($ptodate) ? 'jQuery(".vbo-report-datepicker-to").datepicker("setDate", "'.$ptodate.'");' : '').'
205 //prepare filler helpers
206 jQuery("#vbo-report-istat-hidden").children().detach().appendTo(".vbo-info-overlay-report");
207 jQuery("#choose-comune").select2({placeholder: "- Seleziona un Comune -", width: "200px"});
208 jQuery("#choose-provincia").select2({placeholder: "- Seleziona una Provincia -", width: "200px"});
209 jQuery("#choose-nazione").select2({placeholder: "- Seleziona una Nazione -", width: "200px"});
210 jQuery("#choose-documento").select2({placeholder: "- Seleziona un Documento -", width: "200px"});
211 jQuery("#choose-sesso").select2({placeholder: "- Seleziona Sesso -", width: "200px"});
212 jQuery("#choose-dbirth").datepicker({
213 maxDate: 0,
214 dateFormat: "dd/mm/yy",
215 changeMonth: true,
216 changeYear: true,
217 yearRange: "'.(date('Y') - 100).':'.date('Y').'"
218 });
219 //click events
220 jQuery(".vbo-report-load-comuneres, .vbo-report-load-comunenas").click(function() {
221 reportActiveCell = this;
222 jQuery(".vbo-report-istat-selcont").hide();
223 jQuery("#vbo-report-istat-comune").show();
224 vboShowOverlay();
225 });
226 jQuery(".vbo-report-load-provincia").click(function() {
227 reportActiveCell = this;
228 jQuery(".vbo-report-istat-selcont").hide();
229 jQuery("#vbo-report-istat-provincia").show();
230 vboShowOverlay();
231 });
232
233 jQuery(".vbo-report-load-nazioneres, .vbo-report-load-cittadinanza, .vbo-report-load-nazionenas").click(function() {
234 reportActiveCell = this;
235 jQuery(".vbo-report-istat-selcont").hide();
236 jQuery("#vbo-report-istat-nazione").show();
237 vboShowOverlay();
238 });
239 jQuery(".vbo-report-load-doctype").click(function() {
240 reportActiveCell = this;
241 jQuery(".vbo-report-istat-selcont").hide();
242 jQuery("#vbo-report-istat-doctype").show();
243 vboShowOverlay();
244 });
245 jQuery(".vbo-report-load-docplace").click(function() {
246 reportActiveCell = this;
247 jQuery(".vbo-report-istat-selcont").hide();
248 jQuery("#vbo-report-istat-comune").show();
249 jQuery("#vbo-report-istat-nazione").show();
250 vboShowOverlay();
251 });
252 jQuery(".vbo-report-load-sesso").click(function() {
253 reportActiveCell = this;
254 jQuery(".vbo-report-istat-selcont").hide();
255 jQuery("#vbo-report-istat-sesso").show();
256 vboShowOverlay();
257 });
258 jQuery(".vbo-report-load-docnum").click(function() {
259 reportActiveCell = this;
260 jQuery(".vbo-report-istat-selcont").hide();
261 jQuery("#vbo-report-istat-docnum").show();
262 vboShowOverlay();
263 setTimeout(function(){jQuery("#choose-docnum").focus();}, 500);
264 });
265 jQuery(".vbo-report-load-dbirth").click(function() {
266 reportActiveCell = this;
267 jQuery(".vbo-report-istat-selcont").hide();
268 jQuery("#vbo-report-istat-dbirth").show();
269 vboShowOverlay();
270 //pretend the overlay is off, or navigating in the datepicker will close the modal.
271 setTimeout(function(){vbo_overlay_on = false;}, 800);
272 //
273 });
274 });
275 function vboReportCheckDates(selectedDate, inst) {
276 if (selectedDate === null || inst === null) {
277 return;
278 }
279 var cur_from_date = jQuery(this).val();
280 if (jQuery(this).hasClass("vbo-report-datepicker-from") && cur_from_date.length) {
281 var nowstart = jQuery(this).datepicker("getDate");
282 var nowstartdate = new Date(nowstart.getTime());
283 jQuery(".vbo-report-datepicker-to").datepicker("option", {minDate: nowstartdate});
284 }
285 }
286 function vboReportChosenComune(comune) {
287 var c_code = comune.value;
288 var c_val = comune.options[comune.selectedIndex].text;
289 if (reportActiveCell !== null) {
290 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
291 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
292 alert("Error, cannot find element to update.");
293 } else {
294 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
295 if (!reportObj.hasOwnProperty(nowindex)) {
296 reportObj[nowindex] = {};
297 }
298 if (jQuery(reportActiveCell).hasClass("vbo-report-load-docplace")) {
299 reportObj[nowindex].docplace = c_code;
300 } else if (jQuery(reportActiveCell).hasClass("vbo-report-load-comunenas")) {
301 reportObj[nowindex].combirth = c_code;
302 } else {
303 reportObj[nowindex].comres = c_code;
304
305 }
306 }
307 }
308 reportActiveCell = null;
309 vboHideOverlay();
310 jQuery("#choose-comune").val("").select2("data", null, false);
311 }
312 function vboReportChosenProvincia(prov) {
313 var c_code = prov.value;
314 var c_val = prov.options[prov.selectedIndex].text;
315 if (reportActiveCell !== null) {
316 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
317 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
318 alert("Error, cannot find element to update.");
319 } else {
320 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
321 if (!reportObj.hasOwnProperty(nowindex)) {
322 reportObj[nowindex] = {};
323 }
324 reportObj[nowindex].probirth = c_code;
325 }
326 }
327 reportActiveCell = null;
328 vboHideOverlay();
329 jQuery("#choose-provincia").val("").select2("data", null, false);
330 }
331 function vboReportChosenNazione(naz) {
332 var c_code = naz.value;
333 var c_val = naz.options[naz.selectedIndex].text;
334 if (reportActiveCell !== null) {
335 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
336 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
337 alert("Error, cannot find element to update.");
338 } else {
339 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
340 if (!reportObj.hasOwnProperty(nowindex)) {
341 reportObj[nowindex] = {};
342 }
343 if (jQuery(reportActiveCell).hasClass("vbo-report-load-nazionenas")) {
344 reportObj[nowindex].stabirth = c_code;
345 } else if (jQuery(reportActiveCell).hasClass("vbo-report-load-docplace")) {
346 reportObj[nowindex].docplace = c_code;
347 } else if (jQuery(reportActiveCell).hasClass("vbo-report-load-nazioneres")) {
348 reportObj[nowindex].stares = c_code;
349 } else {
350 reportObj[nowindex].citizen = c_code;
351 }
352 }
353 }
354 reportActiveCell = null;
355 vboHideOverlay();
356 jQuery("#choose-nazione").val("").select2("data", null, false);
357
358 }
359 function vboReportChosenDocumento(doctype) {
360 var c_code = doctype.value;
361 var c_val = doctype.options[doctype.selectedIndex].text;
362 if (reportActiveCell !== null) {
363 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
364 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
365 alert("Error, cannot find element to update.");
366 } else {
367 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
368 if (!reportObj.hasOwnProperty(nowindex)) {
369 reportObj[nowindex] = {};
370 }
371 reportObj[nowindex].doctype = c_code;
372 }
373 }
374 reportActiveCell = null;
375 vboHideOverlay();
376 jQuery("#choose-documento").val("").select2("data", null, false);
377 }
378 function vboReportChosenSesso(sesso) {
379 var c_code = sesso.value;
380 var c_val = sesso.options[sesso.selectedIndex].text;
381 if (reportActiveCell !== null) {
382 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
383 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
384 alert("Error, cannot find element to update.");
385 } else {
386 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
387 if (!reportObj.hasOwnProperty(nowindex)) {
388 reportObj[nowindex] = {};
389 }
390 reportObj[nowindex].gender = c_code;
391 }
392 }
393 reportActiveCell = null;
394 vboHideOverlay();
395 jQuery("#choose-sesso").val("").select2("data", null, false);
396 }
397 function vboReportChosenDocnum(val) {
398 var c_code = val, c_val = val;
399 if (reportActiveCell !== null) {
400 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
401 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
402 alert("Error, cannot find element to update.");
403 } else {
404 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
405 if (!reportObj.hasOwnProperty(nowindex)) {
406 reportObj[nowindex] = {};
407 }
408 reportObj[nowindex].docnum = c_code;
409 }
410 }
411 reportActiveCell = null;
412 vboHideOverlay();
413 jQuery("#choose-docnum").val("");
414 }
415 function vboReportChosenDbirth(val) {
416 var c_code = val, c_val = val;
417 if (reportActiveCell !== null) {
418 var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr"));
419 if (isNaN(nowindex) || parseInt(nowindex) < 0) {
420 alert("Error, cannot find element to update.");
421 } else {
422 jQuery(reportActiveCell).addClass("vbo-report-load-elem-filled").find("span").text(c_val);
423 if (!reportObj.hasOwnProperty(nowindex)) {
424 reportObj[nowindex] = {};
425 }
426 reportObj[nowindex].dbirth = c_code;
427 }
428 }
429 reportActiveCell = null;
430 vboHideOverlay();
431 jQuery("#choose-dbirth").val("");
432 }
433 //download function
434 function vboDownloadIstatDoc() {
435 // check if empty values have been filled in or ask for confirmation
436 var missing_italia = jQuery(".vbo-report-load-nazione").not(".vbo-report-load-elem-filled").length;
437 var missing_tipo = jQuery(".vbo-report-load-cittadinanza").not(".vbo-report-load-elem-filled").length;
438 if ((missing_italia > 0 || missing_tipo > 0) && !confirm("Qualche dato mancante evidenziato in rosso non è stato compilato. Vuoi continuare?")) {
439 return false;
440 } else if (!confirm("Sei sicuro di aver compilato tutti i dati per il documento?")) {
441 return false;
442 }
443 document.adminForm.target = "_blank";
444 document.adminForm.action += "&tmpl=component";
445 vboSetFilters({exportreport: "1", filler: JSON.stringify(reportObj)}, true);
446 setTimeout(function() {
447 document.adminForm.target = "";
448 document.adminForm.action = document.adminForm.action.replace("&tmpl=component", "");
449 vboSetFilters({exportreport: "0", filler: ""}, false);
450 }, 1000);
451 }
452 ';
453 $this->setScript($js);
454
455 // additional CSS code for other elements
456 JFactory::getDocument()->addStyleDeclaration('.vbo-report-load-nazionenas span, .vbo-report-load-nazioneres span, .vbo-report-load-comunenas span, .vbo-report-load-comuneres span {
457 display: inline-block;
458 border: 1px solid #dd0000;
459 cursor: pointer;
460 color: #dd0000;
461 padding: 0px 7px;
462 text-align: center;
463
464 }
465 .vbo-report-load-elem-filled span {
466 border: 0;
467 padding: 0;
468 color: #070f63;
469 }');
470
471 return $this->reportFilters;
472 }
473
474 /**
475 * Loads the report data from the DB.
476 * Returns true in case of success, false otherwise.
477 * Sets the columns and rows for the report to be displayed.
478 *
479 * @return boolean
480 */
481 public function getReportData()
482 {
483 if (strlen($this->getError())) {
484 //Export functions may set errors rather than exiting the process, and the View may continue the execution to attempt to render the report.
485 return false;
486 }
487 //Input fields and other vars
488 $pfromdate = VikRequest::getString('fromdate', '', 'request');
489 $ptodate = VikRequest::getString('todate', '', 'request');
490 $pcodstru = VikRequest::getString('codstru', '', 'request');
491 $pkrsort = VikRequest::getString('krsort', $this->defaultKeySort, 'request');
492 $pkrsort = empty($pkrsort) ? $this->defaultKeySort : $pkrsort;
493 $pkrorder = VikRequest::getString('krorder', $this->defaultKeyOrder, 'request');
494 $pkrorder = empty($pkrorder) ? $this->defaultKeyOrder : $pkrorder;
495 $pkrorder = $pkrorder == 'DESC' ? 'DESC' : 'ASC';
496 $df = $this->getDateFormat();
497 $datesep = VikBooking::getDateSeparator();
498 if (empty($ptodate)) {
499 $ptodate = $pfromdate;
500 }
501 $records = array();
502 $q = "SELECT SUM(`units`) AS `sommaunita`, SUM(`totpeople`) AS `numeropersone`, COUNT(*) AS `numerocamere` FROM `#__vikbooking_rooms` WHERE `avail`= '1';";
503 $this->dbo->setQuery($q);
504 $this->dbo->execute();
505 if ($this->dbo->getNumRows() > 0) {
506 $records = $this->dbo->loadAssocList();
507 }
508 $totalBeds =(int) ($records[0]['sommaunita'] * ($records[0]['numeropersone']/$records[0]['numerocamere']));
509 $pletti = VikRequest::getString('numletti', $totalBeds, 'request');
510 //Get dates timestamps
511 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
512 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59, 59);
513 if (empty($pfromdate) || empty($from_ts) || empty($to_ts)) {
514 $this->setError(JText::translate('VBOREPORTSERRNODATES'));
515 return false;
516 }
517 if (empty($pcodstru)) {
518 $this->setError('Inserisci il codice della tua Struttura.<br/>Si tratta di un codice univoco di identificazione che ti viene assegnato dall\'Amministrazione competente.');
519 return false;
520 }
521
522 //Query to obtain the records (all check-ins within the dates filter)
523 $records = array();
524 $q = "SELECT `o`.`id`,`o`.`custdata`,`o`.`ts`,`o`.`days`,`o`.`checkin`,`o`.`checkout`,`o`.`totpaid`,`o`.`roomsnum`,`o`.`total`,`o`.`idorderota`,`o`.`channel`,`o`.`country`,".
525 "`or`.`idorder`,`or`.`idroom`,`or`.`adults`,`or`.`children`,`or`.`t_first_name`,`or`.`t_last_name`,`or`.`cust_cost`,`or`.`cust_idiva`,`or`.`extracosts`,`or`.`room_cost`,".
526 "`co`.`idcustomer`,`co`.`pax_data`,`c`.`first_name`,`c`.`last_name`,`c`.`country` AS `customer_country`,`c`.`city`,`c`.`doctype`,`c`.`docnum`,`c`.`gender`,`c`.`bdate`,`c`.`pbirth`,`cy`.`country_name`,".
527 "(SELECT `h`.`dt` FROM `#__vikbooking_orderhistory` AS `h` WHERE `h`.`idorder`=`o`.`id` AND `h`.`type`='RP' AND `h`.`descr`=".$this->dbo->quote($this->reportName)." ORDER BY `h`.`dt` DESC LIMIT 1) AS `history_last` ".
528 "FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_ordersrooms` AS `or` ON `or`.`idorder`=`o`.`id` ".
529 "LEFT JOIN `#__vikbooking_customers_orders` AS `co` ON `co`.`idorder`=`o`.`id` LEFT JOIN `#__vikbooking_customers` AS `c` ON `c`.`id`=`co`.`idcustomer` LEFT JOIN `#__vikbooking_countries` AS `cy` ON `cy`.`country_3_code`=`c`.`country` ".
530 "WHERE `o`.`status`='confirmed' AND `o`.`closure`=0 AND `o`.`checkin`>=".$from_ts." AND `o`.`checkin`<=".$to_ts." ".
531 "ORDER BY `o`.`checkin` ASC, `o`.`id` ASC;";
532 $this->dbo->setQuery($q);
533 $records = $this->dbo->loadAssocList();
534
535 if (!$records) {
536 $this->setError(JText::translate('VBOREPORTSERRNORESERV'));
537 return false;
538 }
539
540 //nest records with multiple rooms booked inside sub-array
541 $bookings = array();
542 foreach ($records as $v) {
543 if (!isset($bookings[$v['id']])) {
544 $bookings[$v['id']] = array();
545 }
546 // for bc, if the country is defined at booking level, set it also for the customer
547 if (empty($v['customer_country']) && !empty($v['country'])) {
548 $v['customer_country'] = $v['country'];
549 }
550 //calculate the from_ts and to_ts values for later comparison
551 $in_info = getdate($v['checkin']);
552 $out_info = getdate($v['checkout']);
553 $v['from_ts'] = mktime(0, 0, 0, $in_info['mon'], $in_info['mday'], $in_info['year']);
554 $v['to_ts'] = mktime(23, 59, 59, $out_info['mon'], ($out_info['mday'] - 1), $out_info['year']);
555 //
556 array_push($bookings[$v['id']], $v);
557 }
558
559 //define the columns of the report
560 $this->cols = array(
561 //Tipo alloggiato
562 array(
563 'key' => 'tipo',
564 'attr' => array(
565 'class="vbo-report-longlbl"'
566 ),
567 'label' => 'Tipo Alloggiato'
568 ),
569 //checkin
570 array(
571 'key' => 'checkin',
572 'attr' => array(
573 'class="center"'
574 ),
575 'sortable' => 1,
576 'label' => 'Arrivo'
577 ),
578
579 //cognome
580 array(
581 'key' => 'cognome',
582 'label' => JText::translate('VBTRAVELERLNAME')
583 ),
584 //nome
585 array(
586 'key' => 'nome',
587 'label' => JText::translate('VBTRAVELERNAME')
588 ),
589 //sesso
590 array(
591 'key' => 'gender',
592 'attr' => array(
593 'class="center"'
594 ),
595 'label' => JText::translate('VBCUSTOMERGENDER')
596 ),
597 //data di nascita
598 array(
599 'key' => 'dbirth',
600 'attr' => array(
601 'class="center"'
602 ),
603 'label' => JText::translate('VBCUSTOMERBDATE')
604 ),
605 //stato di nascita
606 array(
607 'key' => 'stabirth',
608 'attr' => array(
609 'class="center"'
610 ),
611 'label' => 'Stato Nascita'
612 ),
613 //comune di nascita
614 array(
615 'key' => 'combirth',
616 'attr' => array(
617 'class="center"'
618 ),
619 'label' => 'Comune Nascita'
620 ),
621 //cittadinanza
622 array(
623 'key' => 'citizen',
624 'attr' => array(
625 'class="center"'
626 ),
627 'label' => 'Cittadinanza'
628 ),
629 //stato di residenza
630 array(
631 'key' => 'stares',
632 'attr' => array(
633 'class="center"'
634 ),
635 'label' => 'Stato residenza'
636 ),
637 //comune di residenza
638 array(
639 'key' => 'comres',
640 'attr' => array(
641 'class="center"'
642 ),
643 'label' => 'Comune residenza'
644 ),
645 //checkout
646 array(
647 'key' => 'checkout',
648 'attr' => array(
649 'class="center"'
650 ),
651 'sortable' => 1,
652 'label' => 'Partenza'
653 ),
654 //occupazione (numero di camere prenotate)
655 array(
656 'key' => 'roomsbooked',
657 'attr' => array(
658 'class="center"'
659 ),
660 'sortable' => 1,
661 'label' => 'Occupazione',
662 'tip' => 'Questo valore indica il numero di camere occupate da ogni prenotazione, ed è un dato che verrà comunicato all\'ISTAT.',
663 ),
664 //camere (numero di camere totali)
665 array(
666 'key' => 'totrooms',
667 'attr' => array(
668 'class="center"'
669 ),
670 'sortable' => 1,
671 'label' => 'Camere',
672 'tip' => 'Questo valore indica il numero totale di camere nella tua struttura, ed è un dato che deve essere comunicato all\'ISTAT. Viene calcolato con una somma delle unità di tutte le camere attualmente Pubblicate nel sistema.',
673 ),
674 //IdSWH (identificativo posizione - we use the booking ID)
675 array(
676 'key' => 'idswh',
677 'attr' => array(
678 'class="center"'
679 ),
680 'sortable' => 1,
681 'label' => 'Codice IDSWH',
682 'tip' => 'Questo è il codice identificativo della trasmissione del dato verso l\'ISTAT, ed è uguale all\'ID della prenotazione nel sistema.',
683 'export_name' => 'IdSWH'
684 )
685 );
686
687 // total rooms units ("camere")
688 $total_rooms_units = $this->countRooms();
689
690 //loop over the bookings to build the rows of the report
691 foreach ($bookings as $gbook) {
692 $guests_rows = array($gbook[0]);
693 $tot_guests_rows = 1;
694
695 $tipo = 16;
696 // Codici Tipo Alloggiato
697 // 16 = Ospite Singolo
698 // 17 = Capofamiglia
699 // 18 = Capogruppo
700 // 19 = Familiare
701 // 20 = Membro Gruppo
702
703 $guestsnum = 0;
704 foreach ($gbook as $book) {
705 $guestsnum += $book['adults'] + $book['children'];
706 }
707
708 $country = '';
709 if (!empty($gbook[0]['country'])) {
710 $country = $gbook[0]['country'];
711 } elseif (!empty($gbook[0]['customer_country'])) {
712 $country = $gbook[0]['customer_country'];
713 }
714
715 // count the total number of guests for all rooms of this booking
716 $tot_booking_guests = 0;
717 $room_guests = array();
718 foreach ($gbook as $rbook) {
719 $tot_booking_guests += ($rbook['adults'] + $rbook['children']);
720 $room_guests[] = ($rbook['adults'] + $rbook['children']);
721 }
722
723 // make sure to decode the current pax data
724 if (!empty($gbook[0]['pax_data'])) {
725 $pax_data = json_decode($gbook[0]['pax_data'], true);
726 if (is_array($pax_data) && $pax_data) {
727 $guests_rows[0]['pax_data'] = $pax_data;
728 $tot_guests_rows = 0;
729 foreach ($pax_data as $roomguests) {
730 $tot_guests_rows += count($roomguests);
731 }
732 for ($i = 1; $i < $tot_guests_rows; $i++) {
733 array_push($guests_rows, $guests_rows[0]);
734 }
735 $tipo = count($guests_rows) > 1 ? 17 : $tipo;
736 }
737 }
738
739 $history_last = $gbook[0]['history_last'];
740 $tipo_provenienza = $this->guessTipoProvenienza($gbook[0]);
741
742 // create one row for each guest
743 $guest_ind = 1;
744 foreach ($guests_rows as $ind => $guests) {
745 // prepare row record for this room-guest
746 $insert_row = array();
747
748 // find the actual guest-room-index
749 $guest_room_ind = $this->calcGuestRoomIndex($room_guests, $guest_ind);
750
751 // determine the type of guest, either automatically or from the check-in pax data
752 $use_tipo = $ind > 0 && $tipo == 17 ? 19 : $tipo;
753 $pax_guest_type = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'guest_type');
754 $use_tipo = !empty($pax_guest_type) ? $pax_guest_type : $use_tipo;
755
756 /**
757 * Il calcolo dello stato di nascita è fatto qua per evitare che poi succeda casino col comune. (Belgio -> Belgioioso, vedi cliente)
758 * In questo modo, il calcolo dello stato di nascita permette di escludere poi la provincia di nascita in caso il cliente sia straniero.
759 *
760 * @since 1.4.1
761 *
762 * @see the updated integration of this report relies on drivers, and so such controls are no longer
763 * needed, if the pax data is collected through the back-end before launching the report.
764 */
765 $stabirth = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'country');
766 $stabirth = $stabirth || '';
767 $staval = $this->checkCountry($stabirth);
768
769 // Tipo Alloggiato
770 array_push($insert_row, array(
771 'key' => 'tipo',
772 'callback' => function($val) {
773 switch ($val) {
774 case 16:
775 return 'Ospite Singolo';
776 case 17:
777 return 'Capofamiglia';
778 case 18:
779 return 'Capogruppo';
780 case 19:
781 return 'Familiare';
782 case 20:
783 return 'Membro Gruppo';
784 }
785 return '?';
786 },
787 'callback_export' => function($val) {
788 return $val;
789 },
790 'value' => $use_tipo
791 ));
792
793 //Data Arrivo
794 array_push($insert_row, array(
795 'key' => 'checkin',
796 'attr' => array(
797 'class="center"'
798 ),
799 'callback' => function($val) {
800 return date('d/m/Y', $val);
801 },
802
803 'value' => $guests['checkin']
804 ));
805
806 // Cognome
807 $cognome = !empty($guests['t_last_name']) ? $guests['t_last_name'] : $guests['last_name'];
808 $pax_cognome = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'last_name');
809 $cognome = !empty($pax_cognome) ? $pax_cognome : $cognome;
810 array_push($insert_row, array(
811 'key' => 'cognome',
812 'value' => $cognome,
813 'callback_export' => function($val) {
814 return $val;
815 },
816 ));
817
818 //Nome
819 $nome = !empty($guests['t_first_name']) ? $guests['t_first_name'] : $guests['first_name'];
820 $pax_nome = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'first_name');
821 $nome = !empty($pax_nome) ? $pax_nome : $nome;
822 array_push($insert_row, array(
823 'key' => 'nome',
824 'value' => $nome,
825 'callback_export' => function($val) {
826 return $val;
827 },
828 ));
829
830 //Sesso
831 $gender = !empty($guests['gender']) && $guest_ind < 2 ? strtoupper($guests['gender']) : '';
832 $pax_gender = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'gender');
833 $gender = !empty($pax_gender) ? $pax_gender : $gender;
834 /**
835 * We make sure the gender will be compatible with both back-end and front-end
836 * check-in/registration data collection driver and processes.
837 *
838 * @since 1.15.0 (J) - 1.5.0 (WP)
839 */
840 if (is_numeric($gender)) {
841 $gender = (int)$gender;
842 } elseif (!strcasecmp($gender, 'F')) {
843 $gender = 2;
844 } elseif (!strcasecmp($gender, 'M')) {
845 $gender = 1;
846 }
847 array_push($insert_row, array(
848 'key' => 'gender',
849 'attr' => array(
850 'class="center'.(empty($gender) ? ' vbo-report-load-sesso' : '').'"'
851 ),
852 'callback' => function($val) {
853 return $val == 2 ? 'F' : ($val == 1 ? 'M' : '?');
854 },
855 'callback_export' => function($val) {
856 return $val == 2 ? 'F' : ($val == 1 ? 'M' : '?');
857 },
858 'value' => $gender
859 ));
860
861 //Data di nascita
862 $dbirth = !empty($guests['bdate']) && $guest_ind < 2 ? VikBooking::getDateTimestamp($guests['bdate'], 0, 0) : '';
863 $pax_dbirth = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'date_birth');
864 $dbirth = !empty($pax_dbirth) ? $pax_dbirth : $dbirth;
865 $dbirth = (strpos($dbirth, '/') === false && strpos($dbirth, VikBooking::getDateSeparator()) === false) ? $dbirth : VikBooking::getDateTimestamp($dbirth, 0, 0);
866 array_push($insert_row, array(
867 'key' => 'dbirth',
868 'attr' => array(
869 'class="center'.(empty($dbirth) ? ' vbo-report-load-dbirth' : '').'"'
870 ),
871 'callback' => function($val) {
872 if (!empty($val) && strpos($val, '/') === false && strpos($val, VikBooking::getDateSeparator()) === false) {
873 return date('d/m/Y', $val);
874 }
875 if (!empty($val) && strpos($val, '/') !== false) {
876 return $val;
877 }
878 return '?';
879 },
880 'value' => $dbirth
881 ));
882
883 /**
884 * Comune di nascita.
885 * Check compatibility with pax_data field of driver for "Italy".
886 */
887 $pax_comval = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'comune_b');
888
889 //if the country has been set and it's not "Italy", then don't let the user select Comune and Provincia.
890 $is_foreign = (empty($staval) || !isset($this->nazioni[$staval]) || strcasecmp($this->nazioni[$staval]['name'], 'ITALIA'));
891
892 // default value for "comune di nascita"
893 $combirth = !empty($guests['pbirth']) && $guest_ind < 2 && !$is_foreign ? strtoupper($guests['pbirth']) : '';
894
895 // assign the default value found from pax_data registration
896 $comval = $pax_comval;
897
898 $result = array();
899 if (empty($pax_comval)) {
900 $result = $this->sanitizeComune($combirth);
901 if (!empty($combirth) && $guest_ind < 2 && (!$is_foreign && !empty($staval)) ) {
902 //if $combirth has been sanitized, then you should just check if the province is the right one
903 if (isset($result['combirth'])) {
904 $result = $this->checkComune($result['combirth'], true, $result['province']);
905 } else {
906 $result = $this->checkComune($combirth, false, '');
907 }
908 $combirth = $result['combirth'];
909 }
910
911 if (!$is_foreign && !empty($staval)) {
912 $pax_combirth = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'place_birth');
913 $combirth = !empty($pax_combirth) ? strtoupper($pax_combirth) : $combirth;
914 $result = $this->sanitizeComune($combirth);
915 //If $combirth have been sanitized, then you should just check if the province is the right one
916 if (isset($result['combirth'])) {
917 $result = $this->checkComune($result['combirth'], true, $result['province']);
918 } else {
919 $result = $this->checkComune($combirth, false, '');
920 }
921 $comval = isset($result['comval']) ? $result['comval'] : $combirth;
922 }
923 }
924
925 /**
926 * Stato di nascita.
927 * Check compatibility with pax_data field of driver for "Italy".
928 */
929 $pax_country = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'country_b');
930
931 $staval = !empty($pax_country) ? $pax_country : $staval;
932 $stabirth = !empty($pax_country) ? $pax_country : $stabirth;
933
934 array_push($insert_row, array(
935 'key' => 'stabirth',
936 'attr' => array(
937 'class="center'.(empty($stabirth) ? ' vbo-report-load-nazione' : '').'"'
938 ),
939 'callback' => function($val) {
940 return (!empty($val) ? $this->nazioni[$val]['name'] : '?');
941 },
942 'no_export_callback' => 1,
943 'value' => $staval
944 ));
945
946 // se il comune di nascita è vuoto o è stato indovinato, allora aggiungi la classe. Altrimenti non rendere selezionabile il comune.
947 $comune = empty($combirth);
948 $comguessed = (isset($result['similar']) && $result['similar']);
949 $addclass = false;
950 if (empty($pax_comval) && ($comune || $comguessed)) {
951 if (empty($staval)) {
952 //se lo stato manca, comunque rendilo selezionabile, sia che sia vuoto, sia che sia stato "indovinato"
953 $addclass = true;
954 } elseif (!$is_foreign && !empty($staval)) {
955 //se lo stato esiste, ed è italiano, allora è selezionabile. Se è straniero, non farlo scegliere in quanto non necessario.
956 $addclass = true;
957 }
958 }
959 array_push($insert_row, array(
960 'key' => 'combirth',
961 'attr' => array(
962 'class="center'.($addclass ? ' vbo-report-load-comune' : '').'"'
963 ),
964 'callback' => function($val) use ($addclass) {
965 return !empty($val) && isset($this->comuniProvince['comuni'][$val]) ? $this->comuniProvince['comuni'][$val]['name'] : ($addclass ? '?' : "---");
966 },
967 'no_export_callback' => 1,
968 'value' => $comval
969 ));
970
971 /**
972 * Cittadinanza.
973 * Check compatibility with pax_data field of driver for "Italy".
974 */
975 $pax_country_c = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'country_c');
976
977 $citizen = !empty($guests['country']) && $guest_ind < 2 ? $guests['country'] : '';
978 $citizenval = '';
979 if (!empty($citizen) && $guest_ind < 2) {
980 $citizenval = $this->checkCountry($citizen);
981 }
982
983 // check nationality field from pre-checkin
984 $pax_citizen = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'nationality');
985 $citizen = !empty($pax_citizen) ? $pax_citizen : $citizen;
986
987 $citizen = !empty($pax_country_c) ? $pax_country_c : $citizen;
988 $citizenval = !empty($pax_country_c) ? $pax_country_c : $this->checkCountry($citizen);
989
990 array_push($insert_row, array(
991 'key' => 'citizen',
992 'attr' => array(
993 'class="center'.(empty($citizen) ? ' vbo-report-load-cittadinanza' : '').'"'
994 ),
995 'callback' => function($val) {
996 return !empty($val) ? $this->nazioni[$val]['name'] : '?';
997 },
998 'no_export_callback' => 1,
999 'value' => !empty($citizenval) ? $citizenval : ''
1000 ));
1001
1002
1003
1004 // TODO go ahead
1005
1006
1007 /**
1008 * Stato di residenza.
1009 * Check compatibility with pax_data field of driver for "Italy".
1010 */
1011 $pax_provstay = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'country_s');
1012 array_push($insert_row, array(
1013 'key' => 'stares',
1014 'attr' => array(
1015 'class="center'.(empty($pax_provstay) && $guest_ind < 2 ? ' vbo-report-load-nazioneres' : '').'"'
1016 ),
1017 'callback' => function($val) use ($guest_ind) {
1018 if ($guest_ind > 1) {
1019 // not needed for the Nth guest
1020 return "---";
1021 }
1022 if (!empty($val) && isset($this->nazioni[$val])) {
1023 return $this->nazioni[$val]['name'];
1024 }
1025 // information is missing and should be provided
1026 return '?';
1027 },
1028 'no_export_callback' => 1,
1029 'value' => $pax_provstay,
1030 ));
1031
1032 /**
1033 * Comune di residenza.
1034 * Check compatibility with pax_data field of driver for "Italy".
1035 */
1036 $pax_comstay = $this->getGuestPaxDataValue($guests['pax_data'], $room_guests, $guest_ind, 'comune_s');
1037 array_push($insert_row, array(
1038 'key' => 'comres',
1039 'attr' => array(
1040 'class="center'.(empty($pax_comstay) && $guest_ind < 2 ? ' vbo-report-load-comuneres' : '').'"'
1041 ),
1042 'callback' => function($val) use ($guest_ind) {
1043 if ($guest_ind > 1) {
1044 // not needed for the Nth guest
1045 return "---";
1046 }
1047 if (!empty($val) && isset($this->comuniProvince['comuni'][$val])) {
1048 return $this->comuniProvince['comuni'][$val]['name'];
1049 }
1050 // information is missing and should be provided
1051 return '?';
1052 },
1053 'no_export_callback' => 1,
1054 'value' => $pax_comstay,
1055 ));
1056
1057 // check-out
1058 array_push($insert_row, array(
1059 'key' => 'checkout',
1060 'attr' => array(
1061 'class="center"'
1062 ),
1063 'callback' => function($val) {
1064 return date('d/m/Y', $val);
1065 },
1066 'value' => $gbook[0]['checkout']
1067 ));
1068
1069 //Camere prenotate
1070 array_push($insert_row, array(
1071 'key' => 'roomsbooked',
1072 'attr' => array(
1073 'class="center"'
1074 ),
1075 'value' => count($gbook),
1076 'callback_export' => function($val) {
1077 return $val;
1078 },
1079 ));
1080
1081 // Totale camere
1082 array_push($insert_row, array(
1083 'key' => 'totrooms',
1084 'attr' => array(
1085 'class="center"'
1086 ),
1087 'value' => $total_rooms_units,
1088 'callback_export' => function($val) {
1089 return $val;
1090 },
1091 ));
1092
1093 //id booking
1094 array_push($insert_row, array(
1095 'key' => 'idbooking',
1096 'attr' => array(
1097 'class="center"'
1098 ),
1099 'callback' => function($val) {
1100 return '<a href="index.php?option=com_vikbooking&task=editorder&cid[]='.$val.'" target="_blank"><i class="'.VikBookingIcons::i('external-link').'"></i> '.$val.'</a>';
1101 },
1102 'callback_export' => function($val) {
1103 return $val;
1104 },
1105 'value' => $guests['id']
1106 ));
1107
1108 // push fields in the rows array as a new row
1109 array_push($this->rows, $insert_row);
1110
1111 // increment guest index
1112 $guest_ind++;
1113 }
1114 }
1115
1116 // sort rows
1117 $this->sortRows($pkrsort, $pkrorder);
1118
1119 // the footer row will just print the amount of records to export
1120 array_push($this->footerRow, array(
1121 array(
1122 'attr' => array(
1123 'class="vbo-report-total"'
1124 ),
1125 'value' => '<h3>'.JText::translate('VBOREPORTSTOTALROW').'</h3>'
1126 ),
1127 array(
1128 'attr' => array(
1129 'colspan="'.(count($this->cols) - 1).'"'
1130 ),
1131 'value' => count($this->rows)
1132 )
1133 ));
1134
1135 // Debug
1136 if ($this->debug) {
1137 $this->setWarning('path to report file = '.urlencode(dirname(__FILE__)).'<br/>');
1138 $this->setWarning('$total_rooms_units = '.$total_rooms_units.'<br/>');
1139 $this->setWarning('$bookings:<pre>'.print_r($bookings, true).'</pre><br/>');
1140 }
1141
1142 return true;
1143 }
1144
1145 /**
1146 * Attempts to guess the column 'tipo' (provenienza)
1147 * depending on the country and city given. For Italians,
1148 * the name of the region is returned (if any, given the city).
1149 * For foreigners, the country type is returned.
1150 *
1151 * @param array the booking record
1152 *
1153 * @return mixed string to use for the column 'tipo', -1 if empty.
1154 */
1155 protected function guessTipoProvenienza($booking)
1156 {
1157 if (empty($booking['customer_country'])) {
1158 // unable to proceed when the country is missing (-1).
1159 return -1;
1160 }
1161
1162 // uppercase 3-char code of the country only
1163 $country3 = substr(strtoupper($booking['customer_country']), 0, 3);
1164
1165 if ($country3 == 'ITA') {
1166 // Italian customer
1167 if (!empty($booking['city'])) {
1168 foreach ($this->map_regioni_prov as $tipo => $cities) {
1169 foreach ($cities as $city) {
1170 if (stripos($city, $booking['city']) !== false) {
1171 // region was found
1172 return $tipo;
1173 }
1174 }
1175 }
1176 }
1177 // empty city or no city found in the map
1178 return -1;
1179 }
1180
1181 // foreigner customer
1182 if (isset($this->map_country_codes[$country3])) {
1183 // country name found for 'tipo' column
1184 return $this->map_country_codes[$country3];
1185 }
1186 // check the 'country_name' in 'other countries'
1187 if (!empty($booking['country_name'])) {
1188 foreach ($this->map_country_others as $tipo => $countries) {
1189 if (stripos($countries, $booking['country_name']) !== false) {
1190 // the name of the country taken from the 3-char code matches with an 'other country'. Guessing makes sense.
1191 return $tipo;
1192 }
1193 }
1194 }
1195
1196 // nothing found
1197 return -1;
1198 }
1199
1200 /**
1201 * Generates the report columns and rows, then it outputs a CSV file
1202 * for download. In case of errors, the process is not terminated (exit)
1203 * to let the View display the error message.
1204 * We use customExport() rather than exportCSV() only because we need a
1205 * different download button rather than the classic "Export as CSV".
1206 *
1207 * @param int $export_type the view will pass this argument to the method to call different types of export.
1208 *
1209 * @return mixed void on success with script termination, false otherwise.
1210 */
1211 public function customExport($export_type = 0)
1212 {
1213 if (!$this->getReportData()) {
1214 return false;
1215 }
1216
1217 // manual values in filler
1218 $pfiller = VikRequest::getString('filler', '', 'request', VIKREQUEST_ALLOWRAW);
1219 $pfiller = !empty($pfiller) ? json_decode($pfiller, true) : array();
1220 $pfiller = !is_array($pfiller) ? array() : $pfiller;
1221 $records = array();
1222
1223 $q = "SELECT SUM(`units`) AS `sommaunita`, SUM(`totpeople`) AS `numeropersone`, COUNT(*) AS `numerocamere` FROM `#__vikbooking_rooms` WHERE `avail`= '1';";
1224 $this->dbo->setQuery($q);
1225 $this->dbo->execute();
1226 if ($this->dbo->getNumRows() > 0) {
1227 $records = $this->dbo->loadAssocList();
1228 }
1229 $totalBeds =(int) ($records[0]['sommaunita'] * ($records[0]['numeropersone']/$records[0]['numerocamere']));
1230 $pletti = VikRequest::getString('numletti', $totalBeds, 'request');
1231
1232 //Debug
1233 if ($this->debug) {
1234 $this->setError('<pre>'.print_r($pfiller, true).'</pre><br/>');
1235 return false;
1236 }
1237
1238 //map of the rows keys with their related length
1239 $keys_length_map = array(
1240 'tipo' => 2,
1241 'checkin' => 10,
1242 'cognome' => 50,
1243 'nome' => 30,
1244 'gender' => 1,
1245 'dbirth' => 10,
1246 'combirth' => 9,
1247 'probirth' => 2,
1248 'stabirth' => 9,
1249 'citizen' => 9,
1250 'comres' => 9,
1251 'prores' => 2,
1252 'stares' => 9,
1253 'checkout' => 10,
1254 'roomsbooked' => 3,
1255 'totrooms' => 3,
1256 'pletti' => 4,
1257 'idbooking' => 10,
1258 'tassasogg' => 1, //blank
1259 'turi' => 30, //blank
1260 'trasp' => 30, //blank
1261 );
1262 $keys_blank_map = array(
1263 'ind' => 50, //blank
1264 'doc' => 5, //blank
1265 'luogodoc' => 20, //blank
1266 'stdoc' => 9, //blank
1267 );
1268 $txt = '';
1269 // I need it to determine if I need the province or not
1270 $italia = false;
1271 $blank = false;
1272
1273 //I need it since I need to save the nation later than the province, so I need to store it somewhere
1274 $nation = '';
1275 foreach ($this->rows as $ind => $row) {
1276 $italia = false;
1277 $nation = '';
1278 $blank = false;
1279 foreach ($row as $field) {
1280 if (isset($field['ignore_export'])) {
1281 continue;
1282 }
1283 // check if a value for this field was filled in manually
1284 if (is_array($pfiller) && isset($pfiller[$ind]) && isset($pfiller[$ind][$field['key']])) {
1285 if (strlen($pfiller[$ind][$field['key']])) {
1286 $field['value'] = $pfiller[$ind][$field['key']];
1287 }
1288 }
1289
1290 // values set to -1 are usually empty and should have been filled in manually
1291 if ($field['value'] === -1) {
1292 // we raise an error in this case without stopping the process
1293 $field['value'] = 0;
1294 VikError::raiseWarning('', 'La riga #'.$ind.' ha un valore vuoto che doveva essere riempito manualmente cliccando sul blocco in rosso. Il file potrebbe contenere valori invalidi per questa riga.');
1295 }
1296
1297 if (isset($field['callback_export'])) {
1298 $field['callback'] = $field['callback_export'];
1299 }
1300 $export_value = !isset($field['no_export_callback']) && isset($field['callback']) && is_callable($field['callback']) ? $field['callback']($field['value']) : $field['value'];
1301
1302 //controllo la nazione
1303 if ($field['key'] == 'stabirth' || $field['key'] == 'stares') {
1304
1305 //se italia imposto il flag a true per prendere anche comuni e province dopo
1306 if ($export_value == '100000100'){
1307 $italia = true;
1308 }
1309 $nation = $this->valueFiller($export_value, $keys_length_map[$field['key']]);
1310 if ($field['key'] == 'stares'){
1311 $blank = true;
1312 }
1313 continue;
1314 }
1315
1316 //controllo su comuni e province:
1317 //se è italiano, allora prendo provincia e comune
1318 //se è straniero, riempio con gli spazi
1319 if ($field['key'] == 'combirth' || $field['key'] == 'comres') {
1320 if ($italia){
1321 //E4J Debug
1322 //echo '<pre>' . print_r("ITALIA", true) . '</pre>';
1323 foreach ($this->comuniProvince['province'] as $provs => $pname) {
1324
1325 if ($export_value == $provs) {
1326 $export_value = $this->valueFiller($export_value, 9);
1327 //echo '<pre> LUNGHEZZA COMUNE ITALIANO: ' .$field['key'] . strlen($export_value) . '</pre>';
1328
1329 $txt .= $export_value.$this->valueFiller($pname, 2);
1330 //echo '<pre> LUNGHEZZA: ' . strlen($export_value) . '</pre>';
1331 }
1332 }
1333 } else {
1334 $temp = $this->valueFiller(' ', 9);
1335 //echo '<pre> LUNGHEZZA ' .$field['key'] .' = '. strlen($temp) . '</pre>';
1336
1337 $txt .= $temp.' ';
1338 }
1339 $txt .= $nation;
1340 //E4J Debug
1341 //echo '<pre>' .strlen($txt). '</pre>';
1342
1343 //se sono arrivato allo stato di residenza, devo inserire tutti i campi vuoti con gli spazi
1344 if($blank){
1345 foreach ($keys_blank_map as $key => $value) {
1346 $txt.= $this->valueFiller('', $value);
1347 //E4J Debug
1348 //echo '<pre>' .strlen($txt). '</pre>';
1349 }
1350 }
1351 continue;
1352 }
1353
1354 $export_value = $this->valueFiller($export_value, $keys_length_map[$field['key']]);
1355 //echo '<pre> LUNGHEZZA POST MODIFICA: ' . strlen($export_value) . '</pre>';
1356
1357 //riempio i campi vuoti mancanti
1358 if ($field['key'] == 'totrooms') {
1359 $export_value .= $this->valueFiller($pletti, $keys_length_map['pletti']).' ';
1360 }
1361
1362 if ($field['key'] == 'checkout') {
1363 $export_value .= $this->valueFiller(' ', $keys_length_map['turi']). $this->valueFiller(' ', $keys_length_map['trasp']);
1364 }
1365
1366 if ($field['key'] != "idbooking") {
1367 $txt .= $export_value;
1368 } else {
1369 $txt .= $export_value."1\r\n";
1370 }
1371 }
1372 }
1373
1374 /**
1375 * Custom export method supports a custom export handler, if previously set.
1376 *
1377 * @since 1.16.1 (J) - 1.6.1 (WP)
1378 */
1379 if ($this->hasExportHandler()) {
1380 // write data onto the custom file handler
1381 $fp = $this->getExportCSVHandler();
1382 fwrite($fp, $txt);
1383 fclose($fp);
1384
1385 return true;
1386 }
1387
1388 // force text file download
1389 header("Content-type: text/plain");
1390 header("Cache-Control: no-store, no-cache");
1391 header('Content-Disposition: attachment; filename="' . $this->getExportCSVFileName() . '"');
1392 echo $txt;
1393
1394 exit;
1395 }
1396
1397 /**
1398 * Registers the name to give to the file being exported.
1399 *
1400 * @return void
1401 *
1402 * @since 1.16.1 (J) - 1.6.1 (WP)
1403 */
1404 protected function registerExportFileName()
1405 {
1406 $pfromdate = VikRequest::getString('fromdate', '', 'request');
1407 $ptodate = VikRequest::getString('todate', '', 'request');
1408 $pcodstru = VikRequest::getString('codstru', '', 'request');
1409
1410 $this->setExportCSVFileName($pcodstru . '-' . str_replace('/', '_', $pfromdate) . '-' . str_replace('/', '_', $ptodate) . '.txt');
1411 }
1412
1413 /**
1414 * Parses the file Comuni.csv and returns two associative
1415 * arrays: one for the Comuni and one for the Province.
1416 * Every line of the CSV is composed of: Codice, Comune, Provincia.
1417 *
1418 * @return array
1419 */
1420 protected function loadComuniProvince()
1421 {
1422 $comprov_codes = array(
1423 'comuni' => array(
1424 0 => '-- Estero --'
1425 ),
1426 'province' => array(
1427 0 => '-- Estero --'
1428 )
1429 );
1430
1431 $csv = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Comuni.csv';
1432 $rows = file($csv);
1433 foreach ($rows as $row) {
1434 if (empty($row)) {
1435 continue;
1436 }
1437
1438 $v = explode(';', $row);
1439 if (count($v) != 3) {
1440 continue;
1441 }
1442
1443 // trim values
1444 $v[0] = trim($v[0]);
1445 $v[1] = trim($v[1]);
1446 $v[2] = trim($v[2]);
1447
1448 if (!isset($comprov_codes['comuni'][$v[0]])) {
1449 $comprov_codes['comuni'][$v[0]] = array();
1450 }
1451
1452 $comprov_codes['comuni'][$v[0]]['name'] = $v[1];
1453 $comprov_codes['comuni'][$v[0]]['province'] = $v[2];
1454 $comprov_codes['province'][$v[2]] = $v[2];
1455 }
1456
1457 return $comprov_codes;
1458 }
1459
1460 /**
1461 * Parses the file Nazioni.csv and returns an associative
1462 * array with the code and name of the Nazione.
1463 * Every line of the CSV is composed of: Codice, Nazione.
1464 *
1465 * @return array
1466 */
1467 protected function loadNazioni()
1468 {
1469 $nazioni = array();
1470
1471 $csv = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Nazioni.csv';
1472 $rows = file($csv);
1473 foreach ($rows as $row) {
1474 if (empty($row)) {
1475 continue;
1476 }
1477
1478 $v = explode(';', $row);
1479 if (count($v) != 3) {
1480 continue;
1481 }
1482
1483 $nazioni[$v[0]]['name'] = $v[1];
1484 $nazioni[$v[0]]['three_code'] = $v[2];
1485 }
1486
1487 return $nazioni;
1488 }
1489
1490 /**
1491 * This method adds blank spaces to the string
1492 * until the passed length of string is reached.
1493 *
1494 * @param string $val
1495 * @param int $len
1496 *
1497 * @return string
1498 */
1499 protected function valueFiller($val, $len)
1500 {
1501 $len = empty($len) || (int)$len <= 0 ? strlen($val) : (int)$len;
1502
1503 //clean up $val in case there is still a CR or LF
1504 $val = str_replace(array("\r\n", "\r", "\n"), '', $val);
1505 //
1506
1507 if (strlen($val) < $len) {
1508 while (strlen($val) < $len) {
1509 $val .= ' ';
1510 }
1511 } elseif (strlen($val) > $len) {
1512 $val = substr($val, 0, $len);
1513 }
1514
1515 return $val;
1516 }
1517
1518 protected function loadCss() {
1519 ?>
1520 <style>
1521 .select2-results__option {
1522 padding-left: 20px !important;
1523 }
1524
1525 </style>
1526 <?php
1527 }
1528
1529 /**
1530 * Returns an array that contains both name and key of the comune
1531 * selected, plus the associated province.
1532 *
1533 * @deprecated 1.5.0 there is no need to rely on this method.
1534 *
1535 * @return array
1536 */
1537 protected function checkComune($combirth, $checked, $province) {
1538 $result = array();
1539 $first_found = '';
1540 if (!count($this->comuniProvince)) {
1541 $this->comuniProvince = $this->loadComuniProvince();
1542 }
1543 if (empty($combirth)) {
1544 return $result;
1545 }
1546 foreach ($this->comuniProvince['comuni'] as $key => $value) {
1547 if (!isset($value['name'])) {
1548 continue;
1549 }
1550 if ($value['name'] == $combirth) {
1551 $result['found'] = true;
1552 $result['combirth'] = $value['name'];
1553 $result['province'] = $value['province'];
1554 $result['comval'] = $key;
1555 $result['similar'] = false;
1556 break;
1557 } else if (strpos($value['name'], trim($combirth)) !== false && empty($first_found)) {
1558 $result['found'] = true;
1559 $result['combirth'] = $value['name'];
1560 $first_found = $key;
1561 $result['similar'] = true;
1562 $result['province'] = $value['province'];
1563 }
1564 }
1565 if (!$result['found']) {
1566 $result['combirth'] = '';
1567 }
1568
1569 if ($checked === true && strlen($province) > 0 && $result['found']) {
1570 $result['province'] = $province;
1571 if($province == $value['province']) {
1572 $result['provinceok'] = true;
1573 $result['province'] = $province;
1574 } else {
1575 $result['provinceok'] = false;
1576 }
1577 }
1578 if ($result['similar'] && $result['found']) {
1579 $result['comval'] = $first_found;
1580 }
1581
1582 return $result;
1583 }
1584
1585 /**
1586 * Returns the key of the state selected by the user.
1587 *
1588 * @deprecated 1.5.0 there is no need to rely on this method.
1589 *
1590 * @return string
1591 */
1592 protected function checkCountry($country) {
1593 $found = false;
1594 $staval = '';
1595 if (!count($this->nazioni)) {
1596 $this->nazioni = $this->loadNazioni();
1597 }
1598 foreach ($this->nazioni as $key => $value) {
1599 if (trim($value['three_code']) == trim($country)) {
1600 $staval = $key;
1601 $found = true;
1602 break;
1603 }
1604 }
1605 if ($found !== true) {
1606 $staval = '';
1607 }
1608 return $staval;
1609 }
1610
1611 /**
1612 * Sanitizes the "Comune" if value also contains also the province. Example "PRATO (PO)".
1613 *
1614 * @deprecated 1.5.0 there is no need to rely on this method.
1615 *
1616 * @param string $combirth the current value to check.
1617 *
1618 * @return array empty array or comune/province info.
1619 */
1620 protected function sanitizeComune($combirth)
1621 {
1622 if (empty($combirth)) {
1623 return array();
1624 }
1625
1626 $result = array();
1627
1628 if (strlen($combirth) > 2) {
1629 if (strpos($combirth, "(") !== false) {
1630 $comnas = explode("(", $combirth);
1631 $result['combirth'] = trim($comnas[0]);
1632 $result['province'] = $comnas[1];
1633 $result['province'] = str_replace(')', '', $result['province']);
1634 }
1635 } elseif(strlen($combirth) > 0) {
1636 $result['province'] = trim($combirth);
1637 $result['similar'] = true;
1638 }
1639
1640 return $result;
1641 }
1642
1643 /**
1644 * Helper method to quickly get a pax_data property for the guest.
1645 *
1646 * @param array $pax_data the current pax_data stored.
1647 * @param array $guests list of total guests per room.
1648 * @param int $guest_ind the guest index.
1649 * @param string $key the pax_data key to look for.
1650 *
1651 * @return mixed null on failure or value fetched.
1652 *
1653 * @since 1.16.1 (J) - 1.6.1 (WP)
1654 */
1655 protected function getGuestPaxDataValue($pax_data, $guests, $guest_ind, $key)
1656 {
1657 if (!is_array($pax_data) || !count($pax_data) || empty($key)) {
1658 return null;
1659 }
1660
1661 // find room index for this guest number
1662 $room_num = 0;
1663 $use_guest_ind = $guest_ind;
1664 foreach ($guests as $room_index => $room_tot_guests) {
1665 // find the proper guest index for the room to which this belongs
1666 if ($use_guest_ind <= $room_tot_guests) {
1667 // proper room index found for this guest
1668 $room_num = $room_index;
1669 break;
1670 } else {
1671 // it's probably in a next room
1672 $use_guest_ind -= $room_tot_guests;
1673 }
1674 }
1675
1676 // check if a value exists for the requested key in the found room and guest indexes
1677 if (isset($pax_data[$room_num]) && isset($pax_data[$room_num][$use_guest_ind])) {
1678 if (isset($pax_data[$room_num][$use_guest_ind][$key])) {
1679 // we've got a value previously stored
1680 return $pax_data[$room_num][$use_guest_ind][$key];
1681 }
1682 }
1683
1684 // nothing was found
1685 return null;
1686 }
1687
1688 /**
1689 * Helper method to determine the exact number for this guest in the room booked.
1690 *
1691 * @param array $guests list of total guests per room.
1692 * @param int $guest_ind the guest index.
1693 *
1694 * @return int the actual guest room index starting from 1.
1695 *
1696 * @since 1.16.1 (J) - 1.6.1 (WP)
1697 */
1698 protected function calcGuestRoomIndex($guests, $guest_ind)
1699 {
1700 // find room index for this guest number
1701 $room_num = 0;
1702 $use_guest_ind = $guest_ind;
1703 foreach ($guests as $room_index => $room_tot_guests) {
1704 // find the proper guest index for the room to which this belongs
1705 if ($use_guest_ind <= $room_tot_guests) {
1706 // proper room index found for this guest
1707 $room_num = $room_index;
1708 break;
1709 } else {
1710 // it's probably in a next room
1711 $use_guest_ind -= $room_tot_guests;
1712 }
1713 }
1714
1715 return $use_guest_ind;
1716 }
1717 }
1718