Si è verificato un errore nell'elaborarazione del modello.
The following has evaluated to null or missing:
==> docTitle [in template "383767#383802#960406" at line 2139, column 50]
----
Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${docTitle?js_string} [in template "383767#383802#960406" at line 2139, column 48]
---- 1<#-- 2 Sezione di pagamento Zainetto Verde 3 ©Suggesto 2024-07-05 4--> 5 6<#assign 7 RoleService = serviceLocator.findService("com.liferay.portal.kernel.service.RoleService") 8 hasAccompagnatorePerm = RoleService.hasUserRole(themeDisplay.getUser().userId, themeDisplay.getCompanyId(), "Accompagnatore", false) 9 10 JALS = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") 11 JSONFactoryUtil = staticUtil["com.liferay.portal.kernel.json.JSONFactoryUtil"] 12 articleId = "1221309" 13 article = JALS.fetchArticle(groupId, articleId) 14 document = saxReaderUtil.read(article.getContent()) 15 rootElement = document.getRootElement() 16 allegati = [] 17 18 stringSelector = "dynamic-element[@name='allegato']" 19 xPathSelector = saxReaderUtil.createXPath(stringSelector) 20/> 21 22<#if xPathSelector.selectNodes(rootElement)??> 23 <#assign allegati = xPathSelector.selectNodes(rootElement)> 24</#if> 25 26<style> 27 .bg-light-gray{ 28 background-color:#f4f4f4; 29 } 30</style> 31 32<#macro printContent> 33 <div id="pay" class="p-3" v-cloak> 34 <div v-show="loading"> 35 <div class="d-flex align-items-center justify-content-center h-full"> 36 <div class="loading-animation"></div> 37 </div> 38 </div> 39 40 <div class="container" v-show="!loading"> 41 <div class="text-center" v-if="name == 'Placeholder'"> 42 <p class="text-dark">Errore interno.</p> 43 <p class="text-dark">Ricarica la pagina per continuare.</p> 44 </div> 45 <div class="row" v-else> 46 <div class="col-12"> 47 <ol class="d-none d-lg-flex nav multi-step-nav multi-step-nav-collapse-sm flex-row" role="tablist"> 48 <li v-for="(num, index) in totalSteps" class="multi-step-item" :class="{'complete': currentStep >= num, 'multi-step-item-expand': index != totalSteps-1}"> 49 <div class="multi-step-divider"></div> 50 <div class="multi-step-indicator"> 51 <button class="multi-step-icon bg-image-none" data-toggle="tab" @click="currentStep = num" v-if="isDev"> 52 <span class="text-white font-weight-bold">{{ num }}</span> 53 </button> 54 <div class="multi-step-icon bg-image-none" data-toggle="tab" v-else> 55 <span class="text-white font-weight-bold">{{ num }}</span> 56 </div> 57 </div> 58 </li> 59 </ol> 60 61 <div class="tbar subnav-tbar subnav-tbar-light d-lg-none"> 62 <div class="container-fluid container-fluid-max-xl"> 63 <div class="tbar-nav"> 64 <div class="tbar-item tbar-item-expand"> 65 <div class="tbar-section"> 66 <span class="component-text text-truncate-inline"> 67 <span class="text-truncate">Acquisto</span> 68 </span> 69 </div> 70 </div> 71 <div class="tbar-item"> 72 <span class="component-text">Pagina {{ currentStep }} di {{ totalSteps }}</span> 73 </div> 74 </div> 75 </div> 76 </div> 77 78 <div class="tab-content mt-lg-5"> 79 80 <#-- STEP 1: CALENDARIO --> 81 <div class="tab-pane fade" :class="{'show active': currentStep == 1}" role="tabpanel"> 82 <div class="row justify-content-between"> 83 <div class="d-none d-lg-block col-12 mb-4"> 84 <p class="text-dark display-5 font-weight-light">Vai avanti per confermare il pacchetto <span class="text-gray small" style="font-size:1rem;">(oppure modifica la tua scelta)</span></p> 85 </div> 86 87 <#-- <div class="col-12 col-lg-5"> 88 <div id="v-calendar" class="single w-100 w-lg-75 mx-auto mb-3 mb-lg-4"> 89 <v-calendar 90 v-if="calendar.ready" 91 v-model="calendar.dataSelected" 92 @dayclick="selectDate" 93 :available-dates="calendar.dateDisponibili" 94 :attributes="calendar.attributes" 95 :min-page="calendar.initialPage" 96 :min-date="calendar.dataInizio" 97 :max-date="calendar.dataFine" 98 nav-visibility="hidden" 99 title-position="left" 100 ref="calendar" 101 mode="single" 102 is-expanded 103 is-inline 104 /> 105 </div> 106 107 <div class="card void mt-4 mt-lg-0"> 108 <div class="card-row flex-column flex-md-row"> 109 <div class="autofit-col autofit-col-expand"> 110 <section class="autofit-section"> 111 <p class="text-dark text-center text-md-left mb-lg-0">Desideri prenotare per un gruppo o verificare la disponibilità di date e orari non elencati?</p> 112 </section> 113 </div> 114 <div class="autofit-col"> 115 <section class="autofit-section"> 116 <button @click="openParentModal('#requestinfo-payment-modal')" class="btn btn-outline-dark btn-block py-2 px-3">Contattaci</button> 117 </section> 118 </div> 119 </div> 120 </div> 121 </div>--> 122 123 <div id="results" class="row" style="width:100%;"> 124 <template v-for="(package, index) in packages"> 125 <template v-if="!needsPermission(package) || (needsPermission(package) && hasAccompagnatorePermission)"> 126 <div class="col-12 col-lg-6"> 127 <div v-if="isAfter(package.startDate) && !package.additionalInfo.ritirato && !package.startDate.includes('2030')" class="card no-shadow rounded" style="border: 2px solid #43A08E !important;" :key="package._id.$oid"> 128 129 <div :class="_.get(selectedPackage, '_id.$oid', '') == package._id.$oid ? 'card-body p-3 bg-light-gray':'card-body p-3'"> 130 131 <div class="card-row" v-show="package.show"> <#-- && !isBefore(package?.endDate) && !package.additionalInfo.ritirato --> 132 <div class="autofit-col autofit-col-expand"> 133 <section class="autofit-section"> 134 <p class="text-muted mb-0">dal {{ package?.startDate | moment().format("DD MMMM YYYY") }} al {{ package?.endDate | moment().format("DD MMMM YYYY") }}</p> 135 <p class="mb-0"> 136 <span class="badge badge-pill badge-primary bg-gradient-h" v-if="package.forGroup"> 137 <span class="badge-item badge-item-expand">Per gruppi</span> 138 </span> 139 <template v-if="package.marketingGroups"> 140 <span v-for="(item, index) in package.marketingGroups" :key="'mg-' + index" class="badge badge-pill badge-primary bg-gradient-h"> 141 <span class="badge-item badge-item-expand">{{ item.name }}</span> 142 </span> 143 </template> 144 </p> 145 <p class="text-dark mb-0">A partire da {{ package.basePrice | money }}</p> 146 147 <template v-for="(sconto, index) in package.purchaseBeforeDiscount"> 148 <p v-if="isDiscountValid(sconto) && sconto.discount != 0" :key="'discount-' + index + '-' + package._id.$oid" class="text-muted small mb-0"> 149 Acquista entro il {{ sconto.dateEnd | moment().subtract(1, "days").format("DD MMMM YYYY") }}: 150 <span class="label label-success"> 151 <span class="label-item label-item-expand">Sconto di {{ sconto.discount | money }}</span> 152 </span> 153 </p> 154 </template> 155 </section> 156 </div> 157 <div class="autofit-col"> 158 <section class="autofit-section"> 159 <button class="btn btn-gradient py-2 px-3 px-lg-4" v-if="_.get(selectedPackage, '_id.$oid', '') == package._id.$oid"> 160 Scelto 161 <i class="fas fa-check ml-2"></i> 162 </button> 163 164 <button @click="selectPackage(package._id.$oid)" class="btn btn-outline-dark py-2 px-3 px-lg-4" v-else> 165 Scegli 166 </button> 167 </section> 168 </div> 169 </div> 170 </div> 171 172 <#-- <div v-if="index < packages.length - 1 && !isBefore(package?.endDate)" class="dropdown-divider w-75 mx-auto my-3"></div> --> 173 </div> 174 </div> 175 </template> 176 </template> 177 </div> 178 179 <div class="col-12"> 180 <div class="card void mt-3 mt-lg-5 mb-0"> 181 <div class="card-row"> 182 <div class="autofit-col autofit-col-expand"> 183 <section class="autofit-section text-left"> 184 <#-- 185 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 186 Indietro 187 </button> 188 --> 189 </section> 190 </div> 191 <div class="autofit-col autofit-col-expand"> 192 <section class="autofit-section text-right"> 193 <button @click="!_.isEmpty(selectedPackage) ? gotoStep('next') : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="_.isEmpty(selectedPackage)"> 194 Avanti 195 </button> 196 </section> 197 </div> 198 </div> 199 </div> 200 </div> 201 </div> 202 </div> 203 204 <#-- STEP 2: TRASPORTO --> 205 <div class="tab-pane fade" :class="{'show active': currentStep == 2}" role="tabpanel"> 206 <div class="row justify-content-between"> 207 <div class="d-none d-lg-block col-12 mb-4"> 208 <p class="text-dark display-5 font-weight-light">Scegli il tuo trasferimento</p> 209 </div> 210 211 <div class="col-12 col-lg-6" v-if="!_.isEmpty(selectedPackage)"> 212 <ul class="list-group mb-lg-0"> 213 <li v-for="(partenza, index) in selectedPackage.airportsAndPrices" :key="'airport-' + index" class="list-group-item"> 214 <div class="card-row flex-column flex-lg-row"> 215 <div class="autofit-col autofit-col-expand"> 216 <section class="autofit-section my-auto"> 217 <#-- <span class="label label-success" v-if="partenza.price == 0"> 218 <span class="label-item label-item-expand">Volo incluso</span> 219 </span> 220 --> 221 <div class="custom-control custom-radio"> 222 <label> 223 <input class="custom-control-input" type="radio" name="airportsAndPrices" v-model="selectedAirport" :value="partenza" /> 224 <span class="custom-control-label"> 225 <span class="custom-control-label-text">{{ getCity(partenza.airport) }}</span> 226 </span> 227 </label> 228 </div> 229 </section> 230 </div> 231 <div class="autofit-col autofit-col-expand"> 232 <section class="autofit-section my-auto"> 233 <p class="text-dark text-right h3 mb-0 mr-3">{{ partenza.price | money }}</p> 234 </section> 235 </div> 236 </div> 237 </li> 238 </ul> 239 </div> 240 <div class="col-12 col-lg-6" v-else> 241 <p class="text-dark display-5 font-weight-light">Per continuare, seleziona un periodo dalla prima pagina.</p> 242 </div> 243 244 <div class="col-12"> 245 <div class="card void mt-3 mt-lg-5 mb-0"> 246 <div class="card-row"> 247 <div class="autofit-col autofit-col-expand"> 248 <section class="autofit-section text-left"> 249 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 250 Indietro 251 </button> 252 </section> 253 </div> 254 <div class="autofit-col autofit-col-expand"> 255 <section class="autofit-section text-right"> 256 <button @click="!_.isEmpty(selectedAirport) ? gotoStep('next') : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="_.isEmpty(selectedAirport)"> 257 Avanti 258 </button> 259 </section> 260 </div> 261 </div> 262 </div> 263 </div> 264 </div> 265 </div> 266 267 <#-- STEP 3: ALLOGGIO --> 268 <div class="tab-pane fade" :class="{'show active': currentStep == 3}" role="tabpanel"> 269 <div class="row"> 270 <div class="d-none d-lg-block col-12 mb-4"> 271 <p class="text-dark display-5 font-weight-light">Scegli l'alloggio</p> 272 </div> 273 274 <div class="col-12 col-lg-7" v-if="!_.isEmpty(selectedPackage)"> 275 <ul class="list-group mb-lg-0"> 276 <li v-for="(accomodation, index) in selectedPackage.lodgingTypesAndPrices" :key="'accomodation-' + index" class="list-group-item"> 277 <div class="card-row flex-column flex-lg-row"> 278 <div class="autofit-col autofit-col-expand"> 279 <section class="autofit-section my-auto"> 280 <div class="custom-control custom-radio"> 281 <label> 282 <input class="custom-control-input" type="radio" name="lodgingTypesAndPrices" v-model="selectedAccomodation" :value="accomodation" /> 283 <span class="custom-control-label"> 284 <span class="custom-control-label-text">{{ accomodation.lodgingType }}</span> 285 </span> 286 </label> 287 </div> 288 </section> 289 </div> 290 <div class="autofit-col autofit-col-expand"> 291 <section class="autofit-section my-auto"> 292 <p class="text-dark text-right h3 mb-0 mr-3">{{ accomodation.price | money }}</p> 293 </section> 294 </div> 295 </div> 296 </li> 297 </ul> 298 </div> 299 <div class="col-12" v-else> 300 <p class="text-dark display-5 font-weight-light">Per continuare, seleziona un periodo dalla prima pagina.</p> 301 </div> 302 303 <div class="col-12"> 304 <div class="card void mt-3 mt-lg-5 mb-0"> 305 <div class="card-row"> 306 <div class="autofit-col autofit-col-expand"> 307 <section class="autofit-section text-left"> 308 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 309 Indietro 310 </button> 311 </section> 312 </div> 313 <div class="autofit-col autofit-col-expand"> 314 <section class="autofit-section text-right"> 315 <button @click="!_.isEmpty(selectedAccomodation) ? gotoStep('next') : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="_.isEmpty(selectedAccomodation)"> 316 Avanti 317 </button> 318 </section> 319 </div> 320 </div> 321 </div> 322 </div> 323 </div> 324 </div> 325 326 <#-- STEP 4: SERVIZI --> 327 <div class="tab-pane fade" :class="{'show active': currentStep == 4}" role="tabpanel"> 328 <div class="row"> 329 <div class="d-none d-lg-block col-12 mb-4"> 330 <p class="text-dark display-5 font-weight-light">Scegli altri servizi</p> 331 </div> 332 333 <div class="col-12 col-lg-7" v-if="!_.isEmpty(selectedPackage)"> 334 <ul class="list-group mb-lg-0"> 335 <li v-for="(service, index) in selectedPackage.servicesAndPrices" :key="'service-' + index" class="list-group-item"> 336 <div class="card-row flex-column flex-lg-row"> 337 <div class="autofit-col autofit-col-expand"> 338 <section class="autofit-section my-auto"> 339 <span class="label label-danger" v-if="service.mandatory"> 340 <span class="label-item label-item-expand">Obbligatorio</span> 341 </span> 342 343 <div class="custom-control custom-checkbox"> 344 <label class="{'no-events': service.mandatory}"> 345 <input class="custom-control-input" :class="{'no-events': service.mandatory}" type="checkbox" v-model="selectedServices" :value="service" :checked="service.mandatory" :disabled="service.mandatory" /> 346 <span class="custom-control-label"> 347 <span class="custom-control-label-text">{{ service.service }}</span> 348 </span> 349 </label> 350 </div> 351 </section> 352 </div> 353 <div class="autofit-col autofit-col-expand" style="min-width: 15%;"> 354 <section class="autofit-section my-auto"> 355 <p class="text-dark text-right h3 mb-0 mr-3">{{ service.price | money }}</p> 356 </section> 357 </div> 358 </div> 359 </li> 360 </ul> 361 </div> 362 <div class="col-12" v-else> 363 <p class="text-dark display-5 font-weight-light">Per continuare, seleziona un periodo dalla prima pagina.</p> 364 </div> 365 366 <div class="col-12"> 367 <div class="card void mt-3 mt-lg-5 mb-0"> 368 <div class="card-row"> 369 <div class="autofit-col autofit-col-expand"> 370 <section class="autofit-section text-left"> 371 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 372 Indietro 373 </button> 374 </section> 375 </div> 376 <div class="autofit-col autofit-col-expand"> 377 <section class="autofit-section text-right"> 378 <button @click="selectedServices.length > 0 ? gotoStep('next') : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="selectedServices.length == 0"> 379 Avanti 380 </button> 381 </section> 382 </div> 383 </div> 384 </div> 385 </div> 386 </div> 387 </div> 388 389 <#-- STEP 5: FORM DATI MINIMAL --> 390 <div class="tab-pane fade" :class="{'show active': currentStep == 5}" role="tabpanel"> 391 <div class="row justify-content-center"> 392 <div class="d-none d-lg-block col-12 mb-4"> 393 <p class="text-dark display-5 font-weight-light">Inserisci i tuoi dati</p> 394 </div> 395 396 <div class="col-12 col-lg-9" v-if="!_.isEmpty(selectedPackage)"> 397 <div class="sheet sheet-lg"> 398 <div class="sheet-header"> 399 <div class="sheet-text"> 400 Inserisci i tuoi dati per poter calcolare, senza impegno, il preventivo e riceverlo automaticamente per email. 401 </div> 402 </div> 403 <div class="sheet-section"> 404 <div class="form-group-autofit"> 405 <div class="form-group-item"> 406 <label for="userName">Nome *</label> 407 <input class="form-control" id="userName" v-model="userData.firstName" type="text"/> 408 </div> 409 <div class="form-group-item"> 410 <label for="userSurname">Cognome *</label> 411 <input class="form-control" id="userSurname" v-model="userData.lastName" type="text"/> 412 </div> 413 </div> 414 <div class="form-group-autofit"> 415 <div class="form-group-item"> 416 <label for="billingEmail">Email *</label> 417 <input class="form-control" id="billingEmail" v-model="userMail" type="email"/> 418 </div> 419 <div class="form-group-item"> 420 <label for="phone">Telefono *</label> 421 <input class="form-control" id="phone" v-model="userData.phone" type="text"/> 422 </div> 423 </div> 424 425 <div class="form-group-autofit"> 426 <div class="form-group-item"> 427 <div class="form-text">I campi contrassegnati con * sono obbligatori.</div> 428 </div> 429 </div> 430 431 432 <div class="form-group-autofit" v-if='sendingMessageError != ""'> 433 <div class="form-group-item"> 434 <div class="form-text"> 435 <p class="text-muted " style="color:red !important;"> 436 Errore durante l'invio del preventivo. Correggi i dati inseriti e riprova 437 </p> 438 </div> 439 </div> 440 </div> 441 442 443 </div> 444 </div> 445 </div> 446 <div class="col-12" v-else> 447 <p class="text-dark display-5 font-weight-light">Per continuare, seleziona un periodo dalla prima pagina.</p> 448 </div> 449 450 <div class="col-12"> 451 <div class="card void mt-3 mt-lg-5 mb-0"> 452 <div class="card-row"> 453 <div class="autofit-col autofit-col-expand"> 454 <section class="autofit-section text-left"> 455 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 456 Indietro 457 </button> 458 </section> 459 </div> 460 <div class="autofit-col autofit-col-expand"> 461 <section class="autofit-section text-right"> 462 <button @click="sendRequestMessage()" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="!minimumValid"> 463 Scarica preventivo 464 </button> 465 </section> 466 </div> 467 </div> 468 </div> 469 </div> 470 </div> 471 </div> 472 473 <#-- STEP 6: RIEPILOGO --> 474 <div class="tab-pane fade" :class="{'show active': currentStep == 6}" role="tabpanel"> 475 476 <div class="sheet border-0 p-0 p-lg-4"> 477 <div class="row"> 478 <div class="d-none d-lg-block col-12 mb-4"> 479 <p class="text-dark display-5 font-weight-light">Il tuo preventivo</p> 480 </div> 481 482 <div class="col-12"> 483 <div class="card void"> 484 <div class="card-row flex-column flex-lg-row mb-4 mb-lg-0"> 485 <div class="autofit-col autofit-col-expand"> 486 <section class="autofit-section mb-auto"> 487 <p class="h1 display-5 title-large">{{ name }}</p> 488 <p class="text-dark"> 489 Dal {{ selectedPackage?.startDate | moment().format("DD MMMM YYYY") }} al {{ selectedPackage?.endDate | moment().format("DD MMMM YYYY") }} 490 </p> 491 </section> 492 </div> 493 </div> 494 </div> 495 </div> 496 </div> 497 498 <div class="row"> 499 <div class="col-12 col-lg-6 order-2 order-lg-1"> 500 <div class="panel panel-secondary" v-if="packagePrice != 0"> 501 <div class="panel-header"> 502 <div class="panel-title"> 503 Informazioni di base: 504 </div> 505 </div> 506 <div class="panel-body"> 507 <p class="mb-0"> 508 Prezzo del viaggio: <span class="font-weight-bold">{{ packagePrice | money }}</span> 509 </p> 510 <p class="mb-0" v-if="packageDiscount != 0"> 511 Sconto applicato: <span class="font-weight-bold">{{ packageDiscount | money }}</span> 512 </p> 513 </div> 514 </div> 515 516 <div class="panel panel-secondary"> 517 <div class="panel-header"> 518 <div class="panel-title"> 519 Sistemazione: 520 </div> 521 </div> 522 <div class="panel-body"> 523 <p class="mb-0"> 524 {{ selectedAccomodation.lodgingType }} <span class="font-weight-bold">({{ selectedAccomodation.price | money }})</span> 525 </p> 526 </div> 527 </div> 528 529 <div class="panel panel-secondary"> 530 <div class="panel-header"> 531 <div class="panel-title"> 532 Servizi scelti: 533 </div> 534 </div> 535 <div class="panel-body"> 536 <p v-for="(service, index) in selectedServices" :key="'selectedService-' + index" class="mb-0"> 537 {{ service.service }} <span class="font-weight-bold">({{ service.price | money }})</span> 538 </p> 539 </div> 540 </div> 541 542 <div class="panel panel-secondary"> 543 <div class="panel-header"> 544 <div class="panel-title"> 545 Trasporto scelto: 546 </div> 547 </div> 548 <div class="panel-body"> 549 <p class="mb-0"> 550 {{ selectedAirport.airport }} <span class="font-weight-bold">({{ selectedAirport.price | money }})</span> 551 </p> 552 </div> 553 </div> 554 555 <div class="panel panel-secondary" v-if="!_.isEmpty(selectedPayment)"> 556 <div class="panel-header"> 557 <div class="panel-title"> 558 Tipo di pagamento scelto (Acconto): 559 </div> 560 </div> 561 <div class="panel-body"> 562 <div class="card void m-0 p-0"> 563 <div class="card-row"> 564 <div class="autofit-col autofit-col-expand my-auto"> 565 <section class="autofit-section"> 566 <p class="mb-0"> 567 {{ selectedPayment.type }} <span class="font-weight-bold" v-if="selectedPayment.amount && selectedPayment.amount != 0">( Acconto: {{ selectedPayment.amount | money }})</span> 568 </p> 569 </section> 570 </div> 571 </div> 572 </div> 573 </div> 574 </div> 575 576 <div class="panel panel-secondary" v-if="!_.isEmpty(selectedBalance)"> 577 <div class="panel-header"> 578 <div class="panel-title"> 579 Tipo di pagamento scelto (Saldo): 580 </div> 581 </div> 582 <div class="panel-body"> 583 <div class="card void m-0 p-0"> 584 <div class="card-row"> 585 <div class="autofit-col autofit-col-expand my-auto"> 586 <section class="autofit-section"> 587 <p class="mb-0"> 588 {{ selectedBalance.type }} 589 </p> 590 </section> 591 </div> 592 </div> 593 </div> 594 </div> 595 </div> 596 597 <div class="panel panel-secondary"> 598 <div class="panel-header"> 599 <div class="panel-title"> 600 Voucher: 601 </div> 602 </div> 603 <div class="panel-body"> 604 <p v-if="voucherDiscount > 0"> 605 Sconto applicato: <span class="font-weight-bold">{{ voucherDiscount | money }}</span> 606 </p> 607 608 <div class="card void m-0 p-0"> 609 <div class="card-row"> 610 <div class="autofit-col autofit-col-expand my-auto"> 611 <section class="autofit-section"> 612 <div class="form-group"> 613 <div class="input-group"> 614 <div class="input-group-item input-group-prepend"> 615 <input type="text" v-model="voucher" class="form-control" placeholder="Inserisci il codice" :disabled="voucherValid" /> 616 </div> 617 <span class="input-group-append input-group-item input-group-item-shrink"> 618 <button @click="checkVoucher()" class="btn btn-secondary" :disabled="voucher == '' || voucherValid"> 619 <span v-if="voucherValid"> 620 Valido 621 <i class="fas fa-check ml-2"></i> 622 </span> 623 <span v-else> 624 Verifica 625 </span> 626 </button> 627 </span> 628 </div> 629 </div> 630 </section> 631 </div> 632 </div> 633 </div> 634 </div> 635 </div> 636 </div> 637 <div class="col-12 col-lg-6 order-1 order-lg-2"> 638 <div class="panel panel-secondary"> 639 <div class="panel-body"> 640 <div class="card void my-3"> 641 <div class="d-flex justify-content-center"> 642 <div class="d-flex flex-column text-center mx-auto"> 643 <span class="sticker sticker-xl sticker-person rounded-circle mb-4"> 644 <span class="sticker-overlay"> 645 <img :src="image" class="w-100 h-100" :alt="name"> 646 </span> 647 </span> 648 649 <button type="button" v-if="signedIn" class="btn btn-outline-dark px-3" @click="favourite ? removeFavourite() : setFavourite()"> 650 <span>{{ favourite ? 'Salvato' : 'Salva' }}</span> 651 <i class="fa-heart fa-lg ml-3" :class="favourite ? 'fas' : 'far'"></i> 652 </button> 653 </div> 654 </div> 655 </div> 656 657 <div class="card void my-3"> 658 <div class="card-row flex-column"> 659 <div class="autofit-col autofit-col-expand"> 660 <section v-if="voucherDiscount > 0" class="autofit-section"> 661 <div class="d-flex flex-row text-dark text-center my-4 justify-content-center"> 662 <p class="my-auto">Totale importo: </p> 663 <span class="text-left d-flex flex-column"> 664 <span class="ml-3" style="text-decoration: line-through;">{{ totalPrice | money }}</span> 665 <span class="display-5 ml-3">{{ totalPriceWithVoucher | money }}</span> 666 </span> 667 </div> 668 <p v-if="_.get(selectedPayment, 'amount', 0) != 0" class="text-dark text-center my-4"> 669 Acconto da pagare: 670 <span class="display-5 ml-3">{{ selectedPayment.depositAmount | money }}</span> 671 </p> 672 </section> 673 674 <section v-else class="autofit-section"> 675 <p class="text-dark text-center my-4"> 676 Totale importo: 677 <span class="display-5 ml-3">{{ totalPrice | money }}</span> 678 </p> 679 <p class="text-dark text-center my-4" v-if="_.get(selectedPayment, 'amount', 0) != 0"> 680 Acconto da pagare: 681 <span class="display-5 ml-3">{{ selectedPayment.amount | money }}</span> 682 </p> 683 </section> 684 </div> 685 <div class="autofit-col autofit-col-expand"> 686 <div class="autofit-section"> 687 <p style="font-size: 0.9rem; line-height: 1.5 !important; font-weight:600;">Grazie! Ti abbiamo inviato il preventivo per email, per qualsiasi informazione contattaci.</p> 688 <p style="font-size: 0.9rem; line-height: 1.5 !important;font-weight:600;">Se vuoi procedere all'acquisto, clicca sul pulsante.</p> 689 <p style="font-size: 0.9rem; line-height: 1.5 !important;"> 690 Modalità di pagamento: acconto alla conferma, saldo prima della data prevista per la partenza. Se sei interessato ad un eventuale finanziamento, richiedi informazioni a 691 <a href="mailto:info@zainettoverde.it" class="text-aqua"><u>info@zainettoverde.it</u></a>. 692 </p> 693 </div> 694 </div> 695 <div class="autofit-col autofit-col-expand"> 696 <section class="autofit-section"> 697 698 <button v-if="signedIn" @click="gotoStep('next')" class="btn btn-gradient btn-block py-2"> 699 Iscrizione e pagamento acconto 700 </button> 701 <button v-else @click="setProgressData();redirectParent('/login')" class="btn btn-outline-dark btn-block py-2"> 702 Accedi per procedere al pagamento acconto 703 </button> 704 </section> 705 </div> 706 </div> 707 </div> 708 </div> 709 </div> 710 </div> 711 </div> 712 713 <div class="row"> 714 <div class="col-12"> 715 <div class="card void mt-3 mt-lg-5 mb-0"> 716 <div class="card-row"> 717 <div class="autofit-col autofit-col-expand"> 718 <section class="autofit-section text-left"> 719 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 720 Indietro 721 </button> 722 </section> 723 </div> 724 </div> 725 </div> 726 </div> 727 </div> 728 </div> 729 </div> 730 731 <#-- STEP 7: FORM DATI ESTESO --> 732 <div class="tab-pane fade" id="payment_step" :class="{'show active': currentStep == 7}" role="tabpanel"> 733 <div class="row justify-content-center"> 734 <div class="d-none d-lg-block col-12 mb-4"> 735 <p class="text-dark display-5 font-weight-light">Completa il modulo di iscrizione</p> 736 </div> 737 738 <div class="col-12 col-lg-9" v-if="!_.isEmpty(selectedPackage) && userData != null && signedIn"> 739 <div class="sheet sheet-lg"> 740 <div class="sheet-header"> 741 <div class="sheet-text" style="color:red;"> 742 <span class="text-red font-weight-bold">IMPORTANTE:</span> 743 per poter impostare correttamente la pratica, è indispensabile compilare <u>tutti i campi</u> del presente modulo 744 </div> 745 </div> 746 747 <div class="sheet-section"> 748 <p class="sheet-title">Dati del genitore per fatturazione</p> 749 750 <div class="form-group-autofit"> 751 <div class="form-group-item"> 752 <label for="tutoreFirstName">Nome</label> 753 <input @blur="checkEmpty($event)" class="form-control" id="tutoreFirstName" v-model="userData.tutore.firstName" type="text"/> 754 </div> 755 <div class="form-group-item"> 756 <label for="tutoreLastName">Cognome</label> 757 <input @blur="checkEmpty($event)" class="form-control" id="tutoreLastName" v-model="userData.tutore.lastName" type="text"/> 758 </div> 759 </div> 760 761 <div class="form-group-autofit"> 762 <div class="form-group-item"> 763 <label for="tutoreBirthdayPlace">Nato a</label> 764 <input @blur="checkEmpty($event)" class="form-control" id="tutoreBirthdayPlace" v-model="userData.tutore.birthdayPlace" type="text"/> 765 </div> 766 <div class="form-group-item"> 767 <label for="tutoreBirthday">il (gg/mm/aaaa)</label> 768 <input @blur="checkDateLength($event)" class="form-control" id="tutoreBirthday" @keydown="restrictDateInput" v-model="userData.tutore.birthday" type="text"/> 769 </div> 770 <div class="form-group-item"> 771 <label>Sesso</label> 772 <div> 773 <div class="custom-control custom-radio custom-control-inline"> 774 <label> 775 <input @change="checkRadio('tutoreGender')" class="custom-control-input" name="tutoreGender" type="radio" value="male" v-model="userData.tutore.gender"/> 776 <span class="custom-control-label"> 777 <span class="custom-control-label-text">M</span> 778 </span> 779 </label> 780 </div> 781 <div class="custom-control custom-radio custom-control-inline"> 782 <label> 783 <input @change="checkRadio('tutoreGender')" class="custom-control-input" name="tutoreGender" type="radio" value="female" v-model="userData.tutore.gender"/> 784 <span class="custom-control-label"> 785 <span class="custom-control-label-text">F</span> 786 </span> 787 </label> 788 </div> 789 </div> 790 </div> 791 <div class="form-group-item"> 792 <label for="tutoreNazione">Nazione</label> 793 <input @blur="checkEmpty($event)" class="form-control" id="tutoreNazione" v-model="userData.tutore.nazione" type="text"/> 794 </div> 795 </div> 796 797 <div class="form-group-autofit"> 798 <div class="form-group-item"> 799 <label for="tutoreAddress">Indirizzo</label> 800 <input @blur="checkEmpty($event)" class="form-control" id="tutoreAddress" v-model="userData.tutore.address" type="text"/> 801 </div> 802 </div> 803 <div class="form-group-autofit"> 804 <div class="form-group-item"> 805 <label for="tutoreCitta">Città</label> 806 <input @blur="checkEmpty($event)" class="form-control" id="tutoreCitta" v-model="userData.tutore.citta" type="text"/> 807 </div> 808 <div class="form-group-item"> 809 <label for="tutoreCap">CAP</label> 810 <input @blur="checkEmpty($event)" class="form-control" id="tutoreCap" v-model="userData.tutore.cap" type="text"/> 811 </div> 812 <div class="form-group-item"> 813 <label for="tutoreProvincia">Provincia</label> 814 <select @blur="checkSelect($event)" class="form-control" id="tutoreProvincia" v-model="userData.tutore.provincia"> 815 <option v-for="province in italianProvinces" :key="province.code" :value="province.code">{{ province.name }}</option> 816 </select> 817 </div> 818 </div> 819 <div class="form-group-autofit"> 820 <div class="form-group-item"> 821 <label for="tutoreCodiceFiscale">Codice fiscale</label> 822 <input @blur="checkCodiceFiscale($event)" class="form-control" id="tutoreCodiceFiscale" v-model="userData.tutore.codiceFiscale" type="text"/> 823 </div> 824 <div class="form-group-item"> 825 <label for="tutoreCellulare">Telefono/Cellulare (solo numeri)</label> 826 <input @blur="checkTelefono($event)" class="form-control" id="tutoreCellulare" @keydown="restrictDigitInput" v-model="userData.tutore.cellulare" type="text"/> 827 </div> 828 <div class="form-group-item"> 829 <label for="tutoreEmail">Email</label> 830 <input @blur="checkEmail($event)" class="form-control" id="tutoreEmail" v-model="userData.tutore.email" type="email"/> 831 </div> 832 </div> 833 </div> 834 835 <div class="sheet-section"> 836 <p class="sheet-title">Recapiti altro genitore</p> 837 838 <div class="form-group-autofit"> 839 <div class="form-group-item"> 840 <label for="tutore2Telefono">Telefono casa/ufficio (inserisci solo numeri)</label> 841 <input @blur="checkTelefono($event)" class="form-control" id="tutore2Telefono" @keydown="restrictDigitInput" v-model="userData.tutore2.telefono" type="text"/> 842 </div> 843 </div> 844 <div class="form-group-autofit"> 845 <div class="form-group-item"> 846 <label for="tutore2Cellulare">Cellulare (inserisci solo numeri)</label> 847 <input @blur="checkTelefono($event)" class="form-control" id="tutore2Cellulare" @keydown="restrictDigitInput" v-model="userData.tutore2.cellulare" type="text"/> 848 </div> 849 <div class="form-group-item"> 850 <label for="tutore2Email">Email</label> 851 <input @blur="checkEmail($event)" class="form-control" id="tutore2Email" v-model="userData.tutore2.email" type="email"/> 852 </div> 853 </div> 854 </div> 855 856 <div class="sheet-section"> 857 <p class="sheet-title">Dati anagrafici del partecipante</p> 858 859 <div class="form-group-autofit"> 860 <div class="form-group-item"> 861 <label for="firstName">Nome</label> 862 <input @blur="checkEmpty($event)" @change="checkOrderAlreadyPresent()" class="form-control" id="firstName" v-model="userData.firstName" type="text"/> 863 </div> 864 <div class="form-group-item"> 865 <label for="lastName">Cognome</label> 866 <input @blur="checkEmpty($event)" @change="checkOrderAlreadyPresent()" class="form-control" id="lastName" v-model="userData.lastName" type="text"/> 867 </div> 868 </div> 869 <div class="form-group-autofit"> 870 <div class="form-group-item"> 871 <label for="birthPlace">Nato a</label> 872 <input @blur="checkEmpty($event)" class="form-control" id="birthPlace" v-model="userData.birthPlace" type="text"/> 873 </div> 874 <div class="form-group-item"> 875 <label for="birthday">Il (gg/mm/aaaa)</label> 876 <input @blur="checkDateLength($event)" class="form-control" id="birthday" @keydown="restrictDateInput" v-model="userData.birthday" type="text"/> 877 </div> 878 <div class="form-group-item"> 879 <label>Sesso</label> 880 <div> 881 <div class="custom-control custom-radio custom-control-inline"> 882 <label> 883 <input @change="checkRadio('gender')" class="custom-control-input" name="gender" type="radio" value="male" v-model="userData.gender"/> 884 <span class="custom-control-label"> 885 <span class="custom-control-label-text">M</span> 886 </span> 887 </label> 888 </div> 889 <div class="custom-control custom-radio custom-control-inline"> 890 <label> 891 <input @change="checkRadio('gender')" class="custom-control-input" name="gender" type="radio" value="female" v-model="userData.gender"/> 892 <span class="custom-control-label"> 893 <span class="custom-control-label-text">F</span> 894 </span> 895 </label> 896 </div> 897 </div> 898 </div> 899 <div class="form-group-item"> 900 <label for="nazionalita">Nazionalità</label> 901 <input @blur="checkEmpty($event)" class="form-control" id="nazionalita" v-model="userData.nazionalita" type="text"/> 902 </div> 903 </div> 904 <div class="form-group-autofit"> 905 <div class="form-group-item"> 906 <label for="address">Indirizzo</label> 907 <input @blur="checkEmpty($event)" class="form-control" id="address" v-model="userData.billingStreetAddress" type="text"/> 908 </div> 909 </div> 910 <div class="form-group-autofit"> 911 <div class="form-group-item"> 912 <label for="citta">Città</label> 913 <input @blur="checkEmpty($event)" class="form-control" id="citta" v-model="userData.billingCity" type="text"/> 914 </div> 915 <div class="form-group-item"> 916 <label for="cap">CAP</label> 917 <input @blur="checkEmpty($event)" class="form-control" id="cap" v-model="userData.billingPostalCode" type="text"/> 918 </div> 919 <div class="form-group-item"> 920 <label for="provincia">Provincia</label> 921 <select @blur="checkSelect($event)" class="form-control" id="provincia" v-model="userData.billingRegionCode"> 922 <option v-for="province in italianProvinces" :key="province.code" :value="province.code">{{ province.name }}</option> 923 </select> 924 </div> 925 </div> 926 927 <div class="form-group-autofit"> 928 <div class="form-group-item"> 929 <label>Problemi di salute del partecipante (patologie/allergie intolleranze alimentari o disturbi di altro genere)</label> 930 <div class="custom-control custom-radio"> 931 <label> 932 <input @change="checkRadio('problemiSalute')" class="custom-control-input" name="problemiSalute" type="radio" value="true" v-model="userData.problemiSalute"/> 933 <span class="custom-control-label"> 934 <span class="custom-control-label-text">Si, come da certificato medico che sarà inviato</span> 935 </span> 936 </label> 937 </div> 938 <div class="custom-control custom-radio"> 939 <label> 940 <input @change="checkRadio('problemiSalute')" class="custom-control-input" name="problemiSalute" type="radio" value="false" v-model="userData.problemiSalute"/> 941 <span class="custom-control-label"> 942 <span class="custom-control-label-text">No</span> 943 </span> 944 </label> 945 </div> 946 </div> 947 </div> 948 </div> 949 950 <div class="sheet-section"> 951 <p class="sheet-title">Documento di identità dello studente (carta d'identità valida per l'espatrio o passaporto)</p> 952 953 <div class="form-group-autofit"> 954 <div class="form-group-item"> 955 <label for="tipoDocumento">Tipo di documento</label> 956 <input @blur="checkEmpty($event)" class="form-control" id="tipoDocumento" v-model="userData.tipoDocumento" type="text"/> 957 </div> 958 <div class="form-group-item"> 959 <label for="numeroDocumento">Numero</label> 960 <input @blur="checkEmpty($event)" class="form-control" id="numeroDocumento" v-model="userData.numeroDocumento" type="text"/> 961 </div> 962 <div class="form-group-item"> 963 <label for="cittadinanzaDocumento">Cittadinanza</label> 964 <input @blur="checkEmpty($event)" class="form-control" id="cittadinanzaDocumento" v-model="userData.cittadinanzaDocumento" type="text"/> 965 </div> 966 </div> 967 <div class="form-group-autofit"> 968 <div class="form-group-item"> 969 <label for="enteRilascioDocumento">Rilasciato da</label> 970 <input @blur="checkEmpty($event)" class="form-control" id="enteRilascioDocumento" v-model="userData.enteRilascioDocumento" type="text"/> 971 </div> 972 <div class="form-group-item"> 973 <label for="dataRilascioDocumento">Data rilascio (gg/mm/aaaa)</label> 974 <input @blur="checkDateLength($event)" class="form-control" id="dataRilascioDocumento" @keydown="restrictDateInput" v-model="userData.dataRilascioDocumento" type="text"/> 975 </div> 976 <div class="form-group-item"> 977 <label for="dataScadenzaDocumento">Data di scadenza (gg/mm/aaaa)</label> 978 <input @blur="checkDateLength($event)" class="form-control" id="dataScadenzaDocumento" @keydown="restrictDateInput" v-model="userData.dataScadenzaDocumento" type="text"/> 979 </div> 980 </div> 981 982 <p class="sheet-text strong-aqua"> 983 <strong>IMPORTANTE</strong>: verificare bene i dati del partecipante, che saranno utilizzati per effettuare il check-in online. <br> 984 In caso variazione del documento che sarà presentato alla partenza, o di errori rilevati dopo l'invio, è necessario darne tempestiva comunicazione, pena l'impossibilità di imbarco. 985 </p> 986 </div> 987 988 <div class="sheet-section"> 989 <div class="form-group-autofit"> 990 <div class="form-group-item"> 991 <label for="allergie">Allergie da segnalare:</label> 992 <input class="form-control" id="allergie" v-model="userData.allergie" type="text"/> 993 </div> 994 </div> 995 <div class="form-group-autofit"> 996 <div class="form-group-item"> 997 <label for="inCameraCon">Vorrei essere sistemato in camera con:</label> 998 <input class="form-control" id="inCameraCon" v-model="userData.inCameraCon" type="text"/> 999 </div> 1000 </div> 1001 </div> 1002 1003 <div class="sheet-section"> 1004 <div class="form-group-autofit"> 1005 <div class="form-group-item"> 1006 <label>Autorizzo la pubblicazione di foto e video di mio/a figlio/a, realizzati durante il programma, sulle pagine social di Zainetto Verde e sul gruppo creato per le famiglie</label> 1007 <div class="custom-control custom-radio"> 1008 <label> 1009 <input @change="checkRadio('autorizzazioneFotoFiglio')" class="custom-control-input" name="autorizzazioneFotoFiglio" type="radio" value="true" v-model="userData.autorizzazioneFotoFiglio"/> 1010 <span class="custom-control-label"> 1011 <span class="custom-control-label-text">Si</span> 1012 </span> 1013 </label> 1014 </div> 1015 <div class="custom-control custom-radio"> 1016 <label> 1017 <input @change="checkRadio('autorizzazioneFotoFiglio')" class="custom-control-input" name="autorizzazioneFotoFiglio" type="radio" value="false" v-model="userData.autorizzazioneFotoFiglio"/> 1018 <span class="custom-control-label"> 1019 <span class="custom-control-label-text">No</span> 1020 </span> 1021 </label> 1022 </div> 1023 </div> 1024 </div> 1025 </div> 1026 </div> 1027 </div> 1028 <div class="col-12" v-else> 1029 <p class="text-dark display-5 font-weight-light">Per continuare, seleziona un periodo dalla prima pagina.</p> 1030 </div> 1031 1032 <div class="col-12 mt-4 text-center" v-if="!moduloValid"> 1033 <span style="color:red;">Non sono compilati tutti i campi richiesti, vedi campi evidenziati</span> 1034 </div> 1035 <div v-if="orderAlreadyPresent" class="col-12 mt-4 text-center"> 1036 <span style="color:red;">Attenzione: questo programma risulta già ordinato dal tuo account per lo stesso partecipante.</span> 1037 </div> 1038 1039 <div class="col-12"> 1040 <div class="card void mt-3 mt-lg-5 mb-0"> 1041 <div class="card-row"> 1042 <div class="autofit-col autofit-col-expand"> 1043 <section class="autofit-section text-left"> 1044 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 1045 Indietro 1046 </button> 1047 </section> 1048 </div> 1049 <div class="autofit-col autofit-col-expand"> 1050 <section class="autofit-section text-right"> 1051 <button @click="gotoStep('next')" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="!moduloValid || orderAlreadyPresent"> 1052 Avanti 1053 </button> 1054 </section> 1055 </div> 1056 </div> 1057 </div> 1058 </div> 1059 </div> 1060 </div> 1061 1062 <#-- STEP 8: PAGAMENTO --> 1063 1064 <div class="tab-pane fade" id="chose_payment" :class="{'show active': currentStep == 8}" v-if="signedIn" role="tabpanel"> 1065 <div class="row"> 1066 <div class="d-none d-lg-block col-12 mb-4"> 1067 <p class="text-dark display-5 font-weight-light" style="line-height: 3rem !important;">Conferma l'acquisto scegliendo il metodo di pagamento</p> 1068 </div> 1069 1070 <#-- SET ACCONTO --> 1071 <template v-for="(type, index) in selectedPackage.paymentType"> 1072 <template v-if="type.type == 'cartaCreditoAcconto' && type.amount != 0"> 1073 <p :set="acconto=1"></p> 1074 </template> 1075 </template> 1076 1077 <template v-if="!_.isEmpty(selectedPackage) && acconto != 0"> 1078 <div class="col-12 col-xl-6 br-light pr-xl-5"> 1079 1080 <template v-for="(type, index) in selectedPackage.paymentType"> 1081 <template v-if="type.type == 'cartaCreditoAcconto' && type.amount != 0"> 1082 <p class="text-dark h4">Scegli modalità pagamento acconto</p> 1083 <p class="custom-control-label-text pl-0">Importo acconto: {{ type.amount | money }}</p> 1084 1085 </template> 1086 </template> 1087 1088 <#-- ACCONTO --> 1089 <ul class="list-group mb-lg-4"> 1090 <template v-for="(type, index) in selectedPackage.paymentType"> 1091 <li v-if="type.type == 'cartaCredito' || type.type == 'bonifico' || type.type == 'cartaCreditoAcconto'" :key="'type-' + index" class="list-group-item"> 1092 <div class="card-row flex-column flex-lg-row"> 1093 <div class="autofit-col autofit-col-expand"> 1094 <section class="autofit-section my-auto"> 1095 <div class="custom-control custom-radio"> 1096 <label> 1097 <input @change="checkRadio('paymentMethod')" class="custom-control-input" type="radio" name="paymentMethod" v-model="selectedPayment" :value="type" /> 1098 <span class="custom-control-label"> 1099 <span class="custom-control-label-text"> 1100 {{ getPaymentLabel(type.type) }} 1101 </span> 1102 </span> 1103 </label> 1104 </div> 1105 </section> 1106 </div> 1107 <div class="autofit-col autofit-col-expand"> 1108 <section class="autofit-section text-right my-auto"> 1109 <img src="${images_folder}/bonifico.png" height="60" alt="bonifico" v-if="type.type == 'bonifico'"> 1110 <img src="${images_folder}/visa-mastercard.png" height="60" alt="visa-mastercard" v-if="type.type == 'cartaCredito'"> 1111 <img src="${images_folder}/visa-mastercard.png" height="60" alt="visa-mastercard" v-if="type.type == 'cartaCreditoAcconto'"> 1112 </section> 1113 </div> 1114 </div> 1115 1116 <p v-if="type.type == 'bonifico'" class="card-subtitle" style="display: block; margin-left: 1.5rem;"> 1117 Intestato a Zainetto Verde srl - IBAN IT42L0100513700000000002639 1118 </p> 1119 </li> 1120 </template> 1121 </ul> 1122 1123 1124 </div> 1125 1126 <#-- SALDO --> 1127 <div class="col-12 col-xl-6 pl-xl-5" v-if="!_.isEmpty(selectedPackage)"> 1128 <p class="text-dark h4">Scegli come vorrai pagare il saldo</p> 1129 <p class="custom-control-label-text pl-0">Importo saldo: come da preventivo</p> 1130 1131 <ul class="list-group mb-lg-0"> 1132 <li class="list-group-item"> 1133 <div class="card-row flex-column flex-lg-row"> 1134 <div class="autofit-col autofit-col-expand"> 1135 <section class="autofit-section my-auto"> 1136 <div class="custom-control custom-radio"> 1137 <label> 1138 <input class="custom-control-input" @change="checkRadio('paymentBalanceMethod')" type="radio" name="paymentBalanceMethod" v-model="selectedBalance" :value="{ amount: 0, type: 'rateale-zv' }" /> 1139 <span class="custom-control-label"> 1140 <span class="custom-control-label-text" style="display: block; margin-left: 1rem;"> 1141 bonifico come da accordi con ZV, con saldo prima della partenza 1142 </span> 1143 </span> 1144 </label> 1145 </div> 1146 </section> 1147 </div> 1148 </div> 1149 </li> 1150 <li class="list-group-item"> 1151 <div class="card-row flex-column flex-lg-row"> 1152 <div class="autofit-col autofit-col-expand"> 1153 <section class="autofit-section my-auto"> 1154 <div class="custom-control custom-radio"> 1155 <label> 1156 <input class="custom-control-input" @change="checkRadio('paymentBalanceMethod')" type="radio" name="paymentBalanceMethod" v-model="selectedBalance" :value="{ amount: 0, type: 'rateale' }" /> 1157 <span class="custom-control-label"> 1158 <span class="custom-control-label-text" style="display: block; margin-left: 1rem;"> 1159 Richiesta di finanziamento con possibilità di scegliere il numero delle rate<br/> (soggetta ad approvazione della finanziaria) 1160 </span> 1161 </span> 1162 </label> 1163 </div> 1164 </section> 1165 </div> 1166 <div class="autofit-col autofit-col-expand"> 1167 <section class="autofit-section text-right my-auto"> 1168 <#-- 1169 <img src="${images_folder}/rateale.png" height="80" alt="rateale"> 1170 1171<img src="/documents/383793/2101965/PagoLight+Pro.svg/a66a8c4e-2422-7684-074c-3478d7862d22?t=1709719439418" height="80" width="120" alt="rateale"> --> 1172<img src="/documents/383793/2101965/Findomestic.jpg/6f581557-094b-14d4-917a-65244cd94560?t=1738307202362" height="51" width="120" alt="rateale"> 1173 </section> 1174 </div> 1175 </div> 1176 </li> 1177 1178 </ul> 1179 </div> 1180 </template> 1181 1182 <#-- SALDO COMPLETO SENZA ACCONTO --> 1183 <template v-if="!_.isEmpty(selectedPackage) && acconto == 0"> 1184 <div class="col-12" v-if="!_.isEmpty(selectedPackage)"> 1185 <p class="text-dark h4">Scegli come vorrai pagare il saldo</p> 1186 <p class="custom-control-label-text pl-0">Importo saldo: come da preventivo</p> 1187 <ul class="list-group mb-lg-0"> 1188 <template v-if="!_.isEmpty(selectedPackage) && acconto == 0"> 1189 <template v-for="(type, index) in selectedPackage.paymentType"> 1190 <li v-if="type.type == 'cartaCredito'" :key="'type-' + index" class="list-group-item"> 1191 <div class="card-row flex-column flex-lg-row"> 1192 <div class="autofit-col autofit-col-expand"> 1193 <section class="autofit-section my-auto"> 1194 <div class="custom-control custom-radio"> 1195 <label> 1196 <input @change="checkRadio('paymentMethod')" class="custom-control-input" type="radio" name="paymentMethod" v-model="selectedPayment" :value="type" /> 1197 <span class="custom-control-label"> 1198 <span class="custom-control-label-text"> 1199 {{ getPaymentLabel(type.type) }} 1200 </span> 1201 </span> 1202 </label> 1203 </div> 1204 </section> 1205 </div> 1206 <div class="autofit-col autofit-col-expand"> 1207 <section class="autofit-section text-right my-auto"> 1208 <img src="${images_folder}/visa-mastercard.png" height="60" alt="visa-mastercard" v-if="type.type == 'cartaCredito'"> 1209 </section> 1210 </div> 1211 </div> 1212 </li> 1213 </template> 1214 </template> 1215 1216 <li class="list-group-item"> 1217 <div class="card-row flex-column flex-lg-row"> 1218 <div class="autofit-col autofit-col-expand"> 1219 <section class="autofit-section my-auto"> 1220 <div class="custom-control custom-radio"> 1221 <label> 1222 <input @change="checkRadio('paymentBalanceMethod')" class="custom-control-input" type="radio" name="paymentBalanceMethod" v-model="selectedPayment" :value="{ amount: 0, type: 'rateale-zv' }" /> 1223 <span class="custom-control-label"> 1224 <span class="custom-control-label-text" style="display: block; margin-left: 1rem;"> 1225 bonifico come da accordi con ZV, con saldo prima della partenza 1226 </span> 1227 </span> 1228 </label> 1229 </div> 1230 </section> 1231 </div> 1232 </div> 1233 </li> 1234 <li class="list-group-item"> 1235 <div class="card-row flex-column flex-lg-row"> 1236 <div class="autofit-col autofit-col-expand"> 1237 <section class="autofit-section my-auto"> 1238 <div class="custom-control custom-radio"> 1239 <label> 1240 <input @focus="checkRadio('paymentBalanceMethod')" class="custom-control-input" type="radio" name="paymentBalanceMethod" v-model="selectedPayment" :value="{ amount: 0, type: 'rateale' }" /> 1241 <span class="custom-control-label"> 1242 <span class="custom-control-label-text" style="display: block; margin-left: 1rem;"> 1243 Richiesta di finanziamento con possibilità di scegliere il numero delle rate<br/> (soggetta ad approvazione della finanziaria) 1244 </span> 1245 </span> 1246 </label> 1247 </div> 1248 </section> 1249 </div> 1250 <div class="autofit-col autofit-col-expand"> 1251 <section class="autofit-section text-right my-auto"> 1252<#-- 1253 <img src="${images_folder}/rateale.png" height="80" alt="rateale"> 1254 1255<img src="/documents/383793/2101965/PagoLight+Pro.svg/a66a8c4e-2422-7684-074c-3478d7862d22?t=1709719439418" height="80" width="120" alt="rateale">--> 1256 1257<img src="/documents/383793/2101965/Findomestic.jpg/6f581557-094b-14d4-917a-65244cd94560?t=1738307202362" height="51" width="120" alt="rateale"> 1258 </section> 1259 </div> 1260 </div> 1261 </li> 1262 1263 </ul> 1264 </div> 1265 </template> 1266 1267 1268 1269 <hr class="col-12"> 1270 1271 <div class="col-12 col-lg-7"> 1272 1273 <p v-if="!attachments.every(att => att.downloaded)" class="mb-3" id="info_accept" style="color:#FF0000;">È necessario scaricare gli allegati per procedere all'accettazione delle condizioni sottostanti</p> 1274 1275 <div class="autofit-section" id="field_att"> 1276 <div v-for="(attachment, index) in attachments" :key="'attachment-' + index"> 1277 <div class="card-row mb-4 mb-lg-2"> 1278 <div class="autofit-col autofit-col-expand"> 1279 <section class="autofit-section"> 1280 <div class="custom-control custom-checkbox"> 1281 <label> 1282 <#-- :disabled="!attachments.every(att => att.downloaded)" --> 1283 <input v-model="policy['condition' + sum(index, 1)]" :id="'condition_' + sum(index, 1)" @change="checkPolicy($event)" class="custom-control-input" type="checkbox" :disabled="!attachments.every(att => att.downloaded)"> 1284 <span class="custom-control-label"> 1285 <span class="custom-control-label-text"> 1286 {{ attachment.title }} 1287 <template v-if="attachment.mandatory">*</template> 1288 </span> 1289 </span> 1290 </label> 1291 </div> 1292 </section> 1293 </div> 1294 <div class="autofit-col"> 1295 <section class="autofit-section"> 1296 <button v-if="attachment.downloaded" @click="downloadAttachment(attachment)" class="btn btn-link text-aqua p-0 mb-0"> 1297 documento scaricato 1298 <i class="fas fa-check ml-1"></i> 1299 </button> 1300 <button v-else @click="downloadAttachment(attachment)" class="btn btn-link p-0 mb-0" style="color:red;"> 1301 Scarica il documento 1302 <i class="fas fa-download ml-1"></i> 1303 </button> 1304 </section> 1305 </div> 1306 </div> 1307 <div class="card-row mb-4 mb-lg-2" v-if="index==0"> 1308 <div class="autofit-col autofit-col-expand"> 1309 <section class="autofit-section"> 1310 <div class="custom-control custom-checkbox"> 1311 <label> 1312 <input v-model="doppiocheck" class="custom-control-input" id="condition_x" type="checkbox" @change="checkPolicy($event)" :disabled="(!attachments.every(att => att.downloaded))"> 1313 <span class="custom-control-label"> 1314 <span class="custom-control-label-text"> 1315 Per espressa accettazione, ex art. 1341 e 1342 c.c., delle condizioni generali richiamate 1316 <template v-if="attachment.mandatory">*</template> 1317 </span> 1318 </span> 1319 </label> 1320 </div> 1321 </section> 1322 </div> 1323 </div> 1324 </div> 1325 </div> 1326 1327 <p v-if="!_.isEmpty(selectedPackage) && orderResult != ''" class="h4">{{ orderResult }}</p> 1328 </div> 1329 1330 <template v-if="!_.isEmpty(selectedPackage) && acconto == 0"> 1331 <div v-if="_.isEmpty(selectedPayment) || !validPolicy" style="border-top: 1px solid #ccc;border-bottom: 1px solid #ccc;" class="col-12 text-center py-3 mt-3 mt-lg-5"> 1332 <p style="color:red;" class="m-0">non sono flaggati tutti i campi richiesti, vedi campi evidenziati in rosso</p> 1333 </div> 1334 </template> 1335 <template v-else> 1336 <div v-if="_.isEmpty(selectedPayment) || !validPolicy || _.isEmpty(selectedBalance)" style="border-top: 1px solid #ccc;border-bottom: 1px solid #ccc;" class="col-12 text-center py-3 mt-3 mt-lg-5"> 1337 <p style="color:red;" class="m-0">non sono flaggati tutti i campi richiesti, vedi campi evidenziati in rosso</p> 1338 </div> 1339 </template> 1340 1341 <div class="col-12"> 1342 <div class="card void mt-3 mt-lg-5 mb-0"> 1343 <div class="card-row"> 1344 <div class="autofit-col autofit-col-expand"> 1345 <section class="autofit-section text-left"> 1346 <button @click="gotoStep('prev')" class="btn btn-outline-dark py-2 px-3 px-lg-4"> 1347 Indietro 1348 </button> 1349 </section> 1350 </div> 1351 1352 <div class="autofit-col autofit-col-expand" v-if="!_.isEmpty(selectedPackage) && acconto == 0"> 1353 <section class="autofit-section text-right"> 1354 <#-- <button v-if="checkOrderAlreadyPresent() && orderAlreadyPresent" class="btn btn-gradient py-2 px-3 px-lg-4" disabled> 1355 Già ordinato 1356 </button> --> 1357 <button @click="!_.isEmpty(selectedPayment) ? createOrderAndPaymentUrl() : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="_.isEmpty(selectedPayment) || !validPolicy"> 1358 Pagamento 1359 </button> 1360 </section> 1361 </div> 1362 1363 <div class="autofit-col autofit-col-expand" v-else> 1364 <section class="autofit-section text-right"> 1365 <#-- <button v-if="orderAlreadyPresent" class="btn btn-gradient py-2 px-3 px-lg-4" disabled> 1366 Già ordinato 1367 </button> --> 1368 <button @click="!_.isEmpty(selectedPayment) && !_.isEmpty(selectedBalance) ? createOrderAndPaymentUrl() : ''" class="btn btn-gradient py-2 px-3 px-lg-4" :disabled="_.isEmpty(selectedPayment) || !validPolicy || _.isEmpty(selectedBalance)"> 1369 Pagamento 1370 </button> 1371 </section> 1372 </div> 1373 1374 </div> 1375 </div> 1376 </div> 1377 </div> 1378 </div> 1379 1380 <#-- STEP 9: RINGRAZIAMENTO --> 1381 <div class="tab-pane fade" :class="{'show active': currentStep == 9}" v-if="signedIn" role="tabpanel"> 1382 <div class="row"> 1383 <div class="d-none d-lg-block col-12 mb-4"> 1384 <p class="text-dark display-5 font-weight-light">Grazie per la tua prenotazione</p> 1385 </div> 1386 1387 <div class="col-12 col-lg-7"> 1388 <p class="h4 text-dark font-weight-regular mt-5"> 1389 Grazie per aver prenotato un pacchetto Zainetto Verde!<br> 1390 Ti è stata inviata una mail di riepilogo e potrai trovare il riepilogo del tuo acquisto anche nella sezione dei tuoi viaggi. 1391 </p> 1392 </div> 1393 1394 <div class="col-12 col-lg-5"> 1395 <div class="d-flex h-100 align-items-end justify-content-center"> 1396 <button @click="redirectParent('/i-miei-viaggi')" class="btn btn-gradient btn-lg mt-4 mt-lg-0">Vai ai tuoi viaggi</button> 1397 </div> 1398 </div> 1399 </div> 1400 </div> 1401 </div> 1402 </div> 1403 </div> 1404 </div> 1405 </div> 1406</#macro> 1407 1408<#assign 1409 DLAppLocalService = serviceLocator.findService("com.liferay.document.library.kernel.service.DLAppLocalService") 1410 JALS = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") 1411 suggestoMkspAPI = serviceLocator.findService("eu.suggesto.suggestogui.service.SuggestoGuiLocalService") 1412 productServiceAPI = serviceLocator.findService("eu.suggesto.d40.builder.d40.service.ProductLocalService") 1413 saxReaderUtil = staticUtil["com.liferay.portal.kernel.xml.SAXReaderUtil"] 1414 1415 images_folder = themeDisplay.getPathThemeImages() 1416 icons_folder = images_folder + "/icons" 1417 contentId = result.getRequestStringParameter("contentId") 1418 defLocale = localeUtil.fromLanguageId("it_IT") 1419 image = "https://via.placeholder.com/300" 1420 dateSoggiorno = [] 1421 packages = [] 1422 name = "Placeholder" 1423 prezzo_base = 0 1424 sCatSistemazione = "" 1425/> 1426 1427<#if contentId?has_content> 1428 <#assign 1429 packages = getPackagesByItemId(groupId, groupId, contentId) 1430 article = JALS.getArticle(themeDisplay.getSiteGroupId(), contentId) 1431 document = saxReaderUtil.read(article.getContent()) 1432 docTitle=article.getTitle(defLocale) 1433 1434 rootElement = document.getRootElement() 1435 groupedCategories = suggestoMkspAPI.getGroupedArticleCategories(groupId, contentId, locale, defLocale) 1436 1437 xPathDate = saxReaderUtil.createXPath("dynamic-element[@name='data_inizio']") 1438 xPathImage = saxReaderUtil.createXPath("dynamic-element[@name='anteprima']") 1439 xPathName = saxReaderUtil.createXPath("dynamic-element[@name='nome_scuola']/dynamic-content[@language-id='" + themeDisplay.getLocale() + "']") 1440 xPathPrezzo = saxReaderUtil.createXPath("dynamic-element[@name='prezzo_base']/dynamic-content[@language-id='" + themeDisplay.getLocale() + "']") 1441 /> 1442 1443 <#if (groupedCategories.length() > 0) > 1444 <#list 0..groupedCategories.length()-1 as i> 1445 <#assign 1446 gc = groupedCategories.getJSONObject(i) 1447 gcCat = gc.getJSONArray("categories") 1448 vacabularyName = gc.getString("vocabularyName") 1449 /> 1450 1451 <#if vacabularyName == "Tipo di sistemazione"> 1452 <#list 0..gcCat.length()-1 as y> 1453 <#assign 1454 sCat = gcCat.getJSONObject(y) 1455 sCatId = sCat.getString("categoryId") 1456 sCatSistemazione = sCat.getString("name") 1457 sCatIcon = sCat.getString("icon") 1458 /> 1459 </#list> 1460 </#if> 1461 </#list> 1462 </#if> 1463 1464 <#if xPathDate.selectNodes(rootElement)??> 1465 <#list xPathDate.selectNodes(rootElement) as node> 1466 <#assign 1467 dataInizio = node.selectSingleNode("dynamic-content[@language-id='" + themeDisplay.getLocale() + "']").getStringValue()?replace("-", "/") 1468 dataFine = node.selectSingleNode("dynamic-element[@name='data_fine']/dynamic-content[@language-id='" + themeDisplay.getLocale() + "']").getStringValue()?replace("-", "/") 1469 dateSoggiorno += [ 1470 { 1471 "dataInizio": "${dataInizio}", 1472 "dataFine": "${dataFine}" 1473 } 1474 ] 1475 /> 1476 </#list> 1477 </#if> 1478 1479 <#if xPathImage.selectSingleNode(rootElement)??> 1480 <#compress> 1481 <#assign tmpImage = xPathImage.selectSingleNode(rootElement).getStringValue()?trim> 1482 </#compress> 1483 1484 <#if tmpImage?has_content> 1485 <#assign 1486 image = tmpImage 1487 jsonField = jsonFactoryUtil.createJSONObject(image) 1488 fileEntry = DLAppLocalService.getFileEntryByUuidAndGroupId(jsonField.uuid, groupId) 1489 image = "/documents/" + jsonField.groupId + "/" + fileEntry.folderId + "/" + jsonField.title + "/" + jsonField.uuid 1490 /> 1491 </#if> 1492 </#if> 1493 1494 <#if xPathName.selectSingleNode(rootElement)??> 1495 <#assign name = xPathName.selectSingleNode(rootElement).getStringValue()?trim?capitalize> 1496 </#if> 1497 1498 <#if xPathPrezzo.selectSingleNode(rootElement)??> 1499 <#assign prezzo_base = xPathPrezzo.selectSingleNode(rootElement).getStringValue()?trim> 1500 </#if> 1501</#if> 1502 1503<@printContent /> 1504 1505<script> 1506 document.addEventListener("DOMContentLoaded", function (){ 1507 if(!Liferay.ThemeDisplay.getUserEmailAddress().includes("@suggesto.")){ 1508 Vue.config.devtools = false; 1509 } 1510 1511 Vue.filter("money", function(value){ 1512 var formatter = new Intl.NumberFormat('it-IT', { 1513 style: 'currency', 1514 currency: 'EUR', 1515 }); 1516 if(typeof value!="undefined" && value!="" && value!="0") 1517 return formatter.format(parseFloat(value)); 1518 else 1519 return ""; 1520 }); 1521 1522 var pay = new Vue({ 1523 el: "#pay", 1524 data: { 1525 isDev: Liferay.ThemeDisplay.getUserEmailAddress().includes("@suggesto") && !Liferay.ThemeDisplay.getUserEmailAddress().includes("studente"), 1526 loading: true, 1527 favourite: false, 1528 contentId: "${contentId}", 1529 image: "${getPrefix(htmlUtil.escape(image), 300, '')}", 1530 currentStep: 1, 1531 totalSteps: 0, 1532 name: "${name}", 1533 signedIn: Liferay.ThemeDisplay.isSignedIn(), 1534 groupId: Liferay.ThemeDisplay.getScopeGroupId(), 1535 userMail: Liferay.ThemeDisplay.getUserEmailAddress(), 1536 defaultLanguage: "it", 1537 defaultCountryId: "8", 1538 packagePrice: 0, 1539 packageDiscount: 0, 1540 acconto: 0, 1541 selectedPackage: {}, 1542 selectedAirport: {}, 1543 selectedAccomodation: {}, 1544 selectedServices: [], 1545 selectedPayment: {}, 1546 selectedBalance: {}, 1547 paymentLink: "#", 1548 hasAccompagnatorePermission: false, 1549 voucher: "", 1550 voucherDiscount: 0, 1551 voucherValid: false, 1552 oid: "", 1553 packages: [], 1554 attachments: [], 1555 doppiocheck:false, 1556 sameUserOrders:[], 1557 orderAlreadyPresent:false, 1558 calendar: { 1559 ready: false, 1560 initialPage: { 1561 month: null, 1562 year: null 1563 }, 1564 periodoSelected: { 1565 start: null, 1566 end: null 1567 }, 1568 dataSelected: null, 1569 dataInizio: null, 1570 dataFine: null, 1571 attributes: [] 1572 }, 1573 policy: { 1574 <#list allegati as allegato> 1575 condition${allegato?counter}: false, 1576 </#list> 1577 }, 1578 countryList: [], 1579 regionList: [], 1580 userData: {}, 1581 orderResult: "", 1582 msgCodiceFiscale:"", 1583 italianProvinces: [ 1584 { code: 'AG', name: 'Agrigento' }, 1585 { code: 'AL', name: 'Alessandria' }, 1586 { code: 'AN', name: 'Ancona' }, 1587 { code: 'AO', name: 'Aosta' }, 1588 { code: 'AR', name: 'Arezzo' }, 1589 { code: 'AP', name: 'Ascoli Piceno' }, 1590 { code: 'AT', name: 'Asti' }, 1591 { code: 'AV', name: 'Avellino' }, 1592 { code: 'BA', name: 'Bari' }, 1593 { code: 'BT', name: 'Barletta-Andria-Trani' }, 1594 { code: 'BL', name: 'Belluno' }, 1595 { code: 'BN', name: 'Benevento' }, 1596 { code: 'BG', name: 'Bergamo' }, 1597 { code: 'BI', name: 'Biella' }, 1598 { code: 'BO', name: 'Bologna' }, 1599 { code: 'BZ', name: 'Bolzano' }, 1600 { code: 'BS', name: 'Brescia' }, 1601 { code: 'BR', name: 'Brindisi' }, 1602 { code: 'CA', name: 'Cagliari' }, 1603 { code: 'CL', name: 'Caltanissetta' }, 1604 { code: 'CB', name: 'Campobasso' }, 1605 { code: 'CI', name: 'Carbonia-Iglesias' }, 1606 { code: 'CE', name: 'Caserta' }, 1607 { code: 'CT', name: 'Catania' }, 1608 { code: 'CZ', name: 'Catanzaro' }, 1609 { code: 'CH', name: 'Chieti' }, 1610 { code: 'CO', name: 'Como' }, 1611 { code: 'CS', name: 'Cosenza' }, 1612 { code: 'CR', name: 'Cremona' }, 1613 { code: 'KR', name: 'Crotone' }, 1614 { code: 'CN', name: 'Cuneo' }, 1615 { code: 'EN', name: 'Enna' }, 1616 { code: 'FM', name: 'Fermo' }, 1617 { code: 'FE', name: 'Ferrara' }, 1618 { code: 'FI', name: 'Firenze' }, 1619 { code: 'FG', name: 'Foggia' }, 1620 { code: 'FC', name: 'Forlì-Cesena' }, 1621 { code: 'FR', name: 'Frosinone' }, 1622 { code: 'GE', name: 'Genova' }, 1623 { code: 'GO', name: 'Gorizia' }, 1624 { code: 'GR', name: 'Grosseto' }, 1625 { code: 'IM', name: 'Imperia' }, 1626 { code: 'IS', name: 'Isernia' }, 1627 { code: 'SP', name: 'La Spezia' }, 1628 { code: 'AQ', name: "L'Aquila" }, 1629 { code: 'LT', name: 'Latina' }, 1630 { code: 'LE', name: 'Lecce' }, 1631 { code: 'LC', name: 'Lecco' }, 1632 { code: 'LI', name: 'Livorno' }, 1633 { code: 'LO', name: 'Lodi' }, 1634 { code: 'LU', name: 'Lucca' }, 1635 { code: 'MC', name: 'Macerata' }, 1636 { code: 'MN', name: 'Mantova' }, 1637 { code: 'MS', name: 'Massa-Carrara' }, 1638 { code: 'MT', name: 'Matera' }, 1639 { code: 'VS', name: 'Medio Campidano' }, 1640 { code: 'ME', name: 'Messina' }, 1641 { code: 'MI', name: 'Milano' }, 1642 { code: 'MO', name: 'Modena' }, 1643 { code: 'MB', name: 'Monza e della Brianza' }, 1644 { code: 'NA', name: 'Napoli' }, 1645 { code: 'NO', name: 'Novara' }, 1646 { code: 'NU', name: 'Nuoro' }, 1647 { code: 'OG', name: 'Ogliastra' }, 1648 { code: 'OT', name: 'Olbia-Tempio' }, 1649 { code: 'OR', name: 'Oristano' }, 1650 { code: 'PD', name: 'Padova' }, 1651 { code: 'PA', name: 'Palermo' }, 1652 { code: 'PR', name: 'Parma' }, 1653 { code: 'PV', name: 'Pavia' }, 1654 { code: 'PG', name: 'Perugia' }, 1655 { code: 'PU', name: 'Pesaro e Urbino' }, 1656 { code: 'PE', name: 'Pescara' }, 1657 { code: 'PC', name: 'Piacenza' }, 1658 { code: 'PI', name: 'Pisa' }, 1659 { code: 'PT', name: 'Pistoia' }, 1660 { code: 'PN', name: 'Pordenone' }, 1661 { code: 'PZ', name: 'Potenza' }, 1662 { code: 'PO', name: 'Prato' }, 1663 { code: 'RG', name: 'Ragusa' }, 1664 { code: 'RA', name: 'Ravenna' }, 1665 { code: 'RC', name: 'Reggio Calabria' }, 1666 { code: 'RE', name: 'Reggio Emilia' }, 1667 { code: 'RI', name: 'Rieti' }, 1668 { code: 'RN', name: 'Rimini' }, 1669 { code: 'RM', name: 'Roma' }, 1670 { code: 'RO', name: 'Rovigo' }, 1671 { code: 'SA', name: 'Salerno' }, 1672 { code: 'SS', name: 'Sassari' }, 1673 { code: 'SV', name: 'Savona' }, 1674 { code: 'SI', name: 'Siena' }, 1675 { code: 'SR', name: 'Siracusa' }, 1676 { code: 'SO', name: 'Sondrio' }, 1677 { code: 'TA', name: 'Taranto' }, 1678 { code: 'TE', name: 'Teramo' }, 1679 { code: 'TR', name: 'Terni' }, 1680 { code: 'TO', name: 'Torino' }, 1681 { code: 'TP', name: 'Trapani' }, 1682 { code: 'TN', name: 'Trento' }, 1683 { code: 'TV', name: 'Treviso' }, 1684 { code: 'TS', name: 'Trieste' }, 1685 { code: 'UD', name: 'Udine' }, 1686 { code: 'VA', name: 'Varese' }, 1687 { code: 'VE', name: 'Venezia' }, 1688 { code: 'VB', name: 'Verbano-Cusio-Ossola' }, 1689 { code: 'VC', name: 'Vercelli' }, 1690 { code: 'VR', name: 'Verona' }, 1691 { code: 'VV', name: 'Vibo Valentia' }, 1692 { code: 'VI', name: 'Vicenza' }, 1693 { code: 'VT', name: 'Viterbo' }, 1694 { code: 'STE', name: 'Stato Estero' } 1695 ], 1696 sendingMessageError:"" 1697 }, 1698 created(){ 1699 var that = this; 1700 1701 moment.locale(navigator.language.split("-")[0]); 1702 1703 window.addEventListener("keyup", function(e){ 1704 if(e.which == 27){ 1705 that.closeParentModal("#pay-modal"); 1706 } 1707 }); 1708 1709 if(this.signedIn){ 1710 if(${hasAccompagnatorePerm?c}){ 1711 this.hasAccompagnatorePermission = true; 1712 console.log("user has permission"); 1713 }else{ 1714 console.log("user doesn't have permission"); 1715 } 1716 } 1717 1718 this.getPackages(); 1719 this.initCalendar(); 1720 this.setAttachments(); 1721 1722 1723 //$('#payment_step input').each(function(){ 1724 // $(this).css({"border":"1px solid orange"}); 1725 //}); 1726 1727 }, 1728 mounted(){ 1729 window.addEventListener("message", this.getExternalData.bind(this)); 1730 1731 if(this.signedIn){ 1732 this.userId = Liferay.ThemeDisplay.getUserId(); 1733 this.checkFavourite(); 1734 this.getUserData(); 1735 1736 this.totalSteps = 9; 1737 }else{ 1738 //this.getCountryList(); 1739 this.totalSteps = 8; 1740 } 1741 1742 console.log("total steps: " + this.totalSteps); 1743 1744 this.calendar.ready = true; 1745 this.getProgressData(); 1746 this.getOrderStatus(); 1747 this.loading = false; 1748 }, 1749 computed: { 1750 totalPrice: function(){ 1751 return this.selectedServices.reduce(function(total, item){ 1752 return Number(total) + Number(item.price); 1753 }, Number(this.packagePrice) - Number(this.packageDiscount) + Number(this.selectedAirport.price || 0) + Number(this.selectedAccomodation.price || 0)); 1754 }, 1755 totalPriceWithVoucher: function(){ 1756 return this.selectedServices.reduce(function(total, item){ 1757 return Number(total) + Number(item.price); 1758 }, Number(this.packagePrice) - Number(this.packageDiscount) + Number(this.selectedAirport.price || 0) + Number(this.selectedAccomodation.price || 0) - Number(this.voucherDiscount || 0)); 1759 }, 1760 validPolicy: function(){ 1761 var valid = false; 1762 1763 if( 1764 <#list allegati as allegato> 1765 <#assign stringSelector = "dynamic-element[@name='mandatory']/dynamic-content[@language-id = '" + themeDisplay.getLocale() + "']"> 1766 <#assign xPathSelector = saxReaderUtil.createXPath(stringSelector)> 1767 <#if xPathSelector.selectSingleNode(allegato)??> 1768 <#assign mandatory = xPathSelector.selectSingleNode(allegato).getData()> 1769 </#if> 1770 1771 <#if mandatory == "true"> 1772 <#if !allegato?is_first> && </#if> 1773 this.policy.condition${allegato?counter} 1774 </#if> 1775 </#list> 1776 ){ 1777 valid = true; 1778 } 1779 console.log("doppiocheck:"+ this.doppiocheck); 1780 if(this.doppiocheck==false) 1781 return false; 1782 return valid; 1783 }, 1784 minimumValid: function(){ 1785 var valid = true; 1786 1787 if(this.userData != null){ 1788 if(!this.userData.hasOwnProperty("firstName") || typeof this.userData["firstName"] !== "string" || this.userData["firstName"].length == 0){ 1789 valid = false; 1790 } 1791 if(!this.userData.hasOwnProperty("lastName") || typeof this.userData["lastName"] !== "string" || this.userData["lastName"].length == 0){ 1792 valid = false; 1793 } 1794 if(!this.userData.hasOwnProperty("phone") || ((/^[0-9]+$/.test(this.userData["phone"]))==false ) || this.userData["phone"].length == 0){ 1795 valid = false; 1796 } 1797 if(this.userMail == ""){ 1798 valid = false; 1799 } 1800 }else{ 1801 valid = false; 1802 } 1803 1804 return valid; 1805 }, 1806 moduloValid: function(){ 1807 var valid = true; 1808 1809 if(this.userData != {}){ 1810 // Tutore/i 1811 1812 if(_.has(this.userData, "tutore.firstName")){ 1813 if(typeof this.userData.tutore.firstName !== "string" || this.userData.tutore.firstName.length == 0){ 1814 valid = false 1815 } 1816 }else{ 1817 valid = false; 1818 } 1819 1820 if(_.has(this.userData, "tutore.lastName")){ 1821 if(typeof this.userData.tutore.lastName !== "string" || this.userData.tutore.lastName.length == 0){ 1822 valid = false 1823 } 1824 }else{ 1825 valid = false; 1826 } 1827 1828 if(_.has(this.userData, "tutore.birthdayPlace")){ 1829 if(typeof this.userData.tutore.birthdayPlace !== "string" || this.userData.tutore.birthdayPlace.length == 0){ 1830 valid = false 1831 } 1832 }else{ 1833 valid = false; 1834 } 1835 1836 if(_.has(this.userData, "tutore.birthday")){ 1837 if(typeof this.userData.tutore.birthday !== "string" || this.userData.tutore.birthday.length != 10 || ! this.dateFormat(this.userData.tutore.birthday) ){ 1838 valid = false 1839 } 1840 }else{ 1841 valid = false; 1842 } 1843 1844 if(_.has(this.userData, "tutore.gender")){ 1845 if(typeof this.userData.tutore.gender !== "string" || this.userData.tutore.gender.length == 0){ 1846 valid = false 1847 } 1848 }else{ 1849 valid = false; 1850 } 1851 1852 if(_.has(this.userData, "tutore.nazione")){ 1853 if(typeof this.userData.tutore.nazione !== "string" || this.userData.tutore.nazione.length == 0){ 1854 valid = false 1855 } 1856 }else{ 1857 valid = false; 1858 } 1859 1860 if(_.has(this.userData, "tutore.address")){ 1861 if(typeof this.userData.tutore.address !== "string" || this.userData.tutore.address.length == 0){ 1862 valid = false 1863 } 1864 }else{ 1865 valid = false; 1866 } 1867 1868 if(_.has(this.userData, "tutore.citta")){ 1869 if(typeof this.userData.tutore.citta !== "string" || this.userData.tutore.citta.length == 0){ 1870 valid = false 1871 } 1872 }else{ 1873 valid = false; 1874 } 1875 1876 if(_.has(this.userData, "tutore.cap")){ 1877 if(typeof this.userData.tutore.cap !== "string" || this.userData.tutore.cap.length == 0){ 1878 valid = false 1879 } 1880 }else{ 1881 valid = false; 1882 } 1883 1884 if(_.has(this.userData, "tutore.provincia")){ 1885 if(typeof this.userData.tutore.provincia !== "string" || this.userData.tutore.provincia.length == 0){ 1886 valid = false 1887 } 1888 }else{ 1889 valid = false; 1890 } 1891 1892 if(_.has(this.userData, "tutore.codiceFiscale")){ 1893 if(typeof this.userData.tutore.codiceFiscale !== "string" || this.userData.tutore.codiceFiscale.length == 0 || 1894 this.controllaCF(this.userData.tutore.codiceFiscale).length!=0){ 1895 valid = false 1896 } 1897 else 1898 this.userData.tutore.codiceFiscale=this.userData.tutore.codiceFiscale.toUpperCase(); 1899 }else{ 1900 valid = false; 1901 } 1902 1903 if(_.has(this.userData, "tutore.cellulare")){ 1904 if(typeof this.userData.tutore.cellulare !== "string" || this.userData.tutore.cellulare.length == 0 || 1905 ((/^[0-9]+$/.test(this.userData.tutore.cellulare))==false ) 1906 1907 ){ 1908 valid = false 1909 } 1910 }else{ 1911 valid = false; 1912 } 1913 1914 if(_.has(this.userData, "tutore.email")){ 1915 if(typeof this.userData.tutore.email !== "string" || this.userData.tutore.email.length == 0){ 1916 valid = false 1917 }else{ 1918 if(this.userData.tutore.email.indexOf("@")>0) { 1919// if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(this.userData.tutore.email)) { 1920 } else { 1921 valid = false; 1922 } 1923 } 1924 }else{ 1925 valid = false; 1926 } 1927 1928 //Tutore2 1929 if(_.has(this.userData, "tutore2.cellulare")){ 1930 if(typeof this.userData.tutore2.cellulare !== "string" || this.userData.tutore2.cellulare.length == 0 || 1931 ((/^[0-9]+$/.test(this.userData.tutore2.cellulare))==false ) 1932 ){ 1933 valid = false 1934 } 1935 }else{ 1936 valid = false; 1937 } 1938 1939 if(_.has(this.userData, "tutore2.email")){ 1940 if(typeof this.userData.tutore2.email !== "string" || this.userData.tutore2.email.length == 0){ 1941 valid = false 1942 }else{ 1943 if(this.userData.tutore2.email.indexOf("@")>0) { 1944// if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(this.userData.tutore2.email)) { 1945 } else { 1946 valid = false; 1947 } 1948 } 1949 }else{ 1950 valid = false; 1951 } 1952 1953 if(_.has(this.userData, "tutore2.telefono")){ 1954 if(typeof this.userData.tutore2.telefono !== "string" || this.userData.tutore2.telefono.length == 0 || 1955 ((/^[0-9]+$/.test(this.userData.tutore2.telefono))==false ) 1956 ){ 1957 valid = false 1958 } 1959 }else{ 1960 valid = false; 1961 } 1962 1963 //Studente 1964 if(_.has(this.userData, "firstName")){ 1965 if(typeof this.userData.firstName !== "string" || this.userData.firstName.length == 0){ 1966 valid = false 1967 } 1968 }else{ 1969 valid = false; 1970 } 1971 1972 if(_.has(this.userData, "lastName")){ 1973 if(typeof this.userData.lastName !== "string" || this.userData.lastName.length == 0){ 1974 valid = false 1975 } 1976 }else{ 1977 valid = false; 1978 } 1979 1980 if(_.has(this.userData, "birthPlace")){ 1981 if(typeof this.userData.birthPlace !== "string" || this.userData.birthPlace.length == 0){ 1982 valid = false 1983 } 1984 }else{ 1985 valid = false; 1986 } 1987 1988 if(_.has(this.userData, "birthday")){ 1989 if(typeof this.userData.birthday !== "string" || this.userData.birthday.length != 10 || ! this.dateFormat(this.userData.birthday) ){ 1990 valid = false 1991 } 1992 }else{ 1993 valid = false; 1994 } 1995 1996 if(_.has(this.userData, "gender")){ 1997 if(typeof this.userData.gender !== "string" || this.userData.gender.length == 0){ 1998 valid = false 1999 } 2000 }else{ 2001 valid = false; 2002 } 2003 2004 if(_.has(this.userData, "nazionalita")){ 2005 if(typeof this.userData.nazionalita !== "string" || this.userData.nazionalita.length == 0){ 2006 valid = false 2007 } 2008 }else{ 2009 valid = false; 2010 } 2011 2012 if(_.has(this.userData, "billingStreetAddress")){ 2013 if(typeof this.userData.billingStreetAddress !== "string" || this.userData.billingStreetAddress.length == 0){ 2014 valid = false 2015 } 2016 }else{ 2017 valid = false; 2018 } 2019 2020 if(_.has(this.userData, "billingCity")){ 2021 if(typeof this.userData.billingCity !== "string" || this.userData.billingCity.length == 0){ 2022 valid = false 2023 } 2024 }else{ 2025 valid = false; 2026 } 2027 2028 if(_.has(this.userData, "billingPostalCode")){ 2029 if(typeof this.userData.billingPostalCode !== "string" || this.userData.billingPostalCode.length == 0){ 2030 valid = false 2031 } 2032 }else{ 2033 valid = false; 2034 } 2035 2036 if(_.has(this.userData, "billingRegionCode")){ 2037 if(typeof this.userData.billingRegionCode !== "string" || this.userData.billingRegionCode.length == 0){ 2038 valid = false 2039 } 2040 }else{ 2041 valid = false; 2042 } 2043 2044 if(_.has(this.userData, "problemiSalute")){ 2045 if(typeof this.userData.problemiSalute !== "string" || this.userData.problemiSalute.length == 0){ 2046 valid = false 2047 } 2048 }else{ 2049 valid = false; 2050 } 2051 2052 if(_.has(this.userData, "tipoDocumento")){ 2053 if(typeof this.userData.tipoDocumento !== "string" || this.userData.tipoDocumento.length == 0){ 2054 valid = false 2055 } 2056 }else{ 2057 valid = false; 2058 } 2059 2060 if(_.has(this.userData, "numeroDocumento")){ 2061 if(typeof this.userData.numeroDocumento !== "string" || this.userData.numeroDocumento.length == 0){ 2062 valid = false 2063 } 2064 }else{ 2065 valid = false; 2066 } 2067 2068 if(_.has(this.userData, "cittadinanzaDocumento")){ 2069 if(typeof this.userData.cittadinanzaDocumento !== "string" || this.userData.cittadinanzaDocumento.length == 0){ 2070 valid = false 2071 } 2072 }else{ 2073 valid = false; 2074 } 2075 2076 if(_.has(this.userData, "enteRilascioDocumento")){ 2077 if(typeof this.userData.enteRilascioDocumento !== "string" || this.userData.enteRilascioDocumento.length == 0){ 2078 valid = false 2079 } 2080 }else{ 2081 valid = false; 2082 } 2083 2084 if(_.has(this.userData, "dataRilascioDocumento")){ 2085 if(typeof this.userData.dataRilascioDocumento !== "string" || this.userData.dataRilascioDocumento.length != 10 || ! this.dateFormat(this.userData.dataRilascioDocumento) ){ 2086 valid = false 2087 } 2088 }else{ 2089 valid = false; 2090 } 2091 2092 if(_.has(this.userData, "dataScadenzaDocumento")){ 2093 if(typeof this.userData.dataScadenzaDocumento !== "string" || this.userData.dataScadenzaDocumento.length != 10 || ! this.dateFormat(this.userData.dataScadenzaDocumento) ){ 2094 valid = false 2095 } 2096 }else{ 2097 valid = false; 2098 } 2099 2100 if(_.has(this.userData, "autorizzazioneFotoFiglio")){ 2101 if(typeof this.userData.autorizzazioneFotoFiglio !== "string" || this.userData.autorizzazioneFotoFiglio.length == 0){ 2102 valid = false 2103 } 2104 }else{ 2105 valid = false; 2106 } 2107 }else{ 2108 valid = false; 2109 } 2110 2111 return valid; 2112 } 2113 }, 2114 methods: { 2115 sum: function(num1, num2){ 2116 return Number(num1 + num2); 2117 }, 2118 openParentModal: function(id){ 2119 window.parent.$(id).modal("show"); 2120 }, 2121 sendRequestMessage: function() { 2122 var that=this; 2123 that.sendingMessageError=""; 2124 var portletNamespace="<@portlet.namespace />"; 2125 var requestInfo= { 2126 email: this.userMail, 2127 message: "", 2128 firstName:this.userData.firstName, 2129 lastName:this.userData.lastName, 2130 parameters: { 2131 firstName: this.userData.firstName, 2132 lastName: this.userData.lastName, 2133 phone: this.userData.phone, 2134 program:"", 2135 age: "", 2136 destination: "", 2137 startFrom: "", 2138 duration: "", 2139 fromPageName: "${docTitle?js_string}", 2140 fromPageUrl: window.top.location.href, 2141 }, 2142 token: "", 2143 component:"PreventivoProgrammi", 2144 emailParams: {} 2145 }; 2146 this.buildMessage(requestInfo); 2147 console.log("sendRequestMessage:",requestInfo); 2148 2149 function cb(status,msg) { 2150 console.log("cb:",status); 2151 if(status==true) { 2152 var nomeEvento="vacanza_studio"; 2153 console.log("sending event invio_preventivo", nomeEvento); 2154 that.addEvent('invio_preventivo',nomeEvento); 2155 that.gotoStep('next'); 2156 } 2157 else { 2158 that.sendingMessageError="error durante l'invio del preventivo"; 2159 } 2160 } 2161 oneInstanceSendRequest(requestInfo,cb); 2162 }, 2163 buildMessage: function (requestInfo) { 2164 2165 var that=this; 2166 var msg=""; 2167 var rowNomeScuola=""; 2168 var rowAcco=""; 2169 var rowAirport=""; 2170 var rowPackagePrice=""; 2171 var rowTotalPrice=""; 2172 var rowPackageDiscount=""; 2173 var rowsServices=[]; 2174 var szRowsServices=""; 2175 if(typeof this.selectedPackage=="undefined") { 2176 return; 2177 } 2178 console.log("build message"); 2179 var docTitle="${docTitle?js_string}"; 2180 if(typeof this.selectedPackage.nome_scuola!="undefined") { 2181 var dtStart=new Date(this.selectedPackage.startDate); 2182 var dtEnd=new Date(this.selectedPackage.endDate); 2183 var szStart=dtStart.getDate() +"-"+(dtStart.getMonth()+1)+"-"+dtStart.getFullYear(); 2184 var szEnd=dtEnd.getDate() +"-"+(dtEnd.getMonth()+1)+"-"+dtEnd.getFullYear(); 2185 rowNomeScuola="<h2>"+this.selectedPackage.nome_scuola +" dal " +szStart+ " al "+szEnd+"</h2>"; 2186 } 2187 if(typeof this.selectedAccomodation!="undefined" && this.selectedAccomodation.lodgingType!="undefined" && this.selectedAccomodation.price!="undefined" ) 2188 rowAcco="<tr>"+ "<td>"+this.selectedAccomodation.lodgingType+"</td>" + "<td style='text-align: right;'>"+this.formatPrice(this.selectedAccomodation.price+"")+"</td>"+"</tr>"; 2189 if(typeof this.selectedAirport!="undefined" && this.selectedAirport.airport!="undefined") { 2190 var airportPrice="0,00 €"; 2191 if(typeof this.selectedAirport.price!="undefined") 2192 airportPrice=this.formatPrice(this.packagePrice); 2193 rowAirport="<tr>"+ "<td>"+this.selectedAirport.airport+"</td>" + "<td style='text-align: right;'>"+airportPrice+"</td>"+"</tr>"; 2194 } 2195 if(typeof this.packagePrice!="undefined") 2196 rowPackagePrice="<tr>"+ "<td>Prezzo base</td>" + "<td style='text-align: right;'>"+this.formatPrice(this.packagePrice)+"</td>"+"</tr>"; 2197 if(typeof this.packageDiscount!="undefined" && this.packageDiscount!="" ) 2198 rowPackageDiscount="<tr>"+ "<td>Sconto applicato</td>" + "<td style='text-align: right;'>"+this.formatPrice(this.packageDiscount)+"</td>"+"</tr>"; 2199 if(typeof this.selectedServices!="undefined") { 2200 for(var i=0;i<this.selectedServices.length;i++) { 2201 var row="<tr>"+ "<td>"+this.selectedServices[i].service+"</td>" + "<td style='text-align: right;'>"+this.formatPrice(this.selectedServices[i].price)+"</td>"+"</tr>"; 2202 rowsServices.push(row); 2203 } 2204 } 2205 if(typeof this.totalPrice!="undefined") 2206 rowTotalPrice="<tr>"+ "<td style='text-align: right;'><strong>TOTALE PREVENTIVO</strong></td>" + "<td style='text-align: right;'><strong>"+this.formatPrice(this.totalPrice)+"</strong></td>"+"</tr>"; 2207 2208 for(var i=0;i<rowsServices.length;i++) { 2209 szRowsServices=szRowsServices+rowsServices[i]; 2210 } 2211 msg = "<h1>Preventivo</h1>"; 2212 msg = msg+ rowNomeScuola; 2213 msg=msg+ '<table>' + 2214 '<thead>' + 2215 '<tr>' + 2216 '<th scope="col">Servizio</th>' + 2217 '<th scope="col" style="text-align: right;">Prezzo</th>' + 2218 '</tr>' + 2219 '</thead>' + 2220 '<tbody>' + 2221 rowPackagePrice+ 2222 rowPackageDiscount+ 2223 rowAcco+ 2224 rowAirport + 2225 szRowsServices + 2226 '<tr style=""><td> </td><td> </td></tr>'+ 2227 rowTotalPrice + 2228 '</tbody>' + 2229 '</table>'; 2230 2231 2232 requestInfo.message="<p>"+requestInfo.message+"</p>"+"<p>"+msg+"</p>"; 2233 2234 requestInfo.message=requestInfo.message + "<p>" + "Ai sensi dell'art.13 del GDPR 679/16, vi informiamo che i dati utilizzati nel presente documento, da voi forniti, saranno utilizzati per le finalità di definizione del rapporto contrattuale in corso di negoziato. Per l'informativa completa si rinvia al sito <a href='https://www.iubenda.com/privacy-policy/20606989/legal'>www.zainettoverde.it</a>, alla sezione privacy"+ "</p>"; 2235 2236 }, 2237 formatPrice: function(price) { 2238 if(typeof price!="undefined" && price!="") { 2239 var formatter = new Intl.NumberFormat('it-IT', { 2240 style: 'currency', 2241 currency: 'EUR', 2242 }); 2243 return formatter.format(parseFloat(price)) ; 2244 } 2245 2246 }, 2247 formatServicePrice: function(service) { 2248 console.log("::"+service.price+"::"); 2249 if(typeof service !="undefined" && typeof service.price!="undefined" && service.price.trim()!="" && service.price.trim()!="undefined") { 2250 var formatter = new Intl.NumberFormat('it-IT', { 2251 style: 'currency', 2252 currency: 'EUR', 2253 }); 2254 return formatter.format(parseFloat(service.price.trim())) ; 2255 } 2256 else 2257 return ""; 2258 2259 2260 }, 2261 closeParentModal: function(id){ 2262 window.parent.$(id).modal("hide"); 2263 }, 2264 redirectParent: function(url){ 2265 window.top.location = "${themeDisplay.getPortalURL()}" + url; 2266 }, 2267 needsPermission: function(item){ 2268 if(item.marketingGroups.some(mg => mg.name == "accompagnatori")){ 2269 return true; 2270 }else{ 2271 return false; 2272 } 2273 }, 2274 gotoStep: function(step){ 2275 this.checkOrderAlreadyPresent(); 2276 if(typeof(step) == "number"){ 2277 this.currentStep = step; 2278 }else{ 2279 if(step == "next"){ 2280 this.currentStep++; 2281 } 2282 if(step == "prev"){ 2283 this.currentStep--; 2284 } 2285 } 2286 if(5 == this.currentStep){ 2287 oneInstanceRefreshCaptcha(); 2288 } 2289 2290 if(7 == this.currentStep){ 2291 setTimeout(function(){ 2292 $('#payment_step input').each(function(){ 2293 if ($(this).attr("id") != "allergie" && $(this).attr("id") != "inCameraCon") { 2294 if("" == $(this).val()) 2295 { 2296 $(this).css({"border":"2px solid red"}); 2297 } 2298 } 2299 }); 2300 }, 500); 2301 2302 setTimeout(function(){ 2303 $('#payment_step input[type=radio]').each(function(){ 2304 $(this).parent().find('.custom-control-label-text').css({ 2305 "color":"red" 2306 }); 2307 }); 2308 }, 500); 2309 2310 setTimeout(function(){ 2311 $('#payment_step select').each(function(){ 2312 $(this).css({"border":"2px solid red"}); 2313 }); 2314 }, 500); 2315 } 2316 2317 if(8 == this.currentStep){ 2318 setTimeout(function(){ 2319 $('#chose_payment input[type=radio]').each(function(){ 2320 $(this).parent().find('.custom-control-label-text').css({ 2321 "color":"red" 2322 }); 2323 }); 2324 }, 500); 2325 } 2326 2327 $('html, body').animate({ 2328 scrollTop: $("#pay").offset().top 2329 }, 0); 2330 }, 2331 getCity: function(fullString){ 2332 return fullString.substr(0, fullString.indexOf('(') === -1 ? fullString.length : fullString.indexOf('(')); 2333 }, 2334 isBefore: function(data){ 2335 return moment(data).isBefore(new Date()); 2336 }, 2337 isAfter: function(data){ 2338 return moment(data).isAfter(new Date()); 2339 }, 2340 getExternalData: function(message){ 2341 var strExtData = JSON.parse(JSON.stringify(message.data)); 2342 2343 if(strExtData.source == null){ 2344 var extData = JSON.parse(strExtData); 2345 console.log("dati ricevuti da iframe"); 2346 2347 if(extData.key == "packageId"){ 2348 if(_.isEmpty(this.selectedPackage)){ 2349 this.selectPackage(extData.data); 2350 2351 this.calendar.periodoSelected.start = moment(this.selectedPackage?.startDate).format("DD MMMM YYYY"); 2352 this.calendar.periodoSelected.end = moment(this.selectedPackage?.endDate).format("DD MMMM YYYY"); 2353 //this.currentStep = 2; 2354 2355 console.log("selected packageIndex: " + extData.data); 2356 }else{ 2357 if(this.selectedPackage._id.$oid != extData.data){ 2358 console.log("Getting other package"); 2359 2360 this.selectPackage(extData.data); 2361 }else{ 2362 console.log("Package already selected"); 2363 } 2364 } 2365 } 2366 } 2367 }, 2368 setAttachments: function(){ 2369 <#list allegati as allegato> 2370 <#assign stringSelector = "dynamic-element[@name='testo']/dynamic-content[@language-id = '" + themeDisplay.getLocale() + "']"> 2371 <#assign xPathSelector = saxReaderUtil.createXPath(stringSelector)> 2372 <#if xPathSelector.selectSingleNode(allegato)??> 2373 <#assign text = xPathSelector.selectSingleNode(allegato).getData()> 2374 </#if> 2375 2376 <#assign stringSelector = "dynamic-element[@name='mandatory']/dynamic-content[@language-id = '" + themeDisplay.getLocale() + "']"> 2377 <#assign xPathSelector = saxReaderUtil.createXPath(stringSelector)> 2378 <#if xPathSelector.selectSingleNode(allegato)??> 2379 <#assign mandatory = xPathSelector.selectSingleNode(allegato).getData()> 2380 </#if> 2381 2382 <#assign stringSelector = "dynamic-element[@name='documento']/dynamic-content[@language-id = '" + themeDisplay.getLocale() + "']"> 2383 <#assign xPathSelector = saxReaderUtil.createXPath(stringSelector)> 2384 <#if xPathSelector.selectSingleNode(allegato)??> 2385 <#assign document = jsonFactoryUtil.createJSONObject(xPathSelector.selectSingleNode(allegato).getData())> 2386 </#if> 2387 2388 var newAttachment = { 2389 title: "${text}", 2390 mandatory: ${mandatory}, 2391 fileName: "${document.getString('title')}", 2392 file: "${'/documents/' + document.getString('groupId') + '/0/' + document.getString('title') + '/' + document.getString('uuid')}", 2393 downloaded: false 2394 } 2395 2396 this.attachments.push(newAttachment); 2397 </#list> 2398 }, 2399 downloadAttachment: function(attachment){ 2400 var that = this, 2401 config = { 2402 headers: { 2403 "Access-Control-Allow-Origin": "*" 2404 }, 2405 responseType: "blob" 2406 }; 2407 2408 axios.get(attachment.file, config).then(function(res){ 2409 var downLink = window.URL.createObjectURL(new Blob([res.data])); 2410 var link = document.createElement("a"); 2411 link.href = downLink; 2412 link.setAttribute("download", attachment.fileName); 2413 document.body.appendChild(link); 2414 link.click(); 2415 that.attachments.find(att => att.fileName == attachment.fileName).downloaded = true; 2416 }).catch(function(err){ 2417 console.error("Error getting attachment: ", err); 2418 }); 2419 2420 setTimeout(function(){ 2421 $('#field_att input[type=checkbox]').not(':disabled').each(function(){ 2422 $(this).parent().find('.custom-control-label-text').attr('style','color:red'); 2423 }); 2424 }, 5000); 2425 2426 2427 if($('.fa-download').length == 0){ 2428 $('#info_accept').attr('style','color:#000 !important'); 2429 } 2430 }, 2431 getOrderStatus: function(){ 2432 var that = this; 2433 2434 if(this.signedIn){ 2435 const mongoQry = { 2436 "userId": this.userId, 2437 "orderParameters.selectedPackage.itemId": this.contentId 2438 } 2439 2440 var curId = this.contentId; 2441 Liferay.Service( 2442 '/destinazione.order/get-orders-by-user-id', 2443 { 2444 groupId: this.groupId, 2445 userId: this.userId 2446 }, 2447 function (res) { 2448 if (res.success) { 2449 2450 if (res.data?.length > 0) { 2451 that.sameUserOrders=res.data; 2452 } 2453 } 2454 else 2455 console.log("UNSUCCESS"); 2456 } 2457 ); 2458 2459 } 2460 }, 2461 checkOrderAlreadyPresent: function(){ 2462 this.orderAlreadyPresent=false; 2463 console.log("checkOrderAlreadyPresent"); 2464 if (this.sameUserOrders?.length > 0) { 2465 let i = 0; 2466 while (i < this.sameUserOrders?.length) { 2467 if (this.sameUserOrders[i].itemId == this.contentId) 2468 { 2469 if (this.sameUserOrders[i].orderStatus == "INSERTED" || this.sameUserOrders[i].orderStatus == "PAYED") 2470 { 2471 if(this.sameUserOrders[i].orderParameters.userData.lastName==this.userData.lastName && 2472 this.sameUserOrders[i].orderParameters.userData.firstName==this.userData.firstName && 2473 this.sameUserOrders[i].orderParameters.selectedPackage.startDate ==this.selectedPackage.startDate) { 2474 console.log("order already present is true"); 2475 this.orderAlreadyPresent=true; 2476 return true; 2477 } 2478 } 2479 } 2480 i++; 2481 } 2482 } 2483 return false; 2484 }, 2485 getUserData: function(){ 2486 var that = this; 2487 2488 Liferay.Service("/destinazione.d40user/get-user-data", { 2489 groupId: this.groupId, 2490 userId: this.userId 2491 }, function(res){ 2492 console.log("Get user data: ", res); 2493 2494 if(res.success){ 2495 that.userData = { 2496 tutore: {}, 2497 tutore2: {}, 2498 ...res.data 2499 }; 2500 that.getCountryList(); 2501 }else{ 2502 console.log("Error getting user data"); 2503 } 2504 }).catch(function(err){ 2505 console.error("Error getting userData: ", err); 2506 }); 2507 }, 2508 getCountryList: function(){ 2509 var that = this; 2510 2511 Liferay.Service("/destinazione.d40user/get-country-list", { 2512 language: this.defaultLanguage 2513 }, function(res){ 2514 console.log("Get country list: ", res); 2515 2516 if(res.success){ 2517 that.countryList = res.data; 2518 2519 if(that.userData.billingCountryId == "0" || that.userData.billingCountryId == null){ 2520 that.userData.billingCountryId = that.countryList.find(country => country.ID === that.defaultCountryId).ID; 2521 }else{ 2522 that.userData.billingCountryId = that.defaultCountryId; 2523 } 2524 2525 that.getRegionList(); 2526 } 2527 }).catch(function(err){ 2528 console.error("Error getting countryList: ", err); 2529 }); 2530 }, 2531 getRegionList: function(){ 2532 var that = this, 2533 idToUse = this.defaultCountryId; 2534 2535 if(this.userData.hasOwnProperty("billingCountryId") && typeof this.userData["billingCountryId"] === "string" && this.userData["billingCountryId"].length){ 2536 idToUse = this.userData.billingCountryId; 2537 } 2538 2539 Liferay.Service("/destinazione.d40user/get-region-list", { 2540 countryId: idToUse 2541 }, function(res){ 2542 console.log("Get region list: ", res); 2543 2544 if(res.success){ 2545 that.regionList = res.data; 2546 2547 if(that.userData.billingRegionId == "0" || that.userData.billingRegionId == null){ 2548 2549 } 2550 } 2551 }).catch(function(err){ 2552 console.error("Error getting regionList: ", err); 2553 }); 2554 }, 2555 getPackages: function(){ 2556 var that = this, 2557 tempPackages = [], 2558 packagesObj = ${jsonFactoryUtil.looseSerialize(packages)}; 2559 2560 packagesObj.data.items.forEach(function(pacchetto){ 2561 pacchetto.airportsAndPrices = JSON.parse(pacchetto.airportsAndPrices); 2562 pacchetto.lodgingTypesAndPrices = JSON.parse(pacchetto.lodgingTypesAndPrices.replace(/lodgingPrice/g, "price")); 2563 pacchetto.servicesAndPrices = JSON.parse(pacchetto.servicesAndPrices); 2564 2565 pType = pacchetto.paymentType; 2566 pacchetto.paymentType = []; 2567 2568 if (JSON.parse(pType) instanceof Array) { 2569 console.log("paymentType: array"); 2570 2571 var types = JSON.parse(pType); 2572 var acconto=0; 2573 types.forEach(function(type){ 2574 if(typeof type === 'object'){ 2575 var newPaymentType = { 2576 "type": type.type, 2577 "amount": Number(type.amount) 2578 } 2579 if(type.type=="cartaCreditoAcconto") 2580 acconto= Number(type.amount); 2581 }else{ 2582 console.log(typeof type); 2583 2584 var newPaymentType = { 2585 "type": type, 2586 "amount": 0 2587 } 2588 } 2589 2590 pacchetto.paymentType.push(newPaymentType); 2591 }); 2592 /* correggo un errore di backoffice, se acconto è zero metto come acconto quello di credit card */ 2593 for(var i =0;i<pacchetto.paymentType.length;i++) { 2594 var payment=pacchetto.paymentType[i]; 2595 if(payment.amount==0) 2596 payment.amount=acconto; 2597 } 2598 console.log("tipo di pagamento corretto",pacchetto.paymentType); 2599 2600 } else { 2601 var types = { 2602 "type": JSON.parse(pType), 2603 "amount": 0 2604 } 2605 2606 pacchetto.paymentType = types; 2607 } 2608 2609 pacchetto.purchaseBeforeDiscount = JSON.parse(pacchetto.purchaseBeforeDiscount); 2610 pacchetto.endDate = moment(pacchetto?.startDate).add(pacchetto.numNights, "days").toDate(); 2611 pacchetto.show = true; 2612 2613 if(pacchetto?.startDate.indexOf("2030-")<0) 2614 tempPackages.push(pacchetto); 2615 }); 2616 2617 tempPackages.sort(function(a, b){ 2618 return new Date(a?.startDate) - new Date(b?.startDate); 2619 }); 2620 2621 this.packages = tempPackages; 2622 }, 2623 2624 resetSelections: function(){ 2625 this.selectedAccomodation = {}; 2626 this.selectedAirport = {}; 2627 this.selectedPayment = {}; 2628 this.selectedBalance = {}; 2629 this.selectedServices = []; 2630 this.paymentLink = "#"; 2631 this.voucher = ""; 2632 this.packagePrice = 0; 2633 this.currentStep = 1; 2634 }, 2635 selectPackage: function(packageId){ 2636 var that = this; 2637 this.resetSelections(); 2638 console.log("select package with id " + packageId); 2639<#-- added adriano 2640 2641 if(typeof this.selectedPackage!== "undefined" && typeof this.selectedPackage._id!="undefined" && packageId!=this.selectedPackage._id.$oid) { 2642 this.selectedAirport={}; 2643 2644 } 2645fine added adriano --> 2646 2647 this.selectedPackage = this.packages.find(function(package){ 2648 return package._id.$oid == packageId 2649 }); 2650 2651 this.packagePrice = this.selectedPackage.basePrice; 2652 this.packageDiscount = 0; 2653 2654 this.selectedPackage.purchaseBeforeDiscount.forEach(function(sconto){ 2655 if(that.isDiscountValid(sconto) && sconto.discount != 0){ 2656 that.packageDiscount = Number(sconto.discount); 2657 } 2658 }); 2659 2660 this.setMandatoryServices(); 2661 }, 2662 select: function(name, obj){ 2663 if(name == "airport"){ 2664 this.selectedAirport = obj; 2665 } 2666 if(name == "accomodation"){ 2667 this.selectedAccomodation = obj; 2668 } 2669 }, 2670 checkFavourite: function(){ 2671 var that = this; 2672 2673 Liferay.Service('/destinazione.favorite/get-wish-list', { 2674 groupId: Liferay.ThemeDisplay.getScopeGroupId(), 2675 sessionId: String(Liferay.ThemeDisplay.getSessionId()), 2676 userId: String(Liferay.ThemeDisplay.getUserId()), 2677 }, function(res){ 2678 console.log("getWishList response: ", res); 2679 if(res.success){ 2680 res.data.forEach(function(obj){ 2681 if(obj.itemId == that.contentId){ 2682 that.favourite = true; 2683 that.oid = obj._id.$oid; 2684 } 2685 }); 2686 } 2687 }).catch(function(err){ 2688 console.error("Error getting wishlist: ", err); 2689 }); 2690 }, 2691 checkVoucher: function(){ 2692 var that = this, 2693 endPoint = "/servicefeed?p_p_id=Configurable&p_p_lifecycle=2&p_p_resource_id=json&_Configurable_jsonParams=", 2694 params = { 2695 "fn": "validate", 2696 "email": this.userMail, 2697 "articleId": this.contentId, 2698 "nomeTariffa": this.selectedPackage.title, 2699 "vc": this.voucher, 2700 "packageId": this.selectedPackage._id.$oid, 2701 "amount": this.totalPrice * 100 2702 } 2703 2704 axios.get(endPoint + JSON.stringify(params)).then(function(res){ 2705 if(res.data.result.data.valid && res.data.result.data.order.total_discount_amount){ 2706 console.log("Voucher res: ", res.data.result.data); 2707 that.voucherValid = true; 2708 that.voucherDiscount = res.data.result.data.order.total_discount_amount / 100; 2709 }else{ 2710 console.error("Something went wrong with voucher: ", res.data); 2711 alert("Voucher non valido"); 2712 } 2713 }).catch(function(err){ 2714 console.error("Error validating voucher: ", err); 2715 }); 2716 }, 2717 createOrderAndPaymentUrl: function(){ 2718 var that = this; 2719 2720 // this.addEvent("stampa_preventivo"); 2721 2722 var orderPrice = 0, 2723 orderParams = { 2724 selectedPackage: this.selectedPackage, 2725 selectedAccomodation: this.selectedAccomodation, 2726 selectedAirport: this.selectedAirport, 2727 selectedServices: this.selectedServices, 2728 selectedPayment: this.selectedPayment, 2729 selectedBalance: this.selectedBalance, 2730 packagePrice: this.packagePrice, 2731 packageDiscount: this.packageDiscount, 2732 totalPrice: this.totalPrice, 2733 voucherDiscount: this.voucherDiscount, 2734 userData: this.userData, 2735 policy:this.policy, 2736 doppioCheck:this.doppiocheck 2737 }; 2738 2739 if(this.selectedPayment.amount == 0 || this.selectedPayment.amount === undefined){ 2740 orderPrice = this.totalPrice; 2741 }else{ 2742 orderPrice = this.selectedPayment.amount; 2743 } 2744 2745 console.log("orderPrice is " + orderPrice); 2746 2747 if(this.selectedPayment.type != "bonifico" && this.selectedPayment.type != "rateale" && this.selectedPayment.type != "rateale-zv"){ 2748 var iframe = window.open("/", "_blank"); 2749 } 2750 2751 Liferay.Service("/destinazione.order/add-order-and-get-payment-url", { 2752 groupId: this.groupId, 2753 userId: this.userId, 2754 itemGroupId: Liferay.ThemeDisplay.getScopeGroupId(), 2755 itemId: this.contentId, 2756 totalPrice: this.totalPrice, 2757 params: JSON.stringify(orderParams), 2758 currency: "EUR", 2759 priceToPay: orderPrice, 2760 userEmail: this.userMail, 2761 languageId: "ITA", 2762 description: this.name, 2763 session_id: String(Liferay.ThemeDisplay.getSessionId()), 2764 cart_id: "12", 2765 baseUrl: Liferay.ThemeDisplay.getURLHome().split("/web/")[0], 2766 locsz: "" 2767 }, function(res){ 2768 console.log("Create order and payment url res: ", res); 2769 2770 // Sezione redemption voucher 2771 if(that.voucherValid){ 2772 var endPoint = "/servicefeed?p_p_id=Configurable&p_p_lifecycle=2&p_p_resource_id=json&_Configurable_jsonParams=", 2773 params = { 2774 "fn": "redemption", 2775 "email": that.userMail, 2776 "articleId": that.contentId, 2777 "nomeTariffa": that.selectedPackage.title, 2778 "vc": that.voucher, 2779 "packageId": that.selectedPackage._id.$oid, 2780 "amount": that.totalPrice * 100 2781 } 2782 2783 axios.get(endPoint + JSON.stringify(params)).then(function(vRes){ 2784 console.log("vRes is ", vRes); 2785 }).catch(function(vErr){ 2786 console.error("Error during voucher redemption: ", vErr); 2787 }); 2788 } 2789 2790 if(res.success){ 2791 that.addEvent("stampa_preventivo",""); 2792 2793 if(that.selectedPayment.type != "bonifico" && that.selectedPayment.type != "rateale" && that.selectedPayment.type != "rateale-zv"){ 2794 console.log("redirecting..."); 2795 iframe.location = res.data.url; 2796 that.closeParentModal("#pay-modal"); 2797 }else{ 2798 that.currentStep++; 2799 console.log("ordine immesso con bonifico, non ridireziono l'utente"); 2800 } 2801 2802 that.orderResult = "Ordine inserito con successo"; 2803 }else{ 2804 that.orderResult = "C'è stato un problema con l'inserimento dell'ordine. Contattare Zainetto Verde se il problema persiste."; 2805 } 2806 }).catch(function(err){ 2807 console.error("Error: ", err); 2808 2809 that.orderResult = "C'è stato un problema con l'inserimento dell'ordine. Contattare Zainetto Verde se il problema persiste."; 2810 }); 2811 }, 2812 setFavourite: function(){ 2813 var that = this; 2814 2815 if(this.signedIn){ 2816 Liferay.Service('/destinazione.favorite/add-to-wish-list', { 2817 groupId: Liferay.ThemeDisplay.getScopeGroupId(), 2818 sessionId: String(Liferay.ThemeDisplay.getSessionId()), 2819 userId: String(Liferay.ThemeDisplay.getUserId()), 2820 itemGroupId: 11, 2821 itemId: this.contentId 2822 }, function(res){ 2823 if(res.success){ 2824 console.log("addToWishList response: ", res); 2825 that.favourite = true; 2826 } 2827 }).catch(function(err){ 2828 console.error("Error adding to wishlist: ", err); 2829 }); 2830 }else{ 2831 this.redirect("login?contentId=${contentId}"); 2832 } 2833 }, 2834 removeFavourite: function(){ 2835 var that = this; 2836 2837 Liferay.Service('/destinazione.favorite/delete-item-from-wish-list', { 2838 oid: this.oid 2839 }, function(res) { 2840 console.log("deleteFromWishList response: ", res); 2841 that.favourite = false; 2842 that.checkFavourite(); 2843 }).catch(function(err){ 2844 console.error("Error removing from wishlist: ", err); 2845 }); 2846 }, 2847 saveData: function(){ 2848 console.log("todo save data"); 2849 }, 2850 getPaymentLabel: function(type){ 2851 if(type == "bonifico") 2852 return "Acconto con bonifico bancario"; 2853 if(type == "cartaCredito") 2854 return "Carta di credito"; 2855 if(type == "cartaCreditoAcconto") 2856 return "Acconto con carta di credito"; 2857 }, 2858 setCustomStyle: function(){ 2859 var that = this, 2860 style = document.createElement('style'); 2861 2862 style.type = 'text/css'; 2863 2864 this.packages.forEach(function(package, index){ 2865 if(index > 0){ 2866 if(moment(package?.startDate).isSame(that.packages[index-1]?.endDate)){ 2867 console.log("la data " + package?.startDate + " combacia"); 2868 2869 var dateClass = ".id-" + moment(package?.startDate).format("YYYY-MM-DD"); 2870 style.innerHTML += dateClass + ' .vc-highlights .vc-day-layer { box-shadow: none !important; }'; 2871 } 2872 } 2873 }); 2874 2875 if(style.innerHTML != ""){ 2876 document.getElementsByTagName('head')[0].appendChild(style); 2877 console.log("custom style for calendar injected"); 2878 } 2879 }, 2880 initCalendar: function(){ 2881 var that = this; 2882 this.calendar.dataInizio = moment(this.packages[0]?.startDate).toDate(); 2883 this.calendar.initialPage.month = moment(this.calendar.dataInizio).month() + 1; 2884 this.calendar.initialPage.year = moment(this.calendar.dataInizio).year(); 2885 this.calendar.dataFine = moment(this.packages[this.packages.length - 1]?.endDate).toDate(); 2886 2887 this.packages.forEach(function(package, index){ 2888 var periodo = { 2889 key: package.itemId + "_" + index, 2890 highlight: true, 2891 dates: [{ 2892 "start": moment(package?.startDate).toDate(), 2893 "end": moment(package?.endDate).toDate() 2894 }], 2895 order: index 2896 }; 2897 2898 that.calendar.attributes.push(periodo); 2899 }); 2900 2901 this.setCustomStyle(); 2902 }, 2903 selectDate: function(value){ 2904 var that = this; 2905 2906 console.log("Data scelta: ", value) 2907 this.calendar.dataSelected = value.date; 2908 2909 this.packages.forEach(function(package){ 2910 if(moment(value.date).isBetween(package?.startDate, package?.endDate)){ 2911 console.log(value.date + " è compresa"); 2912 package.show = true; 2913 } 2914 }); 2915 }, 2916 resetDates: function(){ 2917 this.calendar.dataSelected = null; 2918 this.packages.forEach(function(package){ 2919 package.show = true; 2920 }); 2921 }, 2922 showResults: function(data){ 2923 var that = this; 2924 2925 this.packages.forEach(function(package){ 2926 package.show = false; 2927 2928 if(moment(data).isBetween(package?.startDate, package?.endDate)){ 2929 console.log(data + " è compresa"); 2930 package.show = true; 2931 } 2932 }); 2933 }, 2934 setMandatoryServices: function(){ 2935 var that = this; 2936 2937 this.selectedServices = []; 2938 2939 this.selectedPackage.servicesAndPrices.forEach(function(service){ 2940 if(service.mandatory){ 2941 that.selectedServices.push(service); 2942 } 2943 }); 2944 }, 2945 setProgressData: function(){ 2946 localStorage.removeItem("progressData"); 2947 console.log("removed old progress data"); 2948 2949 var progressData = { 2950 url: window.top.location.href, 2951 selectedAccomodation: this.selectedAccomodation, 2952 selectedAirport: this.selectedAirport, 2953 selectedPackage: this.selectedPackage, 2954 selectedPayment: this.selectedPayment, 2955 selectedBalance: this.selectedBalance, 2956 selectedServices: this.selectedServices, 2957 packagePrice: this.packagePrice, 2958 packageDiscount: this.packageDiscount, 2959 totalPrice:this.totalPrice, 2960 userData: this.userData, 2961 userMail: this.userMail 2962 2963 } 2964 2965 localStorage.setItem("progressData", JSON.stringify(progressData)); 2966 console.log("progressData saved"); 2967 }, 2968 getProgressData: function(){ 2969 if(localStorage.getItem("progressData") !== null){ 2970 console.log("previous data exists, getting it"); 2971 2972 if(JSON.parse(localStorage.getItem("progressData")).url == window.top.location.href){ 2973 console.log("previous data is form actual page, restoring it..."); 2974 2975 var previousData = JSON.parse(localStorage.getItem("progressData")); 2976 2977 this.selectedAccomodation = previousData.selectedAccomodation; 2978 this.selectedAirport = previousData.selectedAirport; 2979 this.selectedPackage = previousData.selectedPackage; 2980 this.selectedPayment = previousData.selectedPayment; 2981 this.selectedBalance = previousData.selectedBalance; 2982 this.selectedServices = previousData.selectedServices; 2983 this.packagePrice = previousData.packagePrice; 2984 this.packageDiscount = previousData.packageDiscount; 2985 this.userData=previousData.userData; 2986 this.userMail=previousData.userMail; 2987 2988 console.log("previous data restored"); 2989 localStorage.removeItem("progressData"); 2990 2991 this.currentStep = 6; 2992 2993 this.openParentModal("#pay-modal"); 2994 }else{ 2995 console.log("ProgressData is from a different page"); 2996 } 2997 }else{ 2998 console.log("no previous data exists"); 2999 } 3000 }, 3001 isBefore: function(data){ 3002 return moment(data).isBefore(new Date()); 3003 }, 3004 isAfter: function(data){ 3005 return moment(data).isAfter(new Date()); 3006 }, 3007 isDiscountValid: function(sconto){ 3008 var today = new Date(), 3009 valid = false; 3010 3011 if(moment(today).isSameOrAfter(sconto.date) && moment(today).isSameOrBefore(sconto.dateEnd)){ 3012 valid = true; 3013 } 3014 3015 return valid; 3016 }, 3017 checkEmpty: function(e){ 3018 const element = e.target; 3019 if("" != element.value) 3020 { 3021 $('#'+element.id).css({"border":"1px solid #e7e7ed"}); 3022 }else{ 3023 $('#'+element.id).css({"border":"2px solid red"}); 3024 } 3025 }, 3026 dateFormat: function (szDate) { 3027 const pattern = /^\d{2}\/\d{2}\/\d{4}$/; 3028 return pattern.test(szDate); 3029 }, 3030 checkDateLength: function(e){ 3031 const element = e.target; 3032 if("" != element.value && element.value.length==10 && this.dateFormat(element.value) ) 3033 { 3034 $('#'+element.id).css({"border":"1px solid #e7e7ed"}); 3035 }else{ 3036 $('#'+element.id).css({"border":"2px solid red"}); 3037 } 3038 }, 3039 restrictDigitInput: function(e) { 3040 const element = e.target; 3041 const allowedCharacters = /[0-9]/; // Caratteri consentiti: numeri 3042 const stringValue=element.value; 3043 if(e.key=='Backspace' || e.key=='ArrowLeft' || e.key=='ArrowRight' || e.key=='Tab') 3044 return; 3045 if (!allowedCharacters.test(e.key)) { 3046 e.preventDefault(); 3047 return; 3048 } 3049 }, 3050 restrictDateInput: function(e) { 3051 const element = e.target; 3052 const allowedCharacters = /[0-9]/; // Caratteri consentiti: numeri 3053 const stringValue=element.value; 3054 if(e.key=='Backspace' || e.key=='ArrowLeft' || e.key=='ArrowRight' || e.key=='Tab') 3055 return; 3056 var curPos=e.target.selectionStart; 3057 switch( curPos ) { 3058 case 0: case 1: 3059 if (!allowedCharacters.test(e.key)) { 3060 e.preventDefault(); 3061 } 3062 break; 3063 case 2: 3064 if(e.key!="/") { 3065 e.preventDefault(); 3066 } 3067 break; 3068 case 3: case 4: 3069 if (!allowedCharacters.test(e.key)) { 3070 e.preventDefault(); 3071 } 3072 break; 3073 case 5: 3074 if(e.key!="/") 3075 e.preventDefault(); 3076 break; 3077 case 6: case 7: case 8: case 9: 3078 if (!allowedCharacters.test(e.key)) { 3079 e.preventDefault(); 3080 } 3081 break; 3082 3083 default: 3084 e.preventDefault(); 3085 } 3086 3087 }, 3088 checkSelect: function(e){ 3089 const element = e.target; 3090 if("" != element.value) 3091 { 3092 $('#'+element.id).css({"border":"1px solid #e7e7ed"}); 3093 }else{ 3094 $('#'+element.id).css({"border":"2px solid red"}); 3095 } 3096 }, 3097 checkEmail: function(e){ 3098 const mail_el = e.target; 3099 if("" != mail_el.value) 3100 { 3101 if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail_el.value)) { 3102 $('#'+mail_el.id).css({"border":"1px solid #e7e7ed"}); 3103 } else { 3104 $('#'+mail_el.id).css({"border":"2px solid red"}); 3105 } 3106 }else{ 3107 $('#'+mail_el.id).css({"border":"2px solid red"}); 3108 } 3109 }, 3110 checkTelefono: function(e) { 3111 const tel_el = e.target; 3112 if("" != tel_el.value) 3113 { 3114 if (/^[0-9]+$/.test(tel_el.value)) { 3115 $('#'+tel_el.id).css({"border":"1px solid #e7e7ed"}); 3116 } else { 3117 $('#'+tel_el.id).css({"border":"2px solid red"}); 3118 } 3119 }else{ 3120 $('#'+tel_el.id).css({"border":"2px solid red"}); 3121 } 3122 }, 3123 checkCodiceFiscale: function(e) { 3124 const cf_el = e.target; 3125 var cf= cf_el.value; 3126 if(""!= cf) { 3127 // se corretto ok, altrimenti border 3128 var ret=this.controllaCF(cf); 3129 console.log(ret); 3130 if(ret=="") { 3131 this.msgCodiceFiscale=ret; 3132 $('#'+cf_el.id).css({"border":"1px solid #e7e7ed"}); 3133 } 3134 else { 3135 this.msgCodiceFiscale=ret; 3136 $('#'+cf_el.id).css({"border":"2px solid red"}); 3137 3138 } 3139 } 3140 else{ 3141 this.msgCodiceFiscale="codice fiscale non valido"; 3142 $('#'+cf_el.id).css({"border":"2px solid red"}); 3143 } 3144 }, 3145 controllaCF: function (cf) { 3146 console.log(cf); 3147 var validi, i, s, set1, set2, setpari, setdisp; 3148 if (cf == '') return ''; 3149 cf = cf.toUpperCase(); 3150 if (cf.length != 16) 3151 return "La lunghezza del codice fiscale non è\n" 3152 + "corretta: il codice fiscale dovrebbe essere lungo\n" 3153 + "esattamente 16 caratteri.\n"; 3154 validi = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 3155 for (i = 0; i < 16; i++) { 3156 if (validi.indexOf(cf.charAt(i)) == -1) 3157 return "Il codice fiscale contiene un carattere non valido `" + 3158 cf.charAt(i) + 3159 "'.\nI caratteri validi sono le lettere e le cifre.\n"; 3160 } 3161 set1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 3162 set2 = "ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ"; 3163 setpari = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 3164 setdisp = "BAKPLCQDREVOSFTGUHMINJWZYX"; 3165 s = 0; 3166 for (i = 1; i <= 13; i += 2) 3167 s += setpari.indexOf(set2.charAt(set1.indexOf(cf.charAt(i)))); 3168 for (i = 0; i <= 14; i += 2) 3169 s += setdisp.indexOf(set2.charAt(set1.indexOf(cf.charAt(i)))); 3170 if (s % 26 != cf.charCodeAt(15) - 'A'.charCodeAt(0)) 3171 return "Il codice fiscale non è corretto:\n" + 3172 "il codice di controllo non corrisponde.\n"; 3173 return ""; 3174 }, 3175 checkRadio: function(radio_name){ 3176 console.log('blur radio'); 3177 if ($('input[name='+radio_name+']:checked').length > 0) { 3178 $('input[name='+radio_name+']').each(function(){ 3179 $(this).parent().find('.custom-control-label-text').css({ 3180 "color":"initial" 3181 }) 3182 }); 3183 }else{ 3184 $('input[name='+radio_name+']').each(function(){ 3185 $(this).parent().find('.custom-control-label-text').css({ 3186 "color":"red" 3187 }) 3188 }); 3189 } 3190 }, 3191 checkPolicy: function(e){ 3192 const check_el = e.target; 3193 console.log('test_change'); 3194 if ($('#'+check_el.id).is(':checked')){ 3195 $('#'+check_el.id).parent().find('.custom-control-label-text').attr('style','color:initial'); 3196 }else{ 3197 $('#'+check_el.id).parent().find('.custom-control-label-text').attr('style','color:red'); 3198 } 3199 }, 3200 checkRadioPayment: function(){ 3201 $('#chose_payment input[type=radio]').each(function(){ 3202 if($(this).is(':checked')){ 3203 $('#chose_payment input[type=radio]').each(function(){ 3204 $(this).parent().find('.custom-control-label-text').css({ 3205 "color":"initial" 3206 }) 3207 }); 3208 } 3209 }); 3210 }, 3211 addEvent: function(eventName,reqType){ 3212 window.dataLayer = window.parent.dataLayer || []; 3213 if(reqType != null && reqType!="") { 3214 dataLayer.push({ 3215 "event": eventName, 3216 "requestType": reqType 3217 }); 3218 } 3219 else { 3220 dataLayer.push({ 3221 "event": eventName 3222 }); 3223 3224 } 3225 } 3226 } 3227 }); 3228 3229 }); 3230</script> 3231 3232<#function getPackagesByItemId groupId itemGroupId itemId> 3233 <#return productServiceAPI.getAvailPackagesByItemId(groupId?number, itemGroupId?number, itemId, "", 0, 100)> 3234</#function> 3235 3236<#function getPrefix img width height> 3237 <#assign 3238 baseUrl = "https://d28r45jypu6nt9.cloudfront.net/o/d40/img/" 3239 siteUrl = themeDisplay.getURLPortal()?replace("://", ".") 3240 w = width 3241 h = height 3242 /> 3243 <#if height?is_string> 3244 <#assign prefix = baseUrl + "w_" + w + "/" + siteUrl> 3245 <#else> 3246 <#assign prefix = baseUrl + "w_" + w + ",h_" + h + "/" + siteUrl> 3247 </#if> 3248 3249 <#if !img?contains("/documents/")> 3250 <#assign prefix = ""> 3251 </#if> 3252 3253 <#return prefix + img> 3254</#function>