PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.2
VikBooking Hotel Booking Engine & PMS v1.7.2
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / controller.php

controller.php in VikBooking Hotel Booking Engine & PMS 1.7.2, at admin/controller.php

15,022 lines 564.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 // import Joomla controller library
14 jimport('joomla.application.component.controller');
15
16 class VikBookingController extends JControllerVikBooking
17 {
18 /**
19 * Default controller's method when no task is defined,
20 * or no method exists for that task. If a View is requested.
21 * attempts to set it, otherwise sets the default View.
22 */
23 public function display($cachable = false, $urlparams = array()) {
24
25 $view = VikRequest::getVar('view', '');
26 $header_val = '';
27
28 if (!empty($view)) {
29 $header_val = $view;
30 VikRequest::setVar('view', $view);
31 } else {
32 $header_val = '18';
33 VikRequest::setVar('view', 'dashboard');
34 }
35
36 $hide_menu = JFactory::getApplication()->input->getBool('hide_menu', false);
37
38 if ($hide_menu === false)
39 {
40 VikBookingHelper::printHeader($header_val);
41 }
42
43 parent::display();
44
45 if (VikBooking::showFooter() && $hide_menu === false) {
46 VikBookingHelper::printFooter();
47 }
48 }
49
50 /**
51 * AJAX request for building dynamic donut charts.
52 *
53 * @return void
54 *
55 * @since 1.12.1
56 */
57 public function donut_charts_data() {
58 $fromdt = VikRequest::getString('fromdt', date('Y-m-d'), 'request');
59 $direction = VikRequest::getString('direction', 'next', 'request');
60 $days = VikRequest::getInt('days', 7, 'request');
61 if (empty($fromdt) || !strtotime($fromdt) || empty($days) || $days < 1) {
62 throw new Exception('Missing required data', 400);
63 }
64
65 $from_info = getdate(strtotime($fromdt));
66 if ($direction != 'next') {
67 // fromdt is always the next day after the end of the loop, so the very first next day from the last displayed
68 $from_info = getdate(mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - ($days * 2)), $from_info['year']));
69 }
70 // always push the start date to the last second (23:59:59)
71 $from_info = getdate(mktime(23, 59, 59, $from_info['mon'], $from_info['mday'], $from_info['year']));
72
73 // months front-end language map
74 $monthsmap = array(
75 JText::translate('VBSHORTMONTHONE'),
76 JText::translate('VBSHORTMONTHTWO'),
77 JText::translate('VBSHORTMONTHTHREE'),
78 JText::translate('VBSHORTMONTHFOUR'),
79 JText::translate('VBSHORTMONTHFIVE'),
80 JText::translate('VBSHORTMONTHSIX'),
81 JText::translate('VBSHORTMONTHSEVEN'),
82 JText::translate('VBSHORTMONTHEIGHT'),
83 JText::translate('VBSHORTMONTHNINE'),
84 JText::translate('VBSHORTMONTHTEN'),
85 JText::translate('VBSHORTMONTHELEVEN'),
86 JText::translate('VBSHORTMONTHTWELVE'),
87 );
88
89 // weekdays front-end language map
90 $wdaysmap = array(
91 JText::translate('VBSUNDAY'),
92 JText::translate('VBMONDAY'),
93 JText::translate('VBTUESDAY'),
94 JText::translate('VBWEDNESDAY'),
95 JText::translate('VBTHURSDAY'),
96 JText::translate('VBFRIDAY'),
97 JText::translate('VBSATURDAY'),
98 );
99
100 // gather information about the rooms and availability
101 $dbo = JFactory::getDbo();
102 $all_rooms_ids = array();
103 $unpublished_rooms = array();
104 $todayymd = date('Y-m-d');
105 $q = "SELECT `id`,`name`,`units`,`params`,`avail` FROM `#__vikbooking_rooms`;";
106 $dbo->setQuery($q);
107 $dbo->execute();
108 if ($dbo->getNumRows()) {
109 $all_rooms = $dbo->loadAssocList();
110 foreach ($all_rooms as $k => $r) {
111 if ($r['avail'] < 1) {
112 $unpublished_rooms[] = $r['id'];
113 }
114 $all_rooms_ids[$r['id']] = $r['name'];
115 }
116 }
117 $q = "SELECT SUM(`units`) FROM `#__vikbooking_rooms` WHERE `avail`=1;";
118 $dbo->setQuery($q);
119 $dbo->execute();
120 $tot_rooms_units = (int)$dbo->loadResult();
121
122 // load busy records
123 $expected_max_ts = mktime(23, 59, 59, $from_info['mon'], ($from_info['mday'] + $days), $from_info['year']);
124 $busy = VikBooking::loadBusyRecordsUnclosed(array_keys($all_rooms_ids), $from_info[0], $expected_max_ts);
125
126 // response body
127 $response = new stdClass;
128 $response->prevweek = ($todayymd != date('Y-m-d', $from_info[0]));
129 $response->nextweek = true;
130 $response->fromd = date('Y-m-d', $from_info[0]);
131 $response->tot_units = $tot_rooms_units;
132 $response->data = array();
133
134 for ($i = 0; $i < $days; $i++) {
135 $tot_booked_today = 0;
136 $today_ts = $from_info[0];
137 $data_obj = new stdClass;
138 $data_obj->ymd = date('Y-m-d', $from_info[0]);
139 $data_obj->lbl = $wdaysmap[(int)$from_info['wday']] . ', ' . $from_info['mday'];
140 $data_obj->lbl = $data_obj->ymd == $todayymd ? JText::translate('VBTODAY') . ', ' . $data_obj->lbl : $data_obj->lbl . ' ' . $monthsmap[($from_info['mon'] - 1)];
141 foreach ($busy as $idroom => $rbusy) {
142 if (in_array($idroom, $unpublished_rooms)) {
143 continue;
144 }
145 foreach ($rbusy as $b) {
146 $tmpone = getdate($b['checkin']);
147 $ritts = mktime(0, 0, 0, $tmpone['mon'], $tmpone['mday'], $tmpone['year']);
148 $tmptwo = getdate($b['checkout']);
149 $conts = mktime(0, 0, 0, $tmptwo['mon'], $tmptwo['mday'], $tmptwo['year']);
150 if ($today_ts >= $ritts && $today_ts < $conts) {
151 $tot_booked_today++;
152 }
153 }
154 }
155
156 $data_obj->tot_booked = $tot_booked_today;
157 $percentage_booked = round((100 * $tot_booked_today / $tot_rooms_units), 2);
158
159 $data_obj->color = '#ff4d4d'; //red
160 if ($percentage_booked > 33 && $percentage_booked <= 66) {
161 $data_obj->color = '#ffa64d'; //orange
162 } elseif ($percentage_booked > 66 && $percentage_booked < 100) {
163 $data_obj->color = '#2a762c'; //green
164 } elseif ($percentage_booked >= 100) {
165 $data_obj->color = '#2482b4'; //light-blue
166 }
167
168 // push today's data
169 array_push($response->data, $data_obj);
170
171 // next day
172 $from_info = getdate(mktime(23, 59, 59, $from_info['mon'], ($from_info['mday'] + 1), $from_info['year']));
173 }
174
175 // update last date (not displayed/included)
176 $response->tod = date('Y-m-d', $from_info[0]);
177
178 echo json_encode($response);
179 exit;
180 }
181
182 /**
183 * AJAX request for adding a new fest.
184 *
185 * @return void
186 *
187 * @since 1.2.0
188 */
189 public function add_fest() {
190 $dt = VikRequest::getString('dt', '', 'request');
191 $type = VikRequest::getString('type', '', 'request');
192 $type = empty($type) ? 'custom' : $type;
193 $name = VikRequest::getString('name', '', 'request');
194 $descr = VikRequest::getString('descr', '', 'request');
195 if (empty($name) || empty($dt) || !strtotime($dt)) {
196 echo 'e4j.error.1';
197 exit;
198 }
199 // build fest array
200 $new_fest = array(
201 'trans_name' => $name
202 );
203
204 $fests = VikBooking::getFestivitiesInstance();
205 $result = $fests->storeFestivity($dt, $new_fest, $type, $descr);
206 if (!$result) {
207 echo 'e4j.error.2';
208 exit;
209 }
210
211 // reload all festivities for this day for the AJAX response
212 $all_fests = $fests->loadFestDates($dt, $dt);
213 foreach ($all_fests as $k => $v) {
214 // we expect just one record to be returned due to the from/to date limit passed to loadFestDates()
215 echo json_encode($v);
216 exit;
217 }
218
219 // no fests found even after storing it
220 echo 'e4j.error.3';
221 exit;
222 }
223
224 /**
225 * AJAX request for removing a fest.
226 *
227 * @return void
228 *
229 * @since 1.2.0
230 */
231 public function remove_fest()
232 {
233 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
234 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
235 }
236
237 $dt = VikRequest::getString('dt', '', 'request');
238 $ind = VikRequest::getInt('ind', 0, 'request');
239 $type = VikRequest::getString('type', '', 'request');
240 $type = empty($type) ? 'custom' : $type;
241 if (empty($dt) || !strtotime($dt)) {
242 echo 'e4j.error.1';
243 exit;
244 }
245
246 $fests = VikBooking::getFestivitiesInstance();
247 $result = $fests->deleteFestivity($dt, $ind, $type);
248 if (!$result) {
249 echo 'e4j.error.2';
250 exit;
251 }
252
253 echo 'e4j.ok';
254 exit;
255 }
256
257 public function einvoicing() {
258 VikBookingHelper::printHeader("einvoicing");
259
260 VikRequest::setVar('view', VikRequest::getCmd('view', 'einvoicing'));
261
262 parent::display();
263
264 if (VikBooking::showFooter()) {
265 VikBookingHelper::printFooter();
266 }
267 }
268
269 public function pmsreports() {
270 VikBookingHelper::printHeader("pmsreports");
271
272 VikRequest::setVar('view', VikRequest::getCmd('view', 'pmsreports'));
273
274 parent::display();
275
276 if (VikBooking::showFooter()) {
277 VikBookingHelper::printFooter();
278 }
279 }
280
281 public function ratesoverv() {
282 VikBookingHelper::printHeader("20");
283
284 VikRequest::setVar('view', VikRequest::getCmd('view', 'ratesoverv'));
285
286 parent::display();
287
288 if (VikBooking::showFooter()) {
289 VikBookingHelper::printFooter();
290 }
291 }
292
293 public function stats() {
294 VikBookingHelper::printHeader("stats");
295
296 VikRequest::setVar('view', VikRequest::getCmd('view', 'stats'));
297
298 parent::display();
299
300 if (VikBooking::showFooter()) {
301 VikBookingHelper::printFooter();
302 }
303 }
304
305 /**
306 * AJAX endpoint to calculate the website rates.
307 *
308 * @return void
309 */
310 public function calc_rates()
311 {
312 $response = 'e4j.error.ErrorCode(1) Server is blocking the self-request';
313 $response_code = 0;
314
315 // availability helper
316 $av_helper = VikBooking::getAvailabilityInstance();
317
318 $currencysymb = VikBooking::getCurrencySymb();
319 $vbo_df = VikBooking::getDateFormat();
320 $df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
321 $id_room = VikRequest::getInt('id_room', '', 'request');
322 $checkin = VikRequest::getString('checkin', '', 'request');
323 $nights = VikRequest::getInt('num_nights', 1, 'request');
324 $adults = VikRequest::getInt('num_adults', 0, 'request');
325 $children = VikRequest::getInt('num_children', 0, 'request');
326 /**
327 * The page Calendar may call this task via AJAX to obtain information
328 * about the various rate plans and final costs associated.
329 *
330 * @since 1.13 (J) - 1.3.0 (WP)
331 */
332 $only_rates = VikRequest::getInt('only_rates', 0, 'request');
333 $units = VikRequest::getInt('units', 1, 'request');
334 $checkinfdate = VikRequest::getString('checkinfdate', '', 'request');
335 $checkoutfdate = VikRequest::getString('checkoutfdate', '', 'request');
336 if (!empty($checkinfdate) && empty($checkin)) {
337 $checkin = date('Y-m-d', VikBooking::getDateTimestamp($checkinfdate, 0, 0, 0));
338 }
339
340 $checkin_ts = strtotime($checkin);
341 if (empty($checkin_ts)) {
342 $checkin = date('Y-m-d');
343 $checkin_ts = strtotime($checkin);
344 }
345
346 if (!empty($checkoutfdate) && !empty($checkinfdate) && $nights < 2) {
347 // checkout date was given rather than number of nights
348 $checkout_ts = VikBooking::getDateTimestamp($checkoutfdate, 0, 0, 0);
349 $checkout = date('Y-m-d', $checkout_ts);
350 $nights = $av_helper->countNightsOfStay($checkin_ts, $checkout_ts);
351 } else {
352 // calculate checkout depending on number of nights of stay
353 $is_dst = date('I', $checkin_ts);
354 $checkout_ts = $checkin_ts;
355 for ($i = 1; $i <= $nights; $i++) {
356 $checkout_ts += 86400;
357 $is_now_dst = date('I', $checkout_ts);
358 if ($is_dst != $is_now_dst) {
359 if ((int)$is_dst == 1) {
360 $checkout_ts += 3600;
361 } else {
362 $checkout_ts -= 3600;
363 }
364 $is_dst = $is_now_dst;
365 }
366 }
367 $checkout = date('Y-m-d', $checkout_ts);
368 }
369
370 /**
371 * We got rid of the CURL request to the front-end task of VBO "tac_av_l"
372 * by replacing the call with the new helper class VikBookingAvailability.
373 *
374 * @since 1.15.0 (J) - 1.5.0 (WP)
375 */
376 $av_helper->setStayDates($checkin, $checkout);
377 $av_helper->setRoomParty($adults, $children);
378 // build extra params to obtain the necessary data
379 $params = array(
380 'hash' => md5('vbo.e4j.vbo'),
381 'req_type' => 'hotel_availability',
382 'nights' => $nights,
383 'num_rooms' => 1,
384 'only_rates' => $only_rates,
385 );
386 $arr_res = $av_helper->getRates($params);
387
388 // pricing pool
389 $price_details = array();
390
391 if (is_array($arr_res)) {
392 if (!strlen($av_helper->getError())) {
393 if (array_key_exists($id_room, $arr_res)) {
394 $response = '';
395 foreach ($arr_res[$id_room] as $rate) {
396 // build pricing object
397 $rplan_details = new stdClass;
398 $rplan_details->idprice = $rate['idprice'];
399 $rplan_details->name = $rate['pricename'];
400 $rplan_details->net = $rate['cost'];
401 $rplan_details->fnet = $currencysymb . ' ' . VikBooking::numberFormat($rate['cost']);
402 $rplan_details->tax = $rate['taxes'];
403 $rplan_details->ftax = $currencysymb . ' ' . VikBooking::numberFormat($rate['taxes']);
404 $rplan_details->tot = $rate['cost'] + $rate['taxes'];
405 $rplan_details->ftot = $currencysymb . ' ' . VikBooking::numberFormat(($rate['cost'] + $rate['taxes']));
406 array_push($price_details, $rplan_details);
407 //
408 $extra_response = '';
409 $response .= '<div class="vbo-calcrates-rateblock" data-idprice="' . $rate['idprice'] . '" data-idroom="' . $id_room . '" data-checkin="' . $checkin . '" data-checkout="' . $checkout . '" data-adults="' . $adults . '" data-children="' . $children . '">';
410 $response .= '<span class="vbo-calcrates-ratename">'.$rate['pricename'].'</span>';
411 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratenet"><span>'.JText::translate('VBCALCRATESNET').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['cost']).'</span>';
412 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratetax"><span>'.JText::translate('VBCALCRATESTAX').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['taxes']).'</span>';
413 if (!empty($rate['city_taxes'])) {
414 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratecitytax"><span>'.JText::translate('VBCALCRATESCITYTAX').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['city_taxes']).'</span>';
415 }
416 if (!empty($rate['fees'])) {
417 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratefees"><span>'.JText::translate('VBCALCRATESFEES').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['fees']).'</span>';
418 }
419 if (array_key_exists('affdays', $rate) && $rate['affdays'] > 0) {
420 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-ratespaffdays"><span>'.JText::translate('VBCALCRATESSPAFFDAYS').'</span>'.$rate['affdays'].'</span>';
421 }
422 if (array_key_exists('diffusagediscount', $rate) && count($rate['diffusagediscount']) > 0) {
423 foreach ($rate['diffusagediscount'] as $roomnumb => $disc) {
424 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancydisc"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>- '.$currencysymb.' '.VikBooking::numberFormat($disc).'</span>';
425 break;
426 }
427 } elseif (array_key_exists('diffusagecost', $rate) && count($rate['diffusagecost']) > 0) {
428 foreach ($rate['diffusagecost'] as $roomnumb => $charge) {
429 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancycharge"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>+ '.$currencysymb.' '.VikBooking::numberFormat($charge).'</span>';
430 break;
431 }
432 }
433 $tot = $rate['cost'] + $rate['taxes'] + $rate['city_taxes'] + $rate['fees'];
434 $tot = round($tot, 2);
435 $response .= '<span class="vbo-calcrates-ratetotal"><span>'.JText::translate('VBCALCRATESTOT').'</span>'.$currencysymb.' '.VikBooking::numberFormat($tot).'</span>';
436 if (!empty($extra_response)) {
437 $response .= '<div class="vbo-calcrates-info">'.$extra_response.'</div>';
438 }
439 $response .= '</div>';
440 }
441 } else {
442 $response = 'e4j.error.'.JText::sprintf('VBCALCRATESROOMNOTAVAILCOMBO', date($df, $checkin_ts), date($df, $checkout_ts));
443 /**
444 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
445 *
446 * @since 1.14 (J) - 1.4.0 (WP)
447 */
448 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
449 $response_code = -1;
450 }
451 }
452 } else {
453 $response = 'e4j.error.' . $av_helper->getError();
454 /**
455 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
456 *
457 * @since 1.14 (J) - 1.4.0 (WP)
458 */
459 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
460 $response_code = -1;
461 }
462 }
463 } else {
464 $response = 'e4j.error.' . $av_helper->getError();
465 }
466
467 if ($only_rates && strpos($response, 'e4j.error') === false) {
468 echo json_encode($price_details);
469 exit;
470 }
471
472 // do not do only echo trim($response); or the currency symbol will not be encoded on some servers
473 $safe_response = array(trim($response));
474 if ($only_rates && !empty($response_code)) {
475 array_push($safe_response, $response_code);
476 }
477
478 echo json_encode($safe_response);
479 exit;
480 }
481
482 /**
483 * This is an AJAX endpoint.
484 */
485 public function cron_exec()
486 {
487 ob_start();
488
489 VikRequest::setVar('view', VikRequest::getCmd('view', 'cronexec'));
490
491 parent::display();
492
493 $content = ob_get_contents();
494 ob_end_clean();
495
496 VBOHttpDocument::getInstance()->json([$content]);
497 }
498
499 public function downloadcron()
500 {
501 /**
502 * @wponly no more executable files need to be downloaded for WordPress.
503 */
504 VBOHttpDocument::getInstance()->close(406, 'Cron Jobs must be executed through WPCron');
505 }
506
507 /**
508 * This is an AJAX endpoint.
509 */
510 public function cronlogs()
511 {
512 $dbo = JFactory::getDBO();
513 $pcron_id = VikRequest::getInt('cron_id', '', 'request');
514
515 ob_start();
516
517 $q = "SELECT * FROM `#__vikbooking_cronjobs` WHERE `id`=".(int)$pcron_id.";";
518 $dbo->setQuery($q);
519 $dbo->execute();
520 if ($dbo->getNumRows() == 1) {
521 $cron_data = $dbo->loadAssoc();
522 $cron_data['logs'] = empty($cron_data['logs']) ? '--------' : $cron_data['logs'];
523 echo '<pre>'.print_r($cron_data['logs'], true).'</pre>';
524 }
525
526 $content = ob_get_contents();
527 ob_end_clean();
528
529 VBOHttpDocument::getInstance()->json([$content]);
530 }
531
532 public function packages() {
533 VikBookingHelper::printHeader("packages");
534
535 VikRequest::setVar('view', VikRequest::getCmd('view', 'packages'));
536
537 parent::display();
538
539 if (VikBooking::showFooter()) {
540 VikBookingHelper::printFooter();
541 }
542 }
543
544 public function newpackage() {
545 VikBookingHelper::printHeader("packages");
546
547 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepackage'));
548
549 parent::display();
550
551 if (VikBooking::showFooter()) {
552 VikBookingHelper::printFooter();
553 }
554 }
555
556 public function editpackage() {
557 VikBookingHelper::printHeader("packages");
558
559 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepackage'));
560
561 parent::display();
562
563 if (VikBooking::showFooter()) {
564 VikBookingHelper::printFooter();
565 }
566 }
567
568 public function createpackage()
569 {
570 if (!JSession::checkToken()) {
571 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
572 }
573
574 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
575 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
576 }
577
578 $this->do_createpackage();
579 }
580
581 public function createpackagestay()
582 {
583 if (!JSession::checkToken()) {
584 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
585 }
586
587 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
588 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
589 }
590
591 $this->do_createpackage(true);
592 }
593
594 private function do_createpackage($stay = false) {
595 $dbo = JFactory::getDBO();
596 $mainframe = JFactory::getApplication();
597 $pname = VikRequest::getString('name', '', 'request');
598 $palias = VikRequest::getString('alias', '', 'request');
599 $palias = empty($palias) ? $pname : $palias;
600 $palias = JFilterOutput::stringURLSafe($palias);
601 $pimg = VikRequest::getVar('img', null, 'files', 'array');
602 $pfrom = VikRequest::getString('from', '', 'request');
603 $pto = VikRequest::getString('to', '', 'request');
604 $pexcludeday = VikRequest::getVar('excludeday', array());
605 $strexcldates = array();
606 foreach ($pexcludeday as $exclday) {
607 if (!empty($exclday)) {
608 $strexcldates[] = $exclday;
609 }
610 }
611 $strexcldates = implode(';', $strexcldates);
612 $prooms = VikRequest::getVar('rooms', array());
613 $pminlos = VikRequest::getInt('minlos', '', 'request');
614 $pminlos = $pminlos < 1 ? 1 : $pminlos;
615 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
616 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
617 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
618 $pcost = VikRequest::getFloat('cost', '', 'request');
619 $paliq = VikRequest::getInt('aliq', '', 'request');
620 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
621 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
622 $pperperson = VikRequest::getInt('perperson', '', 'request');
623 $pperperson = $pperperson > 0 ? 1 : 0;
624 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
625 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
626 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
627 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
628 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
629 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
630 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
631 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
632 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
633 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
634 //file upload
635 jimport('joomla.filesystem.file');
636 $gimg = "";
637 if (isset($pimg) && strlen(trim($pimg['name']))) {
638 $pautoresize = VikRequest::getString('autoresize', '', 'request');
639 $presizeto = VikRequest::getInt('resizeto', '', 'request');
640 $creativik = new vikResizer();
641 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
642 $src = $pimg['tmp_name'];
643 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
644 $j = "";
645 if (file_exists($dest.$filename)) {
646 $j = rand(171, 1717);
647 while (file_exists($dest.$j.$filename)) {
648 $j++;
649 }
650 }
651 $finaldest = $dest.$j.$filename;
652 $check = getimagesize($pimg['tmp_name']);
653 if ($check[2] & imagetypes()) {
654 if (VikBooking::uploadFile($src, $finaldest)) {
655 $gimg = $j.$filename;
656 //orig img
657 $origmod = true;
658 if ($pautoresize == "1" && !empty($presizeto)) {
659 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
660 } else {
661 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
662 }
663 //thumb
664 $thumbsize = VikBooking::getThumbSize();
665 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
666 if (!$thumb || !$origmod) {
667 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
668 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
669 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
670 }
671 @unlink($finaldest);
672 } else {
673 VikError::raiseWarning('', 'Error while uploading image');
674 }
675 } else {
676 VikError::raiseWarning('', 'Uploaded file is not an Image');
677 }
678 }
679 //
680 $goto = "index.php?option=com_vikbooking&task=packages";
681 $q = "INSERT INTO `#__vikbooking_packages` (`name`,`alias`,`img`,`dfrom`,`dto`,`excldates`,`minlos`,`maxlos`,`cost`,`idiva`,`pernight_total`,`perperson`,`descr`,`shortdescr`,`benefits`,`conditions`,`showoptions`) VALUES (".$dbo->quote($pname).", ".$dbo->quote($palias).", ".$dbo->quote($gimg).", ".(int)$ptsinit.", ".(int)$ptsend.", ".$dbo->quote($strexcldates).", ".(int)$pminlos.", ".(int)$pmaxlos.", ".$dbo->quote($pcost).",'".$paliq."', ".(int)$ppernight_total.", ".(int)$pperperson.", ".$dbo->quote($pdescr).", ".$dbo->quote($pshortdescr).", ".$dbo->quote($pbenefits).", ".$dbo->quote($pconditions).", ".(int)$pshowoptions.");";
682 $dbo->setQuery($q);
683 $dbo->execute();
684 $lid = $dbo->insertid();
685 if (!empty($lid)) {
686 $mainframe->enqueueMessage(JText::translate('VBOPKGSAVED'));
687 if ($stay) {
688 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$lid;
689 }
690 foreach ($prooms as $roomid) {
691 if (!empty($roomid)) {
692 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$lid.", ".(int)$roomid.");";
693 $dbo->setQuery($q);
694 $dbo->execute();
695 }
696 }
697 }
698 $mainframe->redirect($goto);
699 }
700
701 public function updatepackage()
702 {
703 if (!JSession::checkToken()) {
704 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
705 }
706
707 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
708 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
709 }
710
711 $this->do_updatepackage();
712 }
713
714 public function updatepackagestay()
715 {
716 if (!JSession::checkToken()) {
717 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
718 }
719
720 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
721 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
722 }
723
724 $this->do_updatepackage(true);
725 }
726
727 private function do_updatepackage($stay = false) {
728 $dbo = JFactory::getDBO();
729 $mainframe = JFactory::getApplication();
730 $pwhereup = VikRequest::getInt('whereup', '', 'request');
731 $q = "SELECT * FROM `#__vikbooking_packages` WHERE `id`=".(int)$pwhereup.";";
732 $dbo->setQuery($q);
733 $dbo->execute();
734 if ($dbo->getNumRows() == 1) {
735 $pkg_data = $dbo->loadAssoc();
736 } else {
737 VikError::raiseWarning('', 'Not Found.');
738 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
739 exit;
740 }
741 $pname = VikRequest::getString('name', '', 'request');
742 $palias = VikRequest::getString('alias', '', 'request');
743 $palias = empty($palias) ? $pname : $palias;
744 $palias = JFilterOutput::stringURLSafe($palias);
745 $pimg = VikRequest::getVar('img', null, 'files', 'array');
746 $pfrom = VikRequest::getString('from', '', 'request');
747 $pto = VikRequest::getString('to', '', 'request');
748 $pexcludeday = VikRequest::getVar('excludeday', array());
749 $strexcldates = array();
750 foreach ($pexcludeday as $exclday) {
751 if (!empty($exclday)) {
752 $strexcldates[] = $exclday;
753 }
754 }
755 $strexcldates = implode(';', $strexcldates);
756 $prooms = VikRequest::getVar('rooms', array());
757 $pminlos = VikRequest::getInt('minlos', '', 'request');
758 $pminlos = $pminlos < 1 ? 1 : $pminlos;
759 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
760 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
761 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
762 $pcost = VikRequest::getFloat('cost', '', 'request');
763 $paliq = VikRequest::getInt('aliq', '', 'request');
764 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
765 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
766 $pperperson = VikRequest::getInt('perperson', '', 'request');
767 $pperperson = $pperperson > 0 ? 1 : 0;
768 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
769 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
770 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
771 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
772 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
773 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
774 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
775 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
776 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
777 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
778 //file upload
779 jimport('joomla.filesystem.file');
780 $gimg = "";
781 if (isset($pimg) && strlen(trim($pimg['name']))) {
782 $pautoresize = VikRequest::getString('autoresize', '', 'request');
783 $presizeto = VikRequest::getInt('resizeto', '', 'request');
784 $creativik = new vikResizer();
785 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
786 $src = $pimg['tmp_name'];
787 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
788 $j = "";
789 if (file_exists($dest.$filename)) {
790 $j = rand(171, 1717);
791 while (file_exists($dest.$j.$filename)) {
792 $j++;
793 }
794 }
795 $finaldest = $dest.$j.$filename;
796 $check = getimagesize($pimg['tmp_name']);
797 if ($check[2] & imagetypes()) {
798 if (VikBooking::uploadFile($src, $finaldest)) {
799 $gimg = $j.$filename;
800 //orig img
801 $origmod = true;
802 if ($pautoresize == "1" && !empty($presizeto)) {
803 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
804 } else {
805 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
806 }
807 //thumb
808 $thumbsize = VikBooking::getThumbSize();
809 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
810 if (!$thumb || !$origmod) {
811 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
812 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
813 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
814 }
815 @unlink($finaldest);
816 } else {
817 VikError::raiseWarning('', 'Error while uploading image');
818 }
819 } else {
820 VikError::raiseWarning('', 'Uploaded file is not an Image');
821 }
822 }
823 //
824 $goto = "index.php?option=com_vikbooking&task=packages";
825 $q = "UPDATE `#__vikbooking_packages` SET `name`=".$dbo->quote($pname).",`alias`=".$dbo->quote($palias)."".(!empty($gimg) ? ",`img`=".$dbo->quote($gimg) : "").",`dfrom`=".(int)$ptsinit.",`dto`=".(int)$ptsend.",`excldates`=".$dbo->quote($strexcldates).",`minlos`=".(int)$pminlos.",`maxlos`=".(int)$pmaxlos.",`cost`=".$dbo->quote($pcost).",`idiva`='".$paliq."',`pernight_total`=".(int)$ppernight_total.",`perperson`=".(int)$pperperson.",`descr`=".$dbo->quote($pdescr).",`shortdescr`=".$dbo->quote($pshortdescr).",`benefits`=".$dbo->quote($pbenefits).",`conditions`=".$dbo->quote($pconditions).",`showoptions`=".(int)$pshowoptions." WHERE `id`=".(int)$pwhereup.";";
826 $dbo->setQuery($q);
827 $dbo->execute();
828 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$pwhereup.";";
829 $dbo->setQuery($q);
830 $dbo->execute();
831 foreach ($prooms as $roomid) {
832 if (!empty($roomid)) {
833 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$pwhereup.", ".(int)$roomid.");";
834 $dbo->setQuery($q);
835 $dbo->execute();
836 }
837 }
838 $mainframe->enqueueMessage(JText::translate('VBOPKGUPDATED'));
839 if ($stay) {
840 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$pwhereup;
841 }
842 $mainframe->redirect($goto);
843 }
844
845 public function removepackages()
846 {
847 if (!JSession::checkToken()) {
848 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
849 }
850
851 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
852 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
853 }
854
855 $ids = VikRequest::getVar('cid', array());
856 $dbo = JFactory::getDbo();
857
858 foreach ($ids as $d) {
859 $q = "DELETE FROM `#__vikbooking_packages` WHERE `id`=".(int)$d.";";
860 $dbo->setQuery($q);
861 $dbo->execute();
862 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$d.";";
863 $dbo->setQuery($q);
864 $dbo->execute();
865 }
866
867 $mainframe = JFactory::getApplication();
868 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
869 }
870
871 public function calendar() {
872 VikBookingHelper::printHeader("19");
873
874 VikRequest::setVar('view', VikRequest::getCmd('view', 'calendar'));
875
876 parent::display();
877
878 if (VikBooking::showFooter()) {
879 VikBookingHelper::printFooter();
880 }
881 }
882
883 public function rooms() {
884 VikBookingHelper::printHeader("7");
885
886 VikRequest::setVar('view', VikRequest::getCmd('view', 'rooms'));
887
888 parent::display();
889
890 if (VikBooking::showFooter()) {
891 VikBookingHelper::printFooter();
892 }
893 }
894
895 public function newroom() {
896 VikBookingHelper::printHeader("7");
897
898 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
899
900 parent::display();
901
902 if (VikBooking::showFooter()) {
903 VikBookingHelper::printFooter();
904 }
905 }
906
907 public function editroom() {
908 VikBookingHelper::printHeader("7");
909
910 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
911
912 parent::display();
913
914 if (VikBooking::showFooter()) {
915 VikBookingHelper::printFooter();
916 }
917 }
918
919 public function createroom()
920 {
921 if (!JSession::checkToken()) {
922 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
923 }
924
925 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
926 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
927 }
928
929 $this->do_createroom();
930 }
931
932 public function createroomstay()
933 {
934 if (!JSession::checkToken()) {
935 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
936 }
937
938 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
939 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
940 }
941
942 $this->do_createroom(true);
943 }
944
945 private function do_createroom($stay = false) {
946 $app = JFactory::getApplication();
947 $pcname = VikRequest::getString('cname', '', 'request');
948 $pccat = VikRequest::getVar('ccat', array(0));
949 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
950 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
951 $pccarat = VikRequest::getVar('ccarat', array(0));
952 $pcoptional = VikRequest::getVar('coptional', array(0));
953 $pcavail = VikRequest::getString('cavail', '', 'request');
954 $pautoresize = VikRequest::getString('autoresize', '', 'request');
955 $presizeto = VikRequest::getString('resizeto', '', 'request');
956 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
957 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
958 $punits = VikRequest::getInt('units', '', 'request');
959 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
960 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
961 $ptoadult = VikRequest::getInt('toadult', '', 'request');
962 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
963 $ptochild = VikRequest::getInt('tochild', '', 'request');
964 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
965 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
966 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
967 $plastavail = VikRequest::getString('lastavail', '', 'request');
968 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
969 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
970 $pcustprice = VikRequest::getString('custprice', '', 'request');
971 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
972 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
973 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
974 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
975 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
976 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
977 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
978 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
979 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
980 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
981 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
982 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
983 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
984 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
985 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
986 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
987 $psefalias = VikRequest::getString('sefalias', '', 'request');
988 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
989 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
990 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
991 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
992 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
993 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
994 $pshare_with = VikRequest::getVar('share_with', array());
995 $scalnights_arr = array();
996 if (!empty($pseasoncal_nights)) {
997 $scalnights = explode(',', $pseasoncal_nights);
998 foreach ($scalnights as $scalnight) {
999 if (intval(trim($scalnight)) > 0) {
1000 $scalnights_arr[] = intval(trim($scalnight));
1001 }
1002 }
1003 }
1004 if (count($scalnights_arr) > 0) {
1005 $pseasoncal_nights = implode(', ', $scalnights_arr);
1006 } else {
1007 $pseasoncal_nights = '';
1008 $pseasoncal = 0;
1009 }
1010 $roomparams = array('lastavail' => $plastavail, 'suggocc' => $psuggocc, 'custprice' => $pcustprice, 'custpricetxt' => $pcustpricetxt, 'custpricesubtxt' => $pcustpricesubtxt, 'reqinfo' => $preqinfo, 'pricecal' => $ppricecal, 'defcalcost' => floatval($pdefcalcost), 'maxminpeople' => $pmaxminpeople, 'seasoncal' => $pseasoncal, 'seasoncal_nights' => $pseasoncal_nights, 'seasoncal_prices' => $pseasoncal_prices, 'seasoncal_restr' => $pseasoncal_restr, 'multi_units' => $pmulti_units, 'custptitle' => $pcustptitle, 'custptitlew' => $pcustptitlew, 'metakeywords' => $pmetakeywords, 'metadescription' => $pmetadescription);
1011 //distinctive features
1012 $roomparams['features'] = array();
1013 if ($punits > 0) {
1014 for ($i=1; $i <= $punits; $i++) {
1015 $distf_name = VikRequest::getVar('feature-name'.$i, array());
1016 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
1017 $distf_value = VikRequest::getVar('feature-value'.$i, array());
1018 foreach ($distf_name as $distf_k => $distf) {
1019 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
1020 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
1021 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
1022 }
1023 }
1024 }
1025 }
1026
1027 /**
1028 * Store room geo params information.
1029 *
1030 * @since 1.14 (J) - 1.4.0 (WP)
1031 */
1032 $geo = VikBooking::getGeocodingInstance();
1033 $geo_params = $geo->getRoomGeoTransient(0);
1034 if ($geo_params !== false) {
1035 // make sure the geocoding service was not turned off
1036 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
1037 if (!$geo_enabled) {
1038 $geo_params->enabled = 0;
1039 }
1040 //
1041 $roomparams['geo'] = $geo_params;
1042 }
1043 //
1044
1045 $roomparamstr = json_encode($roomparams);
1046
1047 if (empty($pcname)) {
1048 $app->enqueueMessage(JText::translate('VBO_PLEASE_FILL_FIELDS'), 'error');
1049 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1050 $app->close();
1051 }
1052
1053 jimport('joomla.filesystem.file');
1054 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1055
1056 if (intval($_FILES['cimg']['error']) == 0 && VikBooking::caniWrite($updpath) && trim($_FILES['cimg']['name'])!="") {
1057 if (@is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1058 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['cimg']['name'])));
1059 if (file_exists($updpath.$safename)) {
1060 $j = 1;
1061 while (file_exists($updpath.$j.$safename)) {
1062 $j++;
1063 }
1064 $pwhere = $updpath.$j.$safename;
1065 } else {
1066 $j = "";
1067 $pwhere = $updpath.$safename;
1068 }
1069 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1070 @unlink($pwhere);
1071 $picon = "";
1072 } else {
1073 VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere);
1074 @chmod($pwhere, 0644);
1075 $picon = $j.$safename;
1076 if ($pautoresize=="1" && !empty($presizeto)) {
1077 $eforj = new vikResizer();
1078 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
1079 if ($origmod) {
1080 @unlink($pwhere);
1081 $picon = 'r_'.$j.$safename;
1082 }
1083 }
1084 }
1085 } else {
1086 $picon = "";
1087 }
1088 } else {
1089 $picon = "";
1090 }
1091 //more images
1092 $creativik = new vikResizer();
1093 $bigsdest = $updpath;
1094 $thumbsdest = $updpath;
1095 $dest = $updpath;
1096 $moreimagestr = "";
1097 $arrimgs = array();
1098 $captiontexts = array();
1099 $imgcaptions = array();
1100 foreach ($pimages['name'] as $kk=>$ci) {
1101 if (!empty($ci)) {
1102 $arrimgs[] = $kk;
1103 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1104 }
1105 }
1106 foreach ($arrimgs as $ki => $imgk) {
1107 if (strlen(trim($pimages['name'][$imgk]))) {
1108 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1109 $src = $pimages['tmp_name'][$imgk];
1110 $j = "";
1111 if (file_exists($dest.$filename)) {
1112 $j = rand(171, 1717);
1113 while (file_exists($dest.$j.$filename)) {
1114 $j++;
1115 }
1116 }
1117 $finaldest = $dest.$j.$filename;
1118 $check = getimagesize($pimages['tmp_name'][$imgk]);
1119 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1120 if (VikBooking::uploadFile($src, $finaldest)) {
1121 $gimg = $j.$filename;
1122 //orig img
1123 $origmod = true;
1124 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1125 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1126 } else {
1127 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1128 }
1129 //thumb
1130 $thumbsize = VikBooking::getThumbSize();
1131 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1132 if (!$thumb || !$origmod) {
1133 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1134 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1135 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1136 } else {
1137 $moreimagestr .= $j.$filename.";;";
1138 $imgcaptions[] = $captiontexts[$ki];
1139 }
1140 @unlink($finaldest);
1141 } else {
1142 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1143 }
1144 } else {
1145 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1146 }
1147 }
1148 }
1149 //end more images
1150 if (is_array($pccat) && count($pccat)) {
1151 $pccatdef="";
1152 foreach ($pccat as $ccat) {
1153 if (!empty($ccat)) {
1154 $pccatdef.=$ccat.";";
1155 }
1156 }
1157 } else {
1158 $pccatdef="";
1159 }
1160 if (is_array($pccarat) && count($pccarat)) {
1161 $pccaratdef="";
1162 foreach ($pccarat as $ccarat) {
1163 $pccaratdef.=$ccarat.";";
1164 }
1165 } else {
1166 $pccaratdef="";
1167 }
1168 if (is_array($pcoptional) && count($pcoptional)) {
1169 $pcoptionaldef="";
1170 foreach ($pcoptional as $coptional) {
1171 $pcoptionaldef.=$coptional.";";
1172 }
1173 } else {
1174 $pcoptionaldef="";
1175 }
1176 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1177 if ($pfromadult > $ptoadult) {
1178 $pfromadult = 1;
1179 $ptoadult = 1;
1180 }
1181 if ($pfromchild > $ptochild) {
1182 $pfromchild = 1;
1183 $ptochild = 1;
1184 }
1185 $dbo = JFactory::getDbo();
1186 $q = "INSERT INTO `#__vikbooking_rooms` (`name`,`img`,`idcat`,`idcarat`,`idopt`,`info`,`avail`,`units`,`moreimgs`,`fromadult`,`toadult`,`fromchild`,`tochild`,`smalldesc`,`totpeople`,`mintotpeople`,`params`,`imgcaptions`,`alias`) VALUES(".$dbo->quote($pcname).",".$dbo->quote($picon).",".$dbo->quote($pccatdef).",".$dbo->quote($pccaratdef).",".$dbo->quote($pcoptionaldef).",".$dbo->quote($pcdescr).",".$dbo->quote($pcavaildef).",".($punits > 0 ? $dbo->quote($punits) : "'1'").", ".$dbo->quote($moreimagestr).", '".$pfromadult."', '".$ptoadult."', '".$pfromchild."', '".$ptochild."', ".$dbo->quote($psmalldesc).", ".$ptotpeople.", ".$pmintotpeople.", ".$dbo->quote($roomparamstr).", ".$dbo->quote(json_encode($imgcaptions)).",".$dbo->quote($psefalias).");";
1187 $dbo->setQuery($q);
1188 $dbo->execute();
1189 $lid = $dbo->insertid();
1190 if (empty($lid)) {
1191 $app->enqueueMessage('Could not store the record on the database', 'error');
1192 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1193 $app->close();
1194 }
1195
1196 /**
1197 * Share availability calendars with other rooms.
1198 *
1199 * @since 1.13
1200 */
1201 // always reset relations for this main room
1202 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$lid};";
1203 $dbo->setQuery($q);
1204 $dbo->execute();
1205 $newxref = array();
1206 foreach ($pshare_with as $cldroom) {
1207 if (!empty($cldroom)) {
1208 array_push($newxref, (int)$cldroom);
1209 }
1210 }
1211 foreach ($newxref as $cldroom) {
1212 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$lid}, {$cldroom});";
1213 $dbo->setQuery($q);
1214 $dbo->execute();
1215 }
1216
1217 /**
1218 * Room upgrade options.
1219 *
1220 * @since 1.16.0 (J) - 1.6.0 (WP)
1221 */
1222 $config = VBOFactory::getConfig();
1223 $room_upgrade_options = [];
1224 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1225 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1226 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1227 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1228 $upgrade_rooms = array_map(function($rid) {
1229 return (int)$rid;
1230 }, $upgrade_rooms);
1231
1232 $room_upgrade_options = [
1233 'rooms' => $upgrade_rooms,
1234 'discount' => $upgrade_discount,
1235 ];
1236 }
1237 $config->set('room_upgrade_options_' . $lid, json_encode($room_upgrade_options));
1238
1239 if ($stay === true) {
1240 $app->enqueueMessage(JText::translate('VBOROOMSAVEOK').' - <a href="index.php?option=com_vikbooking&task=tariffs&cid[]='.$lid.'">'.JText::translate('VBOGOTORATES').'</a>');
1241 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$lid);
1242 $app->close();
1243 }
1244
1245 $app->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$lid);
1246 $app->close();
1247 }
1248
1249 public function updateroom()
1250 {
1251 if (!JSession::checkToken()) {
1252 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1253 }
1254
1255 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1256 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1257 }
1258
1259 $this->do_updateroom();
1260 }
1261
1262 public function updateroomstay()
1263 {
1264 if (!JSession::checkToken()) {
1265 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1266 }
1267
1268 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1269 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1270 }
1271
1272 $this->do_updateroom(true);
1273 }
1274
1275 private function do_updateroom($stay = false)
1276 {
1277 $app = JFactory::getApplication();
1278 $config = VBOFactory::getConfig();
1279
1280 $pcname = VikRequest::getString('cname', '', 'request');
1281 $pccat = VikRequest::getVar('ccat', array(0));
1282 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
1283 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
1284 $pccarat = VikRequest::getVar('ccarat', array(0));
1285 $pcoptional = VikRequest::getVar('coptional', array(0));
1286 $pcavail = VikRequest::getString('cavail', '', 'request');
1287 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
1288 $pautoresize = VikRequest::getString('autoresize', '', 'request');
1289 $presizeto = VikRequest::getString('resizeto', '', 'request');
1290 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
1291 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
1292 $punits = VikRequest::getInt('units', '', 'request');
1293 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
1294 $pactmoreimgs = VikRequest::getString('actmoreimgs', '', 'request');
1295 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
1296 $ptoadult = VikRequest::getInt('toadult', '', 'request');
1297 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
1298 $ptochild = VikRequest::getInt('tochild', '', 'request');
1299 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array(0));
1300 $padultsdiffval = VikRequest::getVar('adultsdiffval', array(0));
1301 $padultsdiffnum = VikRequest::getVar('adultsdiffnum', array(0));
1302 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array(0));
1303 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array(0));
1304 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
1305 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
1306 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
1307 $plastavail = VikRequest::getString('lastavail', '', 'request');
1308 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
1309 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
1310 $pcustprice = VikRequest::getString('custprice', '', 'request');
1311 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
1312 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
1313 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
1314 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
1315 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
1316 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
1317 $pdefrplan = VikRequest::getInt('defrplan', 0, 'request');
1318 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
1319 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
1320 $pimgsorting = VikRequest::getVar('imgsorting', array());
1321 $pupdatecaption = VikRequest::getInt('updatecaption', '', 'request');
1322 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
1323 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
1324 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
1325 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
1326 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
1327 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
1328 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
1329 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
1330 $psefalias = VikRequest::getString('sefalias', '', 'request');
1331 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
1332 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
1333 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
1334 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
1335 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
1336 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
1337 $pshare_with = VikRequest::getVar('share_with', array());
1338 $scalnights_arr = array();
1339 if (!empty($pseasoncal_nights)) {
1340 $scalnights = explode(',', $pseasoncal_nights);
1341 foreach ($scalnights as $scalnight) {
1342 if (intval(trim($scalnight)) > 0) {
1343 $scalnights_arr[] = intval(trim($scalnight));
1344 }
1345 }
1346 }
1347 if (count($scalnights_arr) > 0) {
1348 $pseasoncal_nights = implode(', ', $scalnights_arr);
1349 } else {
1350 $pseasoncal_nights = '';
1351 $pseasoncal = 0;
1352 }
1353 $roomparams = [
1354 'lastavail' => $plastavail,
1355 'suggocc' => $psuggocc,
1356 'custprice' => $pcustprice,
1357 'custpricetxt' => $pcustpricetxt,
1358 'custpricesubtxt' => $pcustpricesubtxt,
1359 'reqinfo' => $preqinfo,
1360 'pricecal' => $ppricecal,
1361 'defcalcost' => floatval($pdefcalcost),
1362 'defrplan' => $pdefrplan,
1363 'maxminpeople' => $pmaxminpeople,
1364 'seasoncal' => $pseasoncal,
1365 'seasoncal_nights' => $pseasoncal_nights,
1366 'seasoncal_prices' => $pseasoncal_prices,
1367 'seasoncal_restr' => $pseasoncal_restr,
1368 'multi_units' => $pmulti_units,
1369 'custptitle' => $pcustptitle,
1370 'custptitlew' => $pcustptitlew,
1371 'metakeywords' => $pmetakeywords,
1372 'metadescription' => $pmetadescription,
1373 ];
1374 //distinctive features
1375 $roomparams['features'] = array();
1376 $newfeatures = array();
1377 if ($punits > 0) {
1378 for ($i=1; $i <= $punits; $i++) {
1379 $distf_name = VikRequest::getVar('feature-name'.$i, array());
1380 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
1381 $distf_value = VikRequest::getVar('feature-value'.$i, array());
1382 foreach ($distf_name as $distf_k => $distf) {
1383 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
1384 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
1385 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
1386 if ($distf_k < 1) {
1387 //check only the first feature
1388 $newfeatures[$i][$use_key] = $distf_value[$distf_k];
1389 }
1390 }
1391 }
1392 }
1393 }
1394
1395 /**
1396 * Store room geo params information.
1397 *
1398 * @since 1.14 (J) - 1.4.0 (WP)
1399 */
1400 $geo = VikBooking::getGeocodingInstance();
1401 $geo_params = $geo->getRoomGeoTransient($pwhereup);
1402 if ($geo_params !== false) {
1403 // make sure the geocoding service was not turned off
1404 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
1405 if (!$geo_enabled) {
1406 $geo_params->enabled = 0;
1407 }
1408 //
1409 $roomparams['geo'] = $geo_params;
1410 }
1411 //
1412
1413 $roomparamstr = json_encode($roomparams);
1414
1415 jimport('joomla.filesystem.file');
1416 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1417 if (!empty($pcname)) {
1418 if (intval($_FILES['cimg']['error']) == 0 && VikBooking::caniWrite($updpath) && trim($_FILES['cimg']['name'])!="") {
1419 if (@is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1420 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['cimg']['name'])));
1421 if (file_exists($updpath.$safename)) {
1422 $j = 1;
1423 while (file_exists($updpath.$j.$safename)) {
1424 $j++;
1425 }
1426 $pwhere = $updpath.$j.$safename;
1427 } else {
1428 $j = "";
1429 $pwhere = $updpath.$safename;
1430 }
1431 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1432 @unlink($pwhere);
1433 $picon = "";
1434 } else {
1435 VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere);
1436 @chmod($pwhere, 0644);
1437 $picon = $j.$safename;
1438 if ($pautoresize == "1" && !empty($presizeto)) {
1439 $eforj = new vikResizer();
1440 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
1441 if ($origmod) {
1442 @unlink($pwhere);
1443 $picon = 'r_'.$j.$safename;
1444 }
1445 }
1446 }
1447 } else {
1448 $picon = "";
1449 }
1450 } else {
1451 $picon = "";
1452 }
1453 //more images
1454 $creativik = new vikResizer();
1455 $bigsdest = $updpath;
1456 $thumbsdest = $updpath;
1457 $dest = $updpath;
1458 $moreimagestr = $pactmoreimgs;
1459 $arrimgs = array();
1460 $captiontexts = array();
1461 $imgcaptions = array();
1462 //captions of uploaded extra images
1463 if (!empty($pactmoreimgs)) {
1464 $sploimgs = explode(';;', $pactmoreimgs);
1465 foreach ($sploimgs as $ki => $oimg) {
1466 if (!empty($oimg)) {
1467 $oldcaption = VikRequest::getString('caption'.$ki, '', 'request', VIKREQUEST_ALLOWHTML);
1468 $imgcaptions[] = $oldcaption;
1469 }
1470 }
1471 }
1472 //
1473 foreach ($pimages['name'] as $kk=>$ci) {
1474 if (!empty($ci)) {
1475 $arrimgs[] = $kk;
1476 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1477 }
1478 }
1479 foreach ($arrimgs as $ki => $imgk) {
1480 if (strlen(trim($pimages['name'][$imgk]))) {
1481 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1482 $src = $pimages['tmp_name'][$imgk];
1483 $j = "";
1484 if (file_exists($dest.$filename)) {
1485 $j = rand(171, 1717);
1486 while (file_exists($dest.$j.$filename)) {
1487 $j++;
1488 }
1489 }
1490 $finaldest = $dest.$j.$filename;
1491 $check = getimagesize($pimages['tmp_name'][$imgk]);
1492 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1493 if (VikBooking::uploadFile($src, $finaldest)) {
1494 $gimg = $j.$filename;
1495 //orig img
1496 $origmod = true;
1497 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1498 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1499 } else {
1500 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1501 }
1502 //thumb
1503 $thumbsize = VikBooking::getThumbSize();
1504 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1505 if (!$thumb || !$origmod) {
1506 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1507 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1508 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1509 } else {
1510 $moreimagestr .= $j.$filename.";;";
1511 $imgcaptions[] = $captiontexts[$ki];
1512 }
1513 @unlink($finaldest);
1514 } else {
1515 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1516 }
1517 } else {
1518 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1519 }
1520 }
1521 }
1522 //sorting of extra images
1523 $sorted_extraim = array();
1524 $sorted_captions = array();
1525 $extraim_parts = explode(';;', $moreimagestr);
1526 foreach ($pimgsorting as $k => $v) {
1527 $capkey = -1;
1528 if (isset($extraim_parts[$k])) {
1529 $sorted_extraim[] = $v;
1530 foreach ($extraim_parts as $oldk => $oldv) {
1531 if ($oldv == $v) {
1532 $capkey = $oldk;
1533 break;
1534 }
1535 }
1536 }
1537 if (isset($imgcaptions[$capkey])) {
1538 $sorted_captions[] = $imgcaptions[$capkey];
1539 }
1540 }
1541 $tot_sorted_im = count($sorted_extraim);
1542 if ($tot_sorted_im != count($extraim_parts)) {
1543 foreach ($extraim_parts as $k => $v) {
1544 if ($k <= ($tot_sorted_im - 1)) {
1545 continue;
1546 }
1547 $sorted_extraim[] = $v;
1548 if (isset($imgcaptions[$k])) {
1549 $sorted_captions[] = $imgcaptions[$k];
1550 }
1551 }
1552 }
1553 $moreimagestr = implode(';;', $sorted_extraim);
1554 $imgcaptions = $sorted_captions;
1555 //end more images
1556 if (is_array($pccat) && count($pccat)) {
1557 $pccatdef = "";
1558 foreach ($pccat as $ccat) {
1559 if (!empty($ccat)) {
1560 $pccatdef .= $ccat.";";
1561 }
1562 }
1563 } else {
1564 $pccatdef = "";
1565 }
1566 if (is_array($pccarat) && count($pccarat)) {
1567 $pccaratdef = "";
1568 foreach ($pccarat as $ccarat) {
1569 $pccaratdef .= $ccarat.";";
1570 }
1571 } else {
1572 $pccaratdef = "";
1573 }
1574 if (is_array($pcoptional) && count($pcoptional)) {
1575 $pcoptionaldef = "";
1576 foreach ($pcoptional as $coptional) {
1577 $pcoptionaldef .= $coptional.";";
1578 }
1579 } else {
1580 $pcoptionaldef = "";
1581 }
1582 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1583 if ($pfromadult > $ptoadult) {
1584 $pfromadult = 1;
1585 $ptoadult = 1;
1586 }
1587 if ($pfromchild > $ptochild) {
1588 $pfromchild = 1;
1589 $ptochild = 1;
1590 }
1591 $dbo = JFactory::getDBO();
1592 //adults charges/discounts
1593 $adchdisctouch = false;
1594 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`='".$pwhereup."';";
1595 $dbo->setQuery($q);
1596 $dbo->execute();
1597 $oldroom = $dbo->loadAssocList();
1598 $oldroom = $oldroom[0];
1599 if ($oldroom['fromadult'] == $pfromadult && $oldroom['toadult'] == $ptoadult) {
1600 if ($oldroom['toadult'] > 1 && $oldroom['fromadult'] < $oldroom['toadult'] && @count($padultsdiffnum) > 0) {
1601 $startadind = $oldroom['fromadult'] > 0 ? $oldroom['fromadult'] : 1;
1602 for($adi = $startadind; $adi <= $oldroom['toadult']; $adi++) {
1603 foreach ($padultsdiffnum as $kad=>$vad) {
1604 if (intval($vad) == intval($adi) && strlen($padultsdiffval[$kad]) > 0) {
1605 $adchdisctouch = true;
1606 $inschdisc = intval($padultsdiffchdisc[$kad]) == 1 ? 1 : 2;
1607 $insvalpcent = intval($padultsdiffvalpcent[$kad]) == 1 ? 1 : 2;
1608 $inspernight = intval($padultsdiffpernight[$kad]) == 1 ? 1 : 0;
1609 $insvalue = floatval($padultsdiffval[$kad]);
1610 //check if it exists
1611 $q = "SELECT `id` FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1612 $dbo->setQuery($q);
1613 $dbo->execute();
1614 if ($dbo->getNumRows() > 0) {
1615 if ($insvalue > 0) {
1616 //update
1617 $q = "UPDATE `#__vikbooking_adultsdiff` SET `chdisc`='".$inschdisc."', `valpcent`='".$insvalpcent."', `value`='".$insvalue."', `pernight`='".$inspernight."' WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1618 $dbo->setQuery($q);
1619 $dbo->execute();
1620 } else {
1621 //delete
1622 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1623 $dbo->setQuery($q);
1624 $dbo->execute();
1625 }
1626 } else {
1627 //insert
1628 $q = "INSERT INTO `#__vikbooking_adultsdiff` (`idroom`,`chdisc`,`valpcent`,`value`,`adults`,`pernight`) VALUES('".$oldroom['id']."', '".$inschdisc."', '".$insvalpcent."', '".$insvalue."', '".$adi."', '".$inspernight."');";
1629 $dbo->setQuery($q);
1630 $dbo->execute();
1631 }
1632 }
1633 }
1634 }
1635 }
1636 } else {
1637 //min and max adults num have changed, delete
1638 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."';";
1639 $dbo->setQuery($q);
1640 $dbo->execute();
1641 }
1642 if ($adchdisctouch == true) {
1643 $app->enqueueMessage(JText::translate('VBUPDROOMADCHDISCSAVED'));
1644 }
1645 //
1646 //check distinctive features if there were any changes
1647 $old_rparams = json_decode($oldroom['params'], true);
1648 $old_rparams = is_array($old_rparams) ? $old_rparams : array();
1649 if (array_key_exists('features', $old_rparams)) {
1650 $oldfeatures = array();
1651 foreach ($old_rparams['features'] as $rnumunit => $oldfeat) {
1652 foreach ($oldfeat as $featname => $featval) {
1653 $oldfeatures[$rnumunit][$featname] = $featval;
1654 break;
1655 }
1656 }
1657 /**
1658 * We reset the sub-unit information to all bookings only in case the new
1659 * number of units is reduced. When we add new units or we modify the contents,
1660 * we keep everything as is for the past reservations.
1661 *
1662 * @since 1.15.2 (J) - 1.5.5 (WP)
1663 */
1664 if ($oldfeatures != $newfeatures && count($newfeatures) < count($oldfeatures)) {
1665 // changes were made to the first index (Room Number by default) of the distinctive features
1666 // set to NULL all the already set roomindexes in bookings
1667 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=NULL WHERE `idroom`=".(int)$oldroom['id'].";";
1668 $dbo->setQuery($q);
1669 $dbo->execute();
1670 }
1671 }
1672 //
1673 $q = "UPDATE `#__vikbooking_rooms` SET `name`=".$dbo->quote($pcname).",".(strlen($picon) > 0 ? "`img`='".$picon."'," : "")."`idcat`=".$dbo->quote($pccatdef).",`idcarat`=".$dbo->quote($pccaratdef).",`idopt`=".$dbo->quote($pcoptionaldef).",`info`=".$dbo->quote($pcdescr).",`avail`=".$dbo->quote($pcavaildef).",`units`=".($punits > 0 ? $dbo->quote($punits) : "'1'").",`moreimgs`=".$dbo->quote($moreimagestr).",`fromadult`='".$pfromadult."',`toadult`='".$ptoadult."',`fromchild`='".$pfromchild."',`tochild`='".$ptochild."',`smalldesc`=".$dbo->quote($psmalldesc).",`totpeople`=".$ptotpeople.",`mintotpeople`=".$pmintotpeople.",`params`=".$dbo->quote($roomparamstr).",`imgcaptions`=".$dbo->quote(json_encode($imgcaptions)).",`alias`=".$dbo->quote($psefalias)." WHERE `id`=".$dbo->quote($pwhereup).";";
1674 $dbo->setQuery($q);
1675 $dbo->execute();
1676
1677 /**
1678 * Share availability calendars with other rooms.
1679 *
1680 * @since 1.13
1681 */
1682 // always reset relations for this main room
1683 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$pwhereup};";
1684 $dbo->setQuery($q);
1685 $dbo->execute();
1686 $newxref = array();
1687 foreach ($pshare_with as $cldroom) {
1688 if (!empty($cldroom)) {
1689 array_push($newxref, (int)$cldroom);
1690 }
1691 }
1692 foreach ($newxref as $cldroom) {
1693 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$pwhereup}, {$cldroom});";
1694 $dbo->setQuery($q);
1695 $dbo->execute();
1696 }
1697
1698 /**
1699 * Room upgrade options.
1700 *
1701 * @since 1.16.0 (J) - 1.6.0 (WP)
1702 */
1703 $room_upgrade_options = [];
1704 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1705 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1706 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1707 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1708 $upgrade_rooms = array_map(function($rid) {
1709 return (int)$rid;
1710 }, $upgrade_rooms);
1711
1712 $room_upgrade_options = [
1713 'rooms' => $upgrade_rooms,
1714 'discount' => $upgrade_discount,
1715 ];
1716 }
1717 $config->set('room_upgrade_options_' . $pwhereup, json_encode($room_upgrade_options));
1718
1719 /**
1720 * Maximum advance booking offset can be defined at room-level.
1721 *
1722 * @since 1.16.3 (J) - 1.6.3 (WP)
1723 */
1724 $pmax_adv_notice_room = VikRequest::getInt('max_adv_notice_room', 0, 'request');
1725 $pmaxdate = VikRequest::getInt('maxdate', 0, 'request');
1726 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
1727 $maxdate_str = '';
1728 if ($pmax_adv_notice_room && $pmaxdate > 0) {
1729 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
1730 $maxdate_str = '+' . $pmaxdate . $pmaxdateinterval;
1731 }
1732 $config->set("room_{$pwhereup}_max_adv_notice", $maxdate_str);
1733
1734 $app->enqueueMessage(JText::translate('VBUPDROOMOK'));
1735 }
1736
1737 if ($pupdatecaption == 1 || $stay === true) {
1738 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$pwhereup);
1739 } else {
1740 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1741 }
1742 }
1743
1744 public function modavail() {
1745 if (!JSession::checkToken() && !JSession::checkToken('get')) {
1746 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1747 }
1748 $cid = VikRequest::getVar('cid', array(0));
1749 $room = $cid[0];
1750 if (!empty($room)) {
1751 $dbo = JFactory::getDBO();
1752 $q = "SELECT `avail` FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($room).";";
1753 $dbo->setQuery($q);
1754 $dbo->execute();
1755 $get = $dbo->loadAssocList();
1756 $q = "UPDATE `#__vikbooking_rooms` SET `avail`='".(intval($get[0]['avail'])==1 ? 0 : 1)."' WHERE `id`=".$dbo->quote($room).";";
1757 $dbo->setQuery($q);
1758 $dbo->execute();
1759 }
1760 $mainframe = JFactory::getApplication();
1761 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1762 }
1763
1764 public function removeroom()
1765 {
1766 if (!JSession::checkToken()) {
1767 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1768 }
1769
1770 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
1771 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1772 }
1773
1774 $ids = VikRequest::getVar('cid', array(0));
1775 if (@count($ids)) {
1776 $dbo = JFactory::getDBO();
1777 foreach ($ids as $d) {
1778 $q = "DELETE FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($d).";";
1779 $dbo->setQuery($q);
1780 $dbo->execute();
1781 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idroom`=".$dbo->quote($d).";";
1782 $dbo->setQuery($q);
1783 $dbo->execute();
1784 }
1785 }
1786 $mainframe = JFactory::getApplication();
1787 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1788 }
1789
1790 public function tariffs() {
1791 VikBookingHelper::printHeader("fares");
1792
1793 VikRequest::setVar('view', VikRequest::getCmd('view', 'tariffs'));
1794
1795 parent::display();
1796
1797 if (VikBooking::showFooter()) {
1798 VikBookingHelper::printFooter();
1799 }
1800 }
1801
1802 public function removetariffs()
1803 {
1804 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
1805 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1806 }
1807
1808 $ids = VikRequest::getVar('cid', array(0));
1809 $proomid = VikRequest::getInt('roomid', '', 'request');
1810 if (@count($ids)) {
1811 $dbo = JFactory::getDBO();
1812 foreach ($ids as $r) {
1813 $x=explode(";", $r);
1814 foreach ($x as $rm) {
1815 if (!empty($rm)) {
1816 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `id`=".$dbo->quote($rm).";";
1817 $dbo->setQuery($q);
1818 $dbo->execute();
1819 }
1820 }
1821 }
1822 }
1823 $mainframe = JFactory::getApplication();
1824 $mainframe->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$proomid);
1825 }
1826
1827 public function editbusy() {
1828 VikBookingHelper::printHeader("8");
1829
1830 VikRequest::setVar('view', VikRequest::getCmd('view', 'editbusy'));
1831
1832 parent::display();
1833
1834 if (VikBooking::showFooter()) {
1835 VikBookingHelper::printFooter();
1836 }
1837 }
1838
1839 public function updatebusy()
1840 {
1841 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1842 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1843 }
1844
1845 $this->do_updatebusy();
1846 }
1847
1848 public function updatebusydoinv()
1849 {
1850 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1851 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1852 }
1853
1854 $this->do_updatebusy('geninvoices');
1855 }
1856
1857 private function do_updatebusy($callback = '')
1858 {
1859 $pidorder = VikRequest::getInt('idorder', 0, 'request');
1860 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
1861 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
1862 $pcheckinh = VikRequest::getString('checkinh', '', 'request');
1863 $pcheckinm = VikRequest::getString('checkinm', '', 'request');
1864 $pcheckouth = VikRequest::getString('checkouth', '', 'request');
1865 $pcheckoutm = VikRequest::getString('checkoutm', '', 'request');
1866 $pcustdata = VikRequest::getString('custdata', '', 'request');
1867 $pareprices = VikRequest::getString('areprices', '', 'request');
1868 $ptotpaid = VikRequest::getString('totpaid', '', 'request');
1869 $prefund = VikRequest::getString('refund', '', 'request');
1870 $pfrominv = VikRequest::getInt('frominv', '', 'request');
1871 $pvcm = VikRequest::getInt('vcm', '', 'request');
1872 $pgoto = VikRequest::getString('goto', '', 'request');
1873 $pextracn = VikRequest::getVar('extracn', []);
1874 $pextracc = VikRequest::getVar('extracc', []);
1875 $pextractx = VikRequest::getVar('extractx', []);
1876 /**
1877 * This is a "foreign key" integer value useful for other Vik plugins
1878 * to store custom extra services within a VBO reservation. Another
1879 * custom value "extra foreign data" (extracdata) is added. We also
1880 * support a "type" string useful for VCM to determine the type of service.
1881 *
1882 * @since 1.16.0 (J) - 1.6.0 (WP)
1883 * @since 1.16.1 (J) - 1.6.1 (WP) added the "type" string.
1884 */
1885 $pextractype = VikRequest::getVar('extractype', []);
1886 $pextracfk = VikRequest::getVar('extracfk', []);
1887 $pextracdata = VikRequest::getVar('extracdata', [], 'request', 'array', VIKREQUEST_ALLOWRAW);
1888
1889 $dbo = JFactory::getDbo();
1890 $user = JFactory::getUser();
1891 $app = JFactory::getApplication();
1892
1893 // availability helper
1894 $av_helper = VikBooking::getAvailabilityInstance();
1895
1896 $actnow = time();
1897 $nowdf = VikBooking::getDateFormat(true);
1898 if ($nowdf == "%d/%m/%Y") {
1899 $df = 'd/m/Y';
1900 } elseif ($nowdf == "%m/%d/%Y") {
1901 $df = 'm/d/Y';
1902 } else {
1903 $df = 'Y/m/d';
1904 }
1905
1906 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
1907 $dbo->setQuery($q, 0, 1);
1908 $ord = $dbo->loadAssoc();
1909 if (!$ord) {
1910 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1911 exit;
1912 }
1913
1914 $q = "SELECT `or`.*,`r`.`name`,`r`.`idopt`,`r`.`units`,`r`.`fromadult`,`r`.`toadult` FROM `#__vikbooking_ordersrooms` AS `or`,`#__vikbooking_rooms` AS `r` WHERE `or`.`idorder`=".$ord['id']." AND `or`.`idroom`=`r`.`id` ORDER BY `or`.`id` ASC;";
1915 $dbo->setQuery($q);
1916 $ordersrooms = $dbo->loadAssocList();
1917
1918 // do not touch this array property because it's used by VCM
1919 $ord['rooms_info'] = $ordersrooms;
1920
1921 // room stay dates in case of split stay
1922 $room_stay_dates = [];
1923 if ($ord['split_stay']) {
1924 if ($ord['status'] == 'confirmed') {
1925 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
1926 } else {
1927 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
1928 }
1929 // immediately count the number of nights of stay for each split room
1930 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
1931 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
1932 // overwrite values for compatibility with non-confirmed bookings
1933 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
1934 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
1935 }
1936 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
1937 // overwrite the whole array
1938 $room_stay_dates[$sps_r_k] = $sps_r_v;
1939 }
1940 }
1941
1942 // package or custom rate
1943 $is_package = !empty($ord['pkg']) ? true : false;
1944 $is_cust_cost = false;
1945 foreach ($ordersrooms as $kor => $or) {
1946 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
1947 $is_cust_cost = true;
1948 break;
1949 }
1950 }
1951
1952 // room switching
1953 $toswitch = array();
1954 $idbooked = array();
1955 $rooms_units = array();
1956
1957 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
1958 $dbo->setQuery($q);
1959 $all_rooms = $dbo->loadAssocList();
1960 foreach ($all_rooms as $rr) {
1961 $rooms_units[$rr['id']]['name'] = $rr['name'];
1962 $rooms_units[$rr['id']]['units'] = $rr['units'];
1963 }
1964
1965 foreach ($ordersrooms as $ind => $or) {
1966 $switch_command = VikRequest::getString('switch_'.$or['id'], '', 'request');
1967 if (!empty($switch_command) && intval($switch_command) != $or['idroom'] && array_key_exists(intval($switch_command), $rooms_units)) {
1968 if (!isset($idbooked[$or['idroom']])) {
1969 $idbooked[$or['idroom']] = 0;
1970 }
1971 $idbooked[$or['idroom']]++;
1972 $orkey = count($toswitch);
1973 $toswitch[$orkey]['from'] = $or['idroom'];
1974 $toswitch[$orkey]['to'] = intval($switch_command);
1975 $toswitch[$orkey]['record'] = $or;
1976 $toswitch[$orkey]['record_ind'] = $ind;
1977 }
1978 }
1979
1980 if (count($toswitch) && (!empty($ordersrooms[0]['idtar']) || $is_package || $is_cust_cost)) {
1981 foreach ($toswitch as $ksw => $rsw) {
1982 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
1983 $room_checkin = $ord['checkin'];
1984 $room_checkout = $ord['checkout'];
1985 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
1986 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
1987 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
1988 }
1989 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
1990 // the room is not available
1991 unset($toswitch[$ksw]);
1992 VikError::raiseWarning('', JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
1993 }
1994 }
1995 if (count($toswitch)) {
1996 // reset first record rate
1997 reset($ordersrooms);
1998 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
1999 $dbo->setQuery($q);
2000 $dbo->execute();
2001
2002 // flag for invoking VCM at a proper time
2003 $vcm_should_run = false;
2004
2005 foreach ($toswitch as $ksw => $rsw) {
2006 // update room reservation record
2007 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=".$rsw['to'].",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$rsw['record']['id'].";";
2008 $dbo->setQuery($q);
2009 $dbo->execute();
2010 $app->enqueueMessage(JText::sprintf('VBSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
2011
2012 // update Notes field for this booking to keep track of the previous room that was assigned
2013 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
2014 if (!empty($prev_room_name)) {
2015 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
2016 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
2017 $dbo->setQuery($q);
2018 $dbo->execute();
2019 }
2020
2021 if ($ord['status'] == 'confirmed') {
2022 // update room record in _busy
2023 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from'] && !empty($room_stay_dates[$rsw['record_ind']]['id'])) {
2024 // in case of a split stay it is fundamental to update the exact busy record ID
2025 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
2026 $dbo->setQuery($q);
2027 $dbo->execute();
2028 } else {
2029 // regular processing of a room ID for a reservation, no matter which one, we switch it
2030 $q = "SELECT `b`.`id`,`b`.`idroom`,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`idroom`=" . $rsw['from'] . " AND `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=" . $ord['id'];
2031 $dbo->setQuery($q, 0, 1);
2032 $cur_busy = $dbo->loadAssoc();
2033 if ($cur_busy) {
2034 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy['id']." AND `idroom`=".$cur_busy['idroom']." LIMIT 1;";
2035 $dbo->setQuery($q);
2036 $dbo->execute();
2037 }
2038 }
2039
2040 /**
2041 * Make sure to take care of the shared calendars before invoking VCM.
2042 * Register the flag to run the Channel Manager and leave the booking
2043 * array unchanged to run just one update request.
2044 *
2045 * @since 1.16.0 (J) - 1.6.0 (WP)
2046 */
2047 $vcm_should_run = true;
2048
2049 } elseif ($ord['status'] == 'standby') {
2050 // remove record in _tmplock
2051 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
2052 $dbo->setQuery($q);
2053 $dbo->execute();
2054 // check if it's a split stay
2055 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
2056 // update room ID in split stay data
2057 $room_stay_dates[$rsw['record_ind']]['idroom'] = $rsw['to'];
2058 // update configuration record
2059 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($room_stay_dates));
2060 }
2061 }
2062 }
2063
2064 // unset any previously booked room due to calendar sharing
2065 VikBooking::cleanSharedCalendarsBusy($ord['id']);
2066 // check if some of the rooms booked have shared calendars
2067 VikBooking::updateSharedCalendars($ord['id']);
2068
2069 if ($vcm_should_run) {
2070 // we can now run the Channel Manager after having updated the shared calendars
2071 $vcm_autosync = VikBooking::vcmAutoUpdate();
2072 if ($vcm_autosync > 0) {
2073 $vcm_obj = VikBooking::getVcmInvoker();
2074 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2075 $sync_result = $vcm_obj->doSync();
2076 if ($sync_result === false) {
2077 $vcm_err = $vcm_obj->getError();
2078 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2079 }
2080 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2081 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <form action="index.php?option=com_vikbooking" method="post"><input type="hidden" name="option" value="com_vikbooking"/><input type="hidden" name="task" value="invoke_vcm"/><input type="hidden" name="stype" value="modify"/><input type="hidden" name="cid[]" value="'.$ord['id'].'"/><input type="hidden" name="origb" value="'.urlencode(json_encode($ord)).'"/><input type="hidden" name="returl" value="'.urlencode("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '')."&cid[]=".$ord['id']).'"/><button type="submit" class="btn btn-primary">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button></form>');
2082 }
2083 }
2084
2085 //Booking History
2086 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
2087 //
2088 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2089 exit;
2090 }
2091 }
2092
2093 // update booking data
2094 $first = VikBooking::getDateTimestamp($pcheckindate, $pcheckinh, $pcheckinm);
2095 $second = VikBooking::getDateTimestamp($pcheckoutdate, $pcheckouth, $pcheckoutm);
2096 if ($second <= $first) {
2097 VikError::raiseWarning('', JText::translate('ERRPREV'));
2098 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2099 exit;
2100 }
2101
2102 $secdiff = $second - $first;
2103 $daysdiff = $secdiff / 86400;
2104 if (is_int($daysdiff)) {
2105 if ($daysdiff < 1) {
2106 $daysdiff = 1;
2107 }
2108 } else {
2109 if ($daysdiff < 1) {
2110 $daysdiff = 1;
2111 } else {
2112 $sum = floor($daysdiff) * 86400;
2113 $newdiff = $secdiff - $sum;
2114 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
2115 if ($maxhmore >= $newdiff) {
2116 $daysdiff = floor($daysdiff);
2117 } else {
2118 $daysdiff = ceil($daysdiff);
2119 }
2120 }
2121 }
2122
2123 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
2124 $opertwounits = true;
2125
2126 $units_counter = array();
2127 $prm_room_oid = VikRequest::getInt('rm_room_oid', 0, 'request');
2128 foreach ($ordersrooms as $ind => $or) {
2129 if (!isset($units_counter[$or['idroom']])) {
2130 $units_counter[$or['idroom']] = -1;
2131 }
2132 if ($prm_room_oid != $or['id']) {
2133 $units_counter[$or['idroom']]++;
2134 }
2135 }
2136
2137 /**
2138 * Split stay data for booking and rooms different stay dates.
2139 *
2140 * @since 1.16.0 (J) - 1.6.0 (WP)
2141 */
2142 $split_stay_data = VikRequest::getVar('split_stay_data', array());
2143 $room_modify_dates = VikRequest::getVar('room_modify_dates', array());
2144 $split_stay_checkins = [];
2145 $split_stay_checkouts = [];
2146
2147 if ($ord['split_stay'] && !empty($split_stay_data)) {
2148 // make sure the min/max split stay dates match the booking global dates
2149 foreach ($split_stay_data as $sps_k => $split_stay) {
2150 if (empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2151 continue;
2152 }
2153 $new_room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2154 $new_room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2155 $split_stay_checkins[] = $new_room_checkin;
2156 $split_stay_checkouts[] = $new_room_checkout;
2157 if (isset($room_stay_dates[$sps_k])) {
2158 $room_stay_dates[$sps_k]['new_checkin'] = $new_room_checkin;
2159 $room_stay_dates[$sps_k]['new_checkout'] = $new_room_checkout;
2160 $room_stay_dates[$sps_k]['new_nights'] = $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout);
2161 }
2162 }
2163 if (empty($split_stay_checkins) || empty($split_stay_checkouts)) {
2164 // error
2165 VikError::raiseWarning('', 'Error, split stay rooms must have their own stay dates matching the booking check-in and check-out dates');
2166 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2167 exit;
2168 }
2169 if (min($split_stay_checkins) != $first) {
2170 // error
2171 VikError::raiseWarning('', sprintf('Error, the earliest check-in (%s) for the split stay rooms must match the booking check-in date (%s)', date('Y-m-d H:i:s', min($split_stay_checkins)), date('Y-m-d H:i:s', $first)));
2172 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2173 exit;
2174 }
2175 if (max($split_stay_checkouts) != $second) {
2176 // error
2177 VikError::raiseWarning('', sprintf('Error, the latest check-out (%s) for the split stay rooms must match the booking check-out date (%s)', date('Y-m-d H:i:s', max($split_stay_checkouts)), date('Y-m-d H:i:s', $second)));
2178 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2179 exit;
2180 }
2181 }
2182
2183 /**
2184 * We need to make sure the sub-units of the rooms involved are not being overbooked.
2185 * In this case, we simply raise an error message by not stopping the process.
2186 *
2187 * @since 1.13.0 (J) - 1.3.0 (WP)
2188 */
2189 $subunits_involved_bids = array();
2190 //
2191
2192 foreach ($ordersrooms as $ind => $or) {
2193 $num = $ind + 1;
2194 $check = "SELECT `b`.`id`,`b`.`checkin`,`b`.`realback`,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`idroom`=" . $or['idroom'] . " AND `b`.`realback`>=" . $first . " AND `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`!=" . $ord['id'] . ";";
2195 $dbo->setQuery($check);
2196 $busy = $dbo->loadAssocList();
2197 if ($busy) {
2198 // determine the days to consider for the count of the availability
2199 $use_groupdays = $groupdays;
2200 $room_checkin = $first;
2201 $room_checkout = $second;
2202 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom'] && !empty($room_stay_dates[$ind]['new_nights'])) {
2203 $use_groupdays = VikBooking::getGroupDays($room_stay_dates[$ind]['new_checkin'], $room_stay_dates[$ind]['new_checkout'], $room_stay_dates[$ind]['new_nights']);
2204 $room_checkin = $room_stay_dates[$ind]['new_checkin'];
2205 $room_checkout = $room_stay_dates[$ind]['new_checkout'];
2206 } elseif (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1 && $ord['status'] == 'confirmed' && VikRequest::getInt('room_modify_dates' . $ind, 0, 'request')) {
2207 // room may have individual stay dates
2208 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2209 // get new stay dates (if changed)
2210 $new_room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2211 $new_room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2212 $use_groupdays = VikBooking::getGroupDays($new_room_checkin, $new_room_checkout, $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout));
2213 $room_checkin = $new_room_checkin;
2214 $room_checkout = $new_room_checkout;
2215 }
2216 }
2217
2218 foreach ($use_groupdays as $gday) {
2219 // count units booked for each stay timestamp
2220 $bfound = 0;
2221 foreach ($busy as $bu) {
2222 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
2223 // increase units booked found
2224 $bfound++;
2225 // keep track of the IDs involved to avoid overbooking for the sub-units
2226 if (!empty($or['roomindex'])) {
2227 if (!isset($subunits_involved_bids[$bu['idorder']])) {
2228 $subunits_involved_bids[$bu['idorder']] = array();
2229 }
2230 array_push($subunits_involved_bids[$bu['idorder']], array(
2231 'idroom' => $or['idroom'],
2232 'roomindex' => $or['roomindex'],
2233 ));
2234 }
2235 }
2236 }
2237
2238 // units booked must be greater than zero in case of split stays involving the same room multiple times
2239 $detract_multi_units = $units_counter[$or['idroom']];
2240 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
2241 // split stay bookings never occupy the same room on the same dates
2242 $detract_multi_units = 0;
2243 }
2244 if ($bfound > 0 && $bfound >= ($or['units'] - $detract_multi_units)) {
2245 $opertwounits = false;
2246 break 2;
2247 }
2248
2249 // make sure the room is not temporarily locked while waiting to be paid/confirmed
2250 if ($ord['status'] == 'confirmed' && !VikBooking::roomNotLocked($or['idroom'], $or['units'], $room_checkin, $room_checkout)) {
2251 $opertwounits = false;
2252 break 2;
2253 }
2254 }
2255 }
2256 }
2257
2258 /**
2259 * Make sure no sub-units are overbooked even though the main room is available.
2260 *
2261 * @since 1.13.0 (J) - 1.3.0 (WP)
2262 */
2263 if ($opertwounits === true && count($subunits_involved_bids)) {
2264 $subunits_involved_bids = array_unique($subunits_involved_bids);
2265 // grab all the information about the bids involved and the related rooms/indexes
2266 $q = "SELECT `or`.`idorder`, `or`.`idroom`, `or`.`roomindex`, `o`.`checkin`, `o`.`checkout`, `r`.`name`, `r`.`params`
2267 FROM `#__vikbooking_ordersrooms` AS `or` LEFT JOIN `#__vikbooking_orders` AS `o` ON `or`.`idorder`=`o`.`id`
2268 LEFT JOIN `#__vikbooking_rooms` AS `r` ON `or`.`idroom`=`r`.`id`
2269 WHERE `or`.`idorder` IN (" . implode(', ', array_keys($subunits_involved_bids)) . ");";
2270 $dbo->setQuery($q);
2271 $involved_data = $dbo->loadAssocList();
2272 if ($involved_data) {
2273 foreach ($involved_data as $invb) {
2274 if (empty($invb['roomindex'])) {
2275 continue;
2276 }
2277 foreach ($subunits_involved_bids[$invb['idorder']] as $bookedindex) {
2278 if ($bookedindex['idroom'] == $invb['idroom'] && $bookedindex['roomindex'] == $invb['roomindex']) {
2279 // this same sub-unit is occupied by this booking ID: raise an error message to inform the administrator
2280 $subunit_name = $invb['roomindex'];
2281 $room_params = json_decode($invb['params'], true);
2282 if (is_array($room_params) && isset($room_params['features']) && @count($room_params['features'])) {
2283 foreach ($room_params['features'] as $rind => $rfeatures) {
2284 if ($rind == $invb['roomindex']) {
2285 foreach ($rfeatures as $fname => $fval) {
2286 if (strlen($fval)) {
2287 $subunit_name = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
2288 break;
2289 }
2290 }
2291 }
2292 }
2293 }
2294 $adjust_link = '<br/><a class="btn btn-danger" target="_blank" href="index.php?option=com_vikbooking&task=editorder&cid[]=' . $invb['idorder'] . '">' . JText::translate('VBOSUBUNITOVERBOOKEDGOTO') . '</a>';
2295 VikError::raiseWarning('', JText::sprintf('VBOSUBUNITOVERBOOKEDERR', $subunit_name, $invb['name'], date($df, $invb['checkin']), date($df, $invb['checkout']), $invb['idorder']) . $adjust_link);
2296 }
2297 }
2298 }
2299 }
2300 }
2301
2302 $forcebooking = VikRequest::getInt('forcebooking', 0, 'request');
2303 if ($opertwounits === true || $forcebooking) {
2304 // update dates, customer information, amount paid and busy records before checking the rates
2305 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
2306 $realback = $turnover_secs + $second;
2307
2308 $newtotalpaid = strlen($ptotpaid) > 0 ? floatval($ptotpaid) : "";
2309 $newrefund = strlen($prefund) > 0 ? floatval($prefund) : null;
2310 $roomsnum = $ord['roomsnum'];
2311
2312 // add room to existing booking
2313 $room_added = false;
2314 $padd_room_id = VikRequest::getInt('add_room_id', '', 'request');
2315 $padd_room_adults = VikRequest::getInt('add_room_adults', 2, 'request');
2316 $padd_room_children = VikRequest::getInt('add_room_children', 0, 'request');
2317 $padd_room_fname = VikRequest::getString('add_room_fname', '', 'request');
2318 $padd_room_lname = VikRequest::getString('add_room_lname', '', 'request');
2319 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2320 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2321 if ($padd_room_id > 0 && ($padd_room_adults + $padd_room_children) > 0) {
2322 // no need to re-validate the availability for this new room, as it was made via JS in the View.
2323 // increase the rooms number for later update, and insert the new room record
2324 $roomsnum++;
2325 $q = "INSERT INTO `#__vikbooking_ordersrooms` (`idorder`,`idroom`,`adults`,`children`,`t_first_name`,`t_last_name`,`cust_cost`,`cust_idiva`) VALUES(".$ord['id'].", ".$padd_room_id.", ".$padd_room_adults.", ".$padd_room_children.", ".$dbo->quote($padd_room_fname).", ".$dbo->quote($padd_room_lname).", ".($padd_room_price > 0 ? $dbo->quote($padd_room_price) : 'NULL').", ".($padd_room_price > 0 && !empty($paliq_add_room) ? $dbo->quote($paliq_add_room) : 'NULL').");";
2326 $dbo->setQuery($q);
2327 $dbo->execute();
2328 $room_added = true;
2329 }
2330
2331 // remove room from existing booking
2332 $room_removed = false;
2333 $room_removed_index = null;
2334 if ($prm_room_oid > 0 && $roomsnum > 1) {
2335 // check if the requested room record exists for removal
2336 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id'].";";
2337 $dbo->setQuery($q);
2338 $room_before_rm = $dbo->loadAssoc();
2339 if ($room_before_rm) {
2340 // decrease the rooms number for later update, and remove the requested room record
2341 $roomsnum--;
2342 // find the index of this room in the current list before removal
2343 foreach ($ordersrooms as $kor => $or) {
2344 if ($or['id'] == $prm_room_oid) {
2345 $room_removed_index = $kor;
2346 break;
2347 }
2348 }
2349 // go ahead with the deletion of the room record
2350 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id']." LIMIT 1;";
2351 $dbo->setQuery($q);
2352 $dbo->execute();
2353 $room_removed = $room_before_rm['idroom'];
2354 }
2355 }
2356
2357 if ($ord['split_stay'] && !empty($split_stay_data) && count($split_stay_checkins) && ($room_added !== false || $room_removed !== false)) {
2358 // split stay booking (even if only 1 room left) and one room was either added or removed: set new global stay dates
2359 if ($room_removed !== false && isset($room_removed_index) && isset($split_stay_checkins[$room_removed_index])) {
2360 // exclude the split stay dates of this room that was just removed
2361 unset($split_stay_checkins[$room_removed_index], $split_stay_checkouts[$room_removed_index]);
2362 }
2363 if (count($split_stay_checkins) && count($split_stay_checkouts)) {
2364 // if we still have rooms, and we should, update the booking global stay dates
2365 $first = min($split_stay_checkins);
2366 $second = max($split_stay_checkouts);
2367 $daysdiff = $av_helper->countNightsOfStay($first, $second);
2368 }
2369 }
2370
2371 // update booking's basic information (customer data, dates, tot paid, number of rooms, refund)
2372 $basic_booking = new stdClass;
2373 $basic_booking->id = $ord['id'];
2374 $basic_booking->custdata = $pcustdata;
2375 $basic_booking->days = (int)$daysdiff;
2376 $basic_booking->checkin = $first;
2377 $basic_booking->checkout = $second;
2378 if (strlen($newtotalpaid) > 0) {
2379 $basic_booking->totpaid = $newtotalpaid;
2380 }
2381 $basic_booking->roomsnum = (int)$roomsnum;
2382 if ($newrefund !== null) {
2383 $basic_booking->refund = $newrefund;
2384 }
2385 if ($ord['split_stay'] && $roomsnum < 2 && $room_removed !== false) {
2386 // there is no point in keep treating this reservation as a split stay
2387 $basic_booking->split_stay = 0;
2388 }
2389 $dbo->updateObject('#__vikbooking_orders', $basic_booking, 'id');
2390
2391 // Booking History log for new amount paid (payment update)
2392 if ($newtotalpaid > 0 && $newtotalpaid > (float)$ord['totpaid']) {
2393 $extra_data = new stdClass;
2394 $extra_data->amount_paid = ($newtotalpaid - (float)$ord['totpaid']);
2395 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$ord['totpaid'])));
2396 }
2397
2398 // booking history log for new refund amount
2399 if ($newrefund !== null && $newrefund != (float)$ord['refund']) {
2400 // update current refund value
2401 $ord['refund'] = $newrefund;
2402 // store event
2403 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData(null)->store('RU', JText::sprintf('VBO_NEWREFUND_AMOUNT', VikBooking::numberFormat($ord['refund']), VikBooking::numberFormat($newrefund)));
2404 }
2405
2406 // update busy records
2407 if ($ord['status'] == 'confirmed') {
2408 $allbusy = [];
2409 if ($ord['split_stay'] && !empty($split_stay_data)) {
2410 // in case of split stay we need to update the busy records according to the nights selected
2411 foreach ($split_stay_data as $sps_k => $split_stay) {
2412 if (empty($split_stay['idbusy']) || empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2413 // missing data
2414 continue;
2415 }
2416 // get selected dates
2417 $room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2418 $room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2419 $room_realback = $turnover_secs + $room_checkout;
2420 // update the exact record
2421 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$split_stay['idbusy'] . ";";
2422 $dbo->setQuery($q);
2423 $dbo->execute();
2424 }
2425 } else {
2426 // regularly update busy records for all rooms involved
2427 $q = "SELECT `b`.`id`,`b`.`idroom` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=" . $ord['id'] . ";";
2428 $dbo->setQuery($q);
2429 $allbusy = $dbo->loadAssocList();
2430 foreach ($allbusy as $bb) {
2431 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $first . ", `checkout`=" . $second . ", `realback`=" . $realback . " WHERE `id`=" . $bb['id'] . ";";
2432 $dbo->setQuery($q);
2433 $dbo->execute();
2434 }
2435 }
2436
2437 /**
2438 * Check if some rooms have modified stay dates different than the booking stay dates.
2439 *
2440 * @since 1.16.0 (J) - 1.6.0 (WP)
2441 */
2442 if (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1) {
2443 // load the occupied stay dates for each room in case they were modified
2444 $room_stay_records = $av_helper->loadSplitStayBusyRecords($ord['id']);
2445 // loop over all rooms to check the requested operations
2446 foreach ($ordersrooms as $ind => $or) {
2447 if (!VikRequest::getInt('room_modify_dates' . $ind, 0, 'request') || !isset($room_stay_records[$ind]) || empty($room_stay_records[$ind]['id'])) {
2448 // toggle is disabled or data is missing
2449 continue;
2450 }
2451 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2452 // calculate the check-in and check-out timestamps, we expect them to be different from the global booking dates
2453 $room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2454 $room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2455 $room_realback = $turnover_secs + $room_checkout;
2456 // we don't need to check if the dates are different, we just update the record
2457 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$room_stay_records[$ind]['id'] . ";";
2458 $dbo->setQuery($q);
2459 $dbo->execute();
2460 // inject new room stay timestamps
2461 $ordersrooms[$ind]['modified_checkin'] = $room_checkin;
2462 $ordersrooms[$ind]['modified_checkout'] = $room_checkout;
2463 }
2464 }
2465 }
2466
2467 // add room to existing (confirmed) booking
2468 if ($room_added === true) {
2469 // add busy record for the new room unit
2470 $q = "INSERT INTO `#__vikbooking_busy` (`idroom`,`checkin`,`checkout`,`realback`) VALUES(".$padd_room_id.", ".$dbo->quote($first).", ".$dbo->quote($second).", ".$dbo->quote($realback).");";
2471 $dbo->setQuery($q);
2472 $dbo->execute();
2473 $newbusyid = $dbo->insertid();
2474 $q = "INSERT INTO `#__vikbooking_ordersbusy` (`idorder`,`idbusy`) VALUES(".$ord['id'].", ".(int)$newbusyid.");";
2475 $dbo->setQuery($q);
2476 $dbo->execute();
2477 }
2478
2479 // remove room from existing (confirmed) booking
2480 if ($room_removed !== false) {
2481 // remove busy record for the removed room
2482 if ($ord['split_stay'] && !empty($split_stay_data) && !empty($room_removed_index)) {
2483 // in case of split stay we want to remove the exact dates of the previously booked room
2484 if (count($room_stay_dates) && isset($room_stay_dates[$room_removed_index]) && $room_stay_dates[$room_removed_index]['idroom'] == $room_removed && !empty($room_stay_dates[$room_removed_index]['id'])) {
2485 // remove the exact records
2486 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=" . $room_stay_dates[$room_removed_index]['id'] . " AND `idroom`=" . $room_removed . ";";
2487 $dbo->setQuery($q);
2488 $dbo->execute();
2489 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=" . $ord['id'] . " AND `idbusy`=" . $room_stay_dates[$room_removed_index]['id'] . ";";
2490 $dbo->setQuery($q);
2491 $dbo->execute();
2492 }
2493 } else {
2494 // regularly remove the first matching room
2495 foreach ($allbusy as $bb) {
2496 if ($bb['idroom'] == $room_removed) {
2497 // remove the first room with this ID that was booked
2498 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=".$bb['id']." AND `idroom`=".$room_removed.";";
2499 $dbo->setQuery($q);
2500 $dbo->execute();
2501 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".$ord['id']." AND `idbusy`=".$bb['id'].";";
2502 $dbo->setQuery($q);
2503 $dbo->execute();
2504 break;
2505 }
2506 }
2507 }
2508 }
2509
2510 if ($ord['checkin'] != $first || $ord['checkout'] != $second || $room_added === true || $room_removed !== false) {
2511 // unset any previously booked room due to calendar sharing
2512 VikBooking::cleanSharedCalendarsBusy($ord['id']);
2513 // check if some of the rooms booked have shared calendars
2514 VikBooking::updateSharedCalendars($ord['id'], array(), $first, $second);
2515
2516 // invoke Channel Manager
2517 $vcm_autosync = VikBooking::vcmAutoUpdate();
2518 if ($vcm_autosync > 0) {
2519 $vcm_obj = VikBooking::getVcmInvoker();
2520 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2521 $sync_result = $vcm_obj->doSync();
2522 if ($sync_result === false) {
2523 $vcm_err = $vcm_obj->getError();
2524 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2525 }
2526 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2527 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <form action="index.php?option=com_vikbooking" method="post"><input type="hidden" name="option" value="com_vikbooking"/><input type="hidden" name="task" value="invoke_vcm"/><input type="hidden" name="stype" value="modify"/><input type="hidden" name="cid[]" value="'.$ord['id'].'"/><input type="hidden" name="origb" value="'.urlencode(json_encode($ord)).'"/><input type="hidden" name="returl" value="'.urlencode("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '')."&cid[]=".$ord['id']).'"/><button type="submit" class="btn btn-primary">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button></form>');
2528 }
2529 //
2530 }
2531 }
2532
2533 $upd_esit = JText::translate('RESUPDATED');
2534
2535 // update the room rates
2536 $isdue = 0;
2537 $tot_taxes = 0;
2538 $tot_city_taxes = 0;
2539 $tot_fees = 0;
2540 $doup = true;
2541 $tars = array();
2542 $cust_costs = array();
2543 $rooms_costs_map = array();
2544 $arrpeople = array();
2545 foreach ($ordersrooms as $kor => $or) {
2546 // remove from existing booking
2547 if ($room_removed !== false) {
2548 if ($or['id'] == $prm_room_oid) {
2549 // do not consider this room for the calculation of the new total amount
2550 // we can unset this array for later use, because the channel manager has already been invoked.
2551 unset($ordersrooms[$kor]);
2552 continue;
2553 }
2554 }
2555
2556 // room index starting from 1
2557 $num = $kor + 1;
2558
2559 // default values to be considered
2560 $room_nights = $daysdiff;
2561 $room_checkin = $ord['checkin'];
2562 $room_checkout = $ord['checkout'];
2563 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom'] && !empty($room_stay_dates[$kor]['new_nights'])) {
2564 $room_nights = $room_stay_dates[$kor]['new_nights'];
2565 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2566 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2567 }
2568
2569 $padults = VikRequest::getString('adults' . $num, '', 'request');
2570 $pchildren = VikRequest::getString('children' . $num, '', 'request');
2571 $ppets = VikRequest::getInt('pets' . $num, 0, 'request');
2572 if (strlen($padults) || strlen($pchildren)) {
2573 $arrpeople[$num]['adults'] = (int)$padults;
2574 $arrpeople[$num]['children'] = (int)$pchildren;
2575 $arrpeople[$num]['pets'] = $ppets;
2576 }
2577 $ppriceid = VikRequest::getString('priceid'.$num, '', 'request');
2578 $polderpriceid = VikRequest::getString('olderpriceid'.$num, '', 'request');
2579 $ppkgid = VikRequest::getString('pkgid'.$num, '', 'request');
2580 $pcust_cost = VikRequest::getString('cust_cost'.$num, '', 'request');
2581 $paliq = VikRequest::getString('aliq'.$num, '', 'request');
2582 if ($is_package === true && !empty($ppkgid)) {
2583 $pkg_cost = $or['cust_cost'];
2584 $pkg_idiva = $or['cust_idiva'];
2585 $pkg_info = VikBooking::getPackage($ppkgid);
2586 if (is_array($pkg_info) && count($pkg_info) > 0) {
2587 $use_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : $or['adults'];
2588 $pkg_cost = $pkg_info['pernight_total'] == 1 ? ($pkg_info['cost'] * $room_nights) : $pkg_info['cost'];
2589 $pkg_cost = $pkg_info['perperson'] == 1 ? ($pkg_cost * ($use_adults > 0 ? $use_adults : 1)) : $pkg_cost;
2590 $pkg_cost = VikBooking::sayPackagePlusIva($pkg_cost, $pkg_info['idiva']);
2591 }
2592 $cust_costs[$num] = array('pkgid' => $ppkgid, 'cust_cost' => $pkg_cost, 'aliq' => $pkg_idiva);
2593 $isdue += $pkg_cost;
2594 $cost_minus_tax = VikBooking::sayPackageMinusIva($pkg_cost, $pkg_idiva);
2595 $tot_taxes += ($pkg_cost - $cost_minus_tax);
2596 continue;
2597 }
2598 if (empty($ppriceid) && !empty($pcust_cost) && floatval($pcust_cost) > 0) {
2599 $cust_costs[$num] = array('cust_cost' => $pcust_cost, 'aliq' => $paliq);
2600 $cost_after_tax = VikBooking::sayPackagePlusIva((float)$pcust_cost, (int)$paliq);
2601 $isdue += $cost_after_tax;
2602 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$pcust_cost, (int)$paliq);
2603 $tot_taxes += ($cost_after_tax - $cost_minus_tax);
2604 continue;
2605 }
2606
2607 // load room rates for the requested rate plan and nights
2608 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `idroom`=" . (int)$or['idroom'] . " AND `days`=" . $room_nights . " AND `idprice`=" . (int)$ppriceid . ";";
2609 $dbo->setQuery($q);
2610 $tar = $dbo->loadAssocList();
2611 if (!$tar) {
2612 $doup = false;
2613 break;
2614 }
2615
2616 /**
2617 * The current price may be different from the price paid at the time of booking.
2618 * Check whether it has been asked to keep the old price of the time of booking.
2619 *
2620 * @since 1.13.0 (J) - 1.3.0 (WP)
2621 */
2622 $old_price_used = false;
2623 if (!empty($polderpriceid)) {
2624 $older_info = explode(':', $polderpriceid);
2625 if ((int)$older_info[0] == (int)$ppriceid) {
2626 $old_price = isset($older_info[1]) ? (float)$older_info[1] : 0;
2627 if ($old_price > 0) {
2628 // we override the 'cost' property of the tar array by taking the previous cost
2629 $old_price_used = true;
2630 $tar[0]['cost'] = $old_price;
2631 }
2632 }
2633 }
2634
2635 if (!$old_price_used) {
2636 // apply seasonal rates
2637 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
2638 }
2639
2640 // different usage
2641 if (!$old_price_used && $or['fromadult'] <= $or['adults'] && $or['toadult'] >= $or['adults']) {
2642 // apply OBP rules
2643 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
2644 }
2645
2646 $cost_plus_tax = VikBooking::sayCostPlusIva($tar[0]['cost'], $tar[0]['idprice']);
2647 $isdue += $cost_plus_tax;
2648 if ($cost_plus_tax == $tar[0]['cost']) {
2649 $cost_minus_tax = VikBooking::sayCostMinusIva($tar[0]['cost'], $tar[0]['idprice']);
2650 $tot_taxes += ($tar[0]['cost'] - $cost_minus_tax);
2651 } else {
2652 $tot_taxes += ($cost_plus_tax - $tar[0]['cost']);
2653 }
2654 $tars[$num] = $tar;
2655 $rooms_costs_map[$num] = $tar[0]['cost'];
2656 }
2657
2658 if ($doup === true) {
2659 if ($room_added === true) {
2660 // add room to existing booking may require to increase the total amount, and taxes
2661 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2662 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2663 if (!empty($padd_room_price) && floatval($padd_room_price) > 0) {
2664 $isdue += (float)$padd_room_price;
2665 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$padd_room_price, (int)$paliq_add_room);
2666 $tot_taxes += ((float)$padd_room_price - $cost_minus_tax);
2667 }
2668 }
2669
2670 // load options
2671 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
2672 $dbo->setQuery($q);
2673 $toptionals = $dbo->loadAssocList();
2674
2675 foreach ($ordersrooms as $kor => $or) {
2676 $num = $kor + 1;
2677
2678 // default values to be considered
2679 $room_nights = $daysdiff;
2680 $room_checkin = $ord['checkin'];
2681 $room_checkout = $ord['checkout'];
2682 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom'] && !empty($room_stay_dates[$kor]['new_nights'])) {
2683 $room_nights = $room_stay_dates[$kor]['new_nights'];
2684 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2685 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2686 }
2687
2688 $pt_first_name = VikRequest::getString('t_first_name'.$num, '', 'request');
2689 $pt_last_name = VikRequest::getString('t_last_name'.$num, '', 'request');
2690 $wop = "";
2691
2692 foreach ($toptionals as $opt) {
2693 if (!empty($opt['ageintervals']) && ($or['children'] > 0 || (array_key_exists($num, $arrpeople) && array_key_exists('children', $arrpeople[$num]))) ) {
2694 $tmpvar = VikRequest::getInt('optid'.$num.$opt['id'], []);
2695 if (is_array($tmpvar) && $tmpvar) {
2696 $opt['quan'] = 1;
2697 $optagenames = VikBooking::getOptionIntervalsAges($opt['ageintervals']);
2698 $optagepcent = VikBooking::getOptionIntervalsPercentage($opt['ageintervals']);
2699 $optageovrct = VikBooking::getOptionIntervalChildOverrides($opt, (isset($arrpeople[$num]) ? $arrpeople[$num]['adults'] : 0), (isset($arrpeople[$num]) ? $arrpeople[$num]['children'] : 0));
2700 $optorigname = $opt['name'];
2701 foreach ($tmpvar as $child_num => $chvar) {
2702 $ageintervals_child_string = isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $opt['ageintervals'];
2703 $optagecosts = VikBooking::getOptionIntervalsCosts($ageintervals_child_string);
2704 $optorigcost = $optagecosts[($chvar - 1)];
2705 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
2706 //percentage value of the adults tariff
2707 if ($is_package !== true && array_key_exists($num, $tars)) {
2708 //type of price
2709 $optorigcost = $tars[$num][0]['cost'] * $optagecosts[($chvar - 1)] / 100;
2710 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2711 //package
2712 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2713 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2714 //custom rate + custom tax rate
2715 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2716 }
2717 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
2718 //VBO 1.10 - percentage value of room base cost
2719 if ($is_package !== true && array_key_exists($num, $tars)) {
2720 //type of price
2721 $usecost = isset($tars[$num][0]['room_base_cost']) ? $tars[$num][0]['room_base_cost'] : $tars[$num][0]['cost'];
2722 $optorigcost = $usecost * $optagecosts[($chvar - 1)] / 100;
2723 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2724 //package
2725 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2726 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2727 //custom rate + custom tax rate
2728 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2729 }
2730 }
2731 $opt['cost'] = $optorigcost;
2732 $opt['name'] = $optorigname.' ('.$optagenames[($chvar - 1)].')';
2733 $opt['chageintv'] = $chvar;
2734 $wop.=$opt['id'].":".$opt['quan']."-".$chvar.";";
2735 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $opt['quan']) : ($opt['cost'] * $opt['quan']));
2736 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2737 $realcost = $opt['maxprice'];
2738 }
2739 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2740 if ($opt['is_citytax'] == 1) {
2741 $tot_city_taxes += $tmpopr;
2742 } elseif ($opt['is_fee'] == 1) {
2743 $tot_fees += $tmpopr;
2744 }
2745 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2746 if ($tmpopr == $realcost) {
2747 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
2748 $tot_taxes += ($realcost - $opt_minus_iva);
2749 } else {
2750 $tot_taxes += ($tmpopr - $realcost);
2751 }
2752 //
2753 $isdue += $tmpopr;
2754 }
2755 }
2756 } else {
2757 $tmpvar = VikRequest::getString('optid'.$num.$opt['id'], '', 'request');
2758 //options forced per child fix, no age intervals, like children tourist taxes
2759 $forcedquan = 1;
2760 $forceperday = false;
2761 $forceperchild = false;
2762 if (intval($opt['forcesel']) == 1 && strlen($opt['forceval']) > 0 && strlen($tmpvar) > 0) {
2763 $forceparts = explode("-", $opt['forceval']);
2764 $forcedquan = intval($forceparts[0]);
2765 $forceperday = intval($forceparts[1]) == 1 ? true : false;
2766 $forceperchild = intval($forceparts[2]) == 1 ? true : false;
2767 $tmpvar = $forcedquan;
2768 $tmpvar = $forceperchild === true && array_key_exists($num, $arrpeople) && array_key_exists('children', $arrpeople[$num]) ? ($tmpvar * $arrpeople[$num]['children']) : $tmpvar;
2769 }
2770 //
2771 if (!empty($tmpvar)) {
2772 $wop .= $opt['id'].":".$tmpvar.";";
2773 // VBO 1.11 - options percentage cost of the room total fee
2774 if ($is_package !== true && array_key_exists($num, $tars)) {
2775 //type of price
2776 $deftar_basecosts = $tars[$num][0]['cost'];
2777 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2778 //package
2779 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2780 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2781 //custom rate + custom tax rate
2782 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2783 }
2784 $opt['cost'] = (int)$opt['pcentroom'] ? ($deftar_basecosts * $opt['cost'] / 100) : $opt['cost'];
2785 //
2786 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $tmpvar) : ($opt['cost'] * $tmpvar));
2787 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2788 $realcost = $opt['maxprice'];
2789 if (intval($opt['hmany']) == 1 && intval($tmpvar) > 1) {
2790 $realcost = $opt['maxprice'] * $tmpvar;
2791 }
2792 }
2793 if ($opt['perperson'] == 1) {
2794 $num_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : 1;
2795 $realcost = $realcost * $num_adults;
2796 }
2797 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2798 if ($opt['is_citytax'] == 1) {
2799 $tot_city_taxes += $tmpopr;
2800 } elseif ($opt['is_fee'] == 1) {
2801 $tot_fees += $tmpopr;
2802 }
2803 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2804 if ($tmpopr == $realcost) {
2805 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
2806 $tot_taxes += ($realcost - $opt_minus_iva);
2807 } else {
2808 $tot_taxes += ($tmpopr - $realcost);
2809 }
2810 //
2811 $isdue += $tmpopr;
2812 }
2813 }
2814 }
2815
2816 $upd_fields = array();
2817 if ($is_package !== true && array_key_exists($num, $tars)) {
2818 // type of price
2819 $upd_fields[] = "`idtar`='".$tars[$num][0]['id']."'";
2820 $upd_fields[] = "`cust_cost`=NULL";
2821 $upd_fields[] = "`cust_idiva`=NULL";
2822 $upd_fields[] = "`room_cost`=".(array_key_exists($num, $rooms_costs_map) ? $dbo->quote($rooms_costs_map[$num]) : "NULL");
2823 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2824 // packages do not update name or cost, just set again the same package ID to avoid risks of empty upd_fields to update
2825 $upd_fields[] = "`idtar`=NULL";
2826 $upd_fields[] = "`pkg_id`='".$cust_costs[$num]['pkgid']."'";
2827 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
2828 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
2829 $upd_fields[] = "`room_cost`=NULL";
2830 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2831 // custom rate + custom tax rate
2832 $upd_fields[] = "`idtar`=NULL";
2833 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
2834 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
2835 $upd_fields[] = "`room_cost`=NULL";
2836 // inject new room price
2837 $ordersrooms[$kor]['modified_price'] = $cust_costs[$num]['cust_cost'];
2838 }
2839 if ($toptionals) {
2840 $upd_fields[] = "`optionals`='".$wop."'";
2841 }
2842 if (!empty($pt_first_name) || !empty($pt_last_name)) {
2843 $upd_fields[] = "`t_first_name`=".$dbo->quote($pt_first_name);
2844 $upd_fields[] = "`t_last_name`=".$dbo->quote($pt_last_name);
2845 }
2846 if (array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num])) {
2847 $upd_fields[] = "`adults`=".intval($arrpeople[$num]['adults']);
2848 $upd_fields[] = "`children`=".intval($arrpeople[$num]['children']);
2849 if (isset($arrpeople[$num]['pets'])) {
2850 $upd_fields[] = "`pets`=" . $arrpeople[$num]['pets'];
2851 }
2852 }
2853
2854 /**
2855 * Meal plans at room-reservation level.
2856 *
2857 * @since 1.16.1 (J) - 1.6.1 (WP)
2858 */
2859 $pmealplans = VikRequest::getVar('mealplan' . $num, []);
2860 $upd_fields[] = "`meals`=" . ($pmealplans ? $dbo->q(json_encode($pmealplans)) : 'NULL');
2861
2862 // calculate the extra costs and increase taxes + isdue
2863 $extracosts_arr = array();
2864 if (count($pextracn) && isset($pextracn[$num]) && count($pextracn[$num])) {
2865 foreach ($pextracn[$num] as $eck => $ecn) {
2866 if ($ecn && array_key_exists($eck, $pextracc[$num]) && is_numeric($pextracc[$num][$eck])) {
2867 $ecidtax = array_key_exists($eck, $pextractx[$num]) && intval($pextractx[$num][$eck]) > 0 ? (int)$pextractx[$num][$eck] : '';
2868 $extracosts_arr[] = array(
2869 'name' => $ecn,
2870 'cost' => (float)$pextracc[$num][$eck],
2871 'idtax' => $ecidtax,
2872 'type' => isset($pextractype[$num][$eck]) ? $pextractype[$num][$eck] : '',
2873 'fk' => isset($pextracfk[$num][$eck]) ? (string)$pextracfk[$num][$eck] : '',
2874 'data' => isset($pextracdata[$num][$eck]) ? json_decode($pextracdata[$num][$eck]) : null,
2875 );
2876 $ecplustax = !empty($ecidtax) ? VikBooking::sayOptionalsPlusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
2877 $ecminustax = !empty($ecidtax) ? VikBooking::sayOptionalsMinusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
2878 $ectottax = (float)$pextracc[$num][$eck] - $ecminustax;
2879 $isdue += $ecplustax;
2880 $tot_taxes += $ectottax;
2881 }
2882 }
2883 }
2884
2885 if ($extracosts_arr) {
2886 $upd_fields[] = "`extracosts`=".$dbo->quote(json_encode($extracosts_arr));
2887 } else {
2888 $upd_fields[] = "`extracosts`=NULL";
2889 }
2890
2891 if ($upd_fields) {
2892 $q = "UPDATE `#__vikbooking_ordersrooms` SET ".implode(', ', $upd_fields)." WHERE `idorder`=".$ord['id']." AND `idroom`='".$or['idroom']."' AND `id`='".$or['id']."';";
2893 $dbo->setQuery($q);
2894 $dbo->execute();
2895 }
2896 }
2897
2898 // update split stay transient record if not confirmed booking
2899 if ($ord['split_stay'] && $ord['status'] != 'confirmed' && !empty($room_stay_dates) && !empty($split_stay_data)) {
2900 /**
2901 * Important: if no rates have been selected for all rooms, we won't enter this inner statement.
2902 * It is necessary to select a rate plan for each room in order to update the split stay data.
2903 */
2904 $new_room_stay_dates = [];
2905 foreach ($room_stay_dates as $kor => $room_stay_info) {
2906 // clone the current information
2907 $clean_room_stay_info = $room_stay_info;
2908 // set new stay values
2909 if (!empty($clean_room_stay_info['checkin_ts'])) {
2910 $clean_room_stay_info['checkin_ts'] = $clean_room_stay_info['new_checkin'];
2911 $clean_room_stay_info['checkout_ts'] = $clean_room_stay_info['new_checkout'];
2912 } else {
2913 $clean_room_stay_info['checkin'] = $clean_room_stay_info['new_checkin'];
2914 $clean_room_stay_info['checkout'] = $clean_room_stay_info['new_checkout'];
2915 }
2916 $clean_room_stay_info['nights'] = $clean_room_stay_info['new_nights'];
2917 // clean up unnecessary keys
2918 unset($clean_room_stay_info['new_checkin'], $clean_room_stay_info['new_checkout'], $clean_room_stay_info['new_nights']);
2919 // push new array info
2920 $new_room_stay_dates[$kor] = $clean_room_stay_info;
2921 }
2922 // update configuration record
2923 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($new_room_stay_dates));
2924 }
2925
2926 // make sure to re-apply the discount with the coupon code
2927 if ($ord['coupon']) {
2928 $expcoupon = explode(";", $ord['coupon']);
2929 $isdue -= $expcoupon[1];
2930 }
2931
2932 // make sure to apply any previously refunded amount
2933 if ($ord['refund'] > 0) {
2934 $isdue -= $ord['refund'];
2935 }
2936
2937 // update totals
2938 $q = "UPDATE `#__vikbooking_orders` SET `total`='".$isdue."', `tot_taxes`='".$tot_taxes."', `tot_city_taxes`='".$tot_city_taxes."', `tot_fees`='".$tot_fees."' WHERE `id`=".$ord['id'].";";
2939 $dbo->setQuery($q);
2940 $dbo->execute();
2941 $upd_esit = JText::translate('VBORESRATESUPDATED');
2942
2943 // Customer Booking
2944 if ($ord['status'] == 'confirmed') {
2945 $q = "SELECT `idcustomer` FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$ord['id'].";";
2946 $dbo->setQuery($q);
2947 $customer_id = $dbo->loadResult();
2948 if ($customer_id) {
2949 $cpin = VikBooking::getCPinIstance();
2950 $cpin->is_admin = true;
2951 $cpin->updateBookingCommissions($ord['id'], $customer_id);
2952 }
2953 }
2954
2955 /**
2956 * Check for any OTA reporting action.
2957 *
2958 * @since 1.16.8 (J) - 1.6.8 (WP)
2959 */
2960 if (class_exists('VCMOtaReporting') && VCMOtaReporting::getInstance($ord)->stayChangeAllowed()) {
2961 // check if an OTA reporting action was selected
2962 $ota_stay_change_data = [];
2963 $ota_stay_change_all = $app->input->getInt('ota_stay_change_all', 0);
2964 foreach ($ordersrooms as $kor => $or) {
2965 $ota_stay_change_room = [];
2966 if ($ota_stay_change_all) {
2967 // set room data for stay change
2968 $ota_stay_change_room = [
2969 'idroom' => $or['idroom'],
2970 'checkin' => date('Y-m-d', $first),
2971 'checkout' => date('Y-m-d', $second),
2972 ];
2973 if (isset($or['modified_price'])) {
2974 $ota_stay_change_room['price'] = $or['modified_price'];
2975 }
2976 } elseif ($app->input->getInt('ota_stay_change_room_' . $kor, 0) && !empty($or['modified_checkin']) && !empty($or['modified_checkout'])) {
2977 // set room index data for stay change
2978 $ota_stay_change_room = [
2979 'idroom' => $or['idroom'],
2980 'index' => $kor,
2981 'checkin' => date('Y-m-d', $or['modified_checkin']),
2982 'checkout' => date('Y-m-d', $or['modified_checkout']),
2983 ];
2984 if (isset($or['modified_price'])) {
2985 $ota_stay_change_room['price'] = $or['modified_price'];
2986 }
2987 }
2988 if ($ota_stay_change_room) {
2989 // push room data for stay change
2990 $ota_stay_change_data[] = $ota_stay_change_room;
2991 }
2992 }
2993
2994 if ($ota_stay_change_data) {
2995 // notify the OTA through Vik Channel Manager
2996 $ota_reporting = VCMOtaReporting::getInstance();
2997 $ota_result = $ota_reporting->notifyStayChange($ota_stay_change_data);
2998 if (!$ota_result) {
2999 // enqueue error message
3000 $app->enqueueMessage($ota_reporting->getError(), 'error');
3001 }
3002 }
3003 }
3004 }
3005
3006 // Booking History
3007 $history_descr = "({$user->name}) " . VikBooking::getLogBookingModification($ord, $room_stay_dates);
3008 if (!$opertwounits && $forcebooking) {
3009 $history_descr .= "\n" . JText::translate('VBO_FORCED_BOOKDATES');
3010 }
3011 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', $history_descr);
3012
3013 // enqueue result message
3014 $app->enqueueMessage($upd_esit);
3015 } else {
3016 VikError::raiseWarning('', JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second));
3017 $allow_force = 1;
3018 $app->enqueueMessage(JText::translate('VBO_BOOKING_SHOULDFORCE'), 'notice');
3019 }
3020
3021 if ($callback == 'geninvoices') {
3022 $app->redirect("index.php?option=com_vikbooking&task=orders&cid[]=".$ord['id']."&confirmgen=1");
3023 } else {
3024 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').(isset($allow_force) ? '&canforce=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
3025 }
3026 }
3027
3028 public function removebusy()
3029 {
3030 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
3031 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3032 }
3033
3034 $dbo = JFactory::getDbo();
3035 $app = JFactory::getApplication();
3036
3037 $user = JFactory::getUser();
3038 $config = VBOFactory::getConfig();
3039
3040 $prev_conf_ids = [];
3041 $pidorder = VikRequest::getInt('idorder', 0, 'request');
3042 $pgoto = VikRequest::getString('goto', '', 'request');
3043
3044 $purged = false;
3045
3046 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
3047 $dbo->setQuery($q, 0, 1);
3048 $row = $dbo->loadAssoc();
3049
3050 // check for any cancellation constraints
3051 $canc_denied = false;
3052 if ($row && class_exists('VCMFeesCancellation')) {
3053 // let VCM detect if there are any constraints for the cancellation
3054 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
3055 if ($canc_denied) {
3056 // set error message
3057 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
3058 if ($canc_deny_error) {
3059 $app->enqueueMessage($canc_deny_error, 'error');
3060 }
3061 }
3062 }
3063
3064 if ($row && !$canc_denied) {
3065 // set status to cancelled
3066 if ($row['status'] != 'cancelled') {
3067 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
3068 $dbo->setQuery($q);
3069 $dbo->execute();
3070 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
3071 $dbo->setQuery($q);
3072 $dbo->execute();
3073 if ($row['status'] == 'confirmed') {
3074 $prev_conf_ids[] = $row['id'];
3075 }
3076 // Booking History
3077 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
3078 }
3079
3080 // free records up
3081 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
3082 $dbo->setQuery($q);
3083 $ordbusy = $dbo->loadAssocList();
3084 if ($ordbusy) {
3085 foreach ($ordbusy as $ob) {
3086 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
3087 $dbo->setQuery($q);
3088 $dbo->execute();
3089 }
3090 }
3091
3092 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
3093 $dbo->setQuery($q);
3094 $dbo->execute();
3095
3096 // check for purge removal
3097 if ($row['status'] == 'cancelled') {
3098 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
3099 $dbo->setQuery($q);
3100 $dbo->execute();
3101 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
3102 $dbo->setQuery($q);
3103 $dbo->execute();
3104 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
3105 $dbo->setQuery($q);
3106 $dbo->execute();
3107 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
3108 $dbo->setQuery($q);
3109 $dbo->execute();
3110 // in case of split stay booking, remove the transient
3111 if ($row['split_stay']) {
3112 $config->remove('split_stay_' . $row['id']);
3113 }
3114 // turn flag on
3115 $purged = true;
3116 }
3117
3118 // enqueue message
3119 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
3120 }
3121
3122 if ($prev_conf_ids) {
3123 $prev_conf_ids_str = '';
3124 foreach ($prev_conf_ids as $prev_id) {
3125 $prev_conf_ids_str .= '&cid[]='.$prev_id;
3126 }
3127 //Invoke Channel Manager
3128 $vcm_autosync = VikBooking::vcmAutoUpdate();
3129 if ($vcm_autosync > 0) {
3130 $vcm_obj = VikBooking::getVcmInvoker();
3131 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
3132 $sync_result = $vcm_obj->doSync();
3133 if ($sync_result === false) {
3134 $vcm_err = $vcm_obj->getError();
3135 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
3136 }
3137 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
3138 $vcm_sync_url = 'index.php?option=com_vikbooking&task=invoke_vcm&stype=cancel'.$prev_conf_ids_str.'&returl='.urlencode('index.php?option=com_vikbooking&task=orders');
3139 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
3140 }
3141 //
3142 }
3143
3144 if ($pgoto == 'overv') {
3145 $app->redirect("index.php?option=com_vikbooking&task=overv");
3146 } elseif (!$purged) {
3147 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pidorder);
3148 } else {
3149 $app->redirect("index.php?option=com_vikbooking&task=orders");
3150 }
3151
3152 $app->close();
3153 }
3154
3155 public function unlockrecords()
3156 {
3157 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
3158 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3159 }
3160
3161 $ids = VikRequest::getVar('cid', array(0));
3162 if (@count($ids)) {
3163 $dbo = JFactory::getDBO();
3164 foreach ($ids as $d) {
3165 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `id`=".$dbo->quote($d).";";
3166 $dbo->setQuery($q);
3167 $dbo->execute();
3168 }
3169 }
3170 $mainframe = JFactory::getApplication();
3171 $mainframe->redirect("index.php?option=com_vikbooking");
3172 }
3173
3174 public function sortoption() {
3175 if (!JSession::checkToken('get')) {
3176 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3177 }
3178 $sortid = VikRequest::getVar('cid', array(0));
3179 $pmode = VikRequest::getString('mode', '', 'request');
3180 $dbo = JFactory::getDBO();
3181 $mainframe = JFactory::getApplication();
3182 if (!empty($pmode)) {
3183 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
3184 $dbo->setQuery($q);
3185 $dbo->execute();
3186 $totr = $dbo->getNumRows();
3187 if ($totr > 1) {
3188 $data = $dbo->loadAssocList();
3189 if ($pmode == "up") {
3190 foreach ($data as $v) {
3191 if ($v['id'] == $sortid[0]) {
3192 $y = $v['ordering'];
3193 }
3194 }
3195 if ($y && $y > 1) {
3196 $vik = $y - 1;
3197 $found = false;
3198 foreach ($data as $v) {
3199 if (intval($v['ordering']) == intval($vik)) {
3200 $found = true;
3201 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3202 $dbo->setQuery($q);
3203 $dbo->execute();
3204 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3205 $dbo->setQuery($q);
3206 $dbo->execute();
3207 break;
3208 }
3209 }
3210 if (!$found) {
3211 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3212 $dbo->setQuery($q);
3213 $dbo->execute();
3214 }
3215 }
3216 } elseif ($pmode == "down") {
3217 foreach ($data as $v) {
3218 if ($v['id'] == $sortid[0]) {
3219 $y = $v['ordering'];
3220 }
3221 }
3222 if ($y) {
3223 $vik = $y + 1;
3224 $found = false;
3225 foreach ($data as $v) {
3226 if (intval($v['ordering']) == intval($vik)) {
3227 $found = true;
3228 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3229 $dbo->setQuery($q);
3230 $dbo->execute();
3231 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3232 $dbo->setQuery($q);
3233 $dbo->execute();
3234 break;
3235 }
3236 }
3237 if (!$found) {
3238 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3239 $dbo->setQuery($q);
3240 $dbo->execute();
3241 }
3242 }
3243 }
3244 }
3245 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
3246 } else {
3247 $mainframe->redirect("index.php?option=com_vikbooking");
3248 }
3249 }
3250
3251 public function sortpayment() {
3252 if (!JSession::checkToken('get')) {
3253 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3254 }
3255 $cid = VikRequest::getVar('cid', array(0));
3256 $sortid = $cid[0];
3257 $dbo = JFactory::getDBO();
3258 $mainframe = JFactory::getApplication();
3259 $pmode = VikRequest::getString('mode', '', 'request');
3260 if (!empty($pmode) && !empty($sortid)) {
3261 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_gpayments` ORDER BY `#__vikbooking_gpayments`.`ordering` ASC;";
3262 $dbo->setQuery($q);
3263 $dbo->execute();
3264 $totr=$dbo->getNumRows();
3265 if ($totr > 1) {
3266 $data = $dbo->loadAssocList();
3267 if ($pmode == "up") {
3268 foreach ($data as $v) {
3269 if ($v['id'] == $sortid) {
3270 $y = $v['ordering'];
3271 }
3272 }
3273 if ($y && $y > 1) {
3274 $vik = $y - 1;
3275 $found = false;
3276 foreach ($data as $v) {
3277 if (intval($v['ordering']) == intval($vik)) {
3278 $found = true;
3279 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3280 $dbo->setQuery($q);
3281 $dbo->execute();
3282 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3283 $dbo->setQuery($q);
3284 $dbo->execute();
3285 break;
3286 }
3287 }
3288 if (!$found) {
3289 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3290 $dbo->setQuery($q);
3291 $dbo->execute();
3292 }
3293 }
3294 } elseif ($pmode == "down") {
3295 foreach ($data as $v) {
3296 if ($v['id'] == $sortid) {
3297 $y = $v['ordering'];
3298 }
3299 }
3300 if ($y) {
3301 $vik = $y + 1;
3302 $found = false;
3303 foreach ($data as $v) {
3304 if (intval($v['ordering']) == intval($vik)) {
3305 $found=true;
3306 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3307 $dbo->setQuery($q);
3308 $dbo->execute();
3309 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3310 $dbo->setQuery($q);
3311 $dbo->execute();
3312 break;
3313 }
3314 }
3315 if (!$found) {
3316 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3317 $dbo->setQuery($q);
3318 $dbo->execute();
3319 }
3320 }
3321 }
3322 }
3323 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3324 } else {
3325 $mainframe->redirect("index.php?option=com_vikbooking");
3326 }
3327 }
3328
3329 public function sortcarat() {
3330 if (!JSession::checkToken('get')) {
3331 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3332 }
3333 $sortid = VikRequest::getVar('cid', array(0));
3334 $pmode = VikRequest::getString('mode', '', 'request');
3335 $dbo = JFactory::getDBO();
3336 $mainframe = JFactory::getApplication();
3337 if (!empty($pmode)) {
3338 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` ASC;";
3339 $dbo->setQuery($q);
3340 $dbo->execute();
3341 $totr = $dbo->getNumRows();
3342 if ($totr > 1) {
3343 $data = $dbo->loadAssocList();
3344 if ($pmode == "up") {
3345 foreach ($data as $v) {
3346 if ($v['id'] == $sortid[0]) {
3347 $y = $v['ordering'];
3348 }
3349 }
3350 if ($y && $y > 1) {
3351 $vik = $y - 1;
3352 $found = false;
3353 foreach ($data as $v) {
3354 if (intval($v['ordering']) == intval($vik)) {
3355 $found = true;
3356 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3357 $dbo->setQuery($q);
3358 $dbo->execute();
3359 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3360 $dbo->setQuery($q);
3361 $dbo->execute();
3362 break;
3363 }
3364 }
3365 if (!$found) {
3366 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3367 $dbo->setQuery($q);
3368 $dbo->execute();
3369 }
3370 }
3371 } elseif ($pmode == "down") {
3372 foreach ($data as $v) {
3373 if ($v['id'] == $sortid[0]) {
3374 $y = $v['ordering'];
3375 }
3376 }
3377 if ($y) {
3378 $vik = $y + 1;
3379 $found = false;
3380 foreach ($data as $v) {
3381 if (intval($v['ordering']) == intval($vik)) {
3382 $found = true;
3383 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3384 $dbo->setQuery($q);
3385 $dbo->execute();
3386 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3387 $dbo->setQuery($q);
3388 $dbo->execute();
3389 break;
3390 }
3391 }
3392 if (!$found) {
3393 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3394 $dbo->setQuery($q);
3395 $dbo->execute();
3396 }
3397 }
3398 }
3399 }
3400 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
3401 } else {
3402 $mainframe->redirect("index.php?option=com_vikbooking");
3403 }
3404 }
3405
3406 public function resendordemail() {
3407 $this->do_resendorderemail();
3408 }
3409
3410 public function sendcancordemail() {
3411 $this->do_resendorderemail(true);
3412 }
3413
3414 private function do_resendorderemail($cancellation = false)
3415 {
3416 $dbo = JFactory::getDbo();
3417 $app = JFactory::getApplication();
3418 $vbo_tn = VikBooking::getTranslator();
3419
3420 $cid = VikRequest::getVar('cid', array(0));
3421 $oid = (int)$cid[0];
3422
3423 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $oid . ";";
3424 $dbo->setQuery($q);
3425 $dbo->execute();
3426 if (!$dbo->getNumRows()) {
3427 $app->redirect("index.php?option=com_vikbooking&task=orders");
3428 $app->close();
3429 }
3430 $order = $dbo->loadAssoc();
3431
3432 // check if the language in use is the same as the one used during the checkout
3433 if (!empty($order['lang'])) {
3434 $lang = JFactory::getLanguage();
3435 if ($lang->getTag() != $order['lang']) {
3436 $lang->load('com_vikbooking', (VBOPlatformDetection::isWordPress() ? VIKBOOKING_LANG : JPATH_ADMINISTRATOR), $order['lang'], true);
3437 if (defined('_JEXEC') && !defined('ABSPATH')) {
3438 $lang->load('joomla', JPATH_ADMINISTRATOR, $order['lang'], true);
3439 }
3440 }
3441 if ($vbo_tn->getDefaultLang() != $order['lang']) {
3442 // force the translation to start because contents should be translated
3443 $vbo_tn::$force_tolang = $order['lang'];
3444 }
3445 }
3446
3447 // availability helper
3448 $av_helper = VikBooking::getAvailabilityInstance();
3449
3450 /**
3451 * Split stay reservation.
3452 *
3453 * @since 1.16.0 (J) - 1.6.0 (WP)
3454 */
3455 $room_stay_dates = [];
3456 if ($order['split_stay']) {
3457 if ($order['status'] == 'confirmed') {
3458 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($order['id']);
3459 } else {
3460 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
3461 }
3462 // immediately count the number of nights of stay for each split room
3463 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
3464 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
3465 // overwrite values for compatibility with non-confirmed bookings
3466 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
3467 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
3468 }
3469 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
3470 // overwrite the whole array
3471 $room_stay_dates[$sps_r_k] = $sps_r_v;
3472 }
3473 }
3474
3475 // load rooms booked
3476 $q = "SELECT `or`.*,`r`.`id` AS `r_reference_id`,`r`.`name`,`r`.`units`,`r`.`fromadult`,`r`.`toadult`,`r`.`params` FROM `#__vikbooking_ordersrooms` AS `or`,`#__vikbooking_rooms` AS `r` WHERE `or`.`idorder`=" . (int)$order['id'] . " AND `or`.`idroom`=`r`.`id` ORDER BY `or`.`id` ASC;";
3477 $dbo->setQuery($q);
3478 $dbo->execute();
3479 $ordersrooms = $dbo->loadAssocList();
3480 $vbo_tn->translateContents($ordersrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
3481
3482 $ftitle = VikBooking::getFrontTitle();
3483 $currencyname = VikBooking::getCurrencyName();
3484
3485 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
3486 $realback = $turnover_secs + $order['checkout'];
3487
3488 $rooms = array();
3489 $tars = array();
3490 $arrpeople = array();
3491 $is_package = !empty($order['pkg']) ? true : false;
3492 $nowts = time();
3493 foreach ($ordersrooms as $kor => $or) {
3494 $num = $kor + 1;
3495 $rooms[$num] = $or;
3496 $arrpeople[$num]['adults'] = $or['adults'];
3497 $arrpeople[$num]['children'] = $or['children'];
3498 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3499 // package or custom cost set from the back-end
3500 continue;
3501 }
3502
3503 // determine the proper values for this room
3504 $room_nights = $order['days'];
3505 $room_checkin = $order['checkin'];
3506 $room_checkout = $order['checkout'];
3507 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3508 $room_nights = $room_stay_dates[$kor]['nights'];
3509 $room_checkin = $room_stay_dates[$kor]['checkin'];
3510 $room_checkout = $room_stay_dates[$kor]['checkout'];
3511 }
3512
3513 // load tariff
3514 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=" . (int)$or['idtar'] . ";";
3515 $dbo->setQuery($q);
3516 $dbo->execute();
3517 if ($dbo->getNumRows() > 0) {
3518 $tar = $dbo->loadAssocList();
3519 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
3520
3521 // different usage
3522 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
3523
3524 $tars[$num] = $tar[0];
3525 } else {
3526 VikError::raiseWarning('', JText::translate('VBERRNOFAREFOUND'));
3527 }
3528 }
3529
3530 $secdiff = $order['checkout'] - $order['checkin'];
3531 $daysdiff = $secdiff / 86400;
3532 if (is_int($daysdiff)) {
3533 if ($daysdiff < 1) {
3534 $daysdiff = 1;
3535 }
3536 } else {
3537 if ($daysdiff < 1) {
3538 $daysdiff = 1;
3539 } else {
3540 $sum = floor($daysdiff) * 86400;
3541 $newdiff = $secdiff - $sum;
3542 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
3543 if ($maxhmore >= $newdiff) {
3544 $daysdiff = floor($daysdiff);
3545 } else {
3546 $daysdiff = ceil($daysdiff);
3547 }
3548 }
3549 }
3550
3551 $isdue = 0;
3552 $pricestr = array();
3553 $optstr = array();
3554 foreach ($ordersrooms as $kor => $or) {
3555 $num = $kor + 1;
3556
3557 // determine the proper values for this room
3558 $room_nights = $order['days'];
3559 $room_checkin = $order['checkin'];
3560 $room_checkout = $order['checkout'];
3561 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3562 $room_nights = $room_stay_dates[$kor]['nights'];
3563 $room_checkin = $room_stay_dates[$kor]['checkin'];
3564 $room_checkout = $room_stay_dates[$kor]['checkout'];
3565 }
3566
3567 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3568 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
3569 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
3570 $isdue += $calctar;
3571 $pricestr[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? ucwords($or['otarplan']) : JText::translate('VBOROOMCUSTRATEPLAN'))).": ".$calctar." ".$currencyname;
3572 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
3573 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3574 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
3575 $tars[$num]['calctar'] = $calctar;
3576 $isdue += $calctar;
3577 $pricestr[$num] = VikBooking::getPriceName($tars[$num]['idprice'], $vbo_tn) . ": " . $calctar . " " . $currencyname . (!empty($tars[$num]['attrdata']) ? "\n" . VikBooking::getPriceAttr($tars[$num]['idprice'], $vbo_tn) . ": " . $tars[$num]['attrdata'] : "");
3578 }
3579 if (!empty($or['optionals'])) {
3580 $stepo = explode(";", $or['optionals']);
3581 foreach ($stepo as $roptkey => $oo) {
3582 if (empty($oo)) {
3583 continue;
3584 }
3585 $stept = explode(":", $oo);
3586 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=" . $dbo->quote($stept[0]) . ";";
3587 $dbo->setQuery($q);
3588 $dbo->execute();
3589 if (!$dbo->getNumRows()) {
3590 continue;
3591 }
3592 $actopt = $dbo->loadAssocList();
3593 $vbo_tn->translateContents($actopt, '#__vikbooking_optionals', array(), array(), (!empty($order['lang']) ? $order['lang'] : null));
3594 $chvar = '';
3595 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
3596 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
3597 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
3598 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
3599 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
3600 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
3601 $agestept = explode('-', $stept[1]);
3602 $stept[1] = $agestept[0];
3603 $chvar = $agestept[1];
3604 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
3605 //percentage value of the adults tariff
3606 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3607 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3608 } else {
3609 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3610 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3611 }
3612 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
3613 //VBO 1.10 - percentage value of room base cost
3614 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3615 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3616 } else {
3617 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
3618 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3619 }
3620 }
3621 $actopt[0]['chageintv'] = $chvar;
3622 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
3623 $actopt[0]['quan'] = $stept[1];
3624 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
3625 } else {
3626 $actopt[0]['quan'] = $stept[1];
3627 // VBO 1.11 - options percentage cost of the room total fee
3628 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3629 $deftar_basecosts = $or['cust_cost'];
3630 } else {
3631 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3632 }
3633 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
3634 //
3635 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
3636 }
3637 if (!empty($actopt[0]['maxprice']) && $actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
3638 $realcost = $actopt[0]['maxprice'];
3639 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
3640 $realcost = $actopt[0]['maxprice'] * $stept[1];
3641 }
3642 }
3643 if ($actopt[0]['perperson'] == 1) {
3644 $realcost = $realcost * $or['adults'];
3645 }
3646 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
3647 $isdue += $tmpopr;
3648 $optstr[$num][] = ($stept[1] > 1 ? $stept[1] . " " : "") . $actopt[0]['name'] . ": " . $tmpopr . " " . $currencyname . "\n";
3649 }
3650 }
3651
3652 // custom extra costs
3653 if (!empty($or['extracosts'])) {
3654 $cur_extra_costs = json_decode($or['extracosts'], true);
3655 foreach ($cur_extra_costs as $eck => $ecv) {
3656 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
3657 $isdue += $ecplustax;
3658 $optstr[$num][] = $ecv['name'] . ": " . $ecplustax . " " . $currencyname."\n";
3659 }
3660 }
3661 }
3662
3663 // coupon
3664 $usedcoupon = false;
3665 $origisdue = $isdue;
3666 if (strlen($order['coupon']) > 0) {
3667 $usedcoupon = true;
3668 $expcoupon = explode(";", $order['coupon']);
3669 $isdue = $isdue - $expcoupon[1];
3670 }
3671
3672 // make sure to apply any previously refunded amount
3673 if ($order['refund'] > 0) {
3674 $isdue -= $order['refund'];
3675 }
3676
3677 // ConfirmationNumber
3678 $confirmnumber = $order['confirmnumber'];
3679
3680 $esit_mess = JText::sprintf('VBORDEREMAILRESENT', $order['custmail']);
3681 $status_str = JText::translate('VBCOMPLETED');
3682 if ($cancellation) {
3683 $confirmnumber = '';
3684 $esit_mess = JText::sprintf('VBCANCORDEREMAILSENT', $order['custmail']);
3685 $status_str = JText::translate('VBCANCELLED');
3686 } elseif ($order['status'] == 'standby') {
3687 $confirmnumber = '';
3688 $status_str = JText::translate('VBWAITINGFORPAYMENT');
3689 }
3690 $app->enqueueMessage($esit_mess);
3691
3692 // force the original total amount if rates have changed
3693 if (number_format($isdue, 2) != number_format($order['total'], 2)) {
3694 $isdue = $order['total'];
3695 }
3696
3697 // send email notification to guest (by ignoring the configuration settings)
3698 VikBooking::sendBookingEmail($order['id'], ['guest'], $send = true, $no_config = true);
3699
3700 if ($cancellation) {
3701 /**
3702 * If "send cancellation email", we log the event in the history.
3703 *
3704 * @since 1.14 (J) - 1.4.0 (WP)
3705 */
3706 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('EC');
3707 } else {
3708 /**
3709 * Instead, we store an event log to remind that the email was re-sent to the guest
3710 *
3711 * @since 1.16.3 (J) - 1.6.3 (WP)
3712 */
3713 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('ER', $esit_mess);
3714 }
3715
3716 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$oid);
3717 $app->close();
3718 }
3719
3720 public function setordconfirmed()
3721 {
3722 $app = JFactory::getApplication();
3723
3724 // the booking ID to confirm
3725 $cid = VikRequest::getVar('cid', array(0));
3726 $oid = (int) $cid[0];
3727
3728 // notify the customer unless it was a re-confirmation
3729 $pskip = $app->input->getInt('skip_notification', 0);
3730
3731 // access the reservation model
3732 $model = VBOModelReservation::getInstance();
3733
3734 // set the booking to confirmed
3735 $confirmed = $model->setConfirmed([
3736 'booking_id' => $oid,
3737 'notify' => (bool) (!$pskip),
3738 ]);
3739
3740 if (!$confirmed) {
3741 $error = $model->getError();
3742 if (!is_string($error) || !$error) {
3743 $error = 'Could not confirm the reservation';
3744 }
3745
3746 // enqueue error message
3747 $app->enqueueMessage($error, 'error');
3748 } else {
3749 // enqueue success message
3750 $app->enqueueMessage(JText::translate('VBORDERSETASCONF'));
3751 }
3752
3753 // redirect
3754 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3755 $app->close();
3756 }
3757
3758 public function payments() {
3759 VikBookingHelper::printHeader("14");
3760
3761 VikRequest::setVar('view', VikRequest::getCmd('view', 'payments'));
3762
3763 parent::display();
3764
3765 if (VikBooking::showFooter()) {
3766 VikBookingHelper::printFooter();
3767 }
3768 }
3769
3770 public function newpayment() {
3771 VikBookingHelper::printHeader("14");
3772
3773 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
3774
3775 parent::display();
3776
3777 if (VikBooking::showFooter()) {
3778 VikBookingHelper::printFooter();
3779 }
3780 }
3781
3782 public function editpayment() {
3783 VikBookingHelper::printHeader("14");
3784
3785 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
3786
3787 parent::display();
3788
3789 if (VikBooking::showFooter()) {
3790 VikBookingHelper::printFooter();
3791 }
3792 }
3793
3794 public function createpayment()
3795 {
3796 if (!JSession::checkToken()) {
3797 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3798 }
3799
3800 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
3801 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3802 }
3803
3804 $mainframe = JFactory::getApplication();
3805 $pname = VikRequest::getString('name', '', 'request');
3806 $ppayment = VikRequest::getString('payment', '', 'request');
3807 $ppublished = VikRequest::getString('published', '', 'request');
3808 $pcharge = VikRequest::getFloat('charge', '', 'request');
3809 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
3810 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
3811 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
3812 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
3813 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWHTML);
3814 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
3815 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
3816 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
3817 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
3818 $poutposition = VikRequest::getString('outposition', 'top', 'request');
3819 $plogo = VikRequest::getString('logo', '', 'request');
3820 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
3821 $pidrooms = VikRequest::getVar('idrooms', array());
3822 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
3823 $payparamarr = array();
3824 $payparamstr = '';
3825 if (count($vikpaymentparams) > 0) {
3826 foreach ($vikpaymentparams as $setting => $cont) {
3827 if (strlen($setting) > 0) {
3828 $payparamarr[$setting] = $cont;
3829 }
3830 }
3831 if (count($payparamarr) > 0) {
3832 $payparamstr = json_encode($payparamarr);
3833 }
3834 }
3835
3836 $dbo = JFactory::getDbo();
3837
3838 $set_idrooms = [];
3839 if (empty($pall_rooms) && !empty($pidrooms)) {
3840 $pidrooms = array_map(function($idroom) {
3841 return (int)$idroom;
3842 }, $pidrooms);
3843 foreach ($pidrooms as $idroom) {
3844 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
3845 continue;
3846 }
3847 $set_idrooms[] = $idroom;
3848 }
3849 }
3850
3851 if (!empty($pname) && !empty($ppayment)) {
3852 $setpub = $ppublished == "1" ? 1 : 0;
3853 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
3854 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
3855 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment).";";
3856 $dbo->setQuery($q);
3857 $dbo->execute();
3858 if ($dbo->getNumRows() >= 0) {
3859 $q = "INSERT INTO `#__vikbooking_gpayments` (`name`,`file`,`published`,`note`,`charge`,`setconfirmed`,`shownotealw`,`val_pcent`,`ch_disc`,`params`,`hidenonrefund`,`onlynonrefund`,`outposition`,`logo`,`idrooms`) VALUES(".$dbo->quote($pname).",".$dbo->quote($ppayment).",'".$setpub."',".$dbo->quote($pnote).",".$dbo->quote($pcharge).",'".$psetconfirmed."','".$pshownotealw."','".$pval_pcent."','".$pch_disc."',".$dbo->quote($payparamstr).",".($phidenonrefund > 0 ? '1' : '0').",".($ponlynonrefund > 0 ? '1' : '0').", " . $dbo->quote($poutposition) . ", " . $dbo->quote($plogo) . ", " . (count($set_idrooms) ? $dbo->quote(json_encode($set_idrooms)) : 'NULL') . ");";
3860 $dbo->setQuery($q);
3861 $dbo->execute();
3862 $mainframe->enqueueMessage(JText::translate('VBPAYMENTSAVED'));
3863 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3864 } else {
3865 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
3866 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
3867 }
3868 } else {
3869 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
3870 }
3871 }
3872
3873 public function updatepayment()
3874 {
3875 if (!JSession::checkToken()) {
3876 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3877 }
3878
3879 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
3880 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3881 }
3882
3883 $this->do_updatepayment($stay = false);
3884 }
3885
3886 public function updatepaymentstay()
3887 {
3888 if (!JSession::checkToken()) {
3889 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3890 }
3891
3892 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
3893 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3894 }
3895
3896 $this->do_updatepayment($stay = true);
3897 }
3898
3899 protected function do_updatepayment($stay = false)
3900 {
3901 $mainframe = JFactory::getApplication();
3902
3903 $pwhere = VikRequest::getString('where', '', 'request');
3904 $pname = VikRequest::getString('name', '', 'request');
3905 $ppayment = VikRequest::getString('payment', '', 'request');
3906 $ppublished = VikRequest::getString('published', '', 'request');
3907 $pcharge = VikRequest::getFloat('charge', '', 'request');
3908 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
3909 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
3910 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
3911 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
3912 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWRAW);
3913 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
3914 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
3915 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
3916 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
3917 $poutposition = VikRequest::getString('outposition', 'top', 'request');
3918 $plogo = VikRequest::getString('logo', '', 'request');
3919 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
3920 $pidrooms = VikRequest::getVar('idrooms', array());
3921 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
3922 $payparamarr = array();
3923 $payparamstr = '';
3924 if (count($vikpaymentparams) > 0) {
3925 foreach ($vikpaymentparams as $setting => $cont) {
3926 if (strlen($setting) > 0) {
3927 $payparamarr[$setting] = $cont;
3928 }
3929 }
3930 if (count($payparamarr) > 0) {
3931 $payparamstr = json_encode($payparamarr);
3932 }
3933 }
3934
3935 $dbo = JFactory::getDbo();
3936
3937 $set_idrooms = [];
3938 if (empty($pall_rooms) && !empty($pidrooms)) {
3939 $pidrooms = array_map(function($idroom) {
3940 return (int)$idroom;
3941 }, $pidrooms);
3942 foreach ($pidrooms as $idroom) {
3943 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
3944 continue;
3945 }
3946 $set_idrooms[] = $idroom;
3947 }
3948 }
3949
3950 if (!empty($pname) && !empty($ppayment) && !empty($pwhere)) {
3951 $setpub = $ppublished == "1" ? 1 : 0;
3952 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
3953 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
3954 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment)." AND `id`!='".$pwhere."';";
3955 $dbo->setQuery($q);
3956 $dbo->execute();
3957 if ($dbo->getNumRows() >= 0) {
3958 $q = "UPDATE `#__vikbooking_gpayments` SET `name`=".$dbo->quote($pname).",`file`=".$dbo->quote($ppayment).",`published`='".$setpub."',`note`=".$dbo->quote($pnote).",`charge`=".$dbo->quote($pcharge).",`setconfirmed`='".$psetconfirmed."',`shownotealw`='".$pshownotealw."',`val_pcent`='".$pval_pcent."',`ch_disc`='".$pch_disc."',`params`=".$dbo->quote($payparamstr).",`hidenonrefund`=".($phidenonrefund > 0 ? '1' : '0').",`onlynonrefund`=".($ponlynonrefund > 0 ? '1' : '0').",`outposition`=" . $dbo->quote($poutposition) . ",`logo`=" . $dbo->quote($plogo) . ",`idrooms`=" . (count($set_idrooms) ? $dbo->quote(json_encode($set_idrooms)) : 'NULL') . " WHERE `id`=".$dbo->quote($pwhere).";";
3959 $dbo->setQuery($q);
3960 $dbo->execute();
3961
3962 $mainframe->enqueueMessage(JText::translate('VBPAYMENTUPDATED'));
3963 if ($stay) {
3964 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
3965 } else {
3966 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3967 }
3968 } else {
3969 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
3970 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
3971 }
3972 } else {
3973 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
3974 }
3975 }
3976
3977 public function removepayments()
3978 {
3979 if (!JSession::checkToken()) {
3980 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3981 }
3982
3983 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
3984 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3985 }
3986
3987 $ids = VikRequest::getVar('cid', array(0));
3988 if ($ids) {
3989 $dbo = JFactory::getDBO();
3990 foreach ($ids as $d) {
3991 $q = "DELETE FROM `#__vikbooking_gpayments` WHERE `id`=".$dbo->quote($d).";";
3992 $dbo->setQuery($q);
3993 $dbo->execute();
3994 }
3995 }
3996 $mainframe = JFactory::getApplication();
3997 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3998 }
3999
4000 public function modavailpayment() {
4001 if (!JSession::checkToken('get')) {
4002 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4003 }
4004 $cid = VikRequest::getVar('cid', array(0));
4005 $idp = $cid[0];
4006 if (!empty($idp)) {
4007 $dbo = JFactory::getDBO();
4008 $q = "SELECT `published` FROM `#__vikbooking_gpayments` WHERE `id`=".intval($idp).";";
4009 $dbo->setQuery($q);
4010 $dbo->execute();
4011 $get = $dbo->loadAssocList();
4012 $q = "UPDATE `#__vikbooking_gpayments` SET `published`=".(intval($get[0]['published']) == 1 ? '0' : '1')." WHERE `id`=".intval($idp).";";
4013 $dbo->setQuery($q);
4014 $dbo->execute();
4015 }
4016 $mainframe = JFactory::getApplication();
4017 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4018 }
4019
4020 public function seasons() {
4021 VikBookingHelper::printHeader("13");
4022
4023 VikRequest::setVar('view', VikRequest::getCmd('view', 'seasons'));
4024
4025 parent::display();
4026
4027 if (VikBooking::showFooter()) {
4028 VikBookingHelper::printFooter();
4029 }
4030 }
4031
4032 public function newseason() {
4033 VikBookingHelper::printHeader("13");
4034
4035 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4036
4037 parent::display();
4038
4039 if (VikBooking::showFooter()) {
4040 VikBookingHelper::printFooter();
4041 }
4042 }
4043
4044 public function editseason() {
4045 VikBookingHelper::printHeader("13");
4046
4047 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4048
4049 parent::display();
4050
4051 if (VikBooking::showFooter()) {
4052 VikBookingHelper::printFooter();
4053 }
4054 }
4055
4056 public function updateseason()
4057 {
4058 if (!JSession::checkToken()) {
4059 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4060 }
4061
4062 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4063 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4064 }
4065
4066 $this->do_updateseason();
4067 }
4068
4069 public function updateseasonstay()
4070 {
4071 if (!JSession::checkToken()) {
4072 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4073 }
4074
4075 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4076 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4077 }
4078
4079 $this->do_updateseason(true);
4080 }
4081
4082 private function do_updateseason($stay = false)
4083 {
4084 $app = JFactory::getApplication();
4085 $dbo = JFactory::getDbo();
4086 $session = JFactory::getSession();
4087
4088 $pwhere = VikRequest::getInt('where', 0, 'request');
4089
4090 $pfrom = VikRequest::getString('from', '', 'request');
4091 $pto = VikRequest::getString('to', '', 'request');
4092 $ptype = VikRequest::getString('type', '', 'request');
4093 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4094 $pidrooms = VikRequest::getVar('idrooms', array());
4095 $pidprices = VikRequest::getVar('idprices', array());
4096 $pwdays = VikRequest::getVar('wdays', array());
4097 $pspname = VikRequest::getString('spname', '', 'request');
4098 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4099 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4100 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4101 $pyeartied = $pyeartied == 1 ? 1 : 0;
4102 $tieyear = 0;
4103 $ppromo = VikRequest::getInt('promo', 0, 'request');
4104 $ppromo = $ppromo == 1 ? 1 : 0;
4105 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4106 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4107 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4108 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4109 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4110 $proundmode = VikRequest::getString('roundmode', '', 'request');
4111 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4112 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4113 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4114 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4115 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4116 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4117 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4118 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4119 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4120 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4121 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4122 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4123 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4124 $occupancy_ovr = array();
4125 $losverridestr = "";
4126
4127 $updforvcm = $session->get('vbVcmRatesUpd', '');
4128 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4129
4130 // check null dates
4131 if ($dbo->getNullDate() == $pfrom) {
4132 $pfrom = '';
4133 }
4134 if ($dbo->getNullDate() == $pto) {
4135 $pto = '';
4136 }
4137
4138 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4139 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4140 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4141 exit;
4142 }
4143
4144 $skipseason = false;
4145 if (empty($pfrom) || empty($pto)) {
4146 $skipseason = true;
4147 }
4148 $skipdays = false;
4149 $wdaystr = null;
4150 if (count($pwdays) == 0) {
4151 $skipdays = true;
4152 } else {
4153 $wdaystr = "";
4154 foreach ($pwdays as $wd) {
4155 $wdaystr .= $wd.';';
4156 }
4157 }
4158 $roomstr = "";
4159 $roomids = array();
4160 foreach ($pidrooms as $room) {
4161 if (empty($room)) {
4162 continue;
4163 }
4164 $roomstr .= "-".$room."-,";
4165 $roomids[] = (int)$room;
4166 }
4167 $pricestr = "";
4168 $priceids = array();
4169 foreach ($pidprices as $price) {
4170 if (empty($price)) {
4171 continue;
4172 }
4173 $pricestr .= "-".$price."-,";
4174 $priceids[] = (int)$price;
4175 }
4176 $valid = true;
4177 $double_records = array();
4178 $sfrom = null;
4179 $sto = null;
4180
4181 // value overrides
4182 if ($pnightsoverrides && $pvaluesoverrides) {
4183 foreach ($pnightsoverrides as $ko => $no) {
4184 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4185 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4186 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4187 }
4188 }
4189 }
4190
4191 if (!$skipseason) {
4192 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4193 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4194
4195 if ($second > 0 && $second == $first) {
4196 $second += 86399;
4197 }
4198
4199 if (!($second > $first)) {
4200 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4201 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4202 exit;
4203 }
4204
4205 $baseone = getdate($first);
4206 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4207 $sfrom = $baseone[0] - $basets;
4208 $basetwo = getdate($second);
4209 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4210 $sto = $basetwo[0] - $basets;
4211
4212 // check leap year
4213 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4214 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4215 if ($baseone[0] > $leapts) {
4216 $sfrom -= 86400;
4217 /**
4218 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4219 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4220 *
4221 * @since July 2nd 2019
4222 */
4223 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4224 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4225 if ($basetwo[0] > $leapts) {
4226 $sto -= date('d-m', $baseone[0]) != '31-12' && date('d-m', $basetwo[0]) == '31-12' ? 1 : 86400;
4227 }
4228 }
4229 }
4230 }
4231
4232 // tied to the year
4233 if ($pyeartied == 1) {
4234 $tieyear = $baseone['year'];
4235 }
4236
4237 // Occupancy Override
4238 if (count($padultsdiffval) > 0) {
4239 foreach ($padultsdiffval as $rid => $valovr_arr) {
4240 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4241 continue;
4242 }
4243 foreach ($valovr_arr as $occ => $valovr) {
4244 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4245 continue;
4246 }
4247 if (!array_key_exists($rid, $occupancy_ovr)) {
4248 $occupancy_ovr[$rid] = array();
4249 }
4250 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4251 }
4252 }
4253 }
4254
4255 // check if seasons dates are valid
4256 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sfrom)." AND `to`>=".$dbo->quote($sfrom)." AND `id`!=".$dbo->quote($pwhere)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4257 $dbo->setQuery($q);
4258 $similar = $dbo->loadAssocList();
4259 if ($similar) {
4260 $valid = false;
4261 foreach ($similar as $sim) {
4262 $double_records[] = $sim['spname'];
4263 }
4264 }
4265
4266 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sto)." AND `id`!=".$dbo->quote($pwhere)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4267 $dbo->setQuery($q);
4268 $similar = $dbo->loadAssocList();
4269 if ($similar) {
4270 $valid = false;
4271 foreach ($similar as $sim) {
4272 $double_records[] = $sim['spname'];
4273 }
4274 }
4275
4276 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`>=".$dbo->quote($sfrom)." AND `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sfrom)." AND `to`<=".$dbo->quote($sto)." AND `id`!=".$dbo->quote($pwhere)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4277 $dbo->setQuery($q);
4278 $dbo->execute();
4279 $similar = $dbo->loadAssocList();
4280 if ($similar) {
4281 $valid = false;
4282 foreach ($similar as $sim) {
4283 $double_records[] = $sim['spname'];
4284 }
4285 }
4286 }
4287
4288 // fetch previous record before the update
4289 $q = $dbo->getQuery(true)
4290 ->select('*')
4291 ->from($dbo->qn('#__vikbooking_seasons'))
4292 ->where($dbo->qn('id') . ' = ' . $pwhere);
4293 $dbo->setQuery($q, 0, 1);
4294 $prev_record = $dbo->loadAssoc();
4295
4296 if (!$valid || !$prev_record) {
4297 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').($double_records ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4298 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4299 exit;
4300 }
4301
4302 /**
4303 * Attempt to access the promotion handlers in advance to perform additional validations.
4304 *
4305 * @since 1.16.4 (J) - 1.6.4 (WP)
4306 */
4307 try {
4308 $promo_handlers = VikBooking::getPromotionHandlers();
4309 } catch (Exception $e) {
4310 // reset the value
4311 $promo_handlers = [];
4312 }
4313
4314 if (!$prev_record['promo'] && $ppromo && $promo_handlers) {
4315 // channels supporting promotions are available, and a regular special price is
4316 // being converted into a promotion - this is not allowed so we make it a non-promotion.
4317 $ppromo = 0;
4318 $app->enqueueMessage(JText::translate('VBO_NOPROMO_UPD_CHANNELS'), 'warning');
4319 }
4320
4321 // update record
4322 $upd_record = new stdClass;
4323 $upd_record->id = $prev_record['id'];
4324 $upd_record->type = $ptype == "1" ? 1 : 2;
4325 $upd_record->from = $sfrom;
4326 $upd_record->to = $sto;
4327 $upd_record->diffcost = $pdiffcost;
4328 $upd_record->idrooms = $roomstr;
4329 $upd_record->spname = $pspname;
4330 $upd_record->wdays = $wdaystr;
4331 $upd_record->checkinincl = $pcheckinincl;
4332 $upd_record->val_pcent = $pval_pcent;
4333 $upd_record->losoverride = $losverridestr;
4334 $upd_record->roundmode = !empty($proundmode) ? $proundmode : null;
4335 $upd_record->year = $pyeartied == 1 ? $tieyear : null;
4336 $upd_record->idprices = $pricestr;
4337 $upd_record->promo = $ppromo;
4338 $upd_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4339 $upd_record->promotxt = $ppromotxt;
4340 $upd_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4341 $upd_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4342 $upd_record->promolastmin = (int)$promolastmin;
4343 $upd_record->promofinalprice = $ppromofinalprice;
4344
4345 $dbo->updateObject('#__vikbooking_seasons', $upd_record, 'id', $nulls = true);
4346
4347 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
4348
4349 // update session values
4350 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4351 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4352 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4353 } else {
4354 $updforvcm['dfrom'] = $first;
4355 }
4356 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4357 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4358 } else {
4359 $updforvcm['dto'] = $second;
4360 }
4361 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4362 foreach ($roomids as $rid) {
4363 if (!in_array($rid, $updforvcm['rooms'])) {
4364 $updforvcm['rooms'][] = $rid;
4365 }
4366 }
4367 } else {
4368 $updforvcm['rooms'] = $roomids;
4369 }
4370 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4371 foreach ($roomids as $rid) {
4372 if (array_key_exists($rid, $updforvcm['rplans'])) {
4373 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4374 } else {
4375 $updforvcm['rplans'][$rid] = $priceids;
4376 }
4377 }
4378 } else {
4379 $updforvcm['rplans'] = array();
4380 foreach ($roomids as $rid) {
4381 $updforvcm['rplans'][$rid] = $priceids;
4382 }
4383 }
4384 $session->set('vbVcmRatesUpd', $updforvcm);
4385
4386 /**
4387 * Query promotion handlers, if any, to trigger the update/delete promotion event.
4388 *
4389 * @since 1.15.0 (J) - 1.5.0 (WP)
4390 * @since 1.16.4 (J) - 1.6.4 (WP) added control to perform a delete operation.
4391 */
4392 $promo_update_type = $prev_record['promo'] && !$ppromo ? 'triggerDelete' : 'triggerUpdate';
4393 $promo_method_type = $prev_record['promo'] && !$ppromo ? 'delete' : 'update';
4394 try {
4395 if ($ppromo && is_array($promo_handlers) && $promo_handlers) {
4396 foreach ($promo_handlers as $promo_handler) {
4397 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, $promo_update_type)) {
4398 // outdated handler object
4399 continue;
4400 }
4401 if (!is_callable(array($promo_handler->instance, $promo_update_type)) || !$promo_handler->instance->{$promo_update_type}()) {
4402 // promotion handler does not support update/delete promotion event
4403 continue;
4404 }
4405 // invoke the update/delete promotion event for this handler
4406 $ch_result = $promo_handler->instance->createPromotion(['vbo_promo_id' => $pwhere], $promo_method_type);
4407 if (!$ch_result) {
4408 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
4409 }
4410 }
4411 }
4412 } catch (Exception $e) {
4413 // do nothing
4414 }
4415
4416 if ($stay) {
4417 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4418 } else {
4419 $app->redirect("index.php?option=com_vikbooking&task=seasons");
4420 }
4421 $app->close();
4422 }
4423
4424 public function createseason()
4425 {
4426 if (!JSession::checkToken()) {
4427 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4428 }
4429
4430 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4431 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4432 }
4433
4434 $this->do_createseason();
4435 }
4436
4437 public function createseason_new()
4438 {
4439 if (!JSession::checkToken()) {
4440 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4441 }
4442
4443 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4444 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4445 }
4446
4447 $this->do_createseason(true);
4448 }
4449
4450 private function do_createseason($andnew = false)
4451 {
4452 $app = JFactory::getApplication();
4453 $dbo = JFactory::getDbo();
4454 $session = JFactory::getSession();
4455
4456 $pfrom = VikRequest::getString('from', '', 'request');
4457 $pto = VikRequest::getString('to', '', 'request');
4458 $ptype = VikRequest::getString('type', '', 'request');
4459 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4460 $pidrooms = VikRequest::getVar('idrooms', array());
4461 $pidprices = VikRequest::getVar('idprices', array());
4462 $pwdays = VikRequest::getVar('wdays', array());
4463 $pspname = VikRequest::getString('spname', '', 'request');
4464 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4465 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4466 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4467 $pyeartied = $pyeartied == 1 ? 1 : 0;
4468 $tieyear = 0;
4469 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4470 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4471 $proundmode = VikRequest::getString('roundmode', '', 'request');
4472 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4473 $ppromo = VikRequest::getInt('promo', 0, 'request');
4474 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4475 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4476 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4477 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4478 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4479 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4480 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4481 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4482 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4483 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4484 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4485 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4486 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4487 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4488 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4489 $pchannels = VikRequest::getVar('channels', array());
4490 $occupancy_ovr = array();
4491 $losverridestr = "";
4492
4493 $updforvcm = $session->get('vbVcmRatesUpd', '');
4494 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4495
4496 // check null dates
4497 if ($dbo->getNullDate() == $pfrom) {
4498 $pfrom = '';
4499 }
4500 if ($dbo->getNullDate() == $pto) {
4501 $pto = '';
4502 }
4503
4504 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4505 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4506 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4507 exit;
4508 }
4509
4510 $skipseason = false;
4511 if (empty($pfrom) || empty($pto)) {
4512 $skipseason = true;
4513 }
4514 $skipdays = false;
4515 $wdaystr = null;
4516 if (!$pwdays) {
4517 $skipdays = true;
4518 } else {
4519 $wdaystr = "";
4520 foreach ($pwdays as $wd) {
4521 $wdaystr .= $wd.';';
4522 }
4523 }
4524 $roomstr = "";
4525 $roomids = array();
4526 foreach ($pidrooms as $room) {
4527 if (empty($room)) {
4528 continue;
4529 }
4530 $roomstr .= "-".$room."-,";
4531 $roomids[] = (int)$room;
4532 }
4533 $pricestr = "";
4534 $priceids = array();
4535 foreach ($pidprices as $price) {
4536 if (empty($price)) {
4537 continue;
4538 }
4539 $pricestr .= "-".$price."-,";
4540 $priceids[] = (int)$price;
4541 }
4542 $valid = true;
4543 $double_records = array();
4544 $sfrom = null;
4545 $sto = null;
4546
4547 // value overrides
4548 if ($pnightsoverrides && $pvaluesoverrides) {
4549 foreach ($pnightsoverrides as $ko => $no) {
4550 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4551 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4552 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4553 }
4554 }
4555 }
4556
4557 if (!$skipseason) {
4558 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4559 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4560
4561 if ($second > 0 && $second == $first) {
4562 $second += 86399;
4563 }
4564
4565 if (!($second > $first)) {
4566 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4567 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4568 exit;
4569 }
4570
4571 $baseone = getdate($first);
4572 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4573 $sfrom = $baseone[0] - $basets;
4574 $basetwo = getdate($second);
4575 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4576 $sto = $basetwo[0] - $basets;
4577
4578 // check leap year
4579 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4580 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4581 if ($baseone[0] > $leapts) {
4582 $sfrom -= 86400;
4583 /**
4584 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4585 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4586 *
4587 * @since July 2nd 2019
4588 */
4589 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4590 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4591 if ($basetwo[0] > $leapts) {
4592 $sto -= date('d-m', $baseone[0]) != '31-12' && date('d-m', $basetwo[0]) == '31-12' ? 1 : 86400;
4593 }
4594 }
4595 }
4596 }
4597
4598 // tied to the year
4599 if ($pyeartied == 1) {
4600 $tieyear = $baseone['year'];
4601 }
4602
4603 // Occupancy Override
4604 if ($padultsdiffval) {
4605 foreach ($padultsdiffval as $rid => $valovr_arr) {
4606 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4607 continue;
4608 }
4609 foreach ($valovr_arr as $occ => $valovr) {
4610 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4611 continue;
4612 }
4613 if (!array_key_exists($rid, $occupancy_ovr)) {
4614 $occupancy_ovr[$rid] = array();
4615 }
4616 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4617 }
4618 }
4619 }
4620
4621 // check if seasons dates are valid
4622 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sfrom)." AND `to`>".$dbo->quote($sfrom)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4623 $dbo->setQuery($q);
4624 $similar = $dbo->loadAssocList();
4625 if ($similar) {
4626 $valid = false;
4627 foreach ($similar as $sim) {
4628 $double_records[] = $sim['spname'];
4629 }
4630 }
4631
4632 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sto)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4633 $dbo->setQuery($q);
4634 $similar = $dbo->loadAssocList();
4635 if ($similar) {
4636 $valid = false;
4637 foreach ($similar as $sim) {
4638 $double_records[] = $sim['spname'];
4639 }
4640 }
4641
4642 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`>=".$dbo->quote($sfrom)." AND `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sfrom)." AND `to`<=".$dbo->quote($sto)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4643 $dbo->setQuery($q);
4644 $similar = $dbo->loadAssocList();
4645 if ($similar) {
4646 $valid = false;
4647 foreach ($similar as $sim) {
4648 $double_records[] = $sim['spname'];
4649 }
4650 }
4651 }
4652
4653 if (!$valid && !$ppromo) {
4654 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').(count($double_records) ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4655 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4656 exit;
4657 }
4658
4659 // insert new record
4660 $sea_record = new stdClass;
4661 $sea_record->type = $ptype == "1" ? 1 : 2;
4662 $sea_record->from = $sfrom;
4663 $sea_record->to = $sto;
4664 $sea_record->diffcost = $pdiffcost;
4665 $sea_record->idrooms = $roomstr;
4666 $sea_record->spname = $pspname;
4667 $sea_record->wdays = $wdaystr;
4668 $sea_record->checkinincl = $pcheckinincl;
4669 $sea_record->val_pcent = $pval_pcent;
4670 $sea_record->losoverride = $losverridestr;
4671 $sea_record->roundmode = !empty($proundmode) ? $proundmode : null;
4672 $sea_record->year = $pyeartied == 1 ? $tieyear : null;
4673 $sea_record->idprices = $pricestr;
4674 $sea_record->promo = $ppromo == 1 ? 1 : 0;
4675 $sea_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4676 $sea_record->promotxt = $ppromotxt;
4677 $sea_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4678 $sea_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4679 $sea_record->promolastmin = (int)$promolastmin;
4680 $sea_record->promofinalprice = $ppromofinalprice;
4681
4682 $dbo->insertObject('#__vikbooking_seasons', $sea_record, 'id');
4683
4684 $vbo_promo_id = $sea_record->id;
4685
4686 $app->enqueueMessage(JText::translate('VBSEASONSAVED'));
4687
4688 // update session values
4689 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4690 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4691 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4692 } else {
4693 $updforvcm['dfrom'] = $first;
4694 }
4695 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4696 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4697 } else {
4698 $updforvcm['dto'] = $second;
4699 }
4700 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4701 foreach ($roomids as $rid) {
4702 if (!in_array($rid, $updforvcm['rooms'])) {
4703 $updforvcm['rooms'][] = $rid;
4704 }
4705 }
4706 } else {
4707 $updforvcm['rooms'] = $roomids;
4708 }
4709 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4710 foreach ($roomids as $rid) {
4711 if (array_key_exists($rid, $updforvcm['rplans'])) {
4712 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4713 } else {
4714 $updforvcm['rplans'][$rid] = $priceids;
4715 }
4716 }
4717 } else {
4718 $updforvcm['rplans'] = array();
4719 foreach ($roomids as $rid) {
4720 $updforvcm['rplans'][$rid] = $priceids;
4721 }
4722 }
4723 if (!$ppromo) {
4724 $session->set('vbVcmRatesUpd', $updforvcm);
4725 }
4726
4727 /**
4728 * Create the promotion also on the selected channels
4729 *
4730 * @since 1.13.0 (J) - 1.3.0 (WP)
4731 */
4732 if ($ppromo && $pchannels) {
4733 foreach ($pchannels as $channel_key) {
4734 $promo_obj = VikBooking::getPromotionHandlers($channel_key);
4735 if (!is_object($promo_obj)) {
4736 continue;
4737 }
4738 /**
4739 * We inject for VCM the ID of the newly created promotion in VBO.
4740 *
4741 * @since 1.15.0 (J) - 1.5.0 (WP)
4742 */
4743 $ch_result = $promo_obj->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'new');
4744 if (!$ch_result) {
4745 VikError::raiseWarning('', $promo_obj->getName() . ': ' . $promo_obj->getError());
4746 } else {
4747 $resp = $promo_obj->getResponse();
4748 $app->enqueueMessage($promo_obj->getName() . ': ' . JText::translate('VBOCHPROMOSUCCESS') . (!empty($resp) ? ' (' . str_replace('e4j.ok.', '', $resp) . ')' : ''));
4749 // in case of success, unset the current session values in VCM
4750 $session->set('vcmBPromo', '');
4751 }
4752 }
4753 }
4754
4755 $app->redirect("index.php?option=com_vikbooking&task=".($andnew ? 'newseason' : 'seasons'));
4756 $app->close();
4757 }
4758
4759 public function removeseasons()
4760 {
4761 if (!JSession::checkToken()) {
4762 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4763 }
4764
4765 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
4766 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4767 }
4768
4769 $app = JFactory::getApplication();
4770 $dbo = JFactory::getDbo();
4771
4772 $ids = VikRequest::getVar('cid', array(0));
4773 $pidroom = VikRequest::getInt('idroom', '', 'request');
4774 $pwhere = VikRequest::getInt('where', '', 'request');
4775 if (!empty($pwhere)) {
4776 $ids[] = $pwhere;
4777 }
4778 $tot_removed = array();
4779 $prev_promos = array();
4780 foreach ($ids as $d) {
4781 if (empty($d)) {
4782 continue;
4783 }
4784 // check if it was a promotion
4785 $q = "SELECT `id` FROM `#__vikbooking_seasons` WHERE `id`=" . (int)$d . " AND `promo`=1;";
4786 $dbo->setQuery($q);
4787 $dbo->execute();
4788 if ($dbo->getNumRows()) {
4789 // push it as a previous promo
4790 array_push($prev_promos, $d);
4791 }
4792
4793 // delete the record
4794 $q = "DELETE FROM `#__vikbooking_seasons` WHERE `id`=".$dbo->quote($d).";";
4795 $dbo->setQuery($q);
4796 $dbo->execute();
4797 $tot_removed[] = $d;
4798 }
4799
4800 /**
4801 * Query promotion handlers, if any, to trigger the delete promotion event.
4802 *
4803 * @since 1.15.0 (J) - 1.5.0 (WP)
4804 */
4805 $promo_handlers = VikBooking::getPromotionHandlers();
4806 foreach ($prev_promos as $vbo_promo_id) {
4807 try {
4808 if (is_array($promo_handlers)) {
4809 foreach ($promo_handlers as $promo_handler) {
4810 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, 'triggerDelete')) {
4811 // outdated handler object
4812 continue;
4813 }
4814 if (!is_callable(array($promo_handler->instance, 'triggerDelete')) || !$promo_handler->instance->triggerDelete()) {
4815 // promotion handler does not support delete promotion event
4816 continue;
4817 }
4818 // invoke the delete promotion event for this handler
4819 $ch_result = $promo_handler->instance->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'delete');
4820 if (!$ch_result) {
4821 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
4822 }
4823 }
4824 }
4825 } catch (Exception $e) {
4826 // do nothing
4827 }
4828 }
4829
4830 $app->enqueueMessage(JText::sprintf('VBRECORDSREMOVED', count($tot_removed)));
4831 $app->redirect("index.php?option=com_vikbooking&task=seasons".(!empty($pidroom) ? '&idroom='.$pidroom : ''));
4832 $app->close();
4833 }
4834
4835 public function updatecustomer()
4836 {
4837 if (!JSession::checkToken()) {
4838 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4839 }
4840
4841 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4842 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4843 }
4844
4845 $this->do_updatecustomer();
4846 }
4847
4848 public function updatecustomerstay()
4849 {
4850 if (!JSession::checkToken()) {
4851 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4852 }
4853
4854 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4855 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4856 }
4857
4858 $this->do_updatecustomer(true);
4859 }
4860
4861 private function do_updatecustomer($stay = false) {
4862 $dbo = JFactory::getDbo();
4863 $mainframe = JFactory::getApplication();
4864 $pfirst_name = VikRequest::getString('first_name', '', 'request');
4865 $plast_name = VikRequest::getString('last_name', '', 'request');
4866 $pcompany = VikRequest::getString('company', '', 'request');
4867 $pvat = VikRequest::getString('vat', '', 'request');
4868 $pemail = VikRequest::getString('email', '', 'request');
4869 $pphone = VikRequest::getString('phone', '', 'request');
4870 $pcountry = VikRequest::getString('country', '', 'request');
4871 $pstate = VikRequest::getString('state', '', 'request');
4872 $ppin = VikRequest::getString('pin', '', 'request');
4873 $pujid = VikRequest::getInt('ujid', '', 'request');
4874 $paddress = VikRequest::getString('address', '', 'request');
4875 $pcity = VikRequest::getString('city', '', 'request');
4876 $pzip = VikRequest::getString('zip', '', 'request');
4877 $pfisccode = VikRequest::getString('fisccode', '', 'request');
4878 $ppec = VikRequest::getString('pec', '', 'request');
4879 $precipcode = VikRequest::getString('recipcode', '', 'request');
4880 $pgender = VikRequest::getString('gender', '', 'request');
4881 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
4882 $pbdate = VikRequest::getString('bdate', '', 'request');
4883 $ppbirth = VikRequest::getString('pbirth', '', 'request');
4884 $pdoctype = VikRequest::getString('doctype', '', 'request');
4885 $pdocnum = VikRequest::getString('docnum', '', 'request');
4886 $pnotes = VikRequest::getString('notes', '', 'request');
4887 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
4888 $pischannel = VikRequest::getInt('ischannel', '', 'request');
4889 $pcommission = VikRequest::getFloat('commission', '', 'request');
4890 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
4891 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
4892 $pchname = VikRequest::getString('chname', '', 'request');
4893 $pchcolor = VikRequest::getString('chcolor', '', 'request');
4894 $pwhere = VikRequest::getInt('where', '', 'request');
4895 $ptmpl = VikRequest::getString('tmpl', '', 'request');
4896 $pcheckin = VikRequest::getInt('checkin', '', 'request');
4897 $pbid = VikRequest::getInt('bid', '', 'request');
4898 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
4899 if (!empty($pwhere) && !empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
4900 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `id`=".(int)$pwhere." LIMIT 1;";
4901 $dbo->setQuery($q);
4902 $dbo->execute();
4903 if ($dbo->getNumRows() == 1) {
4904 $customer = $dbo->loadAssoc();
4905 } else {
4906 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
4907 exit;
4908 }
4909 /**
4910 * Existing customers are recognized by equal first name, last name and email address.
4911 *
4912 * @since 1.3.0
4913 */
4914 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `first_name`=".$dbo->quote($pfirst_name)." AND `last_name`=".$dbo->quote($plast_name)." AND `email`=".$dbo->quote($pemail)." AND `id`!=".(int)$pwhere." LIMIT 1;";
4915 $dbo->setQuery($q);
4916 $dbo->execute();
4917 if ($dbo->getNumRows() == 0) {
4918 $cpin = VikBooking::getCPinIstance();
4919 if (empty($ppin)) {
4920 $ppin = $customer['pin'];
4921 } elseif ($cpin->pinExists($ppin, $customer['pin'])) {
4922 $ppin = $cpin->generateUniquePin();
4923 }
4924 //file upload
4925 jimport('joomla.filesystem.file');
4926 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
4927 $gimg = "";
4928 if (isset($pimg) && strlen(trim($pimg['name']))) {
4929 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
4930 $src = $pimg['tmp_name'];
4931 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
4932 $j = "";
4933 if (file_exists($dest.$filename)) {
4934 $j = rand(171, 1717);
4935 while (file_exists($dest.$j.$filename)) {
4936 $j++;
4937 }
4938 }
4939 $finaldest = $dest.$j.$filename;
4940 $check = getimagesize($pimg['tmp_name']);
4941 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
4942 if (VikBooking::uploadFile($src, $finaldest)) {
4943 $gimg = $j.$filename;
4944 } else {
4945 VikError::raiseWarning('', 'Error while uploading image');
4946 }
4947 } else {
4948 VikError::raiseWarning('', 'Uploaded file is not an Image');
4949 }
4950 } elseif (!empty($pscandocimg)) {
4951 $gimg = $pscandocimg;
4952 }
4953 //
4954 $pischannel = $pischannel > 0 ? 1 : 0;
4955 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
4956 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
4957 $pchname = str_replace(' ', '', trim($pchname));
4958 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
4959 $chparams = array(
4960 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
4961 'calccmmon' => $pcalccmmon,
4962 'applycmmon' => $papplycmmon,
4963 'chcolor' => $pchcolor,
4964 'chname' => $pchname
4965 );
4966
4967 /**
4968 * Customer profile picture (URL or uploaded file).
4969 *
4970 * @since 1.15.3 (J) - 1.5.5 (WP)
4971 */
4972 $customer_pic = VikRequest::getString('pic', '', 'request');
4973 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
4974 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
4975 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
4976 $src = $customer_pic_img['tmp_name'];
4977 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
4978 $j = "";
4979 if (is_file($dest.$filename)) {
4980 $j = rand(1, 99999);
4981 while (is_file($dest . $j .$filename)) {
4982 $j++;
4983 }
4984 }
4985 $finaldest = $dest . $j . $filename;
4986 $check = getimagesize($customer_pic_img['tmp_name']);
4987 if (($check[2] & imagetypes())) {
4988 if (VikBooking::uploadFile($src, $finaldest)) {
4989 $customer_pic = $j . $filename;
4990 } else {
4991 VikError::raiseWarning('', 'Error while uploading image');
4992 }
4993 } else {
4994 VikError::raiseWarning('', 'Uploaded file is not an Image');
4995 }
4996 }
4997
4998 // update customer object
4999 $new_customer = new stdClass;
5000 $new_customer->id = (int)$pwhere;
5001 $new_customer->first_name = $pfirst_name;
5002 $new_customer->last_name = $plast_name;
5003 $new_customer->email = $pemail;
5004 $new_customer->phone = $pphone;
5005 $new_customer->country = $pcountry;
5006 $new_customer->pin = $ppin;
5007 $new_customer->ujid = $pujid;
5008 $new_customer->address = $paddress;
5009 $new_customer->city = $pcity;
5010 $new_customer->zip = $pzip;
5011 $new_customer->state = $pstate;
5012 $new_customer->doctype = $pdoctype;
5013 $new_customer->docnum = $pdocnum;
5014 if (!empty($gimg)) {
5015 $new_customer->docimg = $gimg;
5016 }
5017 $new_customer->notes = $pnotes;
5018 $new_customer->ischannel = $pischannel;
5019 $new_customer->chdata = json_encode($chparams);
5020 $new_customer->company = $pcompany;
5021 $new_customer->vat = $pvat;
5022 $new_customer->gender = $pgender;
5023 $new_customer->bdate = $pbdate;
5024 $new_customer->pbirth = $ppbirth;
5025 $new_customer->fisccode = $pfisccode;
5026 $new_customer->pec = $ppec;
5027 $new_customer->recipcode = $precipcode;
5028 $new_customer->pic = $customer_pic;
5029 /**
5030 * We need to update the previous information stored through
5031 * the custom fields when making a reservation for/by this client.
5032 *
5033 * @since 1.13
5034 */
5035 $skip_prev_fields = array(
5036 'id',
5037 'ujid',
5038 'docimg',
5039 'ischannel',
5040 'chdata',
5041 'notes',
5042 );
5043 if (!empty($customer['cfields'])) {
5044 $custf_info = json_decode($customer['cfields'], true);
5045 foreach ($new_customer as $fname => $fnewval) {
5046 if (!isset($customer[$fname]) || in_array($fname, $skip_prev_fields)) {
5047 continue;
5048 }
5049 // seek for old value in custom fields submitted
5050 foreach ($custf_info as $k => $v) {
5051 if (!empty($customer[$fname]) && $v == $customer[$fname]) {
5052 // field found, replace it with the new value
5053 $custf_info[$k] = $fnewval;
5054 }
5055 }
5056 }
5057 // update value on db
5058 $new_customer->cfields = json_encode($custf_info);
5059 }
5060
5061 // trigger the customer before-update event
5062 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = true);
5063
5064 // update customer record
5065 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5066
5067 // trigger the customer after-save event
5068 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = false);
5069
5070 // update all the bookings affected by this Customer ID as a sales channel
5071 $source_name = 'customer'.$pwhere.'_'.$pchname;
5072 if ($pischannel > 0) {
5073 $oid_clause = '';
5074 if ($customer['ischannel'] < 1) {
5075 //Was not a sales channel but now it is, so update all his bookings
5076 $q = "SELECT `o`.`idorderota`, `co`.`idorder`
5077 FROM `#__vikbooking_customers_orders` AS `co`
5078 LEFT JOIN `#__vikbooking_orders` AS `o` ON `co`.`idorder`=`o`.`id`
5079 WHERE `co`.`idcustomer`=".$customer['id'].";";
5080 $dbo->setQuery($q);
5081 $all_bids = $dbo->loadAssocList();
5082 if ($all_bids) {
5083 $bids = array();
5084 foreach ($all_bids as $bid) {
5085 if (empty($idorderota) && !in_array($bid['idorder'], $bids)) {
5086 $bids[] = $bid['idorder'];
5087 }
5088 }
5089 if ($bids) {
5090 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5091 }
5092 }
5093 }
5094 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5095 } else {
5096 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5097 }
5098 $dbo->setQuery($q);
5099 $dbo->execute();
5100 //
5101 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5102 } else {
5103 //email already exists
5104 $ex_customer = $dbo->loadAssoc();
5105 //check if coming from the Check-in view or not
5106 if (!empty($pcheckin) && !empty($pbid)) {
5107 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5108 /**
5109 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5110 */
5111 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5112 //
5113 exit;
5114 } elseif (!empty($pgoto)) {
5115 // check if coming from a specific task
5116 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5117 $mainframe->redirect(base64_decode($pgoto));
5118 exit;
5119 } else {
5120 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editcustomer&cid[]='.$ex_customer['id'].'" target="_blank">'.$ex_customer['first_name'].' '.$ex_customer['last_name'].'</a>');
5121 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5122 exit;
5123 }
5124 }
5125 }
5126
5127 //check if coming from the Check-in view
5128 if (!empty($pcheckin) && !empty($pbid)) {
5129 /**
5130 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5131 */
5132 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5133 exit;
5134 }
5135
5136 if ($stay) {
5137 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5138 exit;
5139 }
5140
5141 // check if coming from a specific task
5142 if (!empty($pgoto)) {
5143 $mainframe->redirect(base64_decode($pgoto));
5144 exit;
5145 }
5146
5147 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5148 }
5149
5150 public function savecustomer() {
5151 if (!JSession::checkToken()) {
5152 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5153 }
5154 $dbo = JFactory::getDbo();
5155 $mainframe = JFactory::getApplication();
5156 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5157 $plast_name = VikRequest::getString('last_name', '', 'request');
5158 $pcompany = VikRequest::getString('company', '', 'request');
5159 $pvat = VikRequest::getString('vat', '', 'request');
5160 $pemail = VikRequest::getString('email', '', 'request');
5161 $pphone = VikRequest::getString('phone', '', 'request');
5162 $pcountry = VikRequest::getString('country', '', 'request');
5163 $pstate = VikRequest::getString('state', '', 'request');
5164 $ppin = VikRequest::getString('pin', '', 'request');
5165 $pujid = VikRequest::getInt('ujid', '', 'request');
5166 $paddress = VikRequest::getString('address', '', 'request');
5167 $pcity = VikRequest::getString('city', '', 'request');
5168 $pzip = VikRequest::getString('zip', '', 'request');
5169 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5170 $ppec = VikRequest::getString('pec', '', 'request');
5171 $precipcode = VikRequest::getString('recipcode', '', 'request');
5172 $pgender = VikRequest::getString('gender', '', 'request');
5173 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5174 $pbdate = VikRequest::getString('bdate', '', 'request');
5175 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5176 $pdoctype = VikRequest::getString('doctype', '', 'request');
5177 $pdocnum = VikRequest::getString('docnum', '', 'request');
5178 $pnotes = VikRequest::getString('notes', '', 'request');
5179 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5180 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5181 $pcommission = VikRequest::getFloat('commission', '', 'request');
5182 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5183 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5184 $pchname = VikRequest::getString('chname', '', 'request');
5185 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5186 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5187 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5188 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5189 $pbid = VikRequest::getInt('bid', '', 'request');
5190 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5191 $cpin = VikBooking::getCPinIstance();
5192 /**
5193 * Existing customers are recognized by equal first name, last name and email address.
5194 *
5195 * @since 1.3.0
5196 */
5197 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `first_name`=".$dbo->quote($pfirst_name)." AND `last_name`=".$dbo->quote($plast_name)." AND `email`=".$dbo->quote($pemail)." LIMIT 1;";
5198 $dbo->setQuery($q);
5199 $dbo->execute();
5200 if ($dbo->getNumRows() == 0) {
5201 if (empty($ppin)) {
5202 $ppin = $cpin->generateUniquePin();
5203 } elseif ($cpin->pinExists($ppin)) {
5204 $ppin = $cpin->generateUniquePin();
5205 }
5206 //file upload
5207 jimport('joomla.filesystem.file');
5208 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5209 $gimg = "";
5210 if (isset($pimg) && strlen(trim($pimg['name']))) {
5211 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5212 $src = $pimg['tmp_name'];
5213 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5214 $j = "";
5215 if (file_exists($dest.$filename)) {
5216 $j = rand(171, 1717);
5217 while (file_exists($dest.$j.$filename)) {
5218 $j++;
5219 }
5220 }
5221 $finaldest = $dest.$j.$filename;
5222 $check = getimagesize($pimg['tmp_name']);
5223 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5224 if (VikBooking::uploadFile($src, $finaldest)) {
5225 $gimg = $j.$filename;
5226 } else {
5227 VikError::raiseWarning('', 'Error while uploading image');
5228 }
5229 } else {
5230 VikError::raiseWarning('', 'Uploaded file is not an Image');
5231 }
5232 } elseif (!empty($pscandocimg)) {
5233 $gimg = $pscandocimg;
5234 }
5235 //
5236 $pischannel = $pischannel > 0 ? 1 : 0;
5237 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5238 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5239 $pchname = str_replace(' ', '', trim($pchname));
5240 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5241 $chparams = array(
5242 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5243 'calccmmon' => $pcalccmmon,
5244 'applycmmon' => $papplycmmon,
5245 'chcolor' => $pchcolor,
5246 'chname' => $pchname
5247 );
5248
5249 /**
5250 * Customer profile picture (URL or uploaded file).
5251 *
5252 * @since 1.15.3 (J) - 1.5.5 (WP)
5253 */
5254 $customer_pic = VikRequest::getString('pic', '', 'request');
5255 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5256 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5257 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5258 $src = $customer_pic_img['tmp_name'];
5259 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5260 $j = "";
5261 if (is_file($dest.$filename)) {
5262 $j = rand(1, 99999);
5263 while (is_file($dest . $j .$filename)) {
5264 $j++;
5265 }
5266 }
5267 $finaldest = $dest . $j . $filename;
5268 $check = getimagesize($customer_pic_img['tmp_name']);
5269 if (($check[2] & imagetypes())) {
5270 if (VikBooking::uploadFile($src, $finaldest)) {
5271 $customer_pic = $j . $filename;
5272 } else {
5273 VikError::raiseWarning('', 'Error while uploading image');
5274 }
5275 } else {
5276 VikError::raiseWarning('', 'Uploaded file is not an Image');
5277 }
5278 }
5279
5280 // build customer record
5281 $customer_obj = new stdClass;
5282 $customer_obj->first_name = $pfirst_name;
5283 $customer_obj->last_name = $plast_name;
5284 $customer_obj->email = $pemail;
5285 $customer_obj->phone = $pphone;
5286 $customer_obj->country = $pcountry;
5287 $customer_obj->pin = $ppin;
5288 $customer_obj->ujid = $pujid;
5289 $customer_obj->address = $paddress;
5290 $customer_obj->city = $pcity;
5291 $customer_obj->zip = $pzip;
5292 $customer_obj->state = $pstate;
5293 $customer_obj->doctype = $pdoctype;
5294 $customer_obj->docnum = $pdocnum;
5295 $customer_obj->docimg = $gimg;
5296 $customer_obj->notes = $pnotes;
5297 $customer_obj->ischannel = $pischannel;
5298 $customer_obj->chdata = json_encode($chparams);
5299 $customer_obj->company = $pcompany;
5300 $customer_obj->vat = $pvat;
5301 $customer_obj->gender = $pgender;
5302 $customer_obj->bdate = $pbdate;
5303 $customer_obj->pbirth = $ppbirth;
5304 $customer_obj->fisccode = $pfisccode;
5305 $customer_obj->pec = $ppec;
5306 $customer_obj->recipcode = $precipcode;
5307 $customer_obj->pic = !empty($customer_pic) ? $customer_pic : null;
5308
5309 // trigger the customer before-insert event
5310 $cpin->pluginCustomerSync(0, 'insert', (array)$customer_obj, $before = true);
5311
5312 // insert the new customer record
5313 $dbo->insertObject('#__vikbooking_customers', $customer_obj, 'id');
5314 $lid = isset($customer_obj->id) ? $customer_obj->id : null;
5315
5316 // trigger the customer after-save event
5317 $cpin->pluginCustomerSync($lid, 'insert', (array)$customer_obj, $before = false);
5318
5319 if (!empty($lid)) {
5320 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5321 //check if coming from the Check-in view
5322 if (!empty($pcheckin) && !empty($pbid)) {
5323 $cpin->setNewPin($ppin);
5324 $cpin->setNewCustomerId($lid);
5325 $cpin->saveCustomerBooking($pbid);
5326 /**
5327 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5328 */
5329 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5330 //
5331 exit;
5332 }
5333 // check if coming from a specific task
5334 if (!empty($pgoto) && !empty($pbid)) {
5335 $cpin->setNewPin($ppin);
5336 $cpin->setNewCustomerId($lid);
5337 $cpin->saveCustomerBooking($pbid);
5338 $mainframe->redirect(base64_decode($pgoto));
5339 exit;
5340 }
5341 }
5342 } else {
5343 //email already exists
5344 $ex_customer = $dbo->loadAssoc();
5345 //check if coming from the Check-in view or not
5346 if (!empty($pcheckin) && !empty($pbid)) {
5347 $cpin->setNewPin($ex_customer['pin']);
5348 $cpin->setNewCustomerId($ex_customer['id']);
5349 $cpin->saveCustomerBooking($pbid);
5350 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5351 /**
5352 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5353 */
5354 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5355 //
5356 exit;
5357 } elseif (!empty($pgoto) && !empty($pbid)) {
5358 // check if coming from a specific task
5359 $cpin->setNewPin($ex_customer['pin']);
5360 $cpin->setNewCustomerId($ex_customer['id']);
5361 $cpin->saveCustomerBooking($pbid);
5362 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5363 $mainframe->redirect(base64_decode($pgoto));
5364 exit;
5365 } else {
5366 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editcustomer&cid[]='.$ex_customer['id'].'" target="_blank">'.$ex_customer['first_name'].' '.$ex_customer['last_name'].'</a>');
5367 }
5368 }
5369 }
5370 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5371 }
5372
5373 public function customers() {
5374 VikBookingHelper::printHeader("22");
5375
5376 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5377
5378 parent::display();
5379
5380 if (VikBooking::showFooter()) {
5381 VikBookingHelper::printFooter();
5382 }
5383 }
5384
5385 public function newcustomer() {
5386 VikBookingHelper::printHeader("22");
5387
5388 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5389
5390 parent::display();
5391
5392 if (VikBooking::showFooter()) {
5393 VikBookingHelper::printFooter();
5394 }
5395 }
5396
5397 public function editcustomer() {
5398 VikBookingHelper::printHeader("22");
5399
5400 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5401
5402 parent::display();
5403
5404 if (VikBooking::showFooter()) {
5405 VikBookingHelper::printFooter();
5406 }
5407 }
5408
5409 public function removecustomers()
5410 {
5411 if (!JSession::checkToken()) {
5412 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5413 }
5414
5415 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5416 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5417 }
5418
5419 $ids = VikRequest::getVar('cid', array(0));
5420 if ($ids) {
5421 $dbo = JFactory::getDBO();
5422 $cpin = VikBooking::getCPinIstance();
5423 foreach ($ids as $d) {
5424 $cpin->pluginCustomerSync($d, 'delete');
5425 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5426 $dbo->setQuery($q);
5427 $dbo->execute();
5428 }
5429 }
5430 $mainframe = JFactory::getApplication();
5431 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5432 }
5433
5434 public function restrictions() {
5435 VikBookingHelper::printHeader("restrictions");
5436
5437 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5438
5439 parent::display();
5440
5441 if (VikBooking::showFooter()) {
5442 VikBookingHelper::printFooter();
5443 }
5444 }
5445
5446 public function newrestriction() {
5447 VikBookingHelper::printHeader("restrictions");
5448
5449 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5450
5451 parent::display();
5452
5453 if (VikBooking::showFooter()) {
5454 VikBookingHelper::printFooter();
5455 }
5456 }
5457
5458 public function editrestriction() {
5459 VikBookingHelper::printHeader("restrictions");
5460
5461 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5462
5463 parent::display();
5464
5465 if (VikBooking::showFooter()) {
5466 VikBookingHelper::printFooter();
5467 }
5468 }
5469
5470 public function createrestriction()
5471 {
5472 if (!JSession::checkToken()) {
5473 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5474 }
5475
5476 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5477 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5478 }
5479
5480 $dbo = JFactory::getDBO();
5481 $session = JFactory::getSession();
5482 $mainframe = JFactory::getApplication();
5483 $updforvcm = $session->get('vbVcmRatesUpd', '');
5484 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5485 $pname = VikRequest::getString('name', '', 'request');
5486 $pmonth = VikRequest::getInt('month', '', 'request');
5487 $pmonth = empty($pmonth) ? 0 : $pmonth;
5488 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5489 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5490 $pdto = VikRequest::getString('dto', '', 'request');
5491 $pwday = VikRequest::getString('wday', '', 'request');
5492 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5493 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5494 $pcomboa = VikRequest::getString('comboa', '', 'request');
5495 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5496 $pcombob = VikRequest::getString('combob', '', 'request');
5497 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5498 $pcomboc = VikRequest::getString('comboc', '', 'request');
5499 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5500 $pcombod = VikRequest::getString('combod', '', 'request');
5501 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5502 $combostr = '';
5503 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5504 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5505 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5506 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5507 $pminlos = VikRequest::getInt('minlos', '', 'request');
5508 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5509 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5510 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5511 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5512 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5513 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5514 $pallrooms = $pallrooms == "1" ? 1 : 0;
5515 $pidrooms = VikRequest::getVar('idrooms', array(0));
5516 $ridr = '';
5517 $roomidsforsess = array();
5518 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5519 foreach ($pidrooms as $idr) {
5520 if (empty($idr)) {
5521 continue;
5522 }
5523 $ridr .= '-'.$idr.'-;';
5524 $roomidsforsess[] = (int)$idr;
5525 }
5526 } elseif ($pallrooms > 0) {
5527 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5528 $dbo->setQuery($q);
5529 $dbo->execute();
5530 if ($dbo->getNumRows() > 0) {
5531 $fetchids = $dbo->loadAssocList();
5532 foreach ($fetchids as $fetchid) {
5533 $roomidsforsess[] = (int)$fetchid['id'];
5534 }
5535 }
5536 }
5537 $pcta = VikRequest::getInt('cta', '', 'request');
5538 $pctd = VikRequest::getInt('ctd', '', 'request');
5539 $pctad = VikRequest::getVar('ctad', array());
5540 $pctdd = VikRequest::getVar('ctdd', array());
5541 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5542 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5543 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5544 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5545 // exit;
5546 }
5547
5548 //check if there are restrictions for this month
5549 if ($pmonth > 0) {
5550 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5551 $dbo->setQuery($q);
5552 $dbo->execute();
5553 if ($dbo->getNumRows() > 0) {
5554 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5555 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5556 exit;
5557 }
5558 $pdfrom = 0;
5559 $pdto = 0;
5560 } else {
5561 //dates range
5562 if (empty($pdfrom) || empty($pdto)) {
5563 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5564 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5565 exit;
5566 } else {
5567 $housto = $pdfrom == $pdto ? 23 : 0;
5568 $minsto = $pdfrom == $pdto ? 59 : 0;
5569 $secsto = $pdfrom == $pdto ? 59 : 0;
5570 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5571 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5572 }
5573 if ($pdfrom > $pdto) {
5574 // invalid dates in the past
5575 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5576 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5577 exit;
5578 }
5579 }
5580 //CTA and CTD
5581 $setcta = array();
5582 $setctd = array();
5583 if ($pcta > 0 && count($pctad) > 0) {
5584 foreach ($pctad as $ctwd) {
5585 if (strlen($ctwd)) {
5586 $setcta[] = '-'.(int)$ctwd.'-';
5587 }
5588 }
5589 }
5590 if ($pctd > 0 && count($pctdd) > 0) {
5591 foreach ($pctdd as $ctwd) {
5592 if (strlen($ctwd)) {
5593 $setctd[] = '-'.(int)$ctwd.'-';
5594 }
5595 }
5596 }
5597 //
5598 //update session values
5599 if (!($pdfrom > 0)) {
5600 $attemptyear = (int)date('Y');
5601 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5602 if ($attemptfrom < time()) {
5603 $attemptyear++;
5604 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5605 }
5606 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5607 } else {
5608 $attemptfrom = $pdfrom;
5609 $attemptto = $pdto;
5610 }
5611 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5612 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5613 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5614 } else {
5615 $updforvcm['dfrom'] = $attemptfrom;
5616 }
5617 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5618 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5619 } else {
5620 $updforvcm['dto'] = $attemptto;
5621 }
5622 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5623 foreach ($roomidsforsess as $rid) {
5624 if (!in_array($rid, $updforvcm['rooms'])) {
5625 $updforvcm['rooms'][] = $rid;
5626 }
5627 }
5628 } else {
5629 $updforvcm['rooms'] = $roomidsforsess;
5630 }
5631 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5632 $updforvcm['rplans'] = array();
5633 }
5634 $session->set('vbVcmRatesUpd', $updforvcm);
5635 //
5636 $q = "INSERT INTO `#__vikbooking_restrictions` (`name`,`month`,`wday`,`minlos`,`multiplyminlos`,`maxlos`,`dfrom`,`dto`,`wdaytwo`,`wdaycombo`,`allrooms`,`idrooms`,`ctad`,`ctdd`) VALUES(".$dbo->quote($pname).", '".$pmonth."', ".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").", '".$pminlos."', '".$pmultiplyminlos."', '".$pmaxlos."', ".$pdfrom.", ".$pdto.", ".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").", ".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").", ".$pallrooms.", ".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", ".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", ".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL").");";
5637 $dbo->setQuery($q);
5638 $dbo->execute();
5639 $lid = $dbo->insertid();
5640 if (!empty($lid)) {
5641 /**
5642 * Repeat restriction on the selected week days until the limit
5643 *
5644 * @since 1.13
5645 */
5646 $prepeat = VikRequest::getInt('repeat', 0, 'request');
5647 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
5648 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
5649 $repeat_intervals = array();
5650 $start = getdate($pdfrom);
5651 $end = getdate($pdto);
5652 $wdays = array();
5653 while ($start[0] <= $end[0]) {
5654 // push requested week day
5655 array_push($wdays, $start['wday']);
5656 // next day
5657 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
5658 }
5659 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
5660 if (count($wdays) < 7 && $dtuntil > $pdto) {
5661 // increment end date for the repeat
5662 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5663 //
5664 $until_info = getdate($dtuntil);
5665 $interval = array();
5666 while ($end[0] <= $until_info[0]) {
5667 if (in_array($end['wday'], $wdays)) {
5668 if (!isset($interval['from'])) {
5669 $interval['from'] = $end[0];
5670 }
5671 $interval['to'] = $end[0];
5672 } else {
5673 if (isset($interval['from'])) {
5674 // append interval
5675 array_push($repeat_intervals, $interval);
5676 // reset interval
5677 $interval = array();
5678 }
5679 }
5680 // next day
5681 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5682 }
5683 if (isset($interval['from'])) {
5684 // append last hanging interval
5685 array_push($repeat_intervals, $interval);
5686 }
5687 if (count($repeat_intervals)) {
5688 // create the repeated records for the calculated intervals
5689 $repeat_count = 2;
5690 foreach ($repeat_intervals as $rp) {
5691 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
5692 // adjust time in case of equal dates (1 single day restriction)
5693 $rpfrom = getdate($rp['from']);
5694 $rpto = getdate($rp['to']);
5695 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
5696 /**
5697 * The end date of the restriction must cover the whole day until 23:59:59.
5698 *
5699 * @since 1.15.4 (J) - 1.5.4 (WP)
5700 */
5701 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
5702 }
5703 // adjust name
5704 $restr_rp_name = $pname . " #{$repeat_count}";
5705 //
5706 $q = "INSERT INTO `#__vikbooking_restrictions` (`name`,`month`,`wday`,`minlos`,`multiplyminlos`,`maxlos`,`dfrom`,`dto`,`wdaytwo`,`wdaycombo`,`allrooms`,`idrooms`,`ctad`,`ctdd`) VALUES(".$dbo->quote($restr_rp_name).", '".$pmonth."', ".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").", '".$pminlos."', '".$pmultiplyminlos."', '".$pmaxlos."', ".$rp['from'].", ".$rp['to'].", ".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").", ".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").", ".$pallrooms.", ".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", ".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", ".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL").");";
5707 $dbo->setQuery($q);
5708 $dbo->execute();
5709 $lid = $dbo->insertid();
5710 if (!empty($lid)) {
5711 $repeat_count++;
5712 }
5713 }
5714 }
5715 }
5716 }
5717 //
5718 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5719 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5720 } else {
5721 VikError::raiseWarning('', 'Error while saving');
5722 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5723 }
5724 }
5725
5726 public function updaterestriction()
5727 {
5728 if (!JSession::checkToken()) {
5729 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5730 }
5731
5732 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5733 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5734 }
5735
5736 $dbo = JFactory::getDBO();
5737 $session = JFactory::getSession();
5738 $mainframe = JFactory::getApplication();
5739 $updforvcm = $session->get('vbVcmRatesUpd', '');
5740 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5741 $pwhere = VikRequest::getInt('where', '', 'request');
5742 $pname = VikRequest::getString('name', '', 'request');
5743 $pmonth = VikRequest::getInt('month', '', 'request');
5744 $pmonth = empty($pmonth) ? 0 : $pmonth;
5745 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5746 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5747 $pdto = VikRequest::getString('dto', '', 'request');
5748 $pwday = VikRequest::getString('wday', '', 'request');
5749 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5750 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5751 $pcomboa = VikRequest::getString('comboa', '', 'request');
5752 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5753 $pcombob = VikRequest::getString('combob', '', 'request');
5754 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5755 $pcomboc = VikRequest::getString('comboc', '', 'request');
5756 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5757 $pcombod = VikRequest::getString('combod', '', 'request');
5758 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5759 $combostr = '';
5760 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5761 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5762 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5763 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5764 $pminlos = VikRequest::getInt('minlos', '', 'request');
5765 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5766 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5767 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5768 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5769 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5770 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5771 $pallrooms = $pallrooms == "1" ? 1 : 0;
5772 $pidrooms = VikRequest::getVar('idrooms', array(0));
5773 $ridr = '';
5774 $roomidsforsess = array();
5775 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5776 foreach ($pidrooms as $idr) {
5777 if (empty($idr)) {
5778 continue;
5779 }
5780 $ridr .= '-'.$idr.'-;';
5781 $roomidsforsess[] = (int)$idr;
5782 }
5783 } elseif ($pallrooms > 0) {
5784 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5785 $dbo->setQuery($q);
5786 $dbo->execute();
5787 if ($dbo->getNumRows() > 0) {
5788 $fetchids = $dbo->loadAssocList();
5789 foreach ($fetchids as $fetchid) {
5790 $roomidsforsess[] = (int)$fetchid['id'];
5791 }
5792 }
5793 }
5794 $pcta = VikRequest::getInt('cta', '', 'request');
5795 $pctd = VikRequest::getInt('ctd', '', 'request');
5796 $pctad = VikRequest::getVar('ctad', array());
5797 $pctdd = VikRequest::getVar('ctdd', array());
5798 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5799 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5800 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5801 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5802 // exit;
5803 }
5804 //check if there are restrictions for this month
5805 if ($pmonth > 0) {
5806 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
5807 $dbo->setQuery($q);
5808 $dbo->execute();
5809 if ($dbo->getNumRows() > 0) {
5810 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5811 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5812 exit;
5813 }
5814 $pdfrom = 0;
5815 $pdto = 0;
5816 } else {
5817 //dates range
5818 if (empty($pdfrom) || empty($pdto)) {
5819 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5820 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5821 exit;
5822 } else {
5823 $housto = $pdfrom == $pdto ? 23 : 0;
5824 $minsto = $pdfrom == $pdto ? 59 : 0;
5825 $secsto = $pdfrom == $pdto ? 59 : 0;
5826 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5827 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5828 }
5829 if ($pdfrom > $pdto) {
5830 // invalid dates in the past
5831 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5832 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5833 exit;
5834 }
5835 }
5836 //CTA and CTD
5837 $setcta = array();
5838 $setctd = array();
5839 if ($pcta > 0 && count($pctad) > 0) {
5840 foreach ($pctad as $ctwd) {
5841 if (strlen($ctwd)) {
5842 $setcta[] = '-'.(int)$ctwd.'-';
5843 }
5844 }
5845 }
5846 if ($pctd > 0 && count($pctdd) > 0) {
5847 foreach ($pctdd as $ctwd) {
5848 if (strlen($ctwd)) {
5849 $setctd[] = '-'.(int)$ctwd.'-';
5850 }
5851 }
5852 }
5853 //
5854 //update session values
5855 if (!($pdfrom > 0)) {
5856 $attemptyear = (int)date('Y');
5857 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5858 if ($attemptfrom < time()) {
5859 $attemptyear++;
5860 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5861 }
5862 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5863 } else {
5864 $attemptfrom = $pdfrom;
5865 $attemptto = $pdto;
5866 }
5867 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5868 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5869 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5870 } else {
5871 $updforvcm['dfrom'] = $attemptfrom;
5872 }
5873 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5874 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5875 } else {
5876 $updforvcm['dto'] = $attemptto;
5877 }
5878 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5879 foreach ($roomidsforsess as $rid) {
5880 if (!in_array($rid, $updforvcm['rooms'])) {
5881 $updforvcm['rooms'][] = $rid;
5882 }
5883 }
5884 } else {
5885 $updforvcm['rooms'] = $roomidsforsess;
5886 }
5887 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5888 $updforvcm['rplans'] = array();
5889 }
5890 $session->set('vbVcmRatesUpd', $updforvcm);
5891 //
5892 $q = "UPDATE `#__vikbooking_restrictions` SET `name`=".$dbo->quote($pname).",`month`='".$pmonth."',`wday`=".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").",`minlos`='".$pminlos."',`multiplyminlos`='".$pmultiplyminlos."',`maxlos`='".$pmaxlos."',`dfrom`=".$pdfrom.",`dto`=".$pdto.",`wdaytwo`=".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").",`wdaycombo`=".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").",`allrooms`=".$pallrooms.",`idrooms`=".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", `ctad`=".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", `ctdd`=".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL")." WHERE `id`='".$pwhere."';";
5893 $dbo->setQuery($q);
5894 $dbo->execute();
5895 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5896 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5897 }
5898
5899 public function removerestrictions()
5900 {
5901 if (!JSession::checkToken()) {
5902 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5903 }
5904
5905 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5906 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5907 }
5908
5909 $ids = VikRequest::getVar('cid', array(0));
5910 if ($ids) {
5911 $dbo = JFactory::getDBO();
5912 foreach ($ids as $d) {
5913 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
5914 $dbo->setQuery($q);
5915 $dbo->execute();
5916 }
5917 }
5918 $mainframe = JFactory::getApplication();
5919 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5920 }
5921
5922 public function prices() {
5923 VikBookingHelper::printHeader("1");
5924
5925 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
5926
5927 parent::display();
5928
5929 if (VikBooking::showFooter()) {
5930 VikBookingHelper::printFooter();
5931 }
5932 }
5933
5934 public function newprice() {
5935 VikBookingHelper::printHeader("1");
5936
5937 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
5938
5939 parent::display();
5940
5941 if (VikBooking::showFooter()) {
5942 VikBookingHelper::printFooter();
5943 }
5944 }
5945
5946 public function editprice() {
5947 VikBookingHelper::printHeader("1");
5948
5949 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
5950
5951 parent::display();
5952
5953 if (VikBooking::showFooter()) {
5954 VikBookingHelper::printFooter();
5955 }
5956 }
5957
5958 public function createprice()
5959 {
5960 if (!JSession::checkToken()) {
5961 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5962 }
5963
5964 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5965 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5966 }
5967
5968 $this->do_createprice();
5969 }
5970
5971 public function createprice_new()
5972 {
5973 if (!JSession::checkToken()) {
5974 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5975 }
5976
5977 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5978 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5979 }
5980
5981 $this->do_createprice(true);
5982 }
5983
5984 private function do_createprice($new = false)
5985 {
5986 $app = JFactory::getApplication();
5987 $dbo = JFactory::getDbo();
5988
5989 $pprice = VikRequest::getString('price', '', 'request');
5990 $pattr = VikRequest::getString('attr', '', 'request');
5991 $ppraliq = VikRequest::getInt('praliq', '', 'request');
5992 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
5993 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
5994 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
5995 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
5996 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
5997 $pminlos = VikRequest::getInt('minlos', 0, 'request');
5998 $pminlos = $pminlos < 0 ? 0 : $pminlos;
5999 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6000 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6001 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6002
6003 $is_derived = $app->input->getInt('is_derived', 0);
6004 $derived_id = $app->input->getUInt('derived_id', 0);
6005 $derived_data = $app->input->get('derived_data', [], 'array');
6006
6007 $parent_id = 0;
6008 $derived_info = null;
6009
6010 if ($is_derived && $derived_id && $derived_data) {
6011 $parent_id = $derived_id;
6012 $derived_info = $derived_data;
6013 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6014 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6015 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6016 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6017 if (!$derived_info['value']) {
6018 $parent_id = 0;
6019 $derived_info = null;
6020 }
6021 }
6022
6023 if (!empty($pprice)) {
6024 $q = "INSERT INTO `#__vikbooking_prices` (`name`,`attr`,`idiva`,`breakfast_included`,`free_cancellation`,`canc_deadline`,`canc_policy`,`minlos`,`minhadv`,`meal_plans`,`derived_id`,`derived_data`) VALUES(" . $dbo->q($pprice) . ", " . $dbo->q($pattr) . ", " . $dbo->q($ppraliq) . ", " . $pbreakfast_included . ", " . $pfree_cancellation . ", " . $pcanc_deadline . ", " . $dbo->q($pcanc_policy) . ", " . $pminlos . ", " . $pminhadv . ", " . $dbo->q(json_encode($pmeal_plans)) . ", {$parent_id}, " . ($derived_info ? $dbo->q(json_encode($derived_info)) : 'NULL') . ");";
6025 $dbo->setQuery($q);
6026 $dbo->execute();
6027 }
6028
6029 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6030 $app->close();
6031 }
6032
6033 public function updateprice()
6034 {
6035 if (!JSession::checkToken()) {
6036 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6037 }
6038
6039 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6040 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6041 }
6042
6043 $this->do_updateprice();
6044 }
6045
6046 public function updatepricestay()
6047 {
6048 if (!JSession::checkToken()) {
6049 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6050 }
6051
6052 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6053 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6054 }
6055
6056 $this->do_updateprice(true);
6057 }
6058
6059 private function do_updateprice($stay = false)
6060 {
6061 $app = JFactory::getApplication();
6062 $dbo = JFactory::getDbo();
6063
6064 $pprice = VikRequest::getString('price', '', 'request');
6065 $pattr = VikRequest::getString('attr', '', 'request');
6066 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6067 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6068 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6069 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6070 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6071 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6072 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6073 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6074 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6075 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6076 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6077 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6078
6079 $is_derived = $app->input->getInt('is_derived', 0);
6080 $derived_id = $app->input->getUInt('derived_id', 0);
6081 $derived_data = $app->input->get('derived_data', [], 'array');
6082
6083 $parent_id = 0;
6084 $derived_info = null;
6085
6086 if ($is_derived && $derived_id && $derived_data) {
6087 $parent_id = $derived_id;
6088 $derived_info = $derived_data;
6089 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6090 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6091 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6092 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6093 if (!$derived_info['value']) {
6094 $parent_id = 0;
6095 $derived_info = null;
6096 }
6097 }
6098
6099 if (!empty($pprice) && $pwhereup) {
6100 $q = "UPDATE `#__vikbooking_prices` SET `name`=" . $dbo->q($pprice) . ",`attr`=" . $dbo->q($pattr) . ",`idiva`=" . $dbo->q($ppraliq) . ",`breakfast_included`=" . $pbreakfast_included . ",`free_cancellation`=" . $pfree_cancellation . ",`canc_deadline`=" . $pcanc_deadline . ",`canc_policy`=" . $dbo->q($pcanc_policy) . ",`minlos`=" . $pminlos . ",`minhadv`=" . $pminhadv . ",`meal_plans`=" . $dbo->q(json_encode($pmeal_plans)) . ",`derived_id`={$parent_id},`derived_data`=" . ($derived_info ? $dbo->q(json_encode($derived_info)) : 'NULL') . " WHERE `id`=" . $dbo->q($pwhereup) . ";";
6101 $dbo->setQuery($q);
6102 $dbo->execute();
6103 }
6104
6105 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6106 $app->close();
6107 }
6108
6109 public function removeprice()
6110 {
6111 if (!JSession::checkToken()) {
6112 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6113 }
6114
6115 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6116 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6117 }
6118
6119 $ids = VikRequest::getVar('cid', array(0));
6120 if ($ids) {
6121 $dbo = JFactory::getDBO();
6122 foreach ($ids as $d) {
6123 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6124 $dbo->setQuery($q);
6125 $dbo->execute();
6126 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6127 $dbo->setQuery($q);
6128 $dbo->execute();
6129 }
6130 }
6131 $mainframe = JFactory::getApplication();
6132 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6133 }
6134
6135 public function iva() {
6136 VikBookingHelper::printHeader("2");
6137
6138 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6139
6140 parent::display();
6141
6142 if (VikBooking::showFooter()) {
6143 VikBookingHelper::printFooter();
6144 }
6145 }
6146
6147 public function newiva() {
6148 VikBookingHelper::printHeader("2");
6149
6150 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6151
6152 parent::display();
6153
6154 if (VikBooking::showFooter()) {
6155 VikBookingHelper::printFooter();
6156 }
6157 }
6158
6159 public function editiva() {
6160 VikBookingHelper::printHeader("2");
6161
6162 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6163
6164 parent::display();
6165
6166 if (VikBooking::showFooter()) {
6167 VikBookingHelper::printFooter();
6168 }
6169 }
6170
6171 public function createiva()
6172 {
6173 if (!JSession::checkToken()) {
6174 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6175 }
6176
6177 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6178 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6179 }
6180
6181 $paliqname = VikRequest::getString('aliqname', '', 'request');
6182 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6183 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6184 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6185 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6186 if (!empty($paliqperc)) {
6187 $dbo = JFactory::getDBO();
6188 $breakdown_str = '';
6189 if (count($pbreakdown_name) > 0) {
6190 $breakdown_values = array();
6191 $bkcount = 0;
6192 $tot_sub_aliq = 0;
6193 foreach ($pbreakdown_name as $key => $subtax) {
6194 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6195 $breakdown_values[$bkcount]['name'] = $subtax;
6196 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6197 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6198 $bkcount++;
6199 }
6200 }
6201 if (count($breakdown_values) > 0) {
6202 $breakdown_str = json_encode($breakdown_values);
6203 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6204 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6205 }
6206 }
6207 }
6208 $q = "INSERT INTO `#__vikbooking_iva` (`name`,`aliq`,`breakdown`,`taxcap`) VALUES(".$dbo->quote($paliqname).", ".$dbo->quote($paliqperc).", ".(empty($breakdown_str) ? 'NULL' : $dbo->quote($breakdown_str)).", ".($ptaxcap > 0 ? $dbo->quote($ptaxcap) : 'NULL').");";
6209 $dbo->setQuery($q);
6210 $dbo->execute();
6211 }
6212 $mainframe = JFactory::getApplication();
6213 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6214 }
6215
6216 public function updateiva()
6217 {
6218 if (!JSession::checkToken()) {
6219 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6220 }
6221
6222 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6223 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6224 }
6225
6226 $paliqname = VikRequest::getString('aliqname', '', 'request');
6227 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6228 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6229 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6230 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6231 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6232 if (!empty($paliqperc)) {
6233 $dbo = JFactory::getDBO();
6234 $breakdown_str = '';
6235 if (count($pbreakdown_name) > 0) {
6236 $breakdown_values = array();
6237 $bkcount = 0;
6238 $tot_sub_aliq = 0;
6239 foreach ($pbreakdown_name as $key => $subtax) {
6240 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6241 $breakdown_values[$bkcount]['name'] = $subtax;
6242 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6243 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6244 $bkcount++;
6245 }
6246 }
6247 if (count($breakdown_values) > 0) {
6248 $breakdown_str = json_encode($breakdown_values);
6249 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6250 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6251 }
6252 }
6253 }
6254 $q = "UPDATE `#__vikbooking_iva` SET `name`=".$dbo->quote($paliqname).",`aliq`=".$dbo->quote($paliqperc).",`breakdown`=".(empty($breakdown_str) ? 'NULL' : $dbo->quote($breakdown_str)).",`taxcap`=".($ptaxcap > 0 ? $dbo->quote($ptaxcap) : 'NULL')." WHERE `id`=".$dbo->quote($pwhereup).";";
6255 $dbo->setQuery($q);
6256 $dbo->execute();
6257 }
6258 $mainframe = JFactory::getApplication();
6259 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6260 }
6261
6262 public function removeiva()
6263 {
6264 if (!JSession::checkToken()) {
6265 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6266 }
6267
6268 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6269 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6270 }
6271
6272 $ids = VikRequest::getVar('cid', array(0));
6273 if ($ids) {
6274 $dbo = JFactory::getDBO();
6275 foreach ($ids as $d) {
6276 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6277 $dbo->setQuery($q);
6278 $dbo->execute();
6279 }
6280 }
6281 $mainframe = JFactory::getApplication();
6282 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6283 }
6284
6285 public function categories() {
6286 VikBookingHelper::printHeader("4");
6287
6288 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6289
6290 parent::display();
6291
6292 if (VikBooking::showFooter()) {
6293 VikBookingHelper::printFooter();
6294 }
6295 }
6296
6297 public function newcat() {
6298 VikBookingHelper::printHeader("4");
6299
6300 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6301
6302 parent::display();
6303
6304 if (VikBooking::showFooter()) {
6305 VikBookingHelper::printFooter();
6306 }
6307 }
6308
6309 public function editcat() {
6310 VikBookingHelper::printHeader("4");
6311
6312 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6313
6314 parent::display();
6315
6316 if (VikBooking::showFooter()) {
6317 VikBookingHelper::printFooter();
6318 }
6319 }
6320
6321 public function createcat()
6322 {
6323 if (!JSession::checkToken()) {
6324 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6325 }
6326
6327 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6328 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6329 }
6330
6331 $pcatname = VikRequest::getString('catname', '', 'request');
6332 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6333 if (!empty($pcatname)) {
6334 $dbo = JFactory::getDBO();
6335 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6336 $dbo->setQuery($q);
6337 $dbo->execute();
6338 }
6339 $mainframe = JFactory::getApplication();
6340 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6341 }
6342
6343 public function updatecat()
6344 {
6345 if (!JSession::checkToken()) {
6346 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6347 }
6348
6349 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6350 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6351 }
6352
6353 $pcatname = VikRequest::getString('catname', '', 'request');
6354 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6355 $pwhereup = VikRequest::getString('whereup', '', 'request');
6356 if (!empty($pcatname)) {
6357 $dbo = JFactory::getDBO();
6358 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6359 $dbo->setQuery($q);
6360 $dbo->execute();
6361 }
6362 $mainframe = JFactory::getApplication();
6363 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6364 }
6365
6366 public function removecat()
6367 {
6368 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6369 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6370 }
6371
6372 $ids = VikRequest::getVar('cid', array(0));
6373 if ($ids) {
6374 $dbo = JFactory::getDBO();
6375 foreach ($ids as $d) {
6376 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6377 $dbo->setQuery($q);
6378 $dbo->execute();
6379 }
6380 }
6381 $mainframe = JFactory::getApplication();
6382 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6383 }
6384
6385 public function carat() {
6386 VikBookingHelper::printHeader("5");
6387
6388 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6389
6390 parent::display();
6391
6392 if (VikBooking::showFooter()) {
6393 VikBookingHelper::printFooter();
6394 }
6395 }
6396
6397 public function newcarat() {
6398 VikBookingHelper::printHeader("5");
6399
6400 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6401
6402 parent::display();
6403
6404 if (VikBooking::showFooter()) {
6405 VikBookingHelper::printFooter();
6406 }
6407 }
6408
6409 public function editcarat() {
6410 VikBookingHelper::printHeader("5");
6411
6412 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6413
6414 parent::display();
6415
6416 if (VikBooking::showFooter()) {
6417 VikBookingHelper::printFooter();
6418 }
6419 }
6420
6421 public function createcarat()
6422 {
6423 if (!JSession::checkToken()) {
6424 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6425 }
6426
6427 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6428 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6429 }
6430
6431 $pcaratname = VikRequest::getString('caratname', '', 'request');
6432 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6433 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6434 $presizeto = VikRequest::getString('resizeto', '', 'request');
6435 $pidrooms = VikRequest::getVar('idrooms', array());
6436 if (!empty($pcaratname)) {
6437 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6438 jimport('joomla.filesystem.file');
6439 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6440 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6441 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6442 if (file_exists($updpath.$safename)) {
6443 $j=1;
6444 while (file_exists($updpath.$j.$safename)) {
6445 $j++;
6446 }
6447 $pwhere=$updpath.$j.$safename;
6448 } else {
6449 $j="";
6450 $pwhere=$updpath.$safename;
6451 }
6452 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6453 @unlink($pwhere);
6454 $picon="";
6455 } else {
6456 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6457 @chmod($pwhere, 0644);
6458 $picon=$j.$safename;
6459 if ($pautoresize=="1" && !empty($presizeto)) {
6460 $eforj = new vikResizer();
6461 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6462 if ($origmod) {
6463 @unlink($pwhere);
6464 $picon='r_'.$j.$safename;
6465 }
6466 }
6467 }
6468 } else {
6469 $picon="";
6470 }
6471 } else {
6472 $picon="";
6473 }
6474 $dbo = JFactory::getDbo();
6475 // get new ordering
6476 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6477 $dbo->setQuery($q);
6478 $dbo->execute();
6479 if ($dbo->getNumRows()) {
6480 $newsortnum = $dbo->loadResult() + 1;
6481 } else {
6482 $newsortnum = 1;
6483 }
6484 $pordering = VikRequest::getInt('ordering', 0, 'request');
6485 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6486 //
6487 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6488 $dbo->setQuery($q);
6489 $dbo->execute();
6490
6491 $new_carat_id = $dbo->insertid();
6492 if (!empty($new_carat_id)) {
6493 // assign/unset carat-rooms relations
6494 $rooms_with_carat = array();
6495 if (count($pidrooms)) {
6496 // assign this new carat to the requested rooms
6497 foreach ($pidrooms as $idroom) {
6498 if (empty($idroom)) {
6499 continue;
6500 }
6501 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6502 $dbo->setQuery($q);
6503 $dbo->execute();
6504 if (!$dbo->getNumRows()) {
6505 continue;
6506 }
6507 $room_data = $dbo->loadAssoc();
6508 array_push($rooms_with_carat, $room_data['id']);
6509 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6510 if (in_array((string)$new_carat_id, $current_carats)) {
6511 continue;
6512 }
6513 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6514 // make sure we do not concatenate a real ID to 0
6515 $current_carats = array();
6516 }
6517 array_push($current_carats, $new_carat_id);
6518 $new_opts = implode(';', $current_carats) . ';';
6519 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6520 $dbo->setQuery($q);
6521 $dbo->execute();
6522 }
6523 }
6524 if (!count($rooms_with_carat)) {
6525 // get all rooms to unset this carat (if previously set)
6526 array_push($rooms_with_carat, '0');
6527 }
6528 // unset the carat from the other rooms that may have it
6529 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6530 $dbo->setQuery($q);
6531 $dbo->execute();
6532 if ($dbo->getNumRows()) {
6533 $unset_rooms_carat = $dbo->loadAssocList();
6534 foreach ($unset_rooms_carat as $room_data) {
6535 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6536 if (!in_array((string)$new_carat_id, $current_carats)) {
6537 // this room is not using this carat
6538 continue;
6539 }
6540 $caratkey = array_search((string)$new_carat_id, $current_carats);
6541 if ($caratkey === false) {
6542 // key not found
6543 continue;
6544 }
6545 // unset this carat ID from the string
6546 unset($current_carats[$caratkey]);
6547 if (!count($current_carats)) {
6548 // a room with no carats assigned will be listed as "0;"
6549 $current_carats = array(0);
6550 }
6551 $new_opts = implode(';', $current_carats) . ';';
6552 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6553 $dbo->setQuery($q);
6554 $dbo->execute();
6555 }
6556 }
6557 //
6558 }
6559 }
6560 $mainframe = JFactory::getApplication();
6561 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6562 }
6563
6564 public function updatecarat()
6565 {
6566 if (!JSession::checkToken()) {
6567 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6568 }
6569
6570 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6571 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6572 }
6573
6574 $pcaratname = VikRequest::getString('caratname', '', 'request');
6575 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6576 $pwhereup = VikRequest::getString('whereup', '', 'request');
6577 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6578 $presizeto = VikRequest::getString('resizeto', '', 'request');
6579 $pidrooms = VikRequest::getVar('idrooms', array());
6580 $pordering = VikRequest::getInt('ordering', 1, 'request');
6581 if (!empty($pcaratname)) {
6582 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6583 jimport('joomla.filesystem.file');
6584 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6585 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6586 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6587 if (file_exists($updpath.$safename)) {
6588 $j=1;
6589 while (file_exists($updpath.$j.$safename)) {
6590 $j++;
6591 }
6592 $pwhere=$updpath.$j.$safename;
6593 } else {
6594 $j="";
6595 $pwhere=$updpath.$safename;
6596 }
6597 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6598 @unlink($pwhere);
6599 $picon="";
6600 } else {
6601 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6602 @chmod($pwhere, 0644);
6603 $picon=$j.$safename;
6604 if ($pautoresize=="1" && !empty($presizeto)) {
6605 $eforj = new vikResizer();
6606 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6607 if ($origmod) {
6608 @unlink($pwhere);
6609 $picon='r_'.$j.$safename;
6610 }
6611 }
6612 }
6613 } else {
6614 $picon="";
6615 }
6616 } else {
6617 $picon="";
6618 }
6619 $dbo = JFactory::getDbo();
6620 $q = "UPDATE `#__vikbooking_characteristics` SET `name`=".$dbo->quote($pcaratname).",".(strlen($picon) > 0 ? "`icon`='".$picon."'," : "")."`textimg`=".$dbo->quote($pcarattextimg).",`ordering`={$pordering} WHERE `id`=".$dbo->quote($pwhereup).";";
6621 $dbo->setQuery($q);
6622 $dbo->execute();
6623
6624 // assign/unset carat-rooms relations
6625 $rooms_with_carat = array();
6626 if (count($pidrooms)) {
6627 // assign this new carat to the requested rooms
6628 foreach ($pidrooms as $idroom) {
6629 if (empty($idroom)) {
6630 continue;
6631 }
6632 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6633 $dbo->setQuery($q);
6634 $dbo->execute();
6635 if (!$dbo->getNumRows()) {
6636 continue;
6637 }
6638 $room_data = $dbo->loadAssoc();
6639 array_push($rooms_with_carat, $room_data['id']);
6640 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6641 if (in_array((string)$pwhereup, $current_carats)) {
6642 continue;
6643 }
6644 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6645 // make sure we do not concatenate a real ID to 0
6646 $current_carats = array();
6647 }
6648 array_push($current_carats, $pwhereup);
6649 $new_carats = implode(';', $current_carats) . ';';
6650 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6651 $dbo->setQuery($q);
6652 $dbo->execute();
6653 }
6654 }
6655 if (!count($rooms_with_carat)) {
6656 // get all rooms to unset this carat (if previously set)
6657 array_push($rooms_with_carat, '0');
6658 }
6659 // unset the carat from the other rooms that may have it
6660 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6661 $dbo->setQuery($q);
6662 $dbo->execute();
6663 if ($dbo->getNumRows()) {
6664 $unset_rooms_carat = $dbo->loadAssocList();
6665 foreach ($unset_rooms_carat as $room_data) {
6666 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6667 if (!in_array((string)$pwhereup, $current_carats)) {
6668 // this room is not using this carat
6669 continue;
6670 }
6671 $caratkey = array_search((string)$pwhereup, $current_carats);
6672 if ($caratkey === false) {
6673 // key not found
6674 continue;
6675 }
6676 // unset this carat ID from the string
6677 unset($current_carats[$caratkey]);
6678 if (!count($current_carats)) {
6679 // a room with no carats assigned will be listed as "0;"
6680 $current_carats = array(0);
6681 }
6682 $new_carats = implode(';', $current_carats) . ';';
6683 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6684 $dbo->setQuery($q);
6685 $dbo->execute();
6686 }
6687 }
6688 //
6689 }
6690 $mainframe = JFactory::getApplication();
6691 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6692 }
6693
6694 public function removecarat()
6695 {
6696 if (!JSession::checkToken()) {
6697 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6698 }
6699
6700 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6701 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6702 }
6703
6704 $ids = VikRequest::getVar('cid', array(0));
6705 if ($ids) {
6706 $dbo = JFactory::getDBO();
6707 foreach ($ids as $d) {
6708 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6709 $dbo->setQuery($q);
6710 $dbo->execute();
6711 if ($dbo->getNumRows() == 1) {
6712 $rows = $dbo->loadAssocList();
6713 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
6714 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
6715 }
6716 }
6717 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6718 $dbo->setQuery($q);
6719 $dbo->execute();
6720 }
6721 }
6722 $mainframe = JFactory::getApplication();
6723 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6724 }
6725
6726 public function coupons() {
6727 VikBookingHelper::printHeader("17");
6728
6729 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
6730
6731 parent::display();
6732
6733 if (VikBooking::showFooter()) {
6734 VikBookingHelper::printFooter();
6735 }
6736 }
6737
6738 public function newcoupon() {
6739 VikBookingHelper::printHeader("17");
6740
6741 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6742
6743 parent::display();
6744
6745 if (VikBooking::showFooter()) {
6746 VikBookingHelper::printFooter();
6747 }
6748 }
6749
6750 public function editcoupon() {
6751 VikBookingHelper::printHeader("17");
6752
6753 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6754
6755 parent::display();
6756
6757 if (VikBooking::showFooter()) {
6758 VikBookingHelper::printFooter();
6759 }
6760 }
6761
6762 public function createcoupon()
6763 {
6764 if (!JSession::checkToken()) {
6765 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6766 }
6767
6768 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6769 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6770 }
6771
6772 $pcode = VikRequest::getString('code', '', 'request');
6773 $pvalue = VikRequest::getString('value', '', 'request');
6774 $pfrom = VikRequest::getString('from', '', 'request');
6775 $pto = VikRequest::getString('to', '', 'request');
6776 $pidrooms = VikRequest::getVar('idrooms', array(0));
6777 $ptype = VikRequest::getString('type', '', 'request');
6778 $ptype = $ptype == "1" ? 1 : 2;
6779 $ppercentot = VikRequest::getString('percentot', '', 'request');
6780 $ppercentot = $ppercentot == "1" ? 1 : 2;
6781 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6782 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6783 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6784 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6785 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6786 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6787 $pcustomers = VikRequest::getVar('customers', array());
6788 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6789 $stridrooms = "";
6790 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6791 foreach ($pidrooms as $ch) {
6792 if (!empty($ch)) {
6793 $stridrooms .= ";".$ch.";";
6794 }
6795 }
6796 }
6797 $strdatevalid = "";
6798 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6799 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6800 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6801 if ($first < $second) {
6802 $strdatevalid .= $first."-".$second;
6803 }
6804 }
6805
6806 $dbo = JFactory::getDbo();
6807 $app = JFactory::getApplication();
6808
6809 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
6810 $dbo->setQuery($q);
6811 $dbo->execute();
6812 if ($dbo->getNumRows() > 0) {
6813 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6814 } else {
6815 $q = "INSERT INTO `#__vikbooking_coupons` (`code`,`type`,`percentot`,`value`,`datevalid`,`allvehicles`,`idrooms`,`mintotord`,`excludetaxes`,`minlos`,`maxtotord`) VALUES(".$dbo->quote($pcode).",'".$ptype."','".$ppercentot."',".$dbo->quote($pvalue).",'".$strdatevalid."','".$pallvehicles."','".$stridrooms."', ".$dbo->quote($pmintotord).", {$pexcludetaxes}, {$pminlos}, " . $dbo->quote($pmaxtotord) . ");";
6816 $dbo->setQuery($q);
6817 $dbo->execute();
6818
6819 $id_coupon = $dbo->insertid();
6820
6821 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6822
6823 // check if this coupon should be assigned to specific customers
6824 foreach ($pcustomers as $id_customer) {
6825 $customer_coupon = new stdClass;
6826 $customer_coupon->idcustomer = (int)$id_customer;
6827 $customer_coupon->idcoupon = (int)$id_coupon;
6828 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6829
6830 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6831 }
6832 }
6833 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6834 }
6835
6836 public function updatecoupon()
6837 {
6838 if (!JSession::checkToken()) {
6839 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6840 }
6841
6842 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6843 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6844 }
6845
6846 $this->do_updatecoupon($stay = false);
6847 }
6848
6849 public function updatecoupon_stay()
6850 {
6851 if (!JSession::checkToken()) {
6852 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6853 }
6854
6855 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6856 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6857 }
6858
6859 $this->do_updatecoupon($stay = true);
6860 }
6861
6862 protected function do_updatecoupon($stay = false)
6863 {
6864 if (!JSession::checkToken()) {
6865 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6866 }
6867 $pcode = VikRequest::getString('code', '', 'request');
6868 $pvalue = VikRequest::getString('value', '', 'request');
6869 $pfrom = VikRequest::getString('from', '', 'request');
6870 $pto = VikRequest::getString('to', '', 'request');
6871 $pidrooms = VikRequest::getVar('idrooms', array(0));
6872 $pwhere = VikRequest::getInt('where', 0, 'request');
6873 $ptype = VikRequest::getString('type', '', 'request');
6874 $ptype = $ptype == "1" ? 1 : 2;
6875 $ppercentot = VikRequest::getString('percentot', '', 'request');
6876 $ppercentot = $ppercentot == "1" ? 1 : 2;
6877 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6878 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6879 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6880 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6881 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6882 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6883 $pcustomers = VikRequest::getVar('customers', array());
6884 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6885 $stridrooms = "";
6886 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6887 foreach ($pidrooms as $ch) {
6888 if (!empty($ch)) {
6889 $stridrooms .= ";".$ch.";";
6890 }
6891 }
6892 }
6893 $strdatevalid = "";
6894 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6895 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6896 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6897 if ($first < $second) {
6898 $strdatevalid .= $first."-".$second;
6899 }
6900 }
6901
6902 $dbo = JFactory::getDbo();
6903 $app = JFactory::getApplication();
6904
6905 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
6906 $dbo->setQuery($q);
6907 $dbo->execute();
6908 if ($dbo->getNumRows() > 0) {
6909 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6910 } else {
6911 $q = "UPDATE `#__vikbooking_coupons` SET `code`=".$dbo->quote($pcode).",`type`='".$ptype."',`percentot`='".$ppercentot."',`value`=".$dbo->quote($pvalue).",`datevalid`='".$strdatevalid."',`allvehicles`='".$pallvehicles."',`idrooms`='".$stridrooms."',`mintotord`=".$dbo->quote($pmintotord).",`excludetaxes`={$pexcludetaxes},`minlos`={$pminlos},`maxtotord`= " . $dbo->quote($pmaxtotord) . " WHERE `id`=" . $pwhere . ";";
6912 $dbo->setQuery($q);
6913 $dbo->execute();
6914
6915 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6916
6917 // clean up any previously created record with customers
6918 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
6919 $dbo->setQuery($q);
6920 $dbo->execute();
6921
6922 // check if this coupon should be assigned to specific customers
6923 foreach ($pcustomers as $id_customer) {
6924 $customer_coupon = new stdClass;
6925 $customer_coupon->idcustomer = (int)$id_customer;
6926 $customer_coupon->idcoupon = (int)$pwhere;
6927 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6928
6929 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6930 }
6931 }
6932
6933 if ($stay) {
6934 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
6935 } else {
6936 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6937 }
6938 }
6939
6940 public function removecoupons()
6941 {
6942 if (!JSession::checkToken()) {
6943 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6944 }
6945
6946 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6947 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6948 }
6949
6950 $dbo = JFactory::getDbo();
6951
6952 $ids = VikRequest::getVar('cid', array(0));
6953
6954 if ($ids) {
6955 foreach ($ids as $d) {
6956 // delete coupon record
6957 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
6958 $dbo->setQuery($q);
6959 $dbo->execute();
6960
6961 // clean up any previously created record with customers
6962 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
6963 $dbo->setQuery($q);
6964 $dbo->execute();
6965 }
6966 }
6967
6968 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
6969 }
6970
6971 public function removemoreimgs()
6972 {
6973 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6974 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6975 }
6976
6977 $mainframe = JFactory::getApplication();
6978 $proomid = VikRequest::getInt('roomid', '', 'request');
6979 $pimgind = VikRequest::getInt('imgind', '', 'request');
6980 if (!strlen($pimgind)) {
6981 $mainframe->redirect("index.php?option=com_vikbooking");
6982 exit;
6983 }
6984 $dbo = JFactory::getDBO();
6985 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
6986 $dbo->setQuery($q);
6987 $dbo->execute();
6988 $row = $dbo->loadAssoc();
6989 $actmore = $row['moreimgs'];
6990 if (!empty($actmore)) {
6991 $actsplit = explode(';;', $actmore);
6992 $captions = json_decode($row['imgcaptions'], true);
6993 $captions = !is_array($captions) ? array() : $captions;
6994 if ($pimgind < 0) {
6995 foreach ($actsplit as $img) {
6996 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
6997 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
6998 }
6999 // reset images and captions
7000 $actsplit = array();
7001 $captions = array();
7002 } else {
7003 if (array_key_exists($pimgind, $actsplit)) {
7004 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
7005 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
7006 // unset current image
7007 unset($actsplit[$pimgind]);
7008 // unset caption if exists
7009 if (isset($captions[$pimgind])) {
7010 unset($captions[$pimgind]);
7011 $captions = array_values($captions);
7012 }
7013 }
7014 }
7015 $newstr = "";
7016 foreach ($actsplit as $oi) {
7017 if (!empty($oi)) {
7018 $newstr .= $oi.';;';
7019 }
7020 }
7021 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
7022 $dbo->setQuery($q);
7023 $dbo->execute();
7024 }
7025 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
7026 }
7027
7028 public function sortfield() {
7029 if (!JSession::checkToken('get')) {
7030 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7031 }
7032 $mainframe = JFactory::getApplication();
7033 $sortid = VikRequest::getVar('cid', array(0));
7034 $pmode = VikRequest::getString('mode', '', 'request');
7035 $dbo = JFactory::getDBO();
7036 if (!empty($pmode)) {
7037 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7038 $dbo->setQuery($q);
7039 $dbo->execute();
7040 $totr=$dbo->getNumRows();
7041 if ($totr > 1) {
7042 $data = $dbo->loadAssocList();
7043 if ($pmode == "up") {
7044 foreach ($data as $v) {
7045 if ($v['id'] == $sortid[0]) {
7046 $y = $v['ordering'];
7047 }
7048 }
7049 if ($y && $y > 1) {
7050 $vik = $y - 1;
7051 $found = false;
7052 foreach ($data as $v) {
7053 if (intval($v['ordering']) == intval($vik)) {
7054 $found=true;
7055 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7056 $dbo->setQuery($q);
7057 $dbo->execute();
7058 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7059 $dbo->setQuery($q);
7060 $dbo->execute();
7061 break;
7062 }
7063 }
7064 if (!$found) {
7065 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7066 $dbo->setQuery($q);
7067 $dbo->execute();
7068 }
7069 }
7070 } elseif ($pmode == "down") {
7071 foreach ($data as $v) {
7072 if ($v['id'] == $sortid[0]) {
7073 $y = $v['ordering'];
7074 }
7075 }
7076 if ($y) {
7077 $vik = $y + 1;
7078 $found = false;
7079 foreach ($data as $v) {
7080 if (intval($v['ordering']) == intval($vik)) {
7081 $found=true;
7082 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7083 $dbo->setQuery($q);
7084 $dbo->execute();
7085 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7086 $dbo->setQuery($q);
7087 $dbo->execute();
7088 break;
7089 }
7090 }
7091 if (!$found) {
7092 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7093 $dbo->setQuery($q);
7094 $dbo->execute();
7095 }
7096 }
7097 }
7098 }
7099 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7100 } else {
7101 $mainframe->redirect("index.php?option=com_vikbooking");
7102 }
7103 }
7104
7105 public function customf() {
7106 VikBookingHelper::printHeader("16");
7107
7108 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7109
7110 parent::display();
7111
7112 if (VikBooking::showFooter()) {
7113 VikBookingHelper::printFooter();
7114 }
7115 }
7116
7117 public function newcustomf() {
7118 VikBookingHelper::printHeader("16");
7119
7120 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7121
7122 parent::display();
7123
7124 if (VikBooking::showFooter()) {
7125 VikBookingHelper::printFooter();
7126 }
7127 }
7128
7129 public function editcustomf() {
7130 VikBookingHelper::printHeader("16");
7131
7132 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7133
7134 parent::display();
7135
7136 if (VikBooking::showFooter()) {
7137 VikBookingHelper::printFooter();
7138 }
7139 }
7140
7141 public function createcustomf()
7142 {
7143 if (!JSession::checkToken()) {
7144 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7145 }
7146
7147 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7148 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7149 }
7150
7151 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7152 $ptype = VikRequest::getString('type', '', 'request');
7153 $pchoose = VikRequest::getVar('choose', array(0));
7154 $prequired = VikRequest::getString('required', '', 'request');
7155 $prequired = $prequired == "1" ? 1 : 0;
7156 $pflag = VikRequest::getString('flag', '', 'request');
7157 $pisemail = $pflag == 'isemail' ? 1 : 0;
7158 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7159 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7160 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7161 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7162 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7163 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7164 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7165 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7166 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7167 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7168 $fieldflag = '';
7169 if ($pisaddress == 1) {
7170 $fieldflag = 'address';
7171 } elseif ($piscity == 1) {
7172 $fieldflag = 'city';
7173 } elseif ($piszip == 1) {
7174 $fieldflag = 'zip';
7175 } elseif ($piscompany == 1) {
7176 $fieldflag = 'company';
7177 } elseif ($pisvat == 1) {
7178 $fieldflag = 'vat';
7179 } elseif ($pisfisccode == 1) {
7180 $fieldflag = 'fisccode';
7181 } elseif ($pispec == 1) {
7182 $fieldflag = 'pec';
7183 } elseif ($pisrecipcode == 1) {
7184 $fieldflag = 'recipcode';
7185 }
7186 $ppoplink = VikRequest::getString('poplink', '', 'request');
7187 $choosestr = "";
7188 if (is_array($pchoose)) {
7189 foreach ($pchoose as $ch) {
7190 if (!empty($ch)) {
7191 $choosestr .= $ch.";;__;;";
7192 }
7193 }
7194 }
7195 $defvalue = VikRequest::getString('defvalue', '', 'request');
7196
7197 $dbo = JFactory::getDbo();
7198
7199 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7200 $dbo->setQuery($q);
7201 $dbo->execute();
7202 if ($dbo->getNumRows() == 1) {
7203 $getlast = $dbo->loadResult();
7204 $newsortnum = $getlast + 1;
7205 } else {
7206 $newsortnum = 1;
7207 }
7208 $q = "INSERT INTO `#__vikbooking_custfields` (`name`,`type`,`choose`,`required`,`ordering`,`isemail`,`poplink`,`isnominative`,`isphone`,`flag`,`defvalue`) VALUES(".$dbo->quote($pname).", ".$dbo->quote($ptype).", ".$dbo->quote($choosestr).", ".$dbo->quote($prequired).", ".$dbo->quote($newsortnum).", ".$dbo->quote($pisemail).", ".$dbo->quote($ppoplink).", ".$pisnominative.", ".$pisphone.", ".$dbo->quote($fieldflag).", ".$dbo->quote($defvalue).");";
7209 $dbo->setQuery($q);
7210 $dbo->execute();
7211 $mainframe = JFactory::getApplication();
7212 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7213 }
7214
7215 public function updatecustomf()
7216 {
7217 if (!JSession::checkToken()) {
7218 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7219 }
7220
7221 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7222 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7223 }
7224
7225 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7226 $ptype = VikRequest::getString('type', '', 'request');
7227 $pchoose = VikRequest::getVar('choose', array(0));
7228 $prequired = VikRequest::getString('required', '', 'request');
7229 $prequired = $prequired == "1" ? 1 : 0;
7230 $pflag = VikRequest::getString('flag', '', 'request');
7231 $pisemail = $pflag == 'isemail' ? 1 : 0;
7232 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7233 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7234 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7235 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7236 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7237 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7238 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7239 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7240 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7241 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7242 $fieldflag = '';
7243 if ($pisaddress == 1) {
7244 $fieldflag = 'address';
7245 } elseif ($piscity == 1) {
7246 $fieldflag = 'city';
7247 } elseif ($piszip == 1) {
7248 $fieldflag = 'zip';
7249 } elseif ($piscompany == 1) {
7250 $fieldflag = 'company';
7251 } elseif ($pisvat == 1) {
7252 $fieldflag = 'vat';
7253 } elseif ($pisfisccode == 1) {
7254 $fieldflag = 'fisccode';
7255 } elseif ($pispec == 1) {
7256 $fieldflag = 'pec';
7257 } elseif ($pisrecipcode == 1) {
7258 $fieldflag = 'recipcode';
7259 }
7260 $ppoplink = VikRequest::getString('poplink', '', 'request');
7261 $pwhere = VikRequest::getInt('where', '', 'request');
7262 $choosestr = "";
7263 if (is_array($pchoose)) {
7264 foreach ($pchoose as $ch) {
7265 if (!empty($ch)) {
7266 $choosestr .= $ch.";;__;;";
7267 }
7268 }
7269 }
7270 $defvalue = VikRequest::getString('defvalue', '', 'request');
7271
7272 $dbo = JFactory::getDbo();
7273
7274 $q = "UPDATE `#__vikbooking_custfields` SET `name`=".$dbo->quote($pname).",`type`=".$dbo->quote($ptype).",`choose`=".$dbo->quote($choosestr).",`required`=".$dbo->quote($prequired).",`isemail`=".$dbo->quote($pisemail).",`poplink`=".$dbo->quote($ppoplink).",`isnominative`=".$pisnominative.",`isphone`=".$pisphone.",`flag`=".$dbo->quote($fieldflag).",`defvalue`=".$dbo->quote($defvalue)." WHERE `id`=".$dbo->quote($pwhere).";";
7275 $dbo->setQuery($q);
7276 $dbo->execute();
7277 $mainframe = JFactory::getApplication();
7278 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7279 }
7280
7281 public function removecustomf()
7282 {
7283 if (!JSession::checkToken()) {
7284 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7285 }
7286
7287 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7288 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7289 }
7290
7291 $ids = VikRequest::getVar('cid', array(0));
7292 if ($ids) {
7293 $dbo = JFactory::getDBO();
7294 foreach ($ids as $d) {
7295 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7296 $dbo->setQuery($q);
7297 $dbo->execute();
7298 }
7299 }
7300 $mainframe = JFactory::getApplication();
7301 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7302 }
7303
7304 public function overv() {
7305 VikBookingHelper::printHeader("15");
7306
7307 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7308
7309 parent::display();
7310
7311 if (VikBooking::showFooter()) {
7312 VikBookingHelper::printFooter();
7313 }
7314 }
7315
7316 public function translations() {
7317 VikBookingHelper::printHeader("21");
7318
7319 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7320
7321 parent::display();
7322
7323 if (VikBooking::showFooter()) {
7324 VikBookingHelper::printFooter();
7325 }
7326 }
7327
7328 public function savetranslation() {
7329 if (!JSession::checkToken()) {
7330 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7331 }
7332 $this->do_savetranslation();
7333 }
7334
7335 public function savetranslationstay() {
7336 if (!JSession::checkToken()) {
7337 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7338 }
7339 $this->do_savetranslation(true);
7340 }
7341
7342 private function do_savetranslation($stay = false) {
7343 $dbo = JFactory::getDBO();
7344 $mainframe = JFactory::getApplication();
7345 $vbo_tn = VikBooking::getTranslator();
7346 $table = VikRequest::getString('vbo_table', '', 'request');
7347 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7348 $langs = $vbo_tn->getLanguagesList();
7349 $xml_tables = $vbo_tn->getTranslationTables();
7350 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7351 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7352 $tn_saved = 0;
7353 $table_cols = $vbo_tn->getTableColumns($table);
7354 foreach ($langs as $ltag => $lang) {
7355 if ($ltag == $vbo_tn->default_lang) {
7356 continue;
7357 }
7358 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7359 foreach ($tn[$ltag] as $reference_id => $translation) {
7360 $lang_translation = array();
7361 foreach ($table_cols as $field => $fdetails) {
7362 if (!array_key_exists($field, $translation)) {
7363 continue;
7364 }
7365 $ftype = $fdetails['type'];
7366 if ($ftype == 'skip') {
7367 continue;
7368 }
7369
7370 if (is_array($translation[$field])) {
7371 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7372 if (!is_string($tn_field_v)) {
7373 continue;
7374 }
7375 // replace any possible placeholder for special tags
7376 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7377 return $match[2];
7378 }, $translation[$field][$tn_field_k]);
7379 }
7380 } elseif (!empty($translation[$field])) {
7381 // replace any possible placeholder for special tags
7382 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7383 return $match[2];
7384 }, $translation[$field]);
7385 }
7386
7387 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7388 $translation[$field] = json_encode($translation[$field]);
7389 }
7390 $lang_translation[$field] = $translation[$field];
7391 }
7392 if (count($lang_translation) > 0) {
7393 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7394 $dbo->setQuery($q);
7395 $dbo->execute();
7396 if ($dbo->getNumRows() > 0) {
7397 $last_id = $dbo->loadResult();
7398 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7399 } else {
7400 $q = "INSERT INTO `#__vikbooking_translations` (`table`,`lang`,`reference_id`,`content`) VALUES (".$dbo->quote($table).", ".$dbo->quote($ltag).", ".$dbo->quote((int)$reference_id).", ".$dbo->quote(json_encode($lang_translation)).");";
7401 }
7402 $dbo->setQuery($q);
7403 $dbo->execute();
7404 $tn_saved++;
7405 }
7406 }
7407 }
7408 }
7409 if ($tn_saved > 0) {
7410 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7411 }
7412 } else {
7413 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7414 }
7415 $mainframe->redirect("index.php?option=com_vikbooking".($stay ? '&task=translations&vbo_table='.$vbo_tn->replacePrefix($table).'&vbo_lang='.$cur_langtab : '').'&limitstart='.$vbo_tn->lim0.'&limit='.$vbo_tn->lim);
7416 }
7417
7418 public function choosebusy() {
7419 VikBookingHelper::printHeader("8");
7420
7421 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7422
7423 parent::display();
7424
7425 if (VikBooking::showFooter()) {
7426 VikBookingHelper::printFooter();
7427 }
7428 }
7429
7430 public function orders() {
7431 VikBookingHelper::printHeader("8");
7432
7433 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7434
7435 parent::display();
7436
7437 if (VikBooking::showFooter()) {
7438 VikBookingHelper::printFooter();
7439 }
7440 }
7441
7442 public function vieworders() {
7443 //alias method of orders() for backward compatibility with VCM
7444 $this->orders();
7445 }
7446
7447 public function editorder() {
7448 VikBookingHelper::printHeader("8");
7449
7450 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7451
7452 parent::display();
7453
7454 if (VikBooking::showFooter()) {
7455 VikBookingHelper::printFooter();
7456 }
7457 }
7458
7459 public function removeorders()
7460 {
7461 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7462 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7463 }
7464
7465 $dbo = JFactory::getDbo();
7466 $app = JFactory::getApplication();
7467
7468 $ids = VikRequest::getVar('cid', array(0));
7469 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7470
7471 $user = JFactory::getUser();
7472 $config = VBOFactory::getConfig();
7473
7474 $prev_conf_ids = [];
7475 $purged = false;
7476
7477 $tot_cancs = 0;
7478
7479 if (is_array($ids) && count($ids)) {
7480 foreach ($ids as $d) {
7481 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7482 $dbo->setQuery($q, 0, 1);
7483 $row = $dbo->loadAssoc();
7484
7485 // check for any cancellation constraints
7486 $canc_denied = false;
7487 if ($row && class_exists('VCMFeesCancellation')) {
7488 // let VCM detect if there are any constraints for the cancellation
7489 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7490 if ($canc_denied) {
7491 // set error message
7492 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7493 if ($canc_deny_error) {
7494 $app->enqueueMessage($canc_deny_error, 'error');
7495 }
7496 }
7497 }
7498
7499 if ($row && !$canc_denied) {
7500 // increase counter
7501 $tot_cancs++;
7502
7503 // set status to cancelled
7504 if ($row['status'] != 'cancelled') {
7505 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7506 $dbo->setQuery($q);
7507 $dbo->execute();
7508 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7509 $dbo->setQuery($q);
7510 $dbo->execute();
7511 if ($row['status'] == 'confirmed') {
7512 $prev_conf_ids[] = $row['id'];
7513 }
7514 // Booking History
7515 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7516 }
7517
7518 // free records up
7519 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7520 $dbo->setQuery($q);
7521 $ordbusy = $dbo->loadAssocList();
7522 if ($ordbusy) {
7523 foreach ($ordbusy as $ob) {
7524 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7525 $dbo->setQuery($q);
7526 $dbo->execute();
7527 }
7528 }
7529
7530 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7531 $dbo->setQuery($q);
7532 $dbo->execute();
7533
7534 // check for purge removal
7535 if ($row['status'] == 'cancelled') {
7536 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7537 $dbo->setQuery($q);
7538 $dbo->execute();
7539 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7540 $dbo->setQuery($q);
7541 $dbo->execute();
7542 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7543 $dbo->setQuery($q);
7544 $dbo->execute();
7545 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7546 $dbo->setQuery($q);
7547 $dbo->execute();
7548 // in case of split stay booking, remove the transient
7549 if ($row['split_stay']) {
7550 $config->remove('split_stay_' . $row['id']);
7551 }
7552 // turn flag on
7553 $purged = true;
7554 }
7555 }
7556 }
7557
7558 if ($tot_cancs) {
7559 // enqueue system message
7560 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7561 }
7562 }
7563
7564 if ($prev_conf_ids) {
7565 $prev_conf_ids_str = '';
7566 foreach ($prev_conf_ids as $prev_id) {
7567 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7568 }
7569 //Invoke Channel Manager
7570 $vcm_autosync = VikBooking::vcmAutoUpdate();
7571 if ($vcm_autosync > 0) {
7572 $vcm_obj = VikBooking::getVcmInvoker();
7573 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7574 $sync_result = $vcm_obj->doSync();
7575 if ($sync_result === false) {
7576 $vcm_err = $vcm_obj->getError();
7577 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7578 }
7579 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7580 $vcm_sync_url = 'index.php?option=com_vikbooking&task=invoke_vcm&stype=cancel'.$prev_conf_ids_str.'&returl='.urlencode('index.php?option=com_vikbooking&task=orders');
7581 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7582 }
7583 //
7584 }
7585
7586 if (!empty($pgoto)) {
7587 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7588 if ($purged) {
7589 // go back to the bookings list page
7590 $app->redirect("index.php?option=com_vikbooking&task=orders");
7591 } else {
7592 // go back to the booking details page
7593 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7594 }
7595 exit;
7596 }
7597 // we expect the goto URL to be base64 encoded
7598 $app->redirect(base64_decode($pgoto));
7599 exit;
7600 }
7601
7602 // go back to the bookings list page
7603 $app->redirect("index.php?option=com_vikbooking&task=orders");
7604 }
7605
7606 public function config() {
7607 VikBookingHelper::printHeader("11");
7608
7609 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7610
7611 parent::display();
7612
7613 if (VikBooking::showFooter()) {
7614 VikBookingHelper::printFooter();
7615 }
7616 }
7617
7618 public function saveconfig()
7619 {
7620 if (!JSession::checkToken()) {
7621 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7622 }
7623
7624 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking') || !JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
7625 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7626 }
7627
7628 $dbo = JFactory::getDbo();
7629 $app = JFactory::getApplication();
7630
7631 $config = VBOFactory::getConfig();
7632
7633 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7634 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7635 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
7636 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
7637 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
7638 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
7639 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
7640 $pdateformat = VikRequest::getString('dateformat', '', 'request');
7641 $pdatesep = VikRequest::getString('datesep', '', 'request');
7642 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
7643 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
7644 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
7645 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
7646 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
7647 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
7648 $ptokenform = VikRequest::getString('tokenform', '', 'request');
7649 $padminemail = VikRequest::getString('adminemail', '', 'request');
7650 $psenderemail = VikRequest::getString('senderemail', '', 'request');
7651 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
7652 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
7653 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
7654 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
7655 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
7656 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
7657 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
7658 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
7659 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
7660 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
7661 $pusefa = VikRequest::getInt('usefa', '', 'request');
7662 $pusefa = $pusefa > 0 ? 1 : 0;
7663 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
7664 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
7665 $pcalendar = VikRequest::getString('calendar', '', 'request');
7666 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
7667 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
7668 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
7669 $penablepin = VikRequest::getString('enablepin', '', 'request');
7670 $penablepin = $penablepin == "1" ? 1 : 0;
7671 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
7672 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
7673 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
7674 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
7675 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
7676 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
7677 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
7678 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
7679 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
7680 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
7681 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
7682 $pnumadultsfrom = '1';
7683 $pnumadultsto = '10';
7684 }
7685 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
7686 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
7687 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
7688 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
7689 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
7690 $pnumadultsfrom = '1';
7691 $pnumadultsto = '4';
7692 }
7693 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
7694 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
7695 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
7696 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
7697 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
7698 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
7699 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
7700 $pcronkey = VikRequest::getString('cronkey', '', 'request');
7701 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
7702 $pcdsto = VikRequest::getVar('cdsto', array());
7703 $closing_dates = array();
7704 if (count($pcdsfrom)) {
7705 foreach ($pcdsfrom as $kcd => $vcdfrom) {
7706 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
7707 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
7708 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
7709 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
7710 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
7711 if (!in_array($cdval, $closing_dates)) {
7712 $closing_dates[] = $cdval;
7713 }
7714 }
7715 }
7716 }
7717 }
7718 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
7719 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
7720 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
7721 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7722 if ($pvbosef === 1) {
7723 if (!$vbosef) {
7724 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7725 }
7726 } else {
7727 if ($vbosef) {
7728 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
7729 }
7730 }
7731 $pmultilang = VikRequest::getString('multilang', '', 'request');
7732 $pmultilang = $pmultilang == "1" ? 1 : 0;
7733 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
7734 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
7735 /**
7736 * Chat params and configuration settings
7737 *
7738 * @since 1.12
7739 */
7740 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
7741 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
7742 $config->set('chatenabled', $pchatenabled);
7743
7744 // chat params
7745 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
7746 $chat_res_status = array();
7747 foreach ($pchat_res_status as $chatrs) {
7748 if (!empty($chatrs)) {
7749 array_push($chat_res_status, $chatrs);
7750 }
7751 }
7752 $chatparams = new stdClass;
7753 $chatparams->res_status = $chat_res_status;
7754 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
7755 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
7756
7757 $config->set('chatparams', $chatparams);
7758 }
7759
7760 /**
7761 * Pre check-in configuration settings
7762 *
7763 * @since 1.12
7764 */
7765 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
7766 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
7767
7768 $config->set('precheckinenabled', $pprecheckinenabled);
7769 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
7770
7771 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
7772 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
7773 $config->set('upselling', $pupsellingenabled);
7774
7775 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
7776 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
7777 $config->set('orphanscalculation', $porphanscal);
7778
7779 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
7780 $config->set('searchrestmpl', $psrcrtpl);
7781
7782 /**
7783 * Guest Reviews settings
7784 *
7785 * @since 1.13
7786 */
7787 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
7788 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
7789 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
7790 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
7791 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
7792 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
7793 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
7794 $config->set('grenabled', $pgrenabled);
7795 $config->set('grminchars', $pgrminchars);
7796 $config->set('grappr', $pgrappr);
7797 $config->set('grtype', $pgrtype);
7798 try {
7799 // always truncate service names (this query may require special permissions)
7800 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
7801 $dbo->setQuery($q);
7802 $dbo->execute();
7803 } catch (Exception $e) {
7804 // do nothing
7805 }
7806 foreach ($pgrsrv as $srvname) {
7807 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
7808 $dbo->setQuery($q);
7809 $dbo->execute();
7810 }
7811
7812 /**
7813 * Preferred countries ordering, or custom countries.
7814 *
7815 * @since 1.14 (J) - 1.3.11 (WP)
7816 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
7817 */
7818 $pref_countries = VikRequest::getVar('pref_countries', array());
7819 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
7820 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
7821 if (!empty($cust_pref_countries)) {
7822 $all_custom_prefcountries = array();
7823 $cust_pref_countries = explode(',', $cust_pref_countries);
7824 foreach ($cust_pref_countries as $cust_pref_country) {
7825 $cust_pref_country = trim(strtolower($cust_pref_country));
7826 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
7827 continue;
7828 }
7829 array_push($all_custom_prefcountries, $cust_pref_country);
7830 }
7831 if (count($all_custom_prefcountries)) {
7832 $pref_countries = $all_custom_prefcountries;
7833 }
7834 }
7835 $config->set('preferred_countries', $pref_countries);
7836 //
7837
7838 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
7839 $config->set('gmapskey', $gmapskey);
7840
7841 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
7842 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
7843 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
7844 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
7845 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
7846 $pref_colors = array(
7847 'textcolor' => $pref_textcolor,
7848 'bgcolor' => $pref_bgcolor,
7849 'fontcolor' => $pref_fontcolor,
7850 'bgcolorhov' => $pref_bgcolorhov,
7851 'fontcolorhov' => $pref_fontcolorhov,
7852 );
7853 $config->set('pref_colors', $pref_colors);
7854
7855 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
7856 $config->set('interactive_map', $interactive_map);
7857
7858 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
7859 $config->set('noemptydecimals', $noemptydecimals);
7860
7861 /**
7862 * Appearance preferences (light, auto, dark mode).
7863 *
7864 * @since 1.15.0 (J) - 1.5.0 (WP)
7865 * @since 1.16.10 (J) - 1.6.10 (WP) mirrored on VCM.
7866 */
7867 $appearance_pref = VikRequest::getString('appearance_pref', '');
7868 $config->set('appearance_pref', $appearance_pref);
7869 if (class_exists('VCMFactory')) {
7870 VCMFactory::getConfig()->set('appearance_pref', $appearance_pref);
7871 }
7872
7873 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
7874 $picon = "";
7875 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
7876 jimport('joomla.filesystem.file');
7877 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
7878 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
7879 if (file_exists($res_backend_path.$safename)) {
7880 $j = 1;
7881 while (file_exists($res_backend_path.$j.$safename)) {
7882 $j++;
7883 }
7884 $pwhere = $res_backend_path.$j.$safename;
7885 } else {
7886 $j = "";
7887 $pwhere = $res_backend_path.$safename;
7888 }
7889 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7890 @unlink($pwhere);
7891 $picon = "";
7892 } else {
7893 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
7894 @chmod($pwhere, 0644);
7895 $picon = $j.$safename;
7896 }
7897 }
7898 if (!empty($picon)) {
7899 $config->set('sitelogo', $picon);
7900 }
7901 }
7902 $pbackicon = "";
7903 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
7904 jimport('joomla.filesystem.file');
7905 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
7906 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
7907 if (file_exists($res_backend_path.$safename)) {
7908 $j = 1;
7909 while (file_exists($res_backend_path.$j.$safename)) {
7910 $j++;
7911 }
7912 $pwhere = $res_backend_path.$j.$safename;
7913 } else {
7914 $j = "";
7915 $pwhere = $res_backend_path.$safename;
7916 }
7917 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7918 @unlink($pwhere);
7919 $pbackicon = "";
7920 } else {
7921 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
7922 @chmod($pwhere, 0644);
7923 $pbackicon = $j.$safename;
7924 }
7925 }
7926 if (!empty($pbackicon)) {
7927 $config->set('backlogo', $pbackicon);
7928 }
7929 }
7930 $config->set('vcmautoupd', $pvcmautoupd);
7931 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
7932 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
7933 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
7934 $config->set('searchsuggestions', $psearchsuggestions);
7935 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
7936 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
7937 $config->set('search_show_busy_listings', $app->input->getInt('search_show_busy_listings', 0));
7938 $config->set('search_link_roomdetails', $app->input->getInt('search_link_roomdetails', 0));
7939
7940 // translatable text
7941 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
7942 $dbo->setQuery($q);
7943 $dbo->execute();
7944
7945 // translatable text
7946 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
7947 $dbo->setQuery($q);
7948 $dbo->execute();
7949
7950 // translatable text
7951 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
7952 $dbo->setQuery($q);
7953 $dbo->execute();
7954
7955 // terms and conditions
7956 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
7957 $dbo->setQuery($q);
7958 $dbo->execute();
7959 if ($dbo->getNumRows() > 0) {
7960 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
7961 $dbo->setQuery($q);
7962 $dbo->execute();
7963 } else {
7964 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
7965 $dbo->setQuery($q);
7966 $dbo->execute();
7967 }
7968
7969 $config->set('adminemail', $padminemail);
7970 $config->set('senderemail', $psenderemail);
7971 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
7972 $config->set('datesep', $pdatesep);
7973 $config->set('resmodcanc', $presmodcanc);
7974 $config->set('resmodcancmin', $presmodcancmin);
7975 $config->set('minuteslock', $pminuteslock);
7976 $config->set('minautoremove', $pminautoremove);
7977
7978 $openingh = $ptimeopenstorefh * 3600;
7979 $openingm = $ptimeopenstorefm * 60;
7980 $openingts = $openingh + $openingm;
7981 $closingh = $ptimeopenstoreth * 3600;
7982 $closingm = $ptimeopenstoretm * 60;
7983 $closingts = $closingh + $closingm;
7984 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
7985 $prevtimes = $config->get('timeopenstore', '');
7986 if ($prevtimes != $openingts . "-" . $closingts) {
7987 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
7988 $dbo->setQuery($q);
7989 $dbo->execute();
7990 if ($dbo->getNumRows() > 0) {
7991 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
7992 /**
7993 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
7994 * for all reservations to avoid issues with the availability.
7995 *
7996 * @since August 29th 2018
7997 */
7998 VikError::raiseWarning('', '<br/><a href="index.php?option=com_vikbooking&task=unifycheckinout&fh='.$ptimeopenstorefh.'&fm='.$ptimeopenstorefm.'&th='.$ptimeopenstoreth.'&tm='.$ptimeopenstoretm.'" class="btn btn-large btn-warning">'.JText::translate('VBAPPLY').'</a>');
7999 //
8000 }
8001 }
8002 $config->set('timeopenstore', $openingts . "-" . $closingts);
8003
8004 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
8005 $phoursmorebookingback = "0";
8006 if ($closingts > $openingts) {
8007 $diffcheck = ($closingts - $openingts) / 3600;
8008 $phoursmorebookingback = ceil($diffcheck);
8009 }
8010 $config->set('hoursmorebookingback', $phoursmorebookingback);
8011 $config->set('hoursmoreroomavail', '0');
8012 $config->set('multilang', $pmultilang);
8013 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
8014 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
8015 $config->set('todaybookings', $ptodaybookings);
8016 $config->set('bootstrap', $ploadbootstrap);
8017 $config->set('usefa', $pusefa);
8018 $config->set('loadjquery', $ploadjquery);
8019 $config->set('calendar', $pcalendar);
8020 $config->set('enablecoupons', $penablecoupons);
8021 $config->set('enablepin', $penablepin);
8022 $config->set('mindaysadvance', $pmindaysadvance);
8023 $config->set('autodefcalnights', $pautodefcalnights);
8024 $config->set('numrooms', $pnumrooms);
8025 $config->set('numadults', $confnumadults);
8026 $config->set('numchildren', $confnumchildren);
8027 $config->set('closingdates', $closing_dates);
8028 $config->set('smartsearch', $psmartsearch);
8029 $config->set('maxdate', $maxdate_str);
8030 $config->set('cronkey', $pcronkey);
8031
8032 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
8033 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
8034 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
8035 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
8036 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
8037 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
8038 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
8039 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
8040 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
8041 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
8042 $pnumdecimals = intval($pnumdecimals);
8043 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
8044 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
8045 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
8046 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
8047 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
8048 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
8049 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
8050 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
8051 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
8052 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
8053 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
8054 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
8055 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
8056 $pbctagname = VikRequest::getVar('bctagname', array());
8057 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
8058 $pbctagrule = VikRequest::getVar('bctagrule', array());
8059 $bctags_arr = array();
8060 $bctags_rules = array();
8061 if (count($pbctagname) > 0) {
8062 foreach ($pbctagname as $bctk => $bctv) {
8063 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
8064 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
8065 $bctags_rules[] = $pbctagrule[$bctk];
8066 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8067 }
8068 }
8069 }
8070 }
8071 //theme
8072 $ptheme = VikRequest::getString('theme', '', 'request');
8073 if (empty($ptheme) || $ptheme == 'default') {
8074 $ptheme = 'default';
8075 } else {
8076 $validtheme = false;
8077 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8078 if (count($themes) > 0) {
8079 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8080 foreach ($themes as $th) {
8081 if (is_dir($th)) {
8082 $tname = str_replace($strip, '', $th);
8083 if ($tname == $ptheme) {
8084 $validtheme = true;
8085 break;
8086 }
8087 }
8088 }
8089 }
8090 if ($validtheme == false) {
8091 $ptheme = 'default';
8092 }
8093 }
8094 $config->set('theme', $ptheme);
8095 //
8096 $config->set('showpartlyreserved', $pshowpartlyreserved);
8097 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8098 $config->set('numcalendars', $pnumcalendars);
8099
8100 // record may not be set
8101 $config->set('thumbsize', $pthumbsize);
8102
8103 $config->set('firstwday', $pfirstwday);
8104
8105 // translatable text
8106 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8107 $dbo->setQuery($q);
8108 $dbo->execute();
8109
8110 $config->set('fronttitletag', $pfronttitletag);
8111 $config->set('fronttitletagclass', $pfronttitletagclass);
8112 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8113
8114 // translatable texts
8115 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8116 $dbo->setQuery($q);
8117 $dbo->execute();
8118 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8119 $dbo->setQuery($q);
8120 $dbo->execute();
8121
8122 $config->set('currencyname', $pcurrencyname);
8123 $config->set('currencysymb', $pcurrencysymb);
8124 $config->set('currencycodepp', $pcurrencycodepp);
8125 $config->set('numberformat', $numberformatstr);
8126 // bookings color tags
8127 $config->set('bookingsctags', $bctags_arr);
8128
8129 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8130 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8131 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8132 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8133 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8134 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8135 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8136 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8137 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8138 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8139 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8140 $pmultipay = VikRequest::getString('multipay', '', 'request');
8141 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8142 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8143 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8144 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8145 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8146
8147 // translatable text
8148 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8149 $dbo->setQuery($q);
8150 $dbo->execute();
8151 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8152 $dbo->setQuery($q);
8153 $dbo->execute();
8154
8155 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8156 $config->set('taxsummary', $ptaxsummary);
8157 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8158
8159 $config->set('ccpaypal', $pccpaypal);
8160 $config->set('payaccpercent', $ppayaccpercent);
8161 $config->set('typedeposit', $ptypedeposit);
8162 $config->set('depoverrides', $pdepoverrides);
8163 $config->set('multipay', $pmultipay);
8164 $config->set('depifdaysadv', $pdepifdaysadv);
8165 $config->set('nodepnonrefund', $pnodepnonrefund);
8166 $config->set('depcustchoice', $pdepcustchoice);
8167
8168 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8169 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8170 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8171 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8172 $config->set('emailsendwhen', $psendemailwhen);
8173 $config->set('attachical', $pattachical);
8174
8175 // SMS APIs
8176 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8177 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8178 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8179 $psmssendto = VikRequest::getVar('smssendto', array());
8180 $sms_sendto = array();
8181 foreach ($psmssendto as $sto) {
8182 if (in_array($sto, array('admin', 'customer'))) {
8183 $sms_sendto[] = $sto;
8184 }
8185 }
8186 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8187 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8188 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8189 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8190 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8191 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8192 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8193 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8194 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8195 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8196 $smsparamarr = array();
8197 if (count($viksmsparams) > 0) {
8198 foreach ($viksmsparams as $setting => $cont) {
8199 if (strlen($setting) > 0) {
8200 $smsparamarr[$setting] = $cont;
8201 }
8202 }
8203 }
8204 $config->set('smsapi', $psmsapi);
8205 $config->set('smsautosend', $psmsautosend);
8206 $config->set('smssendto', $sms_sendto);
8207 $config->set('smssendwhen', $psmssendwhen);
8208 $config->set('smsadminphone', $psmsadminphone);
8209 $config->set('smsparams', $smsparamarr);
8210
8211 // translatable texts
8212 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8213 $dbo->setQuery($q);
8214 $dbo->execute();
8215 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8216 $dbo->setQuery($q);
8217 $dbo->execute();
8218 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8219 $dbo->setQuery($q);
8220 $dbo->execute();
8221 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8222 $dbo->setQuery($q);
8223 $dbo->execute();
8224 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8225 $dbo->setQuery($q);
8226 $dbo->execute();
8227 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8228 $dbo->setQuery($q);
8229 $dbo->execute();
8230
8231 /**
8232 * Backup settings
8233 *
8234 * @since 1.15.0 (J) - 1.5.0 (WP)
8235 */
8236 $backup_type = $app->input->getString('backuptype', 'full');
8237 $backup_folder = $app->input->getString('backupfolder', '');
8238
8239 $tmp = $app->get('tmp_path');
8240
8241 if (!$backup_folder)
8242 {
8243 // path not specified, use temporary folder
8244 $backup_folder = $tmp;
8245 }
8246
8247 $current = $config->get('backupfolder');
8248
8249 if (!$current)
8250 {
8251 // path was missing, use temporary folder
8252 $current = $tmp;
8253 }
8254
8255 // check whether the backup folder has been moved
8256 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8257 {
8258 $backupModel = new VBOModelBackup();
8259
8260 // backup folder moved, try to copy all the existing overrides
8261 if (!$backupModel->moveArchives($backup_folder))
8262 {
8263 // iterate all errors and display them
8264 foreach ($backupModel->getErrors() as $error)
8265 {
8266 $app->enqueueMessage($error, 'warning');
8267 }
8268 }
8269 }
8270
8271 // save configuration
8272 $config->set('backuptype', $backup_type);
8273 $config->set('backupfolder', $backup_folder);
8274
8275 /**
8276 * Check-in data collection type.
8277 *
8278 * @since 1.15.0 (J) - 1.5.0 (WP)
8279 */
8280 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8281
8282 /**
8283 * Front-end appearance.
8284 *
8285 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8286 */
8287 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8288
8289 /**
8290 * Split stays.
8291 *
8292 * @since 1.16.0 (J) - 1.6.0 (WP)
8293 */
8294 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8295 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8296 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8297 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8298
8299 /**
8300 * Re-build Web App manifest file to let the event trigger.
8301 *
8302 * @since 1.16.5 (J) - 1.6.5 (WP)
8303 */
8304 try {
8305 VBOWebappManifest::build();
8306 } catch (Exception $e) {
8307 // do nothing
8308 }
8309
8310 // redirect
8311 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8312 $app->redirect('index.php?option=com_vikbooking&task=config');
8313 $app->close();
8314 }
8315
8316 /**
8317 * Task to unify the check-in and check-out times for all reservations.
8318 */
8319 public function unifycheckinout()
8320 {
8321 $dbo = JFactory::getDbo();
8322 $app = JFactory::getApplication();
8323 $user = JFactory::getUser();
8324
8325 $fh = VikRequest::getInt('fh', 12, 'request');
8326 $fm = VikRequest::getInt('fm', 0, 'request');
8327 $th = VikRequest::getInt('th', 10, 'request');
8328 $tm = VikRequest::getInt('tm', 0, 'request');
8329
8330 $now = time();
8331 $totmod = 0;
8332 $totbookmod = 0;
8333
8334 // query all busy records
8335 $q = $dbo->getQuery(true)
8336 ->select('*')
8337 ->from($dbo->qn('#__vikbooking_busy'));
8338
8339 $dbo->setQuery($q);
8340 $records = $dbo->loadAssocList();
8341
8342 foreach ($records as $v) {
8343 $info_start = getdate($v['checkin']);
8344 $info_end = getdate($v['checkout']);
8345 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8346 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8347
8348 $q = $dbo->getQuery(true)
8349 ->update($dbo->qn('#__vikbooking_busy'))
8350 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8351 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8352 ->set($dbo->qn('realback') . ' = ' . $new_end)
8353 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8354
8355 $dbo->setQuery($q, 0, 1);
8356 $dbo->execute();
8357
8358 $totmod++;
8359 }
8360
8361 // query all bookings
8362 $q = $dbo->getQuery(true)
8363 ->select($dbo->qn([
8364 'id',
8365 'days',
8366 'checkin',
8367 'checkout',
8368 'total',
8369 ]))
8370 ->from($dbo->qn('#__vikbooking_orders'))
8371 ->order($dbo->qn('checkin') . ' DESC');
8372
8373 $dbo->setQuery($q);
8374 $records = $dbo->loadAssocList();
8375
8376 foreach ($records as $v) {
8377 $info_start = getdate($v['checkin']);
8378 $info_end = getdate($v['checkout']);
8379 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8380 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8381
8382 $q = $dbo->getQuery(true)
8383 ->update($dbo->qn('#__vikbooking_orders'))
8384 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8385 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8386 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8387
8388 $dbo->setQuery($q, 0, 1);
8389 $dbo->execute();
8390
8391 /**
8392 * In case the operation changed the check-in/check-out time for this booking,
8393 * store a new history record for a booking modification.
8394 *
8395 * @since 1.16.6 (J) - 1.6.6 (WP)
8396 */
8397 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8398 // Booking History
8399 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8400 }
8401
8402 $totbookmod++;
8403 }
8404
8405 $app->enqueueMessage('OK: ' . $totbookmod);
8406 $app->redirect("index.php?option=com_vikbooking&task=config");
8407 $app->close();
8408 }
8409
8410 public function savetmplfile() {
8411 if (!JSession::checkToken()) {
8412 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8413 }
8414 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8415 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8416 $mainframe = JFactory::getApplication();
8417 $exists = file_exists($fpath) ? true : false;
8418 if (!$exists) {
8419 $fpath = urldecode($fpath);
8420 }
8421 $fpath = file_exists($fpath) ? $fpath : '';
8422 if (!empty($fpath)) {
8423 $fp = fopen($fpath, 'wb');
8424 $byt = (int)fwrite($fp, $pcont);
8425 fclose($fp);
8426 if ($byt > 0) {
8427 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8428
8429 if (VBOPlatformDetection::isWordPress()) {
8430 /**
8431 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8432 */
8433 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8434 }
8435 } else {
8436 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8437 }
8438 } else {
8439 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8440 }
8441 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8442
8443 exit;
8444 }
8445
8446 public function edittmplfile() {
8447 //modal box, so we do not set menu or footer
8448
8449 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8450
8451 parent::display();
8452 }
8453
8454 public function tmplfileprew() {
8455 //modal box, so we do not set menu or footer
8456
8457 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8458
8459 parent::display();
8460 }
8461
8462 public function invoices() {
8463 VikBookingHelper::printHeader("invoices");
8464
8465 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8466
8467 parent::display();
8468
8469 if (VikBooking::showFooter()) {
8470 VikBookingHelper::printFooter();
8471 }
8472 }
8473
8474 public function newmaninvoice() {
8475 VikBookingHelper::printHeader("invoices");
8476
8477 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8478
8479 parent::display();
8480
8481 if (VikBooking::showFooter()) {
8482 VikBookingHelper::printFooter();
8483 }
8484 }
8485
8486 public function editmaninvoice() {
8487 VikBookingHelper::printHeader("invoices");
8488
8489 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8490
8491 parent::display();
8492
8493 if (VikBooking::showFooter()) {
8494 VikBookingHelper::printFooter();
8495 }
8496 }
8497
8498 public function savemaninvoice() {
8499 if (!JSession::checkToken()) {
8500 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8501 }
8502 $this->do_storemaninvoice('save');
8503 $mainframe = JFactory::getApplication();
8504 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8505 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8506 if (!empty($pgoto)) {
8507 $mainframe->redirect(base64_decode($pgoto));
8508 exit;
8509 }
8510 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8511 }
8512
8513 public function updatemaninvoice()
8514 {
8515 if (!JSession::checkToken()) {
8516 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8517 }
8518
8519 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8520 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8521 }
8522
8523 $invid = VikRequest::getInt('whereup', 0, 'request');
8524 $this->do_storemaninvoice('update', $invid);
8525 $mainframe = JFactory::getApplication();
8526 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8527 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8528 if (!empty($pgoto)) {
8529 $mainframe->redirect(base64_decode($pgoto));
8530 exit;
8531 }
8532 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8533 }
8534
8535 public function updatemaninvoicestay()
8536 {
8537 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8538 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8539 }
8540
8541 $invid = VikRequest::getInt('whereup', 0, 'request');
8542 $this->do_storemaninvoice('updatestay', $invid);
8543 $mainframe = JFactory::getApplication();
8544 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8545 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8546 if (!empty($pgoto)) {
8547 $mainframe->redirect(base64_decode($pgoto));
8548 exit;
8549 }
8550 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8551 }
8552
8553 private function do_storemaninvoice($action, $invid = 0) {
8554 $dbo = JFactory::getDBO();
8555 $mainframe = JFactory::getApplication();
8556 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8557 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8558 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8559 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8560 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8561 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8562 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8563 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8564 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8565 if (empty($pidcustomer)) {
8566 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8567 $mainframe->redirect($error_uri);
8568 exit;
8569 }
8570 $services = VikRequest::getVar('service', array());
8571 $nets = VikRequest::getVar('net', array());
8572 $aliqs = VikRequest::getVar('aliq', array());
8573 $taxs = VikRequest::getVar('tax', array());
8574 $tots = VikRequest::getVar('tot', array());
8575 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8576 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8577 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8578 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8579 VikError::raiseWarning('', 'Missing data.');
8580 $mainframe->redirect($error_uri);
8581 exit;
8582 }
8583 $rawcont = array(
8584 'rows' => array(),
8585 'totalnet' => $ptotalnet,
8586 'totaltax' => $ptotaltax,
8587 'totaltot' => $ptotaltot,
8588 'notes' => $pinvoice_notes,
8589 );
8590 foreach ($services as $k => $service) {
8591 if (empty($service)) {
8592 continue;
8593 }
8594 array_push($rawcont['rows'], array(
8595 'service' => $service,
8596 'net' => (float)$nets[$k],
8597 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8598 'tax' => (float)$taxs[$k],
8599 'tot' => (float)$tots[$k],
8600 ));
8601 }
8602 // store/update manual invoice
8603 $nowts = time();
8604 $retval = 0;
8605 if (strpos($action, 'save') !== false) {
8606 $pdffname = $nowts . '_' . rand() . '.pdf';
8607 $q = "INSERT INTO `#__vikbooking_invoices` (`number`,`file_name`,`idorder`,`idcustomer`,`created_on`,`for_date`,`rawcont`) VALUES (".$dbo->quote($pinvoice_num.$pinvoice_suff).", ".$dbo->quote($pdffname).", ".($pinvoice_num - ($pinvoice_num * 2)).", ".$dbo->quote($pidcustomer).", ".$nowts.", ".$nowts.", ".$dbo->quote(json_encode($rawcont)).");";
8608 $dbo->setQuery($q);
8609 $dbo->execute();
8610 $retval = $dbo->insertid();
8611 } else {
8612 // fetch old record
8613 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8614 $dbo->setQuery($q);
8615 $dbo->execute();
8616 if (!$dbo->getNumRows()) {
8617 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8618 $mainframe->redirect($error_uri);
8619 exit;
8620 }
8621 $previnvoice = $dbo->loadAssoc();
8622 //
8623 $q = "UPDATE `#__vikbooking_invoices` SET `number`=".$dbo->quote($pinvoice_num.$pinvoice_suff).",`file_name`=".$dbo->quote($previnvoice['file_name']).",`idorder`=".($pinvoice_num - ($pinvoice_num * 2)).",`idcustomer`=".$dbo->quote($pidcustomer).",`created_on`=".$nowts.",`rawcont`=".$dbo->quote(json_encode($rawcont))." WHERE `id`=".(int)$previnvoice['id'].";";
8624 $dbo->setQuery($q);
8625 $dbo->execute();
8626 $retval = $previnvoice['id'];
8627 }
8628 // update config values for the invoice
8629 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8630 $dbo->setQuery($q);
8631 $dbo->execute();
8632 // generate the custom invoice
8633 $result = VikBooking::generateCustomInvoice($retval);
8634 //
8635 $nextinv = VikBooking::getNextInvoiceNumber();
8636 $updatenum = ($pinvoice_num >= $nextinv);
8637 if ($updatenum) {
8638 /**
8639 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
8640 * to avoid conflicts with the drivers for the e-invoices generation.
8641 */
8642 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8643 $dbo->setQuery($q);
8644 $dbo->execute();
8645 }
8646
8647 return $retval;
8648 }
8649
8650 public function downloadinvoices() {
8651 $ids = VikRequest::getVar('cid', array(0));
8652 if (@count($ids) > 0) {
8653 $dbo = JFactory::getDBO();
8654 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
8655 $dbo->setQuery($q);
8656 $dbo->execute();
8657 if ($dbo->getNumRows() > 0) {
8658 $invoices = $dbo->loadAssocList();
8659 if (!(count($invoices) > 1)) {
8660 //Single Invoice Download
8661 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
8662 header("Content-type:application/pdf");
8663 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
8664 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
8665 exit;
8666 }
8667 } else {
8668 //Multiple Invoices Download
8669 $to_zip = array();
8670 foreach ($invoices as $k => $invoice) {
8671 $to_zip[$k]['name'] = $invoice['file_name'];
8672 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
8673 }
8674 if (class_exists('ZipArchive')) {
8675 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
8676 $zip = new ZipArchive;
8677 $zip->open($zip_path, ZipArchive::CREATE);
8678 foreach ($to_zip as $k => $zipv) {
8679 $zip->addFile($zipv['path'], $zipv['name']);
8680 }
8681 $zip->close();
8682 header("Content-type:application/zip");
8683 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
8684 header("Content-Length:".filesize($zip_path));
8685 readfile($zip_path);
8686 unlink($zip_path);
8687 exit;
8688 } else {
8689 //Class ZipArchive does not exist
8690 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
8691 }
8692 }
8693 }
8694 }
8695 $mainframe = JFactory::getApplication();
8696 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8697 }
8698
8699 public function resendinvoices() {
8700 $ids = VikRequest::getVar('cid', array(0));
8701 $mainframe = JFactory::getApplication();
8702 if (!(count($ids) > 0)) {
8703 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8704 exit;
8705 }
8706 $dbo = JFactory::getDBO();
8707 $invoices = array();
8708 $q = "SELECT `i`.*,`o`.`custmail`,`c`.`email` AS `customer_email`, CONCAT_WS(' ',`c`.`first_name`,`c`.`last_name`) AS `customer_name`,`c`.`country` AS `customer_country`,`nat`.`country_name` ".
8709 "FROM `#__vikbooking_invoices` AS `i` " .
8710 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
8711 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
8712 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
8713 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
8714 $dbo->setQuery($q);
8715 $dbo->execute();
8716 if ($dbo->getNumRows() > 0) {
8717 $invoices = $dbo->loadAssocList();
8718 }
8719 if (!(count($invoices) > 0)) {
8720 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8721 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8722 exit;
8723 }
8724 $tot_generated = 0;
8725 $tot_sent = 0;
8726 foreach ($invoices as $bkey => $invoice) {
8727 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
8728 $invoices[$bkey] = $invoice;
8729 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
8730 if ($send_res !== false) {
8731 $tot_sent++;
8732 }
8733 }
8734 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8735 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8736 }
8737
8738 public function removeinvoices()
8739 {
8740 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
8741 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8742 }
8743
8744 $ids = VikRequest::getVar('cid', array());
8745 $tot_removed = 0;
8746 $dbo = JFactory::getDbo();
8747
8748 foreach ($ids as $d) {
8749 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8750 $dbo->setQuery($q);
8751 $dbo->execute();
8752 if ($dbo->getNumRows() == 1) {
8753 $cur_invoice = $dbo->loadAssoc();
8754 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
8755 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
8756 }
8757 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8758 $dbo->setQuery($q);
8759 $dbo->execute();
8760 $tot_removed++;
8761 }
8762 }
8763
8764 $mainframe = JFactory::getApplication();
8765 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
8766 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8767 }
8768
8769 public function geninvoices()
8770 {
8771 $dbo = JFactory::getDbo();
8772 $app = JFactory::getApplication();
8773
8774 $ids = VikRequest::getVar('cid', array());
8775
8776 if (!$ids) {
8777 $app->redirect("index.php?option=com_vikbooking&task=orders");
8778 exit;
8779 }
8780
8781 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8782 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8783 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8784 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
8785 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8786 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8787 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
8788 $pinvoice_send = $pinvoice_send > 0 ? true : false;
8789 $increment_inv = true;
8790 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
8791
8792 // if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
8793 if (count($ids) === 1) {
8794 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
8795 $dbo->setQuery($q);
8796 $dbo->execute();
8797 if ($dbo->getNumRows() == 1) {
8798 $increment_inv = false;
8799 }
8800 }
8801
8802 // get bookings
8803 $dbo->setQuery(
8804 $dbo->getQuery(true)
8805 ->select($dbo->qn('o') . '.*')
8806 ->select($dbo->qn('co.idcustomer'))
8807 ->select('CONCAT_WS(\' \', ' . $dbo->qn('c.first_name') . ', ' . $dbo->qn('c.last_name') . ') AS ' . $dbo->qn('customer_name'))
8808 ->select([
8809 $dbo->qn('c.pin', 'customer_pin'),
8810 $dbo->qn('nat.country_name'),
8811 ])
8812 ->from($dbo->qn('#__vikbooking_orders', 'o'))
8813 ->leftJoin($dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $dbo->qn('co.idorder') . ' = ' . $dbo->qn('o.id'))
8814 ->leftJoin($dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $dbo->qn('c.id') . ' = ' . $dbo->qn('co.idcustomer'))
8815 ->leftJoin($dbo->qn('#__vikbooking_countries', 'nat') . ' ON ' . $dbo->qn('nat.country_3_code') . ' = ' . $dbo->qn('o.country'))
8816 ->where($dbo->qn('o.id') . ' IN (' . implode(', ', array_map('intval', $ids)) . ')')
8817 ->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed'))
8818 ->where($dbo->qn('o.total') . ' > 0')
8819 ->order($dbo->qn('o.id') . ' ASC')
8820 );
8821
8822 $bookings = $dbo->loadAssocList();
8823
8824 if (!$bookings) {
8825 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8826 $app->redirect("index.php?option=com_vikbooking&task=orders");
8827 exit;
8828 }
8829
8830 $tot_generated = 0;
8831 $tot_sent = 0;
8832 foreach ($bookings as $bkey => $booking) {
8833 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
8834 if ($gen_res !== false && $gen_res > 0) {
8835 $tot_generated++;
8836 $pinvoice_num++;
8837 if ($pinvoice_send) {
8838 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
8839 if ($send_res !== false) {
8840 $tot_sent++;
8841 }
8842 }
8843 } else {
8844 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
8845 }
8846 }
8847
8848 if ($tot_generated > 0 && $increment_inv === true) {
8849 /**
8850 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
8851 * to avoid conflicts with the drivers for the e-invoices generation.
8852 */
8853 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8854 $dbo->setQuery($q);
8855 $dbo->execute();
8856 }
8857
8858 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
8859 $dbo->setQuery($q);
8860 $dbo->execute();
8861
8862 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8863 $dbo->setQuery($q);
8864 $dbo->execute();
8865
8866 $app->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8867
8868 if ($pconfirmgen > 0) {
8869 $app->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
8870 } elseif (count($bookings) === 1) {
8871 // go to the back-end booking details page
8872 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
8873 } else {
8874 $app->redirect("index.php?option=com_vikbooking&task=orders");
8875 }
8876 }
8877
8878 public function optionals() {
8879 VikBookingHelper::printHeader("6");
8880
8881 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
8882
8883 parent::display();
8884
8885 if (VikBooking::showFooter()) {
8886 VikBookingHelper::printFooter();
8887 }
8888 }
8889
8890 public function newoptionals() {
8891 VikBookingHelper::printHeader("6");
8892
8893 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8894
8895 parent::display();
8896
8897 if (VikBooking::showFooter()) {
8898 VikBookingHelper::printFooter();
8899 }
8900 }
8901
8902 public function editoptional() {
8903 VikBookingHelper::printHeader("6");
8904
8905 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8906
8907 parent::display();
8908
8909 if (VikBooking::showFooter()) {
8910 VikBookingHelper::printFooter();
8911 }
8912 }
8913
8914 public function updateoptional()
8915 {
8916 if (!JSession::checkToken()) {
8917 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8918 }
8919
8920 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8921 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8922 }
8923
8924 $this->do_updateoptional();
8925 }
8926
8927 public function updateoptionalstay()
8928 {
8929 if (!JSession::checkToken()) {
8930 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8931 }
8932
8933 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8934 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8935 }
8936
8937 $this->do_updateoptional(true);
8938 }
8939
8940 private function do_updateoptional($stay = false) {
8941 $dbo = JFactory::getDbo();
8942 $app = JFactory::getApplication();
8943 $poptname = VikRequest::getString('optname', '', 'request');
8944 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
8945 $poptcost = VikRequest::getFloat('optcost', '', 'request');
8946 $poptperday = VikRequest::getString('optperday', '', 'request');
8947 $poptperperson = VikRequest::getString('optperperson', '', 'request');
8948 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
8949 $popthmany = VikRequest::getString('opthmany', '', 'request');
8950 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
8951 $pwhereup = VikRequest::getString('whereup', '', 'request');
8952 $pautoresize = VikRequest::getString('autoresize', '', 'request');
8953 $presizeto = VikRequest::getString('resizeto', '', 'request');
8954 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
8955 $pifchildren = $pifchildren == "1" ? 1 : 0;
8956 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
8957 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
8958 $pforcesel = VikRequest::getString('forcesel', '', 'request');
8959 $pforceval = VikRequest::getString('forceval', '', 'request');
8960 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
8961 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
8962 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
8963 $pforcesel = $pforcesel == "1" ? 1 : 0;
8964 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
8965 $pis_fee = VikRequest::getString('is_fee', '', 'request');
8966 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
8967 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
8968 $pagefrom = VikRequest::getVar('agefrom', array());
8969 $pageto = VikRequest::getVar('ageto', array());
8970 $pagecost = VikRequest::getVar('agecost', array());
8971 $pagectype = VikRequest::getVar('agectype', array());
8972 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
8973 $pavfrom = VikRequest::getString('avfrom', '', 'request');
8974 $pavto = VikRequest::getString('avto', '', 'request');
8975 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
8976 $pidrooms = VikRequest::getVar('idrooms', array());
8977 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
8978 if ($pforcesel == 1) {
8979 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
8980 } else {
8981 $strforceval = "";
8982 }
8983 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
8984 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
8985 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
8986 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
8987 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
8988 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
8989 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
8990 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
8991 $minguests = VikRequest::getInt('minguests', 0, 'request');
8992 $minguests_conflict = false;
8993 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
8994 if ($minguestsnum >= $maxguestsnum) {
8995 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
8996 } elseif (($maxguestsnum - $minguestsnum) < 2) {
8997 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
8998 }
8999 }
9000 if (!$minguests || $minguests_conflict !== false) {
9001 $minguestsnum = 0;
9002 $maxguestsnum = 0;
9003 if ($minguests_conflict !== false) {
9004 // raise warning, but do not stop the process
9005 VikError::raiseWarning('', $minguests_conflict);
9006 }
9007 }
9008 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9009 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9010 $custom_checkinout = VikRequest::getInt('custom_checkinout', 0, 'request');
9011 $set_checkin = VikRequest::getInt('set_checkin', 0, 'request');
9012 $set_checkout = VikRequest::getInt('set_checkout', 0, 'request');
9013 if (!$custom_checkinout) {
9014 $set_checkin = 0;
9015 $set_checkout = 0;
9016 }
9017 if ((!$set_checkin && !$set_checkout) || $set_checkin == $set_checkout) {
9018 // check-in and check-out times should not be equal or both empty
9019 $custom_checkinout = 0;
9020 }
9021 $oparams = [
9022 'minguestsnum' => $minguestsnum,
9023 'mingueststype' => $mingueststype,
9024 'maxguestsnum' => $maxguestsnum,
9025 'maxgueststype' => $maxgueststype,
9026 'damagedep' => $damagedep,
9027 'pet_fee' => $pet_fee,
9028 'custom_checkinout' => $custom_checkinout,
9029 'set_checkin' => $set_checkin,
9030 'set_checkout' => $set_checkout,
9031 ];
9032 /**
9033 * We fetch the previous params to merge them with the new ones
9034 * in case some properties have been set somewhere else.
9035 * For example, the damage deposit transmission to Booking.com.
9036 */
9037 $cur_oparams = array();
9038 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
9039 $dbo->setQuery($q);
9040 $dbo->execute();
9041 if ($dbo->getNumRows()) {
9042 $cur_oparams = $dbo->loadResult();
9043 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
9044 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
9045 // merge previous params with the new ones to get the new values
9046 $oparams = array_merge($cur_oparams, $oparams);
9047 }
9048 //
9049 if (!empty($poptname)) {
9050 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9051 jimport('joomla.filesystem.file');
9052 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9053 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9054 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9055 if (file_exists($updpath.$safename)) {
9056 $j=1;
9057 while (file_exists($updpath.$j.$safename)) {
9058 $j++;
9059 }
9060 $pwhere=$updpath.$j.$safename;
9061 } else {
9062 $j="";
9063 $pwhere=$updpath.$safename;
9064 }
9065 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9066 @unlink($pwhere);
9067 $picon="";
9068 } else {
9069 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9070 @chmod($pwhere, 0644);
9071 $picon=$j.$safename;
9072 if ($pautoresize=="1" && !empty($presizeto)) {
9073 $eforj = new vikResizer();
9074 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9075 if ($origmod) {
9076 @unlink($pwhere);
9077 $picon='r_'.$j.$safename;
9078 }
9079 }
9080 }
9081 } else {
9082 $picon="";
9083 }
9084 } else {
9085 $picon="";
9086 }
9087 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
9088 $poptperperson=($poptperperson=="each" ? "1" : "0");
9089 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
9090 $ageintervalstr = '';
9091 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9092 foreach ($pagefrom as $kage => $vage) {
9093 $afrom = intval($vage);
9094 $ato = intval($pageto[$kage]);
9095 $acost = floatval($pagecost[$kage]);
9096 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9097 if ($ato < $afrom) $ato = $afrom;
9098 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9099 }
9100 }
9101 $ageintervalstr = rtrim($ageintervalstr, ';;');
9102 if (!empty($ageintervalstr)) {
9103 $pforcesel = 1;
9104 }
9105 }
9106 $q = "UPDATE `#__vikbooking_optionals` SET `name`=".$dbo->quote($poptname).",`descr`=".$dbo->quote($poptdescr).",`cost`=".$dbo->quote($poptcost).",`perday`=".$dbo->quote($poptperday).",`hmany`=".$dbo->quote($popthmany).",".(strlen($picon)>0 ? "`img`='".$picon."'," : "")."`idiva`=".$dbo->quote($poptaliq).", `maxprice`=".$dbo->quote($pmaxprice).", `forcesel`='".$pforcesel."', `forceval`='".$strforceval."', `perperson`='".$poptperperson."', `ifchildren`='".$pifchildren."', `maxquant`='".$pmaxquant."', `ageintervals`='".$ageintervalstr."',`is_citytax`=".$pis_citytax.",`is_fee`=".$pis_fee.",`alwaysav`=".$dbo->quote($optavstr).",`pcentroom`=".$dbo->quote($ppcentroom).",`oparams`=" . $dbo->quote(json_encode($oparams)) . " WHERE `id`=".$dbo->quote($pwhereup).";";
9107 $dbo->setQuery($q);
9108 $dbo->execute();
9109 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
9110
9111 // assign/unset option-rooms relations
9112 $rooms_with_opt = array();
9113 if (count($pidrooms)) {
9114 // assign this new option to the requested rooms
9115 foreach ($pidrooms as $idroom) {
9116 if (empty($idroom)) {
9117 continue;
9118 }
9119 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9120 $dbo->setQuery($q);
9121 $dbo->execute();
9122 if (!$dbo->getNumRows()) {
9123 continue;
9124 }
9125 $room_data = $dbo->loadAssoc();
9126 array_push($rooms_with_opt, $room_data['id']);
9127 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9128 if (in_array((string)$pwhereup, $current_opts)) {
9129 continue;
9130 }
9131 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9132 // make sure we do not concatenate a real ID to 0
9133 $current_opts = array();
9134 }
9135 array_push($current_opts, $pwhereup);
9136 $new_opts = implode(';', $current_opts) . ';';
9137 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9138 $dbo->setQuery($q);
9139 $dbo->execute();
9140 }
9141 }
9142 if (!count($rooms_with_opt)) {
9143 // get all rooms to unset this option (if previously set)
9144 array_push($rooms_with_opt, '0');
9145 }
9146 // unset the option from the other rooms that may have it
9147 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9148 $dbo->setQuery($q);
9149 $dbo->execute();
9150 if ($dbo->getNumRows()) {
9151 $unset_rooms_opt = $dbo->loadAssocList();
9152 foreach ($unset_rooms_opt as $room_data) {
9153 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9154 if (!in_array((string)$pwhereup, $current_opts)) {
9155 // this room is not using this option
9156 continue;
9157 }
9158 $optkey = array_search((string)$pwhereup, $current_opts);
9159 if ($optkey === false) {
9160 // key not found
9161 continue;
9162 }
9163 // unset this option ID from the string
9164 unset($current_opts[$optkey]);
9165 if (!count($current_opts)) {
9166 // a room with no options assigned will be listed as "0;"
9167 $current_opts = array(0);
9168 }
9169 $new_opts = implode(';', $current_opts) . ';';
9170 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9171 $dbo->setQuery($q);
9172 $dbo->execute();
9173 }
9174 }
9175 //
9176
9177 }
9178 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9179 }
9180
9181 public function createoptionals()
9182 {
9183 if (!JSession::checkToken()) {
9184 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9185 }
9186
9187 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9188 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9189 }
9190
9191 $this->do_createoptionals();
9192 }
9193
9194 public function createoptionalsstay()
9195 {
9196 if (!JSession::checkToken()) {
9197 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9198 }
9199
9200 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9201 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9202 }
9203
9204 $this->do_createoptionals(true);
9205 }
9206
9207 private function do_createoptionals($stay = false) {
9208 $dbo = JFactory::getDbo();
9209 $poptname = VikRequest::getString('optname', '', 'request');
9210 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9211 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9212 $poptperday = VikRequest::getString('optperday', '', 'request');
9213 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9214 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9215 $popthmany = VikRequest::getString('opthmany', '', 'request');
9216 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9217 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9218 $presizeto = VikRequest::getString('resizeto', '', 'request');
9219 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9220 $pifchildren = $pifchildren == "1" ? 1 : 0;
9221 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9222 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9223 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9224 $pforceval = VikRequest::getString('forceval', '', 'request');
9225 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9226 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9227 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9228 $pforcesel = $pforcesel == "1" ? 1 : 0;
9229 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9230 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9231 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9232 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9233 $pagefrom = VikRequest::getVar('agefrom', array());
9234 $pageto = VikRequest::getVar('ageto', array());
9235 $pagecost = VikRequest::getVar('agecost', array());
9236 $pagectype = VikRequest::getVar('agectype', array());
9237 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9238 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9239 $pavto = VikRequest::getString('avto', '', 'request');
9240 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9241 $pidrooms = VikRequest::getVar('idrooms', array());
9242 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9243 if ($pforcesel == 1) {
9244 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9245 } else {
9246 $strforceval = "";
9247 }
9248 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9249 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9250 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9251 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9252 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9253 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9254 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9255 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9256 $minguests = VikRequest::getInt('minguests', 0, 'request');
9257 $minguests_conflict = false;
9258 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9259 if ($minguestsnum >= $maxguestsnum) {
9260 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9261 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9262 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9263 }
9264 }
9265 if (!$minguests || $minguests_conflict !== false) {
9266 $minguestsnum = 0;
9267 $maxguestsnum = 0;
9268 if ($minguests_conflict !== false) {
9269 // raise warning, but do not stop the process
9270 VikError::raiseWarning('', $minguests_conflict);
9271 }
9272 }
9273 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9274 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9275 $custom_checkinout = VikRequest::getInt('custom_checkinout', 0, 'request');
9276 $set_checkin = VikRequest::getInt('set_checkin', 0, 'request');
9277 $set_checkout = VikRequest::getInt('set_checkout', 0, 'request');
9278 if (!$custom_checkinout) {
9279 $set_checkin = 0;
9280 $set_checkout = 0;
9281 }
9282 if ((!$set_checkin && !$set_checkout) || $set_checkin == $set_checkout) {
9283 // check-in and check-out times should not be equal or both empty
9284 $custom_checkinout = 0;
9285 }
9286 $oparams = [
9287 'minguestsnum' => $minguestsnum,
9288 'mingueststype' => $mingueststype,
9289 'maxguestsnum' => $maxguestsnum,
9290 'maxgueststype' => $maxgueststype,
9291 'damagedep' => $damagedep,
9292 'pet_fee' => $pet_fee,
9293 'custom_checkinout' => $custom_checkinout,
9294 'set_checkin' => $set_checkin,
9295 'set_checkout' => $set_checkout,
9296 ];
9297 if (!empty($poptname)) {
9298 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9299 jimport('joomla.filesystem.file');
9300 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9301 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9302 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9303 if (file_exists($updpath.$safename)) {
9304 $j = 1;
9305 while (file_exists($updpath.$j.$safename)) {
9306 $j++;
9307 }
9308 $pwhere = $updpath.$j.$safename;
9309 } else {
9310 $j = "";
9311 $pwhere = $updpath.$safename;
9312 }
9313 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9314 @unlink($pwhere);
9315 $picon = "";
9316 } else {
9317 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9318 @chmod($pwhere, 0644);
9319 $picon = $j.$safename;
9320 if ($pautoresize == "1" && !empty($presizeto)) {
9321 $eforj = new vikResizer();
9322 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9323 if ($origmod) {
9324 @unlink($pwhere);
9325 $picon = 'r_'.$j.$safename;
9326 }
9327 }
9328 }
9329 } else {
9330 $picon = "";
9331 }
9332 } else {
9333 $picon = "";
9334 }
9335 $poptperday = ($poptperday == "each" ? "1" : "0");
9336 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9337 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9338 $ageintervalstr = '';
9339 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9340 foreach ($pagefrom as $kage => $vage) {
9341 $afrom = intval($vage);
9342 $ato = intval($pageto[$kage]);
9343 $acost = floatval($pagecost[$kage]);
9344 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9345 if ($ato < $afrom) $ato = $afrom;
9346 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9347 }
9348 }
9349 $ageintervalstr = rtrim($ageintervalstr, ';;');
9350 if (!empty($ageintervalstr)) {
9351 $pforcesel = 1;
9352 }
9353 }
9354 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9355 $dbo->setQuery($q);
9356 $dbo->execute();
9357 if ($dbo->getNumRows() == 1) {
9358 $getlast = $dbo->loadResult();
9359 $newsortnum = $getlast + 1;
9360 } else {
9361 $newsortnum = 1;
9362 }
9363 $q = "INSERT INTO `#__vikbooking_optionals` (`name`,`descr`,`cost`,`perday`,`hmany`,`img`,`idiva`,`maxprice`,`forcesel`,`forceval`,`perperson`,`ifchildren`,`maxquant`,`ordering`,`ageintervals`,`is_citytax`,`is_fee`,`alwaysav`,`pcentroom`,`oparams`) VALUES(".$dbo->quote($poptname).", ".$dbo->quote($poptdescr).", ".$dbo->quote($poptcost).", ".$dbo->quote($poptperday).", ".$dbo->quote($popthmany).", '".$picon."', ".$dbo->quote($poptaliq).", ".$dbo->quote($pmaxprice).", '".$pforcesel."', '".$strforceval."', '".$poptperperson."', '".$pifchildren."', '".$pmaxquant."', '".$newsortnum."', '".$ageintervalstr."', '".$pis_citytax."', '".$pis_fee."', ".$dbo->quote($optavstr).", ".$dbo->quote($ppcentroom).", " . $dbo->quote(json_encode($oparams)) . ");";
9364 $dbo->setQuery($q);
9365 $dbo->execute();
9366 $newoptid = $dbo->insertid();
9367
9368 if (!empty($newoptid)) {
9369 // assign/unset option-rooms relations
9370 $rooms_with_opt = array();
9371 if (count($pidrooms)) {
9372 // assign this new option to the requested rooms
9373 foreach ($pidrooms as $idroom) {
9374 if (empty($idroom)) {
9375 continue;
9376 }
9377 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9378 $dbo->setQuery($q);
9379 $dbo->execute();
9380 if (!$dbo->getNumRows()) {
9381 continue;
9382 }
9383 $room_data = $dbo->loadAssoc();
9384 array_push($rooms_with_opt, $room_data['id']);
9385 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9386 if (in_array((string)$newoptid, $current_opts)) {
9387 continue;
9388 }
9389 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9390 // make sure we do not concatenate a real ID to 0
9391 $current_opts = array();
9392 }
9393 array_push($current_opts, $newoptid);
9394 $new_opts = implode(';', $current_opts) . ';';
9395 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9396 $dbo->setQuery($q);
9397 $dbo->execute();
9398 }
9399 }
9400 if (!count($rooms_with_opt)) {
9401 // get all rooms to unset this option (if previously set)
9402 array_push($rooms_with_opt, '0');
9403 }
9404 // unset the option from the other rooms that may have it
9405 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9406 $dbo->setQuery($q);
9407 $dbo->execute();
9408 if ($dbo->getNumRows()) {
9409 $unset_rooms_opt = $dbo->loadAssocList();
9410 foreach ($unset_rooms_opt as $room_data) {
9411 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9412 if (!in_array((string)$newoptid, $current_opts)) {
9413 // this room is not using this option
9414 continue;
9415 }
9416 $optkey = array_search((string)$newoptid, $current_opts);
9417 if ($optkey === false) {
9418 // key not found
9419 continue;
9420 }
9421 // unset this option ID from the string
9422 unset($current_opts[$optkey]);
9423 if (!count($current_opts)) {
9424 // a room with no options assigned will be listed as "0;"
9425 $current_opts = array(0);
9426 }
9427 $new_opts = implode(';', $current_opts) . ';';
9428 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9429 $dbo->setQuery($q);
9430 $dbo->execute();
9431 }
9432 }
9433 //
9434 }
9435
9436 }
9437 $mainframe = JFactory::getApplication();
9438 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9439 }
9440
9441 public function removeoptionals()
9442 {
9443 if (!JSession::checkToken()) {
9444 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9445 }
9446
9447 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9448 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9449 }
9450
9451 $ids = VikRequest::getVar('cid', array(0));
9452 if ($ids) {
9453 $dbo = JFactory::getDbo();
9454 foreach ($ids as $d) {
9455 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9456 $dbo->setQuery($q);
9457 $dbo->execute();
9458 if ($dbo->getNumRows() == 1) {
9459 $rows = $dbo->loadAssocList();
9460 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9461 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9462 }
9463 }
9464 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9465 $dbo->setQuery($q);
9466 $dbo->execute();
9467 }
9468 }
9469 $mainframe = JFactory::getApplication();
9470 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9471 }
9472
9473 public function sendcustomsms() {
9474 $mainframe = JFactory::getApplication();
9475 $pphone = VikRequest::getString('phone', '', 'request');
9476 $psmscont = VikRequest::getString('smscont', '', 'request');
9477 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9478 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9479 if (!empty($pphone) && !empty($psmscont)) {
9480 $sms_api = VikBooking::getSMSAPIClass();
9481 $sms_api_params = VikBooking::getSMSParams();
9482 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9483 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9484 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9485 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9486 if ( !$sms_obj->validateResponse($response_obj) ) {
9487 VikError::raiseWarning('', $sms_obj->getLog());
9488 } else {
9489 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9490 }
9491 } else {
9492 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9493 }
9494 } else {
9495 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9496 }
9497 $mainframe->redirect($pgoto);
9498 }
9499
9500 public function sendcustomemail() {
9501 $dbo = JFactory::getDbo();
9502 $mainframe = JFactory::getApplication();
9503 $vbo_tn = VikBooking::getTranslator();
9504 $pbid = VikRequest::getInt('bid', '', 'request');
9505 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9506 $pemail = VikRequest::getString('email', '', 'request');
9507 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9508 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9509 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9510 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9511 if (!empty($pemail) && !empty($pemailcont)) {
9512 $email_attach = null;
9513 jimport('joomla.filesystem.file');
9514 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9515 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9516 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9517 $src = $pemailattch['tmp_name'];
9518 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9519 $j = "";
9520 if (file_exists($dest.$filename)) {
9521 $j = rand(171, 1717);
9522 while (file_exists($dest.$j.$filename)) {
9523 $j++;
9524 }
9525 }
9526 $finaldest = $dest.$j.$filename;
9527 if (VikBooking::uploadFile($src, $finaldest)) {
9528 $email_attach = $finaldest;
9529 } else {
9530 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9531 $mainframe->redirect($pgoto);
9532 exit;
9533 }
9534 }
9535 //VBO 1.10 - special tags for the custom email template files and messages
9536 $orig_mail_cont = $pemailcont;
9537 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9538 // replace any possible placeholder for special tags
9539 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9540 return $match[2];
9541 }, $pemailcont);
9542
9543 $booking = array();
9544 $q = "SELECT `o`.*,`co`.`idcustomer`,CONCAT_WS(' ',`c`.`first_name`,`c`.`last_name`) AS `customer_name`,`c`.`pin` AS `customer_pin`,`nat`.`country_name` FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idorder`=`o`.`id` AND `co`.`idorder`=".(int)$pbid." LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`co`.`idcustomer` LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`o`.`country` WHERE `o`.`id`=".(int)$pbid.";";
9545 $dbo->setQuery($q);
9546 $dbo->execute();
9547 if ($dbo->getNumRows() > 0) {
9548 $booking = $dbo->loadAssoc();
9549 }
9550 $booking_rooms = array();
9551 $q = "SELECT `or`.*,`r`.`name` AS `room_name` FROM `#__vikbooking_ordersrooms` AS `or` LEFT JOIN `#__vikbooking_rooms` `r` ON `r`.`id`=`or`.`idroom` WHERE `or`.`idorder`=".(int)$pbid.";";
9552 $dbo->setQuery($q);
9553 $dbo->execute();
9554 if ($dbo->getNumRows() > 0) {
9555 $booking_rooms = $dbo->loadAssocList();
9556 if (!empty($booking['lang'])) {
9557 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9558 }
9559 }
9560 //we use the same parsing function as the one for the Customer SMS Template
9561 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9562 }
9563 //
9564 // allow the use of token {booking_id} in subject
9565 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9566 //
9567 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9568 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9569 $vbo_app = VikBooking::getVboApplication();
9570 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9571 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9572 if ($email_attach !== null) {
9573 @unlink($email_attach);
9574 }
9575 //Booking History
9576 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9577 //
9578 //Save email template for future sending
9579 $config_rec_exists = false;
9580 $emtpl = array(
9581 'emailsubj' => $pemailsubj,
9582 'emailcont' => $orig_mail_cont,
9583 'emailfrom' => $pemailfrom
9584 );
9585 $cur_emtpl = array();
9586 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9587 $dbo->setQuery($q);
9588 $dbo->execute();
9589 if ($dbo->getNumRows() > 0) {
9590 $config_rec_exists = true;
9591 $cur_emtpl = $dbo->loadResult();
9592 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9593 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9594 }
9595 if (count($cur_emtpl) > 0) {
9596 $existing_subj = false;
9597 foreach ($cur_emtpl as $emk => $emv) {
9598 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9599 $cur_emtpl[$emk] = $emtpl;
9600 $existing_subj = true;
9601 break;
9602 }
9603 }
9604 if ($existing_subj === false) {
9605 $cur_emtpl[] = $emtpl;
9606 }
9607 } else {
9608 $cur_emtpl[] = $emtpl;
9609 }
9610 if (count($cur_emtpl) > 10) {
9611 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9612 $exceed = count($cur_emtpl) - 10;
9613 for ($tl=0; $tl < $exceed; $tl++) {
9614 unset($cur_emtpl[$tl]);
9615 }
9616 $cur_emtpl = array_values($cur_emtpl);
9617 }
9618 if ($config_rec_exists === true) {
9619 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9620 $dbo->setQuery($q);
9621 $dbo->execute();
9622 } else {
9623 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9624 $dbo->setQuery($q);
9625 $dbo->execute();
9626 }
9627 //
9628 } else {
9629 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9630 }
9631 $mainframe->redirect($pgoto);
9632 }
9633
9634 public function rmcustomemailtpl() {
9635 $cid = VikRequest::getVar('cid', array(0));
9636 $oid = $cid[0];
9637 $dbo = JFactory::getDBO();
9638 $mainframe = JFactory::getApplication();
9639 $tplind = VikRequest::getInt('tplind', '', 'request');
9640 if (empty($oid) || !(strlen($tplind) > 0)) {
9641 VikError::raiseWarning('', 'Missing Data.');
9642 $mainframe->redirect('index.php?option=com_vikbooking');
9643 exit;
9644 }
9645 $cur_emtpl = array();
9646 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9647 $dbo->setQuery($q);
9648 $dbo->execute();
9649 if ($dbo->getNumRows() > 0) {
9650 $cur_emtpl = $dbo->loadResult();
9651 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9652 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9653 } else {
9654 VikError::raiseWarning('', 'Missing Templates Record.');
9655 $mainframe->redirect('index.php?option=com_vikbooking');
9656 exit;
9657 }
9658 if (array_key_exists($tplind, $cur_emtpl)) {
9659 unset($cur_emtpl[$tplind]);
9660 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9661 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9662 $dbo->setQuery($q);
9663 $dbo->execute();
9664 }
9665 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
9666 exit;
9667 }
9668
9669 public function exportcustomers() {
9670 //we do not set the menu for this view
9671
9672 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
9673
9674 parent::display();
9675
9676 if (VikBooking::showFooter()) {
9677 VikBookingHelper::printFooter();
9678 }
9679 }
9680
9681 public function csvexportprepare() {
9682 //modal box, so we do not set menu or footer
9683
9684 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
9685
9686 parent::display();
9687 }
9688
9689 public function icsexportprepare() {
9690 //modal box, so we do not set menu or footer
9691
9692 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
9693
9694 parent::display();
9695 }
9696
9697 public function bookingcheckin() {
9698 //modal box, so we do not set menu or footer
9699
9700 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
9701
9702 parent::display();
9703 }
9704
9705 public function gencheckindoc() {
9706 //modal box, so we do not set menu or footer
9707
9708 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
9709
9710 parent::display();
9711 }
9712
9713 public function checkversion() {
9714 //to be called via ajax
9715 $params = new stdClass;
9716 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9717 $params->alias = 'com_vikbooking';
9718
9719 $result = array();
9720
9721 if (!count($result)) {
9722 $result = new stdClass;
9723 $result->status = 0;
9724 } else {
9725 $result = $result[0];
9726 }
9727
9728 echo json_encode($result);
9729 exit;
9730 }
9731
9732 public function updateprogram() {
9733 $params = new stdClass;
9734 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9735 $params->alias = 'com_vikbooking';
9736
9737 $result = array();
9738
9739 if (!count($result) || !$result[0]) {
9740 if (class_exists('JEventDispatcher')) {
9741 $dispatcher = JEventDispatcher::getInstance();
9742 $result = $dispatcher->trigger('checkVersion', array(&$params));
9743 } else {
9744 $app = JFactory::getApplication();
9745 if (method_exists($app, 'triggerEvent')) {
9746 $result = $app->triggerEvent('checkVersion', array(&$params));
9747 }
9748 }
9749 }
9750
9751 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
9752 exit('Error, plugin disabled');
9753 }
9754
9755 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
9756
9757 VikBookingHelper::pUpdateProgram($result[0]->response);
9758 }
9759
9760 public function updateprogramlaunch() {
9761 $params = new stdClass;
9762 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9763 $params->alias = 'com_vikbooking';
9764
9765 $json = new stdClass;
9766 $json->status = false;
9767
9768 echo json_encode($json);
9769 exit;
9770 }
9771
9772 public function invoke_vcm()
9773 {
9774 $app = JFactory::getApplication();
9775
9776 $oids = VikRequest::getVar('cid', []);
9777 $sync_type = VikRequest::getString('stype', 'new', 'request');
9778 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
9779 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
9780 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
9781 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
9782
9783 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
9784 $app->redirect("index.php?option=com_vikbooking&task=orders");
9785 $app->close();
9786 }
9787
9788 $result = VikBooking::getVcmInvoker()
9789 ->setOids($oids)
9790 ->setSyncType($sync_type)
9791 ->setOriginalBooking($original_booking_js, true)
9792 ->doSync();
9793
9794 if ($result === true) {
9795 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
9796 } else {
9797 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
9798 }
9799
9800 if (!empty($return_url)) {
9801 $app->redirect($return_url);
9802 } else {
9803 $app->redirect("index.php?option=com_vikbooking&task=orders");
9804 }
9805
9806 $app->close();
9807 }
9808
9809 public function multiphotosupload() {
9810 jimport('joomla.filesystem.file');
9811
9812 $dbo = JFactory::getDBO();
9813 $proomid = VikRequest::getInt('roomid', '', 'request');
9814
9815 $resp = array('files' => array());
9816 $error_messages = array(
9817 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
9818 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
9819 3 => 'The uploaded file was only partially uploaded',
9820 4 => 'No file was uploaded',
9821 6 => 'Missing a temporary folder',
9822 7 => 'Failed to write file to disk',
9823 8 => 'A PHP extension stopped the file upload',
9824 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
9825 'max_file_size' => 'File is too big',
9826 'min_file_size' => 'File is too small',
9827 'accept_file_types' => 'Filetype not allowed',
9828 'max_number_of_files' => 'Maximum number of files exceeded',
9829 'max_width' => 'Image exceeds maximum width',
9830 'min_width' => 'Image requires a minimum width',
9831 'max_height' => 'Image exceeds maximum height',
9832 'min_height' => 'Image requires a minimum height',
9833 'abort' => 'File upload aborted',
9834 'image_resize' => 'Failed to resize image',
9835 'vbo_type' => 'The file type cannot be accepted',
9836 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
9837 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
9838 );
9839
9840 $creativik = new vikResizer();
9841 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9842 $bigsdest = $updpath;
9843 $thumbsdest = $updpath;
9844 $dest = $updpath;
9845 $moreimagestr = '';
9846 $cur_captions = json_encode(array());
9847
9848 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
9849 $dbo->setQuery($q);
9850 $dbo->execute();
9851 if ($dbo->getNumRows() == 1) {
9852 $photo_data = $dbo->loadAssocList();
9853 $cur_captions = $photo_data[0]['imgcaptions'];
9854 $cur_photos = $photo_data[0]['moreimgs'];
9855 if (!empty($cur_photos)) {
9856 $moreimagestr .= $cur_photos;
9857 }
9858 }
9859
9860 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
9861
9862 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
9863 foreach ($bulkphotos['name'] as $updk => $photoname) {
9864 $uploaded_image = array();
9865 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
9866 $src = $bulkphotos['tmp_name'][$updk];
9867 $j = "";
9868 if (file_exists($dest.$filename)) {
9869 $j = rand(171, 1717);
9870 while (file_exists($dest.$j.$filename)) {
9871 $j++;
9872 }
9873 }
9874 $finaldest=$dest.$j.$filename;
9875 $is_error = false;
9876 $err_key = '';
9877 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
9878 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
9879 $is_error = true;
9880 $err_key = $bulkphotos['error'][$updk];
9881 }
9882 }
9883 if (!$is_error) {
9884 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
9885 if ($check[2] & imagetypes()) {
9886 if (VikBooking::uploadFile($src, $finaldest)) {
9887 $gimg = $j.$filename;
9888 //orig img
9889 $origmod = true;
9890 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
9891 //thumb
9892 $thumbsize = VikBooking::getThumbSize();
9893 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
9894 if (!$thumb || !$origmod) {
9895 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
9896 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
9897 $is_error = true;
9898 $err_key = 'vbo_perm';
9899 } else {
9900 $moreimagestr.=$j.$filename.";;";
9901 }
9902 @unlink($finaldest);
9903 } else {
9904 $is_error = true;
9905 $err_key = 'vbo_jupload';
9906 }
9907 } else {
9908 $is_error = true;
9909 $err_key = 'vbo_type';
9910 }
9911 }
9912 $img = new stdClass();
9913 if ($is_error) {
9914 $img->name = '';
9915 $img->size = '';
9916 $img->type = '';
9917 $img->url = '';
9918 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
9919 } else {
9920 $img->name = $photoname;
9921 $img->size = $bulkphotos['size'][$updk];
9922 $img->type = $bulkphotos['type'][$updk];
9923 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
9924 }
9925 $resp['files'][] = $img;
9926 }
9927 } else {
9928 $res = new stdClass();
9929 $res->name = '';
9930 $res->size = '';
9931 $res->type = '';
9932 $res->url = '';
9933 $res->error = 'No images received for upload';
9934 $resp['files'][] = $res;
9935 }
9936 //Update current extra images string
9937 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
9938 $dbo->setQuery($q);
9939 $dbo->execute();
9940 $resp['actmoreimgs'] = $moreimagestr;
9941 //Update current extra images uploaded
9942 $cur_thumbs = '';
9943 $morei=explode(';;', $moreimagestr);
9944 if (@count($morei) > 0) {
9945 $imgcaptions = json_decode($cur_captions, true);
9946 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
9947 $cur_thumbs .= '<ul class="vbo-sortable">';
9948 foreach ($morei as $ki => $mi) {
9949 if (!empty($mi)) {
9950 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
9951 $cur_thumbs .= '<a href="'.VBO_SITE_URI.'resources/uploads/big_'.$mi.'" target="_blank" class="vbomodal"><img src="'.VBO_SITE_URI.'resources/uploads/thumb_'.$mi.'" class="maxfifty"/></a>';
9952 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
9953 $cur_thumbs .= '<div id="vbimgdetbox'.$ki.'" class="vbimagedetbox" style="display: none;"><div class="captionlabel"><span>'.JText::translate('VBIMGCAPTION').'</span><input type="text" name="caption'.$ki.'" value="'.($usecaptions === true && isset($imgcaptions[$ki]) ? $imgcaptions[$ki] : "").'" size="40"/></div><input type="hidden" name="imgsorting[]" value="'.$mi.'"/><input class="captionsubmit" type="button" name="updcatpion" value="'.JText::translate('VBIMGUPDATE').'" onclick="javascript: updateCaptions();"/><div class="captionremoveimg"><a class="vbimgrm btn btn-danger" href="index.php?option=com_vikbooking&task=removemoreimgs&roomid='.$proomid.'&imgind='.$ki.'" title="'.JText::translate('VBREMOVEIMG').'"><i class="icon-remove"></i>'.JText::translate('VBREMOVEIMG').'</a></div></div>';
9954 $cur_thumbs .= '</li>';
9955 }
9956 }
9957 $cur_thumbs .= '</ul>';
9958 $cur_thumbs .= '<br clear="all"/>';
9959 }
9960 $resp['currentthumbs'] = $cur_thumbs;
9961
9962 echo json_encode($resp);
9963 exit;
9964 }
9965
9966 public function loadsmsbalance() {
9967 //to be called via ajax
9968 $html = 'Error1 [N/A]';
9969 $sms_api = VikBooking::getSMSAPIClass();
9970 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
9971 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9972 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
9973 if (method_exists('VikSmsApi', 'estimate')) {
9974 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
9975 if ( $array_result->errorCode != 0 ) {
9976 $html = 'Error3 ['.$array_result->errorMsg.']';
9977 } else {
9978 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
9979 }
9980 } else {
9981 $html = 'Error2 [N/A]';
9982 }
9983 }
9984 echo $html;
9985 exit;
9986 }
9987
9988 public function loadsmsparams() {
9989 //to be called via ajax
9990 $html = '---------';
9991 $phpfile = VikRequest::getString('phpfile', '', 'request');
9992 if (!empty($phpfile)) {
9993 $sms_api = VikBooking::getSMSAPIClass();
9994 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
9995 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
9996 }
9997 echo $html;
9998 exit;
9999 }
10000
10001 public function loadcronparams() {
10002 //to be called via ajax
10003 $html = '---------';
10004 $phpfile = VikRequest::getString('phpfile', '', 'request');
10005 if (!empty($phpfile)) {
10006 $html = VikBooking::displayCronParameters($phpfile);
10007 }
10008 echo $html;
10009 exit;
10010 }
10011
10012 public function loadpaymentparams() {
10013 //to be called via ajax
10014 $html = '<p>---------</p>';
10015 $phpfile = VikRequest::getString('phpfile', '', 'request');
10016 if (!empty($phpfile)) {
10017 $html = VikBooking::displayPaymentParameters($phpfile);
10018 }
10019 echo $html;
10020 exit;
10021 }
10022
10023 public function setbookingtag() {
10024 //to be called via ajax
10025 $dbo = JFactory::getDBO();
10026 $pidorder = VikRequest::getInt('idorder', '', 'request');
10027 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
10028 if (!empty($pidorder) && $ptagkey >= 0) {
10029 $all_tags = VikBooking::loadBookingsColorTags();
10030 if (array_key_exists($ptagkey, $all_tags)) {
10031 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
10032 $dbo->setQuery($q);
10033 $dbo->execute();
10034 if ($dbo->getNumRows() > 0) {
10035 $newcolortag = json_encode($all_tags[$ptagkey]);
10036 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
10037 $dbo->setQuery($q);
10038 $dbo->execute();
10039 $newcolortag = $all_tags[$ptagkey];
10040 $newcolortag['name'] = JText::translate($newcolortag['name']);
10041 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
10042 echo json_encode($newcolortag);
10043 } else {
10044 echo 'e4j.error.Booking ('.$pidorder.') not found';
10045 }
10046 } else {
10047 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
10048 }
10049 } else {
10050 echo 'e4j.error.Missing Data';
10051 }
10052 exit;
10053 }
10054
10055 public function updatereceiptnum() {
10056 //to be called via ajax
10057 $pnewnum = VikRequest::getInt('newnum', '', 'request');
10058 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
10059 $poid = VikRequest::getInt('oid', '', 'request');
10060 if ($pnewnum > 0) {
10061 VikBooking::getNextReceiptNumber($poid, $pnewnum);
10062 VikBooking::getReceiptNotes($pnewnotes);
10063 //Booking History
10064 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
10065 //
10066 echo 'e4j.ok';
10067 exit;
10068 }
10069 echo 'e4j.error';
10070 exit;
10071 }
10072
10073 public function isroombookable() {
10074 //to be called via ajax
10075 $dbo = JFactory::getDBO();
10076 $res = array(
10077 'status' => 0,
10078 'err' => ''
10079 );
10080 $prid = VikRequest::getInt('rid', '', 'request');
10081 $pfdate = VikRequest::getString('fdate', '', 'request');
10082 $ptdate = VikRequest::getString('tdate', '', 'request');
10083 $room_info = array();
10084 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
10085 $dbo->setQuery($q);
10086 $dbo->execute();
10087 if ($dbo->getNumRows() > 0) {
10088 $room_info = $dbo->loadAssoc();
10089 }
10090 $pcheckinh = 0;
10091 $pcheckinm = 0;
10092 $pcheckouth = 0;
10093 $pcheckoutm = 0;
10094 $timeopst = VikBooking::getTimeOpenStore();
10095 if (is_array($timeopst)) {
10096 $opent = VikBooking::getHoursMinutes($timeopst[0]);
10097 $closet = VikBooking::getHoursMinutes($timeopst[1]);
10098 $pcheckinh = $opent[0];
10099 $pcheckinm = $opent[1];
10100 $pcheckouth = $closet[0];
10101 $pcheckoutm = $closet[1];
10102 }
10103 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
10104 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
10105 if (
10106 count($room_info) > 0 &&
10107 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
10108 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
10109 {
10110 $res['status'] = 1;
10111 } else {
10112 if (!(count($room_info) > 0)) {
10113 $res['err'] = 'Room not found';
10114 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
10115 $res['err'] = 'Invalid dates';
10116 } else {
10117 //not available
10118 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
10119 }
10120 }
10121
10122 echo json_encode($res);
10123 exit;
10124 }
10125
10126 public function uploadsnapshot() {
10127 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
10128 /**
10129 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
10130 * The old snapshot collection script with Flash no longer works in 2021.
10131 *
10132 * @since 1.14 (J) - 1.4.0 (WP)
10133 */
10134 $result = null;
10135 try {
10136 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
10137 } catch (RuntimeException $e) {
10138 echo "e4j.error.Error " . $e->getMessage();
10139 exit;
10140 }
10141
10142 if (!is_object($result)) {
10143 echo "e4j.error.Invalid upload response";
10144 exit;
10145 }
10146
10147 echo $result->filename;
10148 exit;
10149 }
10150
10151 public function checkvcmrateschanges() {
10152 //to be called via ajax
10153 $session = JFactory::getSession();
10154 $ret = array('changesCount' => 0, 'changesData' => '');
10155 $updforvcm = $session->get('vbVcmRatesUpd', '');
10156 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
10157 $ret['changesCount'] = $updforvcm['count'];
10158 $ret['changesData'] = $updforvcm;
10159 }
10160
10161 echo json_encode($ret);
10162 exit;
10163 }
10164
10165 /**
10166 * AJAX endpoint to load the details of one or more bookings.
10167 *
10168 * @return void
10169 *
10170 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10171 */
10172 public function getbookingsinfo()
10173 {
10174 //to be called via ajax
10175 $dbo = JFactory::getDbo();
10176
10177 $booking_infos = [];
10178 $bookings = [];
10179
10180 $pidorders = VikRequest::getString('idorders', '', 'request');
10181 $psubroom = VikRequest::getString('subroom', '', 'request');
10182 $pstatus = VikRequest::getString('status', '', 'request');
10183 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10184 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10185 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10186
10187 if (!empty($pidorders)) {
10188 $bookings = explode(',', $pidorders);
10189 foreach ($bookings as $k => $v) {
10190 $v = intval(str_replace('-', '', $v));
10191 if (empty($v)) {
10192 unset($bookings[$k]);
10193 continue;
10194 }
10195 $bookings[$k] = $v;
10196 }
10197 }
10198 $bookings = array_values($bookings);
10199
10200 if (!$bookings) {
10201 /**
10202 * AJAX requests made by the page availability overview may contain empty booking IDs
10203 * due to SQL errors that only occupied the room, but could not save the booking record.
10204 * Clean up busy records where the busy relations contain empty booking IDs.
10205 *
10206 * @since 1.14 (J) - 1.4.0 (WP)
10207 */
10208 $hanging_busy_ids = [];
10209
10210 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10211 $dbo->setQuery($q);
10212 $removelist = $dbo->loadAssocList();
10213 if ($removelist) {
10214 foreach ($removelist as $hanging_busy) {
10215 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10216 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10217 array_push($hanging_busy_ids, $hanging_busy_id);
10218 }
10219 }
10220 }
10221
10222 // let's check also for ghost records that only occupy the room
10223 $q = "SELECT `b`.*,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b` LEFT JOIN `#__vikbooking_ordersbusy` AS `ob` ON `b`.`id`=`ob`.`idbusy` WHERE `b`.`checkout` >= " . time() . " AND (`ob`.`idorder` = 0 OR `ob`.`idorder` IS NULL);";
10224 $dbo->setQuery($q);
10225 $removelist = $dbo->loadAssocList();
10226 if ($removelist) {
10227 foreach ($removelist as $hanging_busy) {
10228 $hanging_busy_id = (int)$hanging_busy['id'];
10229 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10230 array_push($hanging_busy_ids, $hanging_busy_id);
10231 }
10232 }
10233 }
10234
10235 if ($hanging_busy_ids) {
10236 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10237 $dbo->setQuery($q);
10238 $dbo->execute();
10239 }
10240 //
10241
10242 // output the error
10243 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10244 }
10245
10246 $nowdf = VikBooking::getDateFormat(true);
10247 if ($nowdf == "%d/%m/%Y") {
10248 $df = 'd/m/Y';
10249 } elseif ($nowdf == "%m/%d/%Y") {
10250 $df = 'm/d/Y';
10251 } else {
10252 $df = 'Y/m/d';
10253 }
10254 $datesep = VikBooking::getDateSeparator(true);
10255 $currencysymb = VikBooking::getCurrencySymb();
10256 $current_y = date('Y');
10257 $current_ts = time();
10258 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10259
10260 $query = $dbo->getQuery(true);
10261 $query->select('o.*');
10262 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10263 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10264 // include the requested booking IDs and the cancelled reservations for this stay date
10265 $stay_date_info = getdate(strtotime($pstay_date));
10266 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10267 $query->where('((' . $dbo->qn('o.checkin') . ' <= ' . $lim_ts_to . ' AND ' . $dbo->qn('o.checkout') . ' > ' . $lim_ts_to . ') OR ' . $dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . '))');
10268 // exclude the pending reservations
10269 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10270 } else {
10271 // include only the requested booking IDs
10272 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10273 }
10274 if ($pstatus != 'any') {
10275 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10276 }
10277 if (!empty($pstay_date) && $pstatus == 'any') {
10278 // sort by confirmed status before cancelled status
10279 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10280 $query->order($dbo->qn('o.id') . ' ASC');
10281 }
10282 $dbo->setQuery($query);
10283 $booking_infos = $dbo->loadAssocList();
10284
10285 foreach ($booking_infos as $k => $row) {
10286 // rooms, amounts and guests information
10287 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10288 $rids_involved = [];
10289 $room_names = [];
10290 $totadults = 0;
10291 $totchildren = 0;
10292 foreach ($rooms as $rr) {
10293 $rids_involved[] = $rr['idroom'];
10294 $totadults += $rr['adults'];
10295 $totchildren += $rr['children'];
10296 $room_names[] = $rr['room_name'];
10297 if ($row['split_stay']) {
10298 // do not sum guests in case of split stay booking
10299 $totadults = $rr['adults'];
10300 $totchildren = $rr['children'];
10301 }
10302 }
10303
10304 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10305 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10306 if (!in_array($pidroom, $rids_involved)) {
10307 $is_out_of_scope = true;
10308 if ($psharedcal && count($bookings) === 1) {
10309 $is_out_of_scope = ($row['id'] != $bookings[0]);
10310 }
10311 if ($is_out_of_scope) {
10312 // out of scope reservation, unset it and go to the next one
10313 unset($booking_infos[$k]);
10314 continue;
10315 }
10316 }
10317 }
10318
10319 // included meal plans to be displayed in case of single-room booking
10320 $included_meals = [];
10321 $rplan_name = '';
10322 if (count($rooms) === 1) {
10323 // rate plan name and ID, if any
10324 $active_rplan_id = 0;
10325 if (!empty($rooms[0]['otarplan'])) {
10326 $rplan_name = $rooms[0]['otarplan'];
10327 } else {
10328 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10329 }
10330
10331 // find the included meals
10332 if (!empty($rooms[0]['meals'])) {
10333 // display included meals defined at room-reservation record
10334 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10335 } else {
10336 // fetch default included meals in the selected rate plan
10337 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10338 }
10339 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10340 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10341 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10342 }
10343 }
10344
10345 if ($included_meals) {
10346 $short_incl_meals = [];
10347 foreach ($included_meals as $meal_enum => $meal_name) {
10348 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10349 }
10350 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10351 }
10352
10353 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10354 $booking_infos[$k]['currency_symb'] = $currencysymb;
10355 if ($row['status'] == 'confirmed') {
10356 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10357 if ($row['checkout'] < $current_ts) {
10358 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10359 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10360 if ($row['checked'] == 1) {
10361 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10362 } elseif ($row['checked'] == -1) {
10363 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10364 }
10365 }
10366 } elseif ($row['status'] == 'standby') {
10367 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10368 } elseif ($row['status'] == 'cancelled') {
10369 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10370 } else {
10371 $booking_infos[$k]['status_lbl'] = $row['status'];
10372 }
10373 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10374 if ($booking_infos[$k]['colortag']) {
10375 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10376 }
10377 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10378 $booking_infos[$k]['tot_adults'] = $totadults;
10379 $booking_infos[$k]['tot_children'] = $totchildren;
10380 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10381 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10382
10383 // room indexes
10384 $rindexes = [];
10385 $av_room_indexes = [];
10386 $used_indexes_map = [];
10387 $sub_units_data = [];
10388 $optindexes = [];
10389 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10390 $missing_index = false;
10391 foreach ($rooms as $kor => $or) {
10392 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10393 // cannot build room indexes data
10394 continue;
10395 }
10396
10397 $room_params = json_decode($or['params'], true);
10398 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10399 // no distinctive features information
10400 continue;
10401 }
10402
10403 if (!strlen($or['roomindex'])) {
10404 // turn flag on for missing index when room does support them
10405 $missing_index = true;
10406 // build array with available room indexes
10407 $av_indexes = [];
10408 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10409 foreach ($room_params['features'] as $rind => $rfeatures) {
10410 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10411 continue;
10412 }
10413 foreach ($rfeatures as $fname => $fval) {
10414 if ($fval) {
10415 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10416 break;
10417 }
10418 }
10419 }
10420 if ($av_indexes) {
10421 // push available indexes for this room
10422 $av_room_indexes[$kor] = [
10423 'rid' => $or['idroom'],
10424 'name' => $or['room_name'],
10425 'list' => $av_indexes,
10426 ];
10427 }
10428 // do not proceed any further
10429 continue;
10430 }
10431
10432 // parse distinctive features
10433 foreach ($room_params['features'] as $rind => $rfeatures) {
10434 if ($rind != $or['roomindex']) {
10435 continue;
10436 }
10437 $ind_str = '';
10438 $ind_str_short = '';
10439 foreach ($rfeatures as $fname => $fval) {
10440 if (strlen($fval)) {
10441 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10442 $ind_str_short = $fval;
10443 break;
10444 }
10445 }
10446 if (!isset($rindexes[$or['room_name']])) {
10447 $rindexes[$or['room_name']] = $ind_str;
10448 $sub_units_data[$or['room_name']] = $ind_str_short;
10449 } else {
10450 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10451 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10452 }
10453 break;
10454 }
10455
10456 // build options to switch sub-unit index
10457 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10458 // build the options for switching the room index for this room
10459 foreach ($room_params['features'] as $rind => $rfeatures) {
10460 foreach ($rfeatures as $fname => $fval) {
10461 if (strlen((string)$fval)) {
10462 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10463 break;
10464 }
10465 }
10466 }
10467 }
10468 }
10469
10470 if ($rindexes) {
10471 $booking_infos[$k]['rindexes'] = $rindexes;
10472 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10473 }
10474
10475 if ($optindexes) {
10476 $booking_infos[$k]['optindexes'] = $optindexes;
10477 }
10478
10479 if ($missing_index && $av_room_indexes) {
10480 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10481 }
10482
10483 // include flag for missing room index
10484 $booking_infos[$k]['missing_index'] = $missing_index;
10485
10486 // channel provenience and small logo URL
10487 $ota_logo_img = JText::translate('VBORDFROMSITE');
10488 $booking_avatar_src = null;
10489 $booking_avatar_alt = null;
10490 if (!empty($row['channel'])) {
10491 $channelparts = explode('_', $row['channel']);
10492 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10493 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10494 if ($ota_logo_img === false) {
10495 $ota_logo_img = $otachannel;
10496 } else {
10497 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10498 }
10499 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10500 if ($logo_helper !== false) {
10501 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10502 $booking_avatar_alt = $logo_helper->provenience;
10503 }
10504 }
10505 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10506 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10507 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10508
10509 // Customer Details
10510 $custdata = $row['custdata'];
10511 $custdata_parts = explode("\n", $row['custdata']);
10512 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10513 //get the first two fields
10514 $custvalues = [];
10515 foreach ($custdata_parts as $custdet) {
10516 if (strlen($custdet) < 1) {
10517 continue;
10518 }
10519 $custdet_parts = explode(':', $custdet);
10520 if (count($custdet_parts) >= 2) {
10521 unset($custdet_parts[0]);
10522 array_push($custvalues, trim(implode(':', $custdet_parts)));
10523 }
10524 if (count($custvalues) > 1) {
10525 break;
10526 }
10527 }
10528 if (count($custvalues) > 1) {
10529 $custdata = implode(' ', $custvalues);
10530 }
10531 }
10532 if (strlen($custdata) > 45) {
10533 $custdata = (function_exists('mb_substr') ? mb_substr($custdata, 0, 45, 'UTF-8') : substr($custdata, 0, 45)) . " ...";
10534 }
10535
10536 // customer record details
10537 $customer = [];
10538 $q = "SELECT `c`.*,`co`.`idorder` FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_customers_orders` `co` ON `c`.`id`=`co`.`idcustomer` WHERE `co`.`idorder`=" . $row['id'];
10539 $dbo->setQuery($q, 0, 1);
10540 $dbo->execute();
10541 if ($dbo->getNumRows()) {
10542 $customer = $dbo->loadAssoc();
10543 if (!empty($customer['first_name'])) {
10544 $custdata = $customer['first_name'].' '.$customer['last_name'];
10545 if (!empty($customer['country'])) {
10546 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10547 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10548 }
10549 }
10550 }
10551 }
10552 $booking_infos[$k]['customer'] = $customer;
10553
10554 // check if a profile picture is available for the customer
10555 if (!empty($customer['pic'])) {
10556 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10557 $booking_avatar_alt = basename($booking_avatar_src);
10558 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10559 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10560 }
10561
10562 // whether this is a closure
10563 $booking_infos[$k]['closure'] = (int)$row['closure'];
10564 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10565
10566 // short customer information
10567 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10568 $booking_infos[$k]['cinfo'] = $custdata;
10569
10570 // formatted dates
10571 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10572 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10573 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10574
10575 // short booking date, check-in, check-out date format
10576 $stay_info_in = getdate($row['checkin']);
10577 $stay_info_out = getdate($row['checkout']);
10578 $str_checkin = date('d', $row['checkin']);
10579 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10580 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10581 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10582 $str_checkout .= ' ' . $stay_info_out['year'];
10583 }
10584 $booking_infos[$k]['checkin_short'] = $str_checkin;
10585 $booking_infos[$k]['checkout_short'] = $str_checkout;
10586 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10587 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10588 }
10589
10590 if (!$booking_infos) {
10591 // output the error
10592 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10593 }
10594
10595 // output the JSON encoded response and exit
10596 VBOHttpDocument::getInstance()->json($booking_infos);
10597 }
10598
10599 public function switchRoomIndex() {
10600 //to be called via ajax
10601 $dbo = JFactory::getDBO();
10602 $bid = VikRequest::getInt('bid', '', 'request');
10603 $rid = VikRequest::getInt('rid', '', 'request');
10604 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10605 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10606 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10607 echo 'e4j.error.#1 Missing Data';
10608 exit;
10609 }
10610 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10611 $dbo->setQuery($q);
10612 $dbo->execute();
10613 if ($dbo->getNumRows() < 1) {
10614 echo 'e4j.error.#2 Record not found';
10615 exit;
10616 }
10617 $rows = $dbo->loadAssocList();
10618 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10619 $dbo->setQuery($q);
10620 $dbo->execute();
10621 echo 'e4j.ok';
10622 exit;
10623 }
10624
10625 public function searchcustomer()
10626 {
10627 // to be called via ajax
10628 $dbo = JFactory::getDbo();
10629
10630 $kw = VikRequest::getString('kw', '', 'request');
10631 $nopin = VikRequest::getInt('nopin', '', 'request');
10632 $email = VikRequest::getInt('email', 0, 'request');
10633 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10634 $no_script = VikRequest::getInt('no_script', 0, 'request');
10635
10636 if (!strlen($kw)) {
10637 VBOHttpDocument::getInstance()->close(200, '');
10638 }
10639
10640 if ($nopin > 0) {
10641 //page all bookings
10642 $q = "SELECT * FROM `#__vikbooking_customers` WHERE CONCAT_WS(' ', `first_name`, `last_name`) LIKE ".$dbo->quote("%".$kw."%")." OR `email` LIKE ".$dbo->quote("%".$kw."%")." ORDER BY `first_name` ASC LIMIT 30;";
10643 } elseif ($email > 0) {
10644 // page calendar for checking if an email exists
10645 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10646 } else {
10647 //page calendar
10648 $q = "SELECT * FROM `#__vikbooking_customers` WHERE CONCAT_WS(' ', `first_name`, `last_name`) LIKE ".$dbo->quote("%".$kw."%")." OR `email` LIKE ".$dbo->quote("%".$kw."%")." OR `pin` LIKE ".$dbo->quote("%".$kw."%")." ORDER BY `first_name` ASC;";
10649 }
10650 $dbo->setQuery($q);
10651 $customers = $dbo->loadAssocList();
10652
10653 if (!$customers) {
10654 VBOHttpDocument::getInstance()->close(200, '');
10655 }
10656
10657 if ($email > 0) {
10658 VBOHttpDocument::getInstance()->json($customers[0]);
10659 }
10660
10661 $cust_old_fields = array();
10662 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10663 foreach ($customers as $k => $v) {
10664 $cstring_search .= '<div class="' . $selector . '" data-custid="'.$v['id'].'" data-email="'.$v['email'].'" data-phone="'.htmlspecialchars($v['phone']).'" data-country="'.$v['country'].'" data-pin="'.$v['pin'].'" data-firstname="'.htmlspecialchars($v['first_name']).'" data-lastname="'.htmlspecialchars($v['last_name']).'">'."\n";
10665 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
10666 if (!empty($v['pic'])) {
10667 $cstring_search .= '<img src="' . (strpos($v['pic'], 'http') === 0 ? $v['pic'] : VBO_SITE_URI . 'resources/uploads/' . $v['pic']) . '" class="vbo-country-flag vbo-customer-avatar-flag"/>'."\n";
10668 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
10669 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
10670 } else {
10671 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
10672 }
10673 $cstring_search .= '</span>';
10674 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
10675 if (!($nopin > 0)) {
10676 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
10677 }
10678 $cstring_search .= '</div>'."\n";
10679 if (!empty($v['cfields'])) {
10680 $oldfields = json_decode($v['cfields'], true);
10681 if (is_array($oldfields) && count($oldfields)) {
10682 $cust_old_fields[$v['id']] = $oldfields;
10683 }
10684 }
10685 }
10686 $cstring_search .= '</div>'."\n";
10687
10688 /**
10689 * Add the necessary JS code for the arrow navigation.
10690 */
10691 $cstring_search_js = '<script type="text/javascript">';
10692 $cstring_search_js .= '
10693 var vboCust = jQuery(".' . $selector . '");
10694 var vboCustSelected = null;
10695 jQuery(window).keydown(function(e) {
10696 if (e.which === 40) {
10697 if (vboCustSelected) {
10698 vboCustSelected.removeClass("' . $selector . '-highligthed");
10699 next = vboCustSelected.next();
10700 if (next.length > 0) {
10701 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10702 } else {
10703 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10704 }
10705 } else {
10706 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10707 }
10708 } else if (e.which === 38) {
10709 if (vboCustSelected) {
10710 vboCustSelected.removeClass("' . $selector . '-highligthed");
10711 next = vboCustSelected.prev();
10712 if (next.length > 0) {
10713 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10714 } else {
10715 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10716 }
10717 } else {
10718 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10719 }
10720 } else if (e.which === 13) {
10721 if (vboCustSelected) {
10722 vboCustSelected.trigger("click");
10723 }
10724 }
10725 });
10726 jQuery(".' . $selector . '").off("hover");
10727 jQuery(".' . $selector . '").hover(function() {
10728 if (vboCustSelected) {
10729 vboCustSelected.removeClass("' . $selector . '-highligthed");
10730 vboCustSelected = null;
10731 }
10732 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
10733 }, function() {
10734 if (vboCustSelected) {
10735 vboCustSelected.removeClass("' . $selector . '-highligthed");
10736 vboCustSelected = null;
10737 }
10738 jQuery(this).removeClass("' . $selector . '-highligthed");
10739 });';
10740 $cstring_search_js .= '</script>';
10741
10742 if (!$no_script) {
10743 // append JS
10744 $cstring_search .= $cstring_search_js;
10745 }
10746
10747 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
10748 }
10749
10750 public function sharesignaturelink() {
10751 //to be called via ajax
10752 $dbo = JFactory::getDBO();
10753 $response = array(
10754 'status' => 0,
10755 'error' => 'Generic Error'
10756 );
10757 $pbid = VikRequest::getInt('bid', '', 'request');
10758 $phow = VikRequest::getString('how', '', 'request');
10759 $pto = VikRequest::getString('to', '', 'request');
10760 $pcustomer = VikRequest::getInt('customer', '', 'request');
10761 $cpin = VikBooking::getCPinIstance();
10762 $customer_info = $cpin->getCustomerByID($pcustomer);
10763 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
10764 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
10765 $dbo->setQuery($q);
10766 $dbo->execute();
10767 if ($dbo->getNumRows() > 0) {
10768 $row = $dbo->loadAssoc();
10769
10770 $share_link = JUri::root() . 'index.php?option=com_vikbooking&task=signature&sid=' . (!empty($row['idorderota']) && !empty($row['channel']) ? $row['idorderota'] : $row['sid']) . '&ts=' . $row['ts'];
10771 if (VBOPlatformDetection::isWordPress()) {
10772 /**
10773 * @wponly Rewrite URI for front-end signature
10774 */
10775 $share_link = str_replace(JUri::root(), '', $share_link);
10776 $model = JModel::getInstance('vikbooking', 'shortcodes');
10777 $itemid = $model->all('post_id', $full = true);
10778 if (count($itemid)) {
10779 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
10780 }
10781 } else {
10782 /**
10783 * @joomlaonly
10784 */
10785 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
10786 if ($best_menuitem_id) {
10787 $share_base = str_replace(JUri::root(), '', $share_link);
10788 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
10789 }
10790 }
10791
10792 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10793 if ($phow == 'email') {
10794 $sender = VikBooking::getSenderMail();
10795 $vbo_app = VikBooking::getVboApplication();
10796 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
10797 $response['status'] = 1;
10798 } elseif ($phow == 'sms') {
10799 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10800 $sms_api = VikBooking::getSMSAPIClass();
10801 $sms_api_params = VikBooking::getSMSParams();
10802 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
10803 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10804 $sms_obj = new VikSmsApi(array(), $sms_api_params);
10805 $response_obj = $sms_obj->sendMessage($pto, $share_message);
10806 if ($sms_obj->validateResponse($response_obj)) {
10807 $response['status'] = 1;
10808 } else {
10809 $response['error'] = $sms_obj->getLog();
10810 }
10811 } else {
10812 $response['error'] = 'No SMS Provider Configured';
10813 }
10814 } else {
10815 $response['error'] = 'Invalid Sending Method';
10816 }
10817 } else {
10818 $response['error'] = 'Invalid Booking ID';
10819 }
10820 } else {
10821 $response['error'] = 'Empty values';
10822 }
10823
10824 echo json_encode($response);
10825 exit;
10826 }
10827
10828 public function dayselectioncount() {
10829 //to be called via ajax
10830 $tsinit = VikRequest::getString('dinit', '', 'request');
10831 $tsend = VikRequest::getString('dend', '', 'request');
10832 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
10833 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
10834 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
10835 $diff = $ptsend - $ptsinit;
10836 if ($diff >= 172800) {
10837 $datef = VikBooking::getDateFormat(true);
10838 if ($datef=="%d/%m/%Y") {
10839 $df = 'd-m-Y';
10840 } else {
10841 $df = 'Y-m-d';
10842 }
10843 //minimum 2 days for excluding some days
10844 $daysdiff = floor($diff / 86400);
10845 $infoinit = getdate($ptsinit);
10846 $select = '';
10847 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
10848 for($i = 0; $i <= $daysdiff; $i++) {
10849 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
10850 $infots = getdate($ts);
10851 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
10852 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
10853 }
10854 $select .= '</select></div>';
10855 //excluded days of the week
10856 if ($daysdiff >= 14) {
10857 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
10858 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
10859 $select .= '<option value="0">'.JText::translate('VBSUNDAY').'</option><option value="1">'.JText::translate('VBMONDAY').'</option><option value="2">'.JText::translate('VBTUESDAY').'</option><option value="3">'.JText::translate('VBWEDNESDAY').'</option><option value="4">'.JText::translate('VBTHURSDAY').'</option><option value="5">'.JText::translate('VBFRIDAY').'</option><option value="6">'.JText::translate('VBSATURDAY').'</option>';
10860 $select .= '</optgroup>';
10861 $select .= '</select></div>';
10862 }
10863 //
10864 echo $select;
10865 } else {
10866 echo '';
10867 }
10868 } else {
10869 echo '';
10870 }
10871 exit;
10872 }
10873
10874 public function createcheckindoc()
10875 {
10876 if (!JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking')) {
10877 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
10878 }
10879
10880 $cid = VikRequest::getVar('cid', array(0));
10881 $id = $cid[0];
10882
10883 $dbo = JFactory::getDBO();
10884 $mainframe = JFactory::getApplication();
10885 $vbo_tn = VikBooking::getTranslator();
10886 $lang = JFactory::getLanguage();
10887 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10888 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
10889 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
10890 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
10891 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
10892 $dbo->setQuery($q);
10893 $row = $dbo->loadAssoc();
10894 if (!$row) {
10895 $mainframe->redirect('index.php');
10896 exit;
10897 }
10898 if (!empty($row['lang'])) {
10899 if ($lang->getTag() != $row['lang']) {
10900 if (VBOPlatformDetection::isWordPress()) {
10901 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
10902 } else {
10903 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
10904 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
10905 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
10906 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
10907 }
10908 }
10909 if ($vbo_tn->getDefaultLang() != $row['lang']) {
10910 // force the translation to start because contents should be translated
10911 $vbo_tn::$force_tolang = $row['lang'];
10912 }
10913 }
10914 $customer = array();
10915 $q = "SELECT `c`.*,`co`.`idorder`,`co`.`signature`,`co`.`pax_data`,`co`.`comments`,`co`.`checkindoc` FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_customers_orders` `co` ON `c`.`id`=`co`.`idcustomer` WHERE `co`.`idorder`=".$row['id'].";";
10916 $dbo->setQuery($q);
10917 $dbo->execute();
10918 if ($dbo->getNumRows() > 0) {
10919 $customer = $dbo->loadAssoc();
10920 if (!empty($customer['country'])) {
10921 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10922 $customer['country_img'] = '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10923 }
10924 }
10925 }
10926 if (!(count($customer) > 0)) {
10927 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10928 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10929 exit;
10930 }
10931 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
10932 //check if the signature has been submitted
10933 $signature_data = '';
10934 $cont_type = '';
10935 if (!empty($psignature)) {
10936 //check whether the format is accepted
10937 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
10938 $parts = explode(';base64,', $psignature);
10939 $cont_type_parts = explode('image/', $parts[0]);
10940 $cont_type = $cont_type_parts[1];
10941 if (!empty($parts[1])) {
10942 $signature_data = base64_decode($parts[1]);
10943 }
10944 }
10945 }
10946 if (!empty($signature_data)) {
10947 //write file
10948 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
10949 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
10950 $fp = fopen($filepath, 'w+');
10951 $bytes = fwrite($fp, $signature_data);
10952 fclose($fp);
10953 if ($bytes !== false && $bytes > 0) {
10954 //update the signature in the DB
10955 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
10956 $dbo->setQuery($q);
10957 $dbo->execute();
10958 $customer['signature'] = $sign_fname;
10959 //resize image for screens with high resolution
10960 if ($ppad_ratio > 1) {
10961 $new_width = floor(($ppad_width / 2));
10962 $creativik = new vikResizer();
10963 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
10964 } else {
10965 /**
10966 * @wponly - trigger files mirroring
10967 */
10968 VikBookingLoader::import('update.manager');
10969 VikBookingUpdateManager::triggerUploadBackup($filepath);
10970 //
10971 }
10972 //
10973 } else {
10974 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
10975 }
10976 }
10977 //
10978 //generate PDF for check-in document by parsing the apposite template file
10979 $booking_rooms = array();
10980 $q = "SELECT `or`.*,`r`.`name` AS `room_name`,`r`.`fromadult`,`r`.`toadult` FROM `#__vikbooking_ordersrooms` AS `or` LEFT JOIN `#__vikbooking_rooms` `r` ON `r`.`id`=`or`.`idroom` WHERE `or`.`idorder`=".(int)$row['id'].";";
10981 $dbo->setQuery($q);
10982 $dbo->execute();
10983 if ($dbo->getNumRows() > 0) {
10984 $booking_rooms = $dbo->loadAssocList();
10985 if (!empty($row['lang'])) {
10986 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
10987 }
10988 }
10989 if (!class_exists('TCPDF')) {
10990 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
10991 }
10992 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
10993
10994 /**
10995 * Trigger event to allow third party plugins to return a specific font name.
10996 *
10997 * @since 1.16.0 (J) - 1.6.0 (WP)
10998 */
10999 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
11000 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
11001 $usepdffont = $custom_pdf_font[0];
11002 }
11003
11004 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
11005 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
11006
11007 // build the proper document SID for bc
11008 $doc_sid = $row['sid'] ?: $row['idorderota'] ?: '';
11009 $pdffname = $row['id'] . '_' . $doc_sid . '.pdf';
11010
11011 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
11012 if (file_exists($pathpdf)) @unlink($pathpdf);
11013 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
11014 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
11015 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
11016 //Header for each page of the pdf
11017 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
11018 $pdf->SetHeaderData($pdfparams['header_data'][0], $pdfparams['header_data'][1], $pdfparams['header_data'][2], $pdfparams['header_data'][3], $pdfparams['header_data'][4], $pdfparams['header_data'][5]);
11019 }
11020 //header and footer fonts
11021 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
11022 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
11023 //margins
11024 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
11025 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
11026 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
11027 //
11028 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
11029 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
11030 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
11031 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
11032 $pdf->SetPrintHeader(false);
11033 }
11034 if ($pdfparams['show_footer'] == 0) {
11035 $pdf->SetPrintFooter(false);
11036 }
11037 $pdf->AddPage();
11038 $pdf->writeHTML($checkin_body, true, false, true, false, '');
11039 $pdf->lastPage();
11040 $pdf->Output($pathpdf, 'F');
11041 if (!file_exists($pathpdf)) {
11042 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
11043 } else {
11044 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
11045 $dbo->setQuery($q);
11046 $dbo->execute();
11047 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
11048 /**
11049 * @wponly - trigger files mirroring
11050 */
11051 VikBookingLoader::import('update.manager');
11052 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
11053 //
11054 }
11055 //
11056 /**
11057 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
11058 */
11059 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
11060 exit;
11061 }
11062
11063 public function updatebookingcheckin()
11064 {
11065 if (!JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking')) {
11066 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11067 }
11068
11069 $cid = VikRequest::getVar('cid', array(0));
11070 $id = $cid[0];
11071
11072 $dbo = JFactory::getDbo();
11073 $app = JFactory::getApplication();
11074
11075 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11076 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
11077 $pguests = VikRequest::getVar('guests', array());
11078 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
11079 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
11080 $valid_actions = array(-1, 0, 1, 2);
11081 if (!in_array($pcheckin_action, $valid_actions)) {
11082 $app->redirect('index.php');
11083 exit;
11084 }
11085 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
11086 $dbo->setQuery($q);
11087 $dbo->execute();
11088 if ($dbo->getNumRows() < 1) {
11089 $app->redirect('index.php');
11090 exit;
11091 }
11092 $row = $dbo->loadAssoc();
11093 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
11094 $dbo->setQuery($q);
11095 $dbo->execute();
11096 if ($dbo->getNumRows() < 1) {
11097 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11098 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11099 exit;
11100 }
11101 $custorder = $dbo->loadAssoc();
11102 //update checked status and new total paid
11103 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
11104 $dbo->setQuery($q);
11105 $dbo->execute();
11106 // Booking History log for new amount paid (payment update)
11107 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
11108 $extra_data = new stdClass;
11109 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
11110 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
11111 }
11112 //
11113 //Booking History
11114 $hist_type = 'A';
11115 if ($pcheckin_action < 0) {
11116 $hist_type = 'Z';
11117 } elseif ($pcheckin_action == 1) {
11118 $hist_type = 'B';
11119 } elseif ($pcheckin_action == 2) {
11120 $hist_type = 'C';
11121 }
11122 $user = JFactory::getUser();
11123 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
11124 //
11125 //Guests Details
11126 $guests_details = array();
11127 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
11128 // grab also the fields for front-end pre check-in
11129 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
11130 //
11131 foreach ($pguests as $ind => $adults) {
11132 foreach ($adults as $aduind => $details) {
11133 foreach ($pax_fields as $key => $v) {
11134 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11135 if (!isset($guests_details[$ind])) {
11136 $guests_details[$ind] = array();
11137 }
11138 if (!isset($guests_details[$ind][$aduind])) {
11139 $guests_details[$ind][$aduind] = array();
11140 }
11141 $guests_details[$ind][$aduind][$key] = $details[$key];
11142 }
11143 }
11144 foreach ($pre_pax_fields as $key => $v) {
11145 if (isset($pax_fields[$key])) {
11146 // we must have parsed this back-end field already
11147 continue;
11148 }
11149 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11150 if (!isset($guests_details[$ind])) {
11151 $guests_details[$ind] = array();
11152 }
11153 if (!isset($guests_details[$ind][$aduind])) {
11154 $guests_details[$ind][$aduind] = array();
11155 }
11156 if (!isset($guests_details[$ind][$aduind][$key])) {
11157 $guests_details[$ind][$aduind][$key] = $details[$key];
11158 }
11159 }
11160 }
11161 }
11162 }
11163
11164 if ($guests_details) {
11165 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
11166 $curpaxdata = json_decode($custorder['pax_data'], true);
11167 if (is_array($curpaxdata) && $curpaxdata) {
11168 // scan new guest registration details
11169 foreach ($guests_details as $ind => $groom) {
11170 foreach ($groom as $aduind => $aduinfo) {
11171 if (isset($curpaxdata[$ind][$aduind])) {
11172 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
11173 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
11174 foreach ($guests_details[$ind][$aduind] as $key => $det) {
11175 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
11176 // this default pax field was specified as empty now, so we cannot merge it
11177 unset($guests_details[$ind][$aduind][$key]);
11178 }
11179 }
11180 }
11181 }
11182 }
11183
11184 /**
11185 * In order to not lose any custom registration data added through PMS reports,
11186 * we scan the previous registration data to ensure we keep them in the update.
11187 *
11188 * @since 1.16.10 (J) - 1.6.10 (WP)
11189 */
11190 foreach ($curpaxdata as $ind => $groom) {
11191 if (!isset($guests_details[$ind])) {
11192 // ignore deleted room registration
11193 continue;
11194 }
11195 foreach ($groom as $aduind => $aduinfo) {
11196 if (!isset($guests_details[$ind][$aduind]) || !is_array($aduinfo)) {
11197 // ignore deleted room-guest registration
11198 continue;
11199 }
11200 foreach ($aduinfo as $field_key => $field_val) {
11201 if (!isset($guests_details[$ind][$aduind][$field_key]) && !empty($field_val)) {
11202 // merge previous room-guest registration data
11203 $guests_details[$ind][$aduind][$field_key] = $field_val;
11204 }
11205 }
11206 }
11207 }
11208 }
11209
11210 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=" . $dbo->q(json_encode($guests_details)) . " WHERE `id`=" . (int) $custorder['id'] . ";";
11211 $dbo->setQuery($q);
11212 $dbo->execute();
11213 }
11214
11215 //'checked' status comments
11216 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11217 $dbo->setQuery($q);
11218 $dbo->execute();
11219
11220 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11221 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11222 exit;
11223 }
11224
11225 public function alterbooking()
11226 {
11227 $dbo = JFactory::getDbo();
11228 $app = JFactory::getApplication();
11229 $user = JFactory::getUser();
11230
11231 $response = array(
11232 'esit' => 1,
11233 'message' => '',
11234 'vcm' => '',
11235 );
11236
11237 // must be a string as it may contain a dash
11238 $pidorder = VikRequest::getString('idorder', '', 'request');
11239 $pidorder = intval(str_replace('-', '', $pidorder));
11240
11241 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11242 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11243 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11244 $ptodate = VikRequest::getString('todate', '', 'request');
11245 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11246 if ($pdebug == 1) {
11247 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11248 exit;
11249 }
11250
11251 $nowdf = VikBooking::getDateFormat(true);
11252 if ($nowdf == "%d/%m/%Y") {
11253 $df = 'd/m/Y';
11254 } elseif ($nowdf == "%m/%d/%Y") {
11255 $df = 'm/d/Y';
11256 } else {
11257 $df = 'Y/m/d';
11258 }
11259 $pcheckinh = 0;
11260 $pcheckinm = 0;
11261 $pcheckouth = 0;
11262 $pcheckoutm = 0;
11263 $timeopst = VikBooking::getTimeOpenStore();
11264 if (is_array($timeopst)) {
11265 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11266 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11267 $pcheckinh = $opent[0];
11268 $pcheckinm = $opent[1];
11269 $pcheckouth = $closet[0];
11270 $pcheckoutm = $closet[1];
11271 }
11272 $info_tsto = getdate(strtotime($ptodate));
11273 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11274 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11275 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11276 $ptodate = date('Y-m-d', $second);
11277 if (!($second > $first)) {
11278 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11279 exit;
11280 }
11281 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11282 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11283 exit;
11284 }
11285
11286 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11287 $dbo->setQuery($q, 0, 1);
11288 $dbo->execute();
11289 if (!$dbo->getNumRows()) {
11290 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11291 exit;
11292 }
11293 $ord = $dbo->loadAssoc();
11294
11295 $q = "SELECT `or`.*,`r`.`name`,`r`.`idopt`,`r`.`units`,`r`.`fromadult`,`r`.`toadult` FROM `#__vikbooking_ordersrooms` AS `or`,`#__vikbooking_rooms` AS `r` WHERE `or`.`idorder`=" . $ord['id'] . " AND `or`.`idroom`=`r`.`id` ORDER BY `or`.`id` ASC;";
11296 $dbo->setQuery($q);
11297 $dbo->execute();
11298 $ordersrooms = $dbo->loadAssocList();
11299
11300 // store for VCM the current rooms before the modification
11301 $ord['rooms_info'] = $ordersrooms;
11302
11303 // package or custom rate
11304 $is_package = !empty($ord['pkg']) ? true : false;
11305 $is_cust_cost = false;
11306 foreach ($ordersrooms as $kor => $or) {
11307 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11308 $is_cust_cost = true;
11309 break;
11310 }
11311 }
11312
11313 // availability helper
11314 $av_helper = VikBooking::getAvailabilityInstance();
11315
11316 // room stay dates in case of split stay
11317 $room_stay_dates = [];
11318 if ($ord['split_stay']) {
11319 // no need to get the transient based on booking status, as the booking must be confirmed
11320 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11321 // immediately count the number of nights of stay for each split room
11322 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11323 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11324 }
11325 }
11326
11327 // determine if dates have changed
11328 $dates_changed = false;
11329 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11330 $dates_changed = true;
11331 }
11332
11333 $toswitch = array();
11334 $idbooked = array();
11335 $rooms_units = array();
11336 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11337 $dbo->setQuery($q);
11338 $dbo->execute();
11339 $all_rooms = $dbo->loadAssocList();
11340 foreach ($all_rooms as $rr) {
11341 $rooms_units[$rr['id']]['name'] = $rr['name'];
11342 $rooms_units[$rr['id']]['units'] = $rr['units'];
11343 }
11344
11345 // switch room
11346 if ($poldidroom != $pidroom) {
11347 foreach ($ordersrooms as $ind => $or) {
11348 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11349 if (!isset($idbooked[$or['idroom']])) {
11350 $idbooked[$or['idroom']] = 0;
11351 }
11352 // $idbooked is not really needed as switch is never made for the same room id
11353 $idbooked[$or['idroom']]++;
11354 //
11355 $orkey = count($toswitch);
11356 $toswitch[$orkey]['from'] = $or['idroom'];
11357 $toswitch[$orkey]['to'] = $pidroom;
11358 $toswitch[$orkey]['record'] = $or;
11359 $toswitch[$orkey]['record_ind'] = $ind;
11360 break;
11361 }
11362 }
11363 }
11364 if (count($toswitch)) {
11365 foreach ($toswitch as $ksw => $rsw) {
11366 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11367 $room_checkin = $ord['checkin'];
11368 $room_checkout = $ord['checkout'];
11369 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11370 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11371 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11372 }
11373 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11374 // the room is not available
11375 unset($toswitch[$ksw]);
11376 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11377 exit;
11378 }
11379 }
11380 if (count($toswitch)) {
11381 //reset first record rate so that rates can be set again (rates are unset only if the room is switched, if just the dates are different the rates are kept equal as the num nights is the same)
11382 reset($ordersrooms);
11383 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11384 $dbo->setQuery($q);
11385 $dbo->execute();
11386 //
11387 foreach ($toswitch as $ksw => $rsw) {
11388 // update room reservation record
11389 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11390 $dbo->setQuery($q);
11391 $dbo->execute();
11392 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11393
11394 // update Notes field for this booking to keep track of the previous room that was assigned
11395 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11396 if (!empty($prev_room_name)) {
11397 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11398 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11399 $dbo->setQuery($q);
11400 $dbo->execute();
11401 }
11402
11403 if ($ord['status'] == 'confirmed') {
11404 // update room record in _busy
11405 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from'] && !empty($room_stay_dates[$rsw['record_ind']]['id'])) {
11406 // in case of a split stay it is fundamental to update the exact busy record ID
11407 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11408 $dbo->setQuery($q);
11409 $dbo->execute();
11410 } else {
11411 // regular processing of a room ID for a reservation, no matter which one, we switch it
11412 $q = "SELECT `b`.`id`,`b`.`idroom`,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`idroom`=" . $rsw['from'] . " AND `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=" . $ord['id'] . " LIMIT 1;";
11413 $dbo->setQuery($q);
11414 $dbo->execute();
11415 if ($dbo->getNumRows() == 1) {
11416 $cur_busy = $dbo->loadAssocList();
11417 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11418 $dbo->setQuery($q);
11419 $dbo->execute();
11420 }
11421 }
11422
11423 // if automated updates enabled, keep $response['vcm'] empty
11424 // Invoke Channel Manager
11425 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11426 $response['vcm'] = JText::translate('VBCHANNELMANAGERINVOKEASK').' <form action="index.php?option=com_vikbooking" method="post"><input type="hidden" name="option" value="com_vikbooking"/><input type="hidden" name="task" value="invoke_vcm"/><input type="hidden" name="stype" value="modify"/><input type="hidden" name="cid[]" value="'.$ord['id'].'"/><input type="hidden" name="origb" value="'.urlencode(json_encode($ord)).'"/><input type="hidden" name="returl" value="'.urlencode("index.php?option=com_vikbooking&task=overview").'"/><button type="submit" class="btn btn-primary">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button></form>';
11427 }
11428 } elseif ($ord['status'] == 'standby') {
11429 // remove record in _tmplock
11430 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11431 $dbo->setQuery($q);
11432 $dbo->execute();
11433 }
11434 }
11435
11436 // check if sub-units should be assigned again when switching room
11437 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11438 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11439 $room_indexes_usemap = [];
11440 foreach ($new_order_rooms as $kor => $or) {
11441 $num = $kor + 1;
11442 // assign room specific unit
11443 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11444 $use_ind_key = 0;
11445 if ($room_indexes) {
11446 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11447 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11448 } else {
11449 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11450 }
11451 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11452 $dbo->setQuery($q);
11453 $dbo->execute();
11454 $room_indexes_usemap[$or['idroom']]++;
11455 }
11456 }
11457 }
11458
11459 // do not terminate the process when there is a switch, proceed to check the dates.
11460 }
11461 }
11462
11463 // change dates
11464 if ($dates_changed) {
11465 if ($ord['split_stay']) {
11466 // we do not allow to drag and change dates for rooms in a split stay reservation
11467 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11468 exit;
11469 }
11470
11471 // total nights of stay
11472 $daysdiff = $ord['days'];
11473
11474 // re-read ordersrooms (as rooms may have been switched)
11475 $q = "SELECT `or`.*,`r`.`name`,`r`.`idopt`,`r`.`units`,`r`.`fromadult`,`r`.`toadult` FROM `#__vikbooking_ordersrooms` AS `or`,`#__vikbooking_rooms` AS `r` WHERE `or`.`idorder`=" . $ord['id'] . " AND `or`.`idroom`=`r`.`id` ORDER BY `or`.`id` ASC;";
11476 $dbo->setQuery($q);
11477 $dbo->execute();
11478 $ordersrooms = $dbo->loadAssocList();
11479
11480 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11481 $opertwounits = true;
11482 $units_counter = array();
11483 foreach ($ordersrooms as $ind => $or) {
11484 if (!isset($units_counter[$or['idroom']])) {
11485 $units_counter[$or['idroom']] = -1;
11486 }
11487 $units_counter[$or['idroom']]++;
11488 }
11489
11490 foreach ($ordersrooms as $ind => $or) {
11491 $num = $ind + 1;
11492 $check = "SELECT `b`.`id`,`b`.`checkin`,`b`.`realback`,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`idroom`=" . $or['idroom'] . " AND `b`.`realback`>=" . $first . " AND `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`!=" . $ord['id'] . ";";
11493 $dbo->setQuery($check);
11494 $dbo->execute();
11495 if ($dbo->getNumRows() > 0) {
11496 $busy = $dbo->loadAssocList();
11497 foreach ($groupdays as $gday) {
11498 $bfound = 0;
11499 foreach ($busy as $bu) {
11500 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11501 $bfound++;
11502 }
11503 }
11504 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11505 $opertwounits = false;
11506 break 2;
11507 }
11508 }
11509 }
11510 }
11511 if ($opertwounits !== true) {
11512 $response['esit'] = 0;
11513 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11514 echo json_encode($response);
11515 exit;
11516 }
11517
11518 // update dates and busy records
11519 $realback = VikBooking::getHoursRoomAvail() * 3600;
11520 $realback += $second;
11521 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11522 $dbo->setQuery($q);
11523 $dbo->execute();
11524 if ($ord['status'] == 'confirmed') {
11525 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11526 $dbo->setQuery($q);
11527 $dbo->execute();
11528 $allbusy = $dbo->loadAssocList();
11529 foreach ($allbusy as $bb) {
11530 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11531 $dbo->setQuery($q);
11532 $dbo->execute();
11533 }
11534 // if automated updates enabled, keep $response['vcm'] empty
11535 // Invoke Channel Manager
11536 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11537 $response['vcm'] = JText::translate('VBCHANNELMANAGERINVOKEASK').' <form action="index.php?option=com_vikbooking" method="post"><input type="hidden" name="option" value="com_vikbooking"/><input type="hidden" name="task" value="invoke_vcm"/><input type="hidden" name="stype" value="modify"/><input type="hidden" name="cid[]" value="'.$ord['id'].'"/><input type="hidden" name="origb" value="'.urlencode(json_encode($ord)).'"/><input type="hidden" name="returl" value="'.urlencode("index.php?option=com_vikbooking&task=overview").'"/><button type="submit" class="btn btn-primary">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button></form>';
11538 }
11539 }
11540 $response['message'] .= JText::translate('RESUPDATED')."\n";
11541 }
11542
11543 if (count($toswitch)) {
11544 /**
11545 * Rooms have changed so the new rates must be re-calculated.
11546 * Maybe they should be calculated in any case, even if just
11547 * the dates have changed. For the moment the rates are reset.
11548 */
11549 }
11550
11551 // unset any previously booked room due to calendar sharing
11552 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11553 // check if some of the rooms booked have shared calendars
11554 VikBooking::updateSharedCalendars($ord['id']);
11555 //
11556
11557 //Booking History
11558 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11559 //
11560
11561 $vcm_autosync = VikBooking::vcmAutoUpdate();
11562 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11563 //unset the vcm property as no buttons should be displayed when in auto-sync
11564 $response['vcm'] = '';
11565 $vcm_obj = VikBooking::getVcmInvoker();
11566 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11567 $sync_result = $vcm_obj->doSync();
11568 if ($sync_result === false) {
11569 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11570 }
11571 }
11572
11573 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11574 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11575 VikError::raiseNotice('', $response['vcm']);
11576 }
11577
11578 $response['message'] = nl2br($response['message']);
11579 echo json_encode($response);
11580 exit;
11581 }
11582
11583 public function modroomrateplans()
11584 {
11585 $dbo = JFactory::getDbo();
11586 $session = JFactory::getSession();
11587
11588 $updforvcm = $session->get('vbVcmRatesUpd', '');
11589 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11590
11591 $pid_room = VikRequest::getInt('id_room', '', 'request');
11592 $pid_price = VikRequest::getInt('id_price', '', 'request');
11593 $ptype = VikRequest::getString('type', '', 'request');
11594 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11595 $ptodate = VikRequest::getString('todate', '', 'request');
11596
11597 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11598 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11599 exit;
11600 }
11601
11602 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11603 $dbo->setQuery($q);
11604 $price_record = $dbo->loadAssoc();
11605
11606 if (!$price_record) {
11607 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11608 exit;
11609 }
11610
11611 $current_closed = array();
11612 if (!empty($price_record['closingd'])) {
11613 $current_closed = json_decode($price_record['closingd'], true);
11614 }
11615 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11616
11617 $start_ts = strtotime($pfromdate);
11618 $end_ts = strtotime($ptodate);
11619 $infostart = getdate($start_ts);
11620 $all_days = array();
11621 $output = array();
11622 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11623 $all_days[] = date('Y-m-d', $infostart[0]);
11624 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11625 $output[$indkey] = array();
11626 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11627 }
11628
11629 if ($ptype == 'close') {
11630 // close
11631 if (!array_key_exists($pid_room, $current_closed)) {
11632 $current_closed[$pid_room] = array();
11633 }
11634 foreach ($all_days as $daymod) {
11635 if (!in_array($daymod, $current_closed[$pid_room])) {
11636 $current_closed[$pid_room][] = $daymod;
11637 }
11638 }
11639 } else {
11640 // open
11641 if (array_key_exists($pid_room, $current_closed)) {
11642 foreach ($all_days as $daymod) {
11643 if (in_array($daymod, $current_closed[$pid_room])) {
11644 foreach ($current_closed[$pid_room] as $ck => $cv) {
11645 if ($daymod == $cv) {
11646 unset($current_closed[$pid_room][$ck]);
11647 }
11648 }
11649 }
11650 }
11651 } else {
11652 $current_closed[$pid_room] = array();
11653 }
11654 }
11655
11656 if (!$current_closed[$pid_room]) {
11657 unset($current_closed[$pid_room]);
11658 }
11659
11660 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11661 $dbo->setQuery($q);
11662 $dbo->execute();
11663
11664 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
11665 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
11666
11667 foreach ($output as $ok => $ov) {
11668 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
11669 }
11670
11671 // build new session values
11672 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
11673
11674 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
11675 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
11676 } else {
11677 $updforvcm['dfrom'] = $start_ts;
11678 }
11679
11680 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
11681 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
11682 } else {
11683 $updforvcm['dto'] = $end_ts;
11684 }
11685
11686 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
11687 if (!in_array($pid_room, $updforvcm['rooms'])) {
11688 $updforvcm['rooms'][] = $pid_room;
11689 }
11690 } else {
11691 $updforvcm['rooms'] = array($pid_room);
11692 }
11693
11694 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
11695 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
11696 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
11697 $updforvcm['rplans'][$pid_room][] = $pid_price;
11698 }
11699 } else {
11700 $updforvcm['rplans'][$pid_room] = array($pid_price);
11701 }
11702 } else {
11703 $updforvcm['rplans'] = array($pid_room => array($pid_price));
11704 }
11705
11706 /**
11707 * Rather than suggesting the administrator to manually invoke VCM to launch a Bulk Action,
11708 * we try to silently trigger an automatic bulk action before updating the session values.
11709 *
11710 * @since 1.17.1 (J) - 1.7.1 (WP)
11711 */
11712 $rates_aligned = false;
11713 try {
11714 if (class_exists('VikChannelManager')) {
11715 $rates_aligned = VikChannelManager::autoBulkActions([
11716 'from_date' => $pfromdate,
11717 'to_date' => $ptodate,
11718 'forced_rooms' => [$pid_room],
11719 'update' => 'rates',
11720 ]);
11721 }
11722 } catch (Throwable $e) {
11723 // do nothing
11724 $rates_aligned = false;
11725 }
11726
11727 if (!$rates_aligned) {
11728 // update session values
11729 $session->set('vbVcmRatesUpd', $updforvcm);
11730 }
11731
11732 echo json_encode($output);
11733 exit;
11734 }
11735
11736 public function icsexportlaunch() {
11737 $dbo = JFactory::getDBO();
11738 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11739 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11740 $pstatus = VikRequest::getString('status', '', 'request');
11741 $validstatus = array('confirmed', 'standby', 'cancelled');
11742 $filterstatus = '';
11743 $filterfirst = 0;
11744 $filtersecond = 0;
11745 $nowdf = VikBooking::getDateFormat(true);
11746 if ($nowdf == "%d/%m/%Y") {
11747 $df = 'd/m/Y';
11748 } elseif ($nowdf == "%m/%d/%Y") {
11749 $df = 'm/d/Y';
11750 } else {
11751 $df = 'Y/m/d';
11752 }
11753 $currencyname = VikBooking::getCurrencyName();
11754 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11755 $filterstatus = $pstatus;
11756 }
11757 if (!empty($pcheckindate)) {
11758 if (VikBooking::dateIsValid($pcheckindate)) {
11759 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11760 $filterfirst = $first;
11761 }
11762 }
11763 if (!empty($pcheckoutdate)) {
11764 if (VikBooking::dateIsValid($pcheckoutdate)) {
11765 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11766 if ($second > $first) {
11767 $filtersecond = $second;
11768 }
11769 }
11770 }
11771 $clause = array();
11772 if ($filterfirst > 0) {
11773 $clause[] = "`o`.`checkin` >= ".$filterfirst;
11774 }
11775 if ($filtersecond > 0) {
11776 $clause[] = "`o`.`checkout` <= ".$filtersecond;
11777 }
11778 if (!empty($filterstatus)) {
11779 $clause[] = "`o`.`status` = '".$filterstatus."'";
11780 }
11781 $q = "SELECT `o`.*,`or`.`idroom`,`or`.`adults`,`or`.`children`,`r`.`name` FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_ordersrooms` `or` ON `or`.`idorder`=`o`.`id` LEFT JOIN `#__vikbooking_rooms` `r` ON `or`.`idroom`=`r`.`id` ".(count($clause) > 0 ? "WHERE ".implode(" AND ", $clause)." " : "")."ORDER BY `o`.`checkin` ASC;";
11782 $dbo->setQuery($q);
11783 $dbo->execute();
11784 if ($dbo->getNumRows() > 0) {
11785 $orders = $dbo->loadAssocList();
11786 $icscontent = "BEGIN:VCALENDAR\n";
11787 $icscontent .= "VERSION:2.0\n";
11788 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
11789 $icscontent .= "CALSCALE:GREGORIAN\n";
11790 $str = "";
11791 foreach ($orders as $kord => $ord) {
11792 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11793 continue;
11794 }
11795 $usecurrencyname = $currencyname;
11796 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11797 $statusstr = '';
11798 if ($ord['status'] == 'confirmed') {
11799 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11800 } elseif ($ord['status'] == 'standby') {
11801 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11802 } elseif ($ord['status'] == 'cancelled') {
11803 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11804 }
11805 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
11806 /**
11807 * @wponly Rewrite URI for front-end
11808 */
11809 $uri = str_replace(JUri::root(), '', $uri);
11810 $model = JModel::getInstance('vikbooking', 'shortcodes');
11811 $itemid = $model->best('booking');
11812 if ($itemid) {
11813 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
11814 }
11815 //
11816 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
11817 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11818 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
11819 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
11820 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
11821 $str .= "BEGIN:VEVENT\n";
11822 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11823 $str .= "UID:" . uniqid() . "\n";
11824 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11825 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
11826 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
11827 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
11828 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11829 $str .= "END:VEVENT\n";
11830 }
11831 $icscontent .= $str;
11832 $icscontent .= "END:VCALENDAR\n";
11833 //download file from buffer
11834 header("Content-Type: application/octet-stream; ");
11835 header("Cache-Control: no-store, no-cache");
11836 header('Content-Disposition: attachment; filename="bookings_export.ics"');
11837 $f = fopen('php://output', "w");
11838 fwrite($f, $icscontent);
11839 fclose($f);
11840 exit;
11841 } else {
11842 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
11843 $mainframe = JFactory::getApplication();
11844 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11845 }
11846 }
11847
11848 public function csvexportlaunch()
11849 {
11850 $dbo = JFactory::getDbo();
11851 $app = JFactory::getApplication();
11852
11853 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
11854 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
11855 $pchfilt = VikRequest::getString('chfilt', '', 'request');
11856 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
11857 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11858 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11859 $pstatus = VikRequest::getString('status', '', 'request');
11860 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
11861 $pformat = VikRequest::getString('format', 'csv', 'request');
11862
11863 // let the report class (a generic one) generate the CSV file in the proper format
11864 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
11865
11866 $validstatus = array('confirmed', 'standby', 'cancelled');
11867 $validdates = array('ts', 'checkin', 'checkout');
11868
11869 $filterdate = '';
11870 $filterstatus = '';
11871 $first = 0;
11872 $filterfirst = 0;
11873 $filtersecond = 0;
11874 $nowdf = VikBooking::getDateFormat(true);
11875 if ($nowdf == "%d/%m/%Y") {
11876 $df = 'd/m/Y';
11877 } elseif ($nowdf == "%m/%d/%Y") {
11878 $df = 'm/d/Y';
11879 } else {
11880 $df = 'Y/m/d';
11881 }
11882 $datesep = VikBooking::getDateSeparator(true);
11883 $currencyname = VikBooking::getCurrencyName();
11884
11885 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11886 $filterstatus = $pstatus;
11887 }
11888 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
11889 $filterdate = $pdatefilt;
11890 }
11891 if (!empty($pcheckindate) && !empty($filterdate)) {
11892 if (VikBooking::dateIsValid($pcheckindate)) {
11893 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11894 $filterfirst = $first;
11895 }
11896 }
11897 if (!empty($pcheckoutdate) && !empty($filterdate)) {
11898 if (VikBooking::dateIsValid($pcheckoutdate)) {
11899 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11900 if ($second > $first) {
11901 $filtersecond = $second;
11902 }
11903 }
11904 }
11905 $clause = array();
11906 if ($filterfirst > 0) {
11907 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
11908 }
11909 if ($filtersecond > 0) {
11910 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
11911 }
11912 if (!empty($filterstatus)) {
11913 $clause[] = "`o`.`status` = '".$filterstatus."'";
11914 }
11915 if (!empty($pchfilt)) {
11916 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
11917 }
11918 if (!empty($ppayfilt)) {
11919 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
11920 }
11921 if (!empty($proomfilt)) {
11922 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
11923 }
11924
11925 if (!empty($pcatfilt)) {
11926 $room_cat_ids = array();
11927 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
11928 $dbo->setQuery($q);
11929 $dbo->execute();
11930 if ($dbo->getNumRows()) {
11931 $records = $dbo->loadAssocList();
11932 foreach ($records as $rcat) {
11933 $parts = explode(';', $rcat['idcat']);
11934 if (in_array($pcatfilt, $parts)) {
11935 $room_cat_ids[] = $rcat['id'];
11936 }
11937 }
11938 }
11939 if (count($room_cat_ids)) {
11940 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
11941 }
11942 }
11943
11944 $q = "SELECT `o`.*,`or`.`idroom`,`or`.`adults`,`or`.`children`,`or`.`idtar`,`or`.`optionals`,`or`.`t_first_name`,`or`.`t_last_name`,`or`.`extracosts`,`or`.`cust_cost`,`or`.`cust_idiva`,`or`.`room_cost`,`r`.`name`,`d`.`idprice`,`p`.`idiva`,`t`.`aliq`,`t`.`breakdown` FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_ordersrooms` `or` ON `or`.`idorder`=`o`.`id` LEFT JOIN `#__vikbooking_rooms` `r` ON `or`.`idroom`=`r`.`id` LEFT JOIN `#__vikbooking_dispcost` `d` ON `or`.`idtar`=`d`.`id` LEFT JOIN `#__vikbooking_prices` `p` ON `d`.`idprice`=`p`.`id` LEFT JOIN `#__vikbooking_iva` `t` ON `p`.`idiva`=`t`.`id` ".(count($clause) > 0 ? "WHERE ".implode(" AND ", $clause)." " : "")."ORDER BY `o`.`checkin` ASC;";
11945 $dbo->setQuery($q);
11946 $orders = $dbo->loadAssocList();
11947 if (!$orders) {
11948 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
11949 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11950 $app->close();
11951 }
11952
11953 // options
11954 $all_options = array();
11955 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
11956 $dbo->setQuery($q);
11957 $options = $dbo->loadAssocList();
11958 if ($options) {
11959 foreach ($options as $ok => $ov) {
11960 $all_options[$ov['id']] = $ov;
11961 }
11962 }
11963
11964 // set CSV columns
11965 $report_obj->setReportCols([
11966 [
11967 'label' => JText::translate('VBDASHBOOKINGID'),
11968 ],
11969 [
11970 'label' => JText::translate('VBPVIEWORDERSONE'),
11971 ],
11972 [
11973 'label' => JText::translate('VBCSVCHECKIN'),
11974 ],
11975 [
11976 'label' => JText::translate('VBCSVCHECKOUT'),
11977 ],
11978 [
11979 'label' => JText::translate('VBCSVNIGHTS'),
11980 ],
11981 [
11982 'label' => JText::translate('VBCSVROOM'),
11983 ],
11984 [
11985 'label' => JText::translate('VBCSVPEOPLE'),
11986 ],
11987 [
11988 'label' => JText::translate('VBCSVCUSTINFO'),
11989 ],
11990 [
11991 'label' => JText::translate('ORDER_SPREQUESTS'),
11992 ],
11993 [
11994 'label' => JText::translate('ORDER_NOTES'),
11995 ],
11996 [
11997 'label' => JText::translate('VBCSVCREATEDBY'),
11998 ],
11999 [
12000 'label' => JText::translate('VBCSVCUSTMAIL'),
12001 ],
12002 [
12003 'label' => JText::translate('ORDER_PHONE'),
12004 ],
12005 [
12006 'label' => JText::translate('VBCSVOPTIONS'),
12007 ],
12008 [
12009 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
12010 ],
12011 [
12012 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
12013 ],
12014 [
12015 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
12016 ],
12017 [
12018 'label' => JText::translate('VBCSVTOTAL'),
12019 ],
12020 [
12021 'label' => JText::translate('VBCSVTOTPAID'),
12022 ],
12023 [
12024 'label' => JText::translate('VBCSVTOTTAXES'),
12025 ],
12026 ]);
12027
12028 // prepare the container for the CSV rows
12029 $orderscsv = [];
12030
12031 // availability helper
12032 $av_helper = VikBooking::getAvailabilityInstance();
12033
12034 $room_inds = [];
12035 $room_stay_dates = [];
12036 foreach ($orders as $kord => $ord) {
12037 // room index in this booking
12038 if (!isset($room_inds[$ord['id']])) {
12039 $room_inds[$ord['id']] = -1;
12040 }
12041 $room_inds[$ord['id']]++;
12042
12043 /**
12044 * Split stay reservation.
12045 *
12046 * @since 1.16.0 (J) - 1.6.0 (WP)
12047 */
12048 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
12049 if ($ord['split_stay']) {
12050 if ($ord['status'] == 'confirmed') {
12051 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
12052 } else {
12053 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
12054 }
12055 // immediately count the number of nights of stay for each split room
12056 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
12057 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
12058 // overwrite values for compatibility with non-confirmed bookings
12059 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
12060 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
12061 }
12062 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
12063 // overwrite the whole array
12064 $room_stay_dates[$sps_r_k] = $sps_r_v;
12065 }
12066 }
12067
12068 // determine nights and dates for this room booking
12069 $booking_nights = $ord['days'];
12070 $booking_checkin = $ord['checkin'];
12071 $booking_checkout = $ord['checkout'];
12072 if ($ord['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$room_inds[$ord['id']]]) && $room_stay_dates[$room_inds[$ord['id']]]['idroom'] == $ord['idroom']) {
12073 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
12074 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
12075 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
12076 }
12077
12078 $usecurrencyname = $currencyname;
12079 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12080 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12081 $custinfostr = str_replace(",", " ", $ord['custdata']);
12082 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
12083 if (count($customer)) {
12084 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
12085 }
12086 $special_requests = '';
12087 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12088 $special_requests = $match[1];
12089 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12090 $special_requests = $match[1];
12091 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
12092 $special_requests = $match[1];
12093 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
12094 $special_requests = $match[1];
12095 }
12096 $paystr = '';
12097 if (!empty($ord['idpayment'])) {
12098 $payparts = explode('=', $ord['idpayment']);
12099 $paystr = $payparts[1];
12100 }
12101 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
12102 $statusstr = '';
12103 if ($ord['status'] == 'confirmed') {
12104 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12105 } elseif ($ord['status'] == 'standby') {
12106 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12107 } elseif ($ord['status'] == 'cancelled') {
12108 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12109 }
12110 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
12111 if ($ord['roomsnum'] > 1) {
12112 // take the cost for the individual room
12113 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
12114 }
12115 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
12116 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12117 // total paid will be printed only for the last room booked
12118 $totalpaidstring = '';
12119 }
12120 $options_str = '';
12121 if (!empty($ord['optionals'])) {
12122 $stepo = explode(";", $ord['optionals']);
12123 foreach ($stepo as $roptkey => $oo) {
12124 if (!empty($oo)) {
12125 $stept = explode(":", $oo);
12126 if (array_key_exists($stept[0], $all_options)) {
12127 $actopt = $all_options[$stept[0]];
12128 $optpcent = false;
12129 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
12130 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
12131 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
12132 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
12133 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
12134 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
12135 $agestept = explode('-', $stept[1]);
12136 $stept[1] = $agestept[0];
12137 $chvar = $agestept[1];
12138 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
12139 $optpcent = true;
12140 }
12141 $actopt['chageintv'] = $chvar;
12142 if (isset($optagenames[($chvar - 1)])) {
12143 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
12144 }
12145 if (isset($optagecosts[($chvar - 1)])) {
12146 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
12147 } else {
12148 $realcost = 0;
12149 }
12150 } else {
12151 // VBO 1.11 - options percentage cost of the room total fee
12152 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
12153 //
12154 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
12155 }
12156 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
12157 $realcost=$actopt['maxprice'];
12158 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
12159 $realcost = $actopt['maxprice'] * $stept[1];
12160 }
12161 }
12162 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
12163 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
12164 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
12165 }
12166 }
12167 }
12168 }
12169
12170 // custom extra costs
12171 if (!empty($ord['extracosts'])) {
12172 $cur_extra_costs = json_decode($ord['extracosts'], true);
12173 foreach ($cur_extra_costs as $eck => $ecv) {
12174 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
12175 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
12176 }
12177 }
12178
12179 // taxes
12180 $taxes_str = '';
12181 if ($ord['tot_taxes'] > 0.00) {
12182 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
12183 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
12184 $tax_breakdown = json_decode($ord['breakdown'], true);
12185 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
12186 if (count($tax_breakdown)) {
12187 foreach ($tax_breakdown as $tbkk => $tbkv) {
12188 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
12189 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
12190 }
12191 }
12192 }
12193 }
12194 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12195 // total taxes will be printed only for the last room booked
12196 $taxes_str = '';
12197 }
12198
12199 // created by
12200 $created_by = '';
12201 if (!empty($ord['ujid'])) {
12202 $creator = new JUser($ord['ujid']);
12203 if (property_exists($creator, 'name')) {
12204 $created_by = $creator->name.' ('.$creator->username.')';
12205 }
12206 }
12207 if (empty($created_by) && !empty($ord['t_first_name'])) {
12208 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
12209 }
12210
12211 // push line for export
12212 $orderscsv[] = [
12213 [
12214 'value' => $ord['id'],
12215 ],
12216 [
12217 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
12218 ],
12219 [
12220 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
12221 ],
12222 [
12223 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
12224 ],
12225 [
12226 'value' => $booking_nights,
12227 ],
12228 [
12229 'value' => $ord['name'],
12230 ],
12231 [
12232 'value' => $peoplestr,
12233 ],
12234 [
12235 'value' => $custinfostr,
12236 ],
12237 [
12238 'value' => $special_requests,
12239 ],
12240 [
12241 'value' => $ord['adminnotes'],
12242 ],
12243 [
12244 'value' => $created_by,
12245 ],
12246 [
12247 'value' => $ord['custmail'],
12248 ],
12249 [
12250 'value' => $ord['phone'],
12251 ],
12252 [
12253 'value' => $options_str,
12254 ],
12255 [
12256 'value' => $paystr,
12257 ],
12258 [
12259 'value' => $ordnumbstr,
12260 ],
12261 [
12262 'value' => $statusstr,
12263 ],
12264 [
12265 'value' => $totalstring,
12266 ],
12267 [
12268 'value' => $totalpaidstring,
12269 ],
12270 [
12271 'value' => $taxes_str,
12272 ],
12273 ];
12274 }
12275
12276 // set CSV rows
12277 $report_obj->setReportRows($orderscsv);
12278
12279 // build lines to export
12280 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12281
12282 // set export file name
12283 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12284
12285 // force the download of the CSV file
12286 $report_obj->outputHeaders();
12287
12288 // send lines to output
12289 $report_obj->outputCSV($csvlines);
12290
12291 exit;
12292 }
12293
12294 public function exportcustomerslaunch() {
12295 $cid = VikRequest::getVar('cid', array(0));
12296 $dbo = JFactory::getDBO();
12297 $pnotes = VikRequest::getInt('notes', '', 'request');
12298 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12299 $ppin = VikRequest::getInt('pin', '', 'request');
12300 $pcountry = VikRequest::getString('country', '', 'request');
12301 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12302 $ptodate = VikRequest::getString('todate', '', 'request');
12303 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12304 $clauses = array();
12305 if (count($cid) > 0 && !empty($cid[0])) {
12306 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12307 }
12308 if (!empty($pcountry)) {
12309 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12310 }
12311 $datescol = '`bk`.`ts`';
12312 if ($pdatefilt > 0) {
12313 if ($pdatefilt == 1) {
12314 $datescol = '`bk`.`ts`';
12315 } elseif ($pdatefilt == 2) {
12316 $datescol = '`bk`.`checkin`';
12317 } elseif ($pdatefilt == 3) {
12318 $datescol = '`bk`.`checkout`';
12319 }
12320 }
12321 if (!empty($pfromdate)) {
12322 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12323 $clauses[] = $datescol.">=".$from_ts;
12324 }
12325 if (!empty($ptodate)) {
12326 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12327 $clauses[] = $datescol."<=".$to_ts;
12328 }
12329 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12330 $q = "SELECT `c`.`id`,`c`.`first_name`,`c`.`last_name`,`c`.`email`,`c`.`phone`,`c`.`country`,`c`.`cfields`,`c`.`pin`,`c`.`ujid`,`c`.`address`,`c`.`city`,`c`.`zip`,`c`.`doctype`,`c`.`docnum`,`c`.`docimg`,`c`.`notes`,`c`.`ischannel`,`c`.`chdata`,`c`.`company`,`c`.`vat`,`c`.`gender`,`c`.`bdate`,`c`.`pbirth`,".
12331 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12332 "`cy`.`country_3_code`,`cy`.`country_name` ".
12333 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12334 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12335 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12336 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12337 GROUP BY `c`.`id`,`c`.`first_name`,`c`.`last_name`,`c`.`email`,`c`.`phone`,`c`.`country`,`c`.`cfields`,`c`.`pin`,`c`.`ujid`,`c`.`address`,`c`.`city`,`c`.`zip`,`c`.`doctype`,`c`.`docnum`,`c`.`docimg`,`c`.`notes`,`c`.`ischannel`,`c`.`chdata`,`c`.`company`,`c`.`vat`,`c`.`gender`,`c`.`bdate`,`c`.`pbirth`,`cy`.`country_3_code`,`cy`.`country_name` ".
12338 "ORDER BY `c`.`last_name` ASC;";
12339 $dbo->setQuery($q);
12340 $dbo->execute();
12341 if (!($dbo->getNumRows() > 0)) {
12342 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12343 $mainframe = JFactory::getApplication();
12344 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12345 exit;
12346 }
12347 $customers = $dbo->loadAssocList();
12348 $csvlines = array();
12349 $csvheadline = array('ID', JText::translate('VBCUSTOMERLASTNAME'), JText::translate('VBCUSTOMERFIRSTNAME'), JText::translate('VBCUSTOMEREMAIL'), JText::translate('VBCUSTOMERPHONE'), JText::translate('VBCUSTOMERADDRESS'), JText::translate('VBCUSTOMERCITY'), JText::translate('VBCUSTOMERZIP'), JText::translate('VBCUSTOMERCOUNTRY'), JText::translate('VBCUSTOMERTOTBOOKINGS'));
12350 if ($ppin > 0) {
12351 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12352 }
12353 if ($pscanimg > 0) {
12354 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12355 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12356 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12357 }
12358 if ($pnotes > 0) {
12359 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12360 }
12361 $csvlines[] = $csvheadline;
12362 foreach ($customers as $customer) {
12363 $csvcustomerline = array($customer['id'], $customer['last_name'], $customer['first_name'], $customer['email'], $customer['phone'], $customer['address'], $customer['city'], $customer['zip'], $customer['country_name'], $customer['tot_bookings']);
12364 if ($ppin > 0) {
12365 $csvcustomerline[] = $customer['pin'];
12366 }
12367 if ($pscanimg > 0) {
12368 $csvcustomerline[] = $customer['doctype'];
12369 $csvcustomerline[] = $customer['docnum'];
12370 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12371 }
12372 if ($pnotes > 0) {
12373 $csvcustomerline[] = $customer['notes'];
12374 }
12375 $csvlines[] = $csvcustomerline;
12376 }
12377 header("Content-type: text/csv");
12378 header("Cache-Control: no-store, no-cache");
12379 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12380 $outstream = fopen("php://output", 'w');
12381 foreach ($csvlines as $csvline) {
12382 fputcsv($outstream, $csvline);
12383 }
12384 fclose($outstream);
12385 exit;
12386 }
12387
12388 public function renewsession() {
12389 /*
12390 * @wponly
12391 * We just destroy the session
12392 */
12393 JSessionHandler::destroy();
12394 $mainframe = JFactory::getApplication();
12395 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12396 }
12397
12398 public function trackings() {
12399 VikBookingHelper::printHeader("trackings");
12400
12401 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12402
12403 parent::display();
12404
12405 if (VikBooking::showFooter()) {
12406 VikBookingHelper::printFooter();
12407 }
12408 }
12409
12410 public function trkconfig() {
12411 VikBookingHelper::printHeader("trackings");
12412
12413 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12414
12415 parent::display();
12416
12417 if (VikBooking::showFooter()) {
12418 VikBookingHelper::printFooter();
12419 }
12420 }
12421
12422 public function savetrkconfigstay() {
12423 if (!JSession::checkToken()) {
12424 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12425 }
12426 $this->do_savetrkconfig(true);
12427 }
12428
12429 public function savetrkconfig() {
12430 if (!JSession::checkToken()) {
12431 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12432 }
12433 $this->do_savetrkconfig();
12434 }
12435
12436 private function do_savetrkconfig($stay = false) {
12437 $dbo = JFactory::getDBO();
12438 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12439 $trkenabled = $trkenabled == 1 ? 1 : 0;
12440 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12441 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12442 $trkcampname = VikRequest::getVar('trkcampname', array());
12443 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12444 $trkcampval = VikRequest::getVar('trkcampval', array());
12445 $trkcampaigns = array();
12446 foreach ($trkcampname as $k => $v) {
12447 if (empty($trkcampkey[$k])) {
12448 continue;
12449 }
12450 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12451 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12452 $trkcampaigns[$trkcampkey[$k]] = array(
12453 'key' => $trkcampkey[$k],
12454 'value' => $trkcampval[$k],
12455 'name' => $name,
12456 );
12457 }
12458
12459 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12460 $dbo->setQuery($q);
12461 $dbo->execute();
12462 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12463 $dbo->setQuery($q);
12464 $dbo->execute();
12465 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12466 $dbo->setQuery($q);
12467 $dbo->execute();
12468
12469 $mainframe = JFactory::getApplication();
12470 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12471 }
12472
12473 public function modtracking() {
12474 $dbo = JFactory::getDbo();
12475 $cid = VikRequest::getVar('cid', array());
12476 foreach ($cid as $id) {
12477 if (!empty($id)) {
12478 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12479 $dbo->setQuery($q);
12480 $dbo->execute();
12481 if ($dbo->getNumRows()) {
12482 $data = $dbo->loadAssoc();
12483 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12484 $dbo->setQuery($q);
12485 $dbo->execute();
12486 }
12487 }
12488 }
12489 $mainframe = JFactory::getApplication();
12490 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12491 }
12492
12493 public function removetrackings()
12494 {
12495 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
12496 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
12497 }
12498
12499 $ids = VikRequest::getVar('cid', array());
12500 $dbo = JFactory::getDbo();
12501
12502 foreach ($ids as $d) {
12503 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12504 $dbo->setQuery($q);
12505 $dbo->execute();
12506 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12507 $dbo->setQuery($q);
12508 $dbo->execute();
12509 }
12510
12511 $mainframe = JFactory::getApplication();
12512 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12513 }
12514
12515 /**
12516 * Invokes the Tracker class to obtain
12517 * geo information about the IP addresses.
12518 * This task is called via ajax.
12519 *
12520 * @since 1.11
12521 */
12522 public function getgeoinfo() {
12523 $ips = VikRequest::getVar('ips', array());
12524 if (!count($ips)) {
12525 echo 'e4j.error.empty IPs';
12526 exit;
12527 }
12528
12529 // require the Tracker class without instantiating the object
12530 VikBooking::getTracker(true);
12531 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12532
12533 if ($geo_info === false) {
12534 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12535 exit;
12536 }
12537
12538 // update db values and compose response
12539 $dbo = JFactory::getDbo();
12540 $resp = array();
12541 foreach ($geo_info as $id => $geo) {
12542 if (is_null($geo) || $geo === false) {
12543 continue;
12544 }
12545 // compose geo info string
12546 $geovals = array();
12547 if (!empty($geo['city'])) {
12548 array_push($geovals, $geo['city']);
12549 }
12550 if (!empty($geo['region'])) {
12551 array_push($geovals, $geo['region']);
12552 }
12553 $threecode = '';
12554 $cname = '';
12555 if (!empty($geo['country'])) {
12556 // returned country is a 2-char code, get the 3-char country code
12557 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12558 $dbo->setQuery($q);
12559 $dbo->execute();
12560 if ($dbo->getNumRows()) {
12561 $cinfo = $dbo->loadAssoc();
12562 $threecode = $cinfo['country_3_code'];
12563 $cname = $cinfo['country_name'];
12564 }
12565 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12566 }
12567
12568 // full geo information string
12569 $geoinfostr = implode(', ', $geovals);
12570
12571 // push data to the response pool
12572 $resp[$id] = array();
12573 $resp[$id]['geo'] = $geoinfostr;
12574 if (!empty($cname)) {
12575 $resp[$id]['country'] = $cname;
12576 }
12577 if (!empty($threecode)) {
12578 $resp[$id]['country3'] = $threecode;
12579 }
12580
12581 // update main tracking record
12582 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12583 $dbo->setQuery($q);
12584 $dbo->execute();
12585 }
12586
12587 // output the JSON response
12588 echo json_encode($resp);
12589 exit;
12590 }
12591
12592 /**
12593 * Counts the orphan dates for all published rooms
12594 * depending on their restrictions and booked dates.
12595 * By default, the task takes up to 3 months ahead.
12596 * It is possible to filter the request by rooms and months.
12597 * This task should be called via ajax.
12598 *
12599 * @since 1.11
12600 */
12601 public function orphanscount()
12602 {
12603 $dbo = JFactory::getDbo();
12604 $orphans = array();
12605
12606 $nowdf = VikBooking::getDateFormat();
12607 if ($nowdf == "%d/%m/%Y") {
12608 $df = 'd/m/Y';
12609 } elseif ($nowdf == "%m/%d/%Y") {
12610 $df = 'm/d/Y';
12611 } else {
12612 $df = 'Y/m/d';
12613 }
12614
12615 // global min los
12616 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12617 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12618
12619 // rooms and dates
12620 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12621 $months = VikRequest::getInt('months', 3, 'request');
12622 $from = VikRequest::getString('from', '', 'request');
12623 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12624 if (!empty($from)) {
12625 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12626 if (!empty($fromts)) {
12627 // custom starting date
12628 $today = $fromts;
12629 }
12630 }
12631 $until = strtotime("+{$months} months", $today);
12632
12633 // load all rooms
12634 $rooms = array();
12635 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12636 $dbo->setQuery($q);
12637 $dbo->execute();
12638 if ($dbo->getNumRows()) {
12639 $allrooms = $dbo->loadAssocList();
12640 foreach ($allrooms as $r) {
12641 $rooms[$r['id']] = $r;
12642 }
12643 }
12644 if (!count($rooms)) {
12645 // no rooms found, exit
12646 echo json_encode($orphans);
12647 exit;
12648 }
12649
12650 // load availabilities
12651 $q = "SELECT `b`.*,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`idroom` IN (".implode(', ', array_keys($rooms)).") AND `b`.`id`=`ob`.`idbusy` AND (`b`.`checkin`>=".$today." OR `b`.`checkout`>=".$today.") AND (`b`.`checkin`<=".$until." OR `b`.`checkout`<=".$today.");";
12652 $dbo->setQuery($q);
12653 $dbo->execute();
12654 if (!$dbo->getNumRows()) {
12655 // no booked dates found, exit
12656 echo json_encode($orphans);
12657 exit;
12658 }
12659 $busy = $dbo->loadAssocList();
12660
12661 // sort booked dates by room id
12662 $rooms_busy = array();
12663 foreach ($busy as $b) {
12664 if (!isset($rooms_busy[$b['idroom']])) {
12665 $rooms_busy[$b['idroom']] = array();
12666 }
12667 array_push($rooms_busy[$b['idroom']], $b);
12668 }
12669
12670 // load restrictions
12671 $rooms_restr = array();
12672 foreach ($rooms as $rid => $r) {
12673 $restrictions = VikBooking::loadRestrictions(true, array($rid));
12674 if (count($restrictions)) {
12675 $rooms_restr[$rid] = $restrictions;
12676 }
12677 }
12678 if (!count($rooms_restr) && $glob_minlos < 2) {
12679 // no restrictions found and minlos=1, exit
12680 echo json_encode($orphans);
12681 exit;
12682 }
12683
12684 // count availability and minlos per day
12685 $rooms_data = array();
12686 foreach ($rooms as $rid => $r) {
12687 $rooms_data[$rid] = array(
12688 'avail' => array(),
12689 'restr' => array()
12690 );
12691 $nowts = getdate($today);
12692 while ($nowts[0] <= $until) {
12693 $dateind = date('Y-m-d', $nowts[0]);
12694
12695 // remaining availability
12696 if (!isset($rooms_busy[$rid])) {
12697 // no bookings for this room, set full availability for this day
12698 $rooms_data[$rid]['avail'][] = array(
12699 'dt' => $dateind,
12700 'units' => $r['units']
12701 );
12702 } else {
12703 // check remaining availability for this day
12704 $totfound = 0;
12705 foreach ($rooms_busy[$rid] as $b) {
12706 $tmpone = getdate($b['checkin']);
12707 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
12708 $ritts = strtotime($rit);
12709 $tmptwo = getdate($b['checkout']);
12710 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
12711 $conts = strtotime($con);
12712 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
12713 $totfound++;
12714 }
12715 }
12716 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
12717 $rooms_data[$rid]['avail'][] = array(
12718 'dt' => $dateind,
12719 'units' => ($r['units'] - $totfound)
12720 );
12721 }
12722
12723 // restrictions
12724 if (!isset($rooms_restr[$rid])) {
12725 // no restrictions for this room, set global minlos for this day
12726 $rooms_data[$rid]['restr'][] = array(
12727 'dt' => $dateind,
12728 'minlos' => $glob_minlos
12729 );
12730 } else {
12731 // get restriction for this day
12732 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
12733 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12734
12735 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
12736 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
12737
12738 $rooms_data[$rid]['restr'][] = array(
12739 'dt' => $dateind,
12740 'minlos' => $minlos
12741 );
12742 }
12743
12744 // next loop
12745 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12746 $nowts = getdate($dayts);
12747 }
12748 }
12749
12750 // week days and months labels
12751 $days_labels = array(
12752 JText::translate('VBSUNDAY'),
12753 JText::translate('VBMONDAY'),
12754 JText::translate('VBTUESDAY'),
12755 JText::translate('VBWEDNESDAY'),
12756 JText::translate('VBTHURSDAY'),
12757 JText::translate('VBFRIDAY'),
12758 JText::translate('VBSATURDAY')
12759 );
12760 $months_labels = array(
12761 JText::translate('VBMONTHONE'),
12762 JText::translate('VBMONTHTWO'),
12763 JText::translate('VBMONTHTHREE'),
12764 JText::translate('VBMONTHFOUR'),
12765 JText::translate('VBMONTHFIVE'),
12766 JText::translate('VBMONTHSIX'),
12767 JText::translate('VBMONTHSEVEN'),
12768 JText::translate('VBMONTHEIGHT'),
12769 JText::translate('VBMONTHNINE'),
12770 JText::translate('VBMONTHTEN'),
12771 JText::translate('VBMONTHELEVEN'),
12772 JText::translate('VBMONTHTWELVE')
12773 );
12774
12775 // orphan dates calculation method
12776 $calc_method = VikBooking::orphansCalculation();
12777
12778 // parse data and build orphans if any
12779 foreach ($rooms_data as $rid => $data) {
12780 foreach ($data['avail'] as $ind => $av) {
12781 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
12782 // continue, no restriction set or no availability for this day
12783 continue;
12784 }
12785 if ($data['restr'][$ind]['minlos'] < 2) {
12786 // continue, no min los > 1 set for this day
12787 continue;
12788 }
12789 // check if any night after today, until min los, is fully booked
12790 $hasorphans = false;
12791 $forward_count = 0;
12792 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
12793 if (!isset($data['avail'][($ind + $i)])) {
12794 // break loop, no info for this day after
12795 break;
12796 }
12797 if ($data['avail'][($ind + $i)]['units'] > 0) {
12798 // continue, availability found for tomorrow, we need a non available next-day
12799 continue;
12800 }
12801 // orphan found
12802 $hasorphans = true;
12803 $forward_count = $i;
12804 break;
12805 }
12806
12807 /**
12808 * Backward calculation method only if "prevnext".
12809 *
12810 * @since 1.3.0
12811 */
12812 $backward_count = 0;
12813 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
12814 if (!isset($data['avail'][($ind - $i)])) {
12815 // break loop, no info for this prev day
12816 break;
12817 }
12818 if ($data['avail'][($ind - $i)]['units'] > 0) {
12819 // increase free nights going backward
12820 $backward_count++;
12821 }
12822 }
12823 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
12824 // this should not be an orphan date because of enough free days back, or enough free days in between
12825 $hasorphans = false;
12826 }
12827 //
12828
12829 if ($hasorphans) {
12830 // we pass the name of the room, the list of raw dates (Y-m-d), the list of readable dates, and the fist date with the VBO format
12831 if (!isset($orphans[$rid])) {
12832 $orphans[$rid] = array(
12833 'name' => $rooms[$rid]['name'],
12834 'dates' => array(),
12835 'rdates' => array(),
12836 'linkd' => date($df, strtotime($av['dt']))
12837 );
12838 }
12839 array_push($orphans[$rid]['dates'], $av['dt']);
12840 // build the value for the readable date
12841 $dtinfo = getdate(strtotime($av['dt']));
12842 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
12843 array_push($orphans[$rid]['rdates'], $rdate);
12844 }
12845 }
12846 }
12847
12848 // output response
12849 echo json_encode($orphans);
12850 exit;
12851 }
12852
12853 public function tableaux() {
12854 VikBookingHelper::printHeader("tableaux");
12855
12856 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
12857
12858 parent::display();
12859
12860 if (VikBooking::showFooter()) {
12861 VikBookingHelper::printFooter();
12862 }
12863 }
12864
12865 public function operators() {
12866 VikBookingHelper::printHeader("operators");
12867
12868 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
12869
12870 parent::display();
12871
12872 if (VikBooking::showFooter()) {
12873 VikBookingHelper::printFooter();
12874 }
12875 }
12876
12877 public function newoperator() {
12878 VikBookingHelper::printHeader("operators");
12879
12880 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12881
12882 parent::display();
12883
12884 if (VikBooking::showFooter()) {
12885 VikBookingHelper::printFooter();
12886 }
12887 }
12888
12889 public function editoperator() {
12890 VikBookingHelper::printHeader("operators");
12891
12892 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12893
12894 parent::display();
12895
12896 if (VikBooking::showFooter()) {
12897 VikBookingHelper::printFooter();
12898 }
12899 }
12900
12901 public function updateoperator()
12902 {
12903 if (!JSession::checkToken()) {
12904 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12905 }
12906
12907 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
12908 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
12909 }
12910
12911 $this->do_updateoperator();
12912 }
12913
12914 public function updateoperatorstay()
12915 {
12916 if (!JSession::checkToken()) {
12917 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12918 }
12919
12920 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
12921 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
12922 }
12923
12924 $this->do_updateoperator(true);
12925 }
12926
12927 private function do_updateoperator($stay = false)
12928 {
12929 $dbo = JFactory::getDbo();
12930 $app = JFactory::getApplication();
12931 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12932 $plast_name = VikRequest::getString('last_name', '', 'request');
12933 $pemail = VikRequest::getString('email', '', 'request');
12934 $pphone = VikRequest::getString('phone', '', 'request');
12935 $pcode = VikRequest::getString('code', '', 'request');
12936 $pujid = VikRequest::getInt('ujid', '', 'request');
12937 $pwhere = VikRequest::getInt('where', '', 'request');
12938
12939 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12940 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
12941 $dbo->setQuery($q);
12942 $customer = $dbo->loadAssoc();
12943 if (!$customer) {
12944 $app->redirect("index.php?option=com_vikbooking&task=operators");
12945 exit;
12946 }
12947
12948 $q = "SELECT * FROM `#__vikbooking_operators` WHERE (`email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid)).") AND `id`!=".(int)$pwhere." LIMIT 1;";
12949 $dbo->setQuery($q);
12950 $ex_operator = $dbo->loadAssoc();
12951 if (!$ex_operator) {
12952 // update fingerprint for the operator
12953 $fingpt = md5($pwhere . $pemail);
12954
12955 /**
12956 * Operator profile picture (URL or uploaded file).
12957 *
12958 * @since 1.16.9 (J) - 1.6.9 (WP)
12959 */
12960 $operator_pic = VikRequest::getString('pic', '', 'request');
12961 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
12962 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
12963 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
12964 $src = $operator_pic_img['tmp_name'];
12965 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
12966 $j = "";
12967 if (is_file($dest.$filename)) {
12968 $j = rand(1, 99999);
12969 while (is_file($dest . $j .$filename)) {
12970 $j++;
12971 }
12972 }
12973 $finaldest = $dest . $j . $filename;
12974 $check = getimagesize($operator_pic_img['tmp_name']);
12975 if (($check[2] & imagetypes())) {
12976 if (VikBooking::uploadFile($src, $finaldest)) {
12977 $operator_pic = $j . $filename;
12978 } else {
12979 VikError::raiseWarning('', 'Error while uploading image');
12980 }
12981 } else {
12982 VikError::raiseWarning('', 'Uploaded file is not an Image');
12983 }
12984 }
12985
12986 // update record
12987 $q = "UPDATE `#__vikbooking_operators` SET `first_name`=" . $dbo->q($pfirst_name) . ",`last_name`=" . $dbo->q($plast_name) . ",`email`=" . $dbo->q($pemail) . ",`phone`=" . $dbo->q($pphone) . ",`code`=" . $dbo->q($pcode) . ",`ujid`=" . $dbo->q($pujid) . ",`fingpt`=" . $dbo->q($fingpt) . ",`pic`=" . $dbo->q($operator_pic) . " WHERE `id`=" . (int)$pwhere;
12988 $dbo->setQuery($q);
12989 $dbo->execute();
12990 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12991 } else {
12992 //email already exists
12993 VikError::raiseWarning('', JText::translate('VBERROPERATOREXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editoperator&cid[]='.$ex_operator['id'].'" target="_blank">'.$ex_operator['first_name'].' '.$ex_operator['last_name'].'</a>');
12994 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12995 exit;
12996 }
12997 } else {
12998 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12999 }
13000
13001 if ($stay) {
13002 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13003 } else {
13004 $app->redirect("index.php?option=com_vikbooking&task=operators");
13005 }
13006
13007 $app->close();
13008 }
13009
13010 public function saveoperator()
13011 {
13012 if (!JSession::checkToken()) {
13013 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13014 }
13015
13016 $dbo = JFactory::getDbo();
13017 $app = JFactory::getApplication();
13018 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13019 $plast_name = VikRequest::getString('last_name', '', 'request');
13020 $pemail = VikRequest::getString('email', '', 'request');
13021 $pphone = VikRequest::getString('phone', '', 'request');
13022 $pcode = VikRequest::getString('code', '', 'request');
13023 $pujid = VikRequest::getInt('ujid', '', 'request');
13024
13025 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
13026 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
13027 $dbo->setQuery($q);
13028 $ex_operator = $dbo->loadAssoc();
13029 if (!$ex_operator) {
13030 /**
13031 * Operator profile picture (URL or uploaded file).
13032 *
13033 * @since 1.16.9 (J) - 1.6.9 (WP)
13034 */
13035 $operator_pic = VikRequest::getString('pic', '', 'request');
13036 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13037 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13038 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13039 $src = $operator_pic_img['tmp_name'];
13040 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13041 $j = "";
13042 if (is_file($dest.$filename)) {
13043 $j = rand(1, 99999);
13044 while (is_file($dest . $j .$filename)) {
13045 $j++;
13046 }
13047 }
13048 $finaldest = $dest . $j . $filename;
13049 $check = getimagesize($operator_pic_img['tmp_name']);
13050 if (($check[2] & imagetypes())) {
13051 if (VikBooking::uploadFile($src, $finaldest)) {
13052 $operator_pic = $j . $filename;
13053 } else {
13054 VikError::raiseWarning('', 'Error while uploading image');
13055 }
13056 } else {
13057 VikError::raiseWarning('', 'Uploaded file is not an Image');
13058 }
13059 }
13060
13061 $q = "INSERT INTO `#__vikbooking_operators` (`first_name`,`last_name`,`email`,`phone`,`code`,`ujid`,`pic`) VALUES(" . $dbo->q($pfirst_name) . ", " . $dbo->q($plast_name) . ", " . $dbo->q($pemail) . ", " . $dbo->q($pphone) . ", " . $dbo->q($pcode) . ", " . $dbo->q($pujid) . ", " . $dbo->q($operator_pic) . ");";
13062 $dbo->setQuery($q);
13063 $dbo->execute();
13064 $lid = $dbo->insertid();
13065 if (!empty($lid)) {
13066 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13067 // generate fingerprint for the operator
13068 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->q(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
13069 $dbo->setQuery($q);
13070 $dbo->execute();
13071 }
13072 } else {
13073 // email already exists
13074 VikError::raiseWarning('', JText::translate('VBERROPERATOREXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editoperator&cid[]='.$ex_operator['id'].'" target="_blank">'.$ex_operator['first_name'].' '.$ex_operator['last_name'].'</a>');
13075 }
13076 } else {
13077 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13078 }
13079
13080 $app->redirect("index.php?option=com_vikbooking&task=operators");
13081 $app->close();
13082 }
13083
13084 public function removeoperators()
13085 {
13086 if (!JSession::checkToken()) {
13087 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13088 }
13089
13090 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13091 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13092 }
13093
13094 $ids = VikRequest::getVar('cid', array(0));
13095 if ($ids) {
13096 $dbo = JFactory::getDBO();
13097 foreach ($ids as $d) {
13098 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
13099 $dbo->setQuery($q);
13100 $dbo->execute();
13101 }
13102 }
13103 $mainframe = JFactory::getApplication();
13104 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13105 }
13106
13107 public function canceloperator() {
13108 $mainframe = JFactory::getApplication();
13109 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13110 }
13111
13112 public function cancelcrons() {
13113 $mainframe = JFactory::getApplication();
13114 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
13115 }
13116
13117 public function cancelpackages() {
13118 $mainframe = JFactory::getApplication();
13119 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
13120 }
13121
13122 public function cancelcustomer() {
13123 $mainframe = JFactory::getApplication();
13124 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13125 if (!empty($pgoto)) {
13126 $mainframe->redirect(base64_decode($pgoto));
13127 exit;
13128 }
13129 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
13130 }
13131
13132 public function cancelbusyvcm() {
13133 $mainframe = JFactory::getApplication();
13134 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
13135 }
13136
13137 public function cancelrestriction() {
13138 $mainframe = JFactory::getApplication();
13139 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
13140 }
13141
13142 public function cancelcoupon() {
13143 $mainframe = JFactory::getApplication();
13144 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
13145 }
13146
13147 public function cancelcustomf() {
13148 $mainframe = JFactory::getApplication();
13149 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
13150 }
13151
13152 public function cancelpayment() {
13153 $mainframe = JFactory::getApplication();
13154 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
13155 }
13156
13157 public function cancelseason() {
13158 $mainframe = JFactory::getApplication();
13159 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
13160 }
13161
13162 public function goconfig() {
13163 $mainframe = JFactory::getApplication();
13164 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
13165 }
13166
13167 public function canceledorder() {
13168 $pgoto = VikRequest::getString('goto', 'orders', 'request');
13169 $mainframe = JFactory::getApplication();
13170 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
13171 }
13172
13173 public function cancelbusy() {
13174 $pidorder = VikRequest::getString('idorder', '', 'request');
13175 $pgoto = VikRequest::getString('goto', '', 'request');
13176 $mainframe = JFactory::getApplication();
13177 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
13178 }
13179
13180 public function canceloverv() {
13181 $mainframe = JFactory::getApplication();
13182 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
13183 }
13184
13185 public function canceltableaux() {
13186 $mainframe = JFactory::getApplication();
13187 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
13188 }
13189
13190 public function cancelcalendar() {
13191 $pidroom = VikRequest::getString('idroom', '', 'request');
13192 $mainframe = JFactory::getApplication();
13193 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
13194 }
13195
13196 public function canceloptionals() {
13197 $mainframe = JFactory::getApplication();
13198 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
13199 }
13200
13201 public function cancel() {
13202 $mainframe = JFactory::getApplication();
13203 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
13204 }
13205
13206 public function cancelcarat() {
13207 $mainframe = JFactory::getApplication();
13208 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
13209 }
13210
13211 public function cancelcat() {
13212 $mainframe = JFactory::getApplication();
13213 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
13214 }
13215
13216 public function cancelprice() {
13217 $mainframe = JFactory::getApplication();
13218 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
13219 }
13220
13221 public function canceliva() {
13222 $mainframe = JFactory::getApplication();
13223 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
13224 }
13225
13226 public function canceltrk() {
13227 $mainframe = JFactory::getApplication();
13228 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13229 }
13230
13231 public function canceldash() {
13232 $mainframe = JFactory::getApplication();
13233 $mainframe->redirect("index.php?option=com_vikbooking");
13234 }
13235
13236 public function cancelinvoice() {
13237 $mainframe = JFactory::getApplication();
13238 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13239 if (!empty($pgoto)) {
13240 $mainframe->redirect(base64_decode($pgoto));
13241 exit;
13242 }
13243 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
13244 }
13245
13246 /**
13247 * AJAX upload the customer documents.
13248 *
13249 * @return void
13250 *
13251 * @throws Exception
13252 */
13253 public function upload_customer_document()
13254 {
13255 $input = JFactory::getApplication()->input;
13256 $dbo = JFactory::getDbo();
13257
13258 $customer_id = $input->getUint('customer', 0);
13259
13260 $result = new stdClass;
13261 $result->status = 0;
13262
13263 try
13264 {
13265 $q = $dbo->getQuery(true)
13266 ->select($dbo->qn(array(
13267 'id',
13268 'first_name',
13269 'last_name',
13270 'email',
13271 'docsfolder',
13272 )))
13273 ->from($dbo->qn('#__vikbooking_customers'))
13274 ->where($dbo->qn('id') . ' = ' . $customer_id);
13275
13276 $dbo->setQuery($q, 0, 1);
13277 $dbo->execute();
13278
13279 if (!$dbo->getNumRows())
13280 {
13281 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13282 }
13283
13284 $customer = $dbo->loadObject();
13285
13286 // fetch documents folder path
13287 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13288
13289 // check if we have a valid directory
13290 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
13291 {
13292 // randomize string
13293 $customer->seed = uniqid();
13294
13295 // create blocks for hashed folder
13296 $parts = [
13297 $customer->first_name,
13298 $customer->last_name,
13299 md5(serialize($customer)),
13300 ];
13301
13302 // join fetched parts
13303 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13304
13305 if (strlen($customer->docsfolder) < 16)
13306 {
13307 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13308 }
13309
13310 jimport('joomla.filesystem.folder');
13311
13312 // create a folder for this customer
13313 $created = JFolder::create($dirpath . $customer->docsfolder);
13314
13315 if (!$created)
13316 {
13317 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13318 }
13319
13320 unset($customer->seed);
13321
13322 // update docs folder
13323 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13324 }
13325
13326 // get file from request
13327 $file = $input->files->get('file', array(), 'array');
13328
13329 // try to upload the file
13330 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13331 $result->status = 1;
13332
13333 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13334 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13335 }
13336 catch (Exception $e)
13337 {
13338 $result->error = $e->getMessage();
13339 $result->code = $e->getCode();
13340 }
13341
13342 echo json_encode($result);
13343 exit;
13344 }
13345
13346 /**
13347 * AJAX delete the customer documents.
13348 *
13349 * @return void
13350 *
13351 * @throws Exception
13352 */
13353 public function delete_customer_document()
13354 {
13355 $input = JFactory::getApplication()->input;
13356 $dbo = JFactory::getDbo();
13357
13358 $customer_id = $input->getUint('customer', 0);
13359
13360 $result = new stdClass;
13361 $result->status = 0;
13362
13363 $q = $dbo->getQuery(true)
13364 ->select($dbo->qn('docsfolder'))
13365 ->from($dbo->qn('#__vikbooking_customers'))
13366 ->where($dbo->qn('id') . ' = ' . $customer_id);
13367
13368 $dbo->setQuery($q, 0, 1);
13369 $dbo->execute();
13370
13371 if (!$dbo->getNumRows())
13372 {
13373 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13374 }
13375
13376 $folder = $dbo->loadResult();
13377
13378 if (!$folder)
13379 {
13380 throw new Exception('The customer does not have any documents', 500);
13381 }
13382
13383 $file = $input->getString('file');
13384
13385 if (!$file)
13386 {
13387 throw new Exception('File to remove not specified', 400);
13388 }
13389
13390 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13391
13392 if (!is_file($path))
13393 {
13394 throw new Exception(sprintf('File [%s] not found', $path), 404);
13395 }
13396
13397 jimport('joomla.filesystem.file');
13398
13399 $removed = JFile::delete($path);
13400
13401 echo json_encode(array('status' => (int) $removed));
13402 exit;
13403 }
13404
13405 /**
13406 * AJAX task to invoke a specific report and obtain information.
13407 *
13408 * @since 1.3.0
13409 */
13410 public function get_report_data()
13411 {
13412 $report_name = VikRequest::getString('report_name', '', 'request');
13413 $current_fest = VikRequest::getString('current_fest', '', 'request');
13414 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13415 $current_todate = VikRequest::getString('current_todate', '', 'request');
13416 $step = VikRequest::getString('step', 'weekend', 'request');
13417 $direction = VikRequest::getString('direction', 'load', 'request');
13418 $period = VikRequest::getString('period', 'full', 'request');
13419 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13420 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13421 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13422 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13423 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13424 // idroom can be an array of IDs or just one ID as int/string
13425 $idroom = VikRequest::getVar('idroom', null, 'request');
13426 //
13427
13428 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13429 throw new Exception("Missing request data", 400);
13430 }
13431
13432 // get requested report instance
13433 $report = VikBooking::getReportInstance($report_name);
13434 if (!$report) {
13435 throw new Exception("Report not found", 404);
13436 }
13437
13438 // chart data
13439 if (empty($chart_datatype)) {
13440 $chart_datatype = array(
13441 'type' => 'doughnut',
13442 'depth' => 1,
13443 'keys' => array($krsort),
13444 );
13445 }
13446
13447 // website date format
13448 $df = $report->getDateFormat();
13449
13450 // prepare request params for the report
13451 $rparams = array(
13452 'fromdate' => $current_fromdate,
13453 'todate' => $current_todate,
13454 'period' => $period,
13455 'krsort' => $krsort,
13456 'krorder' => $krorder,
13457 'idroom' => $idroom,
13458 );
13459
13460 // starting dates info and timestamps
13461 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13462 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13463 $from_info = getdate($from_ts);
13464 $to_info = getdate($to_ts);
13465
13466 // the name of the period requested and whether it's a fest
13467 $period_name = '';
13468 $is_fest = null;
13469
13470 if ($direction == 'prev' || $direction == 'next') {
13471 // calculate prev or next dates
13472 if ($step == 'weekend') {
13473 $period_name = JText::translate('VBOWEEKND');
13474 if ($direction == 'next') {
13475 // next weekend from current end date
13476 $next_ts = strtotime("next friday", $to_ts);
13477 } else {
13478 // prev weekend from current start date
13479 $next_ts = strtotime("previous friday", $from_ts);
13480 }
13481 $next_info = getdate($next_ts);
13482 $new_from_ts = $next_ts;
13483 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13484 $rparams['fromdate'] = date($df, $new_from_ts);
13485 $rparams['todate'] = date($df, $new_to_ts);
13486 } elseif ($step == 'week') {
13487 $period_name = JText::translate('VBOWEEK');
13488 if ($direction == 'next') {
13489 // start next week from the current end date
13490 $new_from_ts = $to_ts;
13491 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13492 $rparams['fromdate'] = $rparams['todate'];
13493 $rparams['todate'] = date($df, $new_to_ts);
13494 } else {
13495 // end prev week from the current from date
13496 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13497 $new_to_ts = $from_ts;
13498 $rparams['todate'] = $rparams['fromdate'];
13499 $rparams['fromdate'] = date($df, $new_from_ts);
13500 }
13501 } else {
13502 // month
13503 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13504 if ($direction == 'next') {
13505 // next month from the current from date
13506 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13507 $new_from_ts = $nextmonts;
13508 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13509 $rparams['fromdate'] = date($df, $new_from_ts);
13510 $rparams['todate'] = date($df, $new_to_ts);
13511 } else {
13512 // prev month from the current from date
13513 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13514 $new_from_ts = $nextmonts;
13515 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13516 $rparams['fromdate'] = date($df, $new_from_ts);
13517 $rparams['todate'] = date($df, $new_to_ts);
13518 }
13519 }
13520
13521 // get the next festivities
13522 $fests = VikBooking::getFestivitiesInstance();
13523 $next_fests = $fests->loadFestDates();
13524 if (count($next_fests)) {
13525 // check whether a festivity should be displayed rather than the calculated period of dates
13526 foreach ($next_fests as $fest) {
13527 $fest_found = false;
13528 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13529 $fest_found = true;
13530 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13531 $fest_found = true;
13532 }
13533 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13534 // festivity found before next calculated period
13535 $is_fest = $fest['festinfo'][0]->next_ts;
13536 $period_name = $fest['festinfo'][0]->trans_name;
13537 $new_from_ts = $fest['festinfo'][0]->from_ts;
13538 $new_to_ts = $fest['festinfo'][0]->to_ts;
13539 $rparams['fromdate'] = date($df, $new_from_ts);
13540 $rparams['todate'] = date($df, $new_to_ts);
13541 break;
13542 }
13543 }
13544 }
13545 } else {
13546 // load requested dates by skipping the festivities
13547 $new_from_ts = $from_ts;
13548 $new_to_ts = $to_ts;
13549 }
13550
13551 // invoke report
13552 $report->injectParams($rparams);
13553 $report_values = $report->getReportValues(1);
13554 $report_cols = $report->getColumnsValues();
13555 $report_chart = null;
13556 $report_chart_metas = array();
13557 $chart_meta_data = array(
13558 'keys' => array(
13559 'occupancy',
13560 'tot_bookings',
13561 'nights_booked',
13562 ),
13563 );
13564 $error = null;
13565
13566 if (!count($report_values)) {
13567 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13568 } else {
13569 // get doughnut Chart for the requested key
13570 $report_chart = $report->getChart($chart_datatype);
13571
13572 // get Chart meta data
13573 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13574 if (count($all_chart_metas)) {
13575 // merge all positions into one array
13576 foreach ($all_chart_metas as $pos_metas) {
13577 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13578 }
13579 }
13580
13581 if (empty($period_name)) {
13582 $period_name = $report->getProperty('chartTitle');
13583 }
13584 }
13585
13586 // build response
13587 $response = new stdClass;
13588 $response->error = $error;
13589 $response->fromdate = $rparams['fromdate'];
13590 $response->todate = $rparams['todate'];
13591 $response->in_days = $report->countDaysTo($new_from_ts);
13592 $response->in_days_to = $report->countDaysTo($new_to_ts);
13593 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13594 $response->period_name = $period_name;
13595 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13596 $response->is_fest = $is_fest;
13597 $response->report_chart = $report_chart;
13598 $response->report_cols = $report_cols;
13599 $response->report_values = $report_values;
13600 $response->report_script = $report->getScript();
13601 $response->chart_labels = $report->getProperty('chartJsLabels');
13602 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13603 $response->chart_colors = $report->getProperty('chartJsColors');
13604 $response->chart_data = $report->getProperty('chartJsData');
13605 $response->report_chart_metas = $report_chart_metas;
13606
13607 echo json_encode($response);
13608 exit;
13609 }
13610
13611 /**
13612 * Go to the previous booking.
13613 *
13614 * @uses navigateToBooking()
13615 *
13616 * @since 1.3.0
13617 */
13618 public function prev_booking()
13619 {
13620 $this->navigateToBooking('prev');
13621 }
13622
13623 /**
13624 * Go to the next booking.
13625 *
13626 * @uses navigateToBooking()
13627 *
13628 * @since 1.3.0
13629 */
13630 public function next_booking()
13631 {
13632 $this->navigateToBooking('next');
13633 }
13634
13635 /**
13636 * Given the current booking ID in the request, we navigate
13637 * either to the next or to the previous reservation (if any).
13638 *
13639 * @param string $direction either next or prev.
13640 *
13641 * @return void
13642 *
13643 * @since 1.3.0
13644 */
13645 private function navigateToBooking($direction = 'next')
13646 {
13647 $bid = VikRequest::getInt('whereup', 0, 'request');
13648 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13649 throw new Exception("Invalid request", 400);
13650 }
13651
13652 $dbo = JFactory::getDbo();
13653 $app = JFactory::getApplication();
13654
13655 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13656 $dbo->setQuery($q, 0, 1);
13657 $dbo->execute();
13658 if (!$dbo->getNumRows()) {
13659 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13660 $app->redirect("index.php?option=com_vikbooking&task=orders");
13661 exit;
13662 }
13663
13664 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
13665 exit;
13666 }
13667
13668 /**
13669 * AJAX request: from a list of reservation IDs, we return the ones
13670 * that have a review with the related review ID on VCM.
13671 *
13672 * @since 1.13
13673 */
13674 public function bookings_have_reviews()
13675 {
13676 if (!JSession::checkToken()) {
13677 // missing CSRF-proof token
13678 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13679 }
13680
13681 $dbo = JFactory::getDbo();
13682
13683 $bids = VikRequest::getVar('bids', [], 'request', 'array');
13684 $vcm_installed = class_exists('VikChannelManager');
13685 $withreviews = [];
13686
13687 if ($vcm_installed && $bids) {
13688 $bids = array_filter(array_map('intval', (array) $bids));
13689 $bids = $bids ?: [0];
13690
13691 try {
13692 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
13693 $dbo->setQuery($q);
13694 $reviews = $dbo->loadAssocList();
13695
13696 foreach ($reviews as $r) {
13697 $withreviews[$r['idorder']] = $r['id'];
13698 }
13699 } catch (Exception $e) {
13700 // do nothing, outdated version
13701 }
13702 }
13703
13704 // output list of booking IDs found, if any
13705 VBOHttpDocument::getInstance()->json($withreviews);
13706 }
13707
13708 /**
13709 * AJAX request for adding a new room-day note.
13710 *
13711 * @return void
13712 *
13713 * @since 1.13.5
13714 */
13715 public function add_roomdaynote()
13716 {
13717 $dt = VikRequest::getString('dt', '', 'request');
13718 $idroom = VikRequest::getInt('idroom', 0, 'request');
13719 $subunit = VikRequest::getInt('subunit', 0, 'request');
13720 $type = VikRequest::getString('type', '', 'request');
13721 $type = empty($type) ? 'custom' : $type;
13722 $name = VikRequest::getString('name', '', 'request');
13723 $descr = VikRequest::getString('descr', '', 'request');
13724 $cdays = VikRequest::getInt('cdays', 0, 'request');
13725 $cdays = $cdays < 0 ? 0 : $cdays;
13726 $cdays = $cdays > 365 ? 365 : $cdays;
13727 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
13728 echo 'e4j.error.1';
13729 exit;
13730 }
13731
13732 // reload end date
13733 $end_date = $dt;
13734
13735 // build critical date object
13736 $new_note = array(
13737 'name' => $name,
13738 'type' => $type,
13739 'descr' => $descr,
13740 );
13741
13742 // get object
13743 $notes = VikBooking::getCriticalDatesInstance();
13744
13745 // store the notes for all consecutive dates
13746 for ($i = 0; $i <= $cdays; $i++) {
13747 $store_dt = $dt;
13748 if ($i > 0) {
13749 $dt_info = getdate(strtotime($store_dt));
13750 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
13751 $end_date = $store_dt;
13752 }
13753 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
13754 if (!$result) {
13755 echo 'e4j.error.2';
13756 exit;
13757 }
13758 }
13759
13760 // reload all room day notes for this day for the AJAX response
13761 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
13762
13763 if (!$all_notes || !count($all_notes)) {
13764 // no notes found even after storing it
13765 echo 'e4j.error.3';
13766 exit;
13767 }
13768
13769 echo json_encode($all_notes);
13770 exit;
13771 }
13772
13773 /**
13774 * AJAX request for removing a room day note.
13775 *
13776 * @return void
13777 *
13778 * @since 1.13.5
13779 */
13780 public function remove_roomdaynote()
13781 {
13782 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13783 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13784 }
13785
13786 $dt = VikRequest::getString('dt', '', 'request');
13787 $idroom = VikRequest::getInt('idroom', 0, 'request');
13788 $subunit = VikRequest::getInt('subunit', 0, 'request');
13789 $type = VikRequest::getString('type', '', 'request');
13790 $type = empty($type) ? 'custom' : $type;
13791 $ind = VikRequest::getInt('ind', 0, 'request');
13792 if (empty($dt) || !strtotime($dt)) {
13793 echo 'e4j.error.1';
13794 exit;
13795 }
13796
13797 $notes = VikBooking::getCriticalDatesInstance();
13798 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
13799 if (!$result) {
13800 echo 'e4j.error.2';
13801 exit;
13802 }
13803
13804 echo 'e4j.ok';
13805 exit;
13806 }
13807
13808 /**
13809 * AJAX request for storing an event for a booking.
13810 * Firstly developed for the VCM Reporting API - Guest Misconduct,
13811 * but it can be used for any other purpose.
13812 *
13813 * @return void
13814 *
13815 * @since 1.13.5
13816 */
13817 public function store_booking_history_event()
13818 {
13819 $bid = VikRequest::getInt('bid', 0, 'request');
13820 $event = VikRequest::getString('event', '', 'request');
13821 $descr = VikRequest::getString('descr', '', 'request');
13822
13823 if (empty($bid) || empty($event)) {
13824 throw new Exception("Missing required information", 500);
13825 }
13826
13827 // Booking History
13828 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
13829 //
13830
13831 echo 'e4j.ok';
13832 exit;
13833 }
13834
13835 /**
13836 * AJAX request for updating an option/extra service.
13837 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
13838 * but it can be used for any other purpose.
13839 *
13840 * @return void
13841 *
13842 * @since 1.13.5
13843 */
13844 public function update_option_params()
13845 {
13846 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13847 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13848 }
13849
13850 $optid = VikRequest::getInt('optid', 0, 'request');
13851 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
13852
13853 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
13854 throw new Exception("Missing required information", 500);
13855 }
13856
13857 $dbo = JFactory::getDbo();
13858 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
13859 $dbo->setQuery($q);
13860 $dbo->execute();
13861 if (!$dbo->getNumRows()) {
13862 throw new Exception("Option not found", 404);
13863 }
13864 $cur_params = $dbo->loadResult();
13865 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
13866 $cur_params = !is_array($cur_params) ? array() : $cur_params;
13867
13868 foreach ($oparams as $k => $v) {
13869 if (empty($k)) {
13870 continue;
13871 }
13872 $cur_params[$k] = $v;
13873 }
13874
13875 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
13876 $dbo->setQuery($q);
13877 $dbo->execute();
13878
13879 echo 'e4j.ok';
13880 exit;
13881 }
13882
13883 /**
13884 * Hidden task to clean up duplicate records in certain database tables
13885 * due to a double execution of the installation queries. Ghost records,
13886 * if any, are also removed to clean up issues with hanging records.
13887 *
13888 * @since November 4th 2020
13889 * @since 1.16.3 (J) - 1.6.3 (WP)
13890 */
13891 public function clean_duplicate_records()
13892 {
13893 $dbo = JFactory::getDbo();
13894
13895 $tables_with_duplicates = [
13896 '#__vikbooking_config' => [
13897 'id_key' => 'id',
13898 'compare_key' => 'param',
13899 ],
13900 '#__vikbooking_countries' => [
13901 'id_key' => 'id',
13902 'compare_key' => 'country_3_code',
13903 ],
13904 '#__vikbooking_custfields' => [
13905 'id_key' => 'id',
13906 'compare_key' => 'name',
13907 ],
13908 '#__vikbooking_texts' => [
13909 'id_key' => 'id',
13910 'compare_key' => 'param',
13911 ],
13912 ];
13913
13914 foreach ($tables_with_duplicates as $tblname => $data) {
13915 $doubles = [];
13916 $storage = [];
13917 $rmlist = [];
13918
13919 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
13920 $dbo->setQuery($q);
13921 $rows = $dbo->loadAssocList();
13922 if (!$rows) {
13923 echo "<p>No records found in table {$tblname}</p>";
13924 continue;
13925 }
13926
13927 foreach ($rows as $row) {
13928 if (!isset($doubles[$row[$data['compare_key']]])) {
13929 $doubles[$row[$data['compare_key']]] = 0;
13930 }
13931 $doubles[$row[$data['compare_key']]]++;
13932 if (!isset($storage[$row[$data['compare_key']]])) {
13933 $storage[$row[$data['compare_key']]] = [];
13934 }
13935 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
13936 }
13937
13938 foreach ($doubles as $paramkey => $paramcount) {
13939 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
13940 continue;
13941 }
13942 $exceeding = $paramcount - 1;
13943 for ($x = 0; $x < $exceeding; $x++) {
13944 array_push($rmlist, $storage[$paramkey][$x]);
13945 }
13946 }
13947
13948 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
13949 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
13950 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
13951
13952 if (count($rmlist)) {
13953 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
13954 $dbo->setQuery($q);
13955 $dbo->execute();
13956 }
13957 }
13958
13959 /**
13960 * Clean up busy records where the busy relations contain empty booking IDs.
13961 */
13962 $hanging_busy_ids = [];
13963
13964 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
13965 $dbo->setQuery($q);
13966 $removelist = $dbo->loadAssocList();
13967 if ($removelist) {
13968 foreach ($removelist as $hanging_busy) {
13969 $hanging_busy_id = (int)$hanging_busy['idbusy'];
13970 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13971 array_push($hanging_busy_ids, $hanging_busy_id);
13972 }
13973 }
13974 }
13975
13976 // let's check also for ghost records that only occupy the room
13977 $q = "SELECT `b`.*,`ob`.`idorder` FROM `#__vikbooking_busy` AS `b` LEFT JOIN `#__vikbooking_ordersbusy` AS `ob` ON `b`.`id`=`ob`.`idbusy` WHERE `b`.`checkout` >= " . time() . " AND (`ob`.`idorder` = 0 OR `ob`.`idorder` IS NULL);";
13978 $dbo->setQuery($q);
13979 $removelist = $dbo->loadAssocList();
13980 if ($removelist) {
13981 foreach ($removelist as $hanging_busy) {
13982 $hanging_busy_id = (int)$hanging_busy['id'];
13983 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13984 array_push($hanging_busy_ids, $hanging_busy_id);
13985 }
13986 }
13987 }
13988
13989 if ($hanging_busy_ids) {
13990 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
13991 $dbo->setQuery($q);
13992 $dbo->execute();
13993 }
13994
13995 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
13996
13997 return;
13998 }
13999
14000 /**
14001 * Hidden task to scan all database tables of VikBooking and Vik Channel Manager
14002 * to ensure the column `id` is defined as a primary key and got an auto-increment
14003 * extra flag properly defined and set. We've noticed that some third-party plugins
14004 * used to migrate WP sites may break the primary keys, and so new records won't get an ID.
14005 *
14006 * @since 1.16.8 (J) - 1.6.8 (WP)
14007 */
14008 public function fix_autoincrement_tables()
14009 {
14010 $dbo = JFactory::getDbo();
14011
14012 // load all the installed database tables
14013 $tables = $dbo->getTableList();
14014
14015 // get current database prefix
14016 $prefix = $dbo->getPrefix();
14017
14018 // replace prefix with placeholder
14019 $tables = array_map(function($table) use ($prefix)
14020 {
14021 return preg_replace("/^{$prefix}/", '#__', $table);
14022 }, $tables);
14023
14024 // remove all the tables that do not belong to VikBooking/VCM
14025 $tables = array_values(array_filter($tables, function($table)
14026 {
14027 if (preg_match("/^#__vik(?:booking|channelmanager)_config$/", $table))
14028 {
14029 // exclude the configuration table, which will be handled in a different way
14030 return false;
14031 }
14032
14033 return preg_match("/^#__vik(?:booking|channelmanager)_/", $table);
14034 }));
14035
14036 foreach ($tables as $table) {
14037 $columns = $dbo->getTableColumns($table, false);
14038 if (!isset($columns['id']) || empty($columns['id']->Type) || !empty($columns['id']->Extra)) {
14039 continue;
14040 }
14041
14042 echo 'Fixing ' . $table. ' for missing auto-increment<br/><pre>' . print_r($columns['id'], true) . '</pre><br/>';
14043
14044 // set auto-increment and primary key
14045 $dbo->setQuery("ALTER TABLE `{$table}` MODIFY `id` " . $columns['id']->Type . " NOT NULL AUTO_INCREMENT PRIMARY KEY;");
14046 $dbo->execute();
14047
14048 // count next auto-increment
14049 $dbo->setQuery("SELECT MAX(`id`) FROM `{$table}`");
14050 $next_ai = (int) $dbo->loadResult() + 1;
14051
14052 // update next auto-increment value
14053 $dbo->setQuery("ALTER TABLE `{$table}` AUTO_INCREMENT = {$next_ai}");
14054 $dbo->execute();
14055 }
14056 }
14057
14058 /**
14059 * Loads a specific admin widget ID and executes the requested method.
14060 * Useful for loading a newly added widget, or to execute custom methods.
14061 *
14062 * @see this is an AJAX endpoint.
14063 *
14064 * @since 1.14 (J) - 1.4.0 (WP)
14065 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
14066 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14067 */
14068 public function exec_admin_widget()
14069 {
14070 if (!JSession::checkToken()) {
14071 // missing CSRF-proof token
14072 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14073 }
14074
14075 $widget_id = VikRequest::getString('widget_id', '', 'request');
14076 $call = VikRequest::getString('call', '', 'request');
14077 $return = VikRequest::getInt('return', 0, 'request');
14078 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
14079 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
14080 $multitask = VikRequest::getInt('multitask', 0, 'request');
14081
14082 if (empty($widget_id)) {
14083 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
14084 }
14085
14086 if (empty($call) || !is_string($call)) {
14087 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14088 }
14089
14090 // invoke admin widgets helper
14091 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14092 $widget = $widgets_helper->getWidget($widget_id);
14093
14094 if ($widget === false) {
14095 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
14096 }
14097
14098 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
14099 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
14100 }
14101
14102 // get the multitask parser object
14103 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
14104
14105 // check if arguments should be passed
14106 $call_args = [];
14107 if ($multitask && $call === 'render') {
14108 // build the multitask data object and inject it to the args as the first index
14109 $call_args[] = $parser->getData();
14110
14111 // bind options within the widget, if any
14112 $widget->bindOptions($call_args[0]);
14113 } else {
14114 // always bind multitask options, if any
14115 $widget->bindOptions($parser->getOptions());
14116 }
14117
14118 try {
14119 if ($return) {
14120 // invoke the widget's method and get the value returned
14121 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
14122 } else {
14123 // invoke the widget's method within a buffer
14124 ob_start();
14125 if ($call_args) {
14126 $res = call_user_func_array([$widget, $call], $call_args);
14127 } else {
14128 $widget->{$call}();
14129 }
14130 $widget_response = ob_get_contents();
14131 ob_end_clean();
14132 }
14133 } catch (Throwable $e) {
14134 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14135 } catch (Exception $e) {
14136 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14137 }
14138
14139 // prepare response object with a property equal to the called method
14140 $response = new stdClass;
14141 $response->{$call} = $widget_response;
14142
14143 // output the JSON encoded response and exit
14144 VBOHttpDocument::getInstance()->json($response);
14145 }
14146
14147 /**
14148 * Updates the map of admin widgets.
14149 *
14150 * @throws Exception this is an AJAX endpoint.
14151 *
14152 * @since 1.4.0
14153 */
14154 public function save_admin_widgets()
14155 {
14156 if (!JSession::checkToken()) {
14157 // missing CSRF-proof token
14158 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14159 }
14160
14161 // make sure permissions are sufficient
14162 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
14163 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
14164 }
14165
14166 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
14167 if (!is_array($psections) || !count($psections)) {
14168 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
14169 }
14170
14171 // request values are all converted to arrays, so restore the object styling
14172 $psections = json_decode(json_encode($psections));
14173
14174 // update map
14175 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
14176
14177 $response = new stdClass;
14178 $response->status = (int)$result;
14179
14180 // output the JSON encoded response and exit
14181 VBOHttpDocument::getInstance()->json($response);
14182 }
14183
14184 /**
14185 * Restores the default admin widgets map.
14186 *
14187 * @since 1.4.0
14188 */
14189 public function reset_admin_widgets()
14190 {
14191 // reset map and redirect to dashboard
14192 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
14193
14194 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
14195 exit;
14196 }
14197
14198 /**
14199 * Updates the welcome message status for the widget's customizer via AJAX.
14200 *
14201 * @since 1.4.0
14202 */
14203 public function admin_widgets_welcome()
14204 {
14205 if (!JSession::checkToken()) {
14206 // missing CSRF-proof token
14207 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14208 }
14209
14210 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
14211 // update configuration value
14212 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
14213
14214 $response = new stdClass;
14215 $response->status = $hide_welcome;
14216
14217 // output the JSON encoded response and exit
14218 VBOHttpDocument::getInstance()->json($response);
14219 }
14220
14221 public function newcondtext()
14222 {
14223 VikBookingHelper::printHeader("11");
14224
14225 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14226
14227 parent::display();
14228
14229 if (VikBooking::showFooter()) {
14230 VikBookingHelper::printFooter();
14231 }
14232 }
14233
14234 public function editcondtext()
14235 {
14236 VikBookingHelper::printHeader("11");
14237
14238 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14239
14240 parent::display();
14241
14242 if (VikBooking::showFooter()) {
14243 VikBookingHelper::printFooter();
14244 }
14245 }
14246
14247 public function cancelcondtext()
14248 {
14249 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
14250 }
14251
14252 public function createcondtext()
14253 {
14254 if (!JSession::checkToken()) {
14255 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14256 }
14257
14258 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14259 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14260 }
14261
14262 $this->_doCreateCondText();
14263 }
14264
14265 public function createcondtextstay()
14266 {
14267 if (!JSession::checkToken()) {
14268 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14269 }
14270
14271 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14272 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14273 }
14274
14275 $this->_doCreateCondText(true);
14276 }
14277
14278 private function _doCreateCondText($stay = false)
14279 {
14280 $dbo = JFactory::getDbo();
14281 $app = JFactory::getApplication();
14282 $rules_helper = VikBooking::getConditionalRulesInstance();
14283 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14284
14285 $condtextname = VikRequest::getString('condtextname', '', 'request');
14286 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14287 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14288 $debug = VikRequest::getInt('debug', 0, 'request');
14289 if (empty($condtextname)) {
14290 $condtextname = date('Y-m-dHis');
14291 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14292 }
14293
14294 $existing_tokens = $rules_helper->getSpecialTags();
14295 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
14296 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
14297 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
14298 exit;
14299 }
14300
14301 $data = new stdClass;
14302 $data->name = $condtextname;
14303 $data->token = $condtexttkn;
14304 $data->rules = json_encode($rules_list);
14305 $data->msg = $msg;
14306 $data->lastupd = JDate::getInstance()->toSql();
14307 $data->debug = $debug;
14308
14309 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
14310
14311 if (isset($data->id)) {
14312 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14313 }
14314
14315 if (!$stay || !isset($data->id)) {
14316 $this->cancelcondtext();
14317 exit;
14318 }
14319
14320 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14321 }
14322
14323 public function updatecondtext()
14324 {
14325 if (!JSession::checkToken()) {
14326 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14327 }
14328
14329 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14330 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14331 }
14332
14333 $this->_doUpdateCondText();
14334 }
14335
14336 public function updatecondtextstay()
14337 {
14338 if (!JSession::checkToken()) {
14339 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14340 }
14341
14342 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14343 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14344 }
14345
14346 $this->_doUpdateCondText(true);
14347 }
14348
14349 private function _doUpdateCondText($stay = false)
14350 {
14351 $dbo = JFactory::getDbo();
14352 $app = JFactory::getApplication();
14353 $rules_helper = VikBooking::getConditionalRulesInstance();
14354 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14355
14356 $pwhere = VikRequest::getInt('where', '', 'request');
14357 $condtextname = VikRequest::getString('condtextname', '', 'request');
14358 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14359 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14360 $debug = VikRequest::getInt('debug', 0, 'request');
14361 if (empty($condtextname)) {
14362 $condtextname = date('Y-m-dHis');
14363 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14364 }
14365
14366 $existing_tokens = $rules_helper->getSpecialTags();
14367 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
14368 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
14369 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
14370 exit;
14371 }
14372
14373 $data = new stdClass;
14374 $data->id = $pwhere;
14375 $data->name = $condtextname;
14376 $data->token = $condtexttkn;
14377 $data->rules = json_encode($rules_list);
14378 $data->msg = $msg;
14379 $data->lastupd = JDate::getInstance()->toSql();
14380 $data->debug = $debug;
14381
14382 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
14383
14384 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14385
14386 if (!$stay) {
14387 $this->cancelcondtext();
14388 exit;
14389 }
14390
14391 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14392 }
14393
14394 public function removecondtext()
14395 {
14396 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14397 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14398 }
14399
14400 $dbo = JFactory::getDbo();
14401 $ids = VikRequest::getVar('cid', array());
14402
14403 VikBooking::getConditionalRulesInstance(true);
14404 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14405
14406 foreach ($ids as $d) {
14407 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14408 $dbo->setQuery($q);
14409 $dbo->execute();
14410 if (!$dbo->getNumRows()) {
14411 continue;
14412 }
14413 $special_tag = $dbo->loadResult();
14414
14415 // remove the token from each template file if it was used before
14416 if (!empty($special_tag)) {
14417 // remove token from all template files
14418 foreach ($templates as $tkey => $tpath) {
14419 // get requested file content
14420 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14421 if (empty($fcontent) || !is_string($fcontent)) {
14422 break;
14423 }
14424 // remove tag from code content
14425 $fcontent = str_replace($special_tag, '', $fcontent);
14426 // update the file code
14427 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14428 }
14429 }
14430
14431 // delete the record
14432 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14433 $dbo->setQuery($q);
14434 $dbo->execute();
14435 }
14436
14437 $this->cancelcondtext();
14438 }
14439
14440 /**
14441 * AJAX endpoint to update one template file with the given tag or styles.
14442 * A JSON response will be echoed by exiting the process.
14443 */
14444 public function condtext_update_tmpl()
14445 {
14446 VikBooking::getConditionalRulesInstance(true);
14447
14448 $tagaction = VikRequest::getString('tagaction', '', 'request');
14449 $tag = VikRequest::getString('tag', '', 'request');
14450 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14451 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14452 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14453
14454 $allowed_actions = array(
14455 'add',
14456 'remove',
14457 'styles',
14458 'restore',
14459 );
14460
14461 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14462 throw new Exception("Invalid request submitted", 500);
14463 }
14464
14465 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14466 throw new Exception("Invalid request submitted - missing tag", 500);
14467 }
14468
14469 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14470 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14471 }
14472
14473 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14474 throw new Exception("No custom CSS classes to parse", 500);
14475 }
14476
14477 if ($tagaction == 'restore') {
14478 // immediately restore the requested file to avoid script interruptions
14479 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14480 }
14481
14482 // get requested file content
14483 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14484 if (empty($fcontent) || !is_string($fcontent)) {
14485 throw new Exception("File not found or its code is unreadable", 404);
14486 }
14487
14488 if ($tagaction == 'remove') {
14489 // remove tag from code content
14490 $fcontent = str_replace($tag, '', $fcontent);
14491 } elseif ($tagaction == 'add') {
14492 // add tag to code content in the same exact position
14493 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14494 } elseif ($tagaction == 'styles') {
14495 // apply the same styling rules
14496 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14497 }
14498
14499 // update the file code
14500 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14501
14502 if (!$res) {
14503 throw new Exception("Could not update the source code of the template file", 500);
14504 }
14505
14506 // parse new HTML content
14507 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14508 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14509 throw new Exception("Could not parse new template file content", 404);
14510 }
14511
14512 // trigger backup/mirroring, if available
14513 if (VBOPlatformDetection::isWordPress()) {
14514 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14515 }
14516
14517 // build output
14518 $output = new stdClass;
14519 $output->newhtml = $newhtmls[$file];
14520 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14521
14522 echo json_encode($output);
14523 exit;
14524 }
14525
14526 /**
14527 * AJAX endpoint to invoke methods of the geocoding helper.
14528 */
14529 public function geocoding_endpoint()
14530 {
14531 $geo = VikBooking::getGeocodingInstance();
14532 $callback = VikRequest::getString('callback', '', 'request');
14533
14534 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14535 throw new Exception("Callback not available", 403);
14536 }
14537
14538 // invoke requested method
14539 $res = $geo->{$callback}();
14540
14541 // prepare response
14542 $response = new stdClass;
14543 $response->{$callback} = $res;
14544
14545 echo json_encode($response);
14546 exit;
14547 }
14548
14549 public function refundtn()
14550 {
14551 //modal box, so we do not set menu or footer
14552
14553 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14554
14555 parent::display();
14556 }
14557
14558 public function do_refundtn()
14559 {
14560 $dbo = JFactory::getDbo();
14561 $app = JFactory::getApplication();
14562
14563 $bid = VikRequest::getInt('bid', 0, 'request');
14564 $amount = VikRequest::getFloat('amount', 0, 'request');
14565 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14566 $tmpl = VikRequest::getString('tmpl', '', 'request');
14567 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14568
14569 $currencysymb = VikBooking::getCurrencySymb();
14570
14571 if (empty($bid) || $amount <= 0) {
14572 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14573 $app->redirect('index.php?option=com_vikbooking');
14574 exit;
14575 }
14576
14577 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14578 $dbo->setQuery($q);
14579 $dbo->execute();
14580 if ($dbo->getNumRows() < 1) {
14581 VikError::raiseWarning('', 'Booking not found');
14582 $app->redirect('index.php?option=com_vikbooking');
14583 exit;
14584 }
14585 $row = $dbo->loadAssoc();
14586
14587 // get booking history instance
14588 $history_obj = VikBooking::getBookingHistoryInstance();
14589 $history_obj->setBid($row['id']);
14590
14591 // get payment information
14592 $payment = VikBooking::getPayment($row['idpayment']);
14593 $tn_driver = is_array($payment) ? $payment['file'] : null;
14594
14595 // transaction data validation callback
14596 $tn_data_callback = function($data) use ($tn_driver) {
14597 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14598 };
14599 // get previous transactions
14600 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14601
14602 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14603 // no previous transactions found
14604 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14605 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14606 exit;
14607 }
14608
14609 // push refund information for the payment gateway
14610 $row['total_to_refund'] = $amount;
14611 $row['transaction'] = $prev_tn_data;
14612 $row['refund_reason'] = $refund_reason;
14613
14614 // push the transaction currency information
14615 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14616
14617 /**
14618 * @wponly The payment gateway is loaded
14619 * through the apposite dispatcher.
14620 */
14621 JLoader::import('adapter.payment.dispatcher');
14622 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14623
14624 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14625 // refund not supported
14626 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14627 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14628 exit;
14629 }
14630
14631 // perform the refund transaction
14632 $array_result = $obj->refund();
14633
14634 if ($array_result['verified'] != 1) {
14635 // raise warning by getting the message
14636 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14637 VikError::raiseWarning('', $array_result['log']);
14638 } else {
14639 VikError::raiseWarning('', 'Operation failed');
14640 }
14641 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14642 exit;
14643 }
14644
14645 /**
14646 * New payment plugins can return the total amount refunded ('tot_paid').
14647 *
14648 * @since 1.15.4 (J) - 1.5.10 (WP)
14649 */
14650 if (!empty($array_result['tot_paid'])) {
14651 // overwrite the requested amount with the returned one
14652 $amount = (float)$array_result['tot_paid'];
14653 }
14654
14655 /**
14656 * The history event extra data will contain the "amount_paid" (refunded).
14657 *
14658 * @since 1.16.9 (J) - 1.6.9 (WP)
14659 */
14660 $history_obj->setExtraData([
14661 'amount_paid' => $amount,
14662 ]);
14663
14664 // update total paid, total and refund columns for the booking
14665 $booking = new stdClass;
14666 $booking->id = $row['id'];
14667 if ($row['totpaid'] > 0) {
14668 $booking->totpaid = $row['totpaid'] - $amount;
14669 }
14670 if ($row['total'] > 0) {
14671 $booking->total = $row['total'] - $amount;
14672 }
14673 $booking->refund = (float)$row['refund'] + $amount;
14674 // update record in db
14675 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
14676
14677 // store the refund event
14678 $event_descr = [
14679 '(' . $payment['name'] . ')',
14680 $refund_reason,
14681 $currencysymb . ' ' . VikBooking::numberFormat($amount),
14682 ];
14683 $history_obj->store('RF', implode("\n", $event_descr));
14684
14685 // display success message and redirect
14686 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
14687 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
14688 exit;
14689 }
14690
14691 /**
14692 * AJAX upload endpoint for media files.
14693 *
14694 * @return void
14695 *
14696 * @throws Exception
14697 *
14698 * @since 1.15.0 (J) - 1.5.0 (WP)
14699 */
14700 public function upload_media_file()
14701 {
14702 $input = JFactory::getApplication()->input;
14703
14704 // allowed types
14705 $type = $input->getString('type', '');
14706 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
14707 if ($type == 'image') {
14708 $mask = "/(image\/.+)$/i";
14709 }
14710
14711 // response object
14712 $result = new stdClass;
14713 $result->status = 0;
14714
14715 try
14716 {
14717 // get file from request
14718 $file = $input->files->get('file', array(), 'array');
14719
14720 // try to upload the file
14721 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
14722 $result->status = 1;
14723
14724 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
14725 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
14726 }
14727 catch (Exception $e)
14728 {
14729 $result->error = $e->getMessage();
14730 $result->code = $e->getCode();
14731 }
14732
14733 echo json_encode($result);
14734 exit;
14735 }
14736
14737 /**
14738 * AJAX endpoint to invoke a report object's method.
14739 *
14740 * @return void
14741 *
14742 * @throws Exception
14743 *
14744 * @since 1.15.0 (J) - 1.5.0 (WP)
14745 */
14746 public function invoke_report()
14747 {
14748 $report_name = VikRequest::getString('report', '', 'request');
14749 $report_call = VikRequest::getString('call', '', 'request');
14750 $params = VikRequest::getVar('params', array(), 'request', 'array');
14751
14752 if (empty($report_name)) {
14753 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
14754 }
14755
14756 if (empty($report_call)) {
14757 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
14758 }
14759
14760 // get requested report instance
14761 $report = VikBooking::getReportInstance($report_name);
14762 if (!$report) {
14763 VBOHttpDocument::getInstance()->close(404, 'Report not found');
14764 }
14765
14766 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
14767 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
14768 }
14769
14770 // call on report's method
14771 $result = $report->{$report_call}($params);
14772
14773 if (is_null($result)) {
14774 VBOHttpDocument::getInstance()->close(400, 'Null response');
14775 }
14776
14777 if (is_scalar($result)) {
14778 // wrap result within an array for a JSON encoded response
14779 VBOHttpDocument::getInstance()->json([$result]);
14780 }
14781
14782 // output the JSON encoded array/object returned
14783 VBOHttpDocument::getInstance()->json($result);
14784 }
14785
14786 /**
14787 * Handles requests for the multitask widgets panel.
14788 *
14789 * @see this is an AJAX endpoint.
14790 *
14791 * @since 1.15.0 (J) - 1.5.0 (WP)
14792 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14793 */
14794 public function exec_multitask_widgets()
14795 {
14796 if (!JSession::checkToken()) {
14797 // missing CSRF-proof token
14798 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14799 }
14800
14801 $call = VikRequest::getString('call', '', 'request');
14802 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
14803
14804 if (empty($call)) {
14805 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14806 }
14807
14808 // invoke admin widgets helper
14809 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14810
14811 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
14812 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
14813 }
14814
14815 try {
14816 // invoke the helper's method and get the value returned
14817 if (is_array($call_args) && count($call_args)) {
14818 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
14819 } else {
14820 $result = $widgets_helper->{$call}();
14821 }
14822 } catch (Throwable $e) {
14823 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14824 } catch (Exception $e) {
14825 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14826 }
14827
14828 // prepare response object with the result property
14829 $response = new stdClass;
14830 $response->result = $result;
14831
14832 // output the JSON response and exit
14833 VBOHttpDocument::getInstance()->json($response);
14834 }
14835
14836 /**
14837 * Handles requests for displaying a browser notification being dispatched.
14838 *
14839 * @see this is an AJAX endpoint.
14840 *
14841 * @since 1.15.0 (J) - 1.5.0 (WP)
14842 */
14843 public function notification_displayer()
14844 {
14845 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
14846
14847 if (empty($payload_str)) {
14848 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
14849 }
14850
14851 // attempt to decode the notification payload
14852 $payload = json_decode($payload_str);
14853
14854 if (!is_object($payload)) {
14855 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
14856 }
14857
14858 // get notification displayer for this type of notification
14859 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
14860 if (!$displayer) {
14861 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
14862 }
14863
14864 // compose the notification display data object
14865 try {
14866 $notif_data = $displayer->getData();
14867 if (!$notif_data) {
14868 throw new Exception('Error building the notification display data', 500);
14869 }
14870 } catch (Exception $e) {
14871 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14872 }
14873
14874 // output the JSON response and exit
14875 VBOHttpDocument::getInstance()->json($notif_data);
14876 }
14877
14878 /**
14879 * Handles requests for watching widgets data and getting
14880 * new events to trigger browser notifications.
14881 *
14882 * @see this is an AJAX endpoint.
14883 *
14884 * @since 1.15.0 (J) - 1.5.0 (WP)
14885 * @since 1.16.8 (J) - 1.6.8 (WP) introduced notification events.
14886 */
14887 public function widgets_watch_data()
14888 {
14889 if (!JSession::checkToken()) {
14890 // missing CSRF-proof token
14891 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14892 }
14893
14894 $app = JFactory::getApplication();
14895
14896 $watch_data_str = $app->input->get('watch_data', '', 'raw');
14897 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
14898
14899 if (empty($watch_data_str)) {
14900 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
14901 }
14902
14903 // attempt to decode the watch-data payload
14904 $watch_data = json_decode($watch_data_str, true);
14905
14906 if (!$watch_data) {
14907 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
14908 }
14909
14910 // check if any pushed data was set
14911 $pushed_data = (array)json_decode($pushed_data_str, true);
14912
14913 // container for new notifications
14914 $notifs_pool = [];
14915
14916 // container for the events data to dispatch
14917 $events_pool = [];
14918
14919 // get admin widgets helper
14920 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14921
14922 foreach ($watch_data as $widget_id => $data) {
14923 // invoke admin widget (with no pre-loading)
14924 $widget_instance = $widgets_helper->getWidget($widget_id);
14925 if (!$widget_instance) {
14926 continue;
14927 }
14928
14929 // build the widget watch data object
14930 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
14931
14932 // check if the widget needs to emit browser notifications
14933 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
14934
14935 // check if the widget needs to emit JavaScript events
14936 $events = $widget_instance->getNotificationEvents($widget_watch_data);
14937
14938 if ($watch_next) {
14939 // update next watch-data object for this widget
14940 $watch_data[$widget_id] = $watch_next;
14941 }
14942
14943 if (is_array($notifications) && $notifications) {
14944 // merge notifications
14945 $notifs_pool = array_merge($notifs_pool, $notifications);
14946 }
14947
14948 if (is_array($events) && $events) {
14949 // push notification events for this widget
14950 $events_pool[] = $events;
14951 }
14952 }
14953
14954 // build the response object
14955 $response = new stdClass;
14956 $response->watch_data = $watch_data;
14957 $response->notifications = $notifs_pool;
14958 $response->events = $events_pool;
14959
14960 // output the JSON response and exit
14961 VBOHttpDocument::getInstance()->json($response);
14962 }
14963
14964 /**
14965 * Outputs a list of CSS assets required to render the admin widgets
14966 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
14967 *
14968 * @see this is an AJAX endpoint.
14969 *
14970 * @since 1.16.0 (J) - 1.6.0 (WP)
14971 */
14972 public function widgets_get_assets()
14973 {
14974 // list of needed CSS asset details
14975 $assets_pool = [];
14976
14977 // appearance preference assets (one or none)
14978 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
14979
14980 if (VBOPlatformDetection::isWordPress()) {
14981 // WordPress (main CSS)
14982 $assets_pool[] = [
14983 'rel' => 'stylesheet',
14984 'id' => 'vbo-style-css',
14985 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14986 'media' => 'all',
14987 ];
14988
14989 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14990 // appearance preference CSS
14991 $assets_pool[] = [
14992 'rel' => 'stylesheet',
14993 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14994 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14995 'media' => 'all',
14996 ];
14997 }
14998 } else {
14999 // Joomla (main CSS)
15000 $assets_pool[] = [
15001 'rel' => 'stylesheet',
15002 'id' => 'vbo-style-css',
15003 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
15004 'media' => 'all',
15005 ];
15006
15007 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15008 // appearance preference CSS
15009 $assets_pool[] = [
15010 'rel' => 'stylesheet',
15011 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15012 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
15013 'media' => 'all',
15014 ];
15015 }
15016 }
15017
15018 // output the JSON response and exit
15019 VBOHttpDocument::getInstance()->json($assets_pool);
15020 }
15021 }
15022