PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.1
VikBooking Hotel Booking Engine & PMS v1.7.1
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.1, at admin/controller.php

15,358 lines 579.8 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 $dbo = JFactory::getDbo();
3723 $app = JFactory::getApplication();
3724
3725 $cid = VikRequest::getVar('cid', array(0));
3726 $oid = $cid[0];
3727
3728 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . (int)$oid . " AND `status` != 'confirmed';";
3729 $dbo->setQuery($q);
3730 $dbo->execute();
3731 if (!$dbo->getNumRows()) {
3732 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3733 exit;
3734 }
3735 $order = $dbo->loadAssoc();
3736
3737 /**
3738 * Memorize the original booking status for VCM in case of OTA booking.
3739 *
3740 * @since 1.14 (J) - 1.4.0 (WP)
3741 */
3742 $original_book_status = null;
3743 if (!empty($order['idorderota']) && !empty($order['channel'])) {
3744 $original_book_status = $order['status'];
3745 }
3746
3747 // availability helper
3748 $av_helper = VikBooking::getAvailabilityInstance();
3749
3750 // room stay dates in case of split stay
3751 $room_stay_dates = [];
3752 if ($order['split_stay']) {
3753 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
3754 }
3755
3756 $vbo_tn = VikBooking::getTranslator();
3757 // check if the language in use is the same as the one used during the checkout
3758 if (!empty($order['lang'])) {
3759 $lang = JFactory::getLanguage();
3760 if ($lang->getTag() != $order['lang']) {
3761 $lang->load('com_vikbooking', (VBOPlatformDetection::isWordPress() ? VIKBOOKING_LANG : JPATH_ADMINISTRATOR), $order['lang'], true);
3762 if (defined('_JEXEC') && !defined('ABSPATH')) {
3763 $lang->load('joomla', JPATH_ADMINISTRATOR, $order['lang'], true);
3764 }
3765 }
3766 if ($vbo_tn->getDefaultLang() != $order['lang']) {
3767 // force the translation to start because contents should be translated
3768 $vbo_tn::$force_tolang = $order['lang'];
3769 }
3770 }
3771
3772 // load order rooms
3773 $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;";
3774 $dbo->setQuery($q);
3775 $dbo->execute();
3776 $ordersrooms = $dbo->loadAssocList();
3777 $vbo_tn->translateContents($ordersrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
3778
3779 $currencyname = VikBooking::getCurrencyName();
3780 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
3781 $realback = $turnover_secs + $order['checkout'];
3782 $allbook = true;
3783 $notavail = [];
3784
3785 /**
3786 * We need to calculate a minus operator for each room that was booked more than once.
3787 * In case we are confirming a booking for more than one unit of the same room, we need to
3788 * make sure the calculation is made properly, as only one unit of that room could be free.
3789 *
3790 * @since 1.13 (J) - 1.3.0 (WP)
3791 */
3792 $units_minus_oper = [];
3793 foreach ($ordersrooms as $ind => $or) {
3794 if (!isset($units_minus_oper[$or['idroom']])) {
3795 $units_minus_oper[$or['idroom']] = -1;
3796 }
3797 // increase counter
3798 $units_minus_oper[$or['idroom']]++;
3799 if (!empty($room_stay_dates)) {
3800 // split stay rooms never have the same stay dates, but they should also be different rooms
3801 $units_minus_oper[$or['idroom']] = 0;
3802 }
3803 }
3804
3805 foreach ($ordersrooms as $ind => $or) {
3806 // determine proper values for this room
3807 $room_stay_checkin = $order['checkin'];
3808 $room_stay_checkout = $order['checkout'];
3809 $room_stay_nights = $order['days'];
3810 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
3811 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
3812 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
3813 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
3814 // inject nights calculated for this room
3815 $room_stay_dates[$ind]['nights'] = $room_stay_nights;
3816 }
3817
3818 // check if the room is available
3819 if (!VikBooking::roomBookable($or['idroom'], ($or['units'] - $units_minus_oper[$or['idroom']]), $room_stay_checkin, $room_stay_checkout)) {
3820 $allbook = false;
3821 $notavail[] = $or['name']." (".JText::translate('VBMAILADULTS').": ".$or['adults'].($or['children'] > 0 ? " - ".JText::translate('VBMAILCHILDREN').": ".$or['children'] : "").")";
3822 }
3823 }
3824
3825 if (!$allbook) {
3826 VikError::raiseWarning('', JText::translate('VBERRCONFORDERNOTAVROOM').' '.implode(", ", $notavail).'<br/>'.JText::translate('VBUNABLESETRESCONF'));
3827 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3828 exit;
3829 }
3830
3831 $rooms = [];
3832 $tars = [];
3833 $arrpeople = [];
3834 $is_package = !empty($order['pkg']) ? true : false;
3835 $rooms_booked = [];
3836 foreach ($ordersrooms as $ind => $or) {
3837 // push room booked
3838 array_push($rooms_booked, (int)$or['idroom']);
3839
3840 // determine proper values for this room
3841 $room_stay_checkin = $order['checkin'];
3842 $room_stay_checkout = $order['checkout'];
3843 $room_stay_realback = $realback;
3844 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
3845 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
3846 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
3847 $room_stay_realback = $turnover_secs + $room_stay_checkout;
3848 }
3849
3850 $q = "INSERT INTO `#__vikbooking_busy` (`idroom`,`checkin`,`checkout`,`realback`) VALUES(" . (int)$or['idroom'] . ", " . (int)$room_stay_checkin . ", " . (int)$room_stay_checkout . ", " . (int)$room_stay_realback . ");";
3851 $dbo->setQuery($q);
3852 $dbo->execute();
3853 $lid = $dbo->insertid();
3854
3855 $q = "INSERT INTO `#__vikbooking_ordersbusy` (`idorder`,`idbusy`) VALUES(" . (int)$oid . ", " . (int)$lid . ");";
3856 $dbo->setQuery($q);
3857 $dbo->execute();
3858 }
3859
3860 // update status
3861 $q = "UPDATE `#__vikbooking_orders` SET `status`='confirmed' WHERE `id`=" . (int)$order['id'] . ";";
3862 $dbo->setQuery($q);
3863 $dbo->execute();
3864
3865 // remove any previous temporary locked record
3866 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . (int)$order['id'] . ";";
3867 $dbo->setQuery($q);
3868 $dbo->execute();
3869
3870 // Booking History
3871 $now_user = JFactory::getUser();
3872 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('TC', "({$now_user->name})");
3873
3874 // check if some of the rooms booked have shared calendars
3875 VikBooking::updateSharedCalendars($order['id'], $rooms_booked, $order['checkin'], $order['checkout']);
3876
3877 // send mail
3878 $ftitle = VikBooking::getFrontTitle();
3879 $nowts = time();
3880 // assign room specific unit
3881 $set_room_indexes = VikBooking::autoRoomUnit();
3882 $room_indexes_usemap = [];
3883
3884 foreach ($ordersrooms as $kor => $or) {
3885 $num = $kor + 1;
3886
3887 // determine proper values for this room
3888 $room_stay_checkin = $order['checkin'];
3889 $room_stay_checkout = $order['checkout'];
3890 $room_stay_nights = $order['days'];
3891 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3892 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
3893 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
3894 $room_stay_nights = $room_stay_dates[$kor]['nights'];
3895 }
3896
3897 $rooms[$num] = $or;
3898 $arrpeople[$num]['adults'] = $or['adults'];
3899 $arrpeople[$num]['children'] = $or['children'];
3900
3901 // assign room specific unit
3902 if ($set_room_indexes === true) {
3903 $room_indexes = VikBooking::getRoomUnitNumsAvailable($order, $or['r_reference_id']);
3904 $use_ind_key = 0;
3905 if (count($room_indexes)) {
3906 if (!array_key_exists($or['r_reference_id'], $room_indexes_usemap)) {
3907 $room_indexes_usemap[$or['r_reference_id']] = $use_ind_key;
3908 } else {
3909 $use_ind_key = $room_indexes_usemap[$or['r_reference_id']];
3910 }
3911 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
3912 $dbo->setQuery($q);
3913 $dbo->execute();
3914 // update rooms references for the customer email sending function
3915 $rooms[$num]['roomindex'] = (int)$room_indexes[$use_ind_key];
3916 //
3917 $room_indexes_usemap[$or['r_reference_id']]++;
3918 }
3919 }
3920
3921 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3922 // package or custom cost set from the back-end
3923 continue;
3924 }
3925
3926 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=" . (int)$or['idtar'] . ";";
3927 $dbo->setQuery($q);
3928 $dbo->execute();
3929 if ($dbo->getNumRows() > 0) {
3930 $tar = $dbo->loadAssocList();
3931 $tar = VikBooking::applySeasonsRoom($tar, $room_stay_checkin, $room_stay_checkout);
3932
3933 // different usage
3934 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
3935
3936 $tars[$num] = $tar[0];
3937 } else {
3938 VikError::raiseWarning('', JText::translate('VBERRNOFAREFOUND'));
3939 }
3940 }
3941
3942 $pcheckin = $order['checkin'];
3943 $pcheckout = $order['checkout'];
3944 $secdiff = $pcheckout - $pcheckin;
3945 $daysdiff = $secdiff / 86400;
3946 if (is_int($daysdiff)) {
3947 if ($daysdiff < 1) {
3948 $daysdiff = 1;
3949 }
3950 } else {
3951 if ($daysdiff < 1) {
3952 $daysdiff = 1;
3953 } else {
3954 $sum = floor($daysdiff) * 86400;
3955 $newdiff = $secdiff - $sum;
3956 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
3957 if ($maxhmore >= $newdiff) {
3958 $daysdiff = floor($daysdiff);
3959 } else {
3960 $daysdiff = ceil($daysdiff);
3961 }
3962 }
3963 }
3964
3965 $isdue = 0;
3966 $pricestr = [];
3967 $optstr = [];
3968 foreach ($ordersrooms as $kor => $or) {
3969 $num = $kor + 1;
3970
3971 // determine proper values for this room
3972 $room_stay_checkin = $order['checkin'];
3973 $room_stay_checkout = $order['checkout'];
3974 $room_stay_nights = $order['days'];
3975 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3976 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
3977 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
3978 $room_stay_nights = $room_stay_dates[$kor]['nights'];
3979 }
3980
3981 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3982 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
3983 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
3984 $isdue += $calctar;
3985 $pricestr[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? ucwords($or['otarplan']) : JText::translate('VBOROOMCUSTRATEPLAN'))).": ".$calctar." ".$currencyname;
3986 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
3987 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3988 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
3989 $tars[$num]['calctar'] = $calctar;
3990 $isdue += $calctar;
3991 $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'] : "");
3992 }
3993 if (!empty($or['optionals'])) {
3994 $stepo = explode(";", $or['optionals']);
3995 foreach ($stepo as $roptkey => $oo) {
3996 if (empty($oo)) {
3997 continue;
3998 }
3999 $stept = explode(":", $oo);
4000 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=" . $dbo->quote($stept[0]) . ";";
4001 $dbo->setQuery($q);
4002 $dbo->execute();
4003 if (!$dbo->getNumRows()) {
4004 continue;
4005 }
4006 $actopt = $dbo->loadAssocList();
4007 $vbo_tn->translateContents($actopt, '#__vikbooking_optionals');
4008 $chvar = '';
4009 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
4010 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
4011 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
4012 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
4013 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
4014 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
4015 $agestept = explode('-', $stept[1]);
4016 $stept[1] = $agestept[0];
4017 $chvar = $agestept[1];
4018 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
4019 //percentage value of the adults tariff
4020 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
4021 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
4022 } else {
4023 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
4024 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
4025 }
4026 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
4027 //VBO 1.10 - percentage value of room base cost
4028 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
4029 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
4030 } else {
4031 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
4032 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
4033 }
4034 }
4035 $actopt[0]['chageintv'] = $chvar;
4036 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
4037 $actopt[0]['quan'] = $stept[1];
4038 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
4039 } else {
4040 $actopt[0]['quan'] = $stept[1];
4041 // VBO 1.11 - options percentage cost of the room total fee
4042 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
4043 $deftar_basecosts = $or['cust_cost'];
4044 } else {
4045 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
4046 }
4047 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
4048 //
4049 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_stay_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
4050 }
4051 if (!empty($actopt[0]['maxprice']) && $actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
4052 $realcost = $actopt[0]['maxprice'];
4053 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
4054 $realcost = $actopt[0]['maxprice'] * $stept[1];
4055 }
4056 }
4057 if ($actopt[0]['perperson'] == 1) {
4058 $realcost = $realcost * $or['adults'];
4059 }
4060 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
4061 $isdue += $tmpopr;
4062 $optstr[$num][] = ($stept[1] > 1 ? $stept[1] . " " : "") . $actopt[0]['name'] . ": " . $tmpopr . " " . $currencyname . "\n";
4063 }
4064 }
4065
4066 // custom extra costs
4067 if (!empty($or['extracosts'])) {
4068 $cur_extra_costs = json_decode($or['extracosts'], true);
4069 foreach ($cur_extra_costs as $eck => $ecv) {
4070 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
4071 $isdue += $ecplustax;
4072 $optstr[$num][] = $ecv['name'] . ": " . $ecplustax . " " . $currencyname."\n";
4073 }
4074 }
4075 }
4076
4077 // coupon
4078 $usedcoupon = false;
4079 $origisdue = $isdue;
4080 if (strlen($order['coupon']) > 0) {
4081 $usedcoupon = true;
4082 $expcoupon = explode(";", $order['coupon']);
4083 $isdue = $isdue - $expcoupon[1];
4084 }
4085
4086 // make sure to apply any previously refunded amount
4087 if ($order['refund'] > 0) {
4088 $isdue -= $order['refund'];
4089 }
4090
4091 // ConfirmationNumber
4092 $confirmnumber = VikBooking::generateConfirmNumber($order['id'], true);
4093
4094 $app->enqueueMessage(JText::translate('VBORDERSETASCONF'));
4095
4096 // notify the customer unless it was a re-confirmation
4097 $pskip = VikRequest::getInt('skip_notification', 0, 'request');
4098 if ($pskip < 1) {
4099 // send email notification to guest
4100 VikBooking::sendBookingEmail($order['id'], array('guest'));
4101
4102 // SMS skipping the administrator
4103 VikBooking::sendBookingSMS($order['id'], array('admin'));
4104 }
4105
4106 // Invoke Channel Manager
4107 $vcm_autosync = VikBooking::vcmAutoUpdate();
4108 if ($vcm_autosync > 0) {
4109 $vcm_obj = VikBooking::getVcmInvoker();
4110 $vcm_obj->setOids(array($order['id']))->setSyncType('new')->setOriginalStatuses(array($original_book_status));
4111 $sync_result = $vcm_obj->doSync();
4112 if ($sync_result === false) {
4113 $vcm_err = $vcm_obj->getError();
4114 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
4115 }
4116 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
4117 $vcm_sync_url = 'index.php?option=com_vikbooking&task=invoke_vcm&stype=new&cid[]='.$order['id'].'&returl='.urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$order['id']);
4118 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
4119 }
4120
4121 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
4122 }
4123
4124 public function payments() {
4125 VikBookingHelper::printHeader("14");
4126
4127 VikRequest::setVar('view', VikRequest::getCmd('view', 'payments'));
4128
4129 parent::display();
4130
4131 if (VikBooking::showFooter()) {
4132 VikBookingHelper::printFooter();
4133 }
4134 }
4135
4136 public function newpayment() {
4137 VikBookingHelper::printHeader("14");
4138
4139 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
4140
4141 parent::display();
4142
4143 if (VikBooking::showFooter()) {
4144 VikBookingHelper::printFooter();
4145 }
4146 }
4147
4148 public function editpayment() {
4149 VikBookingHelper::printHeader("14");
4150
4151 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
4152
4153 parent::display();
4154
4155 if (VikBooking::showFooter()) {
4156 VikBookingHelper::printFooter();
4157 }
4158 }
4159
4160 public function createpayment()
4161 {
4162 if (!JSession::checkToken()) {
4163 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4164 }
4165
4166 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4167 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4168 }
4169
4170 $mainframe = JFactory::getApplication();
4171 $pname = VikRequest::getString('name', '', 'request');
4172 $ppayment = VikRequest::getString('payment', '', 'request');
4173 $ppublished = VikRequest::getString('published', '', 'request');
4174 $pcharge = VikRequest::getFloat('charge', '', 'request');
4175 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4176 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4177 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4178 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4179 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWHTML);
4180 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4181 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4182 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4183 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4184 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4185 $plogo = VikRequest::getString('logo', '', 'request');
4186 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4187 $pidrooms = VikRequest::getVar('idrooms', array());
4188 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4189 $payparamarr = array();
4190 $payparamstr = '';
4191 if (count($vikpaymentparams) > 0) {
4192 foreach ($vikpaymentparams as $setting => $cont) {
4193 if (strlen($setting) > 0) {
4194 $payparamarr[$setting] = $cont;
4195 }
4196 }
4197 if (count($payparamarr) > 0) {
4198 $payparamstr = json_encode($payparamarr);
4199 }
4200 }
4201
4202 $dbo = JFactory::getDbo();
4203
4204 $set_idrooms = [];
4205 if (empty($pall_rooms) && !empty($pidrooms)) {
4206 $pidrooms = array_map(function($idroom) {
4207 return (int)$idroom;
4208 }, $pidrooms);
4209 foreach ($pidrooms as $idroom) {
4210 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4211 continue;
4212 }
4213 $set_idrooms[] = $idroom;
4214 }
4215 }
4216
4217 if (!empty($pname) && !empty($ppayment)) {
4218 $setpub = $ppublished == "1" ? 1 : 0;
4219 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4220 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4221 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment).";";
4222 $dbo->setQuery($q);
4223 $dbo->execute();
4224 if ($dbo->getNumRows() >= 0) {
4225 $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') . ");";
4226 $dbo->setQuery($q);
4227 $dbo->execute();
4228 $mainframe->enqueueMessage(JText::translate('VBPAYMENTSAVED'));
4229 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4230 } else {
4231 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4232 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4233 }
4234 } else {
4235 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4236 }
4237 }
4238
4239 public function updatepayment()
4240 {
4241 if (!JSession::checkToken()) {
4242 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4243 }
4244
4245 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4246 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4247 }
4248
4249 $this->do_updatepayment($stay = false);
4250 }
4251
4252 public function updatepaymentstay()
4253 {
4254 if (!JSession::checkToken()) {
4255 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4256 }
4257
4258 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4259 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4260 }
4261
4262 $this->do_updatepayment($stay = true);
4263 }
4264
4265 protected function do_updatepayment($stay = false)
4266 {
4267 $mainframe = JFactory::getApplication();
4268
4269 $pwhere = VikRequest::getString('where', '', 'request');
4270 $pname = VikRequest::getString('name', '', 'request');
4271 $ppayment = VikRequest::getString('payment', '', 'request');
4272 $ppublished = VikRequest::getString('published', '', 'request');
4273 $pcharge = VikRequest::getFloat('charge', '', 'request');
4274 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4275 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4276 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4277 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4278 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWRAW);
4279 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4280 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4281 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4282 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4283 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4284 $plogo = VikRequest::getString('logo', '', 'request');
4285 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4286 $pidrooms = VikRequest::getVar('idrooms', array());
4287 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4288 $payparamarr = array();
4289 $payparamstr = '';
4290 if (count($vikpaymentparams) > 0) {
4291 foreach ($vikpaymentparams as $setting => $cont) {
4292 if (strlen($setting) > 0) {
4293 $payparamarr[$setting] = $cont;
4294 }
4295 }
4296 if (count($payparamarr) > 0) {
4297 $payparamstr = json_encode($payparamarr);
4298 }
4299 }
4300
4301 $dbo = JFactory::getDbo();
4302
4303 $set_idrooms = [];
4304 if (empty($pall_rooms) && !empty($pidrooms)) {
4305 $pidrooms = array_map(function($idroom) {
4306 return (int)$idroom;
4307 }, $pidrooms);
4308 foreach ($pidrooms as $idroom) {
4309 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4310 continue;
4311 }
4312 $set_idrooms[] = $idroom;
4313 }
4314 }
4315
4316 if (!empty($pname) && !empty($ppayment) && !empty($pwhere)) {
4317 $setpub = $ppublished == "1" ? 1 : 0;
4318 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4319 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4320 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment)." AND `id`!='".$pwhere."';";
4321 $dbo->setQuery($q);
4322 $dbo->execute();
4323 if ($dbo->getNumRows() >= 0) {
4324 $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).";";
4325 $dbo->setQuery($q);
4326 $dbo->execute();
4327
4328 $mainframe->enqueueMessage(JText::translate('VBPAYMENTUPDATED'));
4329 if ($stay) {
4330 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4331 } else {
4332 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4333 }
4334 } else {
4335 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4336 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4337 }
4338 } else {
4339 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4340 }
4341 }
4342
4343 public function removepayments()
4344 {
4345 if (!JSession::checkToken()) {
4346 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4347 }
4348
4349 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
4350 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4351 }
4352
4353 $ids = VikRequest::getVar('cid', array(0));
4354 if ($ids) {
4355 $dbo = JFactory::getDBO();
4356 foreach ($ids as $d) {
4357 $q = "DELETE FROM `#__vikbooking_gpayments` WHERE `id`=".$dbo->quote($d).";";
4358 $dbo->setQuery($q);
4359 $dbo->execute();
4360 }
4361 }
4362 $mainframe = JFactory::getApplication();
4363 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4364 }
4365
4366 public function modavailpayment() {
4367 if (!JSession::checkToken('get')) {
4368 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4369 }
4370 $cid = VikRequest::getVar('cid', array(0));
4371 $idp = $cid[0];
4372 if (!empty($idp)) {
4373 $dbo = JFactory::getDBO();
4374 $q = "SELECT `published` FROM `#__vikbooking_gpayments` WHERE `id`=".intval($idp).";";
4375 $dbo->setQuery($q);
4376 $dbo->execute();
4377 $get = $dbo->loadAssocList();
4378 $q = "UPDATE `#__vikbooking_gpayments` SET `published`=".(intval($get[0]['published']) == 1 ? '0' : '1')." WHERE `id`=".intval($idp).";";
4379 $dbo->setQuery($q);
4380 $dbo->execute();
4381 }
4382 $mainframe = JFactory::getApplication();
4383 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4384 }
4385
4386 public function seasons() {
4387 VikBookingHelper::printHeader("13");
4388
4389 VikRequest::setVar('view', VikRequest::getCmd('view', 'seasons'));
4390
4391 parent::display();
4392
4393 if (VikBooking::showFooter()) {
4394 VikBookingHelper::printFooter();
4395 }
4396 }
4397
4398 public function newseason() {
4399 VikBookingHelper::printHeader("13");
4400
4401 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4402
4403 parent::display();
4404
4405 if (VikBooking::showFooter()) {
4406 VikBookingHelper::printFooter();
4407 }
4408 }
4409
4410 public function editseason() {
4411 VikBookingHelper::printHeader("13");
4412
4413 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4414
4415 parent::display();
4416
4417 if (VikBooking::showFooter()) {
4418 VikBookingHelper::printFooter();
4419 }
4420 }
4421
4422 public function updateseason()
4423 {
4424 if (!JSession::checkToken()) {
4425 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4426 }
4427
4428 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4429 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4430 }
4431
4432 $this->do_updateseason();
4433 }
4434
4435 public function updateseasonstay()
4436 {
4437 if (!JSession::checkToken()) {
4438 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4439 }
4440
4441 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4442 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4443 }
4444
4445 $this->do_updateseason(true);
4446 }
4447
4448 private function do_updateseason($stay = false)
4449 {
4450 $app = JFactory::getApplication();
4451 $dbo = JFactory::getDbo();
4452 $session = JFactory::getSession();
4453
4454 $pwhere = VikRequest::getInt('where', 0, 'request');
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 $ppromo = VikRequest::getInt('promo', 0, 'request');
4470 $ppromo = $ppromo == 1 ? 1 : 0;
4471 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4472 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4473 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4474 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4475 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4476 $proundmode = VikRequest::getString('roundmode', '', 'request');
4477 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4478 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4479 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4480 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4481 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4482 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4483 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4484 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4485 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4486 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4487 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4488 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4489 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
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=editseason&cid[]=" . $pwhere);
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 (count($pwdays) == 0) {
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=editseason&cid[]=" . $pwhere);
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 (count($padultsdiffval) > 0) {
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 `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").";";
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 `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").";";
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 `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").";";
4643 $dbo->setQuery($q);
4644 $dbo->execute();
4645 $similar = $dbo->loadAssocList();
4646 if ($similar) {
4647 $valid = false;
4648 foreach ($similar as $sim) {
4649 $double_records[] = $sim['spname'];
4650 }
4651 }
4652 }
4653
4654 // fetch previous record before the update
4655 $q = $dbo->getQuery(true)
4656 ->select('*')
4657 ->from($dbo->qn('#__vikbooking_seasons'))
4658 ->where($dbo->qn('id') . ' = ' . $pwhere);
4659 $dbo->setQuery($q, 0, 1);
4660 $prev_record = $dbo->loadAssoc();
4661
4662 if (!$valid || !$prev_record) {
4663 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').($double_records ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4664 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4665 exit;
4666 }
4667
4668 /**
4669 * Attempt to access the promotion handlers in advance to perform additional validations.
4670 *
4671 * @since 1.16.4 (J) - 1.6.4 (WP)
4672 */
4673 try {
4674 $promo_handlers = VikBooking::getPromotionHandlers();
4675 } catch (Exception $e) {
4676 // reset the value
4677 $promo_handlers = [];
4678 }
4679
4680 if (!$prev_record['promo'] && $ppromo && $promo_handlers) {
4681 // channels supporting promotions are available, and a regular special price is
4682 // being converted into a promotion - this is not allowed so we make it a non-promotion.
4683 $ppromo = 0;
4684 $app->enqueueMessage(JText::translate('VBO_NOPROMO_UPD_CHANNELS'), 'warning');
4685 }
4686
4687 // update record
4688 $upd_record = new stdClass;
4689 $upd_record->id = $prev_record['id'];
4690 $upd_record->type = $ptype == "1" ? 1 : 2;
4691 $upd_record->from = $sfrom;
4692 $upd_record->to = $sto;
4693 $upd_record->diffcost = $pdiffcost;
4694 $upd_record->idrooms = $roomstr;
4695 $upd_record->spname = $pspname;
4696 $upd_record->wdays = $wdaystr;
4697 $upd_record->checkinincl = $pcheckinincl;
4698 $upd_record->val_pcent = $pval_pcent;
4699 $upd_record->losoverride = $losverridestr;
4700 $upd_record->roundmode = !empty($proundmode) ? $proundmode : null;
4701 $upd_record->year = $pyeartied == 1 ? $tieyear : null;
4702 $upd_record->idprices = $pricestr;
4703 $upd_record->promo = $ppromo;
4704 $upd_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4705 $upd_record->promotxt = $ppromotxt;
4706 $upd_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4707 $upd_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4708 $upd_record->promolastmin = (int)$promolastmin;
4709 $upd_record->promofinalprice = $ppromofinalprice;
4710
4711 $dbo->updateObject('#__vikbooking_seasons', $upd_record, 'id', $nulls = true);
4712
4713 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
4714
4715 // update session values
4716 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4717 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4718 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4719 } else {
4720 $updforvcm['dfrom'] = $first;
4721 }
4722 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4723 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4724 } else {
4725 $updforvcm['dto'] = $second;
4726 }
4727 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4728 foreach ($roomids as $rid) {
4729 if (!in_array($rid, $updforvcm['rooms'])) {
4730 $updforvcm['rooms'][] = $rid;
4731 }
4732 }
4733 } else {
4734 $updforvcm['rooms'] = $roomids;
4735 }
4736 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4737 foreach ($roomids as $rid) {
4738 if (array_key_exists($rid, $updforvcm['rplans'])) {
4739 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4740 } else {
4741 $updforvcm['rplans'][$rid] = $priceids;
4742 }
4743 }
4744 } else {
4745 $updforvcm['rplans'] = array();
4746 foreach ($roomids as $rid) {
4747 $updforvcm['rplans'][$rid] = $priceids;
4748 }
4749 }
4750 $session->set('vbVcmRatesUpd', $updforvcm);
4751
4752 /**
4753 * Query promotion handlers, if any, to trigger the update/delete promotion event.
4754 *
4755 * @since 1.15.0 (J) - 1.5.0 (WP)
4756 * @since 1.16.4 (J) - 1.6.4 (WP) added control to perform a delete operation.
4757 */
4758 $promo_update_type = $prev_record['promo'] && !$ppromo ? 'triggerDelete' : 'triggerUpdate';
4759 $promo_method_type = $prev_record['promo'] && !$ppromo ? 'delete' : 'update';
4760 try {
4761 if ($ppromo && is_array($promo_handlers) && $promo_handlers) {
4762 foreach ($promo_handlers as $promo_handler) {
4763 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, $promo_update_type)) {
4764 // outdated handler object
4765 continue;
4766 }
4767 if (!is_callable(array($promo_handler->instance, $promo_update_type)) || !$promo_handler->instance->{$promo_update_type}()) {
4768 // promotion handler does not support update/delete promotion event
4769 continue;
4770 }
4771 // invoke the update/delete promotion event for this handler
4772 $ch_result = $promo_handler->instance->createPromotion(['vbo_promo_id' => $pwhere], $promo_method_type);
4773 if (!$ch_result) {
4774 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
4775 }
4776 }
4777 }
4778 } catch (Exception $e) {
4779 // do nothing
4780 }
4781
4782 if ($stay) {
4783 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4784 } else {
4785 $app->redirect("index.php?option=com_vikbooking&task=seasons");
4786 }
4787 $app->close();
4788 }
4789
4790 public function createseason()
4791 {
4792 if (!JSession::checkToken()) {
4793 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4794 }
4795
4796 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4797 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4798 }
4799
4800 $this->do_createseason();
4801 }
4802
4803 public function createseason_new()
4804 {
4805 if (!JSession::checkToken()) {
4806 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4807 }
4808
4809 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4810 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4811 }
4812
4813 $this->do_createseason(true);
4814 }
4815
4816 private function do_createseason($andnew = false)
4817 {
4818 $app = JFactory::getApplication();
4819 $dbo = JFactory::getDbo();
4820 $session = JFactory::getSession();
4821
4822 $pfrom = VikRequest::getString('from', '', 'request');
4823 $pto = VikRequest::getString('to', '', 'request');
4824 $ptype = VikRequest::getString('type', '', 'request');
4825 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4826 $pidrooms = VikRequest::getVar('idrooms', array());
4827 $pidprices = VikRequest::getVar('idprices', array());
4828 $pwdays = VikRequest::getVar('wdays', array());
4829 $pspname = VikRequest::getString('spname', '', 'request');
4830 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4831 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4832 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4833 $pyeartied = $pyeartied == 1 ? 1 : 0;
4834 $tieyear = 0;
4835 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4836 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4837 $proundmode = VikRequest::getString('roundmode', '', 'request');
4838 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4839 $ppromo = VikRequest::getInt('promo', 0, 'request');
4840 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4841 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4842 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4843 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4844 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4845 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4846 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4847 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4848 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4849 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4850 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4851 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4852 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4853 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4854 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4855 $pchannels = VikRequest::getVar('channels', array());
4856 $occupancy_ovr = array();
4857 $losverridestr = "";
4858
4859 $updforvcm = $session->get('vbVcmRatesUpd', '');
4860 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4861
4862 // check null dates
4863 if ($dbo->getNullDate() == $pfrom) {
4864 $pfrom = '';
4865 }
4866 if ($dbo->getNullDate() == $pto) {
4867 $pto = '';
4868 }
4869
4870 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4871 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4872 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4873 exit;
4874 }
4875
4876 $skipseason = false;
4877 if (empty($pfrom) || empty($pto)) {
4878 $skipseason = true;
4879 }
4880 $skipdays = false;
4881 $wdaystr = null;
4882 if (!$pwdays) {
4883 $skipdays = true;
4884 } else {
4885 $wdaystr = "";
4886 foreach ($pwdays as $wd) {
4887 $wdaystr .= $wd.';';
4888 }
4889 }
4890 $roomstr = "";
4891 $roomids = array();
4892 foreach ($pidrooms as $room) {
4893 if (empty($room)) {
4894 continue;
4895 }
4896 $roomstr .= "-".$room."-,";
4897 $roomids[] = (int)$room;
4898 }
4899 $pricestr = "";
4900 $priceids = array();
4901 foreach ($pidprices as $price) {
4902 if (empty($price)) {
4903 continue;
4904 }
4905 $pricestr .= "-".$price."-,";
4906 $priceids[] = (int)$price;
4907 }
4908 $valid = true;
4909 $double_records = array();
4910 $sfrom = null;
4911 $sto = null;
4912
4913 // value overrides
4914 if ($pnightsoverrides && $pvaluesoverrides) {
4915 foreach ($pnightsoverrides as $ko => $no) {
4916 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4917 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4918 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4919 }
4920 }
4921 }
4922
4923 if (!$skipseason) {
4924 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4925 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4926
4927 if ($second > 0 && $second == $first) {
4928 $second += 86399;
4929 }
4930
4931 if (!($second > $first)) {
4932 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4933 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4934 exit;
4935 }
4936
4937 $baseone = getdate($first);
4938 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4939 $sfrom = $baseone[0] - $basets;
4940 $basetwo = getdate($second);
4941 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4942 $sto = $basetwo[0] - $basets;
4943
4944 // check leap year
4945 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4946 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4947 if ($baseone[0] > $leapts) {
4948 $sfrom -= 86400;
4949 /**
4950 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4951 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4952 *
4953 * @since July 2nd 2019
4954 */
4955 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4956 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4957 if ($basetwo[0] > $leapts) {
4958 $sto -= date('d-m', $baseone[0]) != '31-12' && date('d-m', $basetwo[0]) == '31-12' ? 1 : 86400;
4959 }
4960 }
4961 }
4962 }
4963
4964 // tied to the year
4965 if ($pyeartied == 1) {
4966 $tieyear = $baseone['year'];
4967 }
4968
4969 // Occupancy Override
4970 if ($padultsdiffval) {
4971 foreach ($padultsdiffval as $rid => $valovr_arr) {
4972 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4973 continue;
4974 }
4975 foreach ($valovr_arr as $occ => $valovr) {
4976 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4977 continue;
4978 }
4979 if (!array_key_exists($rid, $occupancy_ovr)) {
4980 $occupancy_ovr[$rid] = array();
4981 }
4982 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4983 }
4984 }
4985 }
4986
4987 // check if seasons dates are valid
4988 $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").";";
4989 $dbo->setQuery($q);
4990 $similar = $dbo->loadAssocList();
4991 if ($similar) {
4992 $valid = false;
4993 foreach ($similar as $sim) {
4994 $double_records[] = $sim['spname'];
4995 }
4996 }
4997
4998 $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").";";
4999 $dbo->setQuery($q);
5000 $similar = $dbo->loadAssocList();
5001 if ($similar) {
5002 $valid = false;
5003 foreach ($similar as $sim) {
5004 $double_records[] = $sim['spname'];
5005 }
5006 }
5007
5008 $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").";";
5009 $dbo->setQuery($q);
5010 $similar = $dbo->loadAssocList();
5011 if ($similar) {
5012 $valid = false;
5013 foreach ($similar as $sim) {
5014 $double_records[] = $sim['spname'];
5015 }
5016 }
5017 }
5018
5019 if (!$valid && !$ppromo) {
5020 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').(count($double_records) ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
5021 $app->redirect("index.php?option=com_vikbooking&task=newseason");
5022 exit;
5023 }
5024
5025 // insert new record
5026 $sea_record = new stdClass;
5027 $sea_record->type = $ptype == "1" ? 1 : 2;
5028 $sea_record->from = $sfrom;
5029 $sea_record->to = $sto;
5030 $sea_record->diffcost = $pdiffcost;
5031 $sea_record->idrooms = $roomstr;
5032 $sea_record->spname = $pspname;
5033 $sea_record->wdays = $wdaystr;
5034 $sea_record->checkinincl = $pcheckinincl;
5035 $sea_record->val_pcent = $pval_pcent;
5036 $sea_record->losoverride = $losverridestr;
5037 $sea_record->roundmode = !empty($proundmode) ? $proundmode : null;
5038 $sea_record->year = $pyeartied == 1 ? $tieyear : null;
5039 $sea_record->idprices = $pricestr;
5040 $sea_record->promo = $ppromo == 1 ? 1 : 0;
5041 $sea_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
5042 $sea_record->promotxt = $ppromotxt;
5043 $sea_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
5044 $sea_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
5045 $sea_record->promolastmin = (int)$promolastmin;
5046 $sea_record->promofinalprice = $ppromofinalprice;
5047
5048 $dbo->insertObject('#__vikbooking_seasons', $sea_record, 'id');
5049
5050 $vbo_promo_id = $sea_record->id;
5051
5052 $app->enqueueMessage(JText::translate('VBSEASONSAVED'));
5053
5054 // update session values
5055 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5056 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5057 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
5058 } else {
5059 $updforvcm['dfrom'] = $first;
5060 }
5061 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5062 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
5063 } else {
5064 $updforvcm['dto'] = $second;
5065 }
5066 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5067 foreach ($roomids as $rid) {
5068 if (!in_array($rid, $updforvcm['rooms'])) {
5069 $updforvcm['rooms'][] = $rid;
5070 }
5071 }
5072 } else {
5073 $updforvcm['rooms'] = $roomids;
5074 }
5075 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
5076 foreach ($roomids as $rid) {
5077 if (array_key_exists($rid, $updforvcm['rplans'])) {
5078 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
5079 } else {
5080 $updforvcm['rplans'][$rid] = $priceids;
5081 }
5082 }
5083 } else {
5084 $updforvcm['rplans'] = array();
5085 foreach ($roomids as $rid) {
5086 $updforvcm['rplans'][$rid] = $priceids;
5087 }
5088 }
5089 if (!$ppromo) {
5090 $session->set('vbVcmRatesUpd', $updforvcm);
5091 }
5092
5093 /**
5094 * Create the promotion also on the selected channels
5095 *
5096 * @since 1.13.0 (J) - 1.3.0 (WP)
5097 */
5098 if ($ppromo && $pchannels) {
5099 foreach ($pchannels as $channel_key) {
5100 $promo_obj = VikBooking::getPromotionHandlers($channel_key);
5101 if (!is_object($promo_obj)) {
5102 continue;
5103 }
5104 /**
5105 * We inject for VCM the ID of the newly created promotion in VBO.
5106 *
5107 * @since 1.15.0 (J) - 1.5.0 (WP)
5108 */
5109 $ch_result = $promo_obj->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'new');
5110 if (!$ch_result) {
5111 VikError::raiseWarning('', $promo_obj->getName() . ': ' . $promo_obj->getError());
5112 } else {
5113 $resp = $promo_obj->getResponse();
5114 $app->enqueueMessage($promo_obj->getName() . ': ' . JText::translate('VBOCHPROMOSUCCESS') . (!empty($resp) ? ' (' . str_replace('e4j.ok.', '', $resp) . ')' : ''));
5115 // in case of success, unset the current session values in VCM
5116 $session->set('vcmBPromo', '');
5117 }
5118 }
5119 }
5120
5121 $app->redirect("index.php?option=com_vikbooking&task=".($andnew ? 'newseason' : 'seasons'));
5122 $app->close();
5123 }
5124
5125 public function removeseasons()
5126 {
5127 if (!JSession::checkToken()) {
5128 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5129 }
5130
5131 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5132 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5133 }
5134
5135 $app = JFactory::getApplication();
5136 $dbo = JFactory::getDbo();
5137
5138 $ids = VikRequest::getVar('cid', array(0));
5139 $pidroom = VikRequest::getInt('idroom', '', 'request');
5140 $pwhere = VikRequest::getInt('where', '', 'request');
5141 if (!empty($pwhere)) {
5142 $ids[] = $pwhere;
5143 }
5144 $tot_removed = array();
5145 $prev_promos = array();
5146 foreach ($ids as $d) {
5147 if (empty($d)) {
5148 continue;
5149 }
5150 // check if it was a promotion
5151 $q = "SELECT `id` FROM `#__vikbooking_seasons` WHERE `id`=" . (int)$d . " AND `promo`=1;";
5152 $dbo->setQuery($q);
5153 $dbo->execute();
5154 if ($dbo->getNumRows()) {
5155 // push it as a previous promo
5156 array_push($prev_promos, $d);
5157 }
5158
5159 // delete the record
5160 $q = "DELETE FROM `#__vikbooking_seasons` WHERE `id`=".$dbo->quote($d).";";
5161 $dbo->setQuery($q);
5162 $dbo->execute();
5163 $tot_removed[] = $d;
5164 }
5165
5166 /**
5167 * Query promotion handlers, if any, to trigger the delete promotion event.
5168 *
5169 * @since 1.15.0 (J) - 1.5.0 (WP)
5170 */
5171 $promo_handlers = VikBooking::getPromotionHandlers();
5172 foreach ($prev_promos as $vbo_promo_id) {
5173 try {
5174 if (is_array($promo_handlers)) {
5175 foreach ($promo_handlers as $promo_handler) {
5176 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, 'triggerDelete')) {
5177 // outdated handler object
5178 continue;
5179 }
5180 if (!is_callable(array($promo_handler->instance, 'triggerDelete')) || !$promo_handler->instance->triggerDelete()) {
5181 // promotion handler does not support delete promotion event
5182 continue;
5183 }
5184 // invoke the delete promotion event for this handler
5185 $ch_result = $promo_handler->instance->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'delete');
5186 if (!$ch_result) {
5187 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
5188 }
5189 }
5190 }
5191 } catch (Exception $e) {
5192 // do nothing
5193 }
5194 }
5195
5196 $app->enqueueMessage(JText::sprintf('VBRECORDSREMOVED', count($tot_removed)));
5197 $app->redirect("index.php?option=com_vikbooking&task=seasons".(!empty($pidroom) ? '&idroom='.$pidroom : ''));
5198 $app->close();
5199 }
5200
5201 public function updatecustomer()
5202 {
5203 if (!JSession::checkToken()) {
5204 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5205 }
5206
5207 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5208 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5209 }
5210
5211 $this->do_updatecustomer();
5212 }
5213
5214 public function updatecustomerstay()
5215 {
5216 if (!JSession::checkToken()) {
5217 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5218 }
5219
5220 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5221 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5222 }
5223
5224 $this->do_updatecustomer(true);
5225 }
5226
5227 private function do_updatecustomer($stay = false) {
5228 $dbo = JFactory::getDbo();
5229 $mainframe = JFactory::getApplication();
5230 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5231 $plast_name = VikRequest::getString('last_name', '', 'request');
5232 $pcompany = VikRequest::getString('company', '', 'request');
5233 $pvat = VikRequest::getString('vat', '', 'request');
5234 $pemail = VikRequest::getString('email', '', 'request');
5235 $pphone = VikRequest::getString('phone', '', 'request');
5236 $pcountry = VikRequest::getString('country', '', 'request');
5237 $pstate = VikRequest::getString('state', '', 'request');
5238 $ppin = VikRequest::getString('pin', '', 'request');
5239 $pujid = VikRequest::getInt('ujid', '', 'request');
5240 $paddress = VikRequest::getString('address', '', 'request');
5241 $pcity = VikRequest::getString('city', '', 'request');
5242 $pzip = VikRequest::getString('zip', '', 'request');
5243 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5244 $ppec = VikRequest::getString('pec', '', 'request');
5245 $precipcode = VikRequest::getString('recipcode', '', 'request');
5246 $pgender = VikRequest::getString('gender', '', 'request');
5247 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5248 $pbdate = VikRequest::getString('bdate', '', 'request');
5249 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5250 $pdoctype = VikRequest::getString('doctype', '', 'request');
5251 $pdocnum = VikRequest::getString('docnum', '', 'request');
5252 $pnotes = VikRequest::getString('notes', '', 'request');
5253 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5254 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5255 $pcommission = VikRequest::getFloat('commission', '', 'request');
5256 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5257 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5258 $pchname = VikRequest::getString('chname', '', 'request');
5259 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5260 $pwhere = VikRequest::getInt('where', '', 'request');
5261 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5262 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5263 $pbid = VikRequest::getInt('bid', '', 'request');
5264 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5265 if (!empty($pwhere) && !empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5266 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `id`=".(int)$pwhere." LIMIT 1;";
5267 $dbo->setQuery($q);
5268 $dbo->execute();
5269 if ($dbo->getNumRows() == 1) {
5270 $customer = $dbo->loadAssoc();
5271 } else {
5272 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5273 exit;
5274 }
5275 /**
5276 * Existing customers are recognized by equal first name, last name and email address.
5277 *
5278 * @since 1.3.0
5279 */
5280 $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;";
5281 $dbo->setQuery($q);
5282 $dbo->execute();
5283 if ($dbo->getNumRows() == 0) {
5284 $cpin = VikBooking::getCPinIstance();
5285 if (empty($ppin)) {
5286 $ppin = $customer['pin'];
5287 } elseif ($cpin->pinExists($ppin, $customer['pin'])) {
5288 $ppin = $cpin->generateUniquePin();
5289 }
5290 //file upload
5291 jimport('joomla.filesystem.file');
5292 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5293 $gimg = "";
5294 if (isset($pimg) && strlen(trim($pimg['name']))) {
5295 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5296 $src = $pimg['tmp_name'];
5297 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5298 $j = "";
5299 if (file_exists($dest.$filename)) {
5300 $j = rand(171, 1717);
5301 while (file_exists($dest.$j.$filename)) {
5302 $j++;
5303 }
5304 }
5305 $finaldest = $dest.$j.$filename;
5306 $check = getimagesize($pimg['tmp_name']);
5307 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5308 if (VikBooking::uploadFile($src, $finaldest)) {
5309 $gimg = $j.$filename;
5310 } else {
5311 VikError::raiseWarning('', 'Error while uploading image');
5312 }
5313 } else {
5314 VikError::raiseWarning('', 'Uploaded file is not an Image');
5315 }
5316 } elseif (!empty($pscandocimg)) {
5317 $gimg = $pscandocimg;
5318 }
5319 //
5320 $pischannel = $pischannel > 0 ? 1 : 0;
5321 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5322 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5323 $pchname = str_replace(' ', '', trim($pchname));
5324 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5325 $chparams = array(
5326 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5327 'calccmmon' => $pcalccmmon,
5328 'applycmmon' => $papplycmmon,
5329 'chcolor' => $pchcolor,
5330 'chname' => $pchname
5331 );
5332
5333 /**
5334 * Customer profile picture (URL or uploaded file).
5335 *
5336 * @since 1.15.3 (J) - 1.5.5 (WP)
5337 */
5338 $customer_pic = VikRequest::getString('pic', '', 'request');
5339 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5340 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5341 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5342 $src = $customer_pic_img['tmp_name'];
5343 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5344 $j = "";
5345 if (is_file($dest.$filename)) {
5346 $j = rand(1, 99999);
5347 while (is_file($dest . $j .$filename)) {
5348 $j++;
5349 }
5350 }
5351 $finaldest = $dest . $j . $filename;
5352 $check = getimagesize($customer_pic_img['tmp_name']);
5353 if (($check[2] & imagetypes())) {
5354 if (VikBooking::uploadFile($src, $finaldest)) {
5355 $customer_pic = $j . $filename;
5356 } else {
5357 VikError::raiseWarning('', 'Error while uploading image');
5358 }
5359 } else {
5360 VikError::raiseWarning('', 'Uploaded file is not an Image');
5361 }
5362 }
5363
5364 // update customer object
5365 $new_customer = new stdClass;
5366 $new_customer->id = (int)$pwhere;
5367 $new_customer->first_name = $pfirst_name;
5368 $new_customer->last_name = $plast_name;
5369 $new_customer->email = $pemail;
5370 $new_customer->phone = $pphone;
5371 $new_customer->country = $pcountry;
5372 $new_customer->pin = $ppin;
5373 $new_customer->ujid = $pujid;
5374 $new_customer->address = $paddress;
5375 $new_customer->city = $pcity;
5376 $new_customer->zip = $pzip;
5377 $new_customer->state = $pstate;
5378 $new_customer->doctype = $pdoctype;
5379 $new_customer->docnum = $pdocnum;
5380 if (!empty($gimg)) {
5381 $new_customer->docimg = $gimg;
5382 }
5383 $new_customer->notes = $pnotes;
5384 $new_customer->ischannel = $pischannel;
5385 $new_customer->chdata = json_encode($chparams);
5386 $new_customer->company = $pcompany;
5387 $new_customer->vat = $pvat;
5388 $new_customer->gender = $pgender;
5389 $new_customer->bdate = $pbdate;
5390 $new_customer->pbirth = $ppbirth;
5391 $new_customer->fisccode = $pfisccode;
5392 $new_customer->pec = $ppec;
5393 $new_customer->recipcode = $precipcode;
5394 $new_customer->pic = $customer_pic;
5395 /**
5396 * We need to update the previous information stored through
5397 * the custom fields when making a reservation for/by this client.
5398 *
5399 * @since 1.13
5400 */
5401 $skip_prev_fields = array(
5402 'id',
5403 'ujid',
5404 'docimg',
5405 'ischannel',
5406 'chdata',
5407 'notes',
5408 );
5409 if (!empty($customer['cfields'])) {
5410 $custf_info = json_decode($customer['cfields'], true);
5411 foreach ($new_customer as $fname => $fnewval) {
5412 if (!isset($customer[$fname]) || in_array($fname, $skip_prev_fields)) {
5413 continue;
5414 }
5415 // seek for old value in custom fields submitted
5416 foreach ($custf_info as $k => $v) {
5417 if (!empty($customer[$fname]) && $v == $customer[$fname]) {
5418 // field found, replace it with the new value
5419 $custf_info[$k] = $fnewval;
5420 }
5421 }
5422 }
5423 // update value on db
5424 $new_customer->cfields = json_encode($custf_info);
5425 }
5426
5427 // trigger the customer before-update event
5428 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = true);
5429
5430 // update customer record
5431 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5432
5433 // trigger the customer after-save event
5434 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = false);
5435
5436 // update all the bookings affected by this Customer ID as a sales channel
5437 $source_name = 'customer'.$pwhere.'_'.$pchname;
5438 if ($pischannel > 0) {
5439 $oid_clause = '';
5440 if ($customer['ischannel'] < 1) {
5441 //Was not a sales channel but now it is, so update all his bookings
5442 $q = "SELECT `o`.`idorderota`, `co`.`idorder`
5443 FROM `#__vikbooking_customers_orders` AS `co`
5444 LEFT JOIN `#__vikbooking_orders` AS `o` ON `co`.`idorder`=`o`.`id`
5445 WHERE `co`.`idcustomer`=".$customer['id'].";";
5446 $dbo->setQuery($q);
5447 $all_bids = $dbo->loadAssocList();
5448 if ($all_bids) {
5449 $bids = array();
5450 foreach ($all_bids as $bid) {
5451 if (empty($idorderota) && !in_array($bid['idorder'], $bids)) {
5452 $bids[] = $bid['idorder'];
5453 }
5454 }
5455 if ($bids) {
5456 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5457 }
5458 }
5459 }
5460 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5461 } else {
5462 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5463 }
5464 $dbo->setQuery($q);
5465 $dbo->execute();
5466 //
5467 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5468 } else {
5469 //email already exists
5470 $ex_customer = $dbo->loadAssoc();
5471 //check if coming from the Check-in view or not
5472 if (!empty($pcheckin) && !empty($pbid)) {
5473 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5474 /**
5475 * @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
5476 */
5477 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5478 //
5479 exit;
5480 } elseif (!empty($pgoto)) {
5481 // check if coming from a specific task
5482 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5483 $mainframe->redirect(base64_decode($pgoto));
5484 exit;
5485 } else {
5486 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>');
5487 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5488 exit;
5489 }
5490 }
5491 }
5492
5493 //check if coming from the Check-in view
5494 if (!empty($pcheckin) && !empty($pbid)) {
5495 /**
5496 * @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
5497 */
5498 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5499 exit;
5500 }
5501
5502 if ($stay) {
5503 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5504 exit;
5505 }
5506
5507 // check if coming from a specific task
5508 if (!empty($pgoto)) {
5509 $mainframe->redirect(base64_decode($pgoto));
5510 exit;
5511 }
5512
5513 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5514 }
5515
5516 public function savecustomer() {
5517 if (!JSession::checkToken()) {
5518 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5519 }
5520 $dbo = JFactory::getDbo();
5521 $mainframe = JFactory::getApplication();
5522 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5523 $plast_name = VikRequest::getString('last_name', '', 'request');
5524 $pcompany = VikRequest::getString('company', '', 'request');
5525 $pvat = VikRequest::getString('vat', '', 'request');
5526 $pemail = VikRequest::getString('email', '', 'request');
5527 $pphone = VikRequest::getString('phone', '', 'request');
5528 $pcountry = VikRequest::getString('country', '', 'request');
5529 $pstate = VikRequest::getString('state', '', 'request');
5530 $ppin = VikRequest::getString('pin', '', 'request');
5531 $pujid = VikRequest::getInt('ujid', '', 'request');
5532 $paddress = VikRequest::getString('address', '', 'request');
5533 $pcity = VikRequest::getString('city', '', 'request');
5534 $pzip = VikRequest::getString('zip', '', 'request');
5535 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5536 $ppec = VikRequest::getString('pec', '', 'request');
5537 $precipcode = VikRequest::getString('recipcode', '', 'request');
5538 $pgender = VikRequest::getString('gender', '', 'request');
5539 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5540 $pbdate = VikRequest::getString('bdate', '', 'request');
5541 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5542 $pdoctype = VikRequest::getString('doctype', '', 'request');
5543 $pdocnum = VikRequest::getString('docnum', '', 'request');
5544 $pnotes = VikRequest::getString('notes', '', 'request');
5545 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5546 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5547 $pcommission = VikRequest::getFloat('commission', '', 'request');
5548 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5549 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5550 $pchname = VikRequest::getString('chname', '', 'request');
5551 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5552 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5553 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5554 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5555 $pbid = VikRequest::getInt('bid', '', 'request');
5556 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5557 $cpin = VikBooking::getCPinIstance();
5558 /**
5559 * Existing customers are recognized by equal first name, last name and email address.
5560 *
5561 * @since 1.3.0
5562 */
5563 $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;";
5564 $dbo->setQuery($q);
5565 $dbo->execute();
5566 if ($dbo->getNumRows() == 0) {
5567 if (empty($ppin)) {
5568 $ppin = $cpin->generateUniquePin();
5569 } elseif ($cpin->pinExists($ppin)) {
5570 $ppin = $cpin->generateUniquePin();
5571 }
5572 //file upload
5573 jimport('joomla.filesystem.file');
5574 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5575 $gimg = "";
5576 if (isset($pimg) && strlen(trim($pimg['name']))) {
5577 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5578 $src = $pimg['tmp_name'];
5579 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5580 $j = "";
5581 if (file_exists($dest.$filename)) {
5582 $j = rand(171, 1717);
5583 while (file_exists($dest.$j.$filename)) {
5584 $j++;
5585 }
5586 }
5587 $finaldest = $dest.$j.$filename;
5588 $check = getimagesize($pimg['tmp_name']);
5589 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5590 if (VikBooking::uploadFile($src, $finaldest)) {
5591 $gimg = $j.$filename;
5592 } else {
5593 VikError::raiseWarning('', 'Error while uploading image');
5594 }
5595 } else {
5596 VikError::raiseWarning('', 'Uploaded file is not an Image');
5597 }
5598 } elseif (!empty($pscandocimg)) {
5599 $gimg = $pscandocimg;
5600 }
5601 //
5602 $pischannel = $pischannel > 0 ? 1 : 0;
5603 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5604 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5605 $pchname = str_replace(' ', '', trim($pchname));
5606 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5607 $chparams = array(
5608 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5609 'calccmmon' => $pcalccmmon,
5610 'applycmmon' => $papplycmmon,
5611 'chcolor' => $pchcolor,
5612 'chname' => $pchname
5613 );
5614
5615 /**
5616 * Customer profile picture (URL or uploaded file).
5617 *
5618 * @since 1.15.3 (J) - 1.5.5 (WP)
5619 */
5620 $customer_pic = VikRequest::getString('pic', '', 'request');
5621 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5622 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5623 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5624 $src = $customer_pic_img['tmp_name'];
5625 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5626 $j = "";
5627 if (is_file($dest.$filename)) {
5628 $j = rand(1, 99999);
5629 while (is_file($dest . $j .$filename)) {
5630 $j++;
5631 }
5632 }
5633 $finaldest = $dest . $j . $filename;
5634 $check = getimagesize($customer_pic_img['tmp_name']);
5635 if (($check[2] & imagetypes())) {
5636 if (VikBooking::uploadFile($src, $finaldest)) {
5637 $customer_pic = $j . $filename;
5638 } else {
5639 VikError::raiseWarning('', 'Error while uploading image');
5640 }
5641 } else {
5642 VikError::raiseWarning('', 'Uploaded file is not an Image');
5643 }
5644 }
5645
5646 // build customer record
5647 $customer_obj = new stdClass;
5648 $customer_obj->first_name = $pfirst_name;
5649 $customer_obj->last_name = $plast_name;
5650 $customer_obj->email = $pemail;
5651 $customer_obj->phone = $pphone;
5652 $customer_obj->country = $pcountry;
5653 $customer_obj->pin = $ppin;
5654 $customer_obj->ujid = $pujid;
5655 $customer_obj->address = $paddress;
5656 $customer_obj->city = $pcity;
5657 $customer_obj->zip = $pzip;
5658 $customer_obj->state = $pstate;
5659 $customer_obj->doctype = $pdoctype;
5660 $customer_obj->docnum = $pdocnum;
5661 $customer_obj->docimg = $gimg;
5662 $customer_obj->notes = $pnotes;
5663 $customer_obj->ischannel = $pischannel;
5664 $customer_obj->chdata = json_encode($chparams);
5665 $customer_obj->company = $pcompany;
5666 $customer_obj->vat = $pvat;
5667 $customer_obj->gender = $pgender;
5668 $customer_obj->bdate = $pbdate;
5669 $customer_obj->pbirth = $ppbirth;
5670 $customer_obj->fisccode = $pfisccode;
5671 $customer_obj->pec = $ppec;
5672 $customer_obj->recipcode = $precipcode;
5673 $customer_obj->pic = !empty($customer_pic) ? $customer_pic : null;
5674
5675 // trigger the customer before-insert event
5676 $cpin->pluginCustomerSync(0, 'insert', (array)$customer_obj, $before = true);
5677
5678 // insert the new customer record
5679 $dbo->insertObject('#__vikbooking_customers', $customer_obj, 'id');
5680 $lid = isset($customer_obj->id) ? $customer_obj->id : null;
5681
5682 // trigger the customer after-save event
5683 $cpin->pluginCustomerSync($lid, 'insert', (array)$customer_obj, $before = false);
5684
5685 if (!empty($lid)) {
5686 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5687 //check if coming from the Check-in view
5688 if (!empty($pcheckin) && !empty($pbid)) {
5689 $cpin->setNewPin($ppin);
5690 $cpin->setNewCustomerId($lid);
5691 $cpin->saveCustomerBooking($pbid);
5692 /**
5693 * @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
5694 */
5695 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5696 //
5697 exit;
5698 }
5699 // check if coming from a specific task
5700 if (!empty($pgoto) && !empty($pbid)) {
5701 $cpin->setNewPin($ppin);
5702 $cpin->setNewCustomerId($lid);
5703 $cpin->saveCustomerBooking($pbid);
5704 $mainframe->redirect(base64_decode($pgoto));
5705 exit;
5706 }
5707 }
5708 } else {
5709 //email already exists
5710 $ex_customer = $dbo->loadAssoc();
5711 //check if coming from the Check-in view or not
5712 if (!empty($pcheckin) && !empty($pbid)) {
5713 $cpin->setNewPin($ex_customer['pin']);
5714 $cpin->setNewCustomerId($ex_customer['id']);
5715 $cpin->saveCustomerBooking($pbid);
5716 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5717 /**
5718 * @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
5719 */
5720 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5721 //
5722 exit;
5723 } elseif (!empty($pgoto) && !empty($pbid)) {
5724 // check if coming from a specific task
5725 $cpin->setNewPin($ex_customer['pin']);
5726 $cpin->setNewCustomerId($ex_customer['id']);
5727 $cpin->saveCustomerBooking($pbid);
5728 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5729 $mainframe->redirect(base64_decode($pgoto));
5730 exit;
5731 } else {
5732 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>');
5733 }
5734 }
5735 }
5736 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5737 }
5738
5739 public function customers() {
5740 VikBookingHelper::printHeader("22");
5741
5742 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5743
5744 parent::display();
5745
5746 if (VikBooking::showFooter()) {
5747 VikBookingHelper::printFooter();
5748 }
5749 }
5750
5751 public function newcustomer() {
5752 VikBookingHelper::printHeader("22");
5753
5754 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5755
5756 parent::display();
5757
5758 if (VikBooking::showFooter()) {
5759 VikBookingHelper::printFooter();
5760 }
5761 }
5762
5763 public function editcustomer() {
5764 VikBookingHelper::printHeader("22");
5765
5766 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5767
5768 parent::display();
5769
5770 if (VikBooking::showFooter()) {
5771 VikBookingHelper::printFooter();
5772 }
5773 }
5774
5775 public function removecustomers()
5776 {
5777 if (!JSession::checkToken()) {
5778 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5779 }
5780
5781 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5782 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5783 }
5784
5785 $ids = VikRequest::getVar('cid', array(0));
5786 if ($ids) {
5787 $dbo = JFactory::getDBO();
5788 $cpin = VikBooking::getCPinIstance();
5789 foreach ($ids as $d) {
5790 $cpin->pluginCustomerSync($d, 'delete');
5791 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5792 $dbo->setQuery($q);
5793 $dbo->execute();
5794 }
5795 }
5796 $mainframe = JFactory::getApplication();
5797 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5798 }
5799
5800 public function restrictions() {
5801 VikBookingHelper::printHeader("restrictions");
5802
5803 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5804
5805 parent::display();
5806
5807 if (VikBooking::showFooter()) {
5808 VikBookingHelper::printFooter();
5809 }
5810 }
5811
5812 public function newrestriction() {
5813 VikBookingHelper::printHeader("restrictions");
5814
5815 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5816
5817 parent::display();
5818
5819 if (VikBooking::showFooter()) {
5820 VikBookingHelper::printFooter();
5821 }
5822 }
5823
5824 public function editrestriction() {
5825 VikBookingHelper::printHeader("restrictions");
5826
5827 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5828
5829 parent::display();
5830
5831 if (VikBooking::showFooter()) {
5832 VikBookingHelper::printFooter();
5833 }
5834 }
5835
5836 public function createrestriction()
5837 {
5838 if (!JSession::checkToken()) {
5839 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5840 }
5841
5842 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5843 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5844 }
5845
5846 $dbo = JFactory::getDBO();
5847 $session = JFactory::getSession();
5848 $mainframe = JFactory::getApplication();
5849 $updforvcm = $session->get('vbVcmRatesUpd', '');
5850 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5851 $pname = VikRequest::getString('name', '', 'request');
5852 $pmonth = VikRequest::getInt('month', '', 'request');
5853 $pmonth = empty($pmonth) ? 0 : $pmonth;
5854 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5855 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5856 $pdto = VikRequest::getString('dto', '', 'request');
5857 $pwday = VikRequest::getString('wday', '', 'request');
5858 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5859 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5860 $pcomboa = VikRequest::getString('comboa', '', 'request');
5861 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5862 $pcombob = VikRequest::getString('combob', '', 'request');
5863 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5864 $pcomboc = VikRequest::getString('comboc', '', 'request');
5865 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5866 $pcombod = VikRequest::getString('combod', '', 'request');
5867 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5868 $combostr = '';
5869 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5870 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5871 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5872 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5873 $pminlos = VikRequest::getInt('minlos', '', 'request');
5874 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5875 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5876 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5877 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5878 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5879 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5880 $pallrooms = $pallrooms == "1" ? 1 : 0;
5881 $pidrooms = VikRequest::getVar('idrooms', array(0));
5882 $ridr = '';
5883 $roomidsforsess = array();
5884 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5885 foreach ($pidrooms as $idr) {
5886 if (empty($idr)) {
5887 continue;
5888 }
5889 $ridr .= '-'.$idr.'-;';
5890 $roomidsforsess[] = (int)$idr;
5891 }
5892 } elseif ($pallrooms > 0) {
5893 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5894 $dbo->setQuery($q);
5895 $dbo->execute();
5896 if ($dbo->getNumRows() > 0) {
5897 $fetchids = $dbo->loadAssocList();
5898 foreach ($fetchids as $fetchid) {
5899 $roomidsforsess[] = (int)$fetchid['id'];
5900 }
5901 }
5902 }
5903 $pcta = VikRequest::getInt('cta', '', 'request');
5904 $pctd = VikRequest::getInt('ctd', '', 'request');
5905 $pctad = VikRequest::getVar('ctad', array());
5906 $pctdd = VikRequest::getVar('ctdd', array());
5907 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5908 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5909 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5910 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5911 // exit;
5912 }
5913
5914 //check if there are restrictions for this month
5915 if ($pmonth > 0) {
5916 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5917 $dbo->setQuery($q);
5918 $dbo->execute();
5919 if ($dbo->getNumRows() > 0) {
5920 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5921 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5922 exit;
5923 }
5924 $pdfrom = 0;
5925 $pdto = 0;
5926 } else {
5927 //dates range
5928 if (empty($pdfrom) || empty($pdto)) {
5929 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5930 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5931 exit;
5932 } else {
5933 $housto = $pdfrom == $pdto ? 23 : 0;
5934 $minsto = $pdfrom == $pdto ? 59 : 0;
5935 $secsto = $pdfrom == $pdto ? 59 : 0;
5936 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5937 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5938 }
5939 if ($pdfrom > $pdto) {
5940 // invalid dates in the past
5941 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5942 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5943 exit;
5944 }
5945 }
5946 //CTA and CTD
5947 $setcta = array();
5948 $setctd = array();
5949 if ($pcta > 0 && count($pctad) > 0) {
5950 foreach ($pctad as $ctwd) {
5951 if (strlen($ctwd)) {
5952 $setcta[] = '-'.(int)$ctwd.'-';
5953 }
5954 }
5955 }
5956 if ($pctd > 0 && count($pctdd) > 0) {
5957 foreach ($pctdd as $ctwd) {
5958 if (strlen($ctwd)) {
5959 $setctd[] = '-'.(int)$ctwd.'-';
5960 }
5961 }
5962 }
5963 //
5964 //update session values
5965 if (!($pdfrom > 0)) {
5966 $attemptyear = (int)date('Y');
5967 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5968 if ($attemptfrom < time()) {
5969 $attemptyear++;
5970 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5971 }
5972 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5973 } else {
5974 $attemptfrom = $pdfrom;
5975 $attemptto = $pdto;
5976 }
5977 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5978 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5979 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5980 } else {
5981 $updforvcm['dfrom'] = $attemptfrom;
5982 }
5983 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5984 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5985 } else {
5986 $updforvcm['dto'] = $attemptto;
5987 }
5988 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5989 foreach ($roomidsforsess as $rid) {
5990 if (!in_array($rid, $updforvcm['rooms'])) {
5991 $updforvcm['rooms'][] = $rid;
5992 }
5993 }
5994 } else {
5995 $updforvcm['rooms'] = $roomidsforsess;
5996 }
5997 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5998 $updforvcm['rplans'] = array();
5999 }
6000 $session->set('vbVcmRatesUpd', $updforvcm);
6001 //
6002 $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").");";
6003 $dbo->setQuery($q);
6004 $dbo->execute();
6005 $lid = $dbo->insertid();
6006 if (!empty($lid)) {
6007 /**
6008 * Repeat restriction on the selected week days until the limit
6009 *
6010 * @since 1.13
6011 */
6012 $prepeat = VikRequest::getInt('repeat', 0, 'request');
6013 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
6014 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
6015 $repeat_intervals = array();
6016 $start = getdate($pdfrom);
6017 $end = getdate($pdto);
6018 $wdays = array();
6019 while ($start[0] <= $end[0]) {
6020 // push requested week day
6021 array_push($wdays, $start['wday']);
6022 // next day
6023 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
6024 }
6025 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
6026 if (count($wdays) < 7 && $dtuntil > $pdto) {
6027 // increment end date for the repeat
6028 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
6029 //
6030 $until_info = getdate($dtuntil);
6031 $interval = array();
6032 while ($end[0] <= $until_info[0]) {
6033 if (in_array($end['wday'], $wdays)) {
6034 if (!isset($interval['from'])) {
6035 $interval['from'] = $end[0];
6036 }
6037 $interval['to'] = $end[0];
6038 } else {
6039 if (isset($interval['from'])) {
6040 // append interval
6041 array_push($repeat_intervals, $interval);
6042 // reset interval
6043 $interval = array();
6044 }
6045 }
6046 // next day
6047 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
6048 }
6049 if (isset($interval['from'])) {
6050 // append last hanging interval
6051 array_push($repeat_intervals, $interval);
6052 }
6053 if (count($repeat_intervals)) {
6054 // create the repeated records for the calculated intervals
6055 $repeat_count = 2;
6056 foreach ($repeat_intervals as $rp) {
6057 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
6058 // adjust time in case of equal dates (1 single day restriction)
6059 $rpfrom = getdate($rp['from']);
6060 $rpto = getdate($rp['to']);
6061 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
6062 /**
6063 * The end date of the restriction must cover the whole day until 23:59:59.
6064 *
6065 * @since 1.15.4 (J) - 1.5.4 (WP)
6066 */
6067 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
6068 }
6069 // adjust name
6070 $restr_rp_name = $pname . " #{$repeat_count}";
6071 //
6072 $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").");";
6073 $dbo->setQuery($q);
6074 $dbo->execute();
6075 $lid = $dbo->insertid();
6076 if (!empty($lid)) {
6077 $repeat_count++;
6078 }
6079 }
6080 }
6081 }
6082 }
6083 //
6084 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6085 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6086 } else {
6087 VikError::raiseWarning('', 'Error while saving');
6088 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
6089 }
6090 }
6091
6092 public function updaterestriction()
6093 {
6094 if (!JSession::checkToken()) {
6095 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6096 }
6097
6098 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6099 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6100 }
6101
6102 $dbo = JFactory::getDBO();
6103 $session = JFactory::getSession();
6104 $mainframe = JFactory::getApplication();
6105 $updforvcm = $session->get('vbVcmRatesUpd', '');
6106 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
6107 $pwhere = VikRequest::getInt('where', '', 'request');
6108 $pname = VikRequest::getString('name', '', 'request');
6109 $pmonth = VikRequest::getInt('month', '', 'request');
6110 $pmonth = empty($pmonth) ? 0 : $pmonth;
6111 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
6112 $pdfrom = VikRequest::getString('dfrom', '', 'request');
6113 $pdto = VikRequest::getString('dto', '', 'request');
6114 $pwday = VikRequest::getString('wday', '', 'request');
6115 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
6116 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
6117 $pcomboa = VikRequest::getString('comboa', '', 'request');
6118 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
6119 $pcombob = VikRequest::getString('combob', '', 'request');
6120 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
6121 $pcomboc = VikRequest::getString('comboc', '', 'request');
6122 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
6123 $pcombod = VikRequest::getString('combod', '', 'request');
6124 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
6125 $combostr = '';
6126 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
6127 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
6128 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
6129 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
6130 $pminlos = VikRequest::getInt('minlos', '', 'request');
6131 $pminlos = $pminlos < 1 ? 1 : $pminlos;
6132 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
6133 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
6134 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
6135 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
6136 $pallrooms = VikRequest::getString('allrooms', '', 'request');
6137 $pallrooms = $pallrooms == "1" ? 1 : 0;
6138 $pidrooms = VikRequest::getVar('idrooms', array(0));
6139 $ridr = '';
6140 $roomidsforsess = array();
6141 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
6142 foreach ($pidrooms as $idr) {
6143 if (empty($idr)) {
6144 continue;
6145 }
6146 $ridr .= '-'.$idr.'-;';
6147 $roomidsforsess[] = (int)$idr;
6148 }
6149 } elseif ($pallrooms > 0) {
6150 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
6151 $dbo->setQuery($q);
6152 $dbo->execute();
6153 if ($dbo->getNumRows() > 0) {
6154 $fetchids = $dbo->loadAssocList();
6155 foreach ($fetchids as $fetchid) {
6156 $roomidsforsess[] = (int)$fetchid['id'];
6157 }
6158 }
6159 }
6160 $pcta = VikRequest::getInt('cta', '', 'request');
6161 $pctd = VikRequest::getInt('ctd', '', 'request');
6162 $pctad = VikRequest::getVar('ctad', array());
6163 $pctdd = VikRequest::getVar('ctdd', array());
6164 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
6165 // VBO 1.11 - we now allow restrictions with just 1 night of stay
6166 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
6167 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6168 // exit;
6169 }
6170 //check if there are restrictions for this month
6171 if ($pmonth > 0) {
6172 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
6173 $dbo->setQuery($q);
6174 $dbo->execute();
6175 if ($dbo->getNumRows() > 0) {
6176 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
6177 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6178 exit;
6179 }
6180 $pdfrom = 0;
6181 $pdto = 0;
6182 } else {
6183 //dates range
6184 if (empty($pdfrom) || empty($pdto)) {
6185 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6186 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6187 exit;
6188 } else {
6189 $housto = $pdfrom == $pdto ? 23 : 0;
6190 $minsto = $pdfrom == $pdto ? 59 : 0;
6191 $secsto = $pdfrom == $pdto ? 59 : 0;
6192 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
6193 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
6194 }
6195 if ($pdfrom > $pdto) {
6196 // invalid dates in the past
6197 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6198 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6199 exit;
6200 }
6201 }
6202 //CTA and CTD
6203 $setcta = array();
6204 $setctd = array();
6205 if ($pcta > 0 && count($pctad) > 0) {
6206 foreach ($pctad as $ctwd) {
6207 if (strlen($ctwd)) {
6208 $setcta[] = '-'.(int)$ctwd.'-';
6209 }
6210 }
6211 }
6212 if ($pctd > 0 && count($pctdd) > 0) {
6213 foreach ($pctdd as $ctwd) {
6214 if (strlen($ctwd)) {
6215 $setctd[] = '-'.(int)$ctwd.'-';
6216 }
6217 }
6218 }
6219 //
6220 //update session values
6221 if (!($pdfrom > 0)) {
6222 $attemptyear = (int)date('Y');
6223 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6224 if ($attemptfrom < time()) {
6225 $attemptyear++;
6226 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6227 }
6228 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
6229 } else {
6230 $attemptfrom = $pdfrom;
6231 $attemptto = $pdto;
6232 }
6233 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
6234 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
6235 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
6236 } else {
6237 $updforvcm['dfrom'] = $attemptfrom;
6238 }
6239 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
6240 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
6241 } else {
6242 $updforvcm['dto'] = $attemptto;
6243 }
6244 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
6245 foreach ($roomidsforsess as $rid) {
6246 if (!in_array($rid, $updforvcm['rooms'])) {
6247 $updforvcm['rooms'][] = $rid;
6248 }
6249 }
6250 } else {
6251 $updforvcm['rooms'] = $roomidsforsess;
6252 }
6253 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6254 $updforvcm['rplans'] = array();
6255 }
6256 $session->set('vbVcmRatesUpd', $updforvcm);
6257 //
6258 $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."';";
6259 $dbo->setQuery($q);
6260 $dbo->execute();
6261 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6262 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6263 }
6264
6265 public function removerestrictions()
6266 {
6267 if (!JSession::checkToken()) {
6268 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6269 }
6270
6271 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6272 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6273 }
6274
6275 $ids = VikRequest::getVar('cid', array(0));
6276 if ($ids) {
6277 $dbo = JFactory::getDBO();
6278 foreach ($ids as $d) {
6279 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6280 $dbo->setQuery($q);
6281 $dbo->execute();
6282 }
6283 }
6284 $mainframe = JFactory::getApplication();
6285 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6286 }
6287
6288 public function prices() {
6289 VikBookingHelper::printHeader("1");
6290
6291 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6292
6293 parent::display();
6294
6295 if (VikBooking::showFooter()) {
6296 VikBookingHelper::printFooter();
6297 }
6298 }
6299
6300 public function newprice() {
6301 VikBookingHelper::printHeader("1");
6302
6303 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6304
6305 parent::display();
6306
6307 if (VikBooking::showFooter()) {
6308 VikBookingHelper::printFooter();
6309 }
6310 }
6311
6312 public function editprice() {
6313 VikBookingHelper::printHeader("1");
6314
6315 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6316
6317 parent::display();
6318
6319 if (VikBooking::showFooter()) {
6320 VikBookingHelper::printFooter();
6321 }
6322 }
6323
6324 public function createprice()
6325 {
6326 if (!JSession::checkToken()) {
6327 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6328 }
6329
6330 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6331 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6332 }
6333
6334 $this->do_createprice();
6335 }
6336
6337 public function createprice_new()
6338 {
6339 if (!JSession::checkToken()) {
6340 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6341 }
6342
6343 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6344 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6345 }
6346
6347 $this->do_createprice(true);
6348 }
6349
6350 private function do_createprice($new = false)
6351 {
6352 $app = JFactory::getApplication();
6353 $dbo = JFactory::getDbo();
6354
6355 $pprice = VikRequest::getString('price', '', 'request');
6356 $pattr = VikRequest::getString('attr', '', 'request');
6357 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6358 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6359 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6360 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6361 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6362 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6363 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6364 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6365 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6366 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6367 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6368
6369 $is_derived = $app->input->getInt('is_derived', 0);
6370 $derived_id = $app->input->getUInt('derived_id', 0);
6371 $derived_data = $app->input->get('derived_data', [], 'array');
6372
6373 $parent_id = 0;
6374 $derived_info = null;
6375
6376 if ($is_derived && $derived_id && $derived_data) {
6377 $parent_id = $derived_id;
6378 $derived_info = $derived_data;
6379 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6380 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6381 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6382 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6383 if (!$derived_info['value']) {
6384 $parent_id = 0;
6385 $derived_info = null;
6386 }
6387 }
6388
6389 if (!empty($pprice)) {
6390 $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') . ");";
6391 $dbo->setQuery($q);
6392 $dbo->execute();
6393 }
6394
6395 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6396 $app->close();
6397 }
6398
6399 public function updateprice()
6400 {
6401 if (!JSession::checkToken()) {
6402 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6403 }
6404
6405 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6406 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6407 }
6408
6409 $this->do_updateprice();
6410 }
6411
6412 public function updatepricestay()
6413 {
6414 if (!JSession::checkToken()) {
6415 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6416 }
6417
6418 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6419 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6420 }
6421
6422 $this->do_updateprice(true);
6423 }
6424
6425 private function do_updateprice($stay = false)
6426 {
6427 $app = JFactory::getApplication();
6428 $dbo = JFactory::getDbo();
6429
6430 $pprice = VikRequest::getString('price', '', 'request');
6431 $pattr = VikRequest::getString('attr', '', 'request');
6432 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6433 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6434 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6435 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6436 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6437 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6438 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6439 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6440 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6441 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6442 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6443 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6444
6445 $is_derived = $app->input->getInt('is_derived', 0);
6446 $derived_id = $app->input->getUInt('derived_id', 0);
6447 $derived_data = $app->input->get('derived_data', [], 'array');
6448
6449 $parent_id = 0;
6450 $derived_info = null;
6451
6452 if ($is_derived && $derived_id && $derived_data) {
6453 $parent_id = $derived_id;
6454 $derived_info = $derived_data;
6455 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6456 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6457 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6458 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6459 if (!$derived_info['value']) {
6460 $parent_id = 0;
6461 $derived_info = null;
6462 }
6463 }
6464
6465 if (!empty($pprice) && $pwhereup) {
6466 $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) . ";";
6467 $dbo->setQuery($q);
6468 $dbo->execute();
6469 }
6470
6471 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6472 $app->close();
6473 }
6474
6475 public function removeprice()
6476 {
6477 if (!JSession::checkToken()) {
6478 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6479 }
6480
6481 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6482 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6483 }
6484
6485 $ids = VikRequest::getVar('cid', array(0));
6486 if ($ids) {
6487 $dbo = JFactory::getDBO();
6488 foreach ($ids as $d) {
6489 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6490 $dbo->setQuery($q);
6491 $dbo->execute();
6492 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6493 $dbo->setQuery($q);
6494 $dbo->execute();
6495 }
6496 }
6497 $mainframe = JFactory::getApplication();
6498 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6499 }
6500
6501 public function iva() {
6502 VikBookingHelper::printHeader("2");
6503
6504 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6505
6506 parent::display();
6507
6508 if (VikBooking::showFooter()) {
6509 VikBookingHelper::printFooter();
6510 }
6511 }
6512
6513 public function newiva() {
6514 VikBookingHelper::printHeader("2");
6515
6516 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6517
6518 parent::display();
6519
6520 if (VikBooking::showFooter()) {
6521 VikBookingHelper::printFooter();
6522 }
6523 }
6524
6525 public function editiva() {
6526 VikBookingHelper::printHeader("2");
6527
6528 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6529
6530 parent::display();
6531
6532 if (VikBooking::showFooter()) {
6533 VikBookingHelper::printFooter();
6534 }
6535 }
6536
6537 public function createiva()
6538 {
6539 if (!JSession::checkToken()) {
6540 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6541 }
6542
6543 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6544 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6545 }
6546
6547 $paliqname = VikRequest::getString('aliqname', '', 'request');
6548 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6549 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6550 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6551 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6552 if (!empty($paliqperc)) {
6553 $dbo = JFactory::getDBO();
6554 $breakdown_str = '';
6555 if (count($pbreakdown_name) > 0) {
6556 $breakdown_values = array();
6557 $bkcount = 0;
6558 $tot_sub_aliq = 0;
6559 foreach ($pbreakdown_name as $key => $subtax) {
6560 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6561 $breakdown_values[$bkcount]['name'] = $subtax;
6562 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6563 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6564 $bkcount++;
6565 }
6566 }
6567 if (count($breakdown_values) > 0) {
6568 $breakdown_str = json_encode($breakdown_values);
6569 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6570 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6571 }
6572 }
6573 }
6574 $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').");";
6575 $dbo->setQuery($q);
6576 $dbo->execute();
6577 }
6578 $mainframe = JFactory::getApplication();
6579 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6580 }
6581
6582 public function updateiva()
6583 {
6584 if (!JSession::checkToken()) {
6585 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6586 }
6587
6588 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6589 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6590 }
6591
6592 $paliqname = VikRequest::getString('aliqname', '', 'request');
6593 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6594 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6595 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6596 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6597 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6598 if (!empty($paliqperc)) {
6599 $dbo = JFactory::getDBO();
6600 $breakdown_str = '';
6601 if (count($pbreakdown_name) > 0) {
6602 $breakdown_values = array();
6603 $bkcount = 0;
6604 $tot_sub_aliq = 0;
6605 foreach ($pbreakdown_name as $key => $subtax) {
6606 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6607 $breakdown_values[$bkcount]['name'] = $subtax;
6608 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6609 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6610 $bkcount++;
6611 }
6612 }
6613 if (count($breakdown_values) > 0) {
6614 $breakdown_str = json_encode($breakdown_values);
6615 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6616 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6617 }
6618 }
6619 }
6620 $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).";";
6621 $dbo->setQuery($q);
6622 $dbo->execute();
6623 }
6624 $mainframe = JFactory::getApplication();
6625 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6626 }
6627
6628 public function removeiva()
6629 {
6630 if (!JSession::checkToken()) {
6631 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6632 }
6633
6634 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6635 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6636 }
6637
6638 $ids = VikRequest::getVar('cid', array(0));
6639 if ($ids) {
6640 $dbo = JFactory::getDBO();
6641 foreach ($ids as $d) {
6642 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6643 $dbo->setQuery($q);
6644 $dbo->execute();
6645 }
6646 }
6647 $mainframe = JFactory::getApplication();
6648 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6649 }
6650
6651 public function categories() {
6652 VikBookingHelper::printHeader("4");
6653
6654 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6655
6656 parent::display();
6657
6658 if (VikBooking::showFooter()) {
6659 VikBookingHelper::printFooter();
6660 }
6661 }
6662
6663 public function newcat() {
6664 VikBookingHelper::printHeader("4");
6665
6666 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6667
6668 parent::display();
6669
6670 if (VikBooking::showFooter()) {
6671 VikBookingHelper::printFooter();
6672 }
6673 }
6674
6675 public function editcat() {
6676 VikBookingHelper::printHeader("4");
6677
6678 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6679
6680 parent::display();
6681
6682 if (VikBooking::showFooter()) {
6683 VikBookingHelper::printFooter();
6684 }
6685 }
6686
6687 public function createcat()
6688 {
6689 if (!JSession::checkToken()) {
6690 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6691 }
6692
6693 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6694 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6695 }
6696
6697 $pcatname = VikRequest::getString('catname', '', 'request');
6698 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6699 if (!empty($pcatname)) {
6700 $dbo = JFactory::getDBO();
6701 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6702 $dbo->setQuery($q);
6703 $dbo->execute();
6704 }
6705 $mainframe = JFactory::getApplication();
6706 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6707 }
6708
6709 public function updatecat()
6710 {
6711 if (!JSession::checkToken()) {
6712 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6713 }
6714
6715 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6716 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6717 }
6718
6719 $pcatname = VikRequest::getString('catname', '', 'request');
6720 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6721 $pwhereup = VikRequest::getString('whereup', '', 'request');
6722 if (!empty($pcatname)) {
6723 $dbo = JFactory::getDBO();
6724 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6725 $dbo->setQuery($q);
6726 $dbo->execute();
6727 }
6728 $mainframe = JFactory::getApplication();
6729 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6730 }
6731
6732 public function removecat()
6733 {
6734 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6735 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6736 }
6737
6738 $ids = VikRequest::getVar('cid', array(0));
6739 if ($ids) {
6740 $dbo = JFactory::getDBO();
6741 foreach ($ids as $d) {
6742 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6743 $dbo->setQuery($q);
6744 $dbo->execute();
6745 }
6746 }
6747 $mainframe = JFactory::getApplication();
6748 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6749 }
6750
6751 public function carat() {
6752 VikBookingHelper::printHeader("5");
6753
6754 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6755
6756 parent::display();
6757
6758 if (VikBooking::showFooter()) {
6759 VikBookingHelper::printFooter();
6760 }
6761 }
6762
6763 public function newcarat() {
6764 VikBookingHelper::printHeader("5");
6765
6766 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6767
6768 parent::display();
6769
6770 if (VikBooking::showFooter()) {
6771 VikBookingHelper::printFooter();
6772 }
6773 }
6774
6775 public function editcarat() {
6776 VikBookingHelper::printHeader("5");
6777
6778 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6779
6780 parent::display();
6781
6782 if (VikBooking::showFooter()) {
6783 VikBookingHelper::printFooter();
6784 }
6785 }
6786
6787 public function createcarat()
6788 {
6789 if (!JSession::checkToken()) {
6790 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6791 }
6792
6793 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6794 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6795 }
6796
6797 $pcaratname = VikRequest::getString('caratname', '', 'request');
6798 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6799 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6800 $presizeto = VikRequest::getString('resizeto', '', 'request');
6801 $pidrooms = VikRequest::getVar('idrooms', array());
6802 if (!empty($pcaratname)) {
6803 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6804 jimport('joomla.filesystem.file');
6805 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6806 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6807 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6808 if (file_exists($updpath.$safename)) {
6809 $j=1;
6810 while (file_exists($updpath.$j.$safename)) {
6811 $j++;
6812 }
6813 $pwhere=$updpath.$j.$safename;
6814 } else {
6815 $j="";
6816 $pwhere=$updpath.$safename;
6817 }
6818 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6819 @unlink($pwhere);
6820 $picon="";
6821 } else {
6822 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6823 @chmod($pwhere, 0644);
6824 $picon=$j.$safename;
6825 if ($pautoresize=="1" && !empty($presizeto)) {
6826 $eforj = new vikResizer();
6827 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6828 if ($origmod) {
6829 @unlink($pwhere);
6830 $picon='r_'.$j.$safename;
6831 }
6832 }
6833 }
6834 } else {
6835 $picon="";
6836 }
6837 } else {
6838 $picon="";
6839 }
6840 $dbo = JFactory::getDbo();
6841 // get new ordering
6842 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6843 $dbo->setQuery($q);
6844 $dbo->execute();
6845 if ($dbo->getNumRows()) {
6846 $newsortnum = $dbo->loadResult() + 1;
6847 } else {
6848 $newsortnum = 1;
6849 }
6850 $pordering = VikRequest::getInt('ordering', 0, 'request');
6851 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6852 //
6853 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6854 $dbo->setQuery($q);
6855 $dbo->execute();
6856
6857 $new_carat_id = $dbo->insertid();
6858 if (!empty($new_carat_id)) {
6859 // assign/unset carat-rooms relations
6860 $rooms_with_carat = array();
6861 if (count($pidrooms)) {
6862 // assign this new carat to the requested rooms
6863 foreach ($pidrooms as $idroom) {
6864 if (empty($idroom)) {
6865 continue;
6866 }
6867 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6868 $dbo->setQuery($q);
6869 $dbo->execute();
6870 if (!$dbo->getNumRows()) {
6871 continue;
6872 }
6873 $room_data = $dbo->loadAssoc();
6874 array_push($rooms_with_carat, $room_data['id']);
6875 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6876 if (in_array((string)$new_carat_id, $current_carats)) {
6877 continue;
6878 }
6879 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6880 // make sure we do not concatenate a real ID to 0
6881 $current_carats = array();
6882 }
6883 array_push($current_carats, $new_carat_id);
6884 $new_opts = implode(';', $current_carats) . ';';
6885 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6886 $dbo->setQuery($q);
6887 $dbo->execute();
6888 }
6889 }
6890 if (!count($rooms_with_carat)) {
6891 // get all rooms to unset this carat (if previously set)
6892 array_push($rooms_with_carat, '0');
6893 }
6894 // unset the carat from the other rooms that may have it
6895 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6896 $dbo->setQuery($q);
6897 $dbo->execute();
6898 if ($dbo->getNumRows()) {
6899 $unset_rooms_carat = $dbo->loadAssocList();
6900 foreach ($unset_rooms_carat as $room_data) {
6901 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6902 if (!in_array((string)$new_carat_id, $current_carats)) {
6903 // this room is not using this carat
6904 continue;
6905 }
6906 $caratkey = array_search((string)$new_carat_id, $current_carats);
6907 if ($caratkey === false) {
6908 // key not found
6909 continue;
6910 }
6911 // unset this carat ID from the string
6912 unset($current_carats[$caratkey]);
6913 if (!count($current_carats)) {
6914 // a room with no carats assigned will be listed as "0;"
6915 $current_carats = array(0);
6916 }
6917 $new_opts = implode(';', $current_carats) . ';';
6918 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6919 $dbo->setQuery($q);
6920 $dbo->execute();
6921 }
6922 }
6923 //
6924 }
6925 }
6926 $mainframe = JFactory::getApplication();
6927 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6928 }
6929
6930 public function updatecarat()
6931 {
6932 if (!JSession::checkToken()) {
6933 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6934 }
6935
6936 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6937 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6938 }
6939
6940 $pcaratname = VikRequest::getString('caratname', '', 'request');
6941 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6942 $pwhereup = VikRequest::getString('whereup', '', 'request');
6943 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6944 $presizeto = VikRequest::getString('resizeto', '', 'request');
6945 $pidrooms = VikRequest::getVar('idrooms', array());
6946 $pordering = VikRequest::getInt('ordering', 1, 'request');
6947 if (!empty($pcaratname)) {
6948 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6949 jimport('joomla.filesystem.file');
6950 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6951 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6952 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6953 if (file_exists($updpath.$safename)) {
6954 $j=1;
6955 while (file_exists($updpath.$j.$safename)) {
6956 $j++;
6957 }
6958 $pwhere=$updpath.$j.$safename;
6959 } else {
6960 $j="";
6961 $pwhere=$updpath.$safename;
6962 }
6963 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6964 @unlink($pwhere);
6965 $picon="";
6966 } else {
6967 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6968 @chmod($pwhere, 0644);
6969 $picon=$j.$safename;
6970 if ($pautoresize=="1" && !empty($presizeto)) {
6971 $eforj = new vikResizer();
6972 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6973 if ($origmod) {
6974 @unlink($pwhere);
6975 $picon='r_'.$j.$safename;
6976 }
6977 }
6978 }
6979 } else {
6980 $picon="";
6981 }
6982 } else {
6983 $picon="";
6984 }
6985 $dbo = JFactory::getDbo();
6986 $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).";";
6987 $dbo->setQuery($q);
6988 $dbo->execute();
6989
6990 // assign/unset carat-rooms relations
6991 $rooms_with_carat = array();
6992 if (count($pidrooms)) {
6993 // assign this new carat to the requested rooms
6994 foreach ($pidrooms as $idroom) {
6995 if (empty($idroom)) {
6996 continue;
6997 }
6998 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6999 $dbo->setQuery($q);
7000 $dbo->execute();
7001 if (!$dbo->getNumRows()) {
7002 continue;
7003 }
7004 $room_data = $dbo->loadAssoc();
7005 array_push($rooms_with_carat, $room_data['id']);
7006 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
7007 if (in_array((string)$pwhereup, $current_carats)) {
7008 continue;
7009 }
7010 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
7011 // make sure we do not concatenate a real ID to 0
7012 $current_carats = array();
7013 }
7014 array_push($current_carats, $pwhereup);
7015 $new_carats = implode(';', $current_carats) . ';';
7016 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7017 $dbo->setQuery($q);
7018 $dbo->execute();
7019 }
7020 }
7021 if (!count($rooms_with_carat)) {
7022 // get all rooms to unset this carat (if previously set)
7023 array_push($rooms_with_carat, '0');
7024 }
7025 // unset the carat from the other rooms that may have it
7026 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
7027 $dbo->setQuery($q);
7028 $dbo->execute();
7029 if ($dbo->getNumRows()) {
7030 $unset_rooms_carat = $dbo->loadAssocList();
7031 foreach ($unset_rooms_carat as $room_data) {
7032 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
7033 if (!in_array((string)$pwhereup, $current_carats)) {
7034 // this room is not using this carat
7035 continue;
7036 }
7037 $caratkey = array_search((string)$pwhereup, $current_carats);
7038 if ($caratkey === false) {
7039 // key not found
7040 continue;
7041 }
7042 // unset this carat ID from the string
7043 unset($current_carats[$caratkey]);
7044 if (!count($current_carats)) {
7045 // a room with no carats assigned will be listed as "0;"
7046 $current_carats = array(0);
7047 }
7048 $new_carats = implode(';', $current_carats) . ';';
7049 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7050 $dbo->setQuery($q);
7051 $dbo->execute();
7052 }
7053 }
7054 //
7055 }
7056 $mainframe = JFactory::getApplication();
7057 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7058 }
7059
7060 public function removecarat()
7061 {
7062 if (!JSession::checkToken()) {
7063 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7064 }
7065
7066 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7067 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7068 }
7069
7070 $ids = VikRequest::getVar('cid', array(0));
7071 if ($ids) {
7072 $dbo = JFactory::getDBO();
7073 foreach ($ids as $d) {
7074 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7075 $dbo->setQuery($q);
7076 $dbo->execute();
7077 if ($dbo->getNumRows() == 1) {
7078 $rows = $dbo->loadAssocList();
7079 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
7080 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
7081 }
7082 }
7083 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7084 $dbo->setQuery($q);
7085 $dbo->execute();
7086 }
7087 }
7088 $mainframe = JFactory::getApplication();
7089 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7090 }
7091
7092 public function coupons() {
7093 VikBookingHelper::printHeader("17");
7094
7095 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
7096
7097 parent::display();
7098
7099 if (VikBooking::showFooter()) {
7100 VikBookingHelper::printFooter();
7101 }
7102 }
7103
7104 public function newcoupon() {
7105 VikBookingHelper::printHeader("17");
7106
7107 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7108
7109 parent::display();
7110
7111 if (VikBooking::showFooter()) {
7112 VikBookingHelper::printFooter();
7113 }
7114 }
7115
7116 public function editcoupon() {
7117 VikBookingHelper::printHeader("17");
7118
7119 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7120
7121 parent::display();
7122
7123 if (VikBooking::showFooter()) {
7124 VikBookingHelper::printFooter();
7125 }
7126 }
7127
7128 public function createcoupon()
7129 {
7130 if (!JSession::checkToken()) {
7131 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7132 }
7133
7134 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7135 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7136 }
7137
7138 $pcode = VikRequest::getString('code', '', 'request');
7139 $pvalue = VikRequest::getString('value', '', 'request');
7140 $pfrom = VikRequest::getString('from', '', 'request');
7141 $pto = VikRequest::getString('to', '', 'request');
7142 $pidrooms = VikRequest::getVar('idrooms', array(0));
7143 $ptype = VikRequest::getString('type', '', 'request');
7144 $ptype = $ptype == "1" ? 1 : 2;
7145 $ppercentot = VikRequest::getString('percentot', '', 'request');
7146 $ppercentot = $ppercentot == "1" ? 1 : 2;
7147 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7148 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7149 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7150 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7151 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7152 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7153 $pcustomers = VikRequest::getVar('customers', array());
7154 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7155 $stridrooms = "";
7156 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7157 foreach ($pidrooms as $ch) {
7158 if (!empty($ch)) {
7159 $stridrooms .= ";".$ch.";";
7160 }
7161 }
7162 }
7163 $strdatevalid = "";
7164 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7165 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7166 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7167 if ($first < $second) {
7168 $strdatevalid .= $first."-".$second;
7169 }
7170 }
7171
7172 $dbo = JFactory::getDbo();
7173 $app = JFactory::getApplication();
7174
7175 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
7176 $dbo->setQuery($q);
7177 $dbo->execute();
7178 if ($dbo->getNumRows() > 0) {
7179 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7180 } else {
7181 $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) . ");";
7182 $dbo->setQuery($q);
7183 $dbo->execute();
7184
7185 $id_coupon = $dbo->insertid();
7186
7187 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7188
7189 // check if this coupon should be assigned to specific customers
7190 foreach ($pcustomers as $id_customer) {
7191 $customer_coupon = new stdClass;
7192 $customer_coupon->idcustomer = (int)$id_customer;
7193 $customer_coupon->idcoupon = (int)$id_coupon;
7194 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7195
7196 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7197 }
7198 }
7199 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7200 }
7201
7202 public function updatecoupon()
7203 {
7204 if (!JSession::checkToken()) {
7205 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7206 }
7207
7208 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7209 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7210 }
7211
7212 $this->do_updatecoupon($stay = false);
7213 }
7214
7215 public function updatecoupon_stay()
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 $this->do_updatecoupon($stay = true);
7226 }
7227
7228 protected function do_updatecoupon($stay = false)
7229 {
7230 if (!JSession::checkToken()) {
7231 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7232 }
7233 $pcode = VikRequest::getString('code', '', 'request');
7234 $pvalue = VikRequest::getString('value', '', 'request');
7235 $pfrom = VikRequest::getString('from', '', 'request');
7236 $pto = VikRequest::getString('to', '', 'request');
7237 $pidrooms = VikRequest::getVar('idrooms', array(0));
7238 $pwhere = VikRequest::getInt('where', 0, 'request');
7239 $ptype = VikRequest::getString('type', '', 'request');
7240 $ptype = $ptype == "1" ? 1 : 2;
7241 $ppercentot = VikRequest::getString('percentot', '', 'request');
7242 $ppercentot = $ppercentot == "1" ? 1 : 2;
7243 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7244 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7245 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7246 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7247 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7248 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7249 $pcustomers = VikRequest::getVar('customers', array());
7250 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7251 $stridrooms = "";
7252 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7253 foreach ($pidrooms as $ch) {
7254 if (!empty($ch)) {
7255 $stridrooms .= ";".$ch.";";
7256 }
7257 }
7258 }
7259 $strdatevalid = "";
7260 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7261 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7262 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7263 if ($first < $second) {
7264 $strdatevalid .= $first."-".$second;
7265 }
7266 }
7267
7268 $dbo = JFactory::getDbo();
7269 $app = JFactory::getApplication();
7270
7271 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
7272 $dbo->setQuery($q);
7273 $dbo->execute();
7274 if ($dbo->getNumRows() > 0) {
7275 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7276 } else {
7277 $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 . ";";
7278 $dbo->setQuery($q);
7279 $dbo->execute();
7280
7281 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7282
7283 // clean up any previously created record with customers
7284 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
7285 $dbo->setQuery($q);
7286 $dbo->execute();
7287
7288 // check if this coupon should be assigned to specific customers
7289 foreach ($pcustomers as $id_customer) {
7290 $customer_coupon = new stdClass;
7291 $customer_coupon->idcustomer = (int)$id_customer;
7292 $customer_coupon->idcoupon = (int)$pwhere;
7293 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7294
7295 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7296 }
7297 }
7298
7299 if ($stay) {
7300 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
7301 } else {
7302 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7303 }
7304 }
7305
7306 public function removecoupons()
7307 {
7308 if (!JSession::checkToken()) {
7309 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7310 }
7311
7312 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7313 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7314 }
7315
7316 $dbo = JFactory::getDbo();
7317
7318 $ids = VikRequest::getVar('cid', array(0));
7319
7320 if ($ids) {
7321 foreach ($ids as $d) {
7322 // delete coupon record
7323 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
7324 $dbo->setQuery($q);
7325 $dbo->execute();
7326
7327 // clean up any previously created record with customers
7328 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
7329 $dbo->setQuery($q);
7330 $dbo->execute();
7331 }
7332 }
7333
7334 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
7335 }
7336
7337 public function removemoreimgs()
7338 {
7339 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7340 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7341 }
7342
7343 $mainframe = JFactory::getApplication();
7344 $proomid = VikRequest::getInt('roomid', '', 'request');
7345 $pimgind = VikRequest::getInt('imgind', '', 'request');
7346 if (!strlen($pimgind)) {
7347 $mainframe->redirect("index.php?option=com_vikbooking");
7348 exit;
7349 }
7350 $dbo = JFactory::getDBO();
7351 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
7352 $dbo->setQuery($q);
7353 $dbo->execute();
7354 $row = $dbo->loadAssoc();
7355 $actmore = $row['moreimgs'];
7356 if (!empty($actmore)) {
7357 $actsplit = explode(';;', $actmore);
7358 $captions = json_decode($row['imgcaptions'], true);
7359 $captions = !is_array($captions) ? array() : $captions;
7360 if ($pimgind < 0) {
7361 foreach ($actsplit as $img) {
7362 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
7363 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
7364 }
7365 // reset images and captions
7366 $actsplit = array();
7367 $captions = array();
7368 } else {
7369 if (array_key_exists($pimgind, $actsplit)) {
7370 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
7371 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
7372 // unset current image
7373 unset($actsplit[$pimgind]);
7374 // unset caption if exists
7375 if (isset($captions[$pimgind])) {
7376 unset($captions[$pimgind]);
7377 $captions = array_values($captions);
7378 }
7379 }
7380 }
7381 $newstr = "";
7382 foreach ($actsplit as $oi) {
7383 if (!empty($oi)) {
7384 $newstr .= $oi.';;';
7385 }
7386 }
7387 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
7388 $dbo->setQuery($q);
7389 $dbo->execute();
7390 }
7391 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
7392 }
7393
7394 public function sortfield() {
7395 if (!JSession::checkToken('get')) {
7396 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7397 }
7398 $mainframe = JFactory::getApplication();
7399 $sortid = VikRequest::getVar('cid', array(0));
7400 $pmode = VikRequest::getString('mode', '', 'request');
7401 $dbo = JFactory::getDBO();
7402 if (!empty($pmode)) {
7403 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7404 $dbo->setQuery($q);
7405 $dbo->execute();
7406 $totr=$dbo->getNumRows();
7407 if ($totr > 1) {
7408 $data = $dbo->loadAssocList();
7409 if ($pmode == "up") {
7410 foreach ($data as $v) {
7411 if ($v['id'] == $sortid[0]) {
7412 $y = $v['ordering'];
7413 }
7414 }
7415 if ($y && $y > 1) {
7416 $vik = $y - 1;
7417 $found = false;
7418 foreach ($data as $v) {
7419 if (intval($v['ordering']) == intval($vik)) {
7420 $found=true;
7421 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7422 $dbo->setQuery($q);
7423 $dbo->execute();
7424 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7425 $dbo->setQuery($q);
7426 $dbo->execute();
7427 break;
7428 }
7429 }
7430 if (!$found) {
7431 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7432 $dbo->setQuery($q);
7433 $dbo->execute();
7434 }
7435 }
7436 } elseif ($pmode == "down") {
7437 foreach ($data as $v) {
7438 if ($v['id'] == $sortid[0]) {
7439 $y = $v['ordering'];
7440 }
7441 }
7442 if ($y) {
7443 $vik = $y + 1;
7444 $found = false;
7445 foreach ($data as $v) {
7446 if (intval($v['ordering']) == intval($vik)) {
7447 $found=true;
7448 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7449 $dbo->setQuery($q);
7450 $dbo->execute();
7451 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7452 $dbo->setQuery($q);
7453 $dbo->execute();
7454 break;
7455 }
7456 }
7457 if (!$found) {
7458 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7459 $dbo->setQuery($q);
7460 $dbo->execute();
7461 }
7462 }
7463 }
7464 }
7465 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7466 } else {
7467 $mainframe->redirect("index.php?option=com_vikbooking");
7468 }
7469 }
7470
7471 public function customf() {
7472 VikBookingHelper::printHeader("16");
7473
7474 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7475
7476 parent::display();
7477
7478 if (VikBooking::showFooter()) {
7479 VikBookingHelper::printFooter();
7480 }
7481 }
7482
7483 public function newcustomf() {
7484 VikBookingHelper::printHeader("16");
7485
7486 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7487
7488 parent::display();
7489
7490 if (VikBooking::showFooter()) {
7491 VikBookingHelper::printFooter();
7492 }
7493 }
7494
7495 public function editcustomf() {
7496 VikBookingHelper::printHeader("16");
7497
7498 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7499
7500 parent::display();
7501
7502 if (VikBooking::showFooter()) {
7503 VikBookingHelper::printFooter();
7504 }
7505 }
7506
7507 public function createcustomf()
7508 {
7509 if (!JSession::checkToken()) {
7510 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7511 }
7512
7513 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7514 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7515 }
7516
7517 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7518 $ptype = VikRequest::getString('type', '', 'request');
7519 $pchoose = VikRequest::getVar('choose', array(0));
7520 $prequired = VikRequest::getString('required', '', 'request');
7521 $prequired = $prequired == "1" ? 1 : 0;
7522 $pflag = VikRequest::getString('flag', '', 'request');
7523 $pisemail = $pflag == 'isemail' ? 1 : 0;
7524 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7525 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7526 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7527 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7528 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7529 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7530 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7531 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7532 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7533 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7534 $fieldflag = '';
7535 if ($pisaddress == 1) {
7536 $fieldflag = 'address';
7537 } elseif ($piscity == 1) {
7538 $fieldflag = 'city';
7539 } elseif ($piszip == 1) {
7540 $fieldflag = 'zip';
7541 } elseif ($piscompany == 1) {
7542 $fieldflag = 'company';
7543 } elseif ($pisvat == 1) {
7544 $fieldflag = 'vat';
7545 } elseif ($pisfisccode == 1) {
7546 $fieldflag = 'fisccode';
7547 } elseif ($pispec == 1) {
7548 $fieldflag = 'pec';
7549 } elseif ($pisrecipcode == 1) {
7550 $fieldflag = 'recipcode';
7551 }
7552 $ppoplink = VikRequest::getString('poplink', '', 'request');
7553 $choosestr = "";
7554 if (is_array($pchoose)) {
7555 foreach ($pchoose as $ch) {
7556 if (!empty($ch)) {
7557 $choosestr .= $ch.";;__;;";
7558 }
7559 }
7560 }
7561 $defvalue = VikRequest::getString('defvalue', '', 'request');
7562
7563 $dbo = JFactory::getDbo();
7564
7565 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7566 $dbo->setQuery($q);
7567 $dbo->execute();
7568 if ($dbo->getNumRows() == 1) {
7569 $getlast = $dbo->loadResult();
7570 $newsortnum = $getlast + 1;
7571 } else {
7572 $newsortnum = 1;
7573 }
7574 $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).");";
7575 $dbo->setQuery($q);
7576 $dbo->execute();
7577 $mainframe = JFactory::getApplication();
7578 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7579 }
7580
7581 public function updatecustomf()
7582 {
7583 if (!JSession::checkToken()) {
7584 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7585 }
7586
7587 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7588 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7589 }
7590
7591 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7592 $ptype = VikRequest::getString('type', '', 'request');
7593 $pchoose = VikRequest::getVar('choose', array(0));
7594 $prequired = VikRequest::getString('required', '', 'request');
7595 $prequired = $prequired == "1" ? 1 : 0;
7596 $pflag = VikRequest::getString('flag', '', 'request');
7597 $pisemail = $pflag == 'isemail' ? 1 : 0;
7598 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7599 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7600 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7601 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7602 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7603 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7604 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7605 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7606 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7607 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7608 $fieldflag = '';
7609 if ($pisaddress == 1) {
7610 $fieldflag = 'address';
7611 } elseif ($piscity == 1) {
7612 $fieldflag = 'city';
7613 } elseif ($piszip == 1) {
7614 $fieldflag = 'zip';
7615 } elseif ($piscompany == 1) {
7616 $fieldflag = 'company';
7617 } elseif ($pisvat == 1) {
7618 $fieldflag = 'vat';
7619 } elseif ($pisfisccode == 1) {
7620 $fieldflag = 'fisccode';
7621 } elseif ($pispec == 1) {
7622 $fieldflag = 'pec';
7623 } elseif ($pisrecipcode == 1) {
7624 $fieldflag = 'recipcode';
7625 }
7626 $ppoplink = VikRequest::getString('poplink', '', 'request');
7627 $pwhere = VikRequest::getInt('where', '', 'request');
7628 $choosestr = "";
7629 if (is_array($pchoose)) {
7630 foreach ($pchoose as $ch) {
7631 if (!empty($ch)) {
7632 $choosestr .= $ch.";;__;;";
7633 }
7634 }
7635 }
7636 $defvalue = VikRequest::getString('defvalue', '', 'request');
7637
7638 $dbo = JFactory::getDbo();
7639
7640 $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).";";
7641 $dbo->setQuery($q);
7642 $dbo->execute();
7643 $mainframe = JFactory::getApplication();
7644 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7645 }
7646
7647 public function removecustomf()
7648 {
7649 if (!JSession::checkToken()) {
7650 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7651 }
7652
7653 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7654 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7655 }
7656
7657 $ids = VikRequest::getVar('cid', array(0));
7658 if ($ids) {
7659 $dbo = JFactory::getDBO();
7660 foreach ($ids as $d) {
7661 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7662 $dbo->setQuery($q);
7663 $dbo->execute();
7664 }
7665 }
7666 $mainframe = JFactory::getApplication();
7667 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7668 }
7669
7670 public function overv() {
7671 VikBookingHelper::printHeader("15");
7672
7673 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7674
7675 parent::display();
7676
7677 if (VikBooking::showFooter()) {
7678 VikBookingHelper::printFooter();
7679 }
7680 }
7681
7682 public function translations() {
7683 VikBookingHelper::printHeader("21");
7684
7685 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7686
7687 parent::display();
7688
7689 if (VikBooking::showFooter()) {
7690 VikBookingHelper::printFooter();
7691 }
7692 }
7693
7694 public function savetranslation() {
7695 if (!JSession::checkToken()) {
7696 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7697 }
7698 $this->do_savetranslation();
7699 }
7700
7701 public function savetranslationstay() {
7702 if (!JSession::checkToken()) {
7703 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7704 }
7705 $this->do_savetranslation(true);
7706 }
7707
7708 private function do_savetranslation($stay = false) {
7709 $dbo = JFactory::getDBO();
7710 $mainframe = JFactory::getApplication();
7711 $vbo_tn = VikBooking::getTranslator();
7712 $table = VikRequest::getString('vbo_table', '', 'request');
7713 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7714 $langs = $vbo_tn->getLanguagesList();
7715 $xml_tables = $vbo_tn->getTranslationTables();
7716 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7717 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7718 $tn_saved = 0;
7719 $table_cols = $vbo_tn->getTableColumns($table);
7720 foreach ($langs as $ltag => $lang) {
7721 if ($ltag == $vbo_tn->default_lang) {
7722 continue;
7723 }
7724 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7725 foreach ($tn[$ltag] as $reference_id => $translation) {
7726 $lang_translation = array();
7727 foreach ($table_cols as $field => $fdetails) {
7728 if (!array_key_exists($field, $translation)) {
7729 continue;
7730 }
7731 $ftype = $fdetails['type'];
7732 if ($ftype == 'skip') {
7733 continue;
7734 }
7735
7736 if (is_array($translation[$field])) {
7737 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7738 if (!is_string($tn_field_v)) {
7739 continue;
7740 }
7741 // replace any possible placeholder for special tags
7742 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7743 return $match[2];
7744 }, $translation[$field][$tn_field_k]);
7745 }
7746 } elseif (!empty($translation[$field])) {
7747 // replace any possible placeholder for special tags
7748 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7749 return $match[2];
7750 }, $translation[$field]);
7751 }
7752
7753 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7754 $translation[$field] = json_encode($translation[$field]);
7755 }
7756 $lang_translation[$field] = $translation[$field];
7757 }
7758 if (count($lang_translation) > 0) {
7759 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7760 $dbo->setQuery($q);
7761 $dbo->execute();
7762 if ($dbo->getNumRows() > 0) {
7763 $last_id = $dbo->loadResult();
7764 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7765 } else {
7766 $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)).");";
7767 }
7768 $dbo->setQuery($q);
7769 $dbo->execute();
7770 $tn_saved++;
7771 }
7772 }
7773 }
7774 }
7775 if ($tn_saved > 0) {
7776 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7777 }
7778 } else {
7779 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7780 }
7781 $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);
7782 }
7783
7784 public function choosebusy() {
7785 VikBookingHelper::printHeader("8");
7786
7787 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7788
7789 parent::display();
7790
7791 if (VikBooking::showFooter()) {
7792 VikBookingHelper::printFooter();
7793 }
7794 }
7795
7796 public function orders() {
7797 VikBookingHelper::printHeader("8");
7798
7799 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7800
7801 parent::display();
7802
7803 if (VikBooking::showFooter()) {
7804 VikBookingHelper::printFooter();
7805 }
7806 }
7807
7808 public function vieworders() {
7809 //alias method of orders() for backward compatibility with VCM
7810 $this->orders();
7811 }
7812
7813 public function editorder() {
7814 VikBookingHelper::printHeader("8");
7815
7816 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7817
7818 parent::display();
7819
7820 if (VikBooking::showFooter()) {
7821 VikBookingHelper::printFooter();
7822 }
7823 }
7824
7825 public function removeorders()
7826 {
7827 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7828 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7829 }
7830
7831 $dbo = JFactory::getDbo();
7832 $app = JFactory::getApplication();
7833
7834 $ids = VikRequest::getVar('cid', array(0));
7835 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7836
7837 $user = JFactory::getUser();
7838 $config = VBOFactory::getConfig();
7839
7840 $prev_conf_ids = [];
7841 $purged = false;
7842
7843 $tot_cancs = 0;
7844
7845 if (is_array($ids) && count($ids)) {
7846 foreach ($ids as $d) {
7847 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7848 $dbo->setQuery($q, 0, 1);
7849 $row = $dbo->loadAssoc();
7850
7851 // check for any cancellation constraints
7852 $canc_denied = false;
7853 if ($row && class_exists('VCMFeesCancellation')) {
7854 // let VCM detect if there are any constraints for the cancellation
7855 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7856 if ($canc_denied) {
7857 // set error message
7858 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7859 if ($canc_deny_error) {
7860 $app->enqueueMessage($canc_deny_error, 'error');
7861 }
7862 }
7863 }
7864
7865 if ($row && !$canc_denied) {
7866 // increase counter
7867 $tot_cancs++;
7868
7869 // set status to cancelled
7870 if ($row['status'] != 'cancelled') {
7871 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7872 $dbo->setQuery($q);
7873 $dbo->execute();
7874 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7875 $dbo->setQuery($q);
7876 $dbo->execute();
7877 if ($row['status'] == 'confirmed') {
7878 $prev_conf_ids[] = $row['id'];
7879 }
7880 // Booking History
7881 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7882 }
7883
7884 // free records up
7885 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7886 $dbo->setQuery($q);
7887 $ordbusy = $dbo->loadAssocList();
7888 if ($ordbusy) {
7889 foreach ($ordbusy as $ob) {
7890 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7891 $dbo->setQuery($q);
7892 $dbo->execute();
7893 }
7894 }
7895
7896 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7897 $dbo->setQuery($q);
7898 $dbo->execute();
7899
7900 // check for purge removal
7901 if ($row['status'] == 'cancelled') {
7902 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7903 $dbo->setQuery($q);
7904 $dbo->execute();
7905 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7906 $dbo->setQuery($q);
7907 $dbo->execute();
7908 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7909 $dbo->setQuery($q);
7910 $dbo->execute();
7911 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7912 $dbo->setQuery($q);
7913 $dbo->execute();
7914 // in case of split stay booking, remove the transient
7915 if ($row['split_stay']) {
7916 $config->remove('split_stay_' . $row['id']);
7917 }
7918 // turn flag on
7919 $purged = true;
7920 }
7921 }
7922 }
7923
7924 if ($tot_cancs) {
7925 // enqueue system message
7926 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7927 }
7928 }
7929
7930 if ($prev_conf_ids) {
7931 $prev_conf_ids_str = '';
7932 foreach ($prev_conf_ids as $prev_id) {
7933 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7934 }
7935 //Invoke Channel Manager
7936 $vcm_autosync = VikBooking::vcmAutoUpdate();
7937 if ($vcm_autosync > 0) {
7938 $vcm_obj = VikBooking::getVcmInvoker();
7939 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7940 $sync_result = $vcm_obj->doSync();
7941 if ($sync_result === false) {
7942 $vcm_err = $vcm_obj->getError();
7943 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7944 }
7945 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7946 $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');
7947 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7948 }
7949 //
7950 }
7951
7952 if (!empty($pgoto)) {
7953 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7954 if ($purged) {
7955 // go back to the bookings list page
7956 $app->redirect("index.php?option=com_vikbooking&task=orders");
7957 } else {
7958 // go back to the booking details page
7959 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7960 }
7961 exit;
7962 }
7963 // we expect the goto URL to be base64 encoded
7964 $app->redirect(base64_decode($pgoto));
7965 exit;
7966 }
7967
7968 // go back to the bookings list page
7969 $app->redirect("index.php?option=com_vikbooking&task=orders");
7970 }
7971
7972 public function config() {
7973 VikBookingHelper::printHeader("11");
7974
7975 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7976
7977 parent::display();
7978
7979 if (VikBooking::showFooter()) {
7980 VikBookingHelper::printFooter();
7981 }
7982 }
7983
7984 public function saveconfig()
7985 {
7986 if (!JSession::checkToken()) {
7987 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7988 }
7989
7990 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking') || !JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
7991 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7992 }
7993
7994 $dbo = JFactory::getDbo();
7995 $app = JFactory::getApplication();
7996
7997 $config = VBOFactory::getConfig();
7998
7999 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
8000 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
8001 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
8002 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
8003 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
8004 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
8005 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
8006 $pdateformat = VikRequest::getString('dateformat', '', 'request');
8007 $pdatesep = VikRequest::getString('datesep', '', 'request');
8008 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
8009 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
8010 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
8011 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
8012 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
8013 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
8014 $ptokenform = VikRequest::getString('tokenform', '', 'request');
8015 $padminemail = VikRequest::getString('adminemail', '', 'request');
8016 $psenderemail = VikRequest::getString('senderemail', '', 'request');
8017 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
8018 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
8019 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
8020 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
8021 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
8022 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
8023 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
8024 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
8025 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
8026 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
8027 $pusefa = VikRequest::getInt('usefa', '', 'request');
8028 $pusefa = $pusefa > 0 ? 1 : 0;
8029 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
8030 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
8031 $pcalendar = VikRequest::getString('calendar', '', 'request');
8032 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
8033 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
8034 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
8035 $penablepin = VikRequest::getString('enablepin', '', 'request');
8036 $penablepin = $penablepin == "1" ? 1 : 0;
8037 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
8038 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
8039 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
8040 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
8041 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
8042 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
8043 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
8044 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
8045 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
8046 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
8047 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
8048 $pnumadultsfrom = '1';
8049 $pnumadultsto = '10';
8050 }
8051 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
8052 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
8053 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
8054 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
8055 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
8056 $pnumadultsfrom = '1';
8057 $pnumadultsto = '4';
8058 }
8059 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
8060 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
8061 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
8062 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
8063 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
8064 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
8065 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
8066 $pcronkey = VikRequest::getString('cronkey', '', 'request');
8067 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
8068 $pcdsto = VikRequest::getVar('cdsto', array());
8069 $closing_dates = array();
8070 if (count($pcdsfrom)) {
8071 foreach ($pcdsfrom as $kcd => $vcdfrom) {
8072 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
8073 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
8074 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
8075 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
8076 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
8077 if (!in_array($cdval, $closing_dates)) {
8078 $closing_dates[] = $cdval;
8079 }
8080 }
8081 }
8082 }
8083 }
8084 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
8085 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
8086 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
8087 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8088 if ($pvbosef === 1) {
8089 if (!$vbosef) {
8090 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8091 }
8092 } else {
8093 if ($vbosef) {
8094 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
8095 }
8096 }
8097 $pmultilang = VikRequest::getString('multilang', '', 'request');
8098 $pmultilang = $pmultilang == "1" ? 1 : 0;
8099 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
8100 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
8101 /**
8102 * Chat params and configuration settings
8103 *
8104 * @since 1.12
8105 */
8106 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
8107 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
8108 $config->set('chatenabled', $pchatenabled);
8109
8110 // chat params
8111 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
8112 $chat_res_status = array();
8113 foreach ($pchat_res_status as $chatrs) {
8114 if (!empty($chatrs)) {
8115 array_push($chat_res_status, $chatrs);
8116 }
8117 }
8118 $chatparams = new stdClass;
8119 $chatparams->res_status = $chat_res_status;
8120 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
8121 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
8122
8123 $config->set('chatparams', $chatparams);
8124 }
8125
8126 /**
8127 * Pre check-in configuration settings
8128 *
8129 * @since 1.12
8130 */
8131 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
8132 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
8133
8134 $config->set('precheckinenabled', $pprecheckinenabled);
8135 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
8136
8137 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
8138 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
8139 $config->set('upselling', $pupsellingenabled);
8140
8141 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
8142 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
8143 $config->set('orphanscalculation', $porphanscal);
8144
8145 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
8146 $config->set('searchrestmpl', $psrcrtpl);
8147
8148 /**
8149 * Guest Reviews settings
8150 *
8151 * @since 1.13
8152 */
8153 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
8154 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
8155 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
8156 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
8157 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
8158 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
8159 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
8160 $config->set('grenabled', $pgrenabled);
8161 $config->set('grminchars', $pgrminchars);
8162 $config->set('grappr', $pgrappr);
8163 $config->set('grtype', $pgrtype);
8164 try {
8165 // always truncate service names (this query may require special permissions)
8166 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
8167 $dbo->setQuery($q);
8168 $dbo->execute();
8169 } catch (Exception $e) {
8170 // do nothing
8171 }
8172 foreach ($pgrsrv as $srvname) {
8173 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
8174 $dbo->setQuery($q);
8175 $dbo->execute();
8176 }
8177
8178 /**
8179 * Preferred countries ordering, or custom countries.
8180 *
8181 * @since 1.14 (J) - 1.3.11 (WP)
8182 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
8183 */
8184 $pref_countries = VikRequest::getVar('pref_countries', array());
8185 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
8186 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
8187 if (!empty($cust_pref_countries)) {
8188 $all_custom_prefcountries = array();
8189 $cust_pref_countries = explode(',', $cust_pref_countries);
8190 foreach ($cust_pref_countries as $cust_pref_country) {
8191 $cust_pref_country = trim(strtolower($cust_pref_country));
8192 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
8193 continue;
8194 }
8195 array_push($all_custom_prefcountries, $cust_pref_country);
8196 }
8197 if (count($all_custom_prefcountries)) {
8198 $pref_countries = $all_custom_prefcountries;
8199 }
8200 }
8201 $config->set('preferred_countries', $pref_countries);
8202 //
8203
8204 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
8205 $config->set('gmapskey', $gmapskey);
8206
8207 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
8208 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
8209 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
8210 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
8211 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
8212 $pref_colors = array(
8213 'textcolor' => $pref_textcolor,
8214 'bgcolor' => $pref_bgcolor,
8215 'fontcolor' => $pref_fontcolor,
8216 'bgcolorhov' => $pref_bgcolorhov,
8217 'fontcolorhov' => $pref_fontcolorhov,
8218 );
8219 $config->set('pref_colors', $pref_colors);
8220
8221 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
8222 $config->set('interactive_map', $interactive_map);
8223
8224 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
8225 $config->set('noemptydecimals', $noemptydecimals);
8226
8227 /**
8228 * Appearance preferences (light, auto, dark mode).
8229 *
8230 * @since 1.15.0 (J) - 1.5.0 (WP)
8231 * @since 1.16.10 (J) - 1.6.10 (WP) mirrored on VCM.
8232 */
8233 $appearance_pref = VikRequest::getString('appearance_pref', '');
8234 $config->set('appearance_pref', $appearance_pref);
8235 if (class_exists('VCMFactory')) {
8236 VCMFactory::getConfig()->set('appearance_pref', $appearance_pref);
8237 }
8238
8239 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
8240 $picon = "";
8241 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
8242 jimport('joomla.filesystem.file');
8243 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
8244 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
8245 if (file_exists($res_backend_path.$safename)) {
8246 $j = 1;
8247 while (file_exists($res_backend_path.$j.$safename)) {
8248 $j++;
8249 }
8250 $pwhere = $res_backend_path.$j.$safename;
8251 } else {
8252 $j = "";
8253 $pwhere = $res_backend_path.$safename;
8254 }
8255 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8256 @unlink($pwhere);
8257 $picon = "";
8258 } else {
8259 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
8260 @chmod($pwhere, 0644);
8261 $picon = $j.$safename;
8262 }
8263 }
8264 if (!empty($picon)) {
8265 $config->set('sitelogo', $picon);
8266 }
8267 }
8268 $pbackicon = "";
8269 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
8270 jimport('joomla.filesystem.file');
8271 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
8272 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
8273 if (file_exists($res_backend_path.$safename)) {
8274 $j = 1;
8275 while (file_exists($res_backend_path.$j.$safename)) {
8276 $j++;
8277 }
8278 $pwhere = $res_backend_path.$j.$safename;
8279 } else {
8280 $j = "";
8281 $pwhere = $res_backend_path.$safename;
8282 }
8283 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8284 @unlink($pwhere);
8285 $pbackicon = "";
8286 } else {
8287 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
8288 @chmod($pwhere, 0644);
8289 $pbackicon = $j.$safename;
8290 }
8291 }
8292 if (!empty($pbackicon)) {
8293 $config->set('backlogo', $pbackicon);
8294 }
8295 }
8296 $config->set('vcmautoupd', $pvcmautoupd);
8297 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
8298 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
8299 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
8300 $config->set('searchsuggestions', $psearchsuggestions);
8301 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
8302 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
8303
8304 // translatable text
8305 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
8306 $dbo->setQuery($q);
8307 $dbo->execute();
8308
8309 // translatable text
8310 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
8311 $dbo->setQuery($q);
8312 $dbo->execute();
8313
8314 // translatable text
8315 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
8316 $dbo->setQuery($q);
8317 $dbo->execute();
8318
8319 // terms and conditions
8320 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
8321 $dbo->setQuery($q);
8322 $dbo->execute();
8323 if ($dbo->getNumRows() > 0) {
8324 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
8325 $dbo->setQuery($q);
8326 $dbo->execute();
8327 } else {
8328 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
8329 $dbo->setQuery($q);
8330 $dbo->execute();
8331 }
8332
8333 $config->set('adminemail', $padminemail);
8334 $config->set('senderemail', $psenderemail);
8335 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
8336 $config->set('datesep', $pdatesep);
8337 $config->set('resmodcanc', $presmodcanc);
8338 $config->set('resmodcancmin', $presmodcancmin);
8339 $config->set('minuteslock', $pminuteslock);
8340 $config->set('minautoremove', $pminautoremove);
8341
8342 $openingh = $ptimeopenstorefh * 3600;
8343 $openingm = $ptimeopenstorefm * 60;
8344 $openingts = $openingh + $openingm;
8345 $closingh = $ptimeopenstoreth * 3600;
8346 $closingm = $ptimeopenstoretm * 60;
8347 $closingts = $closingh + $closingm;
8348 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
8349 $prevtimes = $config->get('timeopenstore', '');
8350 if ($prevtimes != $openingts . "-" . $closingts) {
8351 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
8352 $dbo->setQuery($q);
8353 $dbo->execute();
8354 if ($dbo->getNumRows() > 0) {
8355 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
8356 /**
8357 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
8358 * for all reservations to avoid issues with the availability.
8359 *
8360 * @since August 29th 2018
8361 */
8362 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>');
8363 //
8364 }
8365 }
8366 $config->set('timeopenstore', $openingts . "-" . $closingts);
8367
8368 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
8369 $phoursmorebookingback = "0";
8370 if ($closingts > $openingts) {
8371 $diffcheck = ($closingts - $openingts) / 3600;
8372 $phoursmorebookingback = ceil($diffcheck);
8373 }
8374 $config->set('hoursmorebookingback', $phoursmorebookingback);
8375 $config->set('hoursmoreroomavail', '0');
8376 $config->set('multilang', $pmultilang);
8377 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
8378 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
8379 $config->set('todaybookings', $ptodaybookings);
8380 $config->set('bootstrap', $ploadbootstrap);
8381 $config->set('usefa', $pusefa);
8382 $config->set('loadjquery', $ploadjquery);
8383 $config->set('calendar', $pcalendar);
8384 $config->set('enablecoupons', $penablecoupons);
8385 $config->set('enablepin', $penablepin);
8386 $config->set('mindaysadvance', $pmindaysadvance);
8387 $config->set('autodefcalnights', $pautodefcalnights);
8388 $config->set('numrooms', $pnumrooms);
8389 $config->set('numadults', $confnumadults);
8390 $config->set('numchildren', $confnumchildren);
8391 $config->set('closingdates', $closing_dates);
8392 $config->set('smartsearch', $psmartsearch);
8393 $config->set('maxdate', $maxdate_str);
8394 $config->set('cronkey', $pcronkey);
8395
8396 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
8397 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
8398 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
8399 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
8400 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
8401 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
8402 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
8403 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
8404 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
8405 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
8406 $pnumdecimals = intval($pnumdecimals);
8407 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
8408 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
8409 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
8410 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
8411 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
8412 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
8413 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
8414 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
8415 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
8416 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
8417 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
8418 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
8419 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
8420 $pbctagname = VikRequest::getVar('bctagname', array());
8421 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
8422 $pbctagrule = VikRequest::getVar('bctagrule', array());
8423 $bctags_arr = array();
8424 $bctags_rules = array();
8425 if (count($pbctagname) > 0) {
8426 foreach ($pbctagname as $bctk => $bctv) {
8427 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
8428 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
8429 $bctags_rules[] = $pbctagrule[$bctk];
8430 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8431 }
8432 }
8433 }
8434 }
8435 //theme
8436 $ptheme = VikRequest::getString('theme', '', 'request');
8437 if (empty($ptheme) || $ptheme == 'default') {
8438 $ptheme = 'default';
8439 } else {
8440 $validtheme = false;
8441 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8442 if (count($themes) > 0) {
8443 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8444 foreach ($themes as $th) {
8445 if (is_dir($th)) {
8446 $tname = str_replace($strip, '', $th);
8447 if ($tname == $ptheme) {
8448 $validtheme = true;
8449 break;
8450 }
8451 }
8452 }
8453 }
8454 if ($validtheme == false) {
8455 $ptheme = 'default';
8456 }
8457 }
8458 $config->set('theme', $ptheme);
8459 //
8460 $config->set('showpartlyreserved', $pshowpartlyreserved);
8461 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8462 $config->set('numcalendars', $pnumcalendars);
8463
8464 // record may not be set
8465 $config->set('thumbsize', $pthumbsize);
8466
8467 $config->set('firstwday', $pfirstwday);
8468
8469 // translatable text
8470 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8471 $dbo->setQuery($q);
8472 $dbo->execute();
8473
8474 $config->set('fronttitletag', $pfronttitletag);
8475 $config->set('fronttitletagclass', $pfronttitletagclass);
8476 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8477
8478 // translatable texts
8479 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8480 $dbo->setQuery($q);
8481 $dbo->execute();
8482 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8483 $dbo->setQuery($q);
8484 $dbo->execute();
8485
8486 $config->set('currencyname', $pcurrencyname);
8487 $config->set('currencysymb', $pcurrencysymb);
8488 $config->set('currencycodepp', $pcurrencycodepp);
8489 $config->set('numberformat', $numberformatstr);
8490 // bookings color tags
8491 $config->set('bookingsctags', $bctags_arr);
8492
8493 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8494 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8495 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8496 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8497 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8498 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8499 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8500 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8501 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8502 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8503 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8504 $pmultipay = VikRequest::getString('multipay', '', 'request');
8505 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8506 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8507 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8508 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8509 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8510
8511 // translatable text
8512 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8513 $dbo->setQuery($q);
8514 $dbo->execute();
8515 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8516 $dbo->setQuery($q);
8517 $dbo->execute();
8518
8519 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8520 $config->set('taxsummary', $ptaxsummary);
8521 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8522
8523 $config->set('ccpaypal', $pccpaypal);
8524 $config->set('payaccpercent', $ppayaccpercent);
8525 $config->set('typedeposit', $ptypedeposit);
8526 $config->set('depoverrides', $pdepoverrides);
8527 $config->set('multipay', $pmultipay);
8528 $config->set('depifdaysadv', $pdepifdaysadv);
8529 $config->set('nodepnonrefund', $pnodepnonrefund);
8530 $config->set('depcustchoice', $pdepcustchoice);
8531
8532 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8533 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8534 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8535 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8536 $config->set('emailsendwhen', $psendemailwhen);
8537 $config->set('attachical', $pattachical);
8538
8539 // SMS APIs
8540 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8541 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8542 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8543 $psmssendto = VikRequest::getVar('smssendto', array());
8544 $sms_sendto = array();
8545 foreach ($psmssendto as $sto) {
8546 if (in_array($sto, array('admin', 'customer'))) {
8547 $sms_sendto[] = $sto;
8548 }
8549 }
8550 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8551 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8552 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8553 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8554 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8555 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8556 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8557 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8558 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8559 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8560 $smsparamarr = array();
8561 if (count($viksmsparams) > 0) {
8562 foreach ($viksmsparams as $setting => $cont) {
8563 if (strlen($setting) > 0) {
8564 $smsparamarr[$setting] = $cont;
8565 }
8566 }
8567 }
8568 $config->set('smsapi', $psmsapi);
8569 $config->set('smsautosend', $psmsautosend);
8570 $config->set('smssendto', $sms_sendto);
8571 $config->set('smssendwhen', $psmssendwhen);
8572 $config->set('smsadminphone', $psmsadminphone);
8573 $config->set('smsparams', $smsparamarr);
8574
8575 // translatable texts
8576 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8577 $dbo->setQuery($q);
8578 $dbo->execute();
8579 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8580 $dbo->setQuery($q);
8581 $dbo->execute();
8582 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8583 $dbo->setQuery($q);
8584 $dbo->execute();
8585 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8586 $dbo->setQuery($q);
8587 $dbo->execute();
8588 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8589 $dbo->setQuery($q);
8590 $dbo->execute();
8591 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8592 $dbo->setQuery($q);
8593 $dbo->execute();
8594
8595 /**
8596 * Backup settings
8597 *
8598 * @since 1.15.0 (J) - 1.5.0 (WP)
8599 */
8600 $backup_type = $app->input->getString('backuptype', 'full');
8601 $backup_folder = $app->input->getString('backupfolder', '');
8602
8603 $tmp = $app->get('tmp_path');
8604
8605 if (!$backup_folder)
8606 {
8607 // path not specified, use temporary folder
8608 $backup_folder = $tmp;
8609 }
8610
8611 $current = $config->get('backupfolder');
8612
8613 if (!$current)
8614 {
8615 // path was missing, use temporary folder
8616 $current = $tmp;
8617 }
8618
8619 // check whether the backup folder has been moved
8620 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8621 {
8622 $backupModel = new VBOModelBackup();
8623
8624 // backup folder moved, try to copy all the existing overrides
8625 if (!$backupModel->moveArchives($backup_folder))
8626 {
8627 // iterate all errors and display them
8628 foreach ($backupModel->getErrors() as $error)
8629 {
8630 $app->enqueueMessage($error, 'warning');
8631 }
8632 }
8633 }
8634
8635 // save configuration
8636 $config->set('backuptype', $backup_type);
8637 $config->set('backupfolder', $backup_folder);
8638
8639 /**
8640 * Check-in data collection type.
8641 *
8642 * @since 1.15.0 (J) - 1.5.0 (WP)
8643 */
8644 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8645
8646 /**
8647 * Front-end appearance.
8648 *
8649 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8650 */
8651 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8652
8653 /**
8654 * Split stays.
8655 *
8656 * @since 1.16.0 (J) - 1.6.0 (WP)
8657 */
8658 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8659 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8660 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8661 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8662
8663 /**
8664 * Re-build Web App manifest file to let the event trigger.
8665 *
8666 * @since 1.16.5 (J) - 1.6.5 (WP)
8667 */
8668 try {
8669 VBOWebappManifest::build();
8670 } catch (Exception $e) {
8671 // do nothing
8672 }
8673
8674 // redirect
8675 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8676 $app->redirect('index.php?option=com_vikbooking&task=config');
8677 $app->close();
8678 }
8679
8680 /**
8681 * Task to unify the check-in and check-out times for all reservations.
8682 */
8683 public function unifycheckinout()
8684 {
8685 $dbo = JFactory::getDbo();
8686 $app = JFactory::getApplication();
8687 $user = JFactory::getUser();
8688
8689 $fh = VikRequest::getInt('fh', 12, 'request');
8690 $fm = VikRequest::getInt('fm', 0, 'request');
8691 $th = VikRequest::getInt('th', 10, 'request');
8692 $tm = VikRequest::getInt('tm', 0, 'request');
8693
8694 $now = time();
8695 $totmod = 0;
8696 $totbookmod = 0;
8697
8698 // query all busy records
8699 $q = $dbo->getQuery(true)
8700 ->select('*')
8701 ->from($dbo->qn('#__vikbooking_busy'));
8702
8703 $dbo->setQuery($q);
8704 $records = $dbo->loadAssocList();
8705
8706 foreach ($records as $v) {
8707 $info_start = getdate($v['checkin']);
8708 $info_end = getdate($v['checkout']);
8709 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8710 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8711
8712 $q = $dbo->getQuery(true)
8713 ->update($dbo->qn('#__vikbooking_busy'))
8714 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8715 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8716 ->set($dbo->qn('realback') . ' = ' . $new_end)
8717 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8718
8719 $dbo->setQuery($q, 0, 1);
8720 $dbo->execute();
8721
8722 $totmod++;
8723 }
8724
8725 // query all bookings
8726 $q = $dbo->getQuery(true)
8727 ->select($dbo->qn([
8728 'id',
8729 'days',
8730 'checkin',
8731 'checkout',
8732 'total',
8733 ]))
8734 ->from($dbo->qn('#__vikbooking_orders'))
8735 ->order($dbo->qn('checkin') . ' DESC');
8736
8737 $dbo->setQuery($q);
8738 $records = $dbo->loadAssocList();
8739
8740 foreach ($records as $v) {
8741 $info_start = getdate($v['checkin']);
8742 $info_end = getdate($v['checkout']);
8743 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8744 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8745
8746 $q = $dbo->getQuery(true)
8747 ->update($dbo->qn('#__vikbooking_orders'))
8748 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8749 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8750 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8751
8752 $dbo->setQuery($q, 0, 1);
8753 $dbo->execute();
8754
8755 /**
8756 * In case the operation changed the check-in/check-out time for this booking,
8757 * store a new history record for a booking modification.
8758 *
8759 * @since 1.16.6 (J) - 1.6.6 (WP)
8760 */
8761 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8762 // Booking History
8763 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8764 }
8765
8766 $totbookmod++;
8767 }
8768
8769 $app->enqueueMessage('OK: ' . $totbookmod);
8770 $app->redirect("index.php?option=com_vikbooking&task=config");
8771 $app->close();
8772 }
8773
8774 public function savetmplfile() {
8775 if (!JSession::checkToken()) {
8776 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8777 }
8778 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8779 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8780 $mainframe = JFactory::getApplication();
8781 $exists = file_exists($fpath) ? true : false;
8782 if (!$exists) {
8783 $fpath = urldecode($fpath);
8784 }
8785 $fpath = file_exists($fpath) ? $fpath : '';
8786 if (!empty($fpath)) {
8787 $fp = fopen($fpath, 'wb');
8788 $byt = (int)fwrite($fp, $pcont);
8789 fclose($fp);
8790 if ($byt > 0) {
8791 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8792
8793 if (VBOPlatformDetection::isWordPress()) {
8794 /**
8795 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8796 */
8797 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8798 }
8799 } else {
8800 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8801 }
8802 } else {
8803 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8804 }
8805 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8806
8807 exit;
8808 }
8809
8810 public function edittmplfile() {
8811 //modal box, so we do not set menu or footer
8812
8813 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8814
8815 parent::display();
8816 }
8817
8818 public function tmplfileprew() {
8819 //modal box, so we do not set menu or footer
8820
8821 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8822
8823 parent::display();
8824 }
8825
8826 public function invoices() {
8827 VikBookingHelper::printHeader("invoices");
8828
8829 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8830
8831 parent::display();
8832
8833 if (VikBooking::showFooter()) {
8834 VikBookingHelper::printFooter();
8835 }
8836 }
8837
8838 public function newmaninvoice() {
8839 VikBookingHelper::printHeader("invoices");
8840
8841 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8842
8843 parent::display();
8844
8845 if (VikBooking::showFooter()) {
8846 VikBookingHelper::printFooter();
8847 }
8848 }
8849
8850 public function editmaninvoice() {
8851 VikBookingHelper::printHeader("invoices");
8852
8853 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8854
8855 parent::display();
8856
8857 if (VikBooking::showFooter()) {
8858 VikBookingHelper::printFooter();
8859 }
8860 }
8861
8862 public function savemaninvoice() {
8863 if (!JSession::checkToken()) {
8864 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8865 }
8866 $this->do_storemaninvoice('save');
8867 $mainframe = JFactory::getApplication();
8868 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8869 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8870 if (!empty($pgoto)) {
8871 $mainframe->redirect(base64_decode($pgoto));
8872 exit;
8873 }
8874 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8875 }
8876
8877 public function updatemaninvoice()
8878 {
8879 if (!JSession::checkToken()) {
8880 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8881 }
8882
8883 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8884 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8885 }
8886
8887 $invid = VikRequest::getInt('whereup', 0, 'request');
8888 $this->do_storemaninvoice('update', $invid);
8889 $mainframe = JFactory::getApplication();
8890 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8891 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8892 if (!empty($pgoto)) {
8893 $mainframe->redirect(base64_decode($pgoto));
8894 exit;
8895 }
8896 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8897 }
8898
8899 public function updatemaninvoicestay()
8900 {
8901 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8902 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8903 }
8904
8905 $invid = VikRequest::getInt('whereup', 0, 'request');
8906 $this->do_storemaninvoice('updatestay', $invid);
8907 $mainframe = JFactory::getApplication();
8908 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8909 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8910 if (!empty($pgoto)) {
8911 $mainframe->redirect(base64_decode($pgoto));
8912 exit;
8913 }
8914 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8915 }
8916
8917 private function do_storemaninvoice($action, $invid = 0) {
8918 $dbo = JFactory::getDBO();
8919 $mainframe = JFactory::getApplication();
8920 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8921 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8922 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8923 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8924 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8925 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8926 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8927 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8928 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8929 if (empty($pidcustomer)) {
8930 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8931 $mainframe->redirect($error_uri);
8932 exit;
8933 }
8934 $services = VikRequest::getVar('service', array());
8935 $nets = VikRequest::getVar('net', array());
8936 $aliqs = VikRequest::getVar('aliq', array());
8937 $taxs = VikRequest::getVar('tax', array());
8938 $tots = VikRequest::getVar('tot', array());
8939 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8940 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8941 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8942 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8943 VikError::raiseWarning('', 'Missing data.');
8944 $mainframe->redirect($error_uri);
8945 exit;
8946 }
8947 $rawcont = array(
8948 'rows' => array(),
8949 'totalnet' => $ptotalnet,
8950 'totaltax' => $ptotaltax,
8951 'totaltot' => $ptotaltot,
8952 'notes' => $pinvoice_notes,
8953 );
8954 foreach ($services as $k => $service) {
8955 if (empty($service)) {
8956 continue;
8957 }
8958 array_push($rawcont['rows'], array(
8959 'service' => $service,
8960 'net' => (float)$nets[$k],
8961 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8962 'tax' => (float)$taxs[$k],
8963 'tot' => (float)$tots[$k],
8964 ));
8965 }
8966 // store/update manual invoice
8967 $nowts = time();
8968 $retval = 0;
8969 if (strpos($action, 'save') !== false) {
8970 $pdffname = $nowts . '_' . rand() . '.pdf';
8971 $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)).");";
8972 $dbo->setQuery($q);
8973 $dbo->execute();
8974 $retval = $dbo->insertid();
8975 } else {
8976 // fetch old record
8977 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8978 $dbo->setQuery($q);
8979 $dbo->execute();
8980 if (!$dbo->getNumRows()) {
8981 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8982 $mainframe->redirect($error_uri);
8983 exit;
8984 }
8985 $previnvoice = $dbo->loadAssoc();
8986 //
8987 $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'].";";
8988 $dbo->setQuery($q);
8989 $dbo->execute();
8990 $retval = $previnvoice['id'];
8991 }
8992 // update config values for the invoice
8993 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8994 $dbo->setQuery($q);
8995 $dbo->execute();
8996 // generate the custom invoice
8997 $result = VikBooking::generateCustomInvoice($retval);
8998 //
8999 $nextinv = VikBooking::getNextInvoiceNumber();
9000 $updatenum = ($pinvoice_num >= $nextinv);
9001 if ($updatenum) {
9002 /**
9003 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
9004 * to avoid conflicts with the drivers for the e-invoices generation.
9005 */
9006 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9007 $dbo->setQuery($q);
9008 $dbo->execute();
9009 }
9010
9011 return $retval;
9012 }
9013
9014 public function downloadinvoices() {
9015 $ids = VikRequest::getVar('cid', array(0));
9016 if (@count($ids) > 0) {
9017 $dbo = JFactory::getDBO();
9018 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
9019 $dbo->setQuery($q);
9020 $dbo->execute();
9021 if ($dbo->getNumRows() > 0) {
9022 $invoices = $dbo->loadAssocList();
9023 if (!(count($invoices) > 1)) {
9024 //Single Invoice Download
9025 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
9026 header("Content-type:application/pdf");
9027 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
9028 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
9029 exit;
9030 }
9031 } else {
9032 //Multiple Invoices Download
9033 $to_zip = array();
9034 foreach ($invoices as $k => $invoice) {
9035 $to_zip[$k]['name'] = $invoice['file_name'];
9036 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
9037 }
9038 if (class_exists('ZipArchive')) {
9039 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
9040 $zip = new ZipArchive;
9041 $zip->open($zip_path, ZipArchive::CREATE);
9042 foreach ($to_zip as $k => $zipv) {
9043 $zip->addFile($zipv['path'], $zipv['name']);
9044 }
9045 $zip->close();
9046 header("Content-type:application/zip");
9047 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
9048 header("Content-Length:".filesize($zip_path));
9049 readfile($zip_path);
9050 unlink($zip_path);
9051 exit;
9052 } else {
9053 //Class ZipArchive does not exist
9054 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
9055 }
9056 }
9057 }
9058 }
9059 $mainframe = JFactory::getApplication();
9060 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9061 }
9062
9063 public function resendinvoices() {
9064 $ids = VikRequest::getVar('cid', array(0));
9065 $mainframe = JFactory::getApplication();
9066 if (!(count($ids) > 0)) {
9067 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9068 exit;
9069 }
9070 $dbo = JFactory::getDBO();
9071 $invoices = array();
9072 $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` ".
9073 "FROM `#__vikbooking_invoices` AS `i` " .
9074 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
9075 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
9076 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
9077 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
9078 $dbo->setQuery($q);
9079 $dbo->execute();
9080 if ($dbo->getNumRows() > 0) {
9081 $invoices = $dbo->loadAssocList();
9082 }
9083 if (!(count($invoices) > 0)) {
9084 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9085 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9086 exit;
9087 }
9088 $tot_generated = 0;
9089 $tot_sent = 0;
9090 foreach ($invoices as $bkey => $invoice) {
9091 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
9092 $invoices[$bkey] = $invoice;
9093 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
9094 if ($send_res !== false) {
9095 $tot_sent++;
9096 }
9097 }
9098 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9099 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9100 }
9101
9102 public function removeinvoices()
9103 {
9104 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9105 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9106 }
9107
9108 $ids = VikRequest::getVar('cid', array());
9109 $tot_removed = 0;
9110 $dbo = JFactory::getDbo();
9111
9112 foreach ($ids as $d) {
9113 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9114 $dbo->setQuery($q);
9115 $dbo->execute();
9116 if ($dbo->getNumRows() == 1) {
9117 $cur_invoice = $dbo->loadAssoc();
9118 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
9119 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
9120 }
9121 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9122 $dbo->setQuery($q);
9123 $dbo->execute();
9124 $tot_removed++;
9125 }
9126 }
9127
9128 $mainframe = JFactory::getApplication();
9129 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
9130 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9131 }
9132
9133 public function geninvoices()
9134 {
9135 $dbo = JFactory::getDbo();
9136 $app = JFactory::getApplication();
9137
9138 $ids = VikRequest::getVar('cid', array());
9139
9140 if (!$ids) {
9141 $app->redirect("index.php?option=com_vikbooking&task=orders");
9142 exit;
9143 }
9144
9145 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
9146 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
9147 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
9148 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
9149 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
9150 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
9151 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
9152 $pinvoice_send = $pinvoice_send > 0 ? true : false;
9153 $increment_inv = true;
9154 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
9155
9156 // if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
9157 if (count($ids) === 1) {
9158 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
9159 $dbo->setQuery($q);
9160 $dbo->execute();
9161 if ($dbo->getNumRows() == 1) {
9162 $increment_inv = false;
9163 }
9164 }
9165
9166 // get bookings
9167 $dbo->setQuery(
9168 $dbo->getQuery(true)
9169 ->select($dbo->qn('o') . '.*')
9170 ->select($dbo->qn('co.idcustomer'))
9171 ->select('CONCAT_WS(\' \', ' . $dbo->qn('c.first_name') . ', ' . $dbo->qn('c.last_name') . ') AS ' . $dbo->qn('customer_name'))
9172 ->select([
9173 $dbo->qn('c.pin', 'customer_pin'),
9174 $dbo->qn('nat.country_name'),
9175 ])
9176 ->from($dbo->qn('#__vikbooking_orders', 'o'))
9177 ->leftJoin($dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $dbo->qn('co.idorder') . ' = ' . $dbo->qn('o.id'))
9178 ->leftJoin($dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $dbo->qn('c.id') . ' = ' . $dbo->qn('co.idcustomer'))
9179 ->leftJoin($dbo->qn('#__vikbooking_countries', 'nat') . ' ON ' . $dbo->qn('nat.country_3_code') . ' = ' . $dbo->qn('o.country'))
9180 ->where($dbo->qn('o.id') . ' IN (' . implode(', ', array_map('intval', $ids)) . ')')
9181 ->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed'))
9182 ->where($dbo->qn('o.total') . ' > 0')
9183 ->order($dbo->qn('o.id') . ' ASC')
9184 );
9185
9186 $bookings = $dbo->loadAssocList();
9187
9188 if (!$bookings) {
9189 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9190 $app->redirect("index.php?option=com_vikbooking&task=orders");
9191 exit;
9192 }
9193
9194 $tot_generated = 0;
9195 $tot_sent = 0;
9196 foreach ($bookings as $bkey => $booking) {
9197 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
9198 if ($gen_res !== false && $gen_res > 0) {
9199 $tot_generated++;
9200 $pinvoice_num++;
9201 if ($pinvoice_send) {
9202 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
9203 if ($send_res !== false) {
9204 $tot_sent++;
9205 }
9206 }
9207 } else {
9208 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
9209 }
9210 }
9211
9212 if ($tot_generated > 0 && $increment_inv === true) {
9213 /**
9214 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
9215 * to avoid conflicts with the drivers for the e-invoices generation.
9216 */
9217 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9218 $dbo->setQuery($q);
9219 $dbo->execute();
9220 }
9221
9222 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
9223 $dbo->setQuery($q);
9224 $dbo->execute();
9225
9226 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
9227 $dbo->setQuery($q);
9228 $dbo->execute();
9229
9230 $app->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9231
9232 if ($pconfirmgen > 0) {
9233 $app->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
9234 } elseif (count($bookings) === 1) {
9235 // go to the back-end booking details page
9236 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
9237 } else {
9238 $app->redirect("index.php?option=com_vikbooking&task=orders");
9239 }
9240 }
9241
9242 public function optionals() {
9243 VikBookingHelper::printHeader("6");
9244
9245 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
9246
9247 parent::display();
9248
9249 if (VikBooking::showFooter()) {
9250 VikBookingHelper::printFooter();
9251 }
9252 }
9253
9254 public function newoptionals() {
9255 VikBookingHelper::printHeader("6");
9256
9257 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9258
9259 parent::display();
9260
9261 if (VikBooking::showFooter()) {
9262 VikBookingHelper::printFooter();
9263 }
9264 }
9265
9266 public function editoptional() {
9267 VikBookingHelper::printHeader("6");
9268
9269 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9270
9271 parent::display();
9272
9273 if (VikBooking::showFooter()) {
9274 VikBookingHelper::printFooter();
9275 }
9276 }
9277
9278 public function updateoptional()
9279 {
9280 if (!JSession::checkToken()) {
9281 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9282 }
9283
9284 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9285 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9286 }
9287
9288 $this->do_updateoptional();
9289 }
9290
9291 public function updateoptionalstay()
9292 {
9293 if (!JSession::checkToken()) {
9294 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9295 }
9296
9297 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9298 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9299 }
9300
9301 $this->do_updateoptional(true);
9302 }
9303
9304 private function do_updateoptional($stay = false) {
9305 $dbo = JFactory::getDbo();
9306 $app = JFactory::getApplication();
9307 $poptname = VikRequest::getString('optname', '', 'request');
9308 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9309 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9310 $poptperday = VikRequest::getString('optperday', '', 'request');
9311 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9312 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9313 $popthmany = VikRequest::getString('opthmany', '', 'request');
9314 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9315 $pwhereup = VikRequest::getString('whereup', '', 'request');
9316 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9317 $presizeto = VikRequest::getString('resizeto', '', 'request');
9318 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9319 $pifchildren = $pifchildren == "1" ? 1 : 0;
9320 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9321 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9322 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9323 $pforceval = VikRequest::getString('forceval', '', 'request');
9324 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9325 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9326 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9327 $pforcesel = $pforcesel == "1" ? 1 : 0;
9328 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9329 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9330 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9331 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9332 $pagefrom = VikRequest::getVar('agefrom', array());
9333 $pageto = VikRequest::getVar('ageto', array());
9334 $pagecost = VikRequest::getVar('agecost', array());
9335 $pagectype = VikRequest::getVar('agectype', array());
9336 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9337 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9338 $pavto = VikRequest::getString('avto', '', 'request');
9339 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9340 $pidrooms = VikRequest::getVar('idrooms', array());
9341 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9342 if ($pforcesel == 1) {
9343 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9344 } else {
9345 $strforceval = "";
9346 }
9347 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9348 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9349 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9350 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9351 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9352 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9353 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9354 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9355 $minguests = VikRequest::getInt('minguests', 0, 'request');
9356 $minguests_conflict = false;
9357 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9358 if ($minguestsnum >= $maxguestsnum) {
9359 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9360 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9361 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9362 }
9363 }
9364 if (!$minguests || $minguests_conflict !== false) {
9365 $minguestsnum = 0;
9366 $maxguestsnum = 0;
9367 if ($minguests_conflict !== false) {
9368 // raise warning, but do not stop the process
9369 VikError::raiseWarning('', $minguests_conflict);
9370 }
9371 }
9372 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9373 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9374 $oparams = array(
9375 'minguestsnum' => $minguestsnum,
9376 'mingueststype' => $mingueststype,
9377 'maxguestsnum' => $maxguestsnum,
9378 'maxgueststype' => $maxgueststype,
9379 'damagedep' => $damagedep,
9380 'pet_fee' => $pet_fee,
9381 );
9382 /**
9383 * We fetch the previous params to merge them with the new ones
9384 * in case some properties have been set somewhere else.
9385 * For example, the damage deposit transmission to Booking.com.
9386 */
9387 $cur_oparams = array();
9388 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
9389 $dbo->setQuery($q);
9390 $dbo->execute();
9391 if ($dbo->getNumRows()) {
9392 $cur_oparams = $dbo->loadResult();
9393 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
9394 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
9395 // merge previous params with the new ones to get the new values
9396 $oparams = array_merge($cur_oparams, $oparams);
9397 }
9398 //
9399 if (!empty($poptname)) {
9400 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9401 jimport('joomla.filesystem.file');
9402 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9403 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9404 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9405 if (file_exists($updpath.$safename)) {
9406 $j=1;
9407 while (file_exists($updpath.$j.$safename)) {
9408 $j++;
9409 }
9410 $pwhere=$updpath.$j.$safename;
9411 } else {
9412 $j="";
9413 $pwhere=$updpath.$safename;
9414 }
9415 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9416 @unlink($pwhere);
9417 $picon="";
9418 } else {
9419 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9420 @chmod($pwhere, 0644);
9421 $picon=$j.$safename;
9422 if ($pautoresize=="1" && !empty($presizeto)) {
9423 $eforj = new vikResizer();
9424 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9425 if ($origmod) {
9426 @unlink($pwhere);
9427 $picon='r_'.$j.$safename;
9428 }
9429 }
9430 }
9431 } else {
9432 $picon="";
9433 }
9434 } else {
9435 $picon="";
9436 }
9437 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
9438 $poptperperson=($poptperperson=="each" ? "1" : "0");
9439 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
9440 $ageintervalstr = '';
9441 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9442 foreach ($pagefrom as $kage => $vage) {
9443 $afrom = intval($vage);
9444 $ato = intval($pageto[$kage]);
9445 $acost = floatval($pagecost[$kage]);
9446 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9447 if ($ato < $afrom) $ato = $afrom;
9448 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9449 }
9450 }
9451 $ageintervalstr = rtrim($ageintervalstr, ';;');
9452 if (!empty($ageintervalstr)) {
9453 $pforcesel = 1;
9454 }
9455 }
9456 $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).";";
9457 $dbo->setQuery($q);
9458 $dbo->execute();
9459 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
9460
9461 // assign/unset option-rooms relations
9462 $rooms_with_opt = array();
9463 if (count($pidrooms)) {
9464 // assign this new option to the requested rooms
9465 foreach ($pidrooms as $idroom) {
9466 if (empty($idroom)) {
9467 continue;
9468 }
9469 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9470 $dbo->setQuery($q);
9471 $dbo->execute();
9472 if (!$dbo->getNumRows()) {
9473 continue;
9474 }
9475 $room_data = $dbo->loadAssoc();
9476 array_push($rooms_with_opt, $room_data['id']);
9477 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9478 if (in_array((string)$pwhereup, $current_opts)) {
9479 continue;
9480 }
9481 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9482 // make sure we do not concatenate a real ID to 0
9483 $current_opts = array();
9484 }
9485 array_push($current_opts, $pwhereup);
9486 $new_opts = implode(';', $current_opts) . ';';
9487 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9488 $dbo->setQuery($q);
9489 $dbo->execute();
9490 }
9491 }
9492 if (!count($rooms_with_opt)) {
9493 // get all rooms to unset this option (if previously set)
9494 array_push($rooms_with_opt, '0');
9495 }
9496 // unset the option from the other rooms that may have it
9497 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9498 $dbo->setQuery($q);
9499 $dbo->execute();
9500 if ($dbo->getNumRows()) {
9501 $unset_rooms_opt = $dbo->loadAssocList();
9502 foreach ($unset_rooms_opt as $room_data) {
9503 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9504 if (!in_array((string)$pwhereup, $current_opts)) {
9505 // this room is not using this option
9506 continue;
9507 }
9508 $optkey = array_search((string)$pwhereup, $current_opts);
9509 if ($optkey === false) {
9510 // key not found
9511 continue;
9512 }
9513 // unset this option ID from the string
9514 unset($current_opts[$optkey]);
9515 if (!count($current_opts)) {
9516 // a room with no options assigned will be listed as "0;"
9517 $current_opts = array(0);
9518 }
9519 $new_opts = implode(';', $current_opts) . ';';
9520 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9521 $dbo->setQuery($q);
9522 $dbo->execute();
9523 }
9524 }
9525 //
9526
9527 }
9528 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9529 }
9530
9531 public function createoptionals()
9532 {
9533 if (!JSession::checkToken()) {
9534 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9535 }
9536
9537 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9538 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9539 }
9540
9541 $this->do_createoptionals();
9542 }
9543
9544 public function createoptionalsstay()
9545 {
9546 if (!JSession::checkToken()) {
9547 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9548 }
9549
9550 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9551 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9552 }
9553
9554 $this->do_createoptionals(true);
9555 }
9556
9557 private function do_createoptionals($stay = false) {
9558 $dbo = JFactory::getDbo();
9559 $poptname = VikRequest::getString('optname', '', 'request');
9560 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9561 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9562 $poptperday = VikRequest::getString('optperday', '', 'request');
9563 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9564 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9565 $popthmany = VikRequest::getString('opthmany', '', 'request');
9566 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9567 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9568 $presizeto = VikRequest::getString('resizeto', '', 'request');
9569 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9570 $pifchildren = $pifchildren == "1" ? 1 : 0;
9571 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9572 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9573 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9574 $pforceval = VikRequest::getString('forceval', '', 'request');
9575 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9576 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9577 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9578 $pforcesel = $pforcesel == "1" ? 1 : 0;
9579 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9580 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9581 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9582 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9583 $pagefrom = VikRequest::getVar('agefrom', array());
9584 $pageto = VikRequest::getVar('ageto', array());
9585 $pagecost = VikRequest::getVar('agecost', array());
9586 $pagectype = VikRequest::getVar('agectype', array());
9587 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9588 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9589 $pavto = VikRequest::getString('avto', '', 'request');
9590 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9591 $pidrooms = VikRequest::getVar('idrooms', array());
9592 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9593 if ($pforcesel == 1) {
9594 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9595 } else {
9596 $strforceval = "";
9597 }
9598 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9599 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9600 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9601 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9602 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9603 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9604 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9605 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9606 $minguests = VikRequest::getInt('minguests', 0, 'request');
9607 $minguests_conflict = false;
9608 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9609 if ($minguestsnum >= $maxguestsnum) {
9610 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9611 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9612 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9613 }
9614 }
9615 if (!$minguests || $minguests_conflict !== false) {
9616 $minguestsnum = 0;
9617 $maxguestsnum = 0;
9618 if ($minguests_conflict !== false) {
9619 // raise warning, but do not stop the process
9620 VikError::raiseWarning('', $minguests_conflict);
9621 }
9622 }
9623 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9624 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9625 $oparams = array(
9626 'minguestsnum' => $minguestsnum,
9627 'mingueststype' => $mingueststype,
9628 'maxguestsnum' => $maxguestsnum,
9629 'maxgueststype' => $maxgueststype,
9630 'damagedep' => $damagedep,
9631 'pet_fee' => $pet_fee,
9632 );
9633 if (!empty($poptname)) {
9634 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9635 jimport('joomla.filesystem.file');
9636 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9637 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9638 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9639 if (file_exists($updpath.$safename)) {
9640 $j = 1;
9641 while (file_exists($updpath.$j.$safename)) {
9642 $j++;
9643 }
9644 $pwhere = $updpath.$j.$safename;
9645 } else {
9646 $j = "";
9647 $pwhere = $updpath.$safename;
9648 }
9649 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9650 @unlink($pwhere);
9651 $picon = "";
9652 } else {
9653 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9654 @chmod($pwhere, 0644);
9655 $picon = $j.$safename;
9656 if ($pautoresize == "1" && !empty($presizeto)) {
9657 $eforj = new vikResizer();
9658 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9659 if ($origmod) {
9660 @unlink($pwhere);
9661 $picon = 'r_'.$j.$safename;
9662 }
9663 }
9664 }
9665 } else {
9666 $picon = "";
9667 }
9668 } else {
9669 $picon = "";
9670 }
9671 $poptperday = ($poptperday == "each" ? "1" : "0");
9672 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9673 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9674 $ageintervalstr = '';
9675 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9676 foreach ($pagefrom as $kage => $vage) {
9677 $afrom = intval($vage);
9678 $ato = intval($pageto[$kage]);
9679 $acost = floatval($pagecost[$kage]);
9680 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9681 if ($ato < $afrom) $ato = $afrom;
9682 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9683 }
9684 }
9685 $ageintervalstr = rtrim($ageintervalstr, ';;');
9686 if (!empty($ageintervalstr)) {
9687 $pforcesel = 1;
9688 }
9689 }
9690 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9691 $dbo->setQuery($q);
9692 $dbo->execute();
9693 if ($dbo->getNumRows() == 1) {
9694 $getlast = $dbo->loadResult();
9695 $newsortnum = $getlast + 1;
9696 } else {
9697 $newsortnum = 1;
9698 }
9699 $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)) . ");";
9700 $dbo->setQuery($q);
9701 $dbo->execute();
9702 $newoptid = $dbo->insertid();
9703
9704 if (!empty($newoptid)) {
9705 // assign/unset option-rooms relations
9706 $rooms_with_opt = array();
9707 if (count($pidrooms)) {
9708 // assign this new option to the requested rooms
9709 foreach ($pidrooms as $idroom) {
9710 if (empty($idroom)) {
9711 continue;
9712 }
9713 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9714 $dbo->setQuery($q);
9715 $dbo->execute();
9716 if (!$dbo->getNumRows()) {
9717 continue;
9718 }
9719 $room_data = $dbo->loadAssoc();
9720 array_push($rooms_with_opt, $room_data['id']);
9721 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9722 if (in_array((string)$newoptid, $current_opts)) {
9723 continue;
9724 }
9725 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9726 // make sure we do not concatenate a real ID to 0
9727 $current_opts = array();
9728 }
9729 array_push($current_opts, $newoptid);
9730 $new_opts = implode(';', $current_opts) . ';';
9731 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9732 $dbo->setQuery($q);
9733 $dbo->execute();
9734 }
9735 }
9736 if (!count($rooms_with_opt)) {
9737 // get all rooms to unset this option (if previously set)
9738 array_push($rooms_with_opt, '0');
9739 }
9740 // unset the option from the other rooms that may have it
9741 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9742 $dbo->setQuery($q);
9743 $dbo->execute();
9744 if ($dbo->getNumRows()) {
9745 $unset_rooms_opt = $dbo->loadAssocList();
9746 foreach ($unset_rooms_opt as $room_data) {
9747 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9748 if (!in_array((string)$newoptid, $current_opts)) {
9749 // this room is not using this option
9750 continue;
9751 }
9752 $optkey = array_search((string)$newoptid, $current_opts);
9753 if ($optkey === false) {
9754 // key not found
9755 continue;
9756 }
9757 // unset this option ID from the string
9758 unset($current_opts[$optkey]);
9759 if (!count($current_opts)) {
9760 // a room with no options assigned will be listed as "0;"
9761 $current_opts = array(0);
9762 }
9763 $new_opts = implode(';', $current_opts) . ';';
9764 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9765 $dbo->setQuery($q);
9766 $dbo->execute();
9767 }
9768 }
9769 //
9770 }
9771
9772 }
9773 $mainframe = JFactory::getApplication();
9774 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9775 }
9776
9777 public function removeoptionals()
9778 {
9779 if (!JSession::checkToken()) {
9780 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9781 }
9782
9783 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9784 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9785 }
9786
9787 $ids = VikRequest::getVar('cid', array(0));
9788 if ($ids) {
9789 $dbo = JFactory::getDbo();
9790 foreach ($ids as $d) {
9791 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9792 $dbo->setQuery($q);
9793 $dbo->execute();
9794 if ($dbo->getNumRows() == 1) {
9795 $rows = $dbo->loadAssocList();
9796 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9797 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9798 }
9799 }
9800 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9801 $dbo->setQuery($q);
9802 $dbo->execute();
9803 }
9804 }
9805 $mainframe = JFactory::getApplication();
9806 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9807 }
9808
9809 public function sendcustomsms() {
9810 $mainframe = JFactory::getApplication();
9811 $pphone = VikRequest::getString('phone', '', 'request');
9812 $psmscont = VikRequest::getString('smscont', '', 'request');
9813 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9814 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9815 if (!empty($pphone) && !empty($psmscont)) {
9816 $sms_api = VikBooking::getSMSAPIClass();
9817 $sms_api_params = VikBooking::getSMSParams();
9818 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9819 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9820 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9821 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9822 if ( !$sms_obj->validateResponse($response_obj) ) {
9823 VikError::raiseWarning('', $sms_obj->getLog());
9824 } else {
9825 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9826 }
9827 } else {
9828 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9829 }
9830 } else {
9831 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9832 }
9833 $mainframe->redirect($pgoto);
9834 }
9835
9836 public function sendcustomemail() {
9837 $dbo = JFactory::getDbo();
9838 $mainframe = JFactory::getApplication();
9839 $vbo_tn = VikBooking::getTranslator();
9840 $pbid = VikRequest::getInt('bid', '', 'request');
9841 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9842 $pemail = VikRequest::getString('email', '', 'request');
9843 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9844 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9845 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9846 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9847 if (!empty($pemail) && !empty($pemailcont)) {
9848 $email_attach = null;
9849 jimport('joomla.filesystem.file');
9850 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9851 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9852 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9853 $src = $pemailattch['tmp_name'];
9854 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9855 $j = "";
9856 if (file_exists($dest.$filename)) {
9857 $j = rand(171, 1717);
9858 while (file_exists($dest.$j.$filename)) {
9859 $j++;
9860 }
9861 }
9862 $finaldest = $dest.$j.$filename;
9863 if (VikBooking::uploadFile($src, $finaldest)) {
9864 $email_attach = $finaldest;
9865 } else {
9866 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9867 $mainframe->redirect($pgoto);
9868 exit;
9869 }
9870 }
9871 //VBO 1.10 - special tags for the custom email template files and messages
9872 $orig_mail_cont = $pemailcont;
9873 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9874 // replace any possible placeholder for special tags
9875 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9876 return $match[2];
9877 }, $pemailcont);
9878
9879 $booking = array();
9880 $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.";";
9881 $dbo->setQuery($q);
9882 $dbo->execute();
9883 if ($dbo->getNumRows() > 0) {
9884 $booking = $dbo->loadAssoc();
9885 }
9886 $booking_rooms = array();
9887 $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.";";
9888 $dbo->setQuery($q);
9889 $dbo->execute();
9890 if ($dbo->getNumRows() > 0) {
9891 $booking_rooms = $dbo->loadAssocList();
9892 if (!empty($booking['lang'])) {
9893 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9894 }
9895 }
9896 //we use the same parsing function as the one for the Customer SMS Template
9897 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9898 }
9899 //
9900 // allow the use of token {booking_id} in subject
9901 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9902 //
9903 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9904 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9905 $vbo_app = VikBooking::getVboApplication();
9906 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9907 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9908 if ($email_attach !== null) {
9909 @unlink($email_attach);
9910 }
9911 //Booking History
9912 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9913 //
9914 //Save email template for future sending
9915 $config_rec_exists = false;
9916 $emtpl = array(
9917 'emailsubj' => $pemailsubj,
9918 'emailcont' => $orig_mail_cont,
9919 'emailfrom' => $pemailfrom
9920 );
9921 $cur_emtpl = array();
9922 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9923 $dbo->setQuery($q);
9924 $dbo->execute();
9925 if ($dbo->getNumRows() > 0) {
9926 $config_rec_exists = true;
9927 $cur_emtpl = $dbo->loadResult();
9928 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9929 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9930 }
9931 if (count($cur_emtpl) > 0) {
9932 $existing_subj = false;
9933 foreach ($cur_emtpl as $emk => $emv) {
9934 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9935 $cur_emtpl[$emk] = $emtpl;
9936 $existing_subj = true;
9937 break;
9938 }
9939 }
9940 if ($existing_subj === false) {
9941 $cur_emtpl[] = $emtpl;
9942 }
9943 } else {
9944 $cur_emtpl[] = $emtpl;
9945 }
9946 if (count($cur_emtpl) > 10) {
9947 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9948 $exceed = count($cur_emtpl) - 10;
9949 for ($tl=0; $tl < $exceed; $tl++) {
9950 unset($cur_emtpl[$tl]);
9951 }
9952 $cur_emtpl = array_values($cur_emtpl);
9953 }
9954 if ($config_rec_exists === true) {
9955 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9956 $dbo->setQuery($q);
9957 $dbo->execute();
9958 } else {
9959 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9960 $dbo->setQuery($q);
9961 $dbo->execute();
9962 }
9963 //
9964 } else {
9965 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9966 }
9967 $mainframe->redirect($pgoto);
9968 }
9969
9970 public function rmcustomemailtpl() {
9971 $cid = VikRequest::getVar('cid', array(0));
9972 $oid = $cid[0];
9973 $dbo = JFactory::getDBO();
9974 $mainframe = JFactory::getApplication();
9975 $tplind = VikRequest::getInt('tplind', '', 'request');
9976 if (empty($oid) || !(strlen($tplind) > 0)) {
9977 VikError::raiseWarning('', 'Missing Data.');
9978 $mainframe->redirect('index.php?option=com_vikbooking');
9979 exit;
9980 }
9981 $cur_emtpl = array();
9982 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9983 $dbo->setQuery($q);
9984 $dbo->execute();
9985 if ($dbo->getNumRows() > 0) {
9986 $cur_emtpl = $dbo->loadResult();
9987 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9988 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9989 } else {
9990 VikError::raiseWarning('', 'Missing Templates Record.');
9991 $mainframe->redirect('index.php?option=com_vikbooking');
9992 exit;
9993 }
9994 if (array_key_exists($tplind, $cur_emtpl)) {
9995 unset($cur_emtpl[$tplind]);
9996 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9997 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9998 $dbo->setQuery($q);
9999 $dbo->execute();
10000 }
10001 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
10002 exit;
10003 }
10004
10005 public function exportcustomers() {
10006 //we do not set the menu for this view
10007
10008 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
10009
10010 parent::display();
10011
10012 if (VikBooking::showFooter()) {
10013 VikBookingHelper::printFooter();
10014 }
10015 }
10016
10017 public function csvexportprepare() {
10018 //modal box, so we do not set menu or footer
10019
10020 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
10021
10022 parent::display();
10023 }
10024
10025 public function icsexportprepare() {
10026 //modal box, so we do not set menu or footer
10027
10028 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
10029
10030 parent::display();
10031 }
10032
10033 public function bookingcheckin() {
10034 //modal box, so we do not set menu or footer
10035
10036 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
10037
10038 parent::display();
10039 }
10040
10041 public function gencheckindoc() {
10042 //modal box, so we do not set menu or footer
10043
10044 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
10045
10046 parent::display();
10047 }
10048
10049 public function checkversion() {
10050 //to be called via ajax
10051 $params = new stdClass;
10052 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10053 $params->alias = 'com_vikbooking';
10054
10055 $result = array();
10056
10057 if (!count($result)) {
10058 $result = new stdClass;
10059 $result->status = 0;
10060 } else {
10061 $result = $result[0];
10062 }
10063
10064 echo json_encode($result);
10065 exit;
10066 }
10067
10068 public function updateprogram() {
10069 $params = new stdClass;
10070 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10071 $params->alias = 'com_vikbooking';
10072
10073 $result = array();
10074
10075 if (!count($result) || !$result[0]) {
10076 if (class_exists('JEventDispatcher')) {
10077 $dispatcher = JEventDispatcher::getInstance();
10078 $result = $dispatcher->trigger('checkVersion', array(&$params));
10079 } else {
10080 $app = JFactory::getApplication();
10081 if (method_exists($app, 'triggerEvent')) {
10082 $result = $app->triggerEvent('checkVersion', array(&$params));
10083 }
10084 }
10085 }
10086
10087 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
10088 exit('Error, plugin disabled');
10089 }
10090
10091 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
10092
10093 VikBookingHelper::pUpdateProgram($result[0]->response);
10094 }
10095
10096 public function updateprogramlaunch() {
10097 $params = new stdClass;
10098 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10099 $params->alias = 'com_vikbooking';
10100
10101 $json = new stdClass;
10102 $json->status = false;
10103
10104 echo json_encode($json);
10105 exit;
10106 }
10107
10108 public function invoke_vcm()
10109 {
10110 $app = JFactory::getApplication();
10111
10112 $oids = VikRequest::getVar('cid', []);
10113 $sync_type = VikRequest::getString('stype', 'new', 'request');
10114 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
10115 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
10116 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
10117 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
10118
10119 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
10120 $app->redirect("index.php?option=com_vikbooking&task=orders");
10121 $app->close();
10122 }
10123
10124 $result = VikBooking::getVcmInvoker()
10125 ->setOids($oids)
10126 ->setSyncType($sync_type)
10127 ->setOriginalBooking($original_booking_js, true)
10128 ->doSync();
10129
10130 if ($result === true) {
10131 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
10132 } else {
10133 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
10134 }
10135
10136 if (!empty($return_url)) {
10137 $app->redirect($return_url);
10138 } else {
10139 $app->redirect("index.php?option=com_vikbooking&task=orders");
10140 }
10141
10142 $app->close();
10143 }
10144
10145 public function multiphotosupload() {
10146 jimport('joomla.filesystem.file');
10147
10148 $dbo = JFactory::getDBO();
10149 $proomid = VikRequest::getInt('roomid', '', 'request');
10150
10151 $resp = array('files' => array());
10152 $error_messages = array(
10153 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
10154 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
10155 3 => 'The uploaded file was only partially uploaded',
10156 4 => 'No file was uploaded',
10157 6 => 'Missing a temporary folder',
10158 7 => 'Failed to write file to disk',
10159 8 => 'A PHP extension stopped the file upload',
10160 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
10161 'max_file_size' => 'File is too big',
10162 'min_file_size' => 'File is too small',
10163 'accept_file_types' => 'Filetype not allowed',
10164 'max_number_of_files' => 'Maximum number of files exceeded',
10165 'max_width' => 'Image exceeds maximum width',
10166 'min_width' => 'Image requires a minimum width',
10167 'max_height' => 'Image exceeds maximum height',
10168 'min_height' => 'Image requires a minimum height',
10169 'abort' => 'File upload aborted',
10170 'image_resize' => 'Failed to resize image',
10171 'vbo_type' => 'The file type cannot be accepted',
10172 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
10173 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
10174 );
10175
10176 $creativik = new vikResizer();
10177 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
10178 $bigsdest = $updpath;
10179 $thumbsdest = $updpath;
10180 $dest = $updpath;
10181 $moreimagestr = '';
10182 $cur_captions = json_encode(array());
10183
10184 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
10185 $dbo->setQuery($q);
10186 $dbo->execute();
10187 if ($dbo->getNumRows() == 1) {
10188 $photo_data = $dbo->loadAssocList();
10189 $cur_captions = $photo_data[0]['imgcaptions'];
10190 $cur_photos = $photo_data[0]['moreimgs'];
10191 if (!empty($cur_photos)) {
10192 $moreimagestr .= $cur_photos;
10193 }
10194 }
10195
10196 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
10197
10198 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
10199 foreach ($bulkphotos['name'] as $updk => $photoname) {
10200 $uploaded_image = array();
10201 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
10202 $src = $bulkphotos['tmp_name'][$updk];
10203 $j = "";
10204 if (file_exists($dest.$filename)) {
10205 $j = rand(171, 1717);
10206 while (file_exists($dest.$j.$filename)) {
10207 $j++;
10208 }
10209 }
10210 $finaldest=$dest.$j.$filename;
10211 $is_error = false;
10212 $err_key = '';
10213 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
10214 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
10215 $is_error = true;
10216 $err_key = $bulkphotos['error'][$updk];
10217 }
10218 }
10219 if (!$is_error) {
10220 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
10221 if ($check[2] & imagetypes()) {
10222 if (VikBooking::uploadFile($src, $finaldest)) {
10223 $gimg = $j.$filename;
10224 //orig img
10225 $origmod = true;
10226 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
10227 //thumb
10228 $thumbsize = VikBooking::getThumbSize();
10229 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
10230 if (!$thumb || !$origmod) {
10231 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
10232 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
10233 $is_error = true;
10234 $err_key = 'vbo_perm';
10235 } else {
10236 $moreimagestr.=$j.$filename.";;";
10237 }
10238 @unlink($finaldest);
10239 } else {
10240 $is_error = true;
10241 $err_key = 'vbo_jupload';
10242 }
10243 } else {
10244 $is_error = true;
10245 $err_key = 'vbo_type';
10246 }
10247 }
10248 $img = new stdClass();
10249 if ($is_error) {
10250 $img->name = '';
10251 $img->size = '';
10252 $img->type = '';
10253 $img->url = '';
10254 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
10255 } else {
10256 $img->name = $photoname;
10257 $img->size = $bulkphotos['size'][$updk];
10258 $img->type = $bulkphotos['type'][$updk];
10259 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
10260 }
10261 $resp['files'][] = $img;
10262 }
10263 } else {
10264 $res = new stdClass();
10265 $res->name = '';
10266 $res->size = '';
10267 $res->type = '';
10268 $res->url = '';
10269 $res->error = 'No images received for upload';
10270 $resp['files'][] = $res;
10271 }
10272 //Update current extra images string
10273 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
10274 $dbo->setQuery($q);
10275 $dbo->execute();
10276 $resp['actmoreimgs'] = $moreimagestr;
10277 //Update current extra images uploaded
10278 $cur_thumbs = '';
10279 $morei=explode(';;', $moreimagestr);
10280 if (@count($morei) > 0) {
10281 $imgcaptions = json_decode($cur_captions, true);
10282 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
10283 $cur_thumbs .= '<ul class="vbo-sortable">';
10284 foreach ($morei as $ki => $mi) {
10285 if (!empty($mi)) {
10286 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
10287 $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>';
10288 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
10289 $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>';
10290 $cur_thumbs .= '</li>';
10291 }
10292 }
10293 $cur_thumbs .= '</ul>';
10294 $cur_thumbs .= '<br clear="all"/>';
10295 }
10296 $resp['currentthumbs'] = $cur_thumbs;
10297
10298 echo json_encode($resp);
10299 exit;
10300 }
10301
10302 public function loadsmsbalance() {
10303 //to be called via ajax
10304 $html = 'Error1 [N/A]';
10305 $sms_api = VikBooking::getSMSAPIClass();
10306 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
10307 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10308 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
10309 if (method_exists('VikSmsApi', 'estimate')) {
10310 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
10311 if ( $array_result->errorCode != 0 ) {
10312 $html = 'Error3 ['.$array_result->errorMsg.']';
10313 } else {
10314 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
10315 }
10316 } else {
10317 $html = 'Error2 [N/A]';
10318 }
10319 }
10320 echo $html;
10321 exit;
10322 }
10323
10324 public function loadsmsparams() {
10325 //to be called via ajax
10326 $html = '---------';
10327 $phpfile = VikRequest::getString('phpfile', '', 'request');
10328 if (!empty($phpfile)) {
10329 $sms_api = VikBooking::getSMSAPIClass();
10330 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
10331 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
10332 }
10333 echo $html;
10334 exit;
10335 }
10336
10337 public function loadcronparams() {
10338 //to be called via ajax
10339 $html = '---------';
10340 $phpfile = VikRequest::getString('phpfile', '', 'request');
10341 if (!empty($phpfile)) {
10342 $html = VikBooking::displayCronParameters($phpfile);
10343 }
10344 echo $html;
10345 exit;
10346 }
10347
10348 public function loadpaymentparams() {
10349 //to be called via ajax
10350 $html = '<p>---------</p>';
10351 $phpfile = VikRequest::getString('phpfile', '', 'request');
10352 if (!empty($phpfile)) {
10353 $html = VikBooking::displayPaymentParameters($phpfile);
10354 }
10355 echo $html;
10356 exit;
10357 }
10358
10359 public function setbookingtag() {
10360 //to be called via ajax
10361 $dbo = JFactory::getDBO();
10362 $pidorder = VikRequest::getInt('idorder', '', 'request');
10363 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
10364 if (!empty($pidorder) && $ptagkey >= 0) {
10365 $all_tags = VikBooking::loadBookingsColorTags();
10366 if (array_key_exists($ptagkey, $all_tags)) {
10367 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
10368 $dbo->setQuery($q);
10369 $dbo->execute();
10370 if ($dbo->getNumRows() > 0) {
10371 $newcolortag = json_encode($all_tags[$ptagkey]);
10372 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
10373 $dbo->setQuery($q);
10374 $dbo->execute();
10375 $newcolortag = $all_tags[$ptagkey];
10376 $newcolortag['name'] = JText::translate($newcolortag['name']);
10377 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
10378 echo json_encode($newcolortag);
10379 } else {
10380 echo 'e4j.error.Booking ('.$pidorder.') not found';
10381 }
10382 } else {
10383 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
10384 }
10385 } else {
10386 echo 'e4j.error.Missing Data';
10387 }
10388 exit;
10389 }
10390
10391 public function updatereceiptnum() {
10392 //to be called via ajax
10393 $pnewnum = VikRequest::getInt('newnum', '', 'request');
10394 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
10395 $poid = VikRequest::getInt('oid', '', 'request');
10396 if ($pnewnum > 0) {
10397 VikBooking::getNextReceiptNumber($poid, $pnewnum);
10398 VikBooking::getReceiptNotes($pnewnotes);
10399 //Booking History
10400 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
10401 //
10402 echo 'e4j.ok';
10403 exit;
10404 }
10405 echo 'e4j.error';
10406 exit;
10407 }
10408
10409 public function isroombookable() {
10410 //to be called via ajax
10411 $dbo = JFactory::getDBO();
10412 $res = array(
10413 'status' => 0,
10414 'err' => ''
10415 );
10416 $prid = VikRequest::getInt('rid', '', 'request');
10417 $pfdate = VikRequest::getString('fdate', '', 'request');
10418 $ptdate = VikRequest::getString('tdate', '', 'request');
10419 $room_info = array();
10420 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
10421 $dbo->setQuery($q);
10422 $dbo->execute();
10423 if ($dbo->getNumRows() > 0) {
10424 $room_info = $dbo->loadAssoc();
10425 }
10426 $pcheckinh = 0;
10427 $pcheckinm = 0;
10428 $pcheckouth = 0;
10429 $pcheckoutm = 0;
10430 $timeopst = VikBooking::getTimeOpenStore();
10431 if (is_array($timeopst)) {
10432 $opent = VikBooking::getHoursMinutes($timeopst[0]);
10433 $closet = VikBooking::getHoursMinutes($timeopst[1]);
10434 $pcheckinh = $opent[0];
10435 $pcheckinm = $opent[1];
10436 $pcheckouth = $closet[0];
10437 $pcheckoutm = $closet[1];
10438 }
10439 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
10440 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
10441 if (
10442 count($room_info) > 0 &&
10443 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
10444 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
10445 {
10446 $res['status'] = 1;
10447 } else {
10448 if (!(count($room_info) > 0)) {
10449 $res['err'] = 'Room not found';
10450 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
10451 $res['err'] = 'Invalid dates';
10452 } else {
10453 //not available
10454 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
10455 }
10456 }
10457
10458 echo json_encode($res);
10459 exit;
10460 }
10461
10462 public function uploadsnapshot() {
10463 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
10464 /**
10465 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
10466 * The old snapshot collection script with Flash no longer works in 2021.
10467 *
10468 * @since 1.14 (J) - 1.4.0 (WP)
10469 */
10470 $result = null;
10471 try {
10472 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
10473 } catch (RuntimeException $e) {
10474 echo "e4j.error.Error " . $e->getMessage();
10475 exit;
10476 }
10477
10478 if (!is_object($result)) {
10479 echo "e4j.error.Invalid upload response";
10480 exit;
10481 }
10482
10483 echo $result->filename;
10484 exit;
10485 }
10486
10487 public function checkvcmrateschanges() {
10488 //to be called via ajax
10489 $session = JFactory::getSession();
10490 $ret = array('changesCount' => 0, 'changesData' => '');
10491 $updforvcm = $session->get('vbVcmRatesUpd', '');
10492 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
10493 $ret['changesCount'] = $updforvcm['count'];
10494 $ret['changesData'] = $updforvcm;
10495 }
10496
10497 echo json_encode($ret);
10498 exit;
10499 }
10500
10501 /**
10502 * AJAX endpoint to load the details of one or more bookings.
10503 *
10504 * @return void
10505 *
10506 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10507 */
10508 public function getbookingsinfo()
10509 {
10510 //to be called via ajax
10511 $dbo = JFactory::getDbo();
10512
10513 $booking_infos = [];
10514 $bookings = [];
10515
10516 $pidorders = VikRequest::getString('idorders', '', 'request');
10517 $psubroom = VikRequest::getString('subroom', '', 'request');
10518 $pstatus = VikRequest::getString('status', '', 'request');
10519 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10520 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10521 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10522
10523 if (!empty($pidorders)) {
10524 $bookings = explode(',', $pidorders);
10525 foreach ($bookings as $k => $v) {
10526 $v = intval(str_replace('-', '', $v));
10527 if (empty($v)) {
10528 unset($bookings[$k]);
10529 continue;
10530 }
10531 $bookings[$k] = $v;
10532 }
10533 }
10534 $bookings = array_values($bookings);
10535
10536 if (!$bookings) {
10537 /**
10538 * AJAX requests made by the page availability overview may contain empty booking IDs
10539 * due to SQL errors that only occupied the room, but could not save the booking record.
10540 * Clean up busy records where the busy relations contain empty booking IDs.
10541 *
10542 * @since 1.14 (J) - 1.4.0 (WP)
10543 */
10544 $hanging_busy_ids = [];
10545
10546 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10547 $dbo->setQuery($q);
10548 $removelist = $dbo->loadAssocList();
10549 if ($removelist) {
10550 foreach ($removelist as $hanging_busy) {
10551 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10552 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10553 array_push($hanging_busy_ids, $hanging_busy_id);
10554 }
10555 }
10556 }
10557
10558 // let's check also for ghost records that only occupy the room
10559 $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);";
10560 $dbo->setQuery($q);
10561 $removelist = $dbo->loadAssocList();
10562 if ($removelist) {
10563 foreach ($removelist as $hanging_busy) {
10564 $hanging_busy_id = (int)$hanging_busy['id'];
10565 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10566 array_push($hanging_busy_ids, $hanging_busy_id);
10567 }
10568 }
10569 }
10570
10571 if ($hanging_busy_ids) {
10572 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10573 $dbo->setQuery($q);
10574 $dbo->execute();
10575 }
10576 //
10577
10578 // output the error
10579 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10580 }
10581
10582 $nowdf = VikBooking::getDateFormat(true);
10583 if ($nowdf == "%d/%m/%Y") {
10584 $df = 'd/m/Y';
10585 } elseif ($nowdf == "%m/%d/%Y") {
10586 $df = 'm/d/Y';
10587 } else {
10588 $df = 'Y/m/d';
10589 }
10590 $datesep = VikBooking::getDateSeparator(true);
10591 $currencysymb = VikBooking::getCurrencySymb();
10592 $current_y = date('Y');
10593 $current_ts = time();
10594 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10595
10596 $query = $dbo->getQuery(true);
10597 $query->select('o.*');
10598 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10599 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10600 // include the requested booking IDs and the cancelled reservations for this stay date
10601 $stay_date_info = getdate(strtotime($pstay_date));
10602 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10603 $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) . '))');
10604 // exclude the pending reservations
10605 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10606 } else {
10607 // include only the requested booking IDs
10608 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10609 }
10610 if ($pstatus != 'any') {
10611 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10612 }
10613 if (!empty($pstay_date) && $pstatus == 'any') {
10614 // sort by confirmed status before cancelled status
10615 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10616 $query->order($dbo->qn('o.id') . ' ASC');
10617 }
10618 $dbo->setQuery($query);
10619 $booking_infos = $dbo->loadAssocList();
10620
10621 foreach ($booking_infos as $k => $row) {
10622 // rooms, amounts and guests information
10623 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10624 $rids_involved = [];
10625 $room_names = [];
10626 $totadults = 0;
10627 $totchildren = 0;
10628 foreach ($rooms as $rr) {
10629 $rids_involved[] = $rr['idroom'];
10630 $totadults += $rr['adults'];
10631 $totchildren += $rr['children'];
10632 $room_names[] = $rr['room_name'];
10633 if ($row['split_stay']) {
10634 // do not sum guests in case of split stay booking
10635 $totadults = $rr['adults'];
10636 $totchildren = $rr['children'];
10637 }
10638 }
10639
10640 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10641 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10642 if (!in_array($pidroom, $rids_involved)) {
10643 $is_out_of_scope = true;
10644 if ($psharedcal && count($bookings) === 1) {
10645 $is_out_of_scope = ($row['id'] != $bookings[0]);
10646 }
10647 if ($is_out_of_scope) {
10648 // out of scope reservation, unset it and go to the next one
10649 unset($booking_infos[$k]);
10650 continue;
10651 }
10652 }
10653 }
10654
10655 // included meal plans to be displayed in case of single-room booking
10656 $included_meals = [];
10657 $rplan_name = '';
10658 if (count($rooms) === 1) {
10659 // rate plan name and ID, if any
10660 $active_rplan_id = 0;
10661 if (!empty($rooms[0]['otarplan'])) {
10662 $rplan_name = $rooms[0]['otarplan'];
10663 } else {
10664 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10665 }
10666
10667 // find the included meals
10668 if (!empty($rooms[0]['meals'])) {
10669 // display included meals defined at room-reservation record
10670 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10671 } else {
10672 // fetch default included meals in the selected rate plan
10673 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10674 }
10675 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10676 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10677 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10678 }
10679 }
10680
10681 if ($included_meals) {
10682 $short_incl_meals = [];
10683 foreach ($included_meals as $meal_enum => $meal_name) {
10684 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10685 }
10686 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10687 }
10688
10689 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10690 $booking_infos[$k]['currency_symb'] = $currencysymb;
10691 if ($row['status'] == 'confirmed') {
10692 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10693 if ($row['checkout'] < $current_ts) {
10694 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10695 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10696 if ($row['checked'] == 1) {
10697 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10698 } elseif ($row['checked'] == -1) {
10699 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10700 }
10701 }
10702 } elseif ($row['status'] == 'standby') {
10703 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10704 } elseif ($row['status'] == 'cancelled') {
10705 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10706 } else {
10707 $booking_infos[$k]['status_lbl'] = $row['status'];
10708 }
10709 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10710 if ($booking_infos[$k]['colortag']) {
10711 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10712 }
10713 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10714 $booking_infos[$k]['tot_adults'] = $totadults;
10715 $booking_infos[$k]['tot_children'] = $totchildren;
10716 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10717 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10718
10719 // room indexes
10720 $rindexes = [];
10721 $av_room_indexes = [];
10722 $used_indexes_map = [];
10723 $sub_units_data = [];
10724 $optindexes = [];
10725 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10726 $missing_index = false;
10727 foreach ($rooms as $kor => $or) {
10728 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10729 // cannot build room indexes data
10730 continue;
10731 }
10732
10733 $room_params = json_decode($or['params'], true);
10734 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10735 // no distinctive features information
10736 continue;
10737 }
10738
10739 if (!strlen($or['roomindex'])) {
10740 // turn flag on for missing index when room does support them
10741 $missing_index = true;
10742 // build array with available room indexes
10743 $av_indexes = [];
10744 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10745 foreach ($room_params['features'] as $rind => $rfeatures) {
10746 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10747 continue;
10748 }
10749 foreach ($rfeatures as $fname => $fval) {
10750 if ($fval) {
10751 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10752 break;
10753 }
10754 }
10755 }
10756 if ($av_indexes) {
10757 // push available indexes for this room
10758 $av_room_indexes[$kor] = [
10759 'rid' => $or['idroom'],
10760 'name' => $or['room_name'],
10761 'list' => $av_indexes,
10762 ];
10763 }
10764 // do not proceed any further
10765 continue;
10766 }
10767
10768 // parse distinctive features
10769 foreach ($room_params['features'] as $rind => $rfeatures) {
10770 if ($rind != $or['roomindex']) {
10771 continue;
10772 }
10773 $ind_str = '';
10774 $ind_str_short = '';
10775 foreach ($rfeatures as $fname => $fval) {
10776 if (strlen($fval)) {
10777 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10778 $ind_str_short = $fval;
10779 break;
10780 }
10781 }
10782 if (!isset($rindexes[$or['room_name']])) {
10783 $rindexes[$or['room_name']] = $ind_str;
10784 $sub_units_data[$or['room_name']] = $ind_str_short;
10785 } else {
10786 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10787 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10788 }
10789 break;
10790 }
10791
10792 // build options to switch sub-unit index
10793 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10794 // build the options for switching the room index for this room
10795 foreach ($room_params['features'] as $rind => $rfeatures) {
10796 foreach ($rfeatures as $fname => $fval) {
10797 if (strlen((string)$fval)) {
10798 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10799 break;
10800 }
10801 }
10802 }
10803 }
10804 }
10805
10806 if ($rindexes) {
10807 $booking_infos[$k]['rindexes'] = $rindexes;
10808 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10809 }
10810
10811 if ($optindexes) {
10812 $booking_infos[$k]['optindexes'] = $optindexes;
10813 }
10814
10815 if ($missing_index && $av_room_indexes) {
10816 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10817 }
10818
10819 // include flag for missing room index
10820 $booking_infos[$k]['missing_index'] = $missing_index;
10821
10822 // channel provenience and small logo URL
10823 $ota_logo_img = JText::translate('VBORDFROMSITE');
10824 $booking_avatar_src = null;
10825 $booking_avatar_alt = null;
10826 if (!empty($row['channel'])) {
10827 $channelparts = explode('_', $row['channel']);
10828 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10829 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10830 if ($ota_logo_img === false) {
10831 $ota_logo_img = $otachannel;
10832 } else {
10833 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10834 }
10835 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10836 if ($logo_helper !== false) {
10837 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10838 $booking_avatar_alt = $logo_helper->provenience;
10839 }
10840 }
10841 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10842 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10843 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10844
10845 // Customer Details
10846 $custdata = $row['custdata'];
10847 $custdata_parts = explode("\n", $row['custdata']);
10848 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10849 //get the first two fields
10850 $custvalues = [];
10851 foreach ($custdata_parts as $custdet) {
10852 if (strlen($custdet) < 1) {
10853 continue;
10854 }
10855 $custdet_parts = explode(':', $custdet);
10856 if (count($custdet_parts) >= 2) {
10857 unset($custdet_parts[0]);
10858 array_push($custvalues, trim(implode(':', $custdet_parts)));
10859 }
10860 if (count($custvalues) > 1) {
10861 break;
10862 }
10863 }
10864 if (count($custvalues) > 1) {
10865 $custdata = implode(' ', $custvalues);
10866 }
10867 }
10868 if (strlen($custdata) > 45) {
10869 $custdata = (function_exists('mb_substr') ? mb_substr($custdata, 0, 45, 'UTF-8') : substr($custdata, 0, 45)) . " ...";
10870 }
10871
10872 // customer record details
10873 $customer = [];
10874 $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'];
10875 $dbo->setQuery($q, 0, 1);
10876 $dbo->execute();
10877 if ($dbo->getNumRows()) {
10878 $customer = $dbo->loadAssoc();
10879 if (!empty($customer['first_name'])) {
10880 $custdata = $customer['first_name'].' '.$customer['last_name'];
10881 if (!empty($customer['country'])) {
10882 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10883 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10884 }
10885 }
10886 }
10887 }
10888 $booking_infos[$k]['customer'] = $customer;
10889
10890 // check if a profile picture is available for the customer
10891 if (!empty($customer['pic'])) {
10892 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10893 $booking_avatar_alt = basename($booking_avatar_src);
10894 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10895 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10896 }
10897
10898 // whether this is a closure
10899 $booking_infos[$k]['closure'] = (int)$row['closure'];
10900 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10901
10902 // short customer information
10903 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10904 $booking_infos[$k]['cinfo'] = $custdata;
10905
10906 // formatted dates
10907 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10908 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10909 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10910
10911 // short booking date, check-in, check-out date format
10912 $stay_info_in = getdate($row['checkin']);
10913 $stay_info_out = getdate($row['checkout']);
10914 $str_checkin = date('d', $row['checkin']);
10915 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10916 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10917 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10918 $str_checkout .= ' ' . $stay_info_out['year'];
10919 }
10920 $booking_infos[$k]['checkin_short'] = $str_checkin;
10921 $booking_infos[$k]['checkout_short'] = $str_checkout;
10922 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10923 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10924 }
10925
10926 if (!$booking_infos) {
10927 // output the error
10928 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10929 }
10930
10931 // output the JSON encoded response and exit
10932 VBOHttpDocument::getInstance()->json($booking_infos);
10933 }
10934
10935 public function switchRoomIndex() {
10936 //to be called via ajax
10937 $dbo = JFactory::getDBO();
10938 $bid = VikRequest::getInt('bid', '', 'request');
10939 $rid = VikRequest::getInt('rid', '', 'request');
10940 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10941 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10942 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10943 echo 'e4j.error.#1 Missing Data';
10944 exit;
10945 }
10946 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10947 $dbo->setQuery($q);
10948 $dbo->execute();
10949 if ($dbo->getNumRows() < 1) {
10950 echo 'e4j.error.#2 Record not found';
10951 exit;
10952 }
10953 $rows = $dbo->loadAssocList();
10954 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10955 $dbo->setQuery($q);
10956 $dbo->execute();
10957 echo 'e4j.ok';
10958 exit;
10959 }
10960
10961 public function searchcustomer()
10962 {
10963 // to be called via ajax
10964 $dbo = JFactory::getDbo();
10965
10966 $kw = VikRequest::getString('kw', '', 'request');
10967 $nopin = VikRequest::getInt('nopin', '', 'request');
10968 $email = VikRequest::getInt('email', 0, 'request');
10969 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10970 $no_script = VikRequest::getInt('no_script', 0, 'request');
10971
10972 if (!strlen($kw)) {
10973 VBOHttpDocument::getInstance()->close(200, '');
10974 }
10975
10976 if ($nopin > 0) {
10977 //page all bookings
10978 $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;";
10979 } elseif ($email > 0) {
10980 // page calendar for checking if an email exists
10981 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10982 } else {
10983 //page calendar
10984 $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;";
10985 }
10986 $dbo->setQuery($q);
10987 $customers = $dbo->loadAssocList();
10988
10989 if (!$customers) {
10990 VBOHttpDocument::getInstance()->close(200, '');
10991 }
10992
10993 if ($email > 0) {
10994 VBOHttpDocument::getInstance()->json($customers[0]);
10995 }
10996
10997 $cust_old_fields = array();
10998 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10999 foreach ($customers as $k => $v) {
11000 $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";
11001 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
11002 if (!empty($v['pic'])) {
11003 $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";
11004 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
11005 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
11006 } else {
11007 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
11008 }
11009 $cstring_search .= '</span>';
11010 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
11011 if (!($nopin > 0)) {
11012 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
11013 }
11014 $cstring_search .= '</div>'."\n";
11015 if (!empty($v['cfields'])) {
11016 $oldfields = json_decode($v['cfields'], true);
11017 if (is_array($oldfields) && count($oldfields)) {
11018 $cust_old_fields[$v['id']] = $oldfields;
11019 }
11020 }
11021 }
11022 $cstring_search .= '</div>'."\n";
11023
11024 /**
11025 * Add the necessary JS code for the arrow navigation.
11026 */
11027 $cstring_search_js = '<script type="text/javascript">';
11028 $cstring_search_js .= '
11029 var vboCust = jQuery(".' . $selector . '");
11030 var vboCustSelected = null;
11031 jQuery(window).keydown(function(e) {
11032 if (e.which === 40) {
11033 if (vboCustSelected) {
11034 vboCustSelected.removeClass("' . $selector . '-highligthed");
11035 next = vboCustSelected.next();
11036 if (next.length > 0) {
11037 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11038 } else {
11039 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11040 }
11041 } else {
11042 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11043 }
11044 } else if (e.which === 38) {
11045 if (vboCustSelected) {
11046 vboCustSelected.removeClass("' . $selector . '-highligthed");
11047 next = vboCustSelected.prev();
11048 if (next.length > 0) {
11049 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11050 } else {
11051 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11052 }
11053 } else {
11054 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11055 }
11056 } else if (e.which === 13) {
11057 if (vboCustSelected) {
11058 vboCustSelected.trigger("click");
11059 }
11060 }
11061 });
11062 jQuery(".' . $selector . '").off("hover");
11063 jQuery(".' . $selector . '").hover(function() {
11064 if (vboCustSelected) {
11065 vboCustSelected.removeClass("' . $selector . '-highligthed");
11066 vboCustSelected = null;
11067 }
11068 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
11069 }, function() {
11070 if (vboCustSelected) {
11071 vboCustSelected.removeClass("' . $selector . '-highligthed");
11072 vboCustSelected = null;
11073 }
11074 jQuery(this).removeClass("' . $selector . '-highligthed");
11075 });';
11076 $cstring_search_js .= '</script>';
11077
11078 if (!$no_script) {
11079 // append JS
11080 $cstring_search .= $cstring_search_js;
11081 }
11082
11083 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
11084 }
11085
11086 public function sharesignaturelink() {
11087 //to be called via ajax
11088 $dbo = JFactory::getDBO();
11089 $response = array(
11090 'status' => 0,
11091 'error' => 'Generic Error'
11092 );
11093 $pbid = VikRequest::getInt('bid', '', 'request');
11094 $phow = VikRequest::getString('how', '', 'request');
11095 $pto = VikRequest::getString('to', '', 'request');
11096 $pcustomer = VikRequest::getInt('customer', '', 'request');
11097 $cpin = VikBooking::getCPinIstance();
11098 $customer_info = $cpin->getCustomerByID($pcustomer);
11099 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
11100 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
11101 $dbo->setQuery($q);
11102 $dbo->execute();
11103 if ($dbo->getNumRows() > 0) {
11104 $row = $dbo->loadAssoc();
11105
11106 $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'];
11107 if (VBOPlatformDetection::isWordPress()) {
11108 /**
11109 * @wponly Rewrite URI for front-end signature
11110 */
11111 $share_link = str_replace(JUri::root(), '', $share_link);
11112 $model = JModel::getInstance('vikbooking', 'shortcodes');
11113 $itemid = $model->all('post_id', $full = true);
11114 if (count($itemid)) {
11115 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
11116 }
11117 } else {
11118 /**
11119 * @joomlaonly
11120 */
11121 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
11122 if ($best_menuitem_id) {
11123 $share_base = str_replace(JUri::root(), '', $share_link);
11124 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
11125 }
11126 }
11127
11128 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11129 if ($phow == 'email') {
11130 $sender = VikBooking::getSenderMail();
11131 $vbo_app = VikBooking::getVboApplication();
11132 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
11133 $response['status'] = 1;
11134 } elseif ($phow == 'sms') {
11135 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11136 $sms_api = VikBooking::getSMSAPIClass();
11137 $sms_api_params = VikBooking::getSMSParams();
11138 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
11139 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
11140 $sms_obj = new VikSmsApi(array(), $sms_api_params);
11141 $response_obj = $sms_obj->sendMessage($pto, $share_message);
11142 if ($sms_obj->validateResponse($response_obj)) {
11143 $response['status'] = 1;
11144 } else {
11145 $response['error'] = $sms_obj->getLog();
11146 }
11147 } else {
11148 $response['error'] = 'No SMS Provider Configured';
11149 }
11150 } else {
11151 $response['error'] = 'Invalid Sending Method';
11152 }
11153 } else {
11154 $response['error'] = 'Invalid Booking ID';
11155 }
11156 } else {
11157 $response['error'] = 'Empty values';
11158 }
11159
11160 echo json_encode($response);
11161 exit;
11162 }
11163
11164 public function dayselectioncount() {
11165 //to be called via ajax
11166 $tsinit = VikRequest::getString('dinit', '', 'request');
11167 $tsend = VikRequest::getString('dend', '', 'request');
11168 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
11169 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
11170 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
11171 $diff = $ptsend - $ptsinit;
11172 if ($diff >= 172800) {
11173 $datef = VikBooking::getDateFormat(true);
11174 if ($datef=="%d/%m/%Y") {
11175 $df = 'd-m-Y';
11176 } else {
11177 $df = 'Y-m-d';
11178 }
11179 //minimum 2 days for excluding some days
11180 $daysdiff = floor($diff / 86400);
11181 $infoinit = getdate($ptsinit);
11182 $select = '';
11183 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
11184 for($i = 0; $i <= $daysdiff; $i++) {
11185 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
11186 $infots = getdate($ts);
11187 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
11188 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
11189 }
11190 $select .= '</select></div>';
11191 //excluded days of the week
11192 if ($daysdiff >= 14) {
11193 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
11194 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
11195 $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>';
11196 $select .= '</optgroup>';
11197 $select .= '</select></div>';
11198 }
11199 //
11200 echo $select;
11201 } else {
11202 echo '';
11203 }
11204 } else {
11205 echo '';
11206 }
11207 exit;
11208 }
11209
11210 public function createcheckindoc()
11211 {
11212 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
11213 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11214 }
11215
11216 $cid = VikRequest::getVar('cid', array(0));
11217 $id = $cid[0];
11218
11219 $dbo = JFactory::getDBO();
11220 $mainframe = JFactory::getApplication();
11221 $vbo_tn = VikBooking::getTranslator();
11222 $lang = JFactory::getLanguage();
11223 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11224 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
11225 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
11226 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
11227 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
11228 $dbo->setQuery($q);
11229 $row = $dbo->loadAssoc();
11230 if (!$row) {
11231 $mainframe->redirect('index.php');
11232 exit;
11233 }
11234 if (!empty($row['lang'])) {
11235 if ($lang->getTag() != $row['lang']) {
11236 if (VBOPlatformDetection::isWordPress()) {
11237 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
11238 } else {
11239 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
11240 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
11241 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
11242 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
11243 }
11244 }
11245 if ($vbo_tn->getDefaultLang() != $row['lang']) {
11246 // force the translation to start because contents should be translated
11247 $vbo_tn::$force_tolang = $row['lang'];
11248 }
11249 }
11250 $customer = array();
11251 $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'].";";
11252 $dbo->setQuery($q);
11253 $dbo->execute();
11254 if ($dbo->getNumRows() > 0) {
11255 $customer = $dbo->loadAssoc();
11256 if (!empty($customer['country'])) {
11257 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
11258 $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"/>';
11259 }
11260 }
11261 }
11262 if (!(count($customer) > 0)) {
11263 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11264 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11265 exit;
11266 }
11267 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
11268 //check if the signature has been submitted
11269 $signature_data = '';
11270 $cont_type = '';
11271 if (!empty($psignature)) {
11272 //check whether the format is accepted
11273 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
11274 $parts = explode(';base64,', $psignature);
11275 $cont_type_parts = explode('image/', $parts[0]);
11276 $cont_type = $cont_type_parts[1];
11277 if (!empty($parts[1])) {
11278 $signature_data = base64_decode($parts[1]);
11279 }
11280 }
11281 }
11282 if (!empty($signature_data)) {
11283 //write file
11284 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
11285 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
11286 $fp = fopen($filepath, 'w+');
11287 $bytes = fwrite($fp, $signature_data);
11288 fclose($fp);
11289 if ($bytes !== false && $bytes > 0) {
11290 //update the signature in the DB
11291 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
11292 $dbo->setQuery($q);
11293 $dbo->execute();
11294 $customer['signature'] = $sign_fname;
11295 //resize image for screens with high resolution
11296 if ($ppad_ratio > 1) {
11297 $new_width = floor(($ppad_width / 2));
11298 $creativik = new vikResizer();
11299 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
11300 } else {
11301 /**
11302 * @wponly - trigger files mirroring
11303 */
11304 VikBookingLoader::import('update.manager');
11305 VikBookingUpdateManager::triggerUploadBackup($filepath);
11306 //
11307 }
11308 //
11309 } else {
11310 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
11311 }
11312 }
11313 //
11314 //generate PDF for check-in document by parsing the apposite template file
11315 $booking_rooms = array();
11316 $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'].";";
11317 $dbo->setQuery($q);
11318 $dbo->execute();
11319 if ($dbo->getNumRows() > 0) {
11320 $booking_rooms = $dbo->loadAssocList();
11321 if (!empty($row['lang'])) {
11322 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
11323 }
11324 }
11325 if (!class_exists('TCPDF')) {
11326 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
11327 }
11328 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
11329
11330 /**
11331 * Trigger event to allow third party plugins to return a specific font name.
11332 *
11333 * @since 1.16.0 (J) - 1.6.0 (WP)
11334 */
11335 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
11336 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
11337 $usepdffont = $custom_pdf_font[0];
11338 }
11339
11340 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
11341 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
11342
11343 // build the proper document SID for bc
11344 $doc_sid = $row['sid'] ?: $row['idorderota'] ?: '';
11345 $pdffname = $row['id'] . '_' . $doc_sid . '.pdf';
11346
11347 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
11348 if (file_exists($pathpdf)) @unlink($pathpdf);
11349 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
11350 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
11351 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
11352 //Header for each page of the pdf
11353 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
11354 $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]);
11355 }
11356 //header and footer fonts
11357 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
11358 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
11359 //margins
11360 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
11361 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
11362 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
11363 //
11364 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
11365 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
11366 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
11367 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
11368 $pdf->SetPrintHeader(false);
11369 }
11370 if ($pdfparams['show_footer'] == 0) {
11371 $pdf->SetPrintFooter(false);
11372 }
11373 $pdf->AddPage();
11374 $pdf->writeHTML($checkin_body, true, false, true, false, '');
11375 $pdf->lastPage();
11376 $pdf->Output($pathpdf, 'F');
11377 if (!file_exists($pathpdf)) {
11378 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
11379 } else {
11380 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
11381 $dbo->setQuery($q);
11382 $dbo->execute();
11383 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
11384 /**
11385 * @wponly - trigger files mirroring
11386 */
11387 VikBookingLoader::import('update.manager');
11388 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
11389 //
11390 }
11391 //
11392 /**
11393 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
11394 */
11395 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
11396 exit;
11397 }
11398
11399 public function updatebookingcheckin()
11400 {
11401 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
11402 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11403 }
11404
11405 $cid = VikRequest::getVar('cid', array(0));
11406 $id = $cid[0];
11407
11408 $dbo = JFactory::getDbo();
11409 $app = JFactory::getApplication();
11410
11411 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11412 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
11413 $pguests = VikRequest::getVar('guests', array());
11414 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
11415 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
11416 $valid_actions = array(-1, 0, 1, 2);
11417 if (!in_array($pcheckin_action, $valid_actions)) {
11418 $app->redirect('index.php');
11419 exit;
11420 }
11421 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
11422 $dbo->setQuery($q);
11423 $dbo->execute();
11424 if ($dbo->getNumRows() < 1) {
11425 $app->redirect('index.php');
11426 exit;
11427 }
11428 $row = $dbo->loadAssoc();
11429 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
11430 $dbo->setQuery($q);
11431 $dbo->execute();
11432 if ($dbo->getNumRows() < 1) {
11433 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11434 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11435 exit;
11436 }
11437 $custorder = $dbo->loadAssoc();
11438 //update checked status and new total paid
11439 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
11440 $dbo->setQuery($q);
11441 $dbo->execute();
11442 // Booking History log for new amount paid (payment update)
11443 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
11444 $extra_data = new stdClass;
11445 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
11446 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
11447 }
11448 //
11449 //Booking History
11450 $hist_type = 'A';
11451 if ($pcheckin_action < 0) {
11452 $hist_type = 'Z';
11453 } elseif ($pcheckin_action == 1) {
11454 $hist_type = 'B';
11455 } elseif ($pcheckin_action == 2) {
11456 $hist_type = 'C';
11457 }
11458 $user = JFactory::getUser();
11459 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
11460 //
11461 //Guests Details
11462 $guests_details = array();
11463 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
11464 // grab also the fields for front-end pre check-in
11465 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
11466 //
11467 foreach ($pguests as $ind => $adults) {
11468 foreach ($adults as $aduind => $details) {
11469 foreach ($pax_fields as $key => $v) {
11470 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11471 if (!isset($guests_details[$ind])) {
11472 $guests_details[$ind] = array();
11473 }
11474 if (!isset($guests_details[$ind][$aduind])) {
11475 $guests_details[$ind][$aduind] = array();
11476 }
11477 $guests_details[$ind][$aduind][$key] = $details[$key];
11478 }
11479 }
11480 foreach ($pre_pax_fields as $key => $v) {
11481 if (isset($pax_fields[$key])) {
11482 // we must have parsed this back-end field already
11483 continue;
11484 }
11485 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11486 if (!isset($guests_details[$ind])) {
11487 $guests_details[$ind] = array();
11488 }
11489 if (!isset($guests_details[$ind][$aduind])) {
11490 $guests_details[$ind][$aduind] = array();
11491 }
11492 if (!isset($guests_details[$ind][$aduind][$key])) {
11493 $guests_details[$ind][$aduind][$key] = $details[$key];
11494 }
11495 }
11496 }
11497 }
11498 }
11499
11500 if ($guests_details) {
11501 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
11502 $curpaxdata = json_decode($custorder['pax_data'], true);
11503 if (is_array($curpaxdata) && $curpaxdata) {
11504 // scan new guest registration details
11505 foreach ($guests_details as $ind => $groom) {
11506 foreach ($groom as $aduind => $aduinfo) {
11507 if (isset($curpaxdata[$ind][$aduind])) {
11508 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
11509 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
11510 foreach ($guests_details[$ind][$aduind] as $key => $det) {
11511 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
11512 // this default pax field was specified as empty now, so we cannot merge it
11513 unset($guests_details[$ind][$aduind][$key]);
11514 }
11515 }
11516 }
11517 }
11518 }
11519
11520 /**
11521 * In order to not lose any custom registration data added through PMS reports,
11522 * we scan the previous registration data to ensure we keep them in the update.
11523 *
11524 * @since 1.16.10 (J) - 1.6.10 (WP)
11525 */
11526 foreach ($curpaxdata as $ind => $groom) {
11527 if (!isset($guests_details[$ind])) {
11528 // ignore deleted room registration
11529 continue;
11530 }
11531 foreach ($groom as $aduind => $aduinfo) {
11532 if (!isset($guests_details[$ind][$aduind]) || !is_array($aduinfo)) {
11533 // ignore deleted room-guest registration
11534 continue;
11535 }
11536 foreach ($aduinfo as $field_key => $field_val) {
11537 if (!isset($guests_details[$ind][$aduind][$field_key]) && !empty($field_val)) {
11538 // merge previous room-guest registration data
11539 $guests_details[$ind][$aduind][$field_key] = $field_val;
11540 }
11541 }
11542 }
11543 }
11544 }
11545
11546 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=" . $dbo->q(json_encode($guests_details)) . " WHERE `id`=" . (int) $custorder['id'] . ";";
11547 $dbo->setQuery($q);
11548 $dbo->execute();
11549 }
11550
11551 //'checked' status comments
11552 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11553 $dbo->setQuery($q);
11554 $dbo->execute();
11555
11556 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11557 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11558 exit;
11559 }
11560
11561 public function alterbooking()
11562 {
11563 $dbo = JFactory::getDbo();
11564 $app = JFactory::getApplication();
11565 $user = JFactory::getUser();
11566
11567 $response = array(
11568 'esit' => 1,
11569 'message' => '',
11570 'vcm' => '',
11571 );
11572
11573 // must be a string as it may contain a dash
11574 $pidorder = VikRequest::getString('idorder', '', 'request');
11575 $pidorder = intval(str_replace('-', '', $pidorder));
11576
11577 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11578 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11579 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11580 $ptodate = VikRequest::getString('todate', '', 'request');
11581 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11582 if ($pdebug == 1) {
11583 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11584 exit;
11585 }
11586
11587 $nowdf = VikBooking::getDateFormat(true);
11588 if ($nowdf == "%d/%m/%Y") {
11589 $df = 'd/m/Y';
11590 } elseif ($nowdf == "%m/%d/%Y") {
11591 $df = 'm/d/Y';
11592 } else {
11593 $df = 'Y/m/d';
11594 }
11595 $pcheckinh = 0;
11596 $pcheckinm = 0;
11597 $pcheckouth = 0;
11598 $pcheckoutm = 0;
11599 $timeopst = VikBooking::getTimeOpenStore();
11600 if (is_array($timeopst)) {
11601 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11602 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11603 $pcheckinh = $opent[0];
11604 $pcheckinm = $opent[1];
11605 $pcheckouth = $closet[0];
11606 $pcheckoutm = $closet[1];
11607 }
11608 $info_tsto = getdate(strtotime($ptodate));
11609 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11610 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11611 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11612 $ptodate = date('Y-m-d', $second);
11613 if (!($second > $first)) {
11614 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11615 exit;
11616 }
11617 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11618 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11619 exit;
11620 }
11621
11622 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11623 $dbo->setQuery($q, 0, 1);
11624 $dbo->execute();
11625 if (!$dbo->getNumRows()) {
11626 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11627 exit;
11628 }
11629 $ord = $dbo->loadAssoc();
11630
11631 $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;";
11632 $dbo->setQuery($q);
11633 $dbo->execute();
11634 $ordersrooms = $dbo->loadAssocList();
11635
11636 // store for VCM the current rooms before the modification
11637 $ord['rooms_info'] = $ordersrooms;
11638
11639 // package or custom rate
11640 $is_package = !empty($ord['pkg']) ? true : false;
11641 $is_cust_cost = false;
11642 foreach ($ordersrooms as $kor => $or) {
11643 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11644 $is_cust_cost = true;
11645 break;
11646 }
11647 }
11648
11649 // availability helper
11650 $av_helper = VikBooking::getAvailabilityInstance();
11651
11652 // room stay dates in case of split stay
11653 $room_stay_dates = [];
11654 if ($ord['split_stay']) {
11655 // no need to get the transient based on booking status, as the booking must be confirmed
11656 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11657 // immediately count the number of nights of stay for each split room
11658 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11659 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11660 }
11661 }
11662
11663 // determine if dates have changed
11664 $dates_changed = false;
11665 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11666 $dates_changed = true;
11667 }
11668
11669 $toswitch = array();
11670 $idbooked = array();
11671 $rooms_units = array();
11672 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11673 $dbo->setQuery($q);
11674 $dbo->execute();
11675 $all_rooms = $dbo->loadAssocList();
11676 foreach ($all_rooms as $rr) {
11677 $rooms_units[$rr['id']]['name'] = $rr['name'];
11678 $rooms_units[$rr['id']]['units'] = $rr['units'];
11679 }
11680
11681 // switch room
11682 if ($poldidroom != $pidroom) {
11683 foreach ($ordersrooms as $ind => $or) {
11684 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11685 if (!isset($idbooked[$or['idroom']])) {
11686 $idbooked[$or['idroom']] = 0;
11687 }
11688 // $idbooked is not really needed as switch is never made for the same room id
11689 $idbooked[$or['idroom']]++;
11690 //
11691 $orkey = count($toswitch);
11692 $toswitch[$orkey]['from'] = $or['idroom'];
11693 $toswitch[$orkey]['to'] = $pidroom;
11694 $toswitch[$orkey]['record'] = $or;
11695 $toswitch[$orkey]['record_ind'] = $ind;
11696 break;
11697 }
11698 }
11699 }
11700 if (count($toswitch)) {
11701 foreach ($toswitch as $ksw => $rsw) {
11702 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11703 $room_checkin = $ord['checkin'];
11704 $room_checkout = $ord['checkout'];
11705 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11706 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11707 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11708 }
11709 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11710 // the room is not available
11711 unset($toswitch[$ksw]);
11712 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11713 exit;
11714 }
11715 }
11716 if (count($toswitch)) {
11717 //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)
11718 reset($ordersrooms);
11719 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11720 $dbo->setQuery($q);
11721 $dbo->execute();
11722 //
11723 foreach ($toswitch as $ksw => $rsw) {
11724 // update room reservation record
11725 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11726 $dbo->setQuery($q);
11727 $dbo->execute();
11728 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11729
11730 // update Notes field for this booking to keep track of the previous room that was assigned
11731 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11732 if (!empty($prev_room_name)) {
11733 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11734 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11735 $dbo->setQuery($q);
11736 $dbo->execute();
11737 }
11738
11739 if ($ord['status'] == 'confirmed') {
11740 // update room record in _busy
11741 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'])) {
11742 // in case of a split stay it is fundamental to update the exact busy record ID
11743 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11744 $dbo->setQuery($q);
11745 $dbo->execute();
11746 } else {
11747 // regular processing of a room ID for a reservation, no matter which one, we switch it
11748 $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;";
11749 $dbo->setQuery($q);
11750 $dbo->execute();
11751 if ($dbo->getNumRows() == 1) {
11752 $cur_busy = $dbo->loadAssocList();
11753 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11754 $dbo->setQuery($q);
11755 $dbo->execute();
11756 }
11757 }
11758
11759 // if automated updates enabled, keep $response['vcm'] empty
11760 // Invoke Channel Manager
11761 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11762 $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>';
11763 }
11764 } elseif ($ord['status'] == 'standby') {
11765 // remove record in _tmplock
11766 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11767 $dbo->setQuery($q);
11768 $dbo->execute();
11769 }
11770 }
11771
11772 // check if sub-units should be assigned again when switching room
11773 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11774 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11775 $room_indexes_usemap = [];
11776 foreach ($new_order_rooms as $kor => $or) {
11777 $num = $kor + 1;
11778 // assign room specific unit
11779 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11780 $use_ind_key = 0;
11781 if ($room_indexes) {
11782 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11783 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11784 } else {
11785 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11786 }
11787 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11788 $dbo->setQuery($q);
11789 $dbo->execute();
11790 $room_indexes_usemap[$or['idroom']]++;
11791 }
11792 }
11793 }
11794
11795 // do not terminate the process when there is a switch, proceed to check the dates.
11796 }
11797 }
11798
11799 // change dates
11800 if ($dates_changed) {
11801 if ($ord['split_stay']) {
11802 // we do not allow to drag and change dates for rooms in a split stay reservation
11803 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11804 exit;
11805 }
11806
11807 // total nights of stay
11808 $daysdiff = $ord['days'];
11809
11810 // re-read ordersrooms (as rooms may have been switched)
11811 $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;";
11812 $dbo->setQuery($q);
11813 $dbo->execute();
11814 $ordersrooms = $dbo->loadAssocList();
11815
11816 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11817 $opertwounits = true;
11818 $units_counter = array();
11819 foreach ($ordersrooms as $ind => $or) {
11820 if (!isset($units_counter[$or['idroom']])) {
11821 $units_counter[$or['idroom']] = -1;
11822 }
11823 $units_counter[$or['idroom']]++;
11824 }
11825
11826 foreach ($ordersrooms as $ind => $or) {
11827 $num = $ind + 1;
11828 $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'] . ";";
11829 $dbo->setQuery($check);
11830 $dbo->execute();
11831 if ($dbo->getNumRows() > 0) {
11832 $busy = $dbo->loadAssocList();
11833 foreach ($groupdays as $gday) {
11834 $bfound = 0;
11835 foreach ($busy as $bu) {
11836 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11837 $bfound++;
11838 }
11839 }
11840 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11841 $opertwounits = false;
11842 break 2;
11843 }
11844 }
11845 }
11846 }
11847 if ($opertwounits !== true) {
11848 $response['esit'] = 0;
11849 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11850 echo json_encode($response);
11851 exit;
11852 }
11853
11854 // update dates and busy records
11855 $realback = VikBooking::getHoursRoomAvail() * 3600;
11856 $realback += $second;
11857 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11858 $dbo->setQuery($q);
11859 $dbo->execute();
11860 if ($ord['status'] == 'confirmed') {
11861 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11862 $dbo->setQuery($q);
11863 $dbo->execute();
11864 $allbusy = $dbo->loadAssocList();
11865 foreach ($allbusy as $bb) {
11866 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11867 $dbo->setQuery($q);
11868 $dbo->execute();
11869 }
11870 // if automated updates enabled, keep $response['vcm'] empty
11871 // Invoke Channel Manager
11872 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11873 $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>';
11874 }
11875 }
11876 $response['message'] .= JText::translate('RESUPDATED')."\n";
11877 }
11878
11879 if (count($toswitch)) {
11880 /**
11881 * Rooms have changed so the new rates must be re-calculated.
11882 * Maybe they should be calculated in any case, even if just
11883 * the dates have changed. For the moment the rates are reset.
11884 */
11885 }
11886
11887 // unset any previously booked room due to calendar sharing
11888 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11889 // check if some of the rooms booked have shared calendars
11890 VikBooking::updateSharedCalendars($ord['id']);
11891 //
11892
11893 //Booking History
11894 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11895 //
11896
11897 $vcm_autosync = VikBooking::vcmAutoUpdate();
11898 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11899 //unset the vcm property as no buttons should be displayed when in auto-sync
11900 $response['vcm'] = '';
11901 $vcm_obj = VikBooking::getVcmInvoker();
11902 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11903 $sync_result = $vcm_obj->doSync();
11904 if ($sync_result === false) {
11905 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11906 }
11907 }
11908
11909 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11910 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11911 VikError::raiseNotice('', $response['vcm']);
11912 }
11913
11914 $response['message'] = nl2br($response['message']);
11915 echo json_encode($response);
11916 exit;
11917 }
11918
11919 public function modroomrateplans()
11920 {
11921 $dbo = JFactory::getDbo();
11922 $session = JFactory::getSession();
11923
11924 $updforvcm = $session->get('vbVcmRatesUpd', '');
11925 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11926
11927 $pid_room = VikRequest::getInt('id_room', '', 'request');
11928 $pid_price = VikRequest::getInt('id_price', '', 'request');
11929 $ptype = VikRequest::getString('type', '', 'request');
11930 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11931 $ptodate = VikRequest::getString('todate', '', 'request');
11932
11933 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11934 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11935 exit;
11936 }
11937
11938 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11939 $dbo->setQuery($q);
11940 $price_record = $dbo->loadAssoc();
11941
11942 if (!$price_record) {
11943 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11944 exit;
11945 }
11946
11947 $current_closed = array();
11948 if (!empty($price_record['closingd'])) {
11949 $current_closed = json_decode($price_record['closingd'], true);
11950 }
11951 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11952
11953 $start_ts = strtotime($pfromdate);
11954 $end_ts = strtotime($ptodate);
11955 $infostart = getdate($start_ts);
11956 $all_days = array();
11957 $output = array();
11958 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11959 $all_days[] = date('Y-m-d', $infostart[0]);
11960 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11961 $output[$indkey] = array();
11962 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11963 }
11964
11965 if ($ptype == 'close') {
11966 // close
11967 if (!array_key_exists($pid_room, $current_closed)) {
11968 $current_closed[$pid_room] = array();
11969 }
11970 foreach ($all_days as $daymod) {
11971 if (!in_array($daymod, $current_closed[$pid_room])) {
11972 $current_closed[$pid_room][] = $daymod;
11973 }
11974 }
11975 } else {
11976 // open
11977 if (array_key_exists($pid_room, $current_closed)) {
11978 foreach ($all_days as $daymod) {
11979 if (in_array($daymod, $current_closed[$pid_room])) {
11980 foreach ($current_closed[$pid_room] as $ck => $cv) {
11981 if ($daymod == $cv) {
11982 unset($current_closed[$pid_room][$ck]);
11983 }
11984 }
11985 }
11986 }
11987 } else {
11988 $current_closed[$pid_room] = array();
11989 }
11990 }
11991
11992 if (!$current_closed[$pid_room]) {
11993 unset($current_closed[$pid_room]);
11994 }
11995
11996 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11997 $dbo->setQuery($q);
11998 $dbo->execute();
11999
12000 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
12001 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
12002
12003 foreach ($output as $ok => $ov) {
12004 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
12005 }
12006
12007 // build new session values
12008 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
12009
12010 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
12011 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
12012 } else {
12013 $updforvcm['dfrom'] = $start_ts;
12014 }
12015
12016 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
12017 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
12018 } else {
12019 $updforvcm['dto'] = $end_ts;
12020 }
12021
12022 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
12023 if (!in_array($pid_room, $updforvcm['rooms'])) {
12024 $updforvcm['rooms'][] = $pid_room;
12025 }
12026 } else {
12027 $updforvcm['rooms'] = array($pid_room);
12028 }
12029
12030 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
12031 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
12032 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
12033 $updforvcm['rplans'][$pid_room][] = $pid_price;
12034 }
12035 } else {
12036 $updforvcm['rplans'][$pid_room] = array($pid_price);
12037 }
12038 } else {
12039 $updforvcm['rplans'] = array($pid_room => array($pid_price));
12040 }
12041
12042 /**
12043 * Rather than suggesting the administrator to manually invoke VCM to launch a Bulk Action,
12044 * we try to silently trigger an automatic bulk action before updating the session values.
12045 *
12046 * @since 1.17.1 (J) - 1.7.1 (WP)
12047 */
12048 $rates_aligned = false;
12049 try {
12050 if (class_exists('VikChannelManager')) {
12051 $rates_aligned = VikChannelManager::autoBulkActions([
12052 'from_date' => $pfromdate,
12053 'to_date' => $ptodate,
12054 'forced_rooms' => [$pid_room],
12055 'update' => 'rates',
12056 ]);
12057 }
12058 } catch (Throwable $e) {
12059 // do nothing
12060 $rates_aligned = false;
12061 }
12062
12063 if (!$rates_aligned) {
12064 // update session values
12065 $session->set('vbVcmRatesUpd', $updforvcm);
12066 }
12067
12068 echo json_encode($output);
12069 exit;
12070 }
12071
12072 public function icsexportlaunch() {
12073 $dbo = JFactory::getDBO();
12074 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12075 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12076 $pstatus = VikRequest::getString('status', '', 'request');
12077 $validstatus = array('confirmed', 'standby', 'cancelled');
12078 $filterstatus = '';
12079 $filterfirst = 0;
12080 $filtersecond = 0;
12081 $nowdf = VikBooking::getDateFormat(true);
12082 if ($nowdf == "%d/%m/%Y") {
12083 $df = 'd/m/Y';
12084 } elseif ($nowdf == "%m/%d/%Y") {
12085 $df = 'm/d/Y';
12086 } else {
12087 $df = 'Y/m/d';
12088 }
12089 $currencyname = VikBooking::getCurrencyName();
12090 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12091 $filterstatus = $pstatus;
12092 }
12093 if (!empty($pcheckindate)) {
12094 if (VikBooking::dateIsValid($pcheckindate)) {
12095 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12096 $filterfirst = $first;
12097 }
12098 }
12099 if (!empty($pcheckoutdate)) {
12100 if (VikBooking::dateIsValid($pcheckoutdate)) {
12101 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12102 if ($second > $first) {
12103 $filtersecond = $second;
12104 }
12105 }
12106 }
12107 $clause = array();
12108 if ($filterfirst > 0) {
12109 $clause[] = "`o`.`checkin` >= ".$filterfirst;
12110 }
12111 if ($filtersecond > 0) {
12112 $clause[] = "`o`.`checkout` <= ".$filtersecond;
12113 }
12114 if (!empty($filterstatus)) {
12115 $clause[] = "`o`.`status` = '".$filterstatus."'";
12116 }
12117 $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;";
12118 $dbo->setQuery($q);
12119 $dbo->execute();
12120 if ($dbo->getNumRows() > 0) {
12121 $orders = $dbo->loadAssocList();
12122 $icscontent = "BEGIN:VCALENDAR\n";
12123 $icscontent .= "VERSION:2.0\n";
12124 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
12125 $icscontent .= "CALSCALE:GREGORIAN\n";
12126 $str = "";
12127 foreach ($orders as $kord => $ord) {
12128 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12129 continue;
12130 }
12131 $usecurrencyname = $currencyname;
12132 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12133 $statusstr = '';
12134 if ($ord['status'] == 'confirmed') {
12135 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12136 } elseif ($ord['status'] == 'standby') {
12137 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12138 } elseif ($ord['status'] == 'cancelled') {
12139 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12140 }
12141 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
12142 /**
12143 * @wponly Rewrite URI for front-end
12144 */
12145 $uri = str_replace(JUri::root(), '', $uri);
12146 $model = JModel::getInstance('vikbooking', 'shortcodes');
12147 $itemid = $model->best('booking');
12148 if ($itemid) {
12149 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
12150 }
12151 //
12152 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
12153 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12154 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
12155 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
12156 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
12157 $str .= "BEGIN:VEVENT\n";
12158 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12159 $str .= "UID:" . uniqid() . "\n";
12160 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12161 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
12162 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
12163 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
12164 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12165 $str .= "END:VEVENT\n";
12166 }
12167 $icscontent .= $str;
12168 $icscontent .= "END:VCALENDAR\n";
12169 //download file from buffer
12170 header("Content-Type: application/octet-stream; ");
12171 header("Cache-Control: no-store, no-cache");
12172 header('Content-Disposition: attachment; filename="bookings_export.ics"');
12173 $f = fopen('php://output', "w");
12174 fwrite($f, $icscontent);
12175 fclose($f);
12176 exit;
12177 } else {
12178 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
12179 $mainframe = JFactory::getApplication();
12180 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12181 }
12182 }
12183
12184 public function csvexportlaunch()
12185 {
12186 $dbo = JFactory::getDbo();
12187 $app = JFactory::getApplication();
12188
12189 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
12190 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
12191 $pchfilt = VikRequest::getString('chfilt', '', 'request');
12192 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
12193 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12194 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12195 $pstatus = VikRequest::getString('status', '', 'request');
12196 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
12197 $pformat = VikRequest::getString('format', 'csv', 'request');
12198
12199 // let the report class (a generic one) generate the CSV file in the proper format
12200 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
12201
12202 $validstatus = array('confirmed', 'standby', 'cancelled');
12203 $validdates = array('ts', 'checkin', 'checkout');
12204
12205 $filterdate = '';
12206 $filterstatus = '';
12207 $first = 0;
12208 $filterfirst = 0;
12209 $filtersecond = 0;
12210 $nowdf = VikBooking::getDateFormat(true);
12211 if ($nowdf == "%d/%m/%Y") {
12212 $df = 'd/m/Y';
12213 } elseif ($nowdf == "%m/%d/%Y") {
12214 $df = 'm/d/Y';
12215 } else {
12216 $df = 'Y/m/d';
12217 }
12218 $datesep = VikBooking::getDateSeparator(true);
12219 $currencyname = VikBooking::getCurrencyName();
12220
12221 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12222 $filterstatus = $pstatus;
12223 }
12224 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
12225 $filterdate = $pdatefilt;
12226 }
12227 if (!empty($pcheckindate) && !empty($filterdate)) {
12228 if (VikBooking::dateIsValid($pcheckindate)) {
12229 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12230 $filterfirst = $first;
12231 }
12232 }
12233 if (!empty($pcheckoutdate) && !empty($filterdate)) {
12234 if (VikBooking::dateIsValid($pcheckoutdate)) {
12235 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12236 if ($second > $first) {
12237 $filtersecond = $second;
12238 }
12239 }
12240 }
12241 $clause = array();
12242 if ($filterfirst > 0) {
12243 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
12244 }
12245 if ($filtersecond > 0) {
12246 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
12247 }
12248 if (!empty($filterstatus)) {
12249 $clause[] = "`o`.`status` = '".$filterstatus."'";
12250 }
12251 if (!empty($pchfilt)) {
12252 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
12253 }
12254 if (!empty($ppayfilt)) {
12255 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
12256 }
12257 if (!empty($proomfilt)) {
12258 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
12259 }
12260
12261 if (!empty($pcatfilt)) {
12262 $room_cat_ids = array();
12263 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
12264 $dbo->setQuery($q);
12265 $dbo->execute();
12266 if ($dbo->getNumRows()) {
12267 $records = $dbo->loadAssocList();
12268 foreach ($records as $rcat) {
12269 $parts = explode(';', $rcat['idcat']);
12270 if (in_array($pcatfilt, $parts)) {
12271 $room_cat_ids[] = $rcat['id'];
12272 }
12273 }
12274 }
12275 if (count($room_cat_ids)) {
12276 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
12277 }
12278 }
12279
12280 $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;";
12281 $dbo->setQuery($q);
12282 $orders = $dbo->loadAssocList();
12283 if (!$orders) {
12284 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
12285 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12286 $app->close();
12287 }
12288
12289 // options
12290 $all_options = array();
12291 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
12292 $dbo->setQuery($q);
12293 $options = $dbo->loadAssocList();
12294 if ($options) {
12295 foreach ($options as $ok => $ov) {
12296 $all_options[$ov['id']] = $ov;
12297 }
12298 }
12299
12300 // set CSV columns
12301 $report_obj->setReportCols([
12302 [
12303 'label' => JText::translate('VBDASHBOOKINGID'),
12304 ],
12305 [
12306 'label' => JText::translate('VBPVIEWORDERSONE'),
12307 ],
12308 [
12309 'label' => JText::translate('VBCSVCHECKIN'),
12310 ],
12311 [
12312 'label' => JText::translate('VBCSVCHECKOUT'),
12313 ],
12314 [
12315 'label' => JText::translate('VBCSVNIGHTS'),
12316 ],
12317 [
12318 'label' => JText::translate('VBCSVROOM'),
12319 ],
12320 [
12321 'label' => JText::translate('VBCSVPEOPLE'),
12322 ],
12323 [
12324 'label' => JText::translate('VBCSVCUSTINFO'),
12325 ],
12326 [
12327 'label' => JText::translate('ORDER_SPREQUESTS'),
12328 ],
12329 [
12330 'label' => JText::translate('ORDER_NOTES'),
12331 ],
12332 [
12333 'label' => JText::translate('VBCSVCREATEDBY'),
12334 ],
12335 [
12336 'label' => JText::translate('VBCSVCUSTMAIL'),
12337 ],
12338 [
12339 'label' => JText::translate('ORDER_PHONE'),
12340 ],
12341 [
12342 'label' => JText::translate('VBCSVOPTIONS'),
12343 ],
12344 [
12345 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
12346 ],
12347 [
12348 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
12349 ],
12350 [
12351 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
12352 ],
12353 [
12354 'label' => JText::translate('VBCSVTOTAL'),
12355 ],
12356 [
12357 'label' => JText::translate('VBCSVTOTPAID'),
12358 ],
12359 [
12360 'label' => JText::translate('VBCSVTOTTAXES'),
12361 ],
12362 ]);
12363
12364 // prepare the container for the CSV rows
12365 $orderscsv = [];
12366
12367 // availability helper
12368 $av_helper = VikBooking::getAvailabilityInstance();
12369
12370 $room_inds = [];
12371 $room_stay_dates = [];
12372 foreach ($orders as $kord => $ord) {
12373 // room index in this booking
12374 if (!isset($room_inds[$ord['id']])) {
12375 $room_inds[$ord['id']] = -1;
12376 }
12377 $room_inds[$ord['id']]++;
12378
12379 /**
12380 * Split stay reservation.
12381 *
12382 * @since 1.16.0 (J) - 1.6.0 (WP)
12383 */
12384 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
12385 if ($ord['split_stay']) {
12386 if ($ord['status'] == 'confirmed') {
12387 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
12388 } else {
12389 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
12390 }
12391 // immediately count the number of nights of stay for each split room
12392 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
12393 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
12394 // overwrite values for compatibility with non-confirmed bookings
12395 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
12396 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
12397 }
12398 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
12399 // overwrite the whole array
12400 $room_stay_dates[$sps_r_k] = $sps_r_v;
12401 }
12402 }
12403
12404 // determine nights and dates for this room booking
12405 $booking_nights = $ord['days'];
12406 $booking_checkin = $ord['checkin'];
12407 $booking_checkout = $ord['checkout'];
12408 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']) {
12409 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
12410 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
12411 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
12412 }
12413
12414 $usecurrencyname = $currencyname;
12415 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12416 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12417 $custinfostr = str_replace(",", " ", $ord['custdata']);
12418 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
12419 if (count($customer)) {
12420 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
12421 }
12422 $special_requests = '';
12423 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12424 $special_requests = $match[1];
12425 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12426 $special_requests = $match[1];
12427 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
12428 $special_requests = $match[1];
12429 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
12430 $special_requests = $match[1];
12431 }
12432 $paystr = '';
12433 if (!empty($ord['idpayment'])) {
12434 $payparts = explode('=', $ord['idpayment']);
12435 $paystr = $payparts[1];
12436 }
12437 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
12438 $statusstr = '';
12439 if ($ord['status'] == 'confirmed') {
12440 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12441 } elseif ($ord['status'] == 'standby') {
12442 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12443 } elseif ($ord['status'] == 'cancelled') {
12444 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12445 }
12446 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
12447 if ($ord['roomsnum'] > 1) {
12448 // take the cost for the individual room
12449 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
12450 }
12451 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
12452 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12453 // total paid will be printed only for the last room booked
12454 $totalpaidstring = '';
12455 }
12456 $options_str = '';
12457 if (!empty($ord['optionals'])) {
12458 $stepo = explode(";", $ord['optionals']);
12459 foreach ($stepo as $roptkey => $oo) {
12460 if (!empty($oo)) {
12461 $stept = explode(":", $oo);
12462 if (array_key_exists($stept[0], $all_options)) {
12463 $actopt = $all_options[$stept[0]];
12464 $optpcent = false;
12465 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
12466 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
12467 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
12468 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
12469 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
12470 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
12471 $agestept = explode('-', $stept[1]);
12472 $stept[1] = $agestept[0];
12473 $chvar = $agestept[1];
12474 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
12475 $optpcent = true;
12476 }
12477 $actopt['chageintv'] = $chvar;
12478 if (isset($optagenames[($chvar - 1)])) {
12479 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
12480 }
12481 if (isset($optagecosts[($chvar - 1)])) {
12482 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
12483 } else {
12484 $realcost = 0;
12485 }
12486 } else {
12487 // VBO 1.11 - options percentage cost of the room total fee
12488 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
12489 //
12490 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
12491 }
12492 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
12493 $realcost=$actopt['maxprice'];
12494 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
12495 $realcost = $actopt['maxprice'] * $stept[1];
12496 }
12497 }
12498 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
12499 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
12500 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
12501 }
12502 }
12503 }
12504 }
12505
12506 // custom extra costs
12507 if (!empty($ord['extracosts'])) {
12508 $cur_extra_costs = json_decode($ord['extracosts'], true);
12509 foreach ($cur_extra_costs as $eck => $ecv) {
12510 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
12511 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
12512 }
12513 }
12514
12515 // taxes
12516 $taxes_str = '';
12517 if ($ord['tot_taxes'] > 0.00) {
12518 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
12519 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
12520 $tax_breakdown = json_decode($ord['breakdown'], true);
12521 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
12522 if (count($tax_breakdown)) {
12523 foreach ($tax_breakdown as $tbkk => $tbkv) {
12524 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
12525 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
12526 }
12527 }
12528 }
12529 }
12530 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12531 // total taxes will be printed only for the last room booked
12532 $taxes_str = '';
12533 }
12534
12535 // created by
12536 $created_by = '';
12537 if (!empty($ord['ujid'])) {
12538 $creator = new JUser($ord['ujid']);
12539 if (property_exists($creator, 'name')) {
12540 $created_by = $creator->name.' ('.$creator->username.')';
12541 }
12542 }
12543 if (empty($created_by) && !empty($ord['t_first_name'])) {
12544 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
12545 }
12546
12547 // push line for export
12548 $orderscsv[] = [
12549 [
12550 'value' => $ord['id'],
12551 ],
12552 [
12553 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
12554 ],
12555 [
12556 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
12557 ],
12558 [
12559 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
12560 ],
12561 [
12562 'value' => $booking_nights,
12563 ],
12564 [
12565 'value' => $ord['name'],
12566 ],
12567 [
12568 'value' => $peoplestr,
12569 ],
12570 [
12571 'value' => $custinfostr,
12572 ],
12573 [
12574 'value' => $special_requests,
12575 ],
12576 [
12577 'value' => $ord['adminnotes'],
12578 ],
12579 [
12580 'value' => $created_by,
12581 ],
12582 [
12583 'value' => $ord['custmail'],
12584 ],
12585 [
12586 'value' => $ord['phone'],
12587 ],
12588 [
12589 'value' => $options_str,
12590 ],
12591 [
12592 'value' => $paystr,
12593 ],
12594 [
12595 'value' => $ordnumbstr,
12596 ],
12597 [
12598 'value' => $statusstr,
12599 ],
12600 [
12601 'value' => $totalstring,
12602 ],
12603 [
12604 'value' => $totalpaidstring,
12605 ],
12606 [
12607 'value' => $taxes_str,
12608 ],
12609 ];
12610 }
12611
12612 // set CSV rows
12613 $report_obj->setReportRows($orderscsv);
12614
12615 // build lines to export
12616 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12617
12618 // set export file name
12619 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12620
12621 // force the download of the CSV file
12622 $report_obj->outputHeaders();
12623
12624 // send lines to output
12625 $report_obj->outputCSV($csvlines);
12626
12627 exit;
12628 }
12629
12630 public function exportcustomerslaunch() {
12631 $cid = VikRequest::getVar('cid', array(0));
12632 $dbo = JFactory::getDBO();
12633 $pnotes = VikRequest::getInt('notes', '', 'request');
12634 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12635 $ppin = VikRequest::getInt('pin', '', 'request');
12636 $pcountry = VikRequest::getString('country', '', 'request');
12637 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12638 $ptodate = VikRequest::getString('todate', '', 'request');
12639 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12640 $clauses = array();
12641 if (count($cid) > 0 && !empty($cid[0])) {
12642 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12643 }
12644 if (!empty($pcountry)) {
12645 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12646 }
12647 $datescol = '`bk`.`ts`';
12648 if ($pdatefilt > 0) {
12649 if ($pdatefilt == 1) {
12650 $datescol = '`bk`.`ts`';
12651 } elseif ($pdatefilt == 2) {
12652 $datescol = '`bk`.`checkin`';
12653 } elseif ($pdatefilt == 3) {
12654 $datescol = '`bk`.`checkout`';
12655 }
12656 }
12657 if (!empty($pfromdate)) {
12658 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12659 $clauses[] = $datescol.">=".$from_ts;
12660 }
12661 if (!empty($ptodate)) {
12662 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12663 $clauses[] = $datescol."<=".$to_ts;
12664 }
12665 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12666 $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`,".
12667 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12668 "`cy`.`country_3_code`,`cy`.`country_name` ".
12669 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12670 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12671 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12672 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12673 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` ".
12674 "ORDER BY `c`.`last_name` ASC;";
12675 $dbo->setQuery($q);
12676 $dbo->execute();
12677 if (!($dbo->getNumRows() > 0)) {
12678 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12679 $mainframe = JFactory::getApplication();
12680 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12681 exit;
12682 }
12683 $customers = $dbo->loadAssocList();
12684 $csvlines = array();
12685 $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'));
12686 if ($ppin > 0) {
12687 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12688 }
12689 if ($pscanimg > 0) {
12690 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12691 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12692 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12693 }
12694 if ($pnotes > 0) {
12695 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12696 }
12697 $csvlines[] = $csvheadline;
12698 foreach ($customers as $customer) {
12699 $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']);
12700 if ($ppin > 0) {
12701 $csvcustomerline[] = $customer['pin'];
12702 }
12703 if ($pscanimg > 0) {
12704 $csvcustomerline[] = $customer['doctype'];
12705 $csvcustomerline[] = $customer['docnum'];
12706 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12707 }
12708 if ($pnotes > 0) {
12709 $csvcustomerline[] = $customer['notes'];
12710 }
12711 $csvlines[] = $csvcustomerline;
12712 }
12713 header("Content-type: text/csv");
12714 header("Cache-Control: no-store, no-cache");
12715 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12716 $outstream = fopen("php://output", 'w');
12717 foreach ($csvlines as $csvline) {
12718 fputcsv($outstream, $csvline);
12719 }
12720 fclose($outstream);
12721 exit;
12722 }
12723
12724 public function renewsession() {
12725 /*
12726 * @wponly
12727 * We just destroy the session
12728 */
12729 JSessionHandler::destroy();
12730 $mainframe = JFactory::getApplication();
12731 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12732 }
12733
12734 public function trackings() {
12735 VikBookingHelper::printHeader("trackings");
12736
12737 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12738
12739 parent::display();
12740
12741 if (VikBooking::showFooter()) {
12742 VikBookingHelper::printFooter();
12743 }
12744 }
12745
12746 public function trkconfig() {
12747 VikBookingHelper::printHeader("trackings");
12748
12749 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12750
12751 parent::display();
12752
12753 if (VikBooking::showFooter()) {
12754 VikBookingHelper::printFooter();
12755 }
12756 }
12757
12758 public function savetrkconfigstay() {
12759 if (!JSession::checkToken()) {
12760 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12761 }
12762 $this->do_savetrkconfig(true);
12763 }
12764
12765 public function savetrkconfig() {
12766 if (!JSession::checkToken()) {
12767 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12768 }
12769 $this->do_savetrkconfig();
12770 }
12771
12772 private function do_savetrkconfig($stay = false) {
12773 $dbo = JFactory::getDBO();
12774 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12775 $trkenabled = $trkenabled == 1 ? 1 : 0;
12776 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12777 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12778 $trkcampname = VikRequest::getVar('trkcampname', array());
12779 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12780 $trkcampval = VikRequest::getVar('trkcampval', array());
12781 $trkcampaigns = array();
12782 foreach ($trkcampname as $k => $v) {
12783 if (empty($trkcampkey[$k])) {
12784 continue;
12785 }
12786 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12787 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12788 $trkcampaigns[$trkcampkey[$k]] = array(
12789 'key' => $trkcampkey[$k],
12790 'value' => $trkcampval[$k],
12791 'name' => $name,
12792 );
12793 }
12794
12795 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12796 $dbo->setQuery($q);
12797 $dbo->execute();
12798 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12799 $dbo->setQuery($q);
12800 $dbo->execute();
12801 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12802 $dbo->setQuery($q);
12803 $dbo->execute();
12804
12805 $mainframe = JFactory::getApplication();
12806 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12807 }
12808
12809 public function modtracking() {
12810 $dbo = JFactory::getDbo();
12811 $cid = VikRequest::getVar('cid', array());
12812 foreach ($cid as $id) {
12813 if (!empty($id)) {
12814 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12815 $dbo->setQuery($q);
12816 $dbo->execute();
12817 if ($dbo->getNumRows()) {
12818 $data = $dbo->loadAssoc();
12819 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12820 $dbo->setQuery($q);
12821 $dbo->execute();
12822 }
12823 }
12824 }
12825 $mainframe = JFactory::getApplication();
12826 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12827 }
12828
12829 public function removetrackings()
12830 {
12831 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
12832 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
12833 }
12834
12835 $ids = VikRequest::getVar('cid', array());
12836 $dbo = JFactory::getDbo();
12837
12838 foreach ($ids as $d) {
12839 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12840 $dbo->setQuery($q);
12841 $dbo->execute();
12842 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12843 $dbo->setQuery($q);
12844 $dbo->execute();
12845 }
12846
12847 $mainframe = JFactory::getApplication();
12848 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12849 }
12850
12851 /**
12852 * Invokes the Tracker class to obtain
12853 * geo information about the IP addresses.
12854 * This task is called via ajax.
12855 *
12856 * @since 1.11
12857 */
12858 public function getgeoinfo() {
12859 $ips = VikRequest::getVar('ips', array());
12860 if (!count($ips)) {
12861 echo 'e4j.error.empty IPs';
12862 exit;
12863 }
12864
12865 // require the Tracker class without instantiating the object
12866 VikBooking::getTracker(true);
12867 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12868
12869 if ($geo_info === false) {
12870 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12871 exit;
12872 }
12873
12874 // update db values and compose response
12875 $dbo = JFactory::getDbo();
12876 $resp = array();
12877 foreach ($geo_info as $id => $geo) {
12878 if (is_null($geo) || $geo === false) {
12879 continue;
12880 }
12881 // compose geo info string
12882 $geovals = array();
12883 if (!empty($geo['city'])) {
12884 array_push($geovals, $geo['city']);
12885 }
12886 if (!empty($geo['region'])) {
12887 array_push($geovals, $geo['region']);
12888 }
12889 $threecode = '';
12890 $cname = '';
12891 if (!empty($geo['country'])) {
12892 // returned country is a 2-char code, get the 3-char country code
12893 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12894 $dbo->setQuery($q);
12895 $dbo->execute();
12896 if ($dbo->getNumRows()) {
12897 $cinfo = $dbo->loadAssoc();
12898 $threecode = $cinfo['country_3_code'];
12899 $cname = $cinfo['country_name'];
12900 }
12901 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12902 }
12903
12904 // full geo information string
12905 $geoinfostr = implode(', ', $geovals);
12906
12907 // push data to the response pool
12908 $resp[$id] = array();
12909 $resp[$id]['geo'] = $geoinfostr;
12910 if (!empty($cname)) {
12911 $resp[$id]['country'] = $cname;
12912 }
12913 if (!empty($threecode)) {
12914 $resp[$id]['country3'] = $threecode;
12915 }
12916
12917 // update main tracking record
12918 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12919 $dbo->setQuery($q);
12920 $dbo->execute();
12921 }
12922
12923 // output the JSON response
12924 echo json_encode($resp);
12925 exit;
12926 }
12927
12928 /**
12929 * Counts the orphan dates for all published rooms
12930 * depending on their restrictions and booked dates.
12931 * By default, the task takes up to 3 months ahead.
12932 * It is possible to filter the request by rooms and months.
12933 * This task should be called via ajax.
12934 *
12935 * @since 1.11
12936 */
12937 public function orphanscount()
12938 {
12939 $dbo = JFactory::getDbo();
12940 $orphans = array();
12941
12942 $nowdf = VikBooking::getDateFormat();
12943 if ($nowdf == "%d/%m/%Y") {
12944 $df = 'd/m/Y';
12945 } elseif ($nowdf == "%m/%d/%Y") {
12946 $df = 'm/d/Y';
12947 } else {
12948 $df = 'Y/m/d';
12949 }
12950
12951 // global min los
12952 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12953 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12954
12955 // rooms and dates
12956 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12957 $months = VikRequest::getInt('months', 3, 'request');
12958 $from = VikRequest::getString('from', '', 'request');
12959 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12960 if (!empty($from)) {
12961 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12962 if (!empty($fromts)) {
12963 // custom starting date
12964 $today = $fromts;
12965 }
12966 }
12967 $until = strtotime("+{$months} months", $today);
12968
12969 // load all rooms
12970 $rooms = array();
12971 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12972 $dbo->setQuery($q);
12973 $dbo->execute();
12974 if ($dbo->getNumRows()) {
12975 $allrooms = $dbo->loadAssocList();
12976 foreach ($allrooms as $r) {
12977 $rooms[$r['id']] = $r;
12978 }
12979 }
12980 if (!count($rooms)) {
12981 // no rooms found, exit
12982 echo json_encode($orphans);
12983 exit;
12984 }
12985
12986 // load availabilities
12987 $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.");";
12988 $dbo->setQuery($q);
12989 $dbo->execute();
12990 if (!$dbo->getNumRows()) {
12991 // no booked dates found, exit
12992 echo json_encode($orphans);
12993 exit;
12994 }
12995 $busy = $dbo->loadAssocList();
12996
12997 // sort booked dates by room id
12998 $rooms_busy = array();
12999 foreach ($busy as $b) {
13000 if (!isset($rooms_busy[$b['idroom']])) {
13001 $rooms_busy[$b['idroom']] = array();
13002 }
13003 array_push($rooms_busy[$b['idroom']], $b);
13004 }
13005
13006 // load restrictions
13007 $rooms_restr = array();
13008 foreach ($rooms as $rid => $r) {
13009 $restrictions = VikBooking::loadRestrictions(true, array($rid));
13010 if (count($restrictions)) {
13011 $rooms_restr[$rid] = $restrictions;
13012 }
13013 }
13014 if (!count($rooms_restr) && $glob_minlos < 2) {
13015 // no restrictions found and minlos=1, exit
13016 echo json_encode($orphans);
13017 exit;
13018 }
13019
13020 // count availability and minlos per day
13021 $rooms_data = array();
13022 foreach ($rooms as $rid => $r) {
13023 $rooms_data[$rid] = array(
13024 'avail' => array(),
13025 'restr' => array()
13026 );
13027 $nowts = getdate($today);
13028 while ($nowts[0] <= $until) {
13029 $dateind = date('Y-m-d', $nowts[0]);
13030
13031 // remaining availability
13032 if (!isset($rooms_busy[$rid])) {
13033 // no bookings for this room, set full availability for this day
13034 $rooms_data[$rid]['avail'][] = array(
13035 'dt' => $dateind,
13036 'units' => $r['units']
13037 );
13038 } else {
13039 // check remaining availability for this day
13040 $totfound = 0;
13041 foreach ($rooms_busy[$rid] as $b) {
13042 $tmpone = getdate($b['checkin']);
13043 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
13044 $ritts = strtotime($rit);
13045 $tmptwo = getdate($b['checkout']);
13046 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
13047 $conts = strtotime($con);
13048 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
13049 $totfound++;
13050 }
13051 }
13052 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
13053 $rooms_data[$rid]['avail'][] = array(
13054 'dt' => $dateind,
13055 'units' => ($r['units'] - $totfound)
13056 );
13057 }
13058
13059 // restrictions
13060 if (!isset($rooms_restr[$rid])) {
13061 // no restrictions for this room, set global minlos for this day
13062 $rooms_data[$rid]['restr'][] = array(
13063 'dt' => $dateind,
13064 'minlos' => $glob_minlos
13065 );
13066 } else {
13067 // get restriction for this day
13068 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
13069 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13070
13071 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
13072 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
13073
13074 $rooms_data[$rid]['restr'][] = array(
13075 'dt' => $dateind,
13076 'minlos' => $minlos
13077 );
13078 }
13079
13080 // next loop
13081 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13082 $nowts = getdate($dayts);
13083 }
13084 }
13085
13086 // week days and months labels
13087 $days_labels = array(
13088 JText::translate('VBSUNDAY'),
13089 JText::translate('VBMONDAY'),
13090 JText::translate('VBTUESDAY'),
13091 JText::translate('VBWEDNESDAY'),
13092 JText::translate('VBTHURSDAY'),
13093 JText::translate('VBFRIDAY'),
13094 JText::translate('VBSATURDAY')
13095 );
13096 $months_labels = array(
13097 JText::translate('VBMONTHONE'),
13098 JText::translate('VBMONTHTWO'),
13099 JText::translate('VBMONTHTHREE'),
13100 JText::translate('VBMONTHFOUR'),
13101 JText::translate('VBMONTHFIVE'),
13102 JText::translate('VBMONTHSIX'),
13103 JText::translate('VBMONTHSEVEN'),
13104 JText::translate('VBMONTHEIGHT'),
13105 JText::translate('VBMONTHNINE'),
13106 JText::translate('VBMONTHTEN'),
13107 JText::translate('VBMONTHELEVEN'),
13108 JText::translate('VBMONTHTWELVE')
13109 );
13110
13111 // orphan dates calculation method
13112 $calc_method = VikBooking::orphansCalculation();
13113
13114 // parse data and build orphans if any
13115 foreach ($rooms_data as $rid => $data) {
13116 foreach ($data['avail'] as $ind => $av) {
13117 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
13118 // continue, no restriction set or no availability for this day
13119 continue;
13120 }
13121 if ($data['restr'][$ind]['minlos'] < 2) {
13122 // continue, no min los > 1 set for this day
13123 continue;
13124 }
13125 // check if any night after today, until min los, is fully booked
13126 $hasorphans = false;
13127 $forward_count = 0;
13128 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
13129 if (!isset($data['avail'][($ind + $i)])) {
13130 // break loop, no info for this day after
13131 break;
13132 }
13133 if ($data['avail'][($ind + $i)]['units'] > 0) {
13134 // continue, availability found for tomorrow, we need a non available next-day
13135 continue;
13136 }
13137 // orphan found
13138 $hasorphans = true;
13139 $forward_count = $i;
13140 break;
13141 }
13142
13143 /**
13144 * Backward calculation method only if "prevnext".
13145 *
13146 * @since 1.3.0
13147 */
13148 $backward_count = 0;
13149 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
13150 if (!isset($data['avail'][($ind - $i)])) {
13151 // break loop, no info for this prev day
13152 break;
13153 }
13154 if ($data['avail'][($ind - $i)]['units'] > 0) {
13155 // increase free nights going backward
13156 $backward_count++;
13157 }
13158 }
13159 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
13160 // this should not be an orphan date because of enough free days back, or enough free days in between
13161 $hasorphans = false;
13162 }
13163 //
13164
13165 if ($hasorphans) {
13166 // 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
13167 if (!isset($orphans[$rid])) {
13168 $orphans[$rid] = array(
13169 'name' => $rooms[$rid]['name'],
13170 'dates' => array(),
13171 'rdates' => array(),
13172 'linkd' => date($df, strtotime($av['dt']))
13173 );
13174 }
13175 array_push($orphans[$rid]['dates'], $av['dt']);
13176 // build the value for the readable date
13177 $dtinfo = getdate(strtotime($av['dt']));
13178 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
13179 array_push($orphans[$rid]['rdates'], $rdate);
13180 }
13181 }
13182 }
13183
13184 // output response
13185 echo json_encode($orphans);
13186 exit;
13187 }
13188
13189 public function tableaux() {
13190 VikBookingHelper::printHeader("tableaux");
13191
13192 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
13193
13194 parent::display();
13195
13196 if (VikBooking::showFooter()) {
13197 VikBookingHelper::printFooter();
13198 }
13199 }
13200
13201 public function operators() {
13202 VikBookingHelper::printHeader("operators");
13203
13204 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
13205
13206 parent::display();
13207
13208 if (VikBooking::showFooter()) {
13209 VikBookingHelper::printFooter();
13210 }
13211 }
13212
13213 public function newoperator() {
13214 VikBookingHelper::printHeader("operators");
13215
13216 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13217
13218 parent::display();
13219
13220 if (VikBooking::showFooter()) {
13221 VikBookingHelper::printFooter();
13222 }
13223 }
13224
13225 public function editoperator() {
13226 VikBookingHelper::printHeader("operators");
13227
13228 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13229
13230 parent::display();
13231
13232 if (VikBooking::showFooter()) {
13233 VikBookingHelper::printFooter();
13234 }
13235 }
13236
13237 public function updateoperator()
13238 {
13239 if (!JSession::checkToken()) {
13240 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13241 }
13242
13243 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13244 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13245 }
13246
13247 $this->do_updateoperator();
13248 }
13249
13250 public function updateoperatorstay()
13251 {
13252 if (!JSession::checkToken()) {
13253 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13254 }
13255
13256 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13257 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13258 }
13259
13260 $this->do_updateoperator(true);
13261 }
13262
13263 private function do_updateoperator($stay = false)
13264 {
13265 $dbo = JFactory::getDbo();
13266 $app = JFactory::getApplication();
13267 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13268 $plast_name = VikRequest::getString('last_name', '', 'request');
13269 $pemail = VikRequest::getString('email', '', 'request');
13270 $pphone = VikRequest::getString('phone', '', 'request');
13271 $pcode = VikRequest::getString('code', '', 'request');
13272 $pujid = VikRequest::getInt('ujid', '', 'request');
13273 $pwhere = VikRequest::getInt('where', '', 'request');
13274
13275 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
13276 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
13277 $dbo->setQuery($q);
13278 $customer = $dbo->loadAssoc();
13279 if (!$customer) {
13280 $app->redirect("index.php?option=com_vikbooking&task=operators");
13281 exit;
13282 }
13283
13284 $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;";
13285 $dbo->setQuery($q);
13286 $ex_operator = $dbo->loadAssoc();
13287 if (!$ex_operator) {
13288 // update fingerprint for the operator
13289 $fingpt = md5($pwhere . $pemail);
13290
13291 /**
13292 * Operator profile picture (URL or uploaded file).
13293 *
13294 * @since 1.16.9 (J) - 1.6.9 (WP)
13295 */
13296 $operator_pic = VikRequest::getString('pic', '', 'request');
13297 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13298 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13299 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13300 $src = $operator_pic_img['tmp_name'];
13301 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13302 $j = "";
13303 if (is_file($dest.$filename)) {
13304 $j = rand(1, 99999);
13305 while (is_file($dest . $j .$filename)) {
13306 $j++;
13307 }
13308 }
13309 $finaldest = $dest . $j . $filename;
13310 $check = getimagesize($operator_pic_img['tmp_name']);
13311 if (($check[2] & imagetypes())) {
13312 if (VikBooking::uploadFile($src, $finaldest)) {
13313 $operator_pic = $j . $filename;
13314 } else {
13315 VikError::raiseWarning('', 'Error while uploading image');
13316 }
13317 } else {
13318 VikError::raiseWarning('', 'Uploaded file is not an Image');
13319 }
13320 }
13321
13322 // update record
13323 $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;
13324 $dbo->setQuery($q);
13325 $dbo->execute();
13326 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13327 } else {
13328 //email already exists
13329 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>');
13330 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13331 exit;
13332 }
13333 } else {
13334 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13335 }
13336
13337 if ($stay) {
13338 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13339 } else {
13340 $app->redirect("index.php?option=com_vikbooking&task=operators");
13341 }
13342
13343 $app->close();
13344 }
13345
13346 public function saveoperator()
13347 {
13348 if (!JSession::checkToken()) {
13349 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13350 }
13351
13352 $dbo = JFactory::getDbo();
13353 $app = JFactory::getApplication();
13354 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13355 $plast_name = VikRequest::getString('last_name', '', 'request');
13356 $pemail = VikRequest::getString('email', '', 'request');
13357 $pphone = VikRequest::getString('phone', '', 'request');
13358 $pcode = VikRequest::getString('code', '', 'request');
13359 $pujid = VikRequest::getInt('ujid', '', 'request');
13360
13361 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
13362 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
13363 $dbo->setQuery($q);
13364 $ex_operator = $dbo->loadAssoc();
13365 if (!$ex_operator) {
13366 /**
13367 * Operator profile picture (URL or uploaded file).
13368 *
13369 * @since 1.16.9 (J) - 1.6.9 (WP)
13370 */
13371 $operator_pic = VikRequest::getString('pic', '', 'request');
13372 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13373 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13374 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13375 $src = $operator_pic_img['tmp_name'];
13376 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13377 $j = "";
13378 if (is_file($dest.$filename)) {
13379 $j = rand(1, 99999);
13380 while (is_file($dest . $j .$filename)) {
13381 $j++;
13382 }
13383 }
13384 $finaldest = $dest . $j . $filename;
13385 $check = getimagesize($operator_pic_img['tmp_name']);
13386 if (($check[2] & imagetypes())) {
13387 if (VikBooking::uploadFile($src, $finaldest)) {
13388 $operator_pic = $j . $filename;
13389 } else {
13390 VikError::raiseWarning('', 'Error while uploading image');
13391 }
13392 } else {
13393 VikError::raiseWarning('', 'Uploaded file is not an Image');
13394 }
13395 }
13396
13397 $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) . ");";
13398 $dbo->setQuery($q);
13399 $dbo->execute();
13400 $lid = $dbo->insertid();
13401 if (!empty($lid)) {
13402 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13403 // generate fingerprint for the operator
13404 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->q(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
13405 $dbo->setQuery($q);
13406 $dbo->execute();
13407 }
13408 } else {
13409 // email already exists
13410 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>');
13411 }
13412 } else {
13413 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13414 }
13415
13416 $app->redirect("index.php?option=com_vikbooking&task=operators");
13417 $app->close();
13418 }
13419
13420 public function removeoperators()
13421 {
13422 if (!JSession::checkToken()) {
13423 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13424 }
13425
13426 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13427 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13428 }
13429
13430 $ids = VikRequest::getVar('cid', array(0));
13431 if ($ids) {
13432 $dbo = JFactory::getDBO();
13433 foreach ($ids as $d) {
13434 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
13435 $dbo->setQuery($q);
13436 $dbo->execute();
13437 }
13438 }
13439 $mainframe = JFactory::getApplication();
13440 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13441 }
13442
13443 public function canceloperator() {
13444 $mainframe = JFactory::getApplication();
13445 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13446 }
13447
13448 public function cancelcrons() {
13449 $mainframe = JFactory::getApplication();
13450 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
13451 }
13452
13453 public function cancelpackages() {
13454 $mainframe = JFactory::getApplication();
13455 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
13456 }
13457
13458 public function cancelcustomer() {
13459 $mainframe = JFactory::getApplication();
13460 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13461 if (!empty($pgoto)) {
13462 $mainframe->redirect(base64_decode($pgoto));
13463 exit;
13464 }
13465 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
13466 }
13467
13468 public function cancelbusyvcm() {
13469 $mainframe = JFactory::getApplication();
13470 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
13471 }
13472
13473 public function cancelrestriction() {
13474 $mainframe = JFactory::getApplication();
13475 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
13476 }
13477
13478 public function cancelcoupon() {
13479 $mainframe = JFactory::getApplication();
13480 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
13481 }
13482
13483 public function cancelcustomf() {
13484 $mainframe = JFactory::getApplication();
13485 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
13486 }
13487
13488 public function cancelpayment() {
13489 $mainframe = JFactory::getApplication();
13490 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
13491 }
13492
13493 public function cancelseason() {
13494 $mainframe = JFactory::getApplication();
13495 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
13496 }
13497
13498 public function goconfig() {
13499 $mainframe = JFactory::getApplication();
13500 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
13501 }
13502
13503 public function canceledorder() {
13504 $pgoto = VikRequest::getString('goto', 'orders', 'request');
13505 $mainframe = JFactory::getApplication();
13506 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
13507 }
13508
13509 public function cancelbusy() {
13510 $pidorder = VikRequest::getString('idorder', '', 'request');
13511 $pgoto = VikRequest::getString('goto', '', 'request');
13512 $mainframe = JFactory::getApplication();
13513 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
13514 }
13515
13516 public function canceloverv() {
13517 $mainframe = JFactory::getApplication();
13518 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
13519 }
13520
13521 public function canceltableaux() {
13522 $mainframe = JFactory::getApplication();
13523 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
13524 }
13525
13526 public function cancelcalendar() {
13527 $pidroom = VikRequest::getString('idroom', '', 'request');
13528 $mainframe = JFactory::getApplication();
13529 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
13530 }
13531
13532 public function canceloptionals() {
13533 $mainframe = JFactory::getApplication();
13534 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
13535 }
13536
13537 public function cancel() {
13538 $mainframe = JFactory::getApplication();
13539 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
13540 }
13541
13542 public function cancelcarat() {
13543 $mainframe = JFactory::getApplication();
13544 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
13545 }
13546
13547 public function cancelcat() {
13548 $mainframe = JFactory::getApplication();
13549 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
13550 }
13551
13552 public function cancelprice() {
13553 $mainframe = JFactory::getApplication();
13554 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
13555 }
13556
13557 public function canceliva() {
13558 $mainframe = JFactory::getApplication();
13559 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
13560 }
13561
13562 public function canceltrk() {
13563 $mainframe = JFactory::getApplication();
13564 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13565 }
13566
13567 public function canceldash() {
13568 $mainframe = JFactory::getApplication();
13569 $mainframe->redirect("index.php?option=com_vikbooking");
13570 }
13571
13572 public function cancelinvoice() {
13573 $mainframe = JFactory::getApplication();
13574 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13575 if (!empty($pgoto)) {
13576 $mainframe->redirect(base64_decode($pgoto));
13577 exit;
13578 }
13579 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
13580 }
13581
13582 /**
13583 * AJAX upload the customer documents.
13584 *
13585 * @return void
13586 *
13587 * @throws Exception
13588 */
13589 public function upload_customer_document()
13590 {
13591 $input = JFactory::getApplication()->input;
13592 $dbo = JFactory::getDbo();
13593
13594 $customer_id = $input->getUint('customer', 0);
13595
13596 $result = new stdClass;
13597 $result->status = 0;
13598
13599 try
13600 {
13601 $q = $dbo->getQuery(true)
13602 ->select($dbo->qn(array(
13603 'id',
13604 'first_name',
13605 'last_name',
13606 'email',
13607 'docsfolder',
13608 )))
13609 ->from($dbo->qn('#__vikbooking_customers'))
13610 ->where($dbo->qn('id') . ' = ' . $customer_id);
13611
13612 $dbo->setQuery($q, 0, 1);
13613 $dbo->execute();
13614
13615 if (!$dbo->getNumRows())
13616 {
13617 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13618 }
13619
13620 $customer = $dbo->loadObject();
13621
13622 // fetch documents folder path
13623 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13624
13625 // check if we have a valid directory
13626 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
13627 {
13628 // randomize string
13629 $customer->seed = uniqid();
13630
13631 // create blocks for hashed folder
13632 $parts = [
13633 $customer->first_name,
13634 $customer->last_name,
13635 md5(serialize($customer)),
13636 ];
13637
13638 // join fetched parts
13639 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13640
13641 if (strlen($customer->docsfolder) < 16)
13642 {
13643 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13644 }
13645
13646 jimport('joomla.filesystem.folder');
13647
13648 // create a folder for this customer
13649 $created = JFolder::create($dirpath . $customer->docsfolder);
13650
13651 if (!$created)
13652 {
13653 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13654 }
13655
13656 unset($customer->seed);
13657
13658 // update docs folder
13659 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13660 }
13661
13662 // get file from request
13663 $file = $input->files->get('file', array(), 'array');
13664
13665 // try to upload the file
13666 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13667 $result->status = 1;
13668
13669 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13670 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13671 }
13672 catch (Exception $e)
13673 {
13674 $result->error = $e->getMessage();
13675 $result->code = $e->getCode();
13676 }
13677
13678 echo json_encode($result);
13679 exit;
13680 }
13681
13682 /**
13683 * AJAX delete the customer documents.
13684 *
13685 * @return void
13686 *
13687 * @throws Exception
13688 */
13689 public function delete_customer_document()
13690 {
13691 $input = JFactory::getApplication()->input;
13692 $dbo = JFactory::getDbo();
13693
13694 $customer_id = $input->getUint('customer', 0);
13695
13696 $result = new stdClass;
13697 $result->status = 0;
13698
13699 $q = $dbo->getQuery(true)
13700 ->select($dbo->qn('docsfolder'))
13701 ->from($dbo->qn('#__vikbooking_customers'))
13702 ->where($dbo->qn('id') . ' = ' . $customer_id);
13703
13704 $dbo->setQuery($q, 0, 1);
13705 $dbo->execute();
13706
13707 if (!$dbo->getNumRows())
13708 {
13709 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13710 }
13711
13712 $folder = $dbo->loadResult();
13713
13714 if (!$folder)
13715 {
13716 throw new Exception('The customer does not have any documents', 500);
13717 }
13718
13719 $file = $input->getString('file');
13720
13721 if (!$file)
13722 {
13723 throw new Exception('File to remove not specified', 400);
13724 }
13725
13726 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13727
13728 if (!is_file($path))
13729 {
13730 throw new Exception(sprintf('File [%s] not found', $path), 404);
13731 }
13732
13733 jimport('joomla.filesystem.file');
13734
13735 $removed = JFile::delete($path);
13736
13737 echo json_encode(array('status' => (int) $removed));
13738 exit;
13739 }
13740
13741 /**
13742 * AJAX task to invoke a specific report and obtain information.
13743 *
13744 * @since 1.3.0
13745 */
13746 public function get_report_data()
13747 {
13748 $report_name = VikRequest::getString('report_name', '', 'request');
13749 $current_fest = VikRequest::getString('current_fest', '', 'request');
13750 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13751 $current_todate = VikRequest::getString('current_todate', '', 'request');
13752 $step = VikRequest::getString('step', 'weekend', 'request');
13753 $direction = VikRequest::getString('direction', 'load', 'request');
13754 $period = VikRequest::getString('period', 'full', 'request');
13755 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13756 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13757 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13758 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13759 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13760 // idroom can be an array of IDs or just one ID as int/string
13761 $idroom = VikRequest::getVar('idroom', null, 'request');
13762 //
13763
13764 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13765 throw new Exception("Missing request data", 400);
13766 }
13767
13768 // get requested report instance
13769 $report = VikBooking::getReportInstance($report_name);
13770 if (!$report) {
13771 throw new Exception("Report not found", 404);
13772 }
13773
13774 // chart data
13775 if (empty($chart_datatype)) {
13776 $chart_datatype = array(
13777 'type' => 'doughnut',
13778 'depth' => 1,
13779 'keys' => array($krsort),
13780 );
13781 }
13782
13783 // website date format
13784 $df = $report->getDateFormat();
13785
13786 // prepare request params for the report
13787 $rparams = array(
13788 'fromdate' => $current_fromdate,
13789 'todate' => $current_todate,
13790 'period' => $period,
13791 'krsort' => $krsort,
13792 'krorder' => $krorder,
13793 'idroom' => $idroom,
13794 );
13795
13796 // starting dates info and timestamps
13797 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13798 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13799 $from_info = getdate($from_ts);
13800 $to_info = getdate($to_ts);
13801
13802 // the name of the period requested and whether it's a fest
13803 $period_name = '';
13804 $is_fest = null;
13805
13806 if ($direction == 'prev' || $direction == 'next') {
13807 // calculate prev or next dates
13808 if ($step == 'weekend') {
13809 $period_name = JText::translate('VBOWEEKND');
13810 if ($direction == 'next') {
13811 // next weekend from current end date
13812 $next_ts = strtotime("next friday", $to_ts);
13813 } else {
13814 // prev weekend from current start date
13815 $next_ts = strtotime("previous friday", $from_ts);
13816 }
13817 $next_info = getdate($next_ts);
13818 $new_from_ts = $next_ts;
13819 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13820 $rparams['fromdate'] = date($df, $new_from_ts);
13821 $rparams['todate'] = date($df, $new_to_ts);
13822 } elseif ($step == 'week') {
13823 $period_name = JText::translate('VBOWEEK');
13824 if ($direction == 'next') {
13825 // start next week from the current end date
13826 $new_from_ts = $to_ts;
13827 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13828 $rparams['fromdate'] = $rparams['todate'];
13829 $rparams['todate'] = date($df, $new_to_ts);
13830 } else {
13831 // end prev week from the current from date
13832 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13833 $new_to_ts = $from_ts;
13834 $rparams['todate'] = $rparams['fromdate'];
13835 $rparams['fromdate'] = date($df, $new_from_ts);
13836 }
13837 } else {
13838 // month
13839 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13840 if ($direction == 'next') {
13841 // next month from the current from date
13842 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13843 $new_from_ts = $nextmonts;
13844 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13845 $rparams['fromdate'] = date($df, $new_from_ts);
13846 $rparams['todate'] = date($df, $new_to_ts);
13847 } else {
13848 // prev month from the current from date
13849 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13850 $new_from_ts = $nextmonts;
13851 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13852 $rparams['fromdate'] = date($df, $new_from_ts);
13853 $rparams['todate'] = date($df, $new_to_ts);
13854 }
13855 }
13856
13857 // get the next festivities
13858 $fests = VikBooking::getFestivitiesInstance();
13859 $next_fests = $fests->loadFestDates();
13860 if (count($next_fests)) {
13861 // check whether a festivity should be displayed rather than the calculated period of dates
13862 foreach ($next_fests as $fest) {
13863 $fest_found = false;
13864 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13865 $fest_found = true;
13866 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13867 $fest_found = true;
13868 }
13869 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13870 // festivity found before next calculated period
13871 $is_fest = $fest['festinfo'][0]->next_ts;
13872 $period_name = $fest['festinfo'][0]->trans_name;
13873 $new_from_ts = $fest['festinfo'][0]->from_ts;
13874 $new_to_ts = $fest['festinfo'][0]->to_ts;
13875 $rparams['fromdate'] = date($df, $new_from_ts);
13876 $rparams['todate'] = date($df, $new_to_ts);
13877 break;
13878 }
13879 }
13880 }
13881 } else {
13882 // load requested dates by skipping the festivities
13883 $new_from_ts = $from_ts;
13884 $new_to_ts = $to_ts;
13885 }
13886
13887 // invoke report
13888 $report->injectParams($rparams);
13889 $report_values = $report->getReportValues(1);
13890 $report_cols = $report->getColumnsValues();
13891 $report_chart = null;
13892 $report_chart_metas = array();
13893 $chart_meta_data = array(
13894 'keys' => array(
13895 'occupancy',
13896 'tot_bookings',
13897 'nights_booked',
13898 ),
13899 );
13900 $error = null;
13901
13902 if (!count($report_values)) {
13903 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13904 } else {
13905 // get doughnut Chart for the requested key
13906 $report_chart = $report->getChart($chart_datatype);
13907
13908 // get Chart meta data
13909 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13910 if (count($all_chart_metas)) {
13911 // merge all positions into one array
13912 foreach ($all_chart_metas as $pos_metas) {
13913 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13914 }
13915 }
13916
13917 if (empty($period_name)) {
13918 $period_name = $report->getProperty('chartTitle');
13919 }
13920 }
13921
13922 // build response
13923 $response = new stdClass;
13924 $response->error = $error;
13925 $response->fromdate = $rparams['fromdate'];
13926 $response->todate = $rparams['todate'];
13927 $response->in_days = $report->countDaysTo($new_from_ts);
13928 $response->in_days_to = $report->countDaysTo($new_to_ts);
13929 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13930 $response->period_name = $period_name;
13931 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13932 $response->is_fest = $is_fest;
13933 $response->report_chart = $report_chart;
13934 $response->report_cols = $report_cols;
13935 $response->report_values = $report_values;
13936 $response->report_script = $report->getScript();
13937 $response->chart_labels = $report->getProperty('chartJsLabels');
13938 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13939 $response->chart_colors = $report->getProperty('chartJsColors');
13940 $response->chart_data = $report->getProperty('chartJsData');
13941 $response->report_chart_metas = $report_chart_metas;
13942
13943 echo json_encode($response);
13944 exit;
13945 }
13946
13947 /**
13948 * Go to the previous booking.
13949 *
13950 * @uses navigateToBooking()
13951 *
13952 * @since 1.3.0
13953 */
13954 public function prev_booking()
13955 {
13956 $this->navigateToBooking('prev');
13957 }
13958
13959 /**
13960 * Go to the next booking.
13961 *
13962 * @uses navigateToBooking()
13963 *
13964 * @since 1.3.0
13965 */
13966 public function next_booking()
13967 {
13968 $this->navigateToBooking('next');
13969 }
13970
13971 /**
13972 * Given the current booking ID in the request, we navigate
13973 * either to the next or to the previous reservation (if any).
13974 *
13975 * @param string $direction either next or prev.
13976 *
13977 * @return void
13978 *
13979 * @since 1.3.0
13980 */
13981 private function navigateToBooking($direction = 'next')
13982 {
13983 $bid = VikRequest::getInt('whereup', 0, 'request');
13984 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13985 throw new Exception("Invalid request", 400);
13986 }
13987
13988 $dbo = JFactory::getDbo();
13989 $app = JFactory::getApplication();
13990
13991 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13992 $dbo->setQuery($q, 0, 1);
13993 $dbo->execute();
13994 if (!$dbo->getNumRows()) {
13995 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13996 $app->redirect("index.php?option=com_vikbooking&task=orders");
13997 exit;
13998 }
13999
14000 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
14001 exit;
14002 }
14003
14004 /**
14005 * AJAX request: from a list of reservation IDs, we return the ones
14006 * that have a review with the related review ID on VCM.
14007 *
14008 * @since 1.13
14009 */
14010 public function bookings_have_reviews()
14011 {
14012 if (!JSession::checkToken()) {
14013 // missing CSRF-proof token
14014 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14015 }
14016
14017 $dbo = JFactory::getDbo();
14018
14019 $bids = VikRequest::getVar('bids', [], 'request', 'array');
14020 $vcm_installed = class_exists('VikChannelManager');
14021 $withreviews = [];
14022
14023 if ($vcm_installed && $bids) {
14024 $bids = array_filter(array_map('intval', (array) $bids));
14025 $bids = $bids ?: [0];
14026
14027 try {
14028 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
14029 $dbo->setQuery($q);
14030 $reviews = $dbo->loadAssocList();
14031
14032 foreach ($reviews as $r) {
14033 $withreviews[$r['idorder']] = $r['id'];
14034 }
14035 } catch (Exception $e) {
14036 // do nothing, outdated version
14037 }
14038 }
14039
14040 // output list of booking IDs found, if any
14041 VBOHttpDocument::getInstance()->json($withreviews);
14042 }
14043
14044 /**
14045 * AJAX request for adding a new room-day note.
14046 *
14047 * @return void
14048 *
14049 * @since 1.13.5
14050 */
14051 public function add_roomdaynote()
14052 {
14053 $dt = VikRequest::getString('dt', '', 'request');
14054 $idroom = VikRequest::getInt('idroom', 0, 'request');
14055 $subunit = VikRequest::getInt('subunit', 0, 'request');
14056 $type = VikRequest::getString('type', '', 'request');
14057 $type = empty($type) ? 'custom' : $type;
14058 $name = VikRequest::getString('name', '', 'request');
14059 $descr = VikRequest::getString('descr', '', 'request');
14060 $cdays = VikRequest::getInt('cdays', 0, 'request');
14061 $cdays = $cdays < 0 ? 0 : $cdays;
14062 $cdays = $cdays > 365 ? 365 : $cdays;
14063 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
14064 echo 'e4j.error.1';
14065 exit;
14066 }
14067
14068 // reload end date
14069 $end_date = $dt;
14070
14071 // build critical date object
14072 $new_note = array(
14073 'name' => $name,
14074 'type' => $type,
14075 'descr' => $descr,
14076 );
14077
14078 // get object
14079 $notes = VikBooking::getCriticalDatesInstance();
14080
14081 // store the notes for all consecutive dates
14082 for ($i = 0; $i <= $cdays; $i++) {
14083 $store_dt = $dt;
14084 if ($i > 0) {
14085 $dt_info = getdate(strtotime($store_dt));
14086 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
14087 $end_date = $store_dt;
14088 }
14089 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
14090 if (!$result) {
14091 echo 'e4j.error.2';
14092 exit;
14093 }
14094 }
14095
14096 // reload all room day notes for this day for the AJAX response
14097 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
14098
14099 if (!$all_notes || !count($all_notes)) {
14100 // no notes found even after storing it
14101 echo 'e4j.error.3';
14102 exit;
14103 }
14104
14105 echo json_encode($all_notes);
14106 exit;
14107 }
14108
14109 /**
14110 * AJAX request for removing a room day note.
14111 *
14112 * @return void
14113 *
14114 * @since 1.13.5
14115 */
14116 public function remove_roomdaynote()
14117 {
14118 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14119 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14120 }
14121
14122 $dt = VikRequest::getString('dt', '', 'request');
14123 $idroom = VikRequest::getInt('idroom', 0, 'request');
14124 $subunit = VikRequest::getInt('subunit', 0, 'request');
14125 $type = VikRequest::getString('type', '', 'request');
14126 $type = empty($type) ? 'custom' : $type;
14127 $ind = VikRequest::getInt('ind', 0, 'request');
14128 if (empty($dt) || !strtotime($dt)) {
14129 echo 'e4j.error.1';
14130 exit;
14131 }
14132
14133 $notes = VikBooking::getCriticalDatesInstance();
14134 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
14135 if (!$result) {
14136 echo 'e4j.error.2';
14137 exit;
14138 }
14139
14140 echo 'e4j.ok';
14141 exit;
14142 }
14143
14144 /**
14145 * AJAX request for storing an event for a booking.
14146 * Firstly developed for the VCM Reporting API - Guest Misconduct,
14147 * but it can be used for any other purpose.
14148 *
14149 * @return void
14150 *
14151 * @since 1.13.5
14152 */
14153 public function store_booking_history_event()
14154 {
14155 $bid = VikRequest::getInt('bid', 0, 'request');
14156 $event = VikRequest::getString('event', '', 'request');
14157 $descr = VikRequest::getString('descr', '', 'request');
14158
14159 if (empty($bid) || empty($event)) {
14160 throw new Exception("Missing required information", 500);
14161 }
14162
14163 // Booking History
14164 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
14165 //
14166
14167 echo 'e4j.ok';
14168 exit;
14169 }
14170
14171 /**
14172 * AJAX request for updating an option/extra service.
14173 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
14174 * but it can be used for any other purpose.
14175 *
14176 * @return void
14177 *
14178 * @since 1.13.5
14179 */
14180 public function update_option_params()
14181 {
14182 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14183 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14184 }
14185
14186 $optid = VikRequest::getInt('optid', 0, 'request');
14187 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
14188
14189 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
14190 throw new Exception("Missing required information", 500);
14191 }
14192
14193 $dbo = JFactory::getDbo();
14194 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
14195 $dbo->setQuery($q);
14196 $dbo->execute();
14197 if (!$dbo->getNumRows()) {
14198 throw new Exception("Option not found", 404);
14199 }
14200 $cur_params = $dbo->loadResult();
14201 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
14202 $cur_params = !is_array($cur_params) ? array() : $cur_params;
14203
14204 foreach ($oparams as $k => $v) {
14205 if (empty($k)) {
14206 continue;
14207 }
14208 $cur_params[$k] = $v;
14209 }
14210
14211 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
14212 $dbo->setQuery($q);
14213 $dbo->execute();
14214
14215 echo 'e4j.ok';
14216 exit;
14217 }
14218
14219 /**
14220 * Hidden task to clean up duplicate records in certain database tables
14221 * due to a double execution of the installation queries. Ghost records,
14222 * if any, are also removed to clean up issues with hanging records.
14223 *
14224 * @since November 4th 2020
14225 * @since 1.16.3 (J) - 1.6.3 (WP)
14226 */
14227 public function clean_duplicate_records()
14228 {
14229 $dbo = JFactory::getDbo();
14230
14231 $tables_with_duplicates = [
14232 '#__vikbooking_config' => [
14233 'id_key' => 'id',
14234 'compare_key' => 'param',
14235 ],
14236 '#__vikbooking_countries' => [
14237 'id_key' => 'id',
14238 'compare_key' => 'country_3_code',
14239 ],
14240 '#__vikbooking_custfields' => [
14241 'id_key' => 'id',
14242 'compare_key' => 'name',
14243 ],
14244 '#__vikbooking_texts' => [
14245 'id_key' => 'id',
14246 'compare_key' => 'param',
14247 ],
14248 ];
14249
14250 foreach ($tables_with_duplicates as $tblname => $data) {
14251 $doubles = [];
14252 $storage = [];
14253 $rmlist = [];
14254
14255 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
14256 $dbo->setQuery($q);
14257 $rows = $dbo->loadAssocList();
14258 if (!$rows) {
14259 echo "<p>No records found in table {$tblname}</p>";
14260 continue;
14261 }
14262
14263 foreach ($rows as $row) {
14264 if (!isset($doubles[$row[$data['compare_key']]])) {
14265 $doubles[$row[$data['compare_key']]] = 0;
14266 }
14267 $doubles[$row[$data['compare_key']]]++;
14268 if (!isset($storage[$row[$data['compare_key']]])) {
14269 $storage[$row[$data['compare_key']]] = [];
14270 }
14271 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
14272 }
14273
14274 foreach ($doubles as $paramkey => $paramcount) {
14275 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
14276 continue;
14277 }
14278 $exceeding = $paramcount - 1;
14279 for ($x = 0; $x < $exceeding; $x++) {
14280 array_push($rmlist, $storage[$paramkey][$x]);
14281 }
14282 }
14283
14284 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
14285 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
14286 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
14287
14288 if (count($rmlist)) {
14289 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
14290 $dbo->setQuery($q);
14291 $dbo->execute();
14292 }
14293 }
14294
14295 /**
14296 * Clean up busy records where the busy relations contain empty booking IDs.
14297 */
14298 $hanging_busy_ids = [];
14299
14300 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
14301 $dbo->setQuery($q);
14302 $removelist = $dbo->loadAssocList();
14303 if ($removelist) {
14304 foreach ($removelist as $hanging_busy) {
14305 $hanging_busy_id = (int)$hanging_busy['idbusy'];
14306 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14307 array_push($hanging_busy_ids, $hanging_busy_id);
14308 }
14309 }
14310 }
14311
14312 // let's check also for ghost records that only occupy the room
14313 $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);";
14314 $dbo->setQuery($q);
14315 $removelist = $dbo->loadAssocList();
14316 if ($removelist) {
14317 foreach ($removelist as $hanging_busy) {
14318 $hanging_busy_id = (int)$hanging_busy['id'];
14319 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14320 array_push($hanging_busy_ids, $hanging_busy_id);
14321 }
14322 }
14323 }
14324
14325 if ($hanging_busy_ids) {
14326 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
14327 $dbo->setQuery($q);
14328 $dbo->execute();
14329 }
14330
14331 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
14332
14333 return;
14334 }
14335
14336 /**
14337 * Hidden task to scan all database tables of VikBooking and Vik Channel Manager
14338 * to ensure the column `id` is defined as a primary key and got an auto-increment
14339 * extra flag properly defined and set. We've noticed that some third-party plugins
14340 * used to migrate WP sites may break the primary keys, and so new records won't get an ID.
14341 *
14342 * @since 1.16.8 (J) - 1.6.8 (WP)
14343 */
14344 public function fix_autoincrement_tables()
14345 {
14346 $dbo = JFactory::getDbo();
14347
14348 // load all the installed database tables
14349 $tables = $dbo->getTableList();
14350
14351 // get current database prefix
14352 $prefix = $dbo->getPrefix();
14353
14354 // replace prefix with placeholder
14355 $tables = array_map(function($table) use ($prefix)
14356 {
14357 return preg_replace("/^{$prefix}/", '#__', $table);
14358 }, $tables);
14359
14360 // remove all the tables that do not belong to VikBooking/VCM
14361 $tables = array_values(array_filter($tables, function($table)
14362 {
14363 if (preg_match("/^#__vik(?:booking|channelmanager)_config$/", $table))
14364 {
14365 // exclude the configuration table, which will be handled in a different way
14366 return false;
14367 }
14368
14369 return preg_match("/^#__vik(?:booking|channelmanager)_/", $table);
14370 }));
14371
14372 foreach ($tables as $table) {
14373 $columns = $dbo->getTableColumns($table, false);
14374 if (!isset($columns['id']) || empty($columns['id']->Type) || !empty($columns['id']->Extra)) {
14375 continue;
14376 }
14377
14378 echo 'Fixing ' . $table. ' for missing auto-increment<br/><pre>' . print_r($columns['id'], true) . '</pre><br/>';
14379
14380 // set auto-increment and primary key
14381 $dbo->setQuery("ALTER TABLE `{$table}` MODIFY `id` " . $columns['id']->Type . " NOT NULL AUTO_INCREMENT PRIMARY KEY;");
14382 $dbo->execute();
14383
14384 // count next auto-increment
14385 $dbo->setQuery("SELECT MAX(`id`) FROM `{$table}`");
14386 $next_ai = (int) $dbo->loadResult() + 1;
14387
14388 // update next auto-increment value
14389 $dbo->setQuery("ALTER TABLE `{$table}` AUTO_INCREMENT = {$next_ai}");
14390 $dbo->execute();
14391 }
14392 }
14393
14394 /**
14395 * Loads a specific admin widget ID and executes the requested method.
14396 * Useful for loading a newly added widget, or to execute custom methods.
14397 *
14398 * @see this is an AJAX endpoint.
14399 *
14400 * @since 1.14 (J) - 1.4.0 (WP)
14401 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
14402 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14403 */
14404 public function exec_admin_widget()
14405 {
14406 if (!JSession::checkToken()) {
14407 // missing CSRF-proof token
14408 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14409 }
14410
14411 $widget_id = VikRequest::getString('widget_id', '', 'request');
14412 $call = VikRequest::getString('call', '', 'request');
14413 $return = VikRequest::getInt('return', 0, 'request');
14414 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
14415 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
14416 $multitask = VikRequest::getInt('multitask', 0, 'request');
14417
14418 if (empty($widget_id)) {
14419 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
14420 }
14421
14422 if (empty($call) || !is_string($call)) {
14423 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14424 }
14425
14426 // invoke admin widgets helper
14427 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14428 $widget = $widgets_helper->getWidget($widget_id);
14429
14430 if ($widget === false) {
14431 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
14432 }
14433
14434 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
14435 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
14436 }
14437
14438 // get the multitask parser object
14439 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
14440
14441 // check if arguments should be passed
14442 $call_args = [];
14443 if ($multitask && $call === 'render') {
14444 // build the multitask data object and inject it to the args as the first index
14445 $call_args[] = $parser->getData();
14446
14447 // bind options within the widget, if any
14448 $widget->bindOptions($call_args[0]);
14449 } else {
14450 // always bind multitask options, if any
14451 $widget->bindOptions($parser->getOptions());
14452 }
14453
14454 try {
14455 if ($return) {
14456 // invoke the widget's method and get the value returned
14457 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
14458 } else {
14459 // invoke the widget's method within a buffer
14460 ob_start();
14461 if ($call_args) {
14462 $res = call_user_func_array([$widget, $call], $call_args);
14463 } else {
14464 $widget->{$call}();
14465 }
14466 $widget_response = ob_get_contents();
14467 ob_end_clean();
14468 }
14469 } catch (Throwable $e) {
14470 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14471 } catch (Exception $e) {
14472 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14473 }
14474
14475 // prepare response object with a property equal to the called method
14476 $response = new stdClass;
14477 $response->{$call} = $widget_response;
14478
14479 // output the JSON encoded response and exit
14480 VBOHttpDocument::getInstance()->json($response);
14481 }
14482
14483 /**
14484 * Updates the map of admin widgets.
14485 *
14486 * @throws Exception this is an AJAX endpoint.
14487 *
14488 * @since 1.4.0
14489 */
14490 public function save_admin_widgets()
14491 {
14492 if (!JSession::checkToken()) {
14493 // missing CSRF-proof token
14494 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14495 }
14496
14497 // make sure permissions are sufficient
14498 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
14499 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
14500 }
14501
14502 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
14503 if (!is_array($psections) || !count($psections)) {
14504 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
14505 }
14506
14507 // request values are all converted to arrays, so restore the object styling
14508 $psections = json_decode(json_encode($psections));
14509
14510 // update map
14511 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
14512
14513 $response = new stdClass;
14514 $response->status = (int)$result;
14515
14516 // output the JSON encoded response and exit
14517 VBOHttpDocument::getInstance()->json($response);
14518 }
14519
14520 /**
14521 * Restores the default admin widgets map.
14522 *
14523 * @since 1.4.0
14524 */
14525 public function reset_admin_widgets()
14526 {
14527 // reset map and redirect to dashboard
14528 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
14529
14530 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
14531 exit;
14532 }
14533
14534 /**
14535 * Updates the welcome message status for the widget's customizer via AJAX.
14536 *
14537 * @since 1.4.0
14538 */
14539 public function admin_widgets_welcome()
14540 {
14541 if (!JSession::checkToken()) {
14542 // missing CSRF-proof token
14543 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14544 }
14545
14546 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
14547 // update configuration value
14548 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
14549
14550 $response = new stdClass;
14551 $response->status = $hide_welcome;
14552
14553 // output the JSON encoded response and exit
14554 VBOHttpDocument::getInstance()->json($response);
14555 }
14556
14557 public function newcondtext()
14558 {
14559 VikBookingHelper::printHeader("11");
14560
14561 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14562
14563 parent::display();
14564
14565 if (VikBooking::showFooter()) {
14566 VikBookingHelper::printFooter();
14567 }
14568 }
14569
14570 public function editcondtext()
14571 {
14572 VikBookingHelper::printHeader("11");
14573
14574 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14575
14576 parent::display();
14577
14578 if (VikBooking::showFooter()) {
14579 VikBookingHelper::printFooter();
14580 }
14581 }
14582
14583 public function cancelcondtext()
14584 {
14585 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
14586 }
14587
14588 public function createcondtext()
14589 {
14590 if (!JSession::checkToken()) {
14591 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14592 }
14593
14594 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14595 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14596 }
14597
14598 $this->_doCreateCondText();
14599 }
14600
14601 public function createcondtextstay()
14602 {
14603 if (!JSession::checkToken()) {
14604 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14605 }
14606
14607 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14608 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14609 }
14610
14611 $this->_doCreateCondText(true);
14612 }
14613
14614 private function _doCreateCondText($stay = false)
14615 {
14616 $dbo = JFactory::getDbo();
14617 $app = JFactory::getApplication();
14618 $rules_helper = VikBooking::getConditionalRulesInstance();
14619 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14620
14621 $condtextname = VikRequest::getString('condtextname', '', 'request');
14622 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14623 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14624 $debug = VikRequest::getInt('debug', 0, 'request');
14625 if (empty($condtextname)) {
14626 $condtextname = date('Y-m-dHis');
14627 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14628 }
14629
14630 $existing_tokens = $rules_helper->getSpecialTags();
14631 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
14632 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
14633 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
14634 exit;
14635 }
14636
14637 $data = new stdClass;
14638 $data->name = $condtextname;
14639 $data->token = $condtexttkn;
14640 $data->rules = json_encode($rules_list);
14641 $data->msg = $msg;
14642 $data->lastupd = JDate::getInstance()->toSql();
14643 $data->debug = $debug;
14644
14645 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
14646
14647 if (isset($data->id)) {
14648 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14649 }
14650
14651 if (!$stay || !isset($data->id)) {
14652 $this->cancelcondtext();
14653 exit;
14654 }
14655
14656 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14657 }
14658
14659 public function updatecondtext()
14660 {
14661 if (!JSession::checkToken()) {
14662 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14663 }
14664
14665 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14666 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14667 }
14668
14669 $this->_doUpdateCondText();
14670 }
14671
14672 public function updatecondtextstay()
14673 {
14674 if (!JSession::checkToken()) {
14675 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14676 }
14677
14678 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14679 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14680 }
14681
14682 $this->_doUpdateCondText(true);
14683 }
14684
14685 private function _doUpdateCondText($stay = false)
14686 {
14687 $dbo = JFactory::getDbo();
14688 $app = JFactory::getApplication();
14689 $rules_helper = VikBooking::getConditionalRulesInstance();
14690 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14691
14692 $pwhere = VikRequest::getInt('where', '', 'request');
14693 $condtextname = VikRequest::getString('condtextname', '', 'request');
14694 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14695 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14696 $debug = VikRequest::getInt('debug', 0, 'request');
14697 if (empty($condtextname)) {
14698 $condtextname = date('Y-m-dHis');
14699 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14700 }
14701
14702 $existing_tokens = $rules_helper->getSpecialTags();
14703 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
14704 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
14705 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
14706 exit;
14707 }
14708
14709 $data = new stdClass;
14710 $data->id = $pwhere;
14711 $data->name = $condtextname;
14712 $data->token = $condtexttkn;
14713 $data->rules = json_encode($rules_list);
14714 $data->msg = $msg;
14715 $data->lastupd = JDate::getInstance()->toSql();
14716 $data->debug = $debug;
14717
14718 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
14719
14720 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14721
14722 if (!$stay) {
14723 $this->cancelcondtext();
14724 exit;
14725 }
14726
14727 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14728 }
14729
14730 public function removecondtext()
14731 {
14732 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14733 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14734 }
14735
14736 $dbo = JFactory::getDbo();
14737 $ids = VikRequest::getVar('cid', array());
14738
14739 VikBooking::getConditionalRulesInstance(true);
14740 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14741
14742 foreach ($ids as $d) {
14743 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14744 $dbo->setQuery($q);
14745 $dbo->execute();
14746 if (!$dbo->getNumRows()) {
14747 continue;
14748 }
14749 $special_tag = $dbo->loadResult();
14750
14751 // remove the token from each template file if it was used before
14752 if (!empty($special_tag)) {
14753 // remove token from all template files
14754 foreach ($templates as $tkey => $tpath) {
14755 // get requested file content
14756 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14757 if (empty($fcontent) || !is_string($fcontent)) {
14758 break;
14759 }
14760 // remove tag from code content
14761 $fcontent = str_replace($special_tag, '', $fcontent);
14762 // update the file code
14763 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14764 }
14765 }
14766
14767 // delete the record
14768 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14769 $dbo->setQuery($q);
14770 $dbo->execute();
14771 }
14772
14773 $this->cancelcondtext();
14774 }
14775
14776 /**
14777 * AJAX endpoint to update one template file with the given tag or styles.
14778 * A JSON response will be echoed by exiting the process.
14779 */
14780 public function condtext_update_tmpl()
14781 {
14782 VikBooking::getConditionalRulesInstance(true);
14783
14784 $tagaction = VikRequest::getString('tagaction', '', 'request');
14785 $tag = VikRequest::getString('tag', '', 'request');
14786 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14787 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14788 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14789
14790 $allowed_actions = array(
14791 'add',
14792 'remove',
14793 'styles',
14794 'restore',
14795 );
14796
14797 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14798 throw new Exception("Invalid request submitted", 500);
14799 }
14800
14801 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14802 throw new Exception("Invalid request submitted - missing tag", 500);
14803 }
14804
14805 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14806 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14807 }
14808
14809 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14810 throw new Exception("No custom CSS classes to parse", 500);
14811 }
14812
14813 if ($tagaction == 'restore') {
14814 // immediately restore the requested file to avoid script interruptions
14815 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14816 }
14817
14818 // get requested file content
14819 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14820 if (empty($fcontent) || !is_string($fcontent)) {
14821 throw new Exception("File not found or its code is unreadable", 404);
14822 }
14823
14824 if ($tagaction == 'remove') {
14825 // remove tag from code content
14826 $fcontent = str_replace($tag, '', $fcontent);
14827 } elseif ($tagaction == 'add') {
14828 // add tag to code content in the same exact position
14829 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14830 } elseif ($tagaction == 'styles') {
14831 // apply the same styling rules
14832 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14833 }
14834
14835 // update the file code
14836 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14837
14838 if (!$res) {
14839 throw new Exception("Could not update the source code of the template file", 500);
14840 }
14841
14842 // parse new HTML content
14843 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14844 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14845 throw new Exception("Could not parse new template file content", 404);
14846 }
14847
14848 // trigger backup/mirroring, if available
14849 if (VBOPlatformDetection::isWordPress()) {
14850 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14851 }
14852
14853 // build output
14854 $output = new stdClass;
14855 $output->newhtml = $newhtmls[$file];
14856 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14857
14858 echo json_encode($output);
14859 exit;
14860 }
14861
14862 /**
14863 * AJAX endpoint to invoke methods of the geocoding helper.
14864 */
14865 public function geocoding_endpoint()
14866 {
14867 $geo = VikBooking::getGeocodingInstance();
14868 $callback = VikRequest::getString('callback', '', 'request');
14869
14870 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14871 throw new Exception("Callback not available", 403);
14872 }
14873
14874 // invoke requested method
14875 $res = $geo->{$callback}();
14876
14877 // prepare response
14878 $response = new stdClass;
14879 $response->{$callback} = $res;
14880
14881 echo json_encode($response);
14882 exit;
14883 }
14884
14885 public function refundtn()
14886 {
14887 //modal box, so we do not set menu or footer
14888
14889 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14890
14891 parent::display();
14892 }
14893
14894 public function do_refundtn()
14895 {
14896 $dbo = JFactory::getDbo();
14897 $app = JFactory::getApplication();
14898
14899 $bid = VikRequest::getInt('bid', 0, 'request');
14900 $amount = VikRequest::getFloat('amount', 0, 'request');
14901 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14902 $tmpl = VikRequest::getString('tmpl', '', 'request');
14903 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14904
14905 $currencysymb = VikBooking::getCurrencySymb();
14906
14907 if (empty($bid) || $amount <= 0) {
14908 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14909 $app->redirect('index.php?option=com_vikbooking');
14910 exit;
14911 }
14912
14913 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14914 $dbo->setQuery($q);
14915 $dbo->execute();
14916 if ($dbo->getNumRows() < 1) {
14917 VikError::raiseWarning('', 'Booking not found');
14918 $app->redirect('index.php?option=com_vikbooking');
14919 exit;
14920 }
14921 $row = $dbo->loadAssoc();
14922
14923 // get booking history instance
14924 $history_obj = VikBooking::getBookingHistoryInstance();
14925 $history_obj->setBid($row['id']);
14926
14927 // get payment information
14928 $payment = VikBooking::getPayment($row['idpayment']);
14929 $tn_driver = is_array($payment) ? $payment['file'] : null;
14930
14931 // transaction data validation callback
14932 $tn_data_callback = function($data) use ($tn_driver) {
14933 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14934 };
14935 // get previous transactions
14936 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14937
14938 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14939 // no previous transactions found
14940 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14941 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14942 exit;
14943 }
14944
14945 // push refund information for the payment gateway
14946 $row['total_to_refund'] = $amount;
14947 $row['transaction'] = $prev_tn_data;
14948 $row['refund_reason'] = $refund_reason;
14949
14950 // push the transaction currency information
14951 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14952
14953 /**
14954 * @wponly The payment gateway is loaded
14955 * through the apposite dispatcher.
14956 */
14957 JLoader::import('adapter.payment.dispatcher');
14958 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14959
14960 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14961 // refund not supported
14962 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14963 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14964 exit;
14965 }
14966
14967 // perform the refund transaction
14968 $array_result = $obj->refund();
14969
14970 if ($array_result['verified'] != 1) {
14971 // raise warning by getting the message
14972 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14973 VikError::raiseWarning('', $array_result['log']);
14974 } else {
14975 VikError::raiseWarning('', 'Operation failed');
14976 }
14977 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14978 exit;
14979 }
14980
14981 /**
14982 * New payment plugins can return the total amount refunded ('tot_paid').
14983 *
14984 * @since 1.15.4 (J) - 1.5.10 (WP)
14985 */
14986 if (!empty($array_result['tot_paid'])) {
14987 // overwrite the requested amount with the returned one
14988 $amount = (float)$array_result['tot_paid'];
14989 }
14990
14991 /**
14992 * The history event extra data will contain the "amount_paid" (refunded).
14993 *
14994 * @since 1.16.9 (J) - 1.6.9 (WP)
14995 */
14996 $history_obj->setExtraData([
14997 'amount_paid' => $amount,
14998 ]);
14999
15000 // update total paid, total and refund columns for the booking
15001 $booking = new stdClass;
15002 $booking->id = $row['id'];
15003 if ($row['totpaid'] > 0) {
15004 $booking->totpaid = $row['totpaid'] - $amount;
15005 }
15006 if ($row['total'] > 0) {
15007 $booking->total = $row['total'] - $amount;
15008 }
15009 $booking->refund = (float)$row['refund'] + $amount;
15010 // update record in db
15011 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
15012
15013 // store the refund event
15014 $event_descr = [
15015 '(' . $payment['name'] . ')',
15016 $refund_reason,
15017 $currencysymb . ' ' . VikBooking::numberFormat($amount),
15018 ];
15019 $history_obj->store('RF', implode("\n", $event_descr));
15020
15021 // display success message and redirect
15022 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
15023 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
15024 exit;
15025 }
15026
15027 /**
15028 * AJAX upload endpoint for media files.
15029 *
15030 * @return void
15031 *
15032 * @throws Exception
15033 *
15034 * @since 1.15.0 (J) - 1.5.0 (WP)
15035 */
15036 public function upload_media_file()
15037 {
15038 $input = JFactory::getApplication()->input;
15039
15040 // allowed types
15041 $type = $input->getString('type', '');
15042 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
15043 if ($type == 'image') {
15044 $mask = "/(image\/.+)$/i";
15045 }
15046
15047 // response object
15048 $result = new stdClass;
15049 $result->status = 0;
15050
15051 try
15052 {
15053 // get file from request
15054 $file = $input->files->get('file', array(), 'array');
15055
15056 // try to upload the file
15057 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
15058 $result->status = 1;
15059
15060 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
15061 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
15062 }
15063 catch (Exception $e)
15064 {
15065 $result->error = $e->getMessage();
15066 $result->code = $e->getCode();
15067 }
15068
15069 echo json_encode($result);
15070 exit;
15071 }
15072
15073 /**
15074 * AJAX endpoint to invoke a report object's method.
15075 *
15076 * @return void
15077 *
15078 * @throws Exception
15079 *
15080 * @since 1.15.0 (J) - 1.5.0 (WP)
15081 */
15082 public function invoke_report()
15083 {
15084 $report_name = VikRequest::getString('report', '', 'request');
15085 $report_call = VikRequest::getString('call', '', 'request');
15086 $params = VikRequest::getVar('params', array(), 'request', 'array');
15087
15088 if (empty($report_name)) {
15089 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
15090 }
15091
15092 if (empty($report_call)) {
15093 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
15094 }
15095
15096 // get requested report instance
15097 $report = VikBooking::getReportInstance($report_name);
15098 if (!$report) {
15099 VBOHttpDocument::getInstance()->close(404, 'Report not found');
15100 }
15101
15102 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
15103 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
15104 }
15105
15106 // call on report's method
15107 $result = $report->{$report_call}($params);
15108
15109 if (is_null($result)) {
15110 VBOHttpDocument::getInstance()->close(400, 'Null response');
15111 }
15112
15113 if (is_scalar($result)) {
15114 // wrap result within an array for a JSON encoded response
15115 VBOHttpDocument::getInstance()->json([$result]);
15116 }
15117
15118 // output the JSON encoded array/object returned
15119 VBOHttpDocument::getInstance()->json($result);
15120 }
15121
15122 /**
15123 * Handles requests for the multitask widgets panel.
15124 *
15125 * @see this is an AJAX endpoint.
15126 *
15127 * @since 1.15.0 (J) - 1.5.0 (WP)
15128 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
15129 */
15130 public function exec_multitask_widgets()
15131 {
15132 if (!JSession::checkToken()) {
15133 // missing CSRF-proof token
15134 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15135 }
15136
15137 $call = VikRequest::getString('call', '', 'request');
15138 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
15139
15140 if (empty($call)) {
15141 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
15142 }
15143
15144 // invoke admin widgets helper
15145 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15146
15147 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
15148 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
15149 }
15150
15151 try {
15152 // invoke the helper's method and get the value returned
15153 if (is_array($call_args) && count($call_args)) {
15154 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
15155 } else {
15156 $result = $widgets_helper->{$call}();
15157 }
15158 } catch (Throwable $e) {
15159 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
15160 } catch (Exception $e) {
15161 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15162 }
15163
15164 // prepare response object with the result property
15165 $response = new stdClass;
15166 $response->result = $result;
15167
15168 // output the JSON response and exit
15169 VBOHttpDocument::getInstance()->json($response);
15170 }
15171
15172 /**
15173 * Handles requests for displaying a browser notification being dispatched.
15174 *
15175 * @see this is an AJAX endpoint.
15176 *
15177 * @since 1.15.0 (J) - 1.5.0 (WP)
15178 */
15179 public function notification_displayer()
15180 {
15181 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
15182
15183 if (empty($payload_str)) {
15184 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
15185 }
15186
15187 // attempt to decode the notification payload
15188 $payload = json_decode($payload_str);
15189
15190 if (!is_object($payload)) {
15191 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
15192 }
15193
15194 // get notification displayer for this type of notification
15195 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
15196 if (!$displayer) {
15197 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
15198 }
15199
15200 // compose the notification display data object
15201 try {
15202 $notif_data = $displayer->getData();
15203 if (!$notif_data) {
15204 throw new Exception('Error building the notification display data', 500);
15205 }
15206 } catch (Exception $e) {
15207 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15208 }
15209
15210 // output the JSON response and exit
15211 VBOHttpDocument::getInstance()->json($notif_data);
15212 }
15213
15214 /**
15215 * Handles requests for watching widgets data and getting
15216 * new events to trigger browser notifications.
15217 *
15218 * @see this is an AJAX endpoint.
15219 *
15220 * @since 1.15.0 (J) - 1.5.0 (WP)
15221 * @since 1.16.8 (J) - 1.6.8 (WP) introduced notification events.
15222 */
15223 public function widgets_watch_data()
15224 {
15225 if (!JSession::checkToken()) {
15226 // missing CSRF-proof token
15227 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15228 }
15229
15230 $app = JFactory::getApplication();
15231
15232 $watch_data_str = $app->input->get('watch_data', '', 'raw');
15233 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
15234
15235 if (empty($watch_data_str)) {
15236 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
15237 }
15238
15239 // attempt to decode the watch-data payload
15240 $watch_data = json_decode($watch_data_str, true);
15241
15242 if (!$watch_data) {
15243 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
15244 }
15245
15246 // check if any pushed data was set
15247 $pushed_data = (array)json_decode($pushed_data_str, true);
15248
15249 // container for new notifications
15250 $notifs_pool = [];
15251
15252 // container for the events data to dispatch
15253 $events_pool = [];
15254
15255 // get admin widgets helper
15256 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15257
15258 foreach ($watch_data as $widget_id => $data) {
15259 // invoke admin widget (with no pre-loading)
15260 $widget_instance = $widgets_helper->getWidget($widget_id);
15261 if (!$widget_instance) {
15262 continue;
15263 }
15264
15265 // build the widget watch data object
15266 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
15267
15268 // check if the widget needs to emit browser notifications
15269 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
15270
15271 // check if the widget needs to emit JavaScript events
15272 $events = $widget_instance->getNotificationEvents($widget_watch_data);
15273
15274 if ($watch_next) {
15275 // update next watch-data object for this widget
15276 $watch_data[$widget_id] = $watch_next;
15277 }
15278
15279 if (is_array($notifications) && $notifications) {
15280 // merge notifications
15281 $notifs_pool = array_merge($notifs_pool, $notifications);
15282 }
15283
15284 if (is_array($events) && $events) {
15285 // push notification events for this widget
15286 $events_pool[] = $events;
15287 }
15288 }
15289
15290 // build the response object
15291 $response = new stdClass;
15292 $response->watch_data = $watch_data;
15293 $response->notifications = $notifs_pool;
15294 $response->events = $events_pool;
15295
15296 // output the JSON response and exit
15297 VBOHttpDocument::getInstance()->json($response);
15298 }
15299
15300 /**
15301 * Outputs a list of CSS assets required to render the admin widgets
15302 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
15303 *
15304 * @see this is an AJAX endpoint.
15305 *
15306 * @since 1.16.0 (J) - 1.6.0 (WP)
15307 */
15308 public function widgets_get_assets()
15309 {
15310 // list of needed CSS asset details
15311 $assets_pool = [];
15312
15313 // appearance preference assets (one or none)
15314 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
15315
15316 if (VBOPlatformDetection::isWordPress()) {
15317 // WordPress (main CSS)
15318 $assets_pool[] = [
15319 'rel' => 'stylesheet',
15320 'id' => 'vbo-style-css',
15321 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15322 'media' => 'all',
15323 ];
15324
15325 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15326 // appearance preference CSS
15327 $assets_pool[] = [
15328 'rel' => 'stylesheet',
15329 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15330 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15331 'media' => 'all',
15332 ];
15333 }
15334 } else {
15335 // Joomla (main CSS)
15336 $assets_pool[] = [
15337 'rel' => 'stylesheet',
15338 'id' => 'vbo-style-css',
15339 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
15340 'media' => 'all',
15341 ];
15342
15343 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15344 // appearance preference CSS
15345 $assets_pool[] = [
15346 'rel' => 'stylesheet',
15347 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15348 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
15349 'media' => 'all',
15350 ];
15351 }
15352 }
15353
15354 // output the JSON response and exit
15355 VBOHttpDocument::getInstance()->json($assets_pool);
15356 }
15357 }
15358