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

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

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