| 1 |
<?php |
| 2 |
/** |
| 3 |
* @package VikBooking |
| 4 |
* @subpackage com_vikbooking |
| 5 |
* @author Alessio Gaggii - E4J srl |
| 6 |
* @copyright Copyright (C) 2024 E4J srl. All rights reserved. |
| 7 |
* @license GNU General Public License version 2 or later; see LICENSE |
| 8 |
* @link https://vikwp.com |
| 9 |
*/ |
| 10 |
|
| 11 |
defined('ABSPATH') or die('No script kiddies please!'); |
| 12 |
|
| 13 |
/** |
| 14 |
* ISTAT ROSS 1000 è valido per diverse regioni. Sicuramente per la Romagna, Veneto e Piemonte. |
| 15 |
* Sviluppato e mantenuto da GIES (Repubblica di San Marino). Simile a SITRA. Il sistema |
| 16 |
* supporta diversi URL regionali/cittadini per l'eventuale trasmissione a mezzo WSDL. |
| 17 |
* |
| 18 |
* @link Piemonte https://piemontedatiturismo.regione.piemonte.it/ws/checkinV2?wsdl |
| 19 |
* @link Città Metropolitana di Firenze https://turismo5firenze.regione.toscana.it/ws/checkinV2?wsdl |
| 20 |
* @link Provincia di Pistoia https://turismo5pistoia.regione.toscana.it/ws/checkinV2?wsdl |
| 21 |
* @link Provincia di Prato https://turismo5prato.regione.toscana.it/ws/checkinV2?wsdl |
| 22 |
* @link Abruzzo https://app.regione.abruzzo.it/Turismo5/ws/checkinV2?wsdl |
| 23 |
* @link Veneto https://flussituristici.regione.veneto.it/ws/checkinV2?wsdl |
| 24 |
* @link Emilia-Romagna https://datiturismo.regione.emilia-romagna.it/ws/checkinV2?wsdl |
| 25 |
* @link Marche https://istrice-ross1000.turismo.marche.it/ws/checkinV2?wsdl |
| 26 |
* @link Lombardia https://www.flussituristici.servizirl.it/Turismo5/app/ws/checkinV2?wsdl |
| 27 |
* @link Calabria https://sirdat.regione.calabria.it/ws/checkinV2?wsdl |
| 28 |
* @link Sardegna https://sardegnaturismo.ross1000.it/ws/checkinV2?wsdl |
| 29 |
* @link Lazio https://lazioturismo.ross1000.it/ws/checkinV2?wsdl |
| 30 |
* |
| 31 |
* @link https://web.gies.sm/cc_allegati/ross1000/Tracciato_XML-WEBSERVICE-2.4.pdf |
| 32 |
* |
| 33 |
* @since 1.15.4 (J) - 1.5.10 (WP) report introduced. |
| 34 |
* @since 1.17.2 (J) - 1.7.2 (WP) report refactoring with settings and custom scoped actions. |
| 35 |
*/ |
| 36 |
class VikBookingReportIstatRoss1000 extends VikBookingReport |
| 37 |
{ |
| 38 |
/** |
| 39 |
* Property 'defaultKeySort' is used by the View that renders the report. |
| 40 |
*/ |
| 41 |
public $defaultKeySort = 'idbooking'; |
| 42 |
|
| 43 |
/** |
| 44 |
* Property 'defaultKeyOrder' is used by the View that renders the report. |
| 45 |
*/ |
| 46 |
public $defaultKeyOrder = 'ASC'; |
| 47 |
|
| 48 |
/** |
| 49 |
* Property 'customExport' is used by the View to display custom export buttons. |
| 50 |
*/ |
| 51 |
public $customExport = ''; |
| 52 |
|
| 53 |
/** |
| 54 |
* List of municipality and provinces. |
| 55 |
* |
| 56 |
* @var array |
| 57 |
*/ |
| 58 |
protected $comuniProvince = []; |
| 59 |
|
| 60 |
/** |
| 61 |
* List of country codes. |
| 62 |
* |
| 63 |
* @var array |
| 64 |
*/ |
| 65 |
protected $nazioni = []; |
| 66 |
|
| 67 |
/** |
| 68 |
* Indicates if no bookings were found for the requested dates. |
| 69 |
* |
| 70 |
* @var bool |
| 71 |
*/ |
| 72 |
protected $datesHaveNoBookings = false; |
| 73 |
|
| 74 |
/** |
| 75 |
* List of tourism type codes. |
| 76 |
* |
| 77 |
* @var array |
| 78 |
*/ |
| 79 |
protected $tourismTypes = [ |
| 80 |
'CULTURALE' => 'Culturale', |
| 81 |
'BALNEARE' => 'Balneare', |
| 82 |
'CONGRESSUALE/AFFARI' => 'Congressuale/Affari', |
| 83 |
'FIERISTICO' => 'Fieristico', |
| 84 |
'SPORTIVO/FITNESS' => 'Sportivo/Fitness', |
| 85 |
'SCOLASTICO' => 'Scolastico', |
| 86 |
'RELIGIOSO' => 'Religioso', |
| 87 |
'SOCIALE' => 'Sociale', |
| 88 |
'PARCHI TEMATICI' => 'Parchi Tematici', |
| 89 |
'TERMALE/TRATTAMENTI SALUTE' => 'Termale/Trattamenti salute', |
| 90 |
'ENOGASTRONOMICO' => 'Enogastronomico', |
| 91 |
'CICLOTURISMO' => 'Cicloturismo', |
| 92 |
'ESCURSIONISTICO/NATURALISTICO' => 'Escursionistico/Naturalistico', |
| 93 |
'ALTRO MOTIVO' => 'Altro motivo', |
| 94 |
'NON SPECIFICATO' => 'Non specificato', |
| 95 |
]; |
| 96 |
|
| 97 |
/** |
| 98 |
* List of meanings of transport codes. |
| 99 |
* |
| 100 |
* @var array |
| 101 |
*/ |
| 102 |
protected $meaningsOfTransport = [ |
| 103 |
'AUTO' => 'Auto', |
| 104 |
'AEREO' => 'Aereo', |
| 105 |
'AEREO+PULLMAN' => 'Aereo+Pullman', |
| 106 |
'AEREO+NAVETTA/TAXI/AUTO' => 'Aereo+Navetta/Taxi/Auto', |
| 107 |
'AEREO+TRENO' => 'Aereo+Treno', |
| 108 |
'TRENO' => 'Treno', |
| 109 |
'PULLMAN' => 'Pullman', |
| 110 |
'CARAVAN/AUTOCARAVAN' => 'Caravan/Autocaravan', |
| 111 |
'BARCA/NAVE/TRAGHETTO' => 'Barca/Nave/Traghetto', |
| 112 |
'MOTO' => 'Moto', |
| 113 |
'BICICLETTA' => 'Bicicletta', |
| 114 |
'A PIEDI' => 'A piedi', |
| 115 |
'ALTRO MOTIVO' => 'Altro motivo', |
| 116 |
'NON SPECIFICATO' => 'Non specificato', |
| 117 |
]; |
| 118 |
|
| 119 |
/** |
| 120 |
* List of booking IDs affected by the export. |
| 121 |
* |
| 122 |
* @var array |
| 123 |
*/ |
| 124 |
protected $export_booking_ids = []; |
| 125 |
|
| 126 |
/** |
| 127 |
* List of exported check-in dates (range). |
| 128 |
* |
| 129 |
* @var array |
| 130 |
*/ |
| 131 |
protected $exported_checkin_dates = []; |
| 132 |
|
| 133 |
/** |
| 134 |
* Class constructor should define the name of the report and |
| 135 |
* other vars. Call the parent constructor to define the DB object. |
| 136 |
*/ |
| 137 |
public function __construct() |
| 138 |
{ |
| 139 |
$this->reportFile = basename(__FILE__, '.php'); |
| 140 |
$this->reportName = JText::translate('ISTAT Ross 1000'); |
| 141 |
$this->reportFilters = []; |
| 142 |
|
| 143 |
$this->cols = []; |
| 144 |
$this->rows = []; |
| 145 |
$this->footerRow = []; |
| 146 |
|
| 147 |
$this->registerExportFileName(); |
| 148 |
|
| 149 |
parent::__construct(); |
| 150 |
} |
| 151 |
|
| 152 |
/** |
| 153 |
* Returns the name of this report. |
| 154 |
* |
| 155 |
* @return string |
| 156 |
*/ |
| 157 |
public function getName() |
| 158 |
{ |
| 159 |
return $this->reportName; |
| 160 |
} |
| 161 |
|
| 162 |
/** |
| 163 |
* Returns the name of this file without .php. |
| 164 |
* |
| 165 |
* @return string |
| 166 |
*/ |
| 167 |
public function getFileName() |
| 168 |
{ |
| 169 |
return $this->reportFile; |
| 170 |
} |
| 171 |
|
| 172 |
/** |
| 173 |
* @inheritDoc |
| 174 |
* |
| 175 |
* @since 1.18.0 (J) - 1.8.0 (WP) |
| 176 |
*/ |
| 177 |
public function allowsProfileSettings() |
| 178 |
{ |
| 179 |
// allow multiple report profile settings |
| 180 |
return true; |
| 181 |
} |
| 182 |
|
| 183 |
/** |
| 184 |
* @inheritDoc |
| 185 |
* |
| 186 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 187 |
*/ |
| 188 |
public function getSettingFields() |
| 189 |
{ |
| 190 |
$example_urls = [ |
| 191 |
[ |
| 192 |
'name' => 'Piemonte', |
| 193 |
'url' => 'https://piemontedatiturismo.regione.piemonte.it/ws/checkinV2?wsdl', |
| 194 |
], |
| 195 |
[ |
| 196 |
'name' => 'Città Metropolitana di Firenze', |
| 197 |
'url' => 'https://turismo5firenze.regione.toscana.it/ws/checkinV2?wsdl', |
| 198 |
], |
| 199 |
[ |
| 200 |
'name' => 'Provincia di Pistoia', |
| 201 |
'url' => 'https://turismo5pistoia.regione.toscana.it/ws/checkinV2?wsdl', |
| 202 |
], |
| 203 |
[ |
| 204 |
'name' => 'Provincia di Prato', |
| 205 |
'url' => 'https://turismo5prato.regione.toscana.it/ws/checkinV2?wsdl', |
| 206 |
], |
| 207 |
[ |
| 208 |
'name' => 'Abruzzo', |
| 209 |
'url' => 'https://app.regione.abruzzo.it/Turismo5/ws/checkinV2?wsdl', |
| 210 |
], |
| 211 |
[ |
| 212 |
'name' => 'Veneto', |
| 213 |
'url' => 'https://flussituristici.regione.veneto.it/ws/checkinV2?wsdl', |
| 214 |
], |
| 215 |
[ |
| 216 |
'name' => 'Emilia-Romagna', |
| 217 |
'url' => 'https://datiturismo.regione.emilia-romagna.it/ws/checkinV2?wsdl', |
| 218 |
], |
| 219 |
[ |
| 220 |
'name' => 'Marche', |
| 221 |
'url' => 'https://istrice-ross1000.turismo.marche.it/ws/checkinV2?wsdl', |
| 222 |
], |
| 223 |
[ |
| 224 |
'name' => 'Lombardia', |
| 225 |
'url' => 'https://www.flussituristici.servizirl.it/Turismo5/app/ws/checkinV2?wsdl', |
| 226 |
], |
| 227 |
[ |
| 228 |
'name' => 'Calabria', |
| 229 |
'url' => 'https://sirdat.regione.calabria.it/ws/checkinV2?wsdl', |
| 230 |
], |
| 231 |
[ |
| 232 |
'name' => 'Sardegna', |
| 233 |
'url' => 'https://sardegnaturismo.ross1000.it/ws/checkinV2?wsdl', |
| 234 |
], |
| 235 |
[ |
| 236 |
'name' => 'Liguria', |
| 237 |
'url' => 'https://turismows.regione.liguria.it/ws/checkinV2?wsdl', |
| 238 |
], |
| 239 |
[ |
| 240 |
'name' => 'Lazio', |
| 241 |
'url' => 'https://lazioturismo.ross1000.it/ws/checkinV2?wsdl', |
| 242 |
], |
| 243 |
]; |
| 244 |
|
| 245 |
$example_urls_str = ''; |
| 246 |
foreach ($example_urls as $example_url) { |
| 247 |
$example_urls_str .= '<li><strong>' . $example_url['name'] . '</strong>: ' . $example_url['url'] . '</li>' . "\n"; |
| 248 |
} |
| 249 |
|
| 250 |
// count room units |
| 251 |
$tot_room_units = $this->countRooms(); |
| 252 |
|
| 253 |
return [ |
| 254 |
'title' => [ |
| 255 |
'type' => 'custom', |
| 256 |
'label' => '', |
| 257 |
'html' => '<p class="info">Configura le impostazioni per la generazione dei tracciati record XML e per la trasmissione delle informazioni verso il WebService della tua regione o provincia.</p>', |
| 258 |
], |
| 259 |
'codstru' => [ |
| 260 |
'type' => 'text', |
| 261 |
'label' => 'Codice Struttura', |
| 262 |
'help' => 'Codice univoco di identificazione della tua struttura assegnato dall\'Amministrazione competente.', |
| 263 |
], |
| 264 |
'numcamere' => [ |
| 265 |
'type' => 'number', |
| 266 |
'label' => 'Numero camere disponibili', |
| 267 |
'help' => 'Numero totale di camere disponibili.', |
| 268 |
'min' => 1, |
| 269 |
'default' => $tot_room_units, |
| 270 |
], |
| 271 |
'numletti' => [ |
| 272 |
'type' => 'number', |
| 273 |
'label' => 'Numero letti disponibili', |
| 274 |
'help' => 'Numero totale di letti disponibili.', |
| 275 |
'min' => 0, |
| 276 |
'default' => $tot_room_units, |
| 277 |
], |
| 278 |
'user' => [ |
| 279 |
'type' => 'text', |
| 280 |
'label' => 'Utente', |
| 281 |
'help' => 'Nome utente assegnato dall\'Ufficio Turismo di competenza.', |
| 282 |
], |
| 283 |
'pwd' => [ |
| 284 |
'type' => 'password', |
| 285 |
'label' => 'Password', |
| 286 |
'help' => 'Password assegnata dall\'Ufficio Turismo di competenza.', |
| 287 |
], |
| 288 |
'endpoint' => [ |
| 289 |
'type' => 'text', |
| 290 |
'label' => 'WS Endpoint URL', |
| 291 |
'help' => 'Indirizzo URL web-service del sito web dell\'ente al quale trasmettere i dati. È suggerito consultare anche la lista di endpoint sottostante.', |
| 292 |
], |
| 293 |
'exampleurls' => [ |
| 294 |
'type' => 'custom', |
| 295 |
'label' => '', |
| 296 |
'html' => '<p class="info">Lista Endpoint web-service:</p><ul>' . $example_urls_str . '</ul><p class="warn">È consigliato verificare tramite il proprio portale ISTAT regionale l\'effettivo URL del Web-Service da utilizzare per la trasmissione dei flussi turistici. In alcuni casi l\'indirizzo URL potrebbe non necessitare della parte finale <code>?wsdl</code>.</p>', |
| 297 |
], |
| 298 |
]; |
| 299 |
} |
| 300 |
|
| 301 |
/** |
| 302 |
* @inheritDoc |
| 303 |
* |
| 304 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 305 |
*/ |
| 306 |
public function getScopedActions($scope = null, $visible = true) |
| 307 |
{ |
| 308 |
// list of custom actions for this report |
| 309 |
$actions = [ |
| 310 |
[ |
| 311 |
'id' => 'transmitRecords', |
| 312 |
'name' => 'Trasmetti flussi turistici', |
| 313 |
'help' => 'Trasmette i dati riguardanti i flussi turistici.', |
| 314 |
'icon' => VikBookingIcons::i('cloud-upload-alt'), |
| 315 |
// flag to indicate that it requires the report data |
| 316 |
'export_data' => true, |
| 317 |
'scopes' => [ |
| 318 |
'web', |
| 319 |
'cron', |
| 320 |
], |
| 321 |
], |
| 322 |
]; |
| 323 |
|
| 324 |
// filter actions by scope |
| 325 |
if ($scope && (!strcasecmp($scope, 'cron') || !strcasecmp($scope, 'web'))) { |
| 326 |
$actions = array_filter($actions, function($action) use ($scope) { |
| 327 |
if (!($action['scopes'] ?? [])) { |
| 328 |
return true; |
| 329 |
} |
| 330 |
|
| 331 |
return in_array(strtolower($scope), $action['scopes']); |
| 332 |
}); |
| 333 |
} |
| 334 |
|
| 335 |
// filter by visibility |
| 336 |
if ($visible) { |
| 337 |
$actions = array_filter($actions, function($action) { |
| 338 |
return !($action['hidden'] ?? false); |
| 339 |
}); |
| 340 |
} |
| 341 |
|
| 342 |
return array_values($actions); |
| 343 |
} |
| 344 |
|
| 345 |
/** |
| 346 |
* Returns the filters of this report. |
| 347 |
* |
| 348 |
* @return array |
| 349 |
*/ |
| 350 |
public function getFilters() |
| 351 |
{ |
| 352 |
if ($this->reportFilters) { |
| 353 |
//do not run this method twice, as it could load JS and CSS files. |
| 354 |
return $this->reportFilters; |
| 355 |
} |
| 356 |
|
| 357 |
$app = JFactory::getApplication(); |
| 358 |
|
| 359 |
//get VBO Application Object |
| 360 |
$vbo_app = VikBooking::getVboApplication(); |
| 361 |
|
| 362 |
// get the possibly injected report options |
| 363 |
$options = $this->getReportOptions(); |
| 364 |
|
| 365 |
//load the jQuery UI Datepicker |
| 366 |
$this->loadDatePicker(); |
| 367 |
|
| 368 |
//custom export button |
| 369 |
$this->customExport = '<a href="JavaScript: void(0);" onclick="vboDownloadSchedaIstat();" class="vbcsvexport"><i class="'.VikBookingIcons::i('download').'"></i> <span>Download File</span></a>'; |
| 370 |
|
| 371 |
// build the hidden values for the selection of Comuni & Province and much more. |
| 372 |
$this->comuniProvince = $this->loadComuniProvince(); |
| 373 |
$this->nazioni = $this->loadNazioni(); |
| 374 |
|
| 375 |
// open hidden fields |
| 376 |
$hidden_vals = '<div id="vbo-report-ross1000-hidden" style="display: none;">'; |
| 377 |
|
| 378 |
// build params container HTML structure |
| 379 |
$hidden_vals .= '<div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">'; |
| 380 |
$hidden_vals .= ' <div class="vbo-params-wrap">'; |
| 381 |
$hidden_vals .= ' <div class="vbo-params-container">'; |
| 382 |
$hidden_vals .= ' <div class="vbo-params-block vbo-params-block-noborder">'; |
| 383 |
|
| 384 |
// comuni |
| 385 |
$hidden_vals .= ' <div id="vbo-report-ross1000-comune" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 386 |
$hidden_vals .= ' <div class="vbo-param-label">Comune</div>'; |
| 387 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 388 |
$hidden_vals .= ' <select id="choose-comune" onchange="vboReportChosenComune(this);">'; |
| 389 |
$hidden_vals .= ' <option value=""></option>'."\n"; |
| 390 |
$hidden_vals .= ' <option value="ES">- Estero -</option>'."\n"; |
| 391 |
foreach ($this->comuniProvince['comuni'] ?? [] as $code => $comune) { |
| 392 |
if (empty($code)) { |
| 393 |
continue; |
| 394 |
} |
| 395 |
$hidden_vals .= ' <option value="' . $code . '">' . (is_array($comune) ? $comune['name'] : '') . '</option>'."\n"; |
| 396 |
} |
| 397 |
$hidden_vals .= ' </select>'; |
| 398 |
$hidden_vals .= ' </div>'; |
| 399 |
$hidden_vals .= ' </div>'; |
| 400 |
|
| 401 |
// mezzi di trasporto |
| 402 |
$hidden_vals .= ' <div id="vbo-report-trasporto" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 403 |
$hidden_vals .= ' <div class="vbo-param-label">Mezzo di trasporto</div>'; |
| 404 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 405 |
$hidden_vals .= ' <select id="choose-trasporto" onchange="vboReportChosenTrasporto(this);"><option value=""></option>'; |
| 406 |
foreach ($this->meaningsOfTransport as $key => $value) { |
| 407 |
$hidden_vals .= ' <option value="' . $value . '">' . $value . '</option>'."\n"; |
| 408 |
} |
| 409 |
$hidden_vals .= ' </select>'; |
| 410 |
$hidden_vals .= ' </div>'; |
| 411 |
$hidden_vals .= ' </div>'; |
| 412 |
|
| 413 |
// tipo di turismo |
| 414 |
$hidden_vals .= ' <div id="vbo-report-turismo" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 415 |
$hidden_vals .= ' <div class="vbo-param-label">Tipo di turismo</div>'; |
| 416 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 417 |
$hidden_vals .= ' <select id="choose-turismo" onchange="vboReportChosenTurismo(this);"><option value=""></option>'; |
| 418 |
foreach ($this->tourismTypes as $key => $value) { |
| 419 |
$hidden_vals .= ' <option value="' . $value . '">' . $value . '</option>'."\n"; |
| 420 |
} |
| 421 |
$hidden_vals .= ' </select>'; |
| 422 |
$hidden_vals .= ' </div>'; |
| 423 |
$hidden_vals .= ' </div>'; |
| 424 |
|
| 425 |
// province |
| 426 |
$hidden_vals .= ' <div id="vbo-report-ross1000-provincia" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 427 |
$hidden_vals .= ' <div class="vbo-param-label">Provincia</div>'; |
| 428 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 429 |
$hidden_vals .= ' <select id="choose-provincia" onchange="vboReportChosenProvincia(this);"><option value=""></option>'; |
| 430 |
foreach ($this->comuniProvince['province'] ?? [] as $code => $provincia) { |
| 431 |
$hidden_vals .= ' <option value="' . $code . '">' . $provincia . '</option>'."\n"; |
| 432 |
} |
| 433 |
$hidden_vals .= ' </select>'; |
| 434 |
$hidden_vals .= ' </div>'; |
| 435 |
$hidden_vals .= ' </div>'; |
| 436 |
|
| 437 |
// nazioni |
| 438 |
$hidden_vals .= ' <div id="vbo-report-ross1000-nazione" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 439 |
$hidden_vals .= ' <div class="vbo-param-label">Paese</div>'; |
| 440 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 441 |
$hidden_vals .= ' <select id="choose-nazione" onchange="vboReportChosenNazione(this);"><option value=""></option>'; |
| 442 |
foreach ($this->nazioni as $code => $nazione) { |
| 443 |
$hidden_vals .= ' <option value="' . $code . '">' . $nazione['name'] . '</option>'; |
| 444 |
} |
| 445 |
$hidden_vals .= ' </select>'; |
| 446 |
$hidden_vals .= ' </div>'; |
| 447 |
$hidden_vals .= ' </div>'; |
| 448 |
|
| 449 |
// sesso |
| 450 |
$hidden_vals .= ' <div id="vbo-report-ross1000-sesso" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 451 |
$hidden_vals .= ' <div class="vbo-param-label">Sesso</div>'; |
| 452 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 453 |
$hidden_vals .= ' <select id="choose-sesso" onchange="vboReportChosenSesso(this);"><option value=""></option>'; |
| 454 |
$sessos = [ |
| 455 |
1 => 'M', |
| 456 |
2 => 'F' |
| 457 |
]; |
| 458 |
foreach ($sessos as $code => $ses) { |
| 459 |
$hidden_vals .= ' <option value="'.$code.'">'.$ses.'</option>'."\n"; |
| 460 |
} |
| 461 |
$hidden_vals .= ' </select>'; |
| 462 |
$hidden_vals .= ' </div>'; |
| 463 |
$hidden_vals .= ' </div>'; |
| 464 |
|
| 465 |
// data di nascita |
| 466 |
$hidden_vals .= ' <div id="vbo-report-ross1000-dbirth" class="vbo-report-ross1000-selcont vbo-param-container" style="display: none;">'; |
| 467 |
$hidden_vals .= ' <div class="vbo-param-label">Data di nascita</div>'; |
| 468 |
$hidden_vals .= ' <div class="vbo-param-setting">'; |
| 469 |
$hidden_vals .= ' <input type="text" size="40" id="choose-dbirth" value="" />'; |
| 470 |
$hidden_vals .= ' </div>'; |
| 471 |
$hidden_vals .= ' </div>'; |
| 472 |
|
| 473 |
// close params container HTML structure |
| 474 |
$hidden_vals .= ' </div>'; |
| 475 |
$hidden_vals .= ' </div>'; |
| 476 |
$hidden_vals .= ' </div>'; |
| 477 |
$hidden_vals .= '</div>'; |
| 478 |
|
| 479 |
// close hidden fields |
| 480 |
$hidden_vals .= '</div>'; |
| 481 |
|
| 482 |
//From Date Filter (with hidden values for the dropdown menus of Comuni, Province, Stati etc..) |
| 483 |
$filter_opt = array( |
| 484 |
'label' => '<label for="fromdate">'.JText::translate('VBOREPORTSDATEFROM').'</label>', |
| 485 |
'html' => '<input type="text" id="fromdate" name="fromdate" value="" class="vbo-report-datepicker vbo-report-datepicker-from" />'.$hidden_vals, |
| 486 |
'type' => 'calendar', |
| 487 |
'name' => 'fromdate' |
| 488 |
); |
| 489 |
array_push($this->reportFilters, $filter_opt); |
| 490 |
|
| 491 |
// To Date Filter |
| 492 |
$filter_opt = array( |
| 493 |
'label' => '<label for="todate">'.JText::translate('VBOREPORTSDATETO').'</label>', |
| 494 |
'html' => '<input type="text" id="todate" name="todate" value="" class="vbo-report-datepicker vbo-report-datepicker-to" />', |
| 495 |
'type' => 'calendar', |
| 496 |
'name' => 'todate' |
| 497 |
); |
| 498 |
array_push($this->reportFilters, $filter_opt); |
| 499 |
|
| 500 |
// Listings Filter |
| 501 |
$filter_opt = array( |
| 502 |
'label' => '<label for="listingsfilt">' . JText::translate('VBO_LISTINGS') . '</label>', |
| 503 |
'html' => '<span class="vbo-toolbar-multiselect-wrap">' . $vbo_app->renderElementsDropDown([ |
| 504 |
'id' => 'listingsfilt', |
| 505 |
'elements' => 'listings', |
| 506 |
'placeholder' => JText::translate('VBO_LISTINGS'), |
| 507 |
'allow_clear' => 1, |
| 508 |
'attributes' => [ |
| 509 |
'name' => 'listings[]', |
| 510 |
'multiple' => 'multiple', |
| 511 |
], |
| 512 |
'selected_values' => (array) ($app->input->get('listings', [], 'array') ?: $options->get('listings', [])), |
| 513 |
]) . '</span>', |
| 514 |
'type' => 'select', |
| 515 |
'multiple' => true, |
| 516 |
'name' => 'listings', |
| 517 |
); |
| 518 |
array_push($this->reportFilters, $filter_opt); |
| 519 |
|
| 520 |
// append button to save the data when creating manual values |
| 521 |
$filter_opt = array( |
| 522 |
'label' => '<label class="vbo-report-ross1000-manualsave" style="display: none;">' . JText::translate('VBOGUESTSDETAILS') . '</label>', |
| 523 |
'html' => '<button type="button" class="btn vbo-config-btn vbo-report-ross1000-manualsave" style="display: none;" onclick="vboRoss1000SaveData();"><i class="' . VikBookingIcons::i('save') . '"></i> ' . JText::translate('VBSAVE') . '</button>', |
| 524 |
); |
| 525 |
array_push($this->reportFilters, $filter_opt); |
| 526 |
|
| 527 |
// jQuery code for the datepicker calendars, select2 and triggers for the dropdown menus |
| 528 |
$pfromdate = VikRequest::getString('fromdate', '', 'request'); |
| 529 |
$ptodate = VikRequest::getString('todate', '', 'request'); |
| 530 |
|
| 531 |
$js_ajax_base = VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=invoke_report&report=' . $this->reportFile); |
| 532 |
$js_save_icn = VikBookingIcons::i('save'); |
| 533 |
$js_saving_icn = VikBookingIcons::i('circle-notch', 'fa-spin fa-fw'); |
| 534 |
$js_saved_icn = VikBookingIcons::i('check-circle'); |
| 535 |
|
| 536 |
$js = 'var reportActiveCell = null, reportObj = {}; |
| 537 |
var vbo_report_js_ajax_base = "' . $js_ajax_base . '"; |
| 538 |
var vbo_ross1000_save_icn = "' . $js_save_icn . '"; |
| 539 |
var vbo_ross1000_saving_icn = "' . $js_saving_icn . '"; |
| 540 |
var vbo_ross1000_saved_icn = "' . $js_saved_icn . '"; |
| 541 |
jQuery(function() { |
| 542 |
// prepare main filters |
| 543 |
jQuery(".vbo-report-datepicker:input").datepicker({ |
| 544 |
maxDate: "+1m", |
| 545 |
dateFormat: "'.$this->getDateFormat('jui').'", |
| 546 |
onSelect: vboReportCheckDates |
| 547 |
}); |
| 548 |
'.(!empty($pfromdate) ? 'jQuery(".vbo-report-datepicker-from").datepicker("setDate", "'.$pfromdate.'");' : '').' |
| 549 |
'.(!empty($ptodate) ? 'jQuery(".vbo-report-datepicker-to").datepicker("setDate", "'.$ptodate.'");' : '').' |
| 550 |
// prepare filler helpers |
| 551 |
jQuery("#vbo-report-ross1000-hidden").children().detach().appendTo(".vbo-info-overlay-report"); |
| 552 |
jQuery("#choose-comune").select2({placeholder: "- Seleziona un Comune -", width: "200px"}); |
| 553 |
jQuery("#choose-provincia").select2({placeholder: "- Seleziona una Provincia -", width: "200px"}); |
| 554 |
jQuery("#choose-nazione").select2({placeholder: "- Seleziona una Nazione -", width: "200px"}); |
| 555 |
jQuery("#choose-sesso").select2({placeholder: "- Seleziona Sesso -", width: "200px"}); |
| 556 |
jQuery("#choose-turismo").select2({placeholder: "- Seleziona Tipo di Turismo -", width: "300px"}); |
| 557 |
jQuery("#choose-trasporto").select2({placeholder: "- Seleziona Mezzo di Trasporto -", width: "300px"}); |
| 558 |
|
| 559 |
jQuery("#choose-dbirth").datepicker({ |
| 560 |
maxDate: 0, |
| 561 |
dateFormat: "dd/mm/yy", |
| 562 |
changeMonth: true, |
| 563 |
changeYear: true, |
| 564 |
yearRange: "'.(date('Y') - 100).':'.date('Y').'" |
| 565 |
}); |
| 566 |
// click events |
| 567 |
jQuery(".vbo-report-load-comune").click(function() { |
| 568 |
reportActiveCell = this; |
| 569 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 570 |
jQuery("#vbo-report-ross1000-comune").show(); |
| 571 |
vboShowOverlay({ |
| 572 |
title: "Compila informazioni", |
| 573 |
extra_class: "vbo-modal-rounded vbo-modal-dialog", |
| 574 |
}); |
| 575 |
}); |
| 576 |
jQuery(".vbo-report-load-provincia").click(function() { |
| 577 |
reportActiveCell = this; |
| 578 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 579 |
jQuery("#vbo-report-ross1000-provincia").show(); |
| 580 |
vboShowOverlay({ |
| 581 |
title: "Compila informazioni", |
| 582 |
extra_class: "vbo-modal-rounded vbo-modal-dialog", |
| 583 |
}); |
| 584 |
}); |
| 585 |
jQuery(".vbo-report-load-nazione, .vbo-report-load-cittadinanza").click(function() { |
| 586 |
reportActiveCell = this; |
| 587 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 588 |
jQuery("#vbo-report-ross1000-nazione").show(); |
| 589 |
vboShowOverlay(); |
| 590 |
}); |
| 591 |
jQuery(".vbo-report-load-sesso").click(function() { |
| 592 |
reportActiveCell = this; |
| 593 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 594 |
jQuery("#vbo-report-ross1000-sesso").show(); |
| 595 |
vboShowOverlay({ |
| 596 |
title: "Compila informazioni", |
| 597 |
extra_class: "vbo-modal-rounded vbo-modal-dialog vbo-modal-nofooter", |
| 598 |
}); |
| 599 |
}); |
| 600 |
jQuery(".vbo-report-load-turismo").click(function() { |
| 601 |
reportActiveCell = this; |
| 602 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 603 |
jQuery("#vbo-report-turismo").show(); |
| 604 |
vboShowOverlay({ |
| 605 |
title: "Compila informazioni", |
| 606 |
extra_class: "vbo-modal-rounded vbo-modal-dialog", |
| 607 |
}); |
| 608 |
}); |
| 609 |
jQuery(".vbo-report-load-trasporto").click(function() { |
| 610 |
reportActiveCell = this; |
| 611 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 612 |
jQuery("#vbo-report-trasporto").show(); |
| 613 |
vboShowOverlay({ |
| 614 |
title: "Compila informazioni", |
| 615 |
extra_class: "vbo-modal-rounded vbo-modal-dialog", |
| 616 |
}); |
| 617 |
}); |
| 618 |
jQuery(".vbo-report-load-dbirth").click(function() { |
| 619 |
reportActiveCell = this; |
| 620 |
jQuery(".vbo-report-ross1000-selcont").hide(); |
| 621 |
jQuery("#vbo-report-ross1000-dbirth").show(); |
| 622 |
vboShowOverlay({ |
| 623 |
title: "Compila informazioni", |
| 624 |
extra_class: "vbo-modal-rounded vbo-modal-dialog", |
| 625 |
footer_right: "<button type=\"button\" class=\"btn btn-success\" onclick=\"vboReportChosenDbirth(document.getElementById(\'choose-dbirth\').value);\">Applica</button>", |
| 626 |
}); |
| 627 |
}); |
| 628 |
}); |
| 629 |
|
| 630 |
function vboReportCheckDates(selectedDate, inst) { |
| 631 |
if (selectedDate === null || inst === null) { |
| 632 |
return; |
| 633 |
} |
| 634 |
var cur_from_date = jQuery(this).val(); |
| 635 |
if (jQuery(this).hasClass("vbo-report-datepicker-from") && cur_from_date.length) { |
| 636 |
var nowstart = jQuery(this).datepicker("getDate"); |
| 637 |
var nowstartdate = new Date(nowstart.getTime()); |
| 638 |
jQuery(".vbo-report-datepicker-to").datepicker("option", {minDate: nowstartdate}); |
| 639 |
} |
| 640 |
} |
| 641 |
|
| 642 |
function vboReportChosenComune(comune) { |
| 643 |
var c_code = comune.value; |
| 644 |
var c_val = comune.options[comune.selectedIndex].text; |
| 645 |
if (reportActiveCell !== null) { |
| 646 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 647 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 648 |
alert("Error, cannot find element to update."); |
| 649 |
} else { |
| 650 |
var rep_act_cell = jQuery(reportActiveCell); |
| 651 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 652 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 653 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 654 |
reportObj[nowindex] = { |
| 655 |
bid: rep_guest_bid, |
| 656 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 657 |
}; |
| 658 |
} |
| 659 |
if (jQuery(reportActiveCell).hasClass("vbo-report-load-docplace")) { |
| 660 |
reportObj[nowindex]["docplace"] = c_code; |
| 661 |
} else { |
| 662 |
reportObj[nowindex]["comune_s"] = c_code; |
| 663 |
} |
| 664 |
} |
| 665 |
} |
| 666 |
reportActiveCell = null; |
| 667 |
vboHideOverlay(); |
| 668 |
jQuery("#choose-comune").val("").select2("data", null, false); |
| 669 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 670 |
} |
| 671 |
|
| 672 |
function vboReportChosenProvincia(prov) { |
| 673 |
var c_code = prov.value; |
| 674 |
var c_val = prov.options[prov.selectedIndex].text; |
| 675 |
if (reportActiveCell !== null) { |
| 676 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 677 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 678 |
alert("Error, cannot find element to update."); |
| 679 |
} else { |
| 680 |
var rep_act_cell = jQuery(reportActiveCell); |
| 681 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 682 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 683 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 684 |
reportObj[nowindex] = { |
| 685 |
bid: rep_guest_bid, |
| 686 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 687 |
}; |
| 688 |
} |
| 689 |
reportObj[nowindex]["comune_s"] = c_code; |
| 690 |
} |
| 691 |
} |
| 692 |
reportActiveCell = null; |
| 693 |
vboHideOverlay(); |
| 694 |
jQuery("#choose-provincia").val("").select2("data", null, false); |
| 695 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 696 |
} |
| 697 |
|
| 698 |
function vboReportChosenNazione(naz) { |
| 699 |
var c_code = naz.value; |
| 700 |
var c_val = naz.options[naz.selectedIndex].text; |
| 701 |
if (reportActiveCell !== null) { |
| 702 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 703 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 704 |
alert("Error, cannot find element to update."); |
| 705 |
} else { |
| 706 |
var rep_act_cell = jQuery(reportActiveCell); |
| 707 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 708 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 709 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 710 |
reportObj[nowindex] = { |
| 711 |
bid: rep_guest_bid, |
| 712 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 713 |
}; |
| 714 |
} |
| 715 |
if (jQuery(reportActiveCell).hasClass("vbo-report-load-nazione")) { |
| 716 |
reportObj[nowindex]["country_s"] = c_code; |
| 717 |
} else if (jQuery(reportActiveCell).hasClass("vbo-report-load-docplace")) { |
| 718 |
reportObj[nowindex]["docplace"] = c_code; |
| 719 |
} else { |
| 720 |
reportObj[nowindex]["country_c"] = c_code; |
| 721 |
} |
| 722 |
} |
| 723 |
} |
| 724 |
reportActiveCell = null; |
| 725 |
vboHideOverlay(); |
| 726 |
jQuery("#choose-nazione").val("").select2("data", null, false); |
| 727 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 728 |
} |
| 729 |
|
| 730 |
function vboReportChosenSesso(sesso) { |
| 731 |
var c_code = sesso.value; |
| 732 |
var c_val = sesso.options[sesso.selectedIndex].text; |
| 733 |
if (reportActiveCell !== null) { |
| 734 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 735 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 736 |
alert("Error, cannot find element to update."); |
| 737 |
} else { |
| 738 |
var rep_act_cell = jQuery(reportActiveCell); |
| 739 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 740 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 741 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 742 |
reportObj[nowindex] = { |
| 743 |
bid: rep_guest_bid, |
| 744 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 745 |
}; |
| 746 |
} |
| 747 |
reportObj[nowindex]["gender"] = c_code; |
| 748 |
} |
| 749 |
} |
| 750 |
reportActiveCell = null; |
| 751 |
vboHideOverlay(); |
| 752 |
jQuery("#choose-sesso").val("").select2("data", null, false); |
| 753 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 754 |
} |
| 755 |
|
| 756 |
function vboReportChosenTrasporto(trasporto) { |
| 757 |
var c_code = trasporto.value; |
| 758 |
var c_val = trasporto.options[trasporto.selectedIndex].text; |
| 759 |
if (reportActiveCell !== null) { |
| 760 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 761 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 762 |
alert("Error, cannot find element to update."); |
| 763 |
} else { |
| 764 |
var rep_act_cell = jQuery(reportActiveCell); |
| 765 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 766 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 767 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 768 |
reportObj[nowindex] = { |
| 769 |
bid: rep_guest_bid, |
| 770 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 771 |
}; |
| 772 |
} |
| 773 |
reportObj[nowindex]["mezzo"] = c_code; |
| 774 |
} |
| 775 |
} |
| 776 |
reportActiveCell = null; |
| 777 |
vboHideOverlay(); |
| 778 |
jQuery("#choose-trasporto").val("").select2("data", null, false); |
| 779 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 780 |
} |
| 781 |
|
| 782 |
function vboReportChosenTurismo(turismo) { |
| 783 |
var c_code = turismo.value; |
| 784 |
var c_val = turismo.options[turismo.selectedIndex].text; |
| 785 |
if (reportActiveCell !== null) { |
| 786 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 787 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 788 |
alert("Error, cannot find element to update."); |
| 789 |
} else { |
| 790 |
var rep_act_cell = jQuery(reportActiveCell); |
| 791 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 792 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 793 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 794 |
reportObj[nowindex] = { |
| 795 |
bid: rep_guest_bid, |
| 796 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 797 |
}; |
| 798 |
} |
| 799 |
reportObj[nowindex]["turismo"] = c_code; |
| 800 |
} |
| 801 |
} |
| 802 |
reportActiveCell = null; |
| 803 |
vboHideOverlay(); |
| 804 |
jQuery("#choose-turismo").val("").select2("data", null, false); |
| 805 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 806 |
} |
| 807 |
|
| 808 |
function vboReportChosenDbirth(val) { |
| 809 |
var c_code = val, c_val = val; |
| 810 |
if (reportActiveCell !== null) { |
| 811 |
var nowindex = jQuery(".vbo-reports-output table tbody tr").index(jQuery(reportActiveCell).closest("tr")); |
| 812 |
if (isNaN(nowindex) || parseInt(nowindex) < 0) { |
| 813 |
alert("Error, cannot find element to update."); |
| 814 |
} else { |
| 815 |
var rep_act_cell = jQuery(reportActiveCell); |
| 816 |
rep_act_cell.addClass("vbo-report-load-elem-filled").find("span").text(c_val); |
| 817 |
var rep_guest_bid = rep_act_cell.closest("tr").find("a[data-bid]").attr("data-bid"); |
| 818 |
if (!reportObj.hasOwnProperty(nowindex)) { |
| 819 |
reportObj[nowindex] = { |
| 820 |
bid: rep_guest_bid, |
| 821 |
bid_index: jQuery(".vbo-reports-output table tbody tr").index(jQuery("a[data-bid=\"" + rep_guest_bid + "\"]").first().closest("tr")) |
| 822 |
}; |
| 823 |
} |
| 824 |
reportObj[nowindex]["date_birth"] = c_code; |
| 825 |
} |
| 826 |
} |
| 827 |
reportActiveCell = null; |
| 828 |
vboHideOverlay(); |
| 829 |
jQuery("#choose-dbirth").val(""); |
| 830 |
jQuery(".vbo-report-ross1000-manualsave").show(); |
| 831 |
} |
| 832 |
|
| 833 |
// download function |
| 834 |
function vboDownloadSchedaIstat(type) { |
| 835 |
if (!confirm("Sei sicuro di aver compilato tutti i dati?")) { |
| 836 |
return false; |
| 837 |
} |
| 838 |
|
| 839 |
let use_blank = true; |
| 840 |
if (typeof type === "undefined") { |
| 841 |
type = 1; |
| 842 |
} else { |
| 843 |
use_blank = false; |
| 844 |
} |
| 845 |
|
| 846 |
if (use_blank) { |
| 847 |
document.adminForm.target = "_blank"; |
| 848 |
document.adminForm.action += "&tmpl=component"; |
| 849 |
} |
| 850 |
|
| 851 |
vboSetFilters({exportreport: type, filler: JSON.stringify(reportObj)}, true); |
| 852 |
|
| 853 |
setTimeout(function() { |
| 854 |
document.adminForm.target = ""; |
| 855 |
document.adminForm.action = document.adminForm.action.replace("&tmpl=component", ""); |
| 856 |
vboSetFilters({exportreport: "0", filler: ""}, false); |
| 857 |
}, 1000); |
| 858 |
} |
| 859 |
|
| 860 |
// save data after manual fillers |
| 861 |
function vboRoss1000SaveData() { |
| 862 |
jQuery("button.vbo-report-ross1000-manualsave").find("i").attr("class", vbo_ross1000_saving_icn); |
| 863 |
VBOCore.doAjax( |
| 864 |
vbo_report_js_ajax_base, |
| 865 |
{ |
| 866 |
call: "updatePaxData", |
| 867 |
params: reportObj, |
| 868 |
tmpl: "component" |
| 869 |
}, |
| 870 |
(response) => { |
| 871 |
if (!response || !response[0]) { |
| 872 |
alert("An error occurred."); |
| 873 |
return false; |
| 874 |
} |
| 875 |
jQuery("button.vbo-report-ross1000-manualsave").addClass("btn-success").find("i").attr("class", vbo_ross1000_saved_icn); |
| 876 |
}, |
| 877 |
(error) => { |
| 878 |
alert(error.responseText); |
| 879 |
jQuery("button.vbo-report-ross1000-manualsave").removeClass("btn-success").find("i").attr("class", vbo_ross1000_save_icn); |
| 880 |
} |
| 881 |
); |
| 882 |
}'; |
| 883 |
$this->setScript($js); |
| 884 |
|
| 885 |
return $this->reportFilters; |
| 886 |
} |
| 887 |
|
| 888 |
/** |
| 889 |
* Loads the report data from the DB. |
| 890 |
* Returns true in case of success, false otherwise. |
| 891 |
* Sets the columns and rows for the report to be displayed. |
| 892 |
* |
| 893 |
* @return boolean |
| 894 |
*/ |
| 895 |
public function getReportData() |
| 896 |
{ |
| 897 |
// always reset no bookings detection flag |
| 898 |
$this->datesHaveNoBookings = false; |
| 899 |
|
| 900 |
if ($this->getError()) { |
| 901 |
// export functions may set errors rather than exiting the process, and |
| 902 |
// the View may continue the execution to attempt to render the report. |
| 903 |
return false; |
| 904 |
} |
| 905 |
|
| 906 |
if ($this->rows) { |
| 907 |
// method must have run already |
| 908 |
return true; |
| 909 |
} |
| 910 |
|
| 911 |
// get the possibly injected report options |
| 912 |
$options = $this->getReportOptions(); |
| 913 |
|
| 914 |
// injected options will replace request variables, if any |
| 915 |
$opt_fromdate = $options->get('fromdate', ''); |
| 916 |
$opt_todate = $options->get('todate', ''); |
| 917 |
|
| 918 |
// input fields and other vars |
| 919 |
$pfromdate = $opt_fromdate ?: VikRequest::getString('fromdate', '', 'request'); |
| 920 |
$ptodate = $opt_todate ?: VikRequest::getString('todate', '', 'request'); |
| 921 |
|
| 922 |
$pkrsort = VikRequest::getString('krsort', $this->defaultKeySort, 'request'); |
| 923 |
$pkrsort = empty($pkrsort) ? $this->defaultKeySort : $pkrsort; |
| 924 |
$pkrorder = VikRequest::getString('krorder', $this->defaultKeyOrder, 'request'); |
| 925 |
$pkrorder = empty($pkrorder) ? $this->defaultKeyOrder : $pkrorder; |
| 926 |
$pkrorder = $pkrorder == 'DESC' ? 'DESC' : 'ASC'; |
| 927 |
$plistings = ((array) VikRequest::getVar('listings', array())) ?: ((array) $options->get('listings', [])); |
| 928 |
$plistings = array_filter(array_map('intval', $plistings)); |
| 929 |
|
| 930 |
$currency_symb = VikBooking::getCurrencySymb(); |
| 931 |
$df = $this->getDateFormat(); |
| 932 |
$datesep = VikBooking::getDateSeparator(); |
| 933 |
if (empty($ptodate)) { |
| 934 |
$ptodate = $pfromdate; |
| 935 |
} |
| 936 |
|
| 937 |
// get date timestamps |
| 938 |
$from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0); |
| 939 |
$to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59, 59); |
| 940 |
if (empty($pfromdate) || empty($from_ts) || empty($to_ts) || $from_ts > $to_ts) { |
| 941 |
$this->setError(JText::translate('VBOREPORTSERRNODATES')); |
| 942 |
return false; |
| 943 |
} |
| 944 |
|
| 945 |
// set the dates being exported |
| 946 |
$this->exported_checkin_dates = [ |
| 947 |
date('Y-m-d', $from_ts), |
| 948 |
date('Y-m-d', $to_ts), |
| 949 |
]; |
| 950 |
|
| 951 |
// load settings |
| 952 |
$settings = $this->loadSettings(); |
| 953 |
|
| 954 |
if (empty($settings['codstru'])) { |
| 955 |
$this->setError('Inserisci il codice della tua Struttura dalle impostazioni.<br/>Si tratta di un codice univoco di identificazione che ti viene assegnato dall\'Amministrazione competente.'); |
| 956 |
return false; |
| 957 |
} |
| 958 |
|
| 959 |
// query to obtain the records (all check-ins, check-outs and reservations created within the dates filter) |
| 960 |
$q = $this->dbo->getQuery(true) |
| 961 |
->select([ |
| 962 |
$this->dbo->qn('o.id'), |
| 963 |
$this->dbo->qn('o.custdata'), |
| 964 |
$this->dbo->qn('o.ts'), |
| 965 |
$this->dbo->qn('o.days'), |
| 966 |
$this->dbo->qn('o.checkin'), |
| 967 |
$this->dbo->qn('o.checkout'), |
| 968 |
$this->dbo->qn('o.totpaid'), |
| 969 |
$this->dbo->qn('o.roomsnum'), |
| 970 |
$this->dbo->qn('o.total'), |
| 971 |
$this->dbo->qn('o.idorderota'), |
| 972 |
$this->dbo->qn('o.channel'), |
| 973 |
$this->dbo->qn('o.country'), |
| 974 |
$this->dbo->qn('o.custmail'), |
| 975 |
$this->dbo->qn('o.phone'), |
| 976 |
$this->dbo->qn('or.idorder'), |
| 977 |
$this->dbo->qn('or.idroom'), |
| 978 |
$this->dbo->qn('or.adults'), |
| 979 |
$this->dbo->qn('or.children'), |
| 980 |
$this->dbo->qn('or.t_first_name'), |
| 981 |
$this->dbo->qn('or.t_last_name'), |
| 982 |
$this->dbo->qn('or.cust_cost'), |
| 983 |
$this->dbo->qn('or.cust_idiva'), |
| 984 |
$this->dbo->qn('or.extracosts'), |
| 985 |
$this->dbo->qn('or.room_cost'), |
| 986 |
$this->dbo->qn('co.idcustomer'), |
| 987 |
$this->dbo->qn('co.pax_data'), |
| 988 |
$this->dbo->qn('c.first_name'), |
| 989 |
$this->dbo->qn('c.last_name'), |
| 990 |
$this->dbo->qn('c.country', 'customer_country'), |
| 991 |
$this->dbo->qn('c.address'), |
| 992 |
$this->dbo->qn('c.doctype'), |
| 993 |
$this->dbo->qn('c.docnum'), |
| 994 |
$this->dbo->qn('c.gender'), |
| 995 |
$this->dbo->qn('c.bdate'), |
| 996 |
$this->dbo->qn('c.pbirth'), |
| 997 |
]) |
| 998 |
->from($this->dbo->qn('#__vikbooking_orders', 'o')) |
| 999 |
->leftJoin($this->dbo->qn('#__vikbooking_ordersrooms', 'or') . ' ON ' . $this->dbo->qn('or.idorder') . ' = ' . $this->dbo->qn('o.id')) |
| 1000 |
->leftJoin($this->dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $this->dbo->qn('co.idorder') . ' = ' . $this->dbo->qn('o.id')) |
| 1001 |
->leftJoin($this->dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $this->dbo->qn('c.id') . ' = ' . $this->dbo->qn('co.idcustomer')) |
| 1002 |
->where($this->dbo->qn('o.status') . ' = ' . $this->dbo->q('confirmed')) |
| 1003 |
->where($this->dbo->qn('o.closure') . ' = 0') |
| 1004 |
// fetch all bookings with check-in, check-out or reservation date within date filters |
| 1005 |
->andWhere([ |
| 1006 |
'(' . $this->dbo->qn('o.checkin') . ' BETWEEN ' . $from_ts . ' AND ' . $to_ts . ')', |
| 1007 |
'(' . $this->dbo->qn('o.checkout') . ' BETWEEN ' . $from_ts . ' AND ' . $to_ts . ')', |
| 1008 |
'(' . $this->dbo->qn('o.ts') . ' BETWEEN ' . $from_ts . ' AND ' . $to_ts . ')', |
| 1009 |
], 'OR') |
| 1010 |
->order($this->dbo->qn('o.checkin') . ' ASC') |
| 1011 |
->order($this->dbo->qn('o.id') . ' ASC') |
| 1012 |
->order($this->dbo->qn('or.id') . ' ASC'); |
| 1013 |
|
| 1014 |
if ($plistings) { |
| 1015 |
$q->where($this->dbo->qn('or.idroom') . ' IN (' . implode(', ', $plistings) . ')'); |
| 1016 |
} |
| 1017 |
|
| 1018 |
$this->dbo->setQuery($q); |
| 1019 |
$records = $this->dbo->loadAssocList(); |
| 1020 |
if (!$records) { |
| 1021 |
// set error message |
| 1022 |
$this->setError(JText::translate('VBOREPORTSERRNORESERV')); |
| 1023 |
$this->setError('Nessun check-in, check-out o prenotazione nelle date selezionate.'); |
| 1024 |
|
| 1025 |
// set no bookings detection flag |
| 1026 |
$this->datesHaveNoBookings = true; |
| 1027 |
|
| 1028 |
// abort |
| 1029 |
return false; |
| 1030 |
} |
| 1031 |
|
| 1032 |
// nest records with multiple rooms booked inside sub-array |
| 1033 |
$bookings = []; |
| 1034 |
foreach ($records as $v) { |
| 1035 |
if (!isset($bookings[$v['id']])) { |
| 1036 |
$bookings[$v['id']] = []; |
| 1037 |
} |
| 1038 |
array_push($bookings[$v['id']], $v); |
| 1039 |
} |
| 1040 |
|
| 1041 |
// define the columns of the report |
| 1042 |
$this->cols = array( |
| 1043 |
// booking code idswh for the PMS software |
| 1044 |
array( |
| 1045 |
'key' => 'idswh', |
| 1046 |
'label' => 'IDSWH', |
| 1047 |
'tip' => 'Codice identificativo del movimento. Generato automaticamente dal sistema.', |
| 1048 |
), |
| 1049 |
// booking id (this is not a duplicate value of "idbooking", it should go before "resdate", "checkin" and "checkout") |
| 1050 |
array( |
| 1051 |
'key' => 'booking_id', |
| 1052 |
'label' => 'ID', |
| 1053 |
// hide this field in the View |
| 1054 |
'ignore_view' => 1, |
| 1055 |
), |
| 1056 |
// reservation date |
| 1057 |
array( |
| 1058 |
'key' => 'resdate', |
| 1059 |
'attr' => array( |
| 1060 |
'class="center"' |
| 1061 |
), |
| 1062 |
'label' => JText::translate('VBPCHOOSEBUSYORDATE'), |
| 1063 |
), |
| 1064 |
// check-in |
| 1065 |
array( |
| 1066 |
'key' => 'checkin', |
| 1067 |
'attr' => array( |
| 1068 |
'class="center"' |
| 1069 |
), |
| 1070 |
'label' => JText::translate('VBPICKUPAT'), |
| 1071 |
), |
| 1072 |
// checkout |
| 1073 |
array( |
| 1074 |
'key' => 'checkout', |
| 1075 |
'attr' => array( |
| 1076 |
'class="center"' |
| 1077 |
), |
| 1078 |
'label' => JText::translate('VBRELEASEAT'), |
| 1079 |
), |
| 1080 |
// nome |
| 1081 |
array( |
| 1082 |
'key' => 'nome', |
| 1083 |
'label' => JText::translate('VBTRAVELERNAME'), |
| 1084 |
), |
| 1085 |
// cognome |
| 1086 |
array( |
| 1087 |
'key' => 'cognome', |
| 1088 |
'label' => JText::translate('VBTRAVELERLNAME'), |
| 1089 |
), |
| 1090 |
// sesso |
| 1091 |
array( |
| 1092 |
'key' => 'gender', |
| 1093 |
'attr' => array( |
| 1094 |
'class="center"' |
| 1095 |
), |
| 1096 |
'label' => JText::translate('VBCUSTOMERGENDER') |
| 1097 |
), |
| 1098 |
// data di nascita |
| 1099 |
array( |
| 1100 |
'key' => 'dbirth', |
| 1101 |
'attr' => array( |
| 1102 |
'class="center"' |
| 1103 |
), |
| 1104 |
'label' => JText::translate('VBCUSTOMERBDATE') |
| 1105 |
), |
| 1106 |
// cittadinanza |
| 1107 |
array( |
| 1108 |
'key' => 'citizen', |
| 1109 |
'attr' => array( |
| 1110 |
'class="center"' |
| 1111 |
), |
| 1112 |
'label' => 'Cittadinanza' |
| 1113 |
), |
| 1114 |
// residenza |
| 1115 |
array( |
| 1116 |
'key' => 'stares', |
| 1117 |
'attr' => array( |
| 1118 |
'class="center"' |
| 1119 |
), |
| 1120 |
'label' => 'Stato di Residenza' |
| 1121 |
), |
| 1122 |
// comune di residenza |
| 1123 |
array( |
| 1124 |
'key' => 'comres', |
| 1125 |
'attr' => array( |
| 1126 |
'class="center"' |
| 1127 |
), |
| 1128 |
'label' => 'Comune Residenza', |
| 1129 |
'tip' => 'Inserire il comune di residenza solo se il cittadino è di nazionalità italiana.' |
| 1130 |
), |
| 1131 |
// tipo |
| 1132 |
array( |
| 1133 |
'key' => 'tipo', |
| 1134 |
'attr' => array( |
| 1135 |
'class="vbo-report-longlbl"', |
| 1136 |
), |
| 1137 |
'label' => 'Tipo Alloggiato', |
| 1138 |
), |
| 1139 |
// tipo di turismo |
| 1140 |
array( |
| 1141 |
'key' => 'turismo', |
| 1142 |
'attr' => array( |
| 1143 |
'class="center"', |
| 1144 |
), |
| 1145 |
'label' => 'Tipo di Turismo', |
| 1146 |
), |
| 1147 |
// mezzo di trasporto |
| 1148 |
array( |
| 1149 |
'key' => 'mezzo', |
| 1150 |
'attr' => array( |
| 1151 |
'class="center"', |
| 1152 |
), |
| 1153 |
'label' => 'Mezzo di Trasporto', |
| 1154 |
), |
| 1155 |
// numero di ospiti |
| 1156 |
array( |
| 1157 |
'key' => 'guestsnum', |
| 1158 |
'attr' => array( |
| 1159 |
'class="center"' |
| 1160 |
), |
| 1161 |
'label' => 'Numero Ospiti', |
| 1162 |
'ignore_view' => 1, |
| 1163 |
), |
| 1164 |
// occupazione |
| 1165 |
array( |
| 1166 |
'key' => 'roomsbooked', |
| 1167 |
'attr' => array( |
| 1168 |
'class="center"' |
| 1169 |
), |
| 1170 |
'label' => 'Camere', |
| 1171 |
'ignore_view' => 1, |
| 1172 |
), |
| 1173 |
// id booking |
| 1174 |
array( |
| 1175 |
'key' => 'idbooking', |
| 1176 |
'attr' => array( |
| 1177 |
'class="center"' |
| 1178 |
), |
| 1179 |
'label' => 'ID / #', |
| 1180 |
), |
| 1181 |
); |
| 1182 |
|
| 1183 |
// line number (to facilitate identifying a specific guest in case of errors with the file submission) |
| 1184 |
$line_number = 0; |
| 1185 |
|
| 1186 |
// loop over the bookings to build the rows of the report |
| 1187 |
$from_info = getdate($from_ts); |
| 1188 |
foreach ($bookings as $gbook) { |
| 1189 |
$guestsnum = 0; |
| 1190 |
$guests_rows = [$gbook[0]]; |
| 1191 |
$room_guests = []; |
| 1192 |
$tot_guests_rows = 1; |
| 1193 |
|
| 1194 |
$tipo = 16; |
| 1195 |
// Codici Tipo Alloggiato |
| 1196 |
// 16 = Ospite Singolo |
| 1197 |
// 17 = Capofamiglia |
| 1198 |
// 18 = Capogruppo |
| 1199 |
// 19 = Familiare |
| 1200 |
// 20 = Membro Gruppo |
| 1201 |
|
| 1202 |
foreach ($gbook as $book) { |
| 1203 |
$guestsnum += $book['adults'] + $book['children']; |
| 1204 |
$room_guests[] = ($book['adults'] + $book['children']); |
| 1205 |
} |
| 1206 |
$pax_data = null; |
| 1207 |
if (!empty($gbook[0]['pax_data'])) { |
| 1208 |
$pax_data = json_decode($gbook[0]['pax_data'], true); |
| 1209 |
if (is_array($pax_data) && count($pax_data)) { |
| 1210 |
$guests_rows[0]['pax_data'] = $pax_data; |
| 1211 |
$tot_guests_rows = 0; |
| 1212 |
foreach ($pax_data as $roomguests) { |
| 1213 |
$tot_guests_rows += count($roomguests); |
| 1214 |
} |
| 1215 |
for ($i = 1; $i < $tot_guests_rows; $i++) { |
| 1216 |
array_push($guests_rows, $guests_rows[0]); |
| 1217 |
} |
| 1218 |
$tipo = count($guests_rows) > 1 ? 17 : $tipo; |
| 1219 |
} |
| 1220 |
} |
| 1221 |
|
| 1222 |
// create one row for each guest |
| 1223 |
$guest_ind = 1; |
| 1224 |
foreach ($guests_rows as $ind => $guests) { |
| 1225 |
// prepare row record |
| 1226 |
$insert_row = []; |
| 1227 |
|
| 1228 |
// find the actual guest-room-index |
| 1229 |
$guest_room_ind = $this->calcGuestRoomIndex($room_guests, $guest_ind); |
| 1230 |
|
| 1231 |
// booking code idswh for the PMS software |
| 1232 |
array_push($insert_row, array( |
| 1233 |
'key' => 'idswh', |
| 1234 |
'value' => $guests['id'] . '-' . $guest_ind, |
| 1235 |
)); |
| 1236 |
|
| 1237 |
// booking id |
| 1238 |
array_push($insert_row, array( |
| 1239 |
'key' => 'booking_id', |
| 1240 |
'value' => $guests['id'], |
| 1241 |
'ignore_view' => 1, |
| 1242 |
)); |
| 1243 |
|
| 1244 |
// reservation date |
| 1245 |
array_push($insert_row, array( |
| 1246 |
'key' => 'resdate', |
| 1247 |
'attr' => array( |
| 1248 |
'class="center"' |
| 1249 |
), |
| 1250 |
'callback' => function($val) { |
| 1251 |
return date('d/m/Y', $val); |
| 1252 |
}, |
| 1253 |
'callback_export' => function($val) { |
| 1254 |
return date('Ymd', $val); |
| 1255 |
}, |
| 1256 |
'value' => $guests['ts'], |
| 1257 |
)); |
| 1258 |
|
| 1259 |
// checkin date |
| 1260 |
array_push($insert_row, array( |
| 1261 |
'key' => 'checkin', |
| 1262 |
'attr' => array( |
| 1263 |
'class="center"' |
| 1264 |
), |
| 1265 |
'callback' => function($val) { |
| 1266 |
return date('d/m/Y', $val); |
| 1267 |
}, |
| 1268 |
'callback_export' => function($val) { |
| 1269 |
return date('Ymd', $val); |
| 1270 |
}, |
| 1271 |
'value' => $guests['checkin'], |
| 1272 |
)); |
| 1273 |
|
| 1274 |
// checkout date |
| 1275 |
array_push($insert_row,array( |
| 1276 |
'key' => 'checkout', |
| 1277 |
'attr' => array( |
| 1278 |
'class="center"' |
| 1279 |
), |
| 1280 |
'callback' => function($val) { |
| 1281 |
return date('d/m/Y', $val); |
| 1282 |
}, |
| 1283 |
'callback_export' => function($val) { |
| 1284 |
return date('Ymd', $val); |
| 1285 |
}, |
| 1286 |
'value' => $guests['checkout'], |
| 1287 |
)); |
| 1288 |
|
| 1289 |
// nome |
| 1290 |
$nome = !empty($guests['t_first_name']) ? $guests['t_first_name'] : $guests['first_name']; |
| 1291 |
$pax_nome = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'first_name'); |
| 1292 |
$nome = !empty($pax_nome) ? $pax_nome : $nome; |
| 1293 |
array_push($insert_row, array( |
| 1294 |
'key' => 'nome', |
| 1295 |
'value' => $nome |
| 1296 |
)); |
| 1297 |
|
| 1298 |
// cognome |
| 1299 |
$cognome = !empty($guests['t_last_name']) ? $guests['t_last_name'] : $guests['last_name']; |
| 1300 |
$pax_cognome = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'last_name'); |
| 1301 |
$cognome = !empty($pax_cognome) ? $pax_cognome : $cognome; |
| 1302 |
array_push($insert_row, array( |
| 1303 |
'key' => 'cognome', |
| 1304 |
'value' => $cognome |
| 1305 |
)); |
| 1306 |
|
| 1307 |
// sesso |
| 1308 |
$gender = !empty($guests['gender']) && $guest_ind < 2 ? strtoupper($guests['gender']) : ''; |
| 1309 |
$gender = $gender == 'F' ? 2 : ($gender == 'M' ? 1 : $gender); |
| 1310 |
$pax_gender = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'gender'); |
| 1311 |
$gender = !empty($pax_gender) ? $pax_gender : $gender; |
| 1312 |
if (is_numeric($gender)) { |
| 1313 |
$gender = (int)$gender; |
| 1314 |
} elseif (!strcasecmp($gender, 'F')) { |
| 1315 |
$gender = 2; |
| 1316 |
} elseif (!strcasecmp($gender, 'M')) { |
| 1317 |
$gender = 1; |
| 1318 |
} |
| 1319 |
array_push($insert_row, array( |
| 1320 |
'key' => 'gender', |
| 1321 |
'attr' => array( |
| 1322 |
'class="center'.(empty($gender) ? ' vbo-report-load-sesso' : '').'"' |
| 1323 |
), |
| 1324 |
'callback' => function($val) { |
| 1325 |
return $val == 2 ? 'F' : ($val == 1 ? 'M' : '?'); |
| 1326 |
}, |
| 1327 |
'callback_export' => function($val) { |
| 1328 |
return $val == 2 ? 'F' : ($val == 1 ? 'M' : '?'); |
| 1329 |
}, |
| 1330 |
'value' => $gender |
| 1331 |
)); |
| 1332 |
|
| 1333 |
// data di nascita |
| 1334 |
$dbirth = !empty($guests['bdate']) && $guest_ind < 2 ? VikBooking::getDateTimestamp($guests['bdate'], 0, 0) : ''; |
| 1335 |
$pax_dbirth = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'date_birth'); |
| 1336 |
$dbirth = !empty($pax_dbirth) ? $pax_dbirth : $dbirth; |
| 1337 |
if (!empty($dbirth)) { |
| 1338 |
$dbirth = str_replace(['/', '-', '.'], VikBooking::getDateSeparator(), (string) $dbirth); |
| 1339 |
} |
| 1340 |
$dbirth = (strpos($dbirth, '/') === false && strpos($dbirth, VikBooking::getDateSeparator()) === false) ? $dbirth : VikBooking::getDateTimestamp($dbirth, 0, 0); |
| 1341 |
array_push($insert_row, array( |
| 1342 |
'key' => 'dbirth', |
| 1343 |
'attr' => array( |
| 1344 |
'class="center'.(empty($dbirth) ? ' vbo-report-load-dbirth' : '').'"' |
| 1345 |
), |
| 1346 |
'callback' => function($val) { |
| 1347 |
if (!empty($val) && strpos($val, VikBooking::getDateSeparator()) === false) { |
| 1348 |
return date('d/m/Y', $val); |
| 1349 |
} |
| 1350 |
if (!empty($val) && strpos($val, VikBooking::getDateSeparator()) !== false) { |
| 1351 |
return $val; |
| 1352 |
} |
| 1353 |
return '?'; |
| 1354 |
}, |
| 1355 |
'callback_export' => function($val) { |
| 1356 |
if (!empty($val) && is_numeric($val)) { |
| 1357 |
return date('Ymd', $val); |
| 1358 |
} |
| 1359 |
if (!empty($val) && strlen($val) > 8) { |
| 1360 |
return date('Ymd', VikBooking::getDateTimestamp($val)); |
| 1361 |
} |
| 1362 |
return $val ?: '?'; |
| 1363 |
}, |
| 1364 |
'value' => $dbirth |
| 1365 |
)); |
| 1366 |
|
| 1367 |
// cittadinanza (compatible with pax data field of driver "Italy") |
| 1368 |
$pax_country_c = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'country_c'); |
| 1369 |
$citizen = !empty($guests['country']) && $guest_ind < 2 ? $guests['country'] : ''; |
| 1370 |
$citizenval = ''; |
| 1371 |
if (!empty($citizen) && $guest_ind < 2) { |
| 1372 |
$citizenval = $this->checkCountry($citizen); |
| 1373 |
} |
| 1374 |
|
| 1375 |
// check nationality field from pre-checkin |
| 1376 |
$pax_citizen = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'nationality'); |
| 1377 |
$citizen = !empty($pax_citizen) ? $pax_citizen : $citizen; |
| 1378 |
$citizen = !empty($pax_country_c) ? $pax_country_c : $citizen; |
| 1379 |
$citizenval = $this->checkCountry((!empty($pax_country_c) ? $pax_country_c : $citizen)); |
| 1380 |
array_push($insert_row, array( |
| 1381 |
'key' => 'citizen', |
| 1382 |
'attr' => array( |
| 1383 |
'class="center'.(empty($citizen) ? ' vbo-report-load-cittadinanza' : '').'"', |
| 1384 |
), |
| 1385 |
'callback' => function($val) { |
| 1386 |
return !empty($val) && isset($this->nazioni[$val]) ? $this->nazioni[$val]['name'] : '?'; |
| 1387 |
}, |
| 1388 |
'no_export_callback' => 1, |
| 1389 |
'value' => !empty($citizenval) ? $citizenval : '', |
| 1390 |
)); |
| 1391 |
|
| 1392 |
// stato di residenza |
| 1393 |
$provstay = ''; |
| 1394 |
$pax_provstay = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, ($guest_ind < 2 ? 'country_s' : 'country_b')); |
| 1395 |
$provstay = !empty($pax_provstay) ? $pax_provstay : $provstay; |
| 1396 |
array_push($insert_row, array( |
| 1397 |
'key' => 'stares', |
| 1398 |
'attr' => array( |
| 1399 |
'class="center'.(empty($provstay) ? ' vbo-report-load-nazione' : '').'"', |
| 1400 |
), |
| 1401 |
'callback' => function($val) { |
| 1402 |
if (!empty($val) && isset($this->nazioni[$val])) { |
| 1403 |
return $this->nazioni[$val]['name']; |
| 1404 |
} |
| 1405 |
// information is missing and should be provided |
| 1406 |
return '?'; |
| 1407 |
}, |
| 1408 |
'no_export_callback' => 1, |
| 1409 |
'value' => $provstay, |
| 1410 |
)); |
| 1411 |
|
| 1412 |
// comune di residenza |
| 1413 |
$comstay = ''; |
| 1414 |
$pax_comstay = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, ($guest_ind < 2 ? 'comune_s' : 'comune_b')); |
| 1415 |
$pax_comstay = $pax_comstay ?: $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, ($guest_ind < 2 ? 'province_s' : 'province_b')); |
| 1416 |
$comstay = !empty($pax_comstay) ? $pax_comstay : $comstay; |
| 1417 |
if (empty($comstay) && !empty($provstay) && $provstay != '100000100' && strtoupper(substr((string) $provstay, 0, 2)) != 'IT') { |
| 1418 |
// we assume the guest is not Italian |
| 1419 |
$comstay = 'ES'; |
| 1420 |
} |
| 1421 |
array_push($insert_row, array( |
| 1422 |
'key' => 'comres', |
| 1423 |
'attr' => array( |
| 1424 |
'class="center'.(empty($comstay) ? ' vbo-report-load-comune' : ' vbo-report-load-comune vbo-report-load-elem-filled').'"' |
| 1425 |
), |
| 1426 |
'callback' => function($val) { |
| 1427 |
if (!empty($val) && isset($this->comuniProvince['comuni'][$val])) { |
| 1428 |
return $this->comuniProvince['comuni'][$val]['name']; |
| 1429 |
} |
| 1430 |
if ($val === 'ES') { |
| 1431 |
return 'Estero'; |
| 1432 |
} |
| 1433 |
// information is missing and should be provided |
| 1434 |
return $val ?: '?'; |
| 1435 |
}, |
| 1436 |
'no_export_callback' => 1, |
| 1437 |
'value' => $comstay, |
| 1438 |
)); |
| 1439 |
|
| 1440 |
// tipo alloggiato |
| 1441 |
$use_tipo = $ind > 0 && $tipo == 17 ? 19 : $tipo; |
| 1442 |
$pax_guest_type = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'guest_type'); |
| 1443 |
$use_tipo = !empty($pax_guest_type) ? $pax_guest_type : $use_tipo; |
| 1444 |
array_push($insert_row, array( |
| 1445 |
'key' => 'tipo', |
| 1446 |
'callback' => function($val) { |
| 1447 |
switch ($val) { |
| 1448 |
case 16: |
| 1449 |
return 'Ospite Singolo'; |
| 1450 |
case 17: |
| 1451 |
return 'Capofamiglia'; |
| 1452 |
case 18: |
| 1453 |
return 'Capogruppo'; |
| 1454 |
case 19: |
| 1455 |
return 'Familiare'; |
| 1456 |
case 20: |
| 1457 |
return 'Membro Gruppo'; |
| 1458 |
} |
| 1459 |
return '?'; |
| 1460 |
}, |
| 1461 |
'no_export_callback' => 1, |
| 1462 |
'value' => $use_tipo |
| 1463 |
)); |
| 1464 |
|
| 1465 |
// tipo di turismo |
| 1466 |
$pax_turismo = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'turismo'); |
| 1467 |
array_push($insert_row, array( |
| 1468 |
'key' => 'turismo', |
| 1469 |
'attr' => array( |
| 1470 |
'class="center' . (empty($pax_turismo) ? ' vbo-report-load-turismo vbo-report-load-elem-filled' : ' vbo-report-load-field-optional') . '"', |
| 1471 |
), |
| 1472 |
'callback' => function($val) { |
| 1473 |
return $this->tourismTypes[$val] ?? $val; |
| 1474 |
}, |
| 1475 |
'no_export_callback' => 1, |
| 1476 |
'value' => ($pax_turismo ?: 'NON SPECIFICATO'), |
| 1477 |
)); |
| 1478 |
|
| 1479 |
// mezzo di trasporto |
| 1480 |
$pax_mezzo = $this->getGuestPaxDataValue($pax_data, $room_guests, $guest_ind, 'mezzo'); |
| 1481 |
array_push($insert_row, array( |
| 1482 |
'key' => 'mezzo', |
| 1483 |
'attr' => array( |
| 1484 |
'class="center' . (empty($pax_mezzo) ? ' vbo-report-load-trasporto vbo-report-load-elem-filled' : ' vbo-report-load-field-optional') . '"', |
| 1485 |
), |
| 1486 |
'callback' => function($val) { |
| 1487 |
return $this->meaningsOfTransport[$val] ?? $val; |
| 1488 |
}, |
| 1489 |
'no_export_callback' => 1, |
| 1490 |
'value' => ($pax_mezzo ?: 'NON SPECIFICATO'), |
| 1491 |
)); |
| 1492 |
|
| 1493 |
// numero di ospiti |
| 1494 |
array_push($insert_row, array( |
| 1495 |
'key' => 'guestsnum', |
| 1496 |
'attr' => array( |
| 1497 |
'class="center"', |
| 1498 |
), |
| 1499 |
'value' => $guestsnum, |
| 1500 |
'ignore_view' => 1, |
| 1501 |
)); |
| 1502 |
|
| 1503 |
// camere prenotate |
| 1504 |
array_push($insert_row, array( |
| 1505 |
'key' => 'roomsbooked', |
| 1506 |
'attr' => array( |
| 1507 |
'class="center"', |
| 1508 |
), |
| 1509 |
'value' => count($gbook), |
| 1510 |
'ignore_view' => 1, |
| 1511 |
)); |
| 1512 |
|
| 1513 |
// id booking |
| 1514 |
array_push($insert_row, array( |
| 1515 |
'key' => 'idbooking', |
| 1516 |
'attr' => array( |
| 1517 |
'class="center"', |
| 1518 |
), |
| 1519 |
'callback' => function($val) use ($line_number) { |
| 1520 |
// make sure to keep the data-bid attribute as it's used by JS to identify the booking ID |
| 1521 |
return '<a data-bid="' . $val . '" href="index.php?option=com_vikbooking&task=editorder&cid[]=' . $val . '" target="_blank"><i class="' . VikBookingIcons::i('external-link') . '"></i> ' . $val . '</a> / <span>#' . $line_number . '</span>'; |
| 1522 |
}, |
| 1523 |
'ignore_export' => 1, |
| 1524 |
'value' => $guests['id'], |
| 1525 |
)); |
| 1526 |
|
| 1527 |
// push fields in the rows array as a new row |
| 1528 |
array_push($this->rows, $insert_row); |
| 1529 |
|
| 1530 |
// increment guest index |
| 1531 |
$guest_ind++; |
| 1532 |
|
| 1533 |
// increment line number |
| 1534 |
$line_number++; |
| 1535 |
} |
| 1536 |
} |
| 1537 |
|
| 1538 |
// do not sort the rows for this report because the lines of the guests of the same booking must be consecutive |
| 1539 |
// $this->sortRows($pkrsort, $pkrorder); |
| 1540 |
|
| 1541 |
// the footer row will just print the amount of records to export |
| 1542 |
array_push($this->footerRow, array( |
| 1543 |
array( |
| 1544 |
'attr' => array( |
| 1545 |
'class="vbo-report-total"', |
| 1546 |
), |
| 1547 |
'value' => '<h3>' . JText::translate('VBOREPORTSTOTALROW') . '</h3>', |
| 1548 |
), |
| 1549 |
array( |
| 1550 |
'attr' => array( |
| 1551 |
'colspan="' . (count($this->cols) - 1) . '"', |
| 1552 |
), |
| 1553 |
'value' => count($this->rows), |
| 1554 |
) |
| 1555 |
)); |
| 1556 |
|
| 1557 |
return true; |
| 1558 |
} |
| 1559 |
|
| 1560 |
public function formatXML($xml) |
| 1561 |
{ |
| 1562 |
if (!class_exists('DOMDocument')) { |
| 1563 |
// we cannot format the XML because DOMDocument is missing |
| 1564 |
return $xml; |
| 1565 |
} |
| 1566 |
|
| 1567 |
$dom = new DOMDocument; |
| 1568 |
$dom->preserveWhiteSpace = false; |
| 1569 |
$dom->loadXML($xml); |
| 1570 |
$dom->formatOutput = true; |
| 1571 |
$xml = $dom->saveXML(); |
| 1572 |
|
| 1573 |
return $xml; |
| 1574 |
} |
| 1575 |
|
| 1576 |
/** |
| 1577 |
* Generates the authority file, then sends it to output for download. |
| 1578 |
* In case of errors, the process is not terminated (exit) to let the View display the |
| 1579 |
* error message(s). The export type argument can eventually determine an action to run. |
| 1580 |
* |
| 1581 |
* @param string $export_type Differentiates the type of export requested. |
| 1582 |
* |
| 1583 |
* @return void|bool Void in case of script termination, boolean otherwise. |
| 1584 |
* |
| 1585 |
* @since 1.17.2 (J) - 1.7.2 (WP) method's logic refactoring. |
| 1586 |
*/ |
| 1587 |
public function customExport($export_type = null) |
| 1588 |
{ |
| 1589 |
// build the XML file |
| 1590 |
$xml = $this->buildXMLFile(); |
| 1591 |
|
| 1592 |
if ($this->datesHaveNoBookings) { |
| 1593 |
// reset errors that may have been set for the View in case of no bookings to proceed |
| 1594 |
$this->resetErrors(); |
| 1595 |
} |
| 1596 |
|
| 1597 |
// build report action data, if needed |
| 1598 |
$action_data = array_merge($this->getActionData($registry = false), ['xml' => $xml]); |
| 1599 |
|
| 1600 |
/** |
| 1601 |
* Custom export method can run a custom action. |
| 1602 |
*/ |
| 1603 |
if ($export_type && !is_numeric($export_type)) { |
| 1604 |
try { |
| 1605 |
// ensure the type of export is a callable scoped action, hidden or visible |
| 1606 |
$actions = $this->getScopedActions($this->getScope(), $visible = false); |
| 1607 |
$action_ids = array_column($actions, 'id'); |
| 1608 |
$action_names = array_column($actions, 'name'); |
| 1609 |
if (!in_array($export_type, $action_ids)) { |
| 1610 |
throw new Exception(sprintf('Cannot invoke the requested type of export [%s].', $export_type), 403); |
| 1611 |
} |
| 1612 |
|
| 1613 |
// get the requested action readable name |
| 1614 |
$action_name = $action_names[array_search($export_type, $action_ids)]; |
| 1615 |
|
| 1616 |
if ($this->getScope() === 'web') { |
| 1617 |
// run the action and output the HTML response string |
| 1618 |
$html_result = $this->_callActionReturn($export_type, 'html', $this->getScope(), $action_data); |
| 1619 |
|
| 1620 |
// build the action result data object |
| 1621 |
$js_result = json_encode([ |
| 1622 |
'actionName' => $action_name, |
| 1623 |
'actionHtml' => $html_result, |
| 1624 |
]); |
| 1625 |
|
| 1626 |
// render modal script with the action result |
| 1627 |
JFactory::getDocument()->addScriptDeclaration( |
| 1628 |
<<<JS |
| 1629 |
;(function($) { |
| 1630 |
$(function() { |
| 1631 |
let result = $js_result; |
| 1632 |
VBOCore.displayModal({ |
| 1633 |
suffix: 'report-custom-scopedaction-result', |
| 1634 |
extra_class: 'vbo-modal-rounded vbo-modal-tall vbo-modal-nofooter', |
| 1635 |
title: result.actionName, |
| 1636 |
body: result.actionHtml, |
| 1637 |
}); |
| 1638 |
}); |
| 1639 |
})(jQuery); |
| 1640 |
JS |
| 1641 |
); |
| 1642 |
|
| 1643 |
// abort and let the View render the result within a modal |
| 1644 |
return; |
| 1645 |
} |
| 1646 |
|
| 1647 |
// let the report custom action run and return a boolean value if invoked by a cron |
| 1648 |
return (bool) $this->_callActionReturn($export_type, 'success', $this->getScope(), $action_data); |
| 1649 |
|
| 1650 |
} catch (Exception $e) { |
| 1651 |
// silently catch the error and set it |
| 1652 |
$this->setError(sprintf('(%s) %s', $e->getCode(), $e->getMessage())); |
| 1653 |
|
| 1654 |
// abort |
| 1655 |
return false; |
| 1656 |
} |
| 1657 |
} |
| 1658 |
|
| 1659 |
// proceed with the regular export function (write on file through cron or download file through web) |
| 1660 |
|
| 1661 |
if (!$xml) { |
| 1662 |
// abort |
| 1663 |
return false; |
| 1664 |
} |
| 1665 |
|
| 1666 |
// update history for all bookings affected before exporting |
| 1667 |
foreach ($this->export_booking_ids as $bid) { |
| 1668 |
VikBooking::getBookingHistoryInstance($bid)->store('RP', $this->reportName); |
| 1669 |
} |
| 1670 |
|
| 1671 |
/** |
| 1672 |
* Custom export method supports a custom export handler, if previously set. |
| 1673 |
* |
| 1674 |
* @since 1.16.1 (J) - 1.6.1 (WP) |
| 1675 |
*/ |
| 1676 |
if ($this->hasExportHandler()) { |
| 1677 |
// write data onto the custom file handler |
| 1678 |
$fp = $this->getExportCSVHandler(); |
| 1679 |
fwrite($fp, $xml); |
| 1680 |
fclose($fp); |
| 1681 |
|
| 1682 |
// return true as data was written |
| 1683 |
return true; |
| 1684 |
} |
| 1685 |
|
| 1686 |
// force file download in case of regular export |
| 1687 |
header("Content-type: text/xml"); |
| 1688 |
header("Cache-Control: no-store, no-cache"); |
| 1689 |
header('Content-Disposition: attachment; filename="' . $this->getExportCSVFileName() . '"'); |
| 1690 |
echo $xml; |
| 1691 |
|
| 1692 |
exit; |
| 1693 |
} |
| 1694 |
|
| 1695 |
/** |
| 1696 |
* Builds the XML file for export or transmission. |
| 1697 |
* |
| 1698 |
* @return string Empty string in case of errors, XML otherwise. |
| 1699 |
* |
| 1700 |
* @since 1.17.2 (J) - 1.7.2 (WP) implemented dedicated method to file generation. |
| 1701 |
*/ |
| 1702 |
protected function buildXMLFile() |
| 1703 |
{ |
| 1704 |
if (!$this->getReportData() && !$this->datesHaveNoBookings) { |
| 1705 |
// do not generate the XML file |
| 1706 |
return ''; |
| 1707 |
} |
| 1708 |
|
| 1709 |
// load report settings |
| 1710 |
$settings = $this->loadSettings(); |
| 1711 |
|
| 1712 |
// get the possibly injected report options |
| 1713 |
$options = $this->getReportOptions(); |
| 1714 |
|
| 1715 |
// injected options will substitute request variables, if any |
| 1716 |
$pfromdate = VikRequest::getString('fromdate', $options->get('fromdate', ''), 'request'); |
| 1717 |
$ptodate = VikRequest::getString('todate', $options->get('todate', ''), 'request'); |
| 1718 |
|
| 1719 |
// access manually filled values, if any |
| 1720 |
$pfiller = VikRequest::getString('filler', '', 'request', VIKREQUEST_ALLOWRAW); |
| 1721 |
$pfiller = !empty($pfiller) ? (array) json_decode($pfiller, true) : []; |
| 1722 |
|
| 1723 |
// numero letti |
| 1724 |
$total_beds = (int) ($settings['numletti'] ?? 1); |
| 1725 |
|
| 1726 |
// count total number of room units |
| 1727 |
$total_rooms = (int) ($settings['numcamere'] ?? $this->countRooms()); |
| 1728 |
|
| 1729 |
// date timestamps |
| 1730 |
$from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0); |
| 1731 |
$to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59, 59); |
| 1732 |
|
| 1733 |
// suppress warning messages |
| 1734 |
libxml_use_internal_errors(true); |
| 1735 |
|
| 1736 |
// get the SimpleXMLElement object |
| 1737 |
$xml = simplexml_load_string('<movimenti></movimenti>'); |
| 1738 |
|
| 1739 |
// add property code and PMS name |
| 1740 |
$xml->addChild('codice', htmlspecialchars($settings['codstru'])); |
| 1741 |
$xml->addChild('prodotto', htmlspecialchars('E4jConnect/VikBooking')); |
| 1742 |
|
| 1743 |
// scan all given dates |
| 1744 |
$date_info = getdate($from_ts); |
| 1745 |
while ($date_info[0] <= $to_ts) { |
| 1746 |
// get today's date in Y-m-d format |
| 1747 |
$today_ymd = date('Y-m-d', $date_info[0]); |
| 1748 |
|
| 1749 |
// open movimento node for this day |
| 1750 |
$movement = $xml->addChild('movimento'); |
| 1751 |
|
| 1752 |
// populate movimento date |
| 1753 |
$movement->addChild('data', date('Ymd', $date_info[0])); |
| 1754 |
|
| 1755 |
// populate movimento property data |
| 1756 |
$property = $movement->addChild('struttura'); |
| 1757 |
|
| 1758 |
// whether the property is open today |
| 1759 |
$is_open = (bool) (!VikBooking::validateClosingDates($date_info[0], $date_info[0])); |
| 1760 |
$property->addChild('apertura', ($is_open ? 'SI' : 'NO')); |
| 1761 |
|
| 1762 |
// number of occupied rooms today, rooms and beds available |
| 1763 |
if (!$is_open) { |
| 1764 |
// property is closed today, so all values should be set as 0 |
| 1765 |
$property->addChild('camereoccupate', 0); |
| 1766 |
$property->addChild('cameredisponibili', 0); |
| 1767 |
$property->addChild('lettidisponibili', 0); |
| 1768 |
|
| 1769 |
// go to next day without even checking the bookings or report rows |
| 1770 |
$date_info = getdate(mktime(0, 0, 0, $date_info['mon'], $date_info['mday'] + 1, $date_info['year'])); |
| 1771 |
|
| 1772 |
// do not proceed for today |
| 1773 |
continue; |
| 1774 |
} |
| 1775 |
|
| 1776 |
// check if some listings were filtered |
| 1777 |
$filtered_listings = (array) (VikRequest::getVar('listings', array()) ?: $options->get('listings', [])); |
| 1778 |
$filtered_listings = array_filter(array_map('intval', $filtered_listings)); |
| 1779 |
|
| 1780 |
// property is open today |
| 1781 |
$property->addChild('camereoccupate', $this->countDayRoomsOccupied($date_info[0], $filtered_listings)); |
| 1782 |
$property->addChild('cameredisponibili', $total_rooms); |
| 1783 |
$property->addChild('lettidisponibili', $total_beds); |
| 1784 |
|
| 1785 |
// check for arrivals, departures or reservations dated today |
| 1786 |
$today_arrivals = []; |
| 1787 |
$today_departures = []; |
| 1788 |
$today_reservations = []; |
| 1789 |
|
| 1790 |
// scan all report rows to gather the needed record types |
| 1791 |
foreach ($this->rows as $ind => $row) { |
| 1792 |
// booking ID flags |
| 1793 |
$current_bid = 0; |
| 1794 |
$current_idswh = ''; |
| 1795 |
|
| 1796 |
// scan row column values |
| 1797 |
foreach ($row as $field) { |
| 1798 |
if ($field['key'] == 'idswh') { |
| 1799 |
// set booking (software) ID |
| 1800 |
$current_idswh = (string) $field['value']; |
| 1801 |
continue; |
| 1802 |
} |
| 1803 |
|
| 1804 |
if ($field['key'] == 'booking_id') { |
| 1805 |
// set booking ID |
| 1806 |
$current_bid = (int) $field['value']; |
| 1807 |
continue; |
| 1808 |
} |
| 1809 |
|
| 1810 |
// check where this whole booking row should be allocated |
| 1811 |
if ($current_bid && $current_idswh) { |
| 1812 |
if ($field['key'] == 'resdate' && date('Y-m-d', $field['value']) == $today_ymd && !($today_reservations[$current_bid] ?? null)) { |
| 1813 |
// this is a reservation made today (one per booking ID, not one per guest) |
| 1814 |
$today_reservations[$current_bid] = $row; |
| 1815 |
} |
| 1816 |
|
| 1817 |
if ($field['key'] == 'checkin' && date('Y-m-d', $field['value']) == $today_ymd && !($today_arrivals[$current_idswh] ?? null)) { |
| 1818 |
// this is a guest arriving today (one row per guest, not per booking) |
| 1819 |
$today_arrivals[$current_idswh] = $row; |
| 1820 |
} |
| 1821 |
|
| 1822 |
if ($field['key'] == 'checkout' && date('Y-m-d', $field['value']) == $today_ymd && !($today_departures[$current_idswh] ?? null)) { |
| 1823 |
// this is a guest departing today (one row per guest, not per booking) |
| 1824 |
$today_departures[$current_idswh] = $row; |
| 1825 |
} |
| 1826 |
} |
| 1827 |
} |
| 1828 |
|
| 1829 |
// push booking ID involved for the export |
| 1830 |
if ($current_bid && !in_array($current_bid, $this->export_booking_ids)) { |
| 1831 |
$this->export_booking_ids[] = $current_bid; |
| 1832 |
} |
| 1833 |
} |
| 1834 |
|
| 1835 |
// check for arrivals first |
| 1836 |
if ($today_arrivals) { |
| 1837 |
// open "arrivals" node |
| 1838 |
$arrivals = $movement->addChild('arrivi'); |
| 1839 |
|
| 1840 |
// map of booking guest heads |
| 1841 |
$booking_guest_heads = []; |
| 1842 |
|
| 1843 |
// scan all arrivals for today |
| 1844 |
foreach ($today_arrivals as $today_arrival_row) { |
| 1845 |
// open "arrival" node |
| 1846 |
$arrival = $arrivals->addChild('arrivo'); |
| 1847 |
|
| 1848 |
// booking ID flags |
| 1849 |
$current_bid = 0; |
| 1850 |
$current_idswh = ''; |
| 1851 |
|
| 1852 |
// guest registration values |
| 1853 |
$guest_reg_vals = []; |
| 1854 |
|
| 1855 |
// scan row column values |
| 1856 |
foreach ($today_arrival_row as $field) { |
| 1857 |
// store guest registration value |
| 1858 |
$guest_reg_vals[$field['key']] = $this->getExportFieldValue($field); |
| 1859 |
|
| 1860 |
if ($field['key'] == 'idswh') { |
| 1861 |
// set booking (software) ID |
| 1862 |
$current_idswh = (string) $field['value']; |
| 1863 |
continue; |
| 1864 |
} |
| 1865 |
|
| 1866 |
if ($field['key'] == 'booking_id') { |
| 1867 |
// set booking ID |
| 1868 |
$current_bid = (int) $field['value']; |
| 1869 |
continue; |
| 1870 |
} |
| 1871 |
|
| 1872 |
if ($current_idswh && $current_bid && $field['key'] == 'tipo' && in_array((int) $field['value'], [17, 18])) { |
| 1873 |
// this is either a "Capofamiglia" or "Capogruppo", add relation |
| 1874 |
$booking_guest_heads[$current_bid] = $current_idswh; |
| 1875 |
} |
| 1876 |
} |
| 1877 |
|
| 1878 |
// add elements |
| 1879 |
$arrival->addChild('idswh', htmlspecialchars($guest_reg_vals['idswh'])); |
| 1880 |
$arrival->addChild('tipoalloggiato', htmlspecialchars($guest_reg_vals['tipo'] ?? '')); |
| 1881 |
if (($booking_guest_heads[$current_bid] ?? null) && $booking_guest_heads[$current_bid] != $guest_reg_vals['idswh']) { |
| 1882 |
$arrival->addChild('idcapo', htmlspecialchars($booking_guest_heads[$current_bid])); |
| 1883 |
} |
| 1884 |
$arrival->addChild('cognome', htmlspecialchars($guest_reg_vals['cognome'] ?? '')); |
| 1885 |
$arrival->addChild('nome', htmlspecialchars($guest_reg_vals['nome'] ?? '')); |
| 1886 |
$arrival->addChild('sesso', htmlspecialchars($guest_reg_vals['gender'] ?? 'M')); |
| 1887 |
$arrival->addChild('cittadinanza', htmlspecialchars($guest_reg_vals['citizen'] ?? '')); |
| 1888 |
$arrival->addChild('statoresidenza', htmlspecialchars($guest_reg_vals['stares'] ?? '')); |
| 1889 |
$arrival->addChild('luogoresidenza', htmlspecialchars($guest_reg_vals['comres'] ?? '')); |
| 1890 |
$arrival->addChild('datanascita', htmlspecialchars($guest_reg_vals['dbirth'] ?? '')); |
| 1891 |
$arrival->addChild('tipoturismo', htmlspecialchars($guest_reg_vals['turismo'] ?? '')); |
| 1892 |
$arrival->addChild('mezzotrasporto', htmlspecialchars($guest_reg_vals['mezzo'] ?? '')); |
| 1893 |
} |
| 1894 |
} |
| 1895 |
|
| 1896 |
// then check for departures |
| 1897 |
if ($today_departures) { |
| 1898 |
// open "departures" node |
| 1899 |
$departures = $movement->addChild('partenze'); |
| 1900 |
|
| 1901 |
// scan all departures for today |
| 1902 |
foreach ($today_departures as $today_departure_row) { |
| 1903 |
// open "departure" node |
| 1904 |
$departure = $departures->addChild('partenza'); |
| 1905 |
|
| 1906 |
// guest registration values |
| 1907 |
$guest_reg_vals = $this->getAssocRowData($today_departure_row); |
| 1908 |
|
| 1909 |
// add elements |
| 1910 |
$departure->addChild('idswh', htmlspecialchars($guest_reg_vals['idswh'] ?? '')); |
| 1911 |
$departure->addChild('tipoalloggiato', htmlspecialchars($guest_reg_vals['tipo'] ?? '')); |
| 1912 |
$departure->addChild('arrivo', htmlspecialchars($guest_reg_vals['checkin'] ?? '')); |
| 1913 |
} |
| 1914 |
} |
| 1915 |
|
| 1916 |
// finally, check for reservations |
| 1917 |
if ($today_reservations) { |
| 1918 |
// open "reservations" node |
| 1919 |
$reservations = $movement->addChild('prenotazioni'); |
| 1920 |
|
| 1921 |
// scan all reservations for today |
| 1922 |
foreach ($today_reservations as $today_reservation_row) { |
| 1923 |
// open "reservation" node |
| 1924 |
$reservation = $reservations->addChild('prenotazione'); |
| 1925 |
|
| 1926 |
// guest registration values |
| 1927 |
$guest_reg_vals = $this->getAssocRowData($today_reservation_row); |
| 1928 |
|
| 1929 |
// add elements |
| 1930 |
$reservation->addChild('idswh', htmlspecialchars($guest_reg_vals['idswh'] ?? '')); |
| 1931 |
$reservation->addChild('arrivo', htmlspecialchars($guest_reg_vals['checkin'] ?? '')); |
| 1932 |
$reservation->addChild('partenza', htmlspecialchars($guest_reg_vals['checkout'] ?? '')); |
| 1933 |
$reservation->addChild('ospiti', intval($guest_reg_vals['guestsnum'] ?? 1)); |
| 1934 |
$reservation->addChild('camere', intval($guest_reg_vals['roomsbooked'] ?? 1)); |
| 1935 |
} |
| 1936 |
} |
| 1937 |
|
| 1938 |
// go to next day |
| 1939 |
$date_info = getdate(mktime(0, 0, 0, $date_info['mon'], $date_info['mday'] + 1, $date_info['year'])); |
| 1940 |
} |
| 1941 |
|
| 1942 |
// format XML document and return it |
| 1943 |
return $this->formatXML($xml->asXML()); |
| 1944 |
} |
| 1945 |
|
| 1946 |
/** |
| 1947 |
* Given a field (row-column) associative list of data, performs |
| 1948 |
* the necessary callback operations to get the value to export. |
| 1949 |
* |
| 1950 |
* @param array $field The row-column exporting data. |
| 1951 |
* |
| 1952 |
* @return mixed The field value to export. |
| 1953 |
* |
| 1954 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 1955 |
*/ |
| 1956 |
protected function getExportFieldValue(array $field) |
| 1957 |
{ |
| 1958 |
$field_val = $field['value']; |
| 1959 |
|
| 1960 |
if ($field['callback_export'] ?? null) { |
| 1961 |
$field['callback'] = $field['callback_export']; |
| 1962 |
} |
| 1963 |
|
| 1964 |
if (!($field['no_export_callback'] ?? 0) && is_callable($field['callback'] ?? null)) { |
| 1965 |
$field_val = $field['callback']($field_val); |
| 1966 |
} |
| 1967 |
|
| 1968 |
return $field_val; |
| 1969 |
} |
| 1970 |
|
| 1971 |
/** |
| 1972 |
* Parses a report row into an associative list of key-value pairs. |
| 1973 |
* |
| 1974 |
* @param array $row The report row to parse. |
| 1975 |
* |
| 1976 |
* @return array |
| 1977 |
* |
| 1978 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 1979 |
*/ |
| 1980 |
protected function getAssocRowData(array $row) |
| 1981 |
{ |
| 1982 |
$row_data = []; |
| 1983 |
|
| 1984 |
foreach ($row as $field) { |
| 1985 |
$field_val = $field['value']; |
| 1986 |
|
| 1987 |
if ($field['callback_export'] ?? null) { |
| 1988 |
$field['callback'] = $field['callback_export']; |
| 1989 |
} |
| 1990 |
|
| 1991 |
if (!($field['no_export_callback'] ?? 0) && is_callable($field['callback'] ?? null)) { |
| 1992 |
$field_val = $field['callback']($field_val); |
| 1993 |
} |
| 1994 |
|
| 1995 |
$row_data[$field['key']] = $field_val; |
| 1996 |
} |
| 1997 |
|
| 1998 |
return $row_data; |
| 1999 |
} |
| 2000 |
|
| 2001 |
/** |
| 2002 |
* Counts the number of occupied rooms on the given day. |
| 2003 |
* |
| 2004 |
* @param int $day_ts The day timestamp (at midnight). |
| 2005 |
* @param array $listings Optional list of filtered listing IDs. |
| 2006 |
* |
| 2007 |
* @return int Number of occupied rooms found. |
| 2008 |
* |
| 2009 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 2010 |
* @since 1.18.0 (J) - 1.8.0 (WP) added support for $listings argument. |
| 2011 |
*/ |
| 2012 |
protected function countDayRoomsOccupied($day_ts, array $listings = []) |
| 2013 |
{ |
| 2014 |
// get the timestamp at the last second of the day |
| 2015 |
$day_ts = strtotime('23:59:59', $day_ts); |
| 2016 |
|
| 2017 |
$dbo = JFactory::getDbo(); |
| 2018 |
|
| 2019 |
if ($listings) { |
| 2020 |
// perform a more accurate query over the listings specified |
| 2021 |
$dbo->setQuery( |
| 2022 |
$dbo->getQuery(true) |
| 2023 |
->select('COUNT(*)') |
| 2024 |
->from($dbo->qn('#__vikbooking_orders', 'o')) |
| 2025 |
->leftJoin($dbo->qn('#__vikbooking_ordersrooms', 'or') . ' ON ' . $dbo->qn('o.id') . ' = ' . $dbo->qn('or.idorder')) |
| 2026 |
->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed')) |
| 2027 |
->where($dbo->qn('o.closure') . ' = 0') |
| 2028 |
->where($dbo->qn('o.checkin') . ' < ' . (int) $day_ts) |
| 2029 |
->where($dbo->qn('o.checkout') . ' > ' . (int) $day_ts) |
| 2030 |
->where($dbo->qn('or.idroom') . ' IN (' . implode(', ', array_map('intval', $listings)) . ')') |
| 2031 |
); |
| 2032 |
} else { |
| 2033 |
// quick query to fetch the total number of occupied rooms |
| 2034 |
$dbo->setQuery( |
| 2035 |
$dbo->getQuery(true) |
| 2036 |
->select('SUM(' . $dbo->qn('roomsnum') . ')') |
| 2037 |
->from($dbo->qn('#__vikbooking_orders')) |
| 2038 |
->where($dbo->qn('status') . ' = ' . $dbo->q('confirmed')) |
| 2039 |
->where($dbo->qn('closure') . ' = 0') |
| 2040 |
->where($dbo->qn('checkin') . ' < ' . (int) $day_ts) |
| 2041 |
->where($dbo->qn('checkout') . ' > ' . (int) $day_ts) |
| 2042 |
); |
| 2043 |
} |
| 2044 |
|
| 2045 |
return (int) $dbo->loadResult(); |
| 2046 |
} |
| 2047 |
|
| 2048 |
/** |
| 2049 |
* Custom scoped action to transmit the XML ISTAT file to the local authority. |
| 2050 |
* Accepted scopes are "web" and "cron", so the "success" property must be returned. |
| 2051 |
* |
| 2052 |
* @param string $scope Optional scope identifier (cron, web, etc..). |
| 2053 |
* @param array $data Optional associative list of data to process. |
| 2054 |
* |
| 2055 |
* @return array The execution result properties. |
| 2056 |
* |
| 2057 |
* @throws Exception |
| 2058 |
*/ |
| 2059 |
protected function transmitRecords($scope = null, array $data = []) |
| 2060 |
{ |
| 2061 |
if (!($data['xml'] ?? '') && $scope === 'web') { |
| 2062 |
// start the process through the interface by submitting the current data |
| 2063 |
return [ |
| 2064 |
'html' => '<script type="text/javascript">vboDownloadSchedaIstat(\'transmitRecords\');</script>', |
| 2065 |
]; |
| 2066 |
} |
| 2067 |
|
| 2068 |
if (!($data['xml'] ?? '')) { |
| 2069 |
// attempt to build the XML file if not set |
| 2070 |
$data['xml'] = $this->buildXMLFile(); |
| 2071 |
} |
| 2072 |
|
| 2073 |
if (!$data['xml']) { |
| 2074 |
throw new Exception('Missing XML request message.', 500); |
| 2075 |
} |
| 2076 |
|
| 2077 |
// load report settings |
| 2078 |
$settings = $this->loadSettings(); |
| 2079 |
|
| 2080 |
if (!$settings || empty($settings['codstru']) || empty($settings['user']) || empty($settings['pwd']) || empty($settings['endpoint'])) { |
| 2081 |
throw new Exception(sprintf('[%s] error: impostazioni report mancanti.', __METHOD__), 500); |
| 2082 |
} |
| 2083 |
|
| 2084 |
// build the SOAP XML string for the request body |
| 2085 |
$soap_xml = ''; |
| 2086 |
$soap_xml .= '<?xml version="1.0"?> |
| 2087 |
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> |
| 2088 |
<S:Body> |
| 2089 |
<ns2:inviaMovimentazione xmlns:ns2="http://checkin.ws.service.turismo5.gies.it/">' . "\n"; |
| 2090 |
|
| 2091 |
// adjust regular XML to SOAP format |
| 2092 |
$soap_body_xml = $data['xml']; |
| 2093 |
$soap_body_xml = preg_replace("/^<\?xml version=\"([0-9\.]+)\"\s?\?>(\r\n|\r|\n)?/", '', $soap_body_xml); |
| 2094 |
$soap_body_xml = str_replace(['<movimenti>', '</movimenti>'], ['<movimentazione>', '</movimentazione>'], $soap_body_xml); |
| 2095 |
|
| 2096 |
// append SOAP XML body |
| 2097 |
$soap_xml .= trim($soap_body_xml); |
| 2098 |
|
| 2099 |
// close SOAP XML string |
| 2100 |
$soap_xml .= "\n" . '</ns2:inviaMovimentazione> |
| 2101 |
</S:Body> |
| 2102 |
</S:Envelope>'; |
| 2103 |
|
| 2104 |
// start the HTTP transporter |
| 2105 |
$http = new JHttp(); |
| 2106 |
|
| 2107 |
/** |
| 2108 |
* POST requests should be made to the endpoint meant as "location", not to the endpoint |
| 2109 |
* representing the Web-Service (WSDL). In this case we should strip out the ending "?wsdl". |
| 2110 |
*/ |
| 2111 |
$settings['endpoint'] = preg_replace("/\?wsdl$/", '', $settings['endpoint']); |
| 2112 |
|
| 2113 |
try { |
| 2114 |
// make a POST request to the specified endpoint URL |
| 2115 |
$response = $http->post($settings['endpoint'], $soap_xml, [ |
| 2116 |
'Accept' => 'text/xml, multipart/related', |
| 2117 |
'Authorization' => 'Basic ' . base64_encode(sprintf('%s:%s', $settings['user'], $settings['pwd'])), |
| 2118 |
'Content-Type' => 'text/xml; charset=utf-8', |
| 2119 |
'SOAPAction' => '', |
| 2120 |
// 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:133.0) Gecko/20100101 Firefox/133.0', |
| 2121 |
'Connection' => 'keep-alive', |
| 2122 |
'Content-Length' => strlen($soap_xml), |
| 2123 |
], 20); |
| 2124 |
|
| 2125 |
// response text |
| 2126 |
$response_txt = strip_tags((string) $response->body); |
| 2127 |
|
| 2128 |
if ($response->code != 200) { |
| 2129 |
// invalid response, throw an exception |
| 2130 |
throw new Exception($response_txt, $response->code); |
| 2131 |
} |
| 2132 |
|
| 2133 |
// build HTML response string |
| 2134 |
$html = ''; |
| 2135 |
$html .= '<p class="successmade">Flusso dati turistici inviati con successo.</p>'; |
| 2136 |
$html .= 'Responso:<br/><pre><code>' . htmlentities($response->body) . '</code></pre>'; |
| 2137 |
|
| 2138 |
} catch (Exception $e) { |
| 2139 |
// propagate the error caught |
| 2140 |
throw new Exception(sprintf('[%s] error: %s', __METHOD__, $e->getMessage()), $e->getCode() ?: 500); |
| 2141 |
} |
| 2142 |
|
| 2143 |
// get the currently active profile ID, if any |
| 2144 |
$activeProfileId = $this->getActiveProfile(); |
| 2145 |
|
| 2146 |
/** |
| 2147 |
* When the report is executed through a cron-job, the transmission of the guest details |
| 2148 |
* will also dump the data transmitted onto a resource file, useful for sending it via email. |
| 2149 |
* |
| 2150 |
* @since 1.18.0 (J) - 1.8.0 (WP) |
| 2151 |
*/ |
| 2152 |
if ($scope === 'cron') { |
| 2153 |
// prepare the XML resource file information |
| 2154 |
$xml_name = implode('_', array_filter([$this->getFileName(), 'trasmissione', 'flussi', time(), $activeProfileId, rand(100, 999)])) . '.xml'; |
| 2155 |
$xml_dest = $this->getDataMediaPath() . DIRECTORY_SEPARATOR . $xml_name; |
| 2156 |
$xml_url = $this->getDataMediaUrl() . $xml_name; |
| 2157 |
|
| 2158 |
// store the XML bytes into a local file on disk |
| 2159 |
$stored = JFile::write($xml_dest, $soap_xml); |
| 2160 |
|
| 2161 |
if ($stored && VBOPlatformDetection::isWordPress()) { |
| 2162 |
/** |
| 2163 |
* Trigger files mirroring operation |
| 2164 |
*/ |
| 2165 |
VikBookingLoader::import('update.manager'); |
| 2166 |
VikBookingUpdateManager::triggerUploadBackup($xml_dest); |
| 2167 |
} |
| 2168 |
|
| 2169 |
if ($stored) { |
| 2170 |
// define a new report resource for the generated file |
| 2171 |
$this->defineResourceFile([ |
| 2172 |
'summary' => sprintf( |
| 2173 |
'%sFlussi turistici generati e trasmessi con successo.', |
| 2174 |
($activeProfileId ? '(' . ucwords($activeProfileId) . ') ' : '') |
| 2175 |
), |
| 2176 |
'url' => $xml_url, |
| 2177 |
'path' => $xml_dest, |
| 2178 |
]); |
| 2179 |
} |
| 2180 |
} |
| 2181 |
|
| 2182 |
// when executed through a cron, store an event in the Notifications Center |
| 2183 |
if ($scope === 'cron') { |
| 2184 |
// build the notification record |
| 2185 |
$notification = [ |
| 2186 |
'sender' => 'reports', |
| 2187 |
'type' => 'pmsreport.sendxml.ok', |
| 2188 |
'title' => 'Ross1000 - Trasmissione flussi turistici', |
| 2189 |
'summary' => sprintf( |
| 2190 |
'%sI flussi turistici sono stati trasmessi con successo per le date dal %s al %s.', |
| 2191 |
($activeProfileId ? '(' . ucwords($activeProfileId) . ') ' : ''), |
| 2192 |
$this->exported_checkin_dates[0] ?? '', |
| 2193 |
$this->exported_checkin_dates[1] ?? '' |
| 2194 |
), |
| 2195 |
]; |
| 2196 |
|
| 2197 |
try { |
| 2198 |
// store the notification record |
| 2199 |
VBOFactory::getNotificationCenter()->store([$notification]); |
| 2200 |
} catch (Exception $e) { |
| 2201 |
// silently catch the error without doing anything |
| 2202 |
} |
| 2203 |
} |
| 2204 |
|
| 2205 |
return [ |
| 2206 |
'html' => $html, |
| 2207 |
'success' => true, |
| 2208 |
'response' => $response->body, |
| 2209 |
]; |
| 2210 |
} |
| 2211 |
|
| 2212 |
/** |
| 2213 |
* Helper method invoked via AJAX by the controller. |
| 2214 |
* Needed to save the manual entries for the pax data. |
| 2215 |
* |
| 2216 |
* @param array $manual_data the object representation of the manual entries. |
| 2217 |
* |
| 2218 |
* @return array one boolean value array with the operation result. |
| 2219 |
*/ |
| 2220 |
public function updatePaxData($manual_data = []) |
| 2221 |
{ |
| 2222 |
if (!is_array($manual_data) || !$manual_data) { |
| 2223 |
VBOHttpDocument::getInstance()->close(400, 'Nothing to save!'); |
| 2224 |
} |
| 2225 |
|
| 2226 |
// re-build manual entries object representation |
| 2227 |
$bids_guests = []; |
| 2228 |
foreach ($manual_data as $guest_ind => $guest_data) { |
| 2229 |
if (!is_numeric($guest_ind) || !is_array($guest_data) || empty($guest_data['bid']) || !isset($guest_data['bid_index']) || count($guest_data) < 2) { |
| 2230 |
// empty or invalid manual entries array |
| 2231 |
continue; |
| 2232 |
} |
| 2233 |
// the guest index in the reportObj starts from 0 |
| 2234 |
$use_guest_ind = ($guest_ind + 1 - (int)$guest_data['bid_index']); |
| 2235 |
if (!isset($bids_guests[$guest_data['bid']])) { |
| 2236 |
$bids_guests[$guest_data['bid']] = []; |
| 2237 |
} |
| 2238 |
// set manual entries for this guest number |
| 2239 |
$bids_guests[$guest_data['bid']][$use_guest_ind] = $guest_data; |
| 2240 |
// remove the "bid" and "bid_index" keys |
| 2241 |
unset($bids_guests[$guest_data['bid']][$use_guest_ind]['bid'], $bids_guests[$guest_data['bid']][$use_guest_ind]['bid_index']); |
| 2242 |
} |
| 2243 |
|
| 2244 |
if (!$bids_guests) { |
| 2245 |
VBOHttpDocument::getInstance()->close(400, 'No manual entries to save found'); |
| 2246 |
} |
| 2247 |
|
| 2248 |
// loop through all bookings to update the data for the various rooms and guests |
| 2249 |
$bids_updated = 0; |
| 2250 |
foreach ($bids_guests as $bid => $entries) { |
| 2251 |
$b_rooms = VikBooking::loadOrdersRoomsData($bid); |
| 2252 |
if (empty($b_rooms)) { |
| 2253 |
continue; |
| 2254 |
} |
| 2255 |
// count guests per room (adults + children) |
| 2256 |
$room_guests = []; |
| 2257 |
foreach ($b_rooms as $b_room) { |
| 2258 |
$room_guests[] = $b_room['adults'] + $b_room['children']; |
| 2259 |
} |
| 2260 |
// get current booking pax data |
| 2261 |
$pax_data = VBOCheckinPax::getBookingPaxData($bid); |
| 2262 |
$pax_data = empty($pax_data) ? [] : $pax_data; |
| 2263 |
foreach ($entries as $guest_ind => $guest_data) { |
| 2264 |
// find room index for this guest |
| 2265 |
$room_num = 0; |
| 2266 |
$use_guest_ind = $guest_ind; |
| 2267 |
foreach ($room_guests as $room_index => $tot_guests) { |
| 2268 |
// find the proper guest index for the room to which this belongs |
| 2269 |
if ($use_guest_ind <= $tot_guests) { |
| 2270 |
// proper room index found for this guest |
| 2271 |
$room_num = $room_index; |
| 2272 |
break; |
| 2273 |
} else { |
| 2274 |
// it's probably in a next room |
| 2275 |
$use_guest_ind -= $tot_guests; |
| 2276 |
} |
| 2277 |
} |
| 2278 |
// push new pax data for this room and guest |
| 2279 |
if (!isset($pax_data[$room_num])) { |
| 2280 |
$pax_data[$room_num] = []; |
| 2281 |
} |
| 2282 |
if (!isset($pax_data[$room_num][$use_guest_ind])) { |
| 2283 |
$pax_data[$room_num][$use_guest_ind] = $guest_data; |
| 2284 |
} else { |
| 2285 |
$pax_data[$room_num][$use_guest_ind] = array_merge($pax_data[$room_num][$use_guest_ind], $guest_data); |
| 2286 |
} |
| 2287 |
} |
| 2288 |
// update booking pax data |
| 2289 |
if (VBOCheckinPax::setBookingPaxData($bid, $pax_data)) { |
| 2290 |
$bids_updated++; |
| 2291 |
} |
| 2292 |
} |
| 2293 |
|
| 2294 |
return $bids_updated ? [true] : [false]; |
| 2295 |
} |
| 2296 |
|
| 2297 |
/** |
| 2298 |
* Registers the name to give to the file being exported. |
| 2299 |
* |
| 2300 |
* @return void |
| 2301 |
* |
| 2302 |
* @since 1.16.1 (J) - 1.6.1 (WP) |
| 2303 |
*/ |
| 2304 |
protected function registerExportFileName() |
| 2305 |
{ |
| 2306 |
$pfromdate = VikRequest::getString('fromdate', '', 'request'); |
| 2307 |
$ptodate = VikRequest::getString('todate', '', 'request'); |
| 2308 |
|
| 2309 |
$this->setExportCSVFileName(str_replace(' ', '_', $this->reportName) . '-' . str_replace('/', '_', $pfromdate) . '-' . str_replace('/', '_', $ptodate) . '.xml'); |
| 2310 |
} |
| 2311 |
|
| 2312 |
/** |
| 2313 |
* Parses the file Comuni.csv and returns two associative |
| 2314 |
* arrays: one for the Comuni and one for the Province. |
| 2315 |
* Every line of the CSV is composed of: Codice, Comune, Provincia. |
| 2316 |
* |
| 2317 |
* @return array |
| 2318 |
*/ |
| 2319 |
protected function loadComuniProvince() |
| 2320 |
{ |
| 2321 |
$vals = [ |
| 2322 |
'comuni' => [ |
| 2323 |
'-- Estero --', |
| 2324 |
], |
| 2325 |
'province' => [ |
| 2326 |
'-- Estero --', |
| 2327 |
] |
| 2328 |
]; |
| 2329 |
|
| 2330 |
$csv = dirname(__FILE__).DIRECTORY_SEPARATOR.'Comuni.csv'; |
| 2331 |
$rows = file($csv); |
| 2332 |
foreach ($rows as $row) { |
| 2333 |
if (empty($row)) { |
| 2334 |
continue; |
| 2335 |
} |
| 2336 |
|
| 2337 |
$v = explode(';', $row); |
| 2338 |
if (count($v) != 3) { |
| 2339 |
continue; |
| 2340 |
} |
| 2341 |
|
| 2342 |
// trim values |
| 2343 |
$v[0] = trim($v[0]); |
| 2344 |
$v[1] = trim($v[1]); |
| 2345 |
$v[2] = trim($v[2]); |
| 2346 |
|
| 2347 |
$vals['comuni'][$v[0]]['name'] = $v[1]; |
| 2348 |
$vals['comuni'][$v[0]]['province'] = $v[2]; |
| 2349 |
$vals['province'][$v[2]] = $v[2]; |
| 2350 |
} |
| 2351 |
|
| 2352 |
return $vals; |
| 2353 |
} |
| 2354 |
|
| 2355 |
/** |
| 2356 |
* Parses the file Nazioni.csv and returns an associative |
| 2357 |
* array with the code and name of the Nazione. |
| 2358 |
* Every line of the CSV is composed of: Codice, Nazione. |
| 2359 |
* |
| 2360 |
* @return array |
| 2361 |
*/ |
| 2362 |
protected function loadNazioni() |
| 2363 |
{ |
| 2364 |
$nazioni = []; |
| 2365 |
|
| 2366 |
$csv = dirname(__FILE__).DIRECTORY_SEPARATOR.'Nazioni.csv'; |
| 2367 |
$rows = file($csv); |
| 2368 |
foreach ($rows as $row) { |
| 2369 |
if (empty($row)) { |
| 2370 |
continue; |
| 2371 |
} |
| 2372 |
$v = explode(';', $row); |
| 2373 |
if (count($v) != 3) { |
| 2374 |
continue; |
| 2375 |
} |
| 2376 |
|
| 2377 |
// trim values |
| 2378 |
$v[0] = trim($v[0]); |
| 2379 |
$v[1] = trim($v[1]); |
| 2380 |
$v[2] = trim($v[2]); |
| 2381 |
|
| 2382 |
$nazioni[$v[0]]['name'] = $v[1]; |
| 2383 |
$nazioni[$v[0]]['three_code'] = $v[2]; |
| 2384 |
|
| 2385 |
} |
| 2386 |
|
| 2387 |
return $nazioni; |
| 2388 |
} |
| 2389 |
|
| 2390 |
/** |
| 2391 |
* Returns the key of the state selected by the user, if any. |
| 2392 |
* |
| 2393 |
* @param string $country The selected country code. |
| 2394 |
* |
| 2395 |
* @return string |
| 2396 |
*/ |
| 2397 |
protected function checkCountry($country) |
| 2398 |
{ |
| 2399 |
$found = false; |
| 2400 |
$staval = ''; |
| 2401 |
|
| 2402 |
if (!$this->nazioni) { |
| 2403 |
$this->nazioni = $this->loadNazioni(); |
| 2404 |
} |
| 2405 |
|
| 2406 |
if ($country && isset($this->nazioni[$country])) { |
| 2407 |
return $country; |
| 2408 |
} |
| 2409 |
|
| 2410 |
foreach ($this->nazioni as $key => $value) { |
| 2411 |
if (trim($value['three_code']) == trim($country)) { |
| 2412 |
$staval = $key; |
| 2413 |
$found = true; |
| 2414 |
break; |
| 2415 |
} |
| 2416 |
} |
| 2417 |
|
| 2418 |
if ($found !== true) { |
| 2419 |
$staval = ''; |
| 2420 |
} |
| 2421 |
|
| 2422 |
return $staval; |
| 2423 |
} |
| 2424 |
|
| 2425 |
/** |
| 2426 |
* Helper method to quickly get a pax_data property for the guest. |
| 2427 |
* |
| 2428 |
* @param array $pax_data the current pax_data stored. |
| 2429 |
* @param array $guests list of total guests per room. |
| 2430 |
* @param int $guest_ind the guest index. |
| 2431 |
* @param string $key the pax_data key to look for. |
| 2432 |
* |
| 2433 |
* @return mixed null on failure or value fetched. |
| 2434 |
*/ |
| 2435 |
protected function getGuestPaxDataValue($pax_data, $guests, $guest_ind, $key) |
| 2436 |
{ |
| 2437 |
if (!is_array($pax_data) || !count($pax_data) || empty($key)) { |
| 2438 |
return null; |
| 2439 |
} |
| 2440 |
|
| 2441 |
// find room index for this guest number |
| 2442 |
$room_num = 0; |
| 2443 |
$use_guest_ind = $guest_ind; |
| 2444 |
foreach ($guests as $room_index => $room_tot_guests) { |
| 2445 |
// find the proper guest index for the room to which this belongs |
| 2446 |
if ($use_guest_ind <= $room_tot_guests) { |
| 2447 |
// proper room index found for this guest |
| 2448 |
$room_num = $room_index; |
| 2449 |
break; |
| 2450 |
} else { |
| 2451 |
// it's probably in a next room |
| 2452 |
$use_guest_ind -= $room_tot_guests; |
| 2453 |
} |
| 2454 |
} |
| 2455 |
|
| 2456 |
// check if a value exists for the requested key in the found room and guest indexes |
| 2457 |
if (isset($pax_data[$room_num]) && isset($pax_data[$room_num][$use_guest_ind])) { |
| 2458 |
if (isset($pax_data[$room_num][$use_guest_ind][$key])) { |
| 2459 |
// we've got a value previously stored |
| 2460 |
return $pax_data[$room_num][$use_guest_ind][$key]; |
| 2461 |
} |
| 2462 |
} |
| 2463 |
|
| 2464 |
// nothing was found |
| 2465 |
return null; |
| 2466 |
} |
| 2467 |
|
| 2468 |
/** |
| 2469 |
* Helper method to determine the exact number for this guest in the room booked. |
| 2470 |
* |
| 2471 |
* @param array $guests list of total guests per room. |
| 2472 |
* @param int $guest_ind the guest index. |
| 2473 |
* |
| 2474 |
* @return int the actual guest room index starting from 1. |
| 2475 |
*/ |
| 2476 |
protected function calcGuestRoomIndex($guests, $guest_ind) |
| 2477 |
{ |
| 2478 |
// find room index for this guest number |
| 2479 |
$room_num = 0; |
| 2480 |
$use_guest_ind = $guest_ind; |
| 2481 |
foreach ($guests as $room_index => $room_tot_guests) { |
| 2482 |
// find the proper guest index for the room to which this belongs |
| 2483 |
if ($use_guest_ind <= $room_tot_guests) { |
| 2484 |
// proper room index found for this guest |
| 2485 |
$room_num = $room_index; |
| 2486 |
break; |
| 2487 |
} else { |
| 2488 |
// it's probably in a next room |
| 2489 |
$use_guest_ind -= $room_tot_guests; |
| 2490 |
} |
| 2491 |
} |
| 2492 |
|
| 2493 |
return $use_guest_ind; |
| 2494 |
} |
| 2495 |
} |
| 2496 |
|