PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.0
VikBooking Hotel Booking Engine & PMS v1.7.0
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.0, at admin/controller.php

15,320 lines 579.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 // 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 -= 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 -= 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 `idorder` FROM `#__vikbooking_customers_orders` WHERE `idcustomer`=".$customer['id'].";";
5443 $dbo->setQuery($q);
5444 $dbo->execute();
5445 if ($dbo->getNumRows() > 0) {
5446 $all_bids = $dbo->loadAssocList();
5447 $bids = array();
5448 foreach ($all_bids as $bid) {
5449 if (!in_array($bid['idorder'], $bids)) {
5450 $bids[] = $bid['idorder'];
5451 }
5452 }
5453 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5454 }
5455 }
5456 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5457 } else {
5458 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5459 }
5460 $dbo->setQuery($q);
5461 $dbo->execute();
5462 //
5463 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5464 } else {
5465 //email already exists
5466 $ex_customer = $dbo->loadAssoc();
5467 //check if coming from the Check-in view or not
5468 if (!empty($pcheckin) && !empty($pbid)) {
5469 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5470 /**
5471 * @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
5472 */
5473 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5474 //
5475 exit;
5476 } elseif (!empty($pgoto)) {
5477 // check if coming from a specific task
5478 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5479 $mainframe->redirect(base64_decode($pgoto));
5480 exit;
5481 } else {
5482 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>');
5483 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5484 exit;
5485 }
5486 }
5487 }
5488
5489 //check if coming from the Check-in view
5490 if (!empty($pcheckin) && !empty($pbid)) {
5491 /**
5492 * @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
5493 */
5494 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5495 exit;
5496 }
5497
5498 if ($stay) {
5499 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5500 exit;
5501 }
5502
5503 // check if coming from a specific task
5504 if (!empty($pgoto)) {
5505 $mainframe->redirect(base64_decode($pgoto));
5506 exit;
5507 }
5508
5509 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5510 }
5511
5512 public function savecustomer() {
5513 if (!JSession::checkToken()) {
5514 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5515 }
5516 $dbo = JFactory::getDbo();
5517 $mainframe = JFactory::getApplication();
5518 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5519 $plast_name = VikRequest::getString('last_name', '', 'request');
5520 $pcompany = VikRequest::getString('company', '', 'request');
5521 $pvat = VikRequest::getString('vat', '', 'request');
5522 $pemail = VikRequest::getString('email', '', 'request');
5523 $pphone = VikRequest::getString('phone', '', 'request');
5524 $pcountry = VikRequest::getString('country', '', 'request');
5525 $pstate = VikRequest::getString('state', '', 'request');
5526 $ppin = VikRequest::getString('pin', '', 'request');
5527 $pujid = VikRequest::getInt('ujid', '', 'request');
5528 $paddress = VikRequest::getString('address', '', 'request');
5529 $pcity = VikRequest::getString('city', '', 'request');
5530 $pzip = VikRequest::getString('zip', '', 'request');
5531 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5532 $ppec = VikRequest::getString('pec', '', 'request');
5533 $precipcode = VikRequest::getString('recipcode', '', 'request');
5534 $pgender = VikRequest::getString('gender', '', 'request');
5535 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5536 $pbdate = VikRequest::getString('bdate', '', 'request');
5537 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5538 $pdoctype = VikRequest::getString('doctype', '', 'request');
5539 $pdocnum = VikRequest::getString('docnum', '', 'request');
5540 $pnotes = VikRequest::getString('notes', '', 'request');
5541 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5542 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5543 $pcommission = VikRequest::getFloat('commission', '', 'request');
5544 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5545 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5546 $pchname = VikRequest::getString('chname', '', 'request');
5547 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5548 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5549 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5550 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5551 $pbid = VikRequest::getInt('bid', '', 'request');
5552 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5553 $cpin = VikBooking::getCPinIstance();
5554 /**
5555 * Existing customers are recognized by equal first name, last name and email address.
5556 *
5557 * @since 1.3.0
5558 */
5559 $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;";
5560 $dbo->setQuery($q);
5561 $dbo->execute();
5562 if ($dbo->getNumRows() == 0) {
5563 if (empty($ppin)) {
5564 $ppin = $cpin->generateUniquePin();
5565 } elseif ($cpin->pinExists($ppin)) {
5566 $ppin = $cpin->generateUniquePin();
5567 }
5568 //file upload
5569 jimport('joomla.filesystem.file');
5570 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5571 $gimg = "";
5572 if (isset($pimg) && strlen(trim($pimg['name']))) {
5573 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5574 $src = $pimg['tmp_name'];
5575 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5576 $j = "";
5577 if (file_exists($dest.$filename)) {
5578 $j = rand(171, 1717);
5579 while (file_exists($dest.$j.$filename)) {
5580 $j++;
5581 }
5582 }
5583 $finaldest = $dest.$j.$filename;
5584 $check = getimagesize($pimg['tmp_name']);
5585 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5586 if (VikBooking::uploadFile($src, $finaldest)) {
5587 $gimg = $j.$filename;
5588 } else {
5589 VikError::raiseWarning('', 'Error while uploading image');
5590 }
5591 } else {
5592 VikError::raiseWarning('', 'Uploaded file is not an Image');
5593 }
5594 } elseif (!empty($pscandocimg)) {
5595 $gimg = $pscandocimg;
5596 }
5597 //
5598 $pischannel = $pischannel > 0 ? 1 : 0;
5599 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5600 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5601 $pchname = str_replace(' ', '', trim($pchname));
5602 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5603 $chparams = array(
5604 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5605 'calccmmon' => $pcalccmmon,
5606 'applycmmon' => $papplycmmon,
5607 'chcolor' => $pchcolor,
5608 'chname' => $pchname
5609 );
5610
5611 /**
5612 * Customer profile picture (URL or uploaded file).
5613 *
5614 * @since 1.15.3 (J) - 1.5.5 (WP)
5615 */
5616 $customer_pic = VikRequest::getString('pic', '', 'request');
5617 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5618 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5619 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5620 $src = $customer_pic_img['tmp_name'];
5621 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5622 $j = "";
5623 if (is_file($dest.$filename)) {
5624 $j = rand(1, 99999);
5625 while (is_file($dest . $j .$filename)) {
5626 $j++;
5627 }
5628 }
5629 $finaldest = $dest . $j . $filename;
5630 $check = getimagesize($customer_pic_img['tmp_name']);
5631 if (($check[2] & imagetypes())) {
5632 if (VikBooking::uploadFile($src, $finaldest)) {
5633 $customer_pic = $j . $filename;
5634 } else {
5635 VikError::raiseWarning('', 'Error while uploading image');
5636 }
5637 } else {
5638 VikError::raiseWarning('', 'Uploaded file is not an Image');
5639 }
5640 }
5641
5642 // build customer record
5643 $customer_obj = new stdClass;
5644 $customer_obj->first_name = $pfirst_name;
5645 $customer_obj->last_name = $plast_name;
5646 $customer_obj->email = $pemail;
5647 $customer_obj->phone = $pphone;
5648 $customer_obj->country = $pcountry;
5649 $customer_obj->pin = $ppin;
5650 $customer_obj->ujid = $pujid;
5651 $customer_obj->address = $paddress;
5652 $customer_obj->city = $pcity;
5653 $customer_obj->zip = $pzip;
5654 $customer_obj->state = $pstate;
5655 $customer_obj->doctype = $pdoctype;
5656 $customer_obj->docnum = $pdocnum;
5657 $customer_obj->docimg = $gimg;
5658 $customer_obj->notes = $pnotes;
5659 $customer_obj->ischannel = $pischannel;
5660 $customer_obj->chdata = json_encode($chparams);
5661 $customer_obj->company = $pcompany;
5662 $customer_obj->vat = $pvat;
5663 $customer_obj->gender = $pgender;
5664 $customer_obj->bdate = $pbdate;
5665 $customer_obj->pbirth = $ppbirth;
5666 $customer_obj->fisccode = $pfisccode;
5667 $customer_obj->pec = $ppec;
5668 $customer_obj->recipcode = $precipcode;
5669 $customer_obj->pic = !empty($customer_pic) ? $customer_pic : null;
5670
5671 // trigger the customer before-insert event
5672 $cpin->pluginCustomerSync(0, 'insert', (array)$customer_obj, $before = true);
5673
5674 // insert the new customer record
5675 $dbo->insertObject('#__vikbooking_customers', $customer_obj, 'id');
5676 $lid = isset($customer_obj->id) ? $customer_obj->id : null;
5677
5678 // trigger the customer after-save event
5679 $cpin->pluginCustomerSync($lid, 'insert', (array)$customer_obj, $before = false);
5680
5681 if (!empty($lid)) {
5682 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5683 //check if coming from the Check-in view
5684 if (!empty($pcheckin) && !empty($pbid)) {
5685 $cpin->setNewPin($ppin);
5686 $cpin->setNewCustomerId($lid);
5687 $cpin->saveCustomerBooking($pbid);
5688 /**
5689 * @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
5690 */
5691 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5692 //
5693 exit;
5694 }
5695 // check if coming from a specific task
5696 if (!empty($pgoto) && !empty($pbid)) {
5697 $cpin->setNewPin($ppin);
5698 $cpin->setNewCustomerId($lid);
5699 $cpin->saveCustomerBooking($pbid);
5700 $mainframe->redirect(base64_decode($pgoto));
5701 exit;
5702 }
5703 }
5704 } else {
5705 //email already exists
5706 $ex_customer = $dbo->loadAssoc();
5707 //check if coming from the Check-in view or not
5708 if (!empty($pcheckin) && !empty($pbid)) {
5709 $cpin->setNewPin($ex_customer['pin']);
5710 $cpin->setNewCustomerId($ex_customer['id']);
5711 $cpin->saveCustomerBooking($pbid);
5712 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5713 /**
5714 * @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
5715 */
5716 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5717 //
5718 exit;
5719 } elseif (!empty($pgoto) && !empty($pbid)) {
5720 // check if coming from a specific task
5721 $cpin->setNewPin($ex_customer['pin']);
5722 $cpin->setNewCustomerId($ex_customer['id']);
5723 $cpin->saveCustomerBooking($pbid);
5724 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5725 $mainframe->redirect(base64_decode($pgoto));
5726 exit;
5727 } else {
5728 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>');
5729 }
5730 }
5731 }
5732 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5733 }
5734
5735 public function customers() {
5736 VikBookingHelper::printHeader("22");
5737
5738 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5739
5740 parent::display();
5741
5742 if (VikBooking::showFooter()) {
5743 VikBookingHelper::printFooter();
5744 }
5745 }
5746
5747 public function newcustomer() {
5748 VikBookingHelper::printHeader("22");
5749
5750 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5751
5752 parent::display();
5753
5754 if (VikBooking::showFooter()) {
5755 VikBookingHelper::printFooter();
5756 }
5757 }
5758
5759 public function editcustomer() {
5760 VikBookingHelper::printHeader("22");
5761
5762 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5763
5764 parent::display();
5765
5766 if (VikBooking::showFooter()) {
5767 VikBookingHelper::printFooter();
5768 }
5769 }
5770
5771 public function removecustomers()
5772 {
5773 if (!JSession::checkToken()) {
5774 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5775 }
5776
5777 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5778 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5779 }
5780
5781 $ids = VikRequest::getVar('cid', array(0));
5782 if ($ids) {
5783 $dbo = JFactory::getDBO();
5784 $cpin = VikBooking::getCPinIstance();
5785 foreach ($ids as $d) {
5786 $cpin->pluginCustomerSync($d, 'delete');
5787 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5788 $dbo->setQuery($q);
5789 $dbo->execute();
5790 }
5791 }
5792 $mainframe = JFactory::getApplication();
5793 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5794 }
5795
5796 public function restrictions() {
5797 VikBookingHelper::printHeader("restrictions");
5798
5799 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5800
5801 parent::display();
5802
5803 if (VikBooking::showFooter()) {
5804 VikBookingHelper::printFooter();
5805 }
5806 }
5807
5808 public function newrestriction() {
5809 VikBookingHelper::printHeader("restrictions");
5810
5811 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5812
5813 parent::display();
5814
5815 if (VikBooking::showFooter()) {
5816 VikBookingHelper::printFooter();
5817 }
5818 }
5819
5820 public function editrestriction() {
5821 VikBookingHelper::printHeader("restrictions");
5822
5823 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5824
5825 parent::display();
5826
5827 if (VikBooking::showFooter()) {
5828 VikBookingHelper::printFooter();
5829 }
5830 }
5831
5832 public function createrestriction()
5833 {
5834 if (!JSession::checkToken()) {
5835 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5836 }
5837
5838 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5839 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5840 }
5841
5842 $dbo = JFactory::getDBO();
5843 $session = JFactory::getSession();
5844 $mainframe = JFactory::getApplication();
5845 $updforvcm = $session->get('vbVcmRatesUpd', '');
5846 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5847 $pname = VikRequest::getString('name', '', 'request');
5848 $pmonth = VikRequest::getInt('month', '', 'request');
5849 $pmonth = empty($pmonth) ? 0 : $pmonth;
5850 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5851 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5852 $pdto = VikRequest::getString('dto', '', 'request');
5853 $pwday = VikRequest::getString('wday', '', 'request');
5854 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5855 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5856 $pcomboa = VikRequest::getString('comboa', '', 'request');
5857 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5858 $pcombob = VikRequest::getString('combob', '', 'request');
5859 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5860 $pcomboc = VikRequest::getString('comboc', '', 'request');
5861 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5862 $pcombod = VikRequest::getString('combod', '', 'request');
5863 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5864 $combostr = '';
5865 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5866 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5867 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5868 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5869 $pminlos = VikRequest::getInt('minlos', '', 'request');
5870 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5871 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5872 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5873 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5874 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5875 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5876 $pallrooms = $pallrooms == "1" ? 1 : 0;
5877 $pidrooms = VikRequest::getVar('idrooms', array(0));
5878 $ridr = '';
5879 $roomidsforsess = array();
5880 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5881 foreach ($pidrooms as $idr) {
5882 if (empty($idr)) {
5883 continue;
5884 }
5885 $ridr .= '-'.$idr.'-;';
5886 $roomidsforsess[] = (int)$idr;
5887 }
5888 } elseif ($pallrooms > 0) {
5889 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5890 $dbo->setQuery($q);
5891 $dbo->execute();
5892 if ($dbo->getNumRows() > 0) {
5893 $fetchids = $dbo->loadAssocList();
5894 foreach ($fetchids as $fetchid) {
5895 $roomidsforsess[] = (int)$fetchid['id'];
5896 }
5897 }
5898 }
5899 $pcta = VikRequest::getInt('cta', '', 'request');
5900 $pctd = VikRequest::getInt('ctd', '', 'request');
5901 $pctad = VikRequest::getVar('ctad', array());
5902 $pctdd = VikRequest::getVar('ctdd', array());
5903 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5904 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5905 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5906 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5907 // exit;
5908 }
5909
5910 //check if there are restrictions for this month
5911 if ($pmonth > 0) {
5912 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5913 $dbo->setQuery($q);
5914 $dbo->execute();
5915 if ($dbo->getNumRows() > 0) {
5916 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5917 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5918 exit;
5919 }
5920 $pdfrom = 0;
5921 $pdto = 0;
5922 } else {
5923 //dates range
5924 if (empty($pdfrom) || empty($pdto)) {
5925 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5926 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5927 exit;
5928 } else {
5929 $housto = $pdfrom == $pdto ? 23 : 0;
5930 $minsto = $pdfrom == $pdto ? 59 : 0;
5931 $secsto = $pdfrom == $pdto ? 59 : 0;
5932 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5933 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5934 }
5935 if ($pdfrom > $pdto) {
5936 // invalid dates in the past
5937 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5938 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5939 exit;
5940 }
5941 }
5942 //CTA and CTD
5943 $setcta = array();
5944 $setctd = array();
5945 if ($pcta > 0 && count($pctad) > 0) {
5946 foreach ($pctad as $ctwd) {
5947 if (strlen($ctwd)) {
5948 $setcta[] = '-'.(int)$ctwd.'-';
5949 }
5950 }
5951 }
5952 if ($pctd > 0 && count($pctdd) > 0) {
5953 foreach ($pctdd as $ctwd) {
5954 if (strlen($ctwd)) {
5955 $setctd[] = '-'.(int)$ctwd.'-';
5956 }
5957 }
5958 }
5959 //
5960 //update session values
5961 if (!($pdfrom > 0)) {
5962 $attemptyear = (int)date('Y');
5963 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5964 if ($attemptfrom < time()) {
5965 $attemptyear++;
5966 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5967 }
5968 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5969 } else {
5970 $attemptfrom = $pdfrom;
5971 $attemptto = $pdto;
5972 }
5973 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5974 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5975 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5976 } else {
5977 $updforvcm['dfrom'] = $attemptfrom;
5978 }
5979 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5980 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5981 } else {
5982 $updforvcm['dto'] = $attemptto;
5983 }
5984 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5985 foreach ($roomidsforsess as $rid) {
5986 if (!in_array($rid, $updforvcm['rooms'])) {
5987 $updforvcm['rooms'][] = $rid;
5988 }
5989 }
5990 } else {
5991 $updforvcm['rooms'] = $roomidsforsess;
5992 }
5993 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5994 $updforvcm['rplans'] = array();
5995 }
5996 $session->set('vbVcmRatesUpd', $updforvcm);
5997 //
5998 $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").");";
5999 $dbo->setQuery($q);
6000 $dbo->execute();
6001 $lid = $dbo->insertid();
6002 if (!empty($lid)) {
6003 /**
6004 * Repeat restriction on the selected week days until the limit
6005 *
6006 * @since 1.13
6007 */
6008 $prepeat = VikRequest::getInt('repeat', 0, 'request');
6009 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
6010 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
6011 $repeat_intervals = array();
6012 $start = getdate($pdfrom);
6013 $end = getdate($pdto);
6014 $wdays = array();
6015 while ($start[0] <= $end[0]) {
6016 // push requested week day
6017 array_push($wdays, $start['wday']);
6018 // next day
6019 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
6020 }
6021 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
6022 if (count($wdays) < 7 && $dtuntil > $pdto) {
6023 // increment end date for the repeat
6024 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
6025 //
6026 $until_info = getdate($dtuntil);
6027 $interval = array();
6028 while ($end[0] <= $until_info[0]) {
6029 if (in_array($end['wday'], $wdays)) {
6030 if (!isset($interval['from'])) {
6031 $interval['from'] = $end[0];
6032 }
6033 $interval['to'] = $end[0];
6034 } else {
6035 if (isset($interval['from'])) {
6036 // append interval
6037 array_push($repeat_intervals, $interval);
6038 // reset interval
6039 $interval = array();
6040 }
6041 }
6042 // next day
6043 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
6044 }
6045 if (isset($interval['from'])) {
6046 // append last hanging interval
6047 array_push($repeat_intervals, $interval);
6048 }
6049 if (count($repeat_intervals)) {
6050 // create the repeated records for the calculated intervals
6051 $repeat_count = 2;
6052 foreach ($repeat_intervals as $rp) {
6053 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
6054 // adjust time in case of equal dates (1 single day restriction)
6055 $rpfrom = getdate($rp['from']);
6056 $rpto = getdate($rp['to']);
6057 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
6058 /**
6059 * The end date of the restriction must cover the whole day until 23:59:59.
6060 *
6061 * @since 1.15.4 (J) - 1.5.4 (WP)
6062 */
6063 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
6064 }
6065 // adjust name
6066 $restr_rp_name = $pname . " #{$repeat_count}";
6067 //
6068 $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").");";
6069 $dbo->setQuery($q);
6070 $dbo->execute();
6071 $lid = $dbo->insertid();
6072 if (!empty($lid)) {
6073 $repeat_count++;
6074 }
6075 }
6076 }
6077 }
6078 }
6079 //
6080 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6081 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6082 } else {
6083 VikError::raiseWarning('', 'Error while saving');
6084 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
6085 }
6086 }
6087
6088 public function updaterestriction()
6089 {
6090 if (!JSession::checkToken()) {
6091 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6092 }
6093
6094 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6095 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6096 }
6097
6098 $dbo = JFactory::getDBO();
6099 $session = JFactory::getSession();
6100 $mainframe = JFactory::getApplication();
6101 $updforvcm = $session->get('vbVcmRatesUpd', '');
6102 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
6103 $pwhere = VikRequest::getInt('where', '', 'request');
6104 $pname = VikRequest::getString('name', '', 'request');
6105 $pmonth = VikRequest::getInt('month', '', 'request');
6106 $pmonth = empty($pmonth) ? 0 : $pmonth;
6107 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
6108 $pdfrom = VikRequest::getString('dfrom', '', 'request');
6109 $pdto = VikRequest::getString('dto', '', 'request');
6110 $pwday = VikRequest::getString('wday', '', 'request');
6111 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
6112 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
6113 $pcomboa = VikRequest::getString('comboa', '', 'request');
6114 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
6115 $pcombob = VikRequest::getString('combob', '', 'request');
6116 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
6117 $pcomboc = VikRequest::getString('comboc', '', 'request');
6118 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
6119 $pcombod = VikRequest::getString('combod', '', 'request');
6120 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
6121 $combostr = '';
6122 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
6123 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
6124 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
6125 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
6126 $pminlos = VikRequest::getInt('minlos', '', 'request');
6127 $pminlos = $pminlos < 1 ? 1 : $pminlos;
6128 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
6129 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
6130 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
6131 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
6132 $pallrooms = VikRequest::getString('allrooms', '', 'request');
6133 $pallrooms = $pallrooms == "1" ? 1 : 0;
6134 $pidrooms = VikRequest::getVar('idrooms', array(0));
6135 $ridr = '';
6136 $roomidsforsess = array();
6137 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
6138 foreach ($pidrooms as $idr) {
6139 if (empty($idr)) {
6140 continue;
6141 }
6142 $ridr .= '-'.$idr.'-;';
6143 $roomidsforsess[] = (int)$idr;
6144 }
6145 } elseif ($pallrooms > 0) {
6146 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
6147 $dbo->setQuery($q);
6148 $dbo->execute();
6149 if ($dbo->getNumRows() > 0) {
6150 $fetchids = $dbo->loadAssocList();
6151 foreach ($fetchids as $fetchid) {
6152 $roomidsforsess[] = (int)$fetchid['id'];
6153 }
6154 }
6155 }
6156 $pcta = VikRequest::getInt('cta', '', 'request');
6157 $pctd = VikRequest::getInt('ctd', '', 'request');
6158 $pctad = VikRequest::getVar('ctad', array());
6159 $pctdd = VikRequest::getVar('ctdd', array());
6160 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
6161 // VBO 1.11 - we now allow restrictions with just 1 night of stay
6162 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
6163 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6164 // exit;
6165 }
6166 //check if there are restrictions for this month
6167 if ($pmonth > 0) {
6168 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
6169 $dbo->setQuery($q);
6170 $dbo->execute();
6171 if ($dbo->getNumRows() > 0) {
6172 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
6173 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6174 exit;
6175 }
6176 $pdfrom = 0;
6177 $pdto = 0;
6178 } else {
6179 //dates range
6180 if (empty($pdfrom) || empty($pdto)) {
6181 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6182 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6183 exit;
6184 } else {
6185 $housto = $pdfrom == $pdto ? 23 : 0;
6186 $minsto = $pdfrom == $pdto ? 59 : 0;
6187 $secsto = $pdfrom == $pdto ? 59 : 0;
6188 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
6189 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
6190 }
6191 if ($pdfrom > $pdto) {
6192 // invalid dates in the past
6193 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6194 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6195 exit;
6196 }
6197 }
6198 //CTA and CTD
6199 $setcta = array();
6200 $setctd = array();
6201 if ($pcta > 0 && count($pctad) > 0) {
6202 foreach ($pctad as $ctwd) {
6203 if (strlen($ctwd)) {
6204 $setcta[] = '-'.(int)$ctwd.'-';
6205 }
6206 }
6207 }
6208 if ($pctd > 0 && count($pctdd) > 0) {
6209 foreach ($pctdd as $ctwd) {
6210 if (strlen($ctwd)) {
6211 $setctd[] = '-'.(int)$ctwd.'-';
6212 }
6213 }
6214 }
6215 //
6216 //update session values
6217 if (!($pdfrom > 0)) {
6218 $attemptyear = (int)date('Y');
6219 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6220 if ($attemptfrom < time()) {
6221 $attemptyear++;
6222 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6223 }
6224 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
6225 } else {
6226 $attemptfrom = $pdfrom;
6227 $attemptto = $pdto;
6228 }
6229 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
6230 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
6231 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
6232 } else {
6233 $updforvcm['dfrom'] = $attemptfrom;
6234 }
6235 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
6236 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
6237 } else {
6238 $updforvcm['dto'] = $attemptto;
6239 }
6240 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
6241 foreach ($roomidsforsess as $rid) {
6242 if (!in_array($rid, $updforvcm['rooms'])) {
6243 $updforvcm['rooms'][] = $rid;
6244 }
6245 }
6246 } else {
6247 $updforvcm['rooms'] = $roomidsforsess;
6248 }
6249 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6250 $updforvcm['rplans'] = array();
6251 }
6252 $session->set('vbVcmRatesUpd', $updforvcm);
6253 //
6254 $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."';";
6255 $dbo->setQuery($q);
6256 $dbo->execute();
6257 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6258 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6259 }
6260
6261 public function removerestrictions()
6262 {
6263 if (!JSession::checkToken()) {
6264 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6265 }
6266
6267 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6268 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6269 }
6270
6271 $ids = VikRequest::getVar('cid', array(0));
6272 if ($ids) {
6273 $dbo = JFactory::getDBO();
6274 foreach ($ids as $d) {
6275 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6276 $dbo->setQuery($q);
6277 $dbo->execute();
6278 }
6279 }
6280 $mainframe = JFactory::getApplication();
6281 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6282 }
6283
6284 public function prices() {
6285 VikBookingHelper::printHeader("1");
6286
6287 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6288
6289 parent::display();
6290
6291 if (VikBooking::showFooter()) {
6292 VikBookingHelper::printFooter();
6293 }
6294 }
6295
6296 public function newprice() {
6297 VikBookingHelper::printHeader("1");
6298
6299 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6300
6301 parent::display();
6302
6303 if (VikBooking::showFooter()) {
6304 VikBookingHelper::printFooter();
6305 }
6306 }
6307
6308 public function editprice() {
6309 VikBookingHelper::printHeader("1");
6310
6311 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6312
6313 parent::display();
6314
6315 if (VikBooking::showFooter()) {
6316 VikBookingHelper::printFooter();
6317 }
6318 }
6319
6320 public function createprice()
6321 {
6322 if (!JSession::checkToken()) {
6323 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6324 }
6325
6326 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6327 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6328 }
6329
6330 $this->do_createprice();
6331 }
6332
6333 public function createprice_new()
6334 {
6335 if (!JSession::checkToken()) {
6336 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6337 }
6338
6339 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6340 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6341 }
6342
6343 $this->do_createprice(true);
6344 }
6345
6346 private function do_createprice($new = false)
6347 {
6348 $app = JFactory::getApplication();
6349 $dbo = JFactory::getDbo();
6350
6351 $pprice = VikRequest::getString('price', '', 'request');
6352 $pattr = VikRequest::getString('attr', '', 'request');
6353 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6354 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6355 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6356 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6357 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6358 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6359 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6360 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6361 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6362 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6363 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6364
6365 $is_derived = $app->input->getInt('is_derived', 0);
6366 $derived_id = $app->input->getUInt('derived_id', 0);
6367 $derived_data = $app->input->get('derived_data', [], 'array');
6368
6369 $parent_id = 0;
6370 $derived_info = null;
6371
6372 if ($is_derived && $derived_id && $derived_data) {
6373 $parent_id = $derived_id;
6374 $derived_info = $derived_data;
6375 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6376 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6377 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6378 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6379 if (!$derived_info['value']) {
6380 $parent_id = 0;
6381 $derived_info = null;
6382 }
6383 }
6384
6385 if (!empty($pprice)) {
6386 $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') . ");";
6387 $dbo->setQuery($q);
6388 $dbo->execute();
6389 }
6390
6391 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6392 $app->close();
6393 }
6394
6395 public function updateprice()
6396 {
6397 if (!JSession::checkToken()) {
6398 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6399 }
6400
6401 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6402 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6403 }
6404
6405 $this->do_updateprice();
6406 }
6407
6408 public function updatepricestay()
6409 {
6410 if (!JSession::checkToken()) {
6411 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6412 }
6413
6414 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6415 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6416 }
6417
6418 $this->do_updateprice(true);
6419 }
6420
6421 private function do_updateprice($stay = false)
6422 {
6423 $app = JFactory::getApplication();
6424 $dbo = JFactory::getDbo();
6425
6426 $pprice = VikRequest::getString('price', '', 'request');
6427 $pattr = VikRequest::getString('attr', '', 'request');
6428 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6429 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6430 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6431 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6432 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6433 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6434 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6435 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6436 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6437 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6438 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6439 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6440
6441 $is_derived = $app->input->getInt('is_derived', 0);
6442 $derived_id = $app->input->getUInt('derived_id', 0);
6443 $derived_data = $app->input->get('derived_data', [], 'array');
6444
6445 $parent_id = 0;
6446 $derived_info = null;
6447
6448 if ($is_derived && $derived_id && $derived_data) {
6449 $parent_id = $derived_id;
6450 $derived_info = $derived_data;
6451 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6452 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6453 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6454 $derived_info['follow_restr'] = (int) ($derived_info['follow_restr'] ?? 1);
6455 if (!$derived_info['value']) {
6456 $parent_id = 0;
6457 $derived_info = null;
6458 }
6459 }
6460
6461 if (!empty($pprice) && $pwhereup) {
6462 $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) . ";";
6463 $dbo->setQuery($q);
6464 $dbo->execute();
6465 }
6466
6467 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6468 $app->close();
6469 }
6470
6471 public function removeprice()
6472 {
6473 if (!JSession::checkToken()) {
6474 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6475 }
6476
6477 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6478 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6479 }
6480
6481 $ids = VikRequest::getVar('cid', array(0));
6482 if ($ids) {
6483 $dbo = JFactory::getDBO();
6484 foreach ($ids as $d) {
6485 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6486 $dbo->setQuery($q);
6487 $dbo->execute();
6488 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6489 $dbo->setQuery($q);
6490 $dbo->execute();
6491 }
6492 }
6493 $mainframe = JFactory::getApplication();
6494 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6495 }
6496
6497 public function iva() {
6498 VikBookingHelper::printHeader("2");
6499
6500 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6501
6502 parent::display();
6503
6504 if (VikBooking::showFooter()) {
6505 VikBookingHelper::printFooter();
6506 }
6507 }
6508
6509 public function newiva() {
6510 VikBookingHelper::printHeader("2");
6511
6512 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6513
6514 parent::display();
6515
6516 if (VikBooking::showFooter()) {
6517 VikBookingHelper::printFooter();
6518 }
6519 }
6520
6521 public function editiva() {
6522 VikBookingHelper::printHeader("2");
6523
6524 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6525
6526 parent::display();
6527
6528 if (VikBooking::showFooter()) {
6529 VikBookingHelper::printFooter();
6530 }
6531 }
6532
6533 public function createiva()
6534 {
6535 if (!JSession::checkToken()) {
6536 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6537 }
6538
6539 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6540 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6541 }
6542
6543 $paliqname = VikRequest::getString('aliqname', '', 'request');
6544 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6545 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6546 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6547 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6548 if (!empty($paliqperc)) {
6549 $dbo = JFactory::getDBO();
6550 $breakdown_str = '';
6551 if (count($pbreakdown_name) > 0) {
6552 $breakdown_values = array();
6553 $bkcount = 0;
6554 $tot_sub_aliq = 0;
6555 foreach ($pbreakdown_name as $key => $subtax) {
6556 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6557 $breakdown_values[$bkcount]['name'] = $subtax;
6558 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6559 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6560 $bkcount++;
6561 }
6562 }
6563 if (count($breakdown_values) > 0) {
6564 $breakdown_str = json_encode($breakdown_values);
6565 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6566 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6567 }
6568 }
6569 }
6570 $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').");";
6571 $dbo->setQuery($q);
6572 $dbo->execute();
6573 }
6574 $mainframe = JFactory::getApplication();
6575 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6576 }
6577
6578 public function updateiva()
6579 {
6580 if (!JSession::checkToken()) {
6581 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6582 }
6583
6584 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6585 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6586 }
6587
6588 $paliqname = VikRequest::getString('aliqname', '', 'request');
6589 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6590 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6591 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6592 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6593 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6594 if (!empty($paliqperc)) {
6595 $dbo = JFactory::getDBO();
6596 $breakdown_str = '';
6597 if (count($pbreakdown_name) > 0) {
6598 $breakdown_values = array();
6599 $bkcount = 0;
6600 $tot_sub_aliq = 0;
6601 foreach ($pbreakdown_name as $key => $subtax) {
6602 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6603 $breakdown_values[$bkcount]['name'] = $subtax;
6604 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6605 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6606 $bkcount++;
6607 }
6608 }
6609 if (count($breakdown_values) > 0) {
6610 $breakdown_str = json_encode($breakdown_values);
6611 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6612 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6613 }
6614 }
6615 }
6616 $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).";";
6617 $dbo->setQuery($q);
6618 $dbo->execute();
6619 }
6620 $mainframe = JFactory::getApplication();
6621 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6622 }
6623
6624 public function removeiva()
6625 {
6626 if (!JSession::checkToken()) {
6627 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6628 }
6629
6630 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6631 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6632 }
6633
6634 $ids = VikRequest::getVar('cid', array(0));
6635 if ($ids) {
6636 $dbo = JFactory::getDBO();
6637 foreach ($ids as $d) {
6638 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6639 $dbo->setQuery($q);
6640 $dbo->execute();
6641 }
6642 }
6643 $mainframe = JFactory::getApplication();
6644 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6645 }
6646
6647 public function categories() {
6648 VikBookingHelper::printHeader("4");
6649
6650 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6651
6652 parent::display();
6653
6654 if (VikBooking::showFooter()) {
6655 VikBookingHelper::printFooter();
6656 }
6657 }
6658
6659 public function newcat() {
6660 VikBookingHelper::printHeader("4");
6661
6662 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6663
6664 parent::display();
6665
6666 if (VikBooking::showFooter()) {
6667 VikBookingHelper::printFooter();
6668 }
6669 }
6670
6671 public function editcat() {
6672 VikBookingHelper::printHeader("4");
6673
6674 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6675
6676 parent::display();
6677
6678 if (VikBooking::showFooter()) {
6679 VikBookingHelper::printFooter();
6680 }
6681 }
6682
6683 public function createcat()
6684 {
6685 if (!JSession::checkToken()) {
6686 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6687 }
6688
6689 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6690 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6691 }
6692
6693 $pcatname = VikRequest::getString('catname', '', 'request');
6694 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6695 if (!empty($pcatname)) {
6696 $dbo = JFactory::getDBO();
6697 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6698 $dbo->setQuery($q);
6699 $dbo->execute();
6700 }
6701 $mainframe = JFactory::getApplication();
6702 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6703 }
6704
6705 public function updatecat()
6706 {
6707 if (!JSession::checkToken()) {
6708 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6709 }
6710
6711 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6712 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6713 }
6714
6715 $pcatname = VikRequest::getString('catname', '', 'request');
6716 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6717 $pwhereup = VikRequest::getString('whereup', '', 'request');
6718 if (!empty($pcatname)) {
6719 $dbo = JFactory::getDBO();
6720 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6721 $dbo->setQuery($q);
6722 $dbo->execute();
6723 }
6724 $mainframe = JFactory::getApplication();
6725 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6726 }
6727
6728 public function removecat()
6729 {
6730 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6731 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6732 }
6733
6734 $ids = VikRequest::getVar('cid', array(0));
6735 if ($ids) {
6736 $dbo = JFactory::getDBO();
6737 foreach ($ids as $d) {
6738 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6739 $dbo->setQuery($q);
6740 $dbo->execute();
6741 }
6742 }
6743 $mainframe = JFactory::getApplication();
6744 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6745 }
6746
6747 public function carat() {
6748 VikBookingHelper::printHeader("5");
6749
6750 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6751
6752 parent::display();
6753
6754 if (VikBooking::showFooter()) {
6755 VikBookingHelper::printFooter();
6756 }
6757 }
6758
6759 public function newcarat() {
6760 VikBookingHelper::printHeader("5");
6761
6762 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6763
6764 parent::display();
6765
6766 if (VikBooking::showFooter()) {
6767 VikBookingHelper::printFooter();
6768 }
6769 }
6770
6771 public function editcarat() {
6772 VikBookingHelper::printHeader("5");
6773
6774 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6775
6776 parent::display();
6777
6778 if (VikBooking::showFooter()) {
6779 VikBookingHelper::printFooter();
6780 }
6781 }
6782
6783 public function createcarat()
6784 {
6785 if (!JSession::checkToken()) {
6786 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6787 }
6788
6789 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6790 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6791 }
6792
6793 $pcaratname = VikRequest::getString('caratname', '', 'request');
6794 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6795 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6796 $presizeto = VikRequest::getString('resizeto', '', 'request');
6797 $pidrooms = VikRequest::getVar('idrooms', array());
6798 if (!empty($pcaratname)) {
6799 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6800 jimport('joomla.filesystem.file');
6801 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6802 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6803 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6804 if (file_exists($updpath.$safename)) {
6805 $j=1;
6806 while (file_exists($updpath.$j.$safename)) {
6807 $j++;
6808 }
6809 $pwhere=$updpath.$j.$safename;
6810 } else {
6811 $j="";
6812 $pwhere=$updpath.$safename;
6813 }
6814 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6815 @unlink($pwhere);
6816 $picon="";
6817 } else {
6818 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6819 @chmod($pwhere, 0644);
6820 $picon=$j.$safename;
6821 if ($pautoresize=="1" && !empty($presizeto)) {
6822 $eforj = new vikResizer();
6823 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6824 if ($origmod) {
6825 @unlink($pwhere);
6826 $picon='r_'.$j.$safename;
6827 }
6828 }
6829 }
6830 } else {
6831 $picon="";
6832 }
6833 } else {
6834 $picon="";
6835 }
6836 $dbo = JFactory::getDbo();
6837 // get new ordering
6838 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6839 $dbo->setQuery($q);
6840 $dbo->execute();
6841 if ($dbo->getNumRows()) {
6842 $newsortnum = $dbo->loadResult() + 1;
6843 } else {
6844 $newsortnum = 1;
6845 }
6846 $pordering = VikRequest::getInt('ordering', 0, 'request');
6847 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6848 //
6849 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6850 $dbo->setQuery($q);
6851 $dbo->execute();
6852
6853 $new_carat_id = $dbo->insertid();
6854 if (!empty($new_carat_id)) {
6855 // assign/unset carat-rooms relations
6856 $rooms_with_carat = array();
6857 if (count($pidrooms)) {
6858 // assign this new carat to the requested rooms
6859 foreach ($pidrooms as $idroom) {
6860 if (empty($idroom)) {
6861 continue;
6862 }
6863 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6864 $dbo->setQuery($q);
6865 $dbo->execute();
6866 if (!$dbo->getNumRows()) {
6867 continue;
6868 }
6869 $room_data = $dbo->loadAssoc();
6870 array_push($rooms_with_carat, $room_data['id']);
6871 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6872 if (in_array((string)$new_carat_id, $current_carats)) {
6873 continue;
6874 }
6875 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6876 // make sure we do not concatenate a real ID to 0
6877 $current_carats = array();
6878 }
6879 array_push($current_carats, $new_carat_id);
6880 $new_opts = implode(';', $current_carats) . ';';
6881 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6882 $dbo->setQuery($q);
6883 $dbo->execute();
6884 }
6885 }
6886 if (!count($rooms_with_carat)) {
6887 // get all rooms to unset this carat (if previously set)
6888 array_push($rooms_with_carat, '0');
6889 }
6890 // unset the carat from the other rooms that may have it
6891 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6892 $dbo->setQuery($q);
6893 $dbo->execute();
6894 if ($dbo->getNumRows()) {
6895 $unset_rooms_carat = $dbo->loadAssocList();
6896 foreach ($unset_rooms_carat as $room_data) {
6897 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6898 if (!in_array((string)$new_carat_id, $current_carats)) {
6899 // this room is not using this carat
6900 continue;
6901 }
6902 $caratkey = array_search((string)$new_carat_id, $current_carats);
6903 if ($caratkey === false) {
6904 // key not found
6905 continue;
6906 }
6907 // unset this carat ID from the string
6908 unset($current_carats[$caratkey]);
6909 if (!count($current_carats)) {
6910 // a room with no carats assigned will be listed as "0;"
6911 $current_carats = array(0);
6912 }
6913 $new_opts = implode(';', $current_carats) . ';';
6914 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6915 $dbo->setQuery($q);
6916 $dbo->execute();
6917 }
6918 }
6919 //
6920 }
6921 }
6922 $mainframe = JFactory::getApplication();
6923 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6924 }
6925
6926 public function updatecarat()
6927 {
6928 if (!JSession::checkToken()) {
6929 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6930 }
6931
6932 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6933 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6934 }
6935
6936 $pcaratname = VikRequest::getString('caratname', '', 'request');
6937 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6938 $pwhereup = VikRequest::getString('whereup', '', 'request');
6939 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6940 $presizeto = VikRequest::getString('resizeto', '', 'request');
6941 $pidrooms = VikRequest::getVar('idrooms', array());
6942 $pordering = VikRequest::getInt('ordering', 1, 'request');
6943 if (!empty($pcaratname)) {
6944 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6945 jimport('joomla.filesystem.file');
6946 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6947 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6948 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6949 if (file_exists($updpath.$safename)) {
6950 $j=1;
6951 while (file_exists($updpath.$j.$safename)) {
6952 $j++;
6953 }
6954 $pwhere=$updpath.$j.$safename;
6955 } else {
6956 $j="";
6957 $pwhere=$updpath.$safename;
6958 }
6959 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6960 @unlink($pwhere);
6961 $picon="";
6962 } else {
6963 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6964 @chmod($pwhere, 0644);
6965 $picon=$j.$safename;
6966 if ($pautoresize=="1" && !empty($presizeto)) {
6967 $eforj = new vikResizer();
6968 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6969 if ($origmod) {
6970 @unlink($pwhere);
6971 $picon='r_'.$j.$safename;
6972 }
6973 }
6974 }
6975 } else {
6976 $picon="";
6977 }
6978 } else {
6979 $picon="";
6980 }
6981 $dbo = JFactory::getDbo();
6982 $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).";";
6983 $dbo->setQuery($q);
6984 $dbo->execute();
6985
6986 // assign/unset carat-rooms relations
6987 $rooms_with_carat = array();
6988 if (count($pidrooms)) {
6989 // assign this new carat to the requested rooms
6990 foreach ($pidrooms as $idroom) {
6991 if (empty($idroom)) {
6992 continue;
6993 }
6994 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6995 $dbo->setQuery($q);
6996 $dbo->execute();
6997 if (!$dbo->getNumRows()) {
6998 continue;
6999 }
7000 $room_data = $dbo->loadAssoc();
7001 array_push($rooms_with_carat, $room_data['id']);
7002 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
7003 if (in_array((string)$pwhereup, $current_carats)) {
7004 continue;
7005 }
7006 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
7007 // make sure we do not concatenate a real ID to 0
7008 $current_carats = array();
7009 }
7010 array_push($current_carats, $pwhereup);
7011 $new_carats = implode(';', $current_carats) . ';';
7012 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7013 $dbo->setQuery($q);
7014 $dbo->execute();
7015 }
7016 }
7017 if (!count($rooms_with_carat)) {
7018 // get all rooms to unset this carat (if previously set)
7019 array_push($rooms_with_carat, '0');
7020 }
7021 // unset the carat from the other rooms that may have it
7022 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
7023 $dbo->setQuery($q);
7024 $dbo->execute();
7025 if ($dbo->getNumRows()) {
7026 $unset_rooms_carat = $dbo->loadAssocList();
7027 foreach ($unset_rooms_carat as $room_data) {
7028 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
7029 if (!in_array((string)$pwhereup, $current_carats)) {
7030 // this room is not using this carat
7031 continue;
7032 }
7033 $caratkey = array_search((string)$pwhereup, $current_carats);
7034 if ($caratkey === false) {
7035 // key not found
7036 continue;
7037 }
7038 // unset this carat ID from the string
7039 unset($current_carats[$caratkey]);
7040 if (!count($current_carats)) {
7041 // a room with no carats assigned will be listed as "0;"
7042 $current_carats = array(0);
7043 }
7044 $new_carats = implode(';', $current_carats) . ';';
7045 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7046 $dbo->setQuery($q);
7047 $dbo->execute();
7048 }
7049 }
7050 //
7051 }
7052 $mainframe = JFactory::getApplication();
7053 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7054 }
7055
7056 public function removecarat()
7057 {
7058 if (!JSession::checkToken()) {
7059 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7060 }
7061
7062 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7063 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7064 }
7065
7066 $ids = VikRequest::getVar('cid', array(0));
7067 if ($ids) {
7068 $dbo = JFactory::getDBO();
7069 foreach ($ids as $d) {
7070 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7071 $dbo->setQuery($q);
7072 $dbo->execute();
7073 if ($dbo->getNumRows() == 1) {
7074 $rows = $dbo->loadAssocList();
7075 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
7076 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
7077 }
7078 }
7079 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7080 $dbo->setQuery($q);
7081 $dbo->execute();
7082 }
7083 }
7084 $mainframe = JFactory::getApplication();
7085 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7086 }
7087
7088 public function coupons() {
7089 VikBookingHelper::printHeader("17");
7090
7091 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
7092
7093 parent::display();
7094
7095 if (VikBooking::showFooter()) {
7096 VikBookingHelper::printFooter();
7097 }
7098 }
7099
7100 public function newcoupon() {
7101 VikBookingHelper::printHeader("17");
7102
7103 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7104
7105 parent::display();
7106
7107 if (VikBooking::showFooter()) {
7108 VikBookingHelper::printFooter();
7109 }
7110 }
7111
7112 public function editcoupon() {
7113 VikBookingHelper::printHeader("17");
7114
7115 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7116
7117 parent::display();
7118
7119 if (VikBooking::showFooter()) {
7120 VikBookingHelper::printFooter();
7121 }
7122 }
7123
7124 public function createcoupon()
7125 {
7126 if (!JSession::checkToken()) {
7127 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7128 }
7129
7130 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7131 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7132 }
7133
7134 $pcode = VikRequest::getString('code', '', 'request');
7135 $pvalue = VikRequest::getString('value', '', 'request');
7136 $pfrom = VikRequest::getString('from', '', 'request');
7137 $pto = VikRequest::getString('to', '', 'request');
7138 $pidrooms = VikRequest::getVar('idrooms', array(0));
7139 $ptype = VikRequest::getString('type', '', 'request');
7140 $ptype = $ptype == "1" ? 1 : 2;
7141 $ppercentot = VikRequest::getString('percentot', '', 'request');
7142 $ppercentot = $ppercentot == "1" ? 1 : 2;
7143 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7144 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7145 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7146 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7147 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7148 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7149 $pcustomers = VikRequest::getVar('customers', array());
7150 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7151 $stridrooms = "";
7152 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7153 foreach ($pidrooms as $ch) {
7154 if (!empty($ch)) {
7155 $stridrooms .= ";".$ch.";";
7156 }
7157 }
7158 }
7159 $strdatevalid = "";
7160 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7161 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7162 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7163 if ($first < $second) {
7164 $strdatevalid .= $first."-".$second;
7165 }
7166 }
7167
7168 $dbo = JFactory::getDbo();
7169 $app = JFactory::getApplication();
7170
7171 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
7172 $dbo->setQuery($q);
7173 $dbo->execute();
7174 if ($dbo->getNumRows() > 0) {
7175 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7176 } else {
7177 $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) . ");";
7178 $dbo->setQuery($q);
7179 $dbo->execute();
7180
7181 $id_coupon = $dbo->insertid();
7182
7183 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7184
7185 // check if this coupon should be assigned to specific customers
7186 foreach ($pcustomers as $id_customer) {
7187 $customer_coupon = new stdClass;
7188 $customer_coupon->idcustomer = (int)$id_customer;
7189 $customer_coupon->idcoupon = (int)$id_coupon;
7190 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7191
7192 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7193 }
7194 }
7195 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7196 }
7197
7198 public function updatecoupon()
7199 {
7200 if (!JSession::checkToken()) {
7201 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7202 }
7203
7204 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7205 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7206 }
7207
7208 $this->do_updatecoupon($stay = false);
7209 }
7210
7211 public function updatecoupon_stay()
7212 {
7213 if (!JSession::checkToken()) {
7214 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7215 }
7216
7217 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7218 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7219 }
7220
7221 $this->do_updatecoupon($stay = true);
7222 }
7223
7224 protected function do_updatecoupon($stay = false)
7225 {
7226 if (!JSession::checkToken()) {
7227 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7228 }
7229 $pcode = VikRequest::getString('code', '', 'request');
7230 $pvalue = VikRequest::getString('value', '', 'request');
7231 $pfrom = VikRequest::getString('from', '', 'request');
7232 $pto = VikRequest::getString('to', '', 'request');
7233 $pidrooms = VikRequest::getVar('idrooms', array(0));
7234 $pwhere = VikRequest::getInt('where', 0, 'request');
7235 $ptype = VikRequest::getString('type', '', 'request');
7236 $ptype = $ptype == "1" ? 1 : 2;
7237 $ppercentot = VikRequest::getString('percentot', '', 'request');
7238 $ppercentot = $ppercentot == "1" ? 1 : 2;
7239 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7240 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7241 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7242 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7243 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7244 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7245 $pcustomers = VikRequest::getVar('customers', array());
7246 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7247 $stridrooms = "";
7248 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7249 foreach ($pidrooms as $ch) {
7250 if (!empty($ch)) {
7251 $stridrooms .= ";".$ch.";";
7252 }
7253 }
7254 }
7255 $strdatevalid = "";
7256 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7257 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7258 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7259 if ($first < $second) {
7260 $strdatevalid .= $first."-".$second;
7261 }
7262 }
7263
7264 $dbo = JFactory::getDbo();
7265 $app = JFactory::getApplication();
7266
7267 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
7268 $dbo->setQuery($q);
7269 $dbo->execute();
7270 if ($dbo->getNumRows() > 0) {
7271 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7272 } else {
7273 $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 . ";";
7274 $dbo->setQuery($q);
7275 $dbo->execute();
7276
7277 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7278
7279 // clean up any previously created record with customers
7280 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
7281 $dbo->setQuery($q);
7282 $dbo->execute();
7283
7284 // check if this coupon should be assigned to specific customers
7285 foreach ($pcustomers as $id_customer) {
7286 $customer_coupon = new stdClass;
7287 $customer_coupon->idcustomer = (int)$id_customer;
7288 $customer_coupon->idcoupon = (int)$pwhere;
7289 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7290
7291 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7292 }
7293 }
7294
7295 if ($stay) {
7296 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
7297 } else {
7298 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7299 }
7300 }
7301
7302 public function removecoupons()
7303 {
7304 if (!JSession::checkToken()) {
7305 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7306 }
7307
7308 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7309 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7310 }
7311
7312 $dbo = JFactory::getDbo();
7313
7314 $ids = VikRequest::getVar('cid', array(0));
7315
7316 if ($ids) {
7317 foreach ($ids as $d) {
7318 // delete coupon record
7319 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
7320 $dbo->setQuery($q);
7321 $dbo->execute();
7322
7323 // clean up any previously created record with customers
7324 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
7325 $dbo->setQuery($q);
7326 $dbo->execute();
7327 }
7328 }
7329
7330 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
7331 }
7332
7333 public function removemoreimgs()
7334 {
7335 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7336 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7337 }
7338
7339 $mainframe = JFactory::getApplication();
7340 $proomid = VikRequest::getInt('roomid', '', 'request');
7341 $pimgind = VikRequest::getInt('imgind', '', 'request');
7342 if (!strlen($pimgind)) {
7343 $mainframe->redirect("index.php?option=com_vikbooking");
7344 exit;
7345 }
7346 $dbo = JFactory::getDBO();
7347 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
7348 $dbo->setQuery($q);
7349 $dbo->execute();
7350 $row = $dbo->loadAssoc();
7351 $actmore = $row['moreimgs'];
7352 if (!empty($actmore)) {
7353 $actsplit = explode(';;', $actmore);
7354 $captions = json_decode($row['imgcaptions'], true);
7355 $captions = !is_array($captions) ? array() : $captions;
7356 if ($pimgind < 0) {
7357 foreach ($actsplit as $img) {
7358 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
7359 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
7360 }
7361 // reset images and captions
7362 $actsplit = array();
7363 $captions = array();
7364 } else {
7365 if (array_key_exists($pimgind, $actsplit)) {
7366 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
7367 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
7368 // unset current image
7369 unset($actsplit[$pimgind]);
7370 // unset caption if exists
7371 if (isset($captions[$pimgind])) {
7372 unset($captions[$pimgind]);
7373 $captions = array_values($captions);
7374 }
7375 }
7376 }
7377 $newstr = "";
7378 foreach ($actsplit as $oi) {
7379 if (!empty($oi)) {
7380 $newstr .= $oi.';;';
7381 }
7382 }
7383 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
7384 $dbo->setQuery($q);
7385 $dbo->execute();
7386 }
7387 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
7388 }
7389
7390 public function sortfield() {
7391 if (!JSession::checkToken('get')) {
7392 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7393 }
7394 $mainframe = JFactory::getApplication();
7395 $sortid = VikRequest::getVar('cid', array(0));
7396 $pmode = VikRequest::getString('mode', '', 'request');
7397 $dbo = JFactory::getDBO();
7398 if (!empty($pmode)) {
7399 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7400 $dbo->setQuery($q);
7401 $dbo->execute();
7402 $totr=$dbo->getNumRows();
7403 if ($totr > 1) {
7404 $data = $dbo->loadAssocList();
7405 if ($pmode == "up") {
7406 foreach ($data as $v) {
7407 if ($v['id'] == $sortid[0]) {
7408 $y = $v['ordering'];
7409 }
7410 }
7411 if ($y && $y > 1) {
7412 $vik = $y - 1;
7413 $found = false;
7414 foreach ($data as $v) {
7415 if (intval($v['ordering']) == intval($vik)) {
7416 $found=true;
7417 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7418 $dbo->setQuery($q);
7419 $dbo->execute();
7420 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7421 $dbo->setQuery($q);
7422 $dbo->execute();
7423 break;
7424 }
7425 }
7426 if (!$found) {
7427 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7428 $dbo->setQuery($q);
7429 $dbo->execute();
7430 }
7431 }
7432 } elseif ($pmode == "down") {
7433 foreach ($data as $v) {
7434 if ($v['id'] == $sortid[0]) {
7435 $y = $v['ordering'];
7436 }
7437 }
7438 if ($y) {
7439 $vik = $y + 1;
7440 $found = false;
7441 foreach ($data as $v) {
7442 if (intval($v['ordering']) == intval($vik)) {
7443 $found=true;
7444 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7445 $dbo->setQuery($q);
7446 $dbo->execute();
7447 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7448 $dbo->setQuery($q);
7449 $dbo->execute();
7450 break;
7451 }
7452 }
7453 if (!$found) {
7454 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7455 $dbo->setQuery($q);
7456 $dbo->execute();
7457 }
7458 }
7459 }
7460 }
7461 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7462 } else {
7463 $mainframe->redirect("index.php?option=com_vikbooking");
7464 }
7465 }
7466
7467 public function customf() {
7468 VikBookingHelper::printHeader("16");
7469
7470 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7471
7472 parent::display();
7473
7474 if (VikBooking::showFooter()) {
7475 VikBookingHelper::printFooter();
7476 }
7477 }
7478
7479 public function newcustomf() {
7480 VikBookingHelper::printHeader("16");
7481
7482 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7483
7484 parent::display();
7485
7486 if (VikBooking::showFooter()) {
7487 VikBookingHelper::printFooter();
7488 }
7489 }
7490
7491 public function editcustomf() {
7492 VikBookingHelper::printHeader("16");
7493
7494 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7495
7496 parent::display();
7497
7498 if (VikBooking::showFooter()) {
7499 VikBookingHelper::printFooter();
7500 }
7501 }
7502
7503 public function createcustomf()
7504 {
7505 if (!JSession::checkToken()) {
7506 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7507 }
7508
7509 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7510 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7511 }
7512
7513 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7514 $ptype = VikRequest::getString('type', '', 'request');
7515 $pchoose = VikRequest::getVar('choose', array(0));
7516 $prequired = VikRequest::getString('required', '', 'request');
7517 $prequired = $prequired == "1" ? 1 : 0;
7518 $pflag = VikRequest::getString('flag', '', 'request');
7519 $pisemail = $pflag == 'isemail' ? 1 : 0;
7520 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7521 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7522 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7523 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7524 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7525 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7526 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7527 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7528 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7529 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7530 $fieldflag = '';
7531 if ($pisaddress == 1) {
7532 $fieldflag = 'address';
7533 } elseif ($piscity == 1) {
7534 $fieldflag = 'city';
7535 } elseif ($piszip == 1) {
7536 $fieldflag = 'zip';
7537 } elseif ($piscompany == 1) {
7538 $fieldflag = 'company';
7539 } elseif ($pisvat == 1) {
7540 $fieldflag = 'vat';
7541 } elseif ($pisfisccode == 1) {
7542 $fieldflag = 'fisccode';
7543 } elseif ($pispec == 1) {
7544 $fieldflag = 'pec';
7545 } elseif ($pisrecipcode == 1) {
7546 $fieldflag = 'recipcode';
7547 }
7548 $ppoplink = VikRequest::getString('poplink', '', 'request');
7549 $choosestr = "";
7550 if (is_array($pchoose)) {
7551 foreach ($pchoose as $ch) {
7552 if (!empty($ch)) {
7553 $choosestr .= $ch.";;__;;";
7554 }
7555 }
7556 }
7557 $defvalue = VikRequest::getString('defvalue', '', 'request');
7558
7559 $dbo = JFactory::getDbo();
7560
7561 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7562 $dbo->setQuery($q);
7563 $dbo->execute();
7564 if ($dbo->getNumRows() == 1) {
7565 $getlast = $dbo->loadResult();
7566 $newsortnum = $getlast + 1;
7567 } else {
7568 $newsortnum = 1;
7569 }
7570 $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).");";
7571 $dbo->setQuery($q);
7572 $dbo->execute();
7573 $mainframe = JFactory::getApplication();
7574 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7575 }
7576
7577 public function updatecustomf()
7578 {
7579 if (!JSession::checkToken()) {
7580 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7581 }
7582
7583 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7584 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7585 }
7586
7587 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7588 $ptype = VikRequest::getString('type', '', 'request');
7589 $pchoose = VikRequest::getVar('choose', array(0));
7590 $prequired = VikRequest::getString('required', '', 'request');
7591 $prequired = $prequired == "1" ? 1 : 0;
7592 $pflag = VikRequest::getString('flag', '', 'request');
7593 $pisemail = $pflag == 'isemail' ? 1 : 0;
7594 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7595 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7596 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7597 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7598 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7599 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7600 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7601 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7602 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7603 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7604 $fieldflag = '';
7605 if ($pisaddress == 1) {
7606 $fieldflag = 'address';
7607 } elseif ($piscity == 1) {
7608 $fieldflag = 'city';
7609 } elseif ($piszip == 1) {
7610 $fieldflag = 'zip';
7611 } elseif ($piscompany == 1) {
7612 $fieldflag = 'company';
7613 } elseif ($pisvat == 1) {
7614 $fieldflag = 'vat';
7615 } elseif ($pisfisccode == 1) {
7616 $fieldflag = 'fisccode';
7617 } elseif ($pispec == 1) {
7618 $fieldflag = 'pec';
7619 } elseif ($pisrecipcode == 1) {
7620 $fieldflag = 'recipcode';
7621 }
7622 $ppoplink = VikRequest::getString('poplink', '', 'request');
7623 $pwhere = VikRequest::getInt('where', '', 'request');
7624 $choosestr = "";
7625 if (is_array($pchoose)) {
7626 foreach ($pchoose as $ch) {
7627 if (!empty($ch)) {
7628 $choosestr .= $ch.";;__;;";
7629 }
7630 }
7631 }
7632 $defvalue = VikRequest::getString('defvalue', '', 'request');
7633
7634 $dbo = JFactory::getDbo();
7635
7636 $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).";";
7637 $dbo->setQuery($q);
7638 $dbo->execute();
7639 $mainframe = JFactory::getApplication();
7640 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7641 }
7642
7643 public function removecustomf()
7644 {
7645 if (!JSession::checkToken()) {
7646 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7647 }
7648
7649 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7650 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7651 }
7652
7653 $ids = VikRequest::getVar('cid', array(0));
7654 if ($ids) {
7655 $dbo = JFactory::getDBO();
7656 foreach ($ids as $d) {
7657 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7658 $dbo->setQuery($q);
7659 $dbo->execute();
7660 }
7661 }
7662 $mainframe = JFactory::getApplication();
7663 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7664 }
7665
7666 public function overv() {
7667 VikBookingHelper::printHeader("15");
7668
7669 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7670
7671 parent::display();
7672
7673 if (VikBooking::showFooter()) {
7674 VikBookingHelper::printFooter();
7675 }
7676 }
7677
7678 public function translations() {
7679 VikBookingHelper::printHeader("21");
7680
7681 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7682
7683 parent::display();
7684
7685 if (VikBooking::showFooter()) {
7686 VikBookingHelper::printFooter();
7687 }
7688 }
7689
7690 public function savetranslation() {
7691 if (!JSession::checkToken()) {
7692 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7693 }
7694 $this->do_savetranslation();
7695 }
7696
7697 public function savetranslationstay() {
7698 if (!JSession::checkToken()) {
7699 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7700 }
7701 $this->do_savetranslation(true);
7702 }
7703
7704 private function do_savetranslation($stay = false) {
7705 $dbo = JFactory::getDBO();
7706 $mainframe = JFactory::getApplication();
7707 $vbo_tn = VikBooking::getTranslator();
7708 $table = VikRequest::getString('vbo_table', '', 'request');
7709 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7710 $langs = $vbo_tn->getLanguagesList();
7711 $xml_tables = $vbo_tn->getTranslationTables();
7712 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7713 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7714 $tn_saved = 0;
7715 $table_cols = $vbo_tn->getTableColumns($table);
7716 foreach ($langs as $ltag => $lang) {
7717 if ($ltag == $vbo_tn->default_lang) {
7718 continue;
7719 }
7720 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7721 foreach ($tn[$ltag] as $reference_id => $translation) {
7722 $lang_translation = array();
7723 foreach ($table_cols as $field => $fdetails) {
7724 if (!array_key_exists($field, $translation)) {
7725 continue;
7726 }
7727 $ftype = $fdetails['type'];
7728 if ($ftype == 'skip') {
7729 continue;
7730 }
7731
7732 if (is_array($translation[$field])) {
7733 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7734 if (!is_string($tn_field_v)) {
7735 continue;
7736 }
7737 // replace any possible placeholder for special tags
7738 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7739 return $match[2];
7740 }, $translation[$field][$tn_field_k]);
7741 }
7742 } elseif (!empty($translation[$field])) {
7743 // replace any possible placeholder for special tags
7744 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7745 return $match[2];
7746 }, $translation[$field]);
7747 }
7748
7749 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7750 $translation[$field] = json_encode($translation[$field]);
7751 }
7752 $lang_translation[$field] = $translation[$field];
7753 }
7754 if (count($lang_translation) > 0) {
7755 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7756 $dbo->setQuery($q);
7757 $dbo->execute();
7758 if ($dbo->getNumRows() > 0) {
7759 $last_id = $dbo->loadResult();
7760 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7761 } else {
7762 $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)).");";
7763 }
7764 $dbo->setQuery($q);
7765 $dbo->execute();
7766 $tn_saved++;
7767 }
7768 }
7769 }
7770 }
7771 if ($tn_saved > 0) {
7772 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7773 }
7774 } else {
7775 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7776 }
7777 $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);
7778 }
7779
7780 public function choosebusy() {
7781 VikBookingHelper::printHeader("8");
7782
7783 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7784
7785 parent::display();
7786
7787 if (VikBooking::showFooter()) {
7788 VikBookingHelper::printFooter();
7789 }
7790 }
7791
7792 public function orders() {
7793 VikBookingHelper::printHeader("8");
7794
7795 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7796
7797 parent::display();
7798
7799 if (VikBooking::showFooter()) {
7800 VikBookingHelper::printFooter();
7801 }
7802 }
7803
7804 public function vieworders() {
7805 //alias method of orders() for backward compatibility with VCM
7806 $this->orders();
7807 }
7808
7809 public function editorder() {
7810 VikBookingHelper::printHeader("8");
7811
7812 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7813
7814 parent::display();
7815
7816 if (VikBooking::showFooter()) {
7817 VikBookingHelper::printFooter();
7818 }
7819 }
7820
7821 public function removeorders()
7822 {
7823 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7824 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7825 }
7826
7827 $dbo = JFactory::getDbo();
7828 $app = JFactory::getApplication();
7829
7830 $ids = VikRequest::getVar('cid', array(0));
7831 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7832
7833 $user = JFactory::getUser();
7834 $config = VBOFactory::getConfig();
7835
7836 $prev_conf_ids = [];
7837 $purged = false;
7838
7839 $tot_cancs = 0;
7840
7841 if (is_array($ids) && count($ids)) {
7842 foreach ($ids as $d) {
7843 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7844 $dbo->setQuery($q, 0, 1);
7845 $row = $dbo->loadAssoc();
7846
7847 // check for any cancellation constraints
7848 $canc_denied = false;
7849 if ($row && class_exists('VCMFeesCancellation')) {
7850 // let VCM detect if there are any constraints for the cancellation
7851 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7852 if ($canc_denied) {
7853 // set error message
7854 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7855 if ($canc_deny_error) {
7856 $app->enqueueMessage($canc_deny_error, 'error');
7857 }
7858 }
7859 }
7860
7861 if ($row && !$canc_denied) {
7862 // increase counter
7863 $tot_cancs++;
7864
7865 // set status to cancelled
7866 if ($row['status'] != 'cancelled') {
7867 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7868 $dbo->setQuery($q);
7869 $dbo->execute();
7870 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7871 $dbo->setQuery($q);
7872 $dbo->execute();
7873 if ($row['status'] == 'confirmed') {
7874 $prev_conf_ids[] = $row['id'];
7875 }
7876 // Booking History
7877 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7878 }
7879
7880 // free records up
7881 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7882 $dbo->setQuery($q);
7883 $ordbusy = $dbo->loadAssocList();
7884 if ($ordbusy) {
7885 foreach ($ordbusy as $ob) {
7886 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7887 $dbo->setQuery($q);
7888 $dbo->execute();
7889 }
7890 }
7891
7892 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7893 $dbo->setQuery($q);
7894 $dbo->execute();
7895
7896 // check for purge removal
7897 if ($row['status'] == 'cancelled') {
7898 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7899 $dbo->setQuery($q);
7900 $dbo->execute();
7901 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7902 $dbo->setQuery($q);
7903 $dbo->execute();
7904 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7905 $dbo->setQuery($q);
7906 $dbo->execute();
7907 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7908 $dbo->setQuery($q);
7909 $dbo->execute();
7910 // in case of split stay booking, remove the transient
7911 if ($row['split_stay']) {
7912 $config->remove('split_stay_' . $row['id']);
7913 }
7914 // turn flag on
7915 $purged = true;
7916 }
7917 }
7918 }
7919
7920 if ($tot_cancs) {
7921 // enqueue system message
7922 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7923 }
7924 }
7925
7926 if ($prev_conf_ids) {
7927 $prev_conf_ids_str = '';
7928 foreach ($prev_conf_ids as $prev_id) {
7929 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7930 }
7931 //Invoke Channel Manager
7932 $vcm_autosync = VikBooking::vcmAutoUpdate();
7933 if ($vcm_autosync > 0) {
7934 $vcm_obj = VikBooking::getVcmInvoker();
7935 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7936 $sync_result = $vcm_obj->doSync();
7937 if ($sync_result === false) {
7938 $vcm_err = $vcm_obj->getError();
7939 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7940 }
7941 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7942 $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');
7943 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7944 }
7945 //
7946 }
7947
7948 if (!empty($pgoto)) {
7949 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7950 if ($purged) {
7951 // go back to the bookings list page
7952 $app->redirect("index.php?option=com_vikbooking&task=orders");
7953 } else {
7954 // go back to the booking details page
7955 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7956 }
7957 exit;
7958 }
7959 // we expect the goto URL to be base64 encoded
7960 $app->redirect(base64_decode($pgoto));
7961 exit;
7962 }
7963
7964 // go back to the bookings list page
7965 $app->redirect("index.php?option=com_vikbooking&task=orders");
7966 }
7967
7968 public function config() {
7969 VikBookingHelper::printHeader("11");
7970
7971 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7972
7973 parent::display();
7974
7975 if (VikBooking::showFooter()) {
7976 VikBookingHelper::printFooter();
7977 }
7978 }
7979
7980 public function saveconfig()
7981 {
7982 if (!JSession::checkToken()) {
7983 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7984 }
7985
7986 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking') || !JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
7987 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7988 }
7989
7990 $dbo = JFactory::getDbo();
7991 $app = JFactory::getApplication();
7992
7993 $config = VBOFactory::getConfig();
7994
7995 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7996 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7997 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
7998 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
7999 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
8000 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
8001 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
8002 $pdateformat = VikRequest::getString('dateformat', '', 'request');
8003 $pdatesep = VikRequest::getString('datesep', '', 'request');
8004 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
8005 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
8006 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
8007 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
8008 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
8009 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
8010 $ptokenform = VikRequest::getString('tokenform', '', 'request');
8011 $padminemail = VikRequest::getString('adminemail', '', 'request');
8012 $psenderemail = VikRequest::getString('senderemail', '', 'request');
8013 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
8014 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
8015 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
8016 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
8017 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
8018 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
8019 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
8020 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
8021 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
8022 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
8023 $pusefa = VikRequest::getInt('usefa', '', 'request');
8024 $pusefa = $pusefa > 0 ? 1 : 0;
8025 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
8026 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
8027 $pcalendar = VikRequest::getString('calendar', '', 'request');
8028 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
8029 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
8030 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
8031 $penablepin = VikRequest::getString('enablepin', '', 'request');
8032 $penablepin = $penablepin == "1" ? 1 : 0;
8033 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
8034 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
8035 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
8036 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
8037 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
8038 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
8039 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
8040 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
8041 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
8042 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
8043 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
8044 $pnumadultsfrom = '1';
8045 $pnumadultsto = '10';
8046 }
8047 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
8048 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
8049 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
8050 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
8051 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
8052 $pnumadultsfrom = '1';
8053 $pnumadultsto = '4';
8054 }
8055 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
8056 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
8057 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
8058 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
8059 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
8060 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
8061 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
8062 $pcronkey = VikRequest::getString('cronkey', '', 'request');
8063 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
8064 $pcdsto = VikRequest::getVar('cdsto', array());
8065 $closing_dates = array();
8066 if (count($pcdsfrom)) {
8067 foreach ($pcdsfrom as $kcd => $vcdfrom) {
8068 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
8069 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
8070 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
8071 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
8072 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
8073 if (!in_array($cdval, $closing_dates)) {
8074 $closing_dates[] = $cdval;
8075 }
8076 }
8077 }
8078 }
8079 }
8080 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
8081 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
8082 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
8083 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8084 if ($pvbosef === 1) {
8085 if (!$vbosef) {
8086 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8087 }
8088 } else {
8089 if ($vbosef) {
8090 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
8091 }
8092 }
8093 $pmultilang = VikRequest::getString('multilang', '', 'request');
8094 $pmultilang = $pmultilang == "1" ? 1 : 0;
8095 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
8096 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
8097 /**
8098 * Chat params and configuration settings
8099 *
8100 * @since 1.12
8101 */
8102 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
8103 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
8104 $config->set('chatenabled', $pchatenabled);
8105
8106 // chat params
8107 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
8108 $chat_res_status = array();
8109 foreach ($pchat_res_status as $chatrs) {
8110 if (!empty($chatrs)) {
8111 array_push($chat_res_status, $chatrs);
8112 }
8113 }
8114 $chatparams = new stdClass;
8115 $chatparams->res_status = $chat_res_status;
8116 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
8117 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
8118
8119 $config->set('chatparams', $chatparams);
8120 }
8121
8122 /**
8123 * Pre check-in configuration settings
8124 *
8125 * @since 1.12
8126 */
8127 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
8128 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
8129
8130 $config->set('precheckinenabled', $pprecheckinenabled);
8131 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
8132
8133 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
8134 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
8135 $config->set('upselling', $pupsellingenabled);
8136
8137 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
8138 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
8139 $config->set('orphanscalculation', $porphanscal);
8140
8141 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
8142 $config->set('searchrestmpl', $psrcrtpl);
8143
8144 /**
8145 * Guest Reviews settings
8146 *
8147 * @since 1.13
8148 */
8149 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
8150 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
8151 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
8152 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
8153 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
8154 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
8155 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
8156 $config->set('grenabled', $pgrenabled);
8157 $config->set('grminchars', $pgrminchars);
8158 $config->set('grappr', $pgrappr);
8159 $config->set('grtype', $pgrtype);
8160 try {
8161 // always truncate service names (this query may require special permissions)
8162 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
8163 $dbo->setQuery($q);
8164 $dbo->execute();
8165 } catch (Exception $e) {
8166 // do nothing
8167 }
8168 foreach ($pgrsrv as $srvname) {
8169 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
8170 $dbo->setQuery($q);
8171 $dbo->execute();
8172 }
8173
8174 /**
8175 * Preferred countries ordering, or custom countries.
8176 *
8177 * @since 1.14 (J) - 1.3.11 (WP)
8178 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
8179 */
8180 $pref_countries = VikRequest::getVar('pref_countries', array());
8181 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
8182 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
8183 if (!empty($cust_pref_countries)) {
8184 $all_custom_prefcountries = array();
8185 $cust_pref_countries = explode(',', $cust_pref_countries);
8186 foreach ($cust_pref_countries as $cust_pref_country) {
8187 $cust_pref_country = trim(strtolower($cust_pref_country));
8188 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
8189 continue;
8190 }
8191 array_push($all_custom_prefcountries, $cust_pref_country);
8192 }
8193 if (count($all_custom_prefcountries)) {
8194 $pref_countries = $all_custom_prefcountries;
8195 }
8196 }
8197 $config->set('preferred_countries', $pref_countries);
8198 //
8199
8200 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
8201 $config->set('gmapskey', $gmapskey);
8202
8203 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
8204 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
8205 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
8206 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
8207 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
8208 $pref_colors = array(
8209 'textcolor' => $pref_textcolor,
8210 'bgcolor' => $pref_bgcolor,
8211 'fontcolor' => $pref_fontcolor,
8212 'bgcolorhov' => $pref_bgcolorhov,
8213 'fontcolorhov' => $pref_fontcolorhov,
8214 );
8215 $config->set('pref_colors', $pref_colors);
8216
8217 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
8218 $config->set('interactive_map', $interactive_map);
8219
8220 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
8221 $config->set('noemptydecimals', $noemptydecimals);
8222
8223 /**
8224 * Appearance preferences (light, auto, dark mode).
8225 *
8226 * @since 1.15.0 (J) - 1.5.0 (WP)
8227 * @since 1.16.10 (J) - 1.6.10 (WP) mirrored on VCM.
8228 */
8229 $appearance_pref = VikRequest::getString('appearance_pref', '');
8230 $config->set('appearance_pref', $appearance_pref);
8231 if (class_exists('VCMFactory')) {
8232 VCMFactory::getConfig()->set('appearance_pref', $appearance_pref);
8233 }
8234
8235 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
8236 $picon = "";
8237 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
8238 jimport('joomla.filesystem.file');
8239 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
8240 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
8241 if (file_exists($res_backend_path.$safename)) {
8242 $j = 1;
8243 while (file_exists($res_backend_path.$j.$safename)) {
8244 $j++;
8245 }
8246 $pwhere = $res_backend_path.$j.$safename;
8247 } else {
8248 $j = "";
8249 $pwhere = $res_backend_path.$safename;
8250 }
8251 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8252 @unlink($pwhere);
8253 $picon = "";
8254 } else {
8255 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
8256 @chmod($pwhere, 0644);
8257 $picon = $j.$safename;
8258 }
8259 }
8260 if (!empty($picon)) {
8261 $config->set('sitelogo', $picon);
8262 }
8263 }
8264 $pbackicon = "";
8265 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
8266 jimport('joomla.filesystem.file');
8267 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
8268 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
8269 if (file_exists($res_backend_path.$safename)) {
8270 $j = 1;
8271 while (file_exists($res_backend_path.$j.$safename)) {
8272 $j++;
8273 }
8274 $pwhere = $res_backend_path.$j.$safename;
8275 } else {
8276 $j = "";
8277 $pwhere = $res_backend_path.$safename;
8278 }
8279 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8280 @unlink($pwhere);
8281 $pbackicon = "";
8282 } else {
8283 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
8284 @chmod($pwhere, 0644);
8285 $pbackicon = $j.$safename;
8286 }
8287 }
8288 if (!empty($pbackicon)) {
8289 $config->set('backlogo', $pbackicon);
8290 }
8291 }
8292 $config->set('vcmautoupd', $pvcmautoupd);
8293 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
8294 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
8295 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
8296 $config->set('searchsuggestions', $psearchsuggestions);
8297 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
8298 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
8299
8300 // translatable text
8301 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
8302 $dbo->setQuery($q);
8303 $dbo->execute();
8304
8305 // translatable text
8306 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
8307 $dbo->setQuery($q);
8308 $dbo->execute();
8309
8310 // translatable text
8311 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
8312 $dbo->setQuery($q);
8313 $dbo->execute();
8314
8315 // terms and conditions
8316 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
8317 $dbo->setQuery($q);
8318 $dbo->execute();
8319 if ($dbo->getNumRows() > 0) {
8320 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
8321 $dbo->setQuery($q);
8322 $dbo->execute();
8323 } else {
8324 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
8325 $dbo->setQuery($q);
8326 $dbo->execute();
8327 }
8328
8329 $config->set('adminemail', $padminemail);
8330 $config->set('senderemail', $psenderemail);
8331 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
8332 $config->set('datesep', $pdatesep);
8333 $config->set('resmodcanc', $presmodcanc);
8334 $config->set('resmodcancmin', $presmodcancmin);
8335 $config->set('minuteslock', $pminuteslock);
8336 $config->set('minautoremove', $pminautoremove);
8337
8338 $openingh = $ptimeopenstorefh * 3600;
8339 $openingm = $ptimeopenstorefm * 60;
8340 $openingts = $openingh + $openingm;
8341 $closingh = $ptimeopenstoreth * 3600;
8342 $closingm = $ptimeopenstoretm * 60;
8343 $closingts = $closingh + $closingm;
8344 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
8345 $prevtimes = $config->get('timeopenstore', '');
8346 if ($prevtimes != $openingts . "-" . $closingts) {
8347 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
8348 $dbo->setQuery($q);
8349 $dbo->execute();
8350 if ($dbo->getNumRows() > 0) {
8351 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
8352 /**
8353 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
8354 * for all reservations to avoid issues with the availability.
8355 *
8356 * @since August 29th 2018
8357 */
8358 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>');
8359 //
8360 }
8361 }
8362 $config->set('timeopenstore', $openingts . "-" . $closingts);
8363
8364 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
8365 $phoursmorebookingback = "0";
8366 if ($closingts > $openingts) {
8367 $diffcheck = ($closingts - $openingts) / 3600;
8368 $phoursmorebookingback = ceil($diffcheck);
8369 }
8370 $config->set('hoursmorebookingback', $phoursmorebookingback);
8371 $config->set('hoursmoreroomavail', '0');
8372 $config->set('multilang', $pmultilang);
8373 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
8374 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
8375 $config->set('todaybookings', $ptodaybookings);
8376 $config->set('bootstrap', $ploadbootstrap);
8377 $config->set('usefa', $pusefa);
8378 $config->set('loadjquery', $ploadjquery);
8379 $config->set('calendar', $pcalendar);
8380 $config->set('enablecoupons', $penablecoupons);
8381 $config->set('enablepin', $penablepin);
8382 $config->set('mindaysadvance', $pmindaysadvance);
8383 $config->set('autodefcalnights', $pautodefcalnights);
8384 $config->set('numrooms', $pnumrooms);
8385 $config->set('numadults', $confnumadults);
8386 $config->set('numchildren', $confnumchildren);
8387 $config->set('closingdates', $closing_dates);
8388 $config->set('smartsearch', $psmartsearch);
8389 $config->set('maxdate', $maxdate_str);
8390 $config->set('cronkey', $pcronkey);
8391
8392 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
8393 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
8394 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
8395 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
8396 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
8397 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
8398 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
8399 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
8400 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
8401 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
8402 $pnumdecimals = intval($pnumdecimals);
8403 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
8404 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
8405 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
8406 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
8407 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
8408 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
8409 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
8410 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
8411 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
8412 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
8413 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
8414 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
8415 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
8416 $pbctagname = VikRequest::getVar('bctagname', array());
8417 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
8418 $pbctagrule = VikRequest::getVar('bctagrule', array());
8419 $bctags_arr = array();
8420 $bctags_rules = array();
8421 if (count($pbctagname) > 0) {
8422 foreach ($pbctagname as $bctk => $bctv) {
8423 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
8424 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
8425 $bctags_rules[] = $pbctagrule[$bctk];
8426 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8427 }
8428 }
8429 }
8430 }
8431 //theme
8432 $ptheme = VikRequest::getString('theme', '', 'request');
8433 if (empty($ptheme) || $ptheme == 'default') {
8434 $ptheme = 'default';
8435 } else {
8436 $validtheme = false;
8437 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8438 if (count($themes) > 0) {
8439 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8440 foreach ($themes as $th) {
8441 if (is_dir($th)) {
8442 $tname = str_replace($strip, '', $th);
8443 if ($tname == $ptheme) {
8444 $validtheme = true;
8445 break;
8446 }
8447 }
8448 }
8449 }
8450 if ($validtheme == false) {
8451 $ptheme = 'default';
8452 }
8453 }
8454 $config->set('theme', $ptheme);
8455 //
8456 $config->set('showpartlyreserved', $pshowpartlyreserved);
8457 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8458 $config->set('numcalendars', $pnumcalendars);
8459
8460 // record may not be set
8461 $config->set('thumbsize', $pthumbsize);
8462
8463 $config->set('firstwday', $pfirstwday);
8464
8465 // translatable text
8466 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8467 $dbo->setQuery($q);
8468 $dbo->execute();
8469
8470 $config->set('fronttitletag', $pfronttitletag);
8471 $config->set('fronttitletagclass', $pfronttitletagclass);
8472 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8473
8474 // translatable texts
8475 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8476 $dbo->setQuery($q);
8477 $dbo->execute();
8478 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8479 $dbo->setQuery($q);
8480 $dbo->execute();
8481
8482 $config->set('currencyname', $pcurrencyname);
8483 $config->set('currencysymb', $pcurrencysymb);
8484 $config->set('currencycodepp', $pcurrencycodepp);
8485 $config->set('numberformat', $numberformatstr);
8486 // bookings color tags
8487 $config->set('bookingsctags', $bctags_arr);
8488
8489 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8490 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8491 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8492 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8493 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8494 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8495 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8496 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8497 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8498 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8499 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8500 $pmultipay = VikRequest::getString('multipay', '', 'request');
8501 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8502 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8503 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8504 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8505 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8506
8507 // translatable text
8508 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8509 $dbo->setQuery($q);
8510 $dbo->execute();
8511 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8512 $dbo->setQuery($q);
8513 $dbo->execute();
8514
8515 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8516 $config->set('taxsummary', $ptaxsummary);
8517 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8518
8519 $config->set('ccpaypal', $pccpaypal);
8520 $config->set('payaccpercent', $ppayaccpercent);
8521 $config->set('typedeposit', $ptypedeposit);
8522 $config->set('depoverrides', $pdepoverrides);
8523 $config->set('multipay', $pmultipay);
8524 $config->set('depifdaysadv', $pdepifdaysadv);
8525 $config->set('nodepnonrefund', $pnodepnonrefund);
8526 $config->set('depcustchoice', $pdepcustchoice);
8527
8528 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8529 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8530 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8531 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8532 $config->set('emailsendwhen', $psendemailwhen);
8533 $config->set('attachical', $pattachical);
8534
8535 // SMS APIs
8536 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8537 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8538 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8539 $psmssendto = VikRequest::getVar('smssendto', array());
8540 $sms_sendto = array();
8541 foreach ($psmssendto as $sto) {
8542 if (in_array($sto, array('admin', 'customer'))) {
8543 $sms_sendto[] = $sto;
8544 }
8545 }
8546 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8547 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8548 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8549 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8550 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8551 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8552 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8553 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8554 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8555 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8556 $smsparamarr = array();
8557 if (count($viksmsparams) > 0) {
8558 foreach ($viksmsparams as $setting => $cont) {
8559 if (strlen($setting) > 0) {
8560 $smsparamarr[$setting] = $cont;
8561 }
8562 }
8563 }
8564 $config->set('smsapi', $psmsapi);
8565 $config->set('smsautosend', $psmsautosend);
8566 $config->set('smssendto', $sms_sendto);
8567 $config->set('smssendwhen', $psmssendwhen);
8568 $config->set('smsadminphone', $psmsadminphone);
8569 $config->set('smsparams', $smsparamarr);
8570
8571 // translatable texts
8572 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8573 $dbo->setQuery($q);
8574 $dbo->execute();
8575 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8576 $dbo->setQuery($q);
8577 $dbo->execute();
8578 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8579 $dbo->setQuery($q);
8580 $dbo->execute();
8581 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8582 $dbo->setQuery($q);
8583 $dbo->execute();
8584 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8585 $dbo->setQuery($q);
8586 $dbo->execute();
8587 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8588 $dbo->setQuery($q);
8589 $dbo->execute();
8590
8591 /**
8592 * Backup settings
8593 *
8594 * @since 1.15.0 (J) - 1.5.0 (WP)
8595 */
8596 $backup_type = $app->input->getString('backuptype', 'full');
8597 $backup_folder = $app->input->getString('backupfolder', '');
8598
8599 $tmp = $app->get('tmp_path');
8600
8601 if (!$backup_folder)
8602 {
8603 // path not specified, use temporary folder
8604 $backup_folder = $tmp;
8605 }
8606
8607 $current = $config->get('backupfolder');
8608
8609 if (!$current)
8610 {
8611 // path was missing, use temporary folder
8612 $current = $tmp;
8613 }
8614
8615 // check whether the backup folder has been moved
8616 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8617 {
8618 $backupModel = new VBOModelBackup();
8619
8620 // backup folder moved, try to copy all the existing overrides
8621 if (!$backupModel->moveArchives($backup_folder))
8622 {
8623 // iterate all errors and display them
8624 foreach ($backupModel->getErrors() as $error)
8625 {
8626 $app->enqueueMessage($error, 'warning');
8627 }
8628 }
8629 }
8630
8631 // save configuration
8632 $config->set('backuptype', $backup_type);
8633 $config->set('backupfolder', $backup_folder);
8634
8635 /**
8636 * Check-in data collection type.
8637 *
8638 * @since 1.15.0 (J) - 1.5.0 (WP)
8639 */
8640 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8641
8642 /**
8643 * Front-end appearance.
8644 *
8645 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8646 */
8647 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8648
8649 /**
8650 * Split stays.
8651 *
8652 * @since 1.16.0 (J) - 1.6.0 (WP)
8653 */
8654 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8655 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8656 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8657 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8658
8659 /**
8660 * Re-build Web App manifest file to let the event trigger.
8661 *
8662 * @since 1.16.5 (J) - 1.6.5 (WP)
8663 */
8664 try {
8665 VBOWebappManifest::build();
8666 } catch (Exception $e) {
8667 // do nothing
8668 }
8669
8670 // redirect
8671 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8672 $app->redirect('index.php?option=com_vikbooking&task=config');
8673 $app->close();
8674 }
8675
8676 /**
8677 * Task to unify the check-in and check-out times for all reservations.
8678 */
8679 public function unifycheckinout()
8680 {
8681 $dbo = JFactory::getDbo();
8682 $app = JFactory::getApplication();
8683 $user = JFactory::getUser();
8684
8685 $fh = VikRequest::getInt('fh', 12, 'request');
8686 $fm = VikRequest::getInt('fm', 0, 'request');
8687 $th = VikRequest::getInt('th', 10, 'request');
8688 $tm = VikRequest::getInt('tm', 0, 'request');
8689
8690 $now = time();
8691 $totmod = 0;
8692 $totbookmod = 0;
8693
8694 // query all busy records
8695 $q = $dbo->getQuery(true)
8696 ->select('*')
8697 ->from($dbo->qn('#__vikbooking_busy'));
8698
8699 $dbo->setQuery($q);
8700 $records = $dbo->loadAssocList();
8701
8702 foreach ($records as $v) {
8703 $info_start = getdate($v['checkin']);
8704 $info_end = getdate($v['checkout']);
8705 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8706 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8707
8708 $q = $dbo->getQuery(true)
8709 ->update($dbo->qn('#__vikbooking_busy'))
8710 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8711 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8712 ->set($dbo->qn('realback') . ' = ' . $new_end)
8713 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8714
8715 $dbo->setQuery($q, 0, 1);
8716 $dbo->execute();
8717
8718 $totmod++;
8719 }
8720
8721 // query all bookings
8722 $q = $dbo->getQuery(true)
8723 ->select($dbo->qn([
8724 'id',
8725 'days',
8726 'checkin',
8727 'checkout',
8728 'total',
8729 ]))
8730 ->from($dbo->qn('#__vikbooking_orders'))
8731 ->order($dbo->qn('checkin') . ' DESC');
8732
8733 $dbo->setQuery($q);
8734 $records = $dbo->loadAssocList();
8735
8736 foreach ($records as $v) {
8737 $info_start = getdate($v['checkin']);
8738 $info_end = getdate($v['checkout']);
8739 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8740 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8741
8742 $q = $dbo->getQuery(true)
8743 ->update($dbo->qn('#__vikbooking_orders'))
8744 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8745 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8746 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8747
8748 $dbo->setQuery($q, 0, 1);
8749 $dbo->execute();
8750
8751 /**
8752 * In case the operation changed the check-in/check-out time for this booking,
8753 * store a new history record for a booking modification.
8754 *
8755 * @since 1.16.6 (J) - 1.6.6 (WP)
8756 */
8757 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8758 // Booking History
8759 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8760 }
8761
8762 $totbookmod++;
8763 }
8764
8765 $app->enqueueMessage('OK: ' . $totbookmod);
8766 $app->redirect("index.php?option=com_vikbooking&task=config");
8767 $app->close();
8768 }
8769
8770 public function savetmplfile() {
8771 if (!JSession::checkToken()) {
8772 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8773 }
8774 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8775 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8776 $mainframe = JFactory::getApplication();
8777 $exists = file_exists($fpath) ? true : false;
8778 if (!$exists) {
8779 $fpath = urldecode($fpath);
8780 }
8781 $fpath = file_exists($fpath) ? $fpath : '';
8782 if (!empty($fpath)) {
8783 $fp = fopen($fpath, 'wb');
8784 $byt = (int)fwrite($fp, $pcont);
8785 fclose($fp);
8786 if ($byt > 0) {
8787 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8788
8789 if (VBOPlatformDetection::isWordPress()) {
8790 /**
8791 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8792 */
8793 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8794 }
8795 } else {
8796 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8797 }
8798 } else {
8799 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8800 }
8801 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8802
8803 exit;
8804 }
8805
8806 public function edittmplfile() {
8807 //modal box, so we do not set menu or footer
8808
8809 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8810
8811 parent::display();
8812 }
8813
8814 public function tmplfileprew() {
8815 //modal box, so we do not set menu or footer
8816
8817 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8818
8819 parent::display();
8820 }
8821
8822 public function invoices() {
8823 VikBookingHelper::printHeader("invoices");
8824
8825 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8826
8827 parent::display();
8828
8829 if (VikBooking::showFooter()) {
8830 VikBookingHelper::printFooter();
8831 }
8832 }
8833
8834 public function newmaninvoice() {
8835 VikBookingHelper::printHeader("invoices");
8836
8837 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8838
8839 parent::display();
8840
8841 if (VikBooking::showFooter()) {
8842 VikBookingHelper::printFooter();
8843 }
8844 }
8845
8846 public function editmaninvoice() {
8847 VikBookingHelper::printHeader("invoices");
8848
8849 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8850
8851 parent::display();
8852
8853 if (VikBooking::showFooter()) {
8854 VikBookingHelper::printFooter();
8855 }
8856 }
8857
8858 public function savemaninvoice() {
8859 if (!JSession::checkToken()) {
8860 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8861 }
8862 $this->do_storemaninvoice('save');
8863 $mainframe = JFactory::getApplication();
8864 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8865 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8866 if (!empty($pgoto)) {
8867 $mainframe->redirect(base64_decode($pgoto));
8868 exit;
8869 }
8870 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8871 }
8872
8873 public function updatemaninvoice()
8874 {
8875 if (!JSession::checkToken()) {
8876 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8877 }
8878
8879 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8880 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8881 }
8882
8883 $invid = VikRequest::getInt('whereup', 0, 'request');
8884 $this->do_storemaninvoice('update', $invid);
8885 $mainframe = JFactory::getApplication();
8886 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8887 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8888 if (!empty($pgoto)) {
8889 $mainframe->redirect(base64_decode($pgoto));
8890 exit;
8891 }
8892 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8893 }
8894
8895 public function updatemaninvoicestay()
8896 {
8897 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8898 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8899 }
8900
8901 $invid = VikRequest::getInt('whereup', 0, 'request');
8902 $this->do_storemaninvoice('updatestay', $invid);
8903 $mainframe = JFactory::getApplication();
8904 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8905 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8906 if (!empty($pgoto)) {
8907 $mainframe->redirect(base64_decode($pgoto));
8908 exit;
8909 }
8910 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8911 }
8912
8913 private function do_storemaninvoice($action, $invid = 0) {
8914 $dbo = JFactory::getDBO();
8915 $mainframe = JFactory::getApplication();
8916 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8917 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8918 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8919 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8920 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8921 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8922 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8923 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8924 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8925 if (empty($pidcustomer)) {
8926 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8927 $mainframe->redirect($error_uri);
8928 exit;
8929 }
8930 $services = VikRequest::getVar('service', array());
8931 $nets = VikRequest::getVar('net', array());
8932 $aliqs = VikRequest::getVar('aliq', array());
8933 $taxs = VikRequest::getVar('tax', array());
8934 $tots = VikRequest::getVar('tot', array());
8935 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8936 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8937 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8938 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8939 VikError::raiseWarning('', 'Missing data.');
8940 $mainframe->redirect($error_uri);
8941 exit;
8942 }
8943 $rawcont = array(
8944 'rows' => array(),
8945 'totalnet' => $ptotalnet,
8946 'totaltax' => $ptotaltax,
8947 'totaltot' => $ptotaltot,
8948 'notes' => $pinvoice_notes,
8949 );
8950 foreach ($services as $k => $service) {
8951 if (empty($service)) {
8952 continue;
8953 }
8954 array_push($rawcont['rows'], array(
8955 'service' => $service,
8956 'net' => (float)$nets[$k],
8957 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8958 'tax' => (float)$taxs[$k],
8959 'tot' => (float)$tots[$k],
8960 ));
8961 }
8962 // store/update manual invoice
8963 $nowts = time();
8964 $retval = 0;
8965 if (strpos($action, 'save') !== false) {
8966 $pdffname = $nowts . '_' . rand() . '.pdf';
8967 $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)).");";
8968 $dbo->setQuery($q);
8969 $dbo->execute();
8970 $retval = $dbo->insertid();
8971 } else {
8972 // fetch old record
8973 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8974 $dbo->setQuery($q);
8975 $dbo->execute();
8976 if (!$dbo->getNumRows()) {
8977 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8978 $mainframe->redirect($error_uri);
8979 exit;
8980 }
8981 $previnvoice = $dbo->loadAssoc();
8982 //
8983 $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'].";";
8984 $dbo->setQuery($q);
8985 $dbo->execute();
8986 $retval = $previnvoice['id'];
8987 }
8988 // update config values for the invoice
8989 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8990 $dbo->setQuery($q);
8991 $dbo->execute();
8992 // generate the custom invoice
8993 $result = VikBooking::generateCustomInvoice($retval);
8994 //
8995 $nextinv = VikBooking::getNextInvoiceNumber();
8996 $updatenum = ($pinvoice_num >= $nextinv);
8997 if ($updatenum) {
8998 /**
8999 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
9000 * to avoid conflicts with the drivers for the e-invoices generation.
9001 */
9002 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9003 $dbo->setQuery($q);
9004 $dbo->execute();
9005 }
9006
9007 return $retval;
9008 }
9009
9010 public function downloadinvoices() {
9011 $ids = VikRequest::getVar('cid', array(0));
9012 if (@count($ids) > 0) {
9013 $dbo = JFactory::getDBO();
9014 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
9015 $dbo->setQuery($q);
9016 $dbo->execute();
9017 if ($dbo->getNumRows() > 0) {
9018 $invoices = $dbo->loadAssocList();
9019 if (!(count($invoices) > 1)) {
9020 //Single Invoice Download
9021 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
9022 header("Content-type:application/pdf");
9023 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
9024 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
9025 exit;
9026 }
9027 } else {
9028 //Multiple Invoices Download
9029 $to_zip = array();
9030 foreach ($invoices as $k => $invoice) {
9031 $to_zip[$k]['name'] = $invoice['file_name'];
9032 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
9033 }
9034 if (class_exists('ZipArchive')) {
9035 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
9036 $zip = new ZipArchive;
9037 $zip->open($zip_path, ZipArchive::CREATE);
9038 foreach ($to_zip as $k => $zipv) {
9039 $zip->addFile($zipv['path'], $zipv['name']);
9040 }
9041 $zip->close();
9042 header("Content-type:application/zip");
9043 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
9044 header("Content-Length:".filesize($zip_path));
9045 readfile($zip_path);
9046 unlink($zip_path);
9047 exit;
9048 } else {
9049 //Class ZipArchive does not exist
9050 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
9051 }
9052 }
9053 }
9054 }
9055 $mainframe = JFactory::getApplication();
9056 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9057 }
9058
9059 public function resendinvoices() {
9060 $ids = VikRequest::getVar('cid', array(0));
9061 $mainframe = JFactory::getApplication();
9062 if (!(count($ids) > 0)) {
9063 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9064 exit;
9065 }
9066 $dbo = JFactory::getDBO();
9067 $invoices = array();
9068 $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` ".
9069 "FROM `#__vikbooking_invoices` AS `i` " .
9070 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
9071 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
9072 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
9073 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
9074 $dbo->setQuery($q);
9075 $dbo->execute();
9076 if ($dbo->getNumRows() > 0) {
9077 $invoices = $dbo->loadAssocList();
9078 }
9079 if (!(count($invoices) > 0)) {
9080 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9081 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9082 exit;
9083 }
9084 $tot_generated = 0;
9085 $tot_sent = 0;
9086 foreach ($invoices as $bkey => $invoice) {
9087 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
9088 $invoices[$bkey] = $invoice;
9089 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
9090 if ($send_res !== false) {
9091 $tot_sent++;
9092 }
9093 }
9094 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9095 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9096 }
9097
9098 public function removeinvoices()
9099 {
9100 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9101 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9102 }
9103
9104 $ids = VikRequest::getVar('cid', array());
9105 $tot_removed = 0;
9106 $dbo = JFactory::getDbo();
9107
9108 foreach ($ids as $d) {
9109 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9110 $dbo->setQuery($q);
9111 $dbo->execute();
9112 if ($dbo->getNumRows() == 1) {
9113 $cur_invoice = $dbo->loadAssoc();
9114 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
9115 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
9116 }
9117 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9118 $dbo->setQuery($q);
9119 $dbo->execute();
9120 $tot_removed++;
9121 }
9122 }
9123
9124 $mainframe = JFactory::getApplication();
9125 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
9126 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9127 }
9128
9129 public function geninvoices()
9130 {
9131 $dbo = JFactory::getDbo();
9132 $app = JFactory::getApplication();
9133
9134 $ids = VikRequest::getVar('cid', array());
9135
9136 if (!$ids) {
9137 $app->redirect("index.php?option=com_vikbooking&task=orders");
9138 exit;
9139 }
9140
9141 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
9142 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
9143 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
9144 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
9145 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
9146 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
9147 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
9148 $pinvoice_send = $pinvoice_send > 0 ? true : false;
9149 $increment_inv = true;
9150 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
9151
9152 // if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
9153 if (count($ids) === 1) {
9154 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
9155 $dbo->setQuery($q);
9156 $dbo->execute();
9157 if ($dbo->getNumRows() == 1) {
9158 $increment_inv = false;
9159 }
9160 }
9161
9162 // get bookings
9163 $dbo->setQuery(
9164 $dbo->getQuery(true)
9165 ->select($dbo->qn('o') . '.*')
9166 ->select($dbo->qn('co.idcustomer'))
9167 ->select('CONCAT_WS(\' \', ' . $dbo->qn('c.first_name') . ', ' . $dbo->qn('c.last_name') . ') AS ' . $dbo->qn('customer_name'))
9168 ->select([
9169 $dbo->qn('c.pin', 'customer_pin'),
9170 $dbo->qn('nat.country_name'),
9171 ])
9172 ->from($dbo->qn('#__vikbooking_orders', 'o'))
9173 ->leftJoin($dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $dbo->qn('co.idorder') . ' = ' . $dbo->qn('o.id'))
9174 ->leftJoin($dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $dbo->qn('c.id') . ' = ' . $dbo->qn('co.idcustomer'))
9175 ->leftJoin($dbo->qn('#__vikbooking_countries', 'nat') . ' ON ' . $dbo->qn('nat.country_3_code') . ' = ' . $dbo->qn('o.country'))
9176 ->where($dbo->qn('o.id') . ' IN (' . implode(', ', array_map('intval', $ids)) . ')')
9177 ->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed'))
9178 ->where($dbo->qn('o.total') . ' > 0')
9179 ->order($dbo->qn('o.id') . ' ASC')
9180 );
9181
9182 $bookings = $dbo->loadAssocList();
9183
9184 if (!$bookings) {
9185 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9186 $app->redirect("index.php?option=com_vikbooking&task=orders");
9187 exit;
9188 }
9189
9190 $tot_generated = 0;
9191 $tot_sent = 0;
9192 foreach ($bookings as $bkey => $booking) {
9193 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
9194 if ($gen_res !== false && $gen_res > 0) {
9195 $tot_generated++;
9196 $pinvoice_num++;
9197 if ($pinvoice_send) {
9198 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
9199 if ($send_res !== false) {
9200 $tot_sent++;
9201 }
9202 }
9203 } else {
9204 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
9205 }
9206 }
9207
9208 if ($tot_generated > 0 && $increment_inv === true) {
9209 /**
9210 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
9211 * to avoid conflicts with the drivers for the e-invoices generation.
9212 */
9213 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9214 $dbo->setQuery($q);
9215 $dbo->execute();
9216 }
9217
9218 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
9219 $dbo->setQuery($q);
9220 $dbo->execute();
9221
9222 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
9223 $dbo->setQuery($q);
9224 $dbo->execute();
9225
9226 $app->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9227
9228 if ($pconfirmgen > 0) {
9229 $app->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
9230 } elseif (count($bookings) === 1) {
9231 // go to the back-end booking details page
9232 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
9233 } else {
9234 $app->redirect("index.php?option=com_vikbooking&task=orders");
9235 }
9236 }
9237
9238 public function optionals() {
9239 VikBookingHelper::printHeader("6");
9240
9241 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
9242
9243 parent::display();
9244
9245 if (VikBooking::showFooter()) {
9246 VikBookingHelper::printFooter();
9247 }
9248 }
9249
9250 public function newoptionals() {
9251 VikBookingHelper::printHeader("6");
9252
9253 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9254
9255 parent::display();
9256
9257 if (VikBooking::showFooter()) {
9258 VikBookingHelper::printFooter();
9259 }
9260 }
9261
9262 public function editoptional() {
9263 VikBookingHelper::printHeader("6");
9264
9265 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9266
9267 parent::display();
9268
9269 if (VikBooking::showFooter()) {
9270 VikBookingHelper::printFooter();
9271 }
9272 }
9273
9274 public function updateoptional()
9275 {
9276 if (!JSession::checkToken()) {
9277 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9278 }
9279
9280 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9281 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9282 }
9283
9284 $this->do_updateoptional();
9285 }
9286
9287 public function updateoptionalstay()
9288 {
9289 if (!JSession::checkToken()) {
9290 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9291 }
9292
9293 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9294 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9295 }
9296
9297 $this->do_updateoptional(true);
9298 }
9299
9300 private function do_updateoptional($stay = false) {
9301 $dbo = JFactory::getDbo();
9302 $app = JFactory::getApplication();
9303 $poptname = VikRequest::getString('optname', '', 'request');
9304 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9305 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9306 $poptperday = VikRequest::getString('optperday', '', 'request');
9307 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9308 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9309 $popthmany = VikRequest::getString('opthmany', '', 'request');
9310 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9311 $pwhereup = VikRequest::getString('whereup', '', 'request');
9312 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9313 $presizeto = VikRequest::getString('resizeto', '', 'request');
9314 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9315 $pifchildren = $pifchildren == "1" ? 1 : 0;
9316 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9317 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9318 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9319 $pforceval = VikRequest::getString('forceval', '', 'request');
9320 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9321 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9322 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9323 $pforcesel = $pforcesel == "1" ? 1 : 0;
9324 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9325 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9326 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9327 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9328 $pagefrom = VikRequest::getVar('agefrom', array());
9329 $pageto = VikRequest::getVar('ageto', array());
9330 $pagecost = VikRequest::getVar('agecost', array());
9331 $pagectype = VikRequest::getVar('agectype', array());
9332 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9333 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9334 $pavto = VikRequest::getString('avto', '', 'request');
9335 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9336 $pidrooms = VikRequest::getVar('idrooms', array());
9337 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9338 if ($pforcesel == 1) {
9339 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9340 } else {
9341 $strforceval = "";
9342 }
9343 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9344 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9345 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9346 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9347 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9348 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9349 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9350 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9351 $minguests = VikRequest::getInt('minguests', 0, 'request');
9352 $minguests_conflict = false;
9353 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9354 if ($minguestsnum >= $maxguestsnum) {
9355 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9356 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9357 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9358 }
9359 }
9360 if (!$minguests || $minguests_conflict !== false) {
9361 $minguestsnum = 0;
9362 $maxguestsnum = 0;
9363 if ($minguests_conflict !== false) {
9364 // raise warning, but do not stop the process
9365 VikError::raiseWarning('', $minguests_conflict);
9366 }
9367 }
9368 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9369 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9370 $oparams = array(
9371 'minguestsnum' => $minguestsnum,
9372 'mingueststype' => $mingueststype,
9373 'maxguestsnum' => $maxguestsnum,
9374 'maxgueststype' => $maxgueststype,
9375 'damagedep' => $damagedep,
9376 'pet_fee' => $pet_fee,
9377 );
9378 /**
9379 * We fetch the previous params to merge them with the new ones
9380 * in case some properties have been set somewhere else.
9381 * For example, the damage deposit transmission to Booking.com.
9382 */
9383 $cur_oparams = array();
9384 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
9385 $dbo->setQuery($q);
9386 $dbo->execute();
9387 if ($dbo->getNumRows()) {
9388 $cur_oparams = $dbo->loadResult();
9389 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
9390 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
9391 // merge previous params with the new ones to get the new values
9392 $oparams = array_merge($cur_oparams, $oparams);
9393 }
9394 //
9395 if (!empty($poptname)) {
9396 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9397 jimport('joomla.filesystem.file');
9398 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9399 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9400 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9401 if (file_exists($updpath.$safename)) {
9402 $j=1;
9403 while (file_exists($updpath.$j.$safename)) {
9404 $j++;
9405 }
9406 $pwhere=$updpath.$j.$safename;
9407 } else {
9408 $j="";
9409 $pwhere=$updpath.$safename;
9410 }
9411 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9412 @unlink($pwhere);
9413 $picon="";
9414 } else {
9415 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9416 @chmod($pwhere, 0644);
9417 $picon=$j.$safename;
9418 if ($pautoresize=="1" && !empty($presizeto)) {
9419 $eforj = new vikResizer();
9420 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9421 if ($origmod) {
9422 @unlink($pwhere);
9423 $picon='r_'.$j.$safename;
9424 }
9425 }
9426 }
9427 } else {
9428 $picon="";
9429 }
9430 } else {
9431 $picon="";
9432 }
9433 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
9434 $poptperperson=($poptperperson=="each" ? "1" : "0");
9435 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
9436 $ageintervalstr = '';
9437 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9438 foreach ($pagefrom as $kage => $vage) {
9439 $afrom = intval($vage);
9440 $ato = intval($pageto[$kage]);
9441 $acost = floatval($pagecost[$kage]);
9442 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9443 if ($ato < $afrom) $ato = $afrom;
9444 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9445 }
9446 }
9447 $ageintervalstr = rtrim($ageintervalstr, ';;');
9448 if (!empty($ageintervalstr)) {
9449 $pforcesel = 1;
9450 }
9451 }
9452 $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).";";
9453 $dbo->setQuery($q);
9454 $dbo->execute();
9455 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
9456
9457 // assign/unset option-rooms relations
9458 $rooms_with_opt = array();
9459 if (count($pidrooms)) {
9460 // assign this new option to the requested rooms
9461 foreach ($pidrooms as $idroom) {
9462 if (empty($idroom)) {
9463 continue;
9464 }
9465 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9466 $dbo->setQuery($q);
9467 $dbo->execute();
9468 if (!$dbo->getNumRows()) {
9469 continue;
9470 }
9471 $room_data = $dbo->loadAssoc();
9472 array_push($rooms_with_opt, $room_data['id']);
9473 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9474 if (in_array((string)$pwhereup, $current_opts)) {
9475 continue;
9476 }
9477 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9478 // make sure we do not concatenate a real ID to 0
9479 $current_opts = array();
9480 }
9481 array_push($current_opts, $pwhereup);
9482 $new_opts = implode(';', $current_opts) . ';';
9483 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9484 $dbo->setQuery($q);
9485 $dbo->execute();
9486 }
9487 }
9488 if (!count($rooms_with_opt)) {
9489 // get all rooms to unset this option (if previously set)
9490 array_push($rooms_with_opt, '0');
9491 }
9492 // unset the option from the other rooms that may have it
9493 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9494 $dbo->setQuery($q);
9495 $dbo->execute();
9496 if ($dbo->getNumRows()) {
9497 $unset_rooms_opt = $dbo->loadAssocList();
9498 foreach ($unset_rooms_opt as $room_data) {
9499 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9500 if (!in_array((string)$pwhereup, $current_opts)) {
9501 // this room is not using this option
9502 continue;
9503 }
9504 $optkey = array_search((string)$pwhereup, $current_opts);
9505 if ($optkey === false) {
9506 // key not found
9507 continue;
9508 }
9509 // unset this option ID from the string
9510 unset($current_opts[$optkey]);
9511 if (!count($current_opts)) {
9512 // a room with no options assigned will be listed as "0;"
9513 $current_opts = array(0);
9514 }
9515 $new_opts = implode(';', $current_opts) . ';';
9516 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9517 $dbo->setQuery($q);
9518 $dbo->execute();
9519 }
9520 }
9521 //
9522
9523 }
9524 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9525 }
9526
9527 public function createoptionals()
9528 {
9529 if (!JSession::checkToken()) {
9530 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9531 }
9532
9533 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9534 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9535 }
9536
9537 $this->do_createoptionals();
9538 }
9539
9540 public function createoptionalsstay()
9541 {
9542 if (!JSession::checkToken()) {
9543 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9544 }
9545
9546 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9547 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9548 }
9549
9550 $this->do_createoptionals(true);
9551 }
9552
9553 private function do_createoptionals($stay = false) {
9554 $dbo = JFactory::getDbo();
9555 $poptname = VikRequest::getString('optname', '', 'request');
9556 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9557 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9558 $poptperday = VikRequest::getString('optperday', '', 'request');
9559 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9560 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9561 $popthmany = VikRequest::getString('opthmany', '', 'request');
9562 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9563 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9564 $presizeto = VikRequest::getString('resizeto', '', 'request');
9565 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9566 $pifchildren = $pifchildren == "1" ? 1 : 0;
9567 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9568 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9569 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9570 $pforceval = VikRequest::getString('forceval', '', 'request');
9571 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9572 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9573 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9574 $pforcesel = $pforcesel == "1" ? 1 : 0;
9575 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9576 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9577 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9578 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9579 $pagefrom = VikRequest::getVar('agefrom', array());
9580 $pageto = VikRequest::getVar('ageto', array());
9581 $pagecost = VikRequest::getVar('agecost', array());
9582 $pagectype = VikRequest::getVar('agectype', array());
9583 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9584 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9585 $pavto = VikRequest::getString('avto', '', 'request');
9586 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9587 $pidrooms = VikRequest::getVar('idrooms', array());
9588 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9589 if ($pforcesel == 1) {
9590 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9591 } else {
9592 $strforceval = "";
9593 }
9594 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9595 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9596 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9597 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9598 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9599 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9600 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9601 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9602 $minguests = VikRequest::getInt('minguests', 0, 'request');
9603 $minguests_conflict = false;
9604 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9605 if ($minguestsnum >= $maxguestsnum) {
9606 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9607 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9608 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9609 }
9610 }
9611 if (!$minguests || $minguests_conflict !== false) {
9612 $minguestsnum = 0;
9613 $maxguestsnum = 0;
9614 if ($minguests_conflict !== false) {
9615 // raise warning, but do not stop the process
9616 VikError::raiseWarning('', $minguests_conflict);
9617 }
9618 }
9619 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9620 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9621 $oparams = array(
9622 'minguestsnum' => $minguestsnum,
9623 'mingueststype' => $mingueststype,
9624 'maxguestsnum' => $maxguestsnum,
9625 'maxgueststype' => $maxgueststype,
9626 'damagedep' => $damagedep,
9627 'pet_fee' => $pet_fee,
9628 );
9629 if (!empty($poptname)) {
9630 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9631 jimport('joomla.filesystem.file');
9632 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9633 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9634 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9635 if (file_exists($updpath.$safename)) {
9636 $j = 1;
9637 while (file_exists($updpath.$j.$safename)) {
9638 $j++;
9639 }
9640 $pwhere = $updpath.$j.$safename;
9641 } else {
9642 $j = "";
9643 $pwhere = $updpath.$safename;
9644 }
9645 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9646 @unlink($pwhere);
9647 $picon = "";
9648 } else {
9649 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9650 @chmod($pwhere, 0644);
9651 $picon = $j.$safename;
9652 if ($pautoresize == "1" && !empty($presizeto)) {
9653 $eforj = new vikResizer();
9654 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9655 if ($origmod) {
9656 @unlink($pwhere);
9657 $picon = 'r_'.$j.$safename;
9658 }
9659 }
9660 }
9661 } else {
9662 $picon = "";
9663 }
9664 } else {
9665 $picon = "";
9666 }
9667 $poptperday = ($poptperday == "each" ? "1" : "0");
9668 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9669 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9670 $ageintervalstr = '';
9671 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9672 foreach ($pagefrom as $kage => $vage) {
9673 $afrom = intval($vage);
9674 $ato = intval($pageto[$kage]);
9675 $acost = floatval($pagecost[$kage]);
9676 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9677 if ($ato < $afrom) $ato = $afrom;
9678 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9679 }
9680 }
9681 $ageintervalstr = rtrim($ageintervalstr, ';;');
9682 if (!empty($ageintervalstr)) {
9683 $pforcesel = 1;
9684 }
9685 }
9686 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9687 $dbo->setQuery($q);
9688 $dbo->execute();
9689 if ($dbo->getNumRows() == 1) {
9690 $getlast = $dbo->loadResult();
9691 $newsortnum = $getlast + 1;
9692 } else {
9693 $newsortnum = 1;
9694 }
9695 $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)) . ");";
9696 $dbo->setQuery($q);
9697 $dbo->execute();
9698 $newoptid = $dbo->insertid();
9699
9700 if (!empty($newoptid)) {
9701 // assign/unset option-rooms relations
9702 $rooms_with_opt = array();
9703 if (count($pidrooms)) {
9704 // assign this new option to the requested rooms
9705 foreach ($pidrooms as $idroom) {
9706 if (empty($idroom)) {
9707 continue;
9708 }
9709 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9710 $dbo->setQuery($q);
9711 $dbo->execute();
9712 if (!$dbo->getNumRows()) {
9713 continue;
9714 }
9715 $room_data = $dbo->loadAssoc();
9716 array_push($rooms_with_opt, $room_data['id']);
9717 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9718 if (in_array((string)$newoptid, $current_opts)) {
9719 continue;
9720 }
9721 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9722 // make sure we do not concatenate a real ID to 0
9723 $current_opts = array();
9724 }
9725 array_push($current_opts, $newoptid);
9726 $new_opts = implode(';', $current_opts) . ';';
9727 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9728 $dbo->setQuery($q);
9729 $dbo->execute();
9730 }
9731 }
9732 if (!count($rooms_with_opt)) {
9733 // get all rooms to unset this option (if previously set)
9734 array_push($rooms_with_opt, '0');
9735 }
9736 // unset the option from the other rooms that may have it
9737 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9738 $dbo->setQuery($q);
9739 $dbo->execute();
9740 if ($dbo->getNumRows()) {
9741 $unset_rooms_opt = $dbo->loadAssocList();
9742 foreach ($unset_rooms_opt as $room_data) {
9743 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9744 if (!in_array((string)$newoptid, $current_opts)) {
9745 // this room is not using this option
9746 continue;
9747 }
9748 $optkey = array_search((string)$newoptid, $current_opts);
9749 if ($optkey === false) {
9750 // key not found
9751 continue;
9752 }
9753 // unset this option ID from the string
9754 unset($current_opts[$optkey]);
9755 if (!count($current_opts)) {
9756 // a room with no options assigned will be listed as "0;"
9757 $current_opts = array(0);
9758 }
9759 $new_opts = implode(';', $current_opts) . ';';
9760 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9761 $dbo->setQuery($q);
9762 $dbo->execute();
9763 }
9764 }
9765 //
9766 }
9767
9768 }
9769 $mainframe = JFactory::getApplication();
9770 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9771 }
9772
9773 public function removeoptionals()
9774 {
9775 if (!JSession::checkToken()) {
9776 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9777 }
9778
9779 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9780 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9781 }
9782
9783 $ids = VikRequest::getVar('cid', array(0));
9784 if ($ids) {
9785 $dbo = JFactory::getDbo();
9786 foreach ($ids as $d) {
9787 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9788 $dbo->setQuery($q);
9789 $dbo->execute();
9790 if ($dbo->getNumRows() == 1) {
9791 $rows = $dbo->loadAssocList();
9792 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9793 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9794 }
9795 }
9796 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9797 $dbo->setQuery($q);
9798 $dbo->execute();
9799 }
9800 }
9801 $mainframe = JFactory::getApplication();
9802 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9803 }
9804
9805 public function sendcustomsms() {
9806 $mainframe = JFactory::getApplication();
9807 $pphone = VikRequest::getString('phone', '', 'request');
9808 $psmscont = VikRequest::getString('smscont', '', 'request');
9809 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9810 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9811 if (!empty($pphone) && !empty($psmscont)) {
9812 $sms_api = VikBooking::getSMSAPIClass();
9813 $sms_api_params = VikBooking::getSMSParams();
9814 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9815 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9816 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9817 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9818 if ( !$sms_obj->validateResponse($response_obj) ) {
9819 VikError::raiseWarning('', $sms_obj->getLog());
9820 } else {
9821 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9822 }
9823 } else {
9824 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9825 }
9826 } else {
9827 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9828 }
9829 $mainframe->redirect($pgoto);
9830 }
9831
9832 public function sendcustomemail() {
9833 $dbo = JFactory::getDbo();
9834 $mainframe = JFactory::getApplication();
9835 $vbo_tn = VikBooking::getTranslator();
9836 $pbid = VikRequest::getInt('bid', '', 'request');
9837 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9838 $pemail = VikRequest::getString('email', '', 'request');
9839 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9840 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9841 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9842 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9843 if (!empty($pemail) && !empty($pemailcont)) {
9844 $email_attach = null;
9845 jimport('joomla.filesystem.file');
9846 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9847 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9848 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9849 $src = $pemailattch['tmp_name'];
9850 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9851 $j = "";
9852 if (file_exists($dest.$filename)) {
9853 $j = rand(171, 1717);
9854 while (file_exists($dest.$j.$filename)) {
9855 $j++;
9856 }
9857 }
9858 $finaldest = $dest.$j.$filename;
9859 if (VikBooking::uploadFile($src, $finaldest)) {
9860 $email_attach = $finaldest;
9861 } else {
9862 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9863 $mainframe->redirect($pgoto);
9864 exit;
9865 }
9866 }
9867 //VBO 1.10 - special tags for the custom email template files and messages
9868 $orig_mail_cont = $pemailcont;
9869 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9870 // replace any possible placeholder for special tags
9871 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9872 return $match[2];
9873 }, $pemailcont);
9874
9875 $booking = array();
9876 $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.";";
9877 $dbo->setQuery($q);
9878 $dbo->execute();
9879 if ($dbo->getNumRows() > 0) {
9880 $booking = $dbo->loadAssoc();
9881 }
9882 $booking_rooms = array();
9883 $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.";";
9884 $dbo->setQuery($q);
9885 $dbo->execute();
9886 if ($dbo->getNumRows() > 0) {
9887 $booking_rooms = $dbo->loadAssocList();
9888 if (!empty($booking['lang'])) {
9889 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9890 }
9891 }
9892 //we use the same parsing function as the one for the Customer SMS Template
9893 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9894 }
9895 //
9896 // allow the use of token {booking_id} in subject
9897 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9898 //
9899 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9900 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9901 $vbo_app = VikBooking::getVboApplication();
9902 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9903 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9904 if ($email_attach !== null) {
9905 @unlink($email_attach);
9906 }
9907 //Booking History
9908 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9909 //
9910 //Save email template for future sending
9911 $config_rec_exists = false;
9912 $emtpl = array(
9913 'emailsubj' => $pemailsubj,
9914 'emailcont' => $orig_mail_cont,
9915 'emailfrom' => $pemailfrom
9916 );
9917 $cur_emtpl = array();
9918 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9919 $dbo->setQuery($q);
9920 $dbo->execute();
9921 if ($dbo->getNumRows() > 0) {
9922 $config_rec_exists = true;
9923 $cur_emtpl = $dbo->loadResult();
9924 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9925 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9926 }
9927 if (count($cur_emtpl) > 0) {
9928 $existing_subj = false;
9929 foreach ($cur_emtpl as $emk => $emv) {
9930 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9931 $cur_emtpl[$emk] = $emtpl;
9932 $existing_subj = true;
9933 break;
9934 }
9935 }
9936 if ($existing_subj === false) {
9937 $cur_emtpl[] = $emtpl;
9938 }
9939 } else {
9940 $cur_emtpl[] = $emtpl;
9941 }
9942 if (count($cur_emtpl) > 10) {
9943 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9944 $exceed = count($cur_emtpl) - 10;
9945 for ($tl=0; $tl < $exceed; $tl++) {
9946 unset($cur_emtpl[$tl]);
9947 }
9948 $cur_emtpl = array_values($cur_emtpl);
9949 }
9950 if ($config_rec_exists === true) {
9951 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9952 $dbo->setQuery($q);
9953 $dbo->execute();
9954 } else {
9955 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9956 $dbo->setQuery($q);
9957 $dbo->execute();
9958 }
9959 //
9960 } else {
9961 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9962 }
9963 $mainframe->redirect($pgoto);
9964 }
9965
9966 public function rmcustomemailtpl() {
9967 $cid = VikRequest::getVar('cid', array(0));
9968 $oid = $cid[0];
9969 $dbo = JFactory::getDBO();
9970 $mainframe = JFactory::getApplication();
9971 $tplind = VikRequest::getInt('tplind', '', 'request');
9972 if (empty($oid) || !(strlen($tplind) > 0)) {
9973 VikError::raiseWarning('', 'Missing Data.');
9974 $mainframe->redirect('index.php?option=com_vikbooking');
9975 exit;
9976 }
9977 $cur_emtpl = array();
9978 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9979 $dbo->setQuery($q);
9980 $dbo->execute();
9981 if ($dbo->getNumRows() > 0) {
9982 $cur_emtpl = $dbo->loadResult();
9983 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9984 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9985 } else {
9986 VikError::raiseWarning('', 'Missing Templates Record.');
9987 $mainframe->redirect('index.php?option=com_vikbooking');
9988 exit;
9989 }
9990 if (array_key_exists($tplind, $cur_emtpl)) {
9991 unset($cur_emtpl[$tplind]);
9992 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9993 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9994 $dbo->setQuery($q);
9995 $dbo->execute();
9996 }
9997 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
9998 exit;
9999 }
10000
10001 public function exportcustomers() {
10002 //we do not set the menu for this view
10003
10004 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
10005
10006 parent::display();
10007
10008 if (VikBooking::showFooter()) {
10009 VikBookingHelper::printFooter();
10010 }
10011 }
10012
10013 public function csvexportprepare() {
10014 //modal box, so we do not set menu or footer
10015
10016 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
10017
10018 parent::display();
10019 }
10020
10021 public function icsexportprepare() {
10022 //modal box, so we do not set menu or footer
10023
10024 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
10025
10026 parent::display();
10027 }
10028
10029 public function bookingcheckin() {
10030 //modal box, so we do not set menu or footer
10031
10032 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
10033
10034 parent::display();
10035 }
10036
10037 public function gencheckindoc() {
10038 //modal box, so we do not set menu or footer
10039
10040 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
10041
10042 parent::display();
10043 }
10044
10045 public function checkversion() {
10046 //to be called via ajax
10047 $params = new stdClass;
10048 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10049 $params->alias = 'com_vikbooking';
10050
10051 $result = array();
10052
10053 if (!count($result)) {
10054 $result = new stdClass;
10055 $result->status = 0;
10056 } else {
10057 $result = $result[0];
10058 }
10059
10060 echo json_encode($result);
10061 exit;
10062 }
10063
10064 public function updateprogram() {
10065 $params = new stdClass;
10066 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10067 $params->alias = 'com_vikbooking';
10068
10069 $result = array();
10070
10071 if (!count($result) || !$result[0]) {
10072 if (class_exists('JEventDispatcher')) {
10073 $dispatcher = JEventDispatcher::getInstance();
10074 $result = $dispatcher->trigger('checkVersion', array(&$params));
10075 } else {
10076 $app = JFactory::getApplication();
10077 if (method_exists($app, 'triggerEvent')) {
10078 $result = $app->triggerEvent('checkVersion', array(&$params));
10079 }
10080 }
10081 }
10082
10083 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
10084 exit('Error, plugin disabled');
10085 }
10086
10087 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
10088
10089 VikBookingHelper::pUpdateProgram($result[0]->response);
10090 }
10091
10092 public function updateprogramlaunch() {
10093 $params = new stdClass;
10094 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10095 $params->alias = 'com_vikbooking';
10096
10097 $json = new stdClass;
10098 $json->status = false;
10099
10100 echo json_encode($json);
10101 exit;
10102 }
10103
10104 public function invoke_vcm()
10105 {
10106 $app = JFactory::getApplication();
10107
10108 $oids = VikRequest::getVar('cid', []);
10109 $sync_type = VikRequest::getString('stype', 'new', 'request');
10110 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
10111 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
10112 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
10113 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
10114
10115 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
10116 $app->redirect("index.php?option=com_vikbooking&task=orders");
10117 $app->close();
10118 }
10119
10120 $result = VikBooking::getVcmInvoker()
10121 ->setOids($oids)
10122 ->setSyncType($sync_type)
10123 ->setOriginalBooking($original_booking_js, true)
10124 ->doSync();
10125
10126 if ($result === true) {
10127 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
10128 } else {
10129 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
10130 }
10131
10132 if (!empty($return_url)) {
10133 $app->redirect($return_url);
10134 } else {
10135 $app->redirect("index.php?option=com_vikbooking&task=orders");
10136 }
10137
10138 $app->close();
10139 }
10140
10141 public function multiphotosupload() {
10142 jimport('joomla.filesystem.file');
10143
10144 $dbo = JFactory::getDBO();
10145 $proomid = VikRequest::getInt('roomid', '', 'request');
10146
10147 $resp = array('files' => array());
10148 $error_messages = array(
10149 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
10150 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
10151 3 => 'The uploaded file was only partially uploaded',
10152 4 => 'No file was uploaded',
10153 6 => 'Missing a temporary folder',
10154 7 => 'Failed to write file to disk',
10155 8 => 'A PHP extension stopped the file upload',
10156 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
10157 'max_file_size' => 'File is too big',
10158 'min_file_size' => 'File is too small',
10159 'accept_file_types' => 'Filetype not allowed',
10160 'max_number_of_files' => 'Maximum number of files exceeded',
10161 'max_width' => 'Image exceeds maximum width',
10162 'min_width' => 'Image requires a minimum width',
10163 'max_height' => 'Image exceeds maximum height',
10164 'min_height' => 'Image requires a minimum height',
10165 'abort' => 'File upload aborted',
10166 'image_resize' => 'Failed to resize image',
10167 'vbo_type' => 'The file type cannot be accepted',
10168 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
10169 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
10170 );
10171
10172 $creativik = new vikResizer();
10173 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
10174 $bigsdest = $updpath;
10175 $thumbsdest = $updpath;
10176 $dest = $updpath;
10177 $moreimagestr = '';
10178 $cur_captions = json_encode(array());
10179
10180 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
10181 $dbo->setQuery($q);
10182 $dbo->execute();
10183 if ($dbo->getNumRows() == 1) {
10184 $photo_data = $dbo->loadAssocList();
10185 $cur_captions = $photo_data[0]['imgcaptions'];
10186 $cur_photos = $photo_data[0]['moreimgs'];
10187 if (!empty($cur_photos)) {
10188 $moreimagestr .= $cur_photos;
10189 }
10190 }
10191
10192 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
10193
10194 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
10195 foreach ($bulkphotos['name'] as $updk => $photoname) {
10196 $uploaded_image = array();
10197 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
10198 $src = $bulkphotos['tmp_name'][$updk];
10199 $j = "";
10200 if (file_exists($dest.$filename)) {
10201 $j = rand(171, 1717);
10202 while (file_exists($dest.$j.$filename)) {
10203 $j++;
10204 }
10205 }
10206 $finaldest=$dest.$j.$filename;
10207 $is_error = false;
10208 $err_key = '';
10209 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
10210 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
10211 $is_error = true;
10212 $err_key = $bulkphotos['error'][$updk];
10213 }
10214 }
10215 if (!$is_error) {
10216 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
10217 if ($check[2] & imagetypes()) {
10218 if (VikBooking::uploadFile($src, $finaldest)) {
10219 $gimg = $j.$filename;
10220 //orig img
10221 $origmod = true;
10222 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
10223 //thumb
10224 $thumbsize = VikBooking::getThumbSize();
10225 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
10226 if (!$thumb || !$origmod) {
10227 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
10228 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
10229 $is_error = true;
10230 $err_key = 'vbo_perm';
10231 } else {
10232 $moreimagestr.=$j.$filename.";;";
10233 }
10234 @unlink($finaldest);
10235 } else {
10236 $is_error = true;
10237 $err_key = 'vbo_jupload';
10238 }
10239 } else {
10240 $is_error = true;
10241 $err_key = 'vbo_type';
10242 }
10243 }
10244 $img = new stdClass();
10245 if ($is_error) {
10246 $img->name = '';
10247 $img->size = '';
10248 $img->type = '';
10249 $img->url = '';
10250 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
10251 } else {
10252 $img->name = $photoname;
10253 $img->size = $bulkphotos['size'][$updk];
10254 $img->type = $bulkphotos['type'][$updk];
10255 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
10256 }
10257 $resp['files'][] = $img;
10258 }
10259 } else {
10260 $res = new stdClass();
10261 $res->name = '';
10262 $res->size = '';
10263 $res->type = '';
10264 $res->url = '';
10265 $res->error = 'No images received for upload';
10266 $resp['files'][] = $res;
10267 }
10268 //Update current extra images string
10269 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
10270 $dbo->setQuery($q);
10271 $dbo->execute();
10272 $resp['actmoreimgs'] = $moreimagestr;
10273 //Update current extra images uploaded
10274 $cur_thumbs = '';
10275 $morei=explode(';;', $moreimagestr);
10276 if (@count($morei) > 0) {
10277 $imgcaptions = json_decode($cur_captions, true);
10278 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
10279 $cur_thumbs .= '<ul class="vbo-sortable">';
10280 foreach ($morei as $ki => $mi) {
10281 if (!empty($mi)) {
10282 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
10283 $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>';
10284 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
10285 $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>';
10286 $cur_thumbs .= '</li>';
10287 }
10288 }
10289 $cur_thumbs .= '</ul>';
10290 $cur_thumbs .= '<br clear="all"/>';
10291 }
10292 $resp['currentthumbs'] = $cur_thumbs;
10293
10294 echo json_encode($resp);
10295 exit;
10296 }
10297
10298 public function loadsmsbalance() {
10299 //to be called via ajax
10300 $html = 'Error1 [N/A]';
10301 $sms_api = VikBooking::getSMSAPIClass();
10302 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
10303 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10304 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
10305 if (method_exists('VikSmsApi', 'estimate')) {
10306 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
10307 if ( $array_result->errorCode != 0 ) {
10308 $html = 'Error3 ['.$array_result->errorMsg.']';
10309 } else {
10310 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
10311 }
10312 } else {
10313 $html = 'Error2 [N/A]';
10314 }
10315 }
10316 echo $html;
10317 exit;
10318 }
10319
10320 public function loadsmsparams() {
10321 //to be called via ajax
10322 $html = '---------';
10323 $phpfile = VikRequest::getString('phpfile', '', 'request');
10324 if (!empty($phpfile)) {
10325 $sms_api = VikBooking::getSMSAPIClass();
10326 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
10327 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
10328 }
10329 echo $html;
10330 exit;
10331 }
10332
10333 public function loadcronparams() {
10334 //to be called via ajax
10335 $html = '---------';
10336 $phpfile = VikRequest::getString('phpfile', '', 'request');
10337 if (!empty($phpfile)) {
10338 $html = VikBooking::displayCronParameters($phpfile);
10339 }
10340 echo $html;
10341 exit;
10342 }
10343
10344 public function loadpaymentparams() {
10345 //to be called via ajax
10346 $html = '<p>---------</p>';
10347 $phpfile = VikRequest::getString('phpfile', '', 'request');
10348 if (!empty($phpfile)) {
10349 $html = VikBooking::displayPaymentParameters($phpfile);
10350 }
10351 echo $html;
10352 exit;
10353 }
10354
10355 public function setbookingtag() {
10356 //to be called via ajax
10357 $dbo = JFactory::getDBO();
10358 $pidorder = VikRequest::getInt('idorder', '', 'request');
10359 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
10360 if (!empty($pidorder) && $ptagkey >= 0) {
10361 $all_tags = VikBooking::loadBookingsColorTags();
10362 if (array_key_exists($ptagkey, $all_tags)) {
10363 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
10364 $dbo->setQuery($q);
10365 $dbo->execute();
10366 if ($dbo->getNumRows() > 0) {
10367 $newcolortag = json_encode($all_tags[$ptagkey]);
10368 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
10369 $dbo->setQuery($q);
10370 $dbo->execute();
10371 $newcolortag = $all_tags[$ptagkey];
10372 $newcolortag['name'] = JText::translate($newcolortag['name']);
10373 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
10374 echo json_encode($newcolortag);
10375 } else {
10376 echo 'e4j.error.Booking ('.$pidorder.') not found';
10377 }
10378 } else {
10379 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
10380 }
10381 } else {
10382 echo 'e4j.error.Missing Data';
10383 }
10384 exit;
10385 }
10386
10387 public function updatereceiptnum() {
10388 //to be called via ajax
10389 $pnewnum = VikRequest::getInt('newnum', '', 'request');
10390 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
10391 $poid = VikRequest::getInt('oid', '', 'request');
10392 if ($pnewnum > 0) {
10393 VikBooking::getNextReceiptNumber($poid, $pnewnum);
10394 VikBooking::getReceiptNotes($pnewnotes);
10395 //Booking History
10396 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
10397 //
10398 echo 'e4j.ok';
10399 exit;
10400 }
10401 echo 'e4j.error';
10402 exit;
10403 }
10404
10405 public function isroombookable() {
10406 //to be called via ajax
10407 $dbo = JFactory::getDBO();
10408 $res = array(
10409 'status' => 0,
10410 'err' => ''
10411 );
10412 $prid = VikRequest::getInt('rid', '', 'request');
10413 $pfdate = VikRequest::getString('fdate', '', 'request');
10414 $ptdate = VikRequest::getString('tdate', '', 'request');
10415 $room_info = array();
10416 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
10417 $dbo->setQuery($q);
10418 $dbo->execute();
10419 if ($dbo->getNumRows() > 0) {
10420 $room_info = $dbo->loadAssoc();
10421 }
10422 $pcheckinh = 0;
10423 $pcheckinm = 0;
10424 $pcheckouth = 0;
10425 $pcheckoutm = 0;
10426 $timeopst = VikBooking::getTimeOpenStore();
10427 if (is_array($timeopst)) {
10428 $opent = VikBooking::getHoursMinutes($timeopst[0]);
10429 $closet = VikBooking::getHoursMinutes($timeopst[1]);
10430 $pcheckinh = $opent[0];
10431 $pcheckinm = $opent[1];
10432 $pcheckouth = $closet[0];
10433 $pcheckoutm = $closet[1];
10434 }
10435 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
10436 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
10437 if (
10438 count($room_info) > 0 &&
10439 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
10440 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
10441 {
10442 $res['status'] = 1;
10443 } else {
10444 if (!(count($room_info) > 0)) {
10445 $res['err'] = 'Room not found';
10446 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
10447 $res['err'] = 'Invalid dates';
10448 } else {
10449 //not available
10450 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
10451 }
10452 }
10453
10454 echo json_encode($res);
10455 exit;
10456 }
10457
10458 public function uploadsnapshot() {
10459 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
10460 /**
10461 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
10462 * The old snapshot collection script with Flash no longer works in 2021.
10463 *
10464 * @since 1.14 (J) - 1.4.0 (WP)
10465 */
10466 $result = null;
10467 try {
10468 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
10469 } catch (RuntimeException $e) {
10470 echo "e4j.error.Error " . $e->getMessage();
10471 exit;
10472 }
10473
10474 if (!is_object($result)) {
10475 echo "e4j.error.Invalid upload response";
10476 exit;
10477 }
10478
10479 echo $result->filename;
10480 exit;
10481 }
10482
10483 public function checkvcmrateschanges() {
10484 //to be called via ajax
10485 $session = JFactory::getSession();
10486 $ret = array('changesCount' => 0, 'changesData' => '');
10487 $updforvcm = $session->get('vbVcmRatesUpd', '');
10488 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
10489 $ret['changesCount'] = $updforvcm['count'];
10490 $ret['changesData'] = $updforvcm;
10491 }
10492
10493 echo json_encode($ret);
10494 exit;
10495 }
10496
10497 /**
10498 * AJAX endpoint to load the details of one or more bookings.
10499 *
10500 * @return void
10501 *
10502 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10503 */
10504 public function getbookingsinfo()
10505 {
10506 //to be called via ajax
10507 $dbo = JFactory::getDbo();
10508
10509 $booking_infos = [];
10510 $bookings = [];
10511
10512 $pidorders = VikRequest::getString('idorders', '', 'request');
10513 $psubroom = VikRequest::getString('subroom', '', 'request');
10514 $pstatus = VikRequest::getString('status', '', 'request');
10515 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10516 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10517 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10518
10519 if (!empty($pidorders)) {
10520 $bookings = explode(',', $pidorders);
10521 foreach ($bookings as $k => $v) {
10522 $v = intval(str_replace('-', '', $v));
10523 if (empty($v)) {
10524 unset($bookings[$k]);
10525 continue;
10526 }
10527 $bookings[$k] = $v;
10528 }
10529 }
10530 $bookings = array_values($bookings);
10531
10532 if (!$bookings) {
10533 /**
10534 * AJAX requests made by the page availability overview may contain empty booking IDs
10535 * due to SQL errors that only occupied the room, but could not save the booking record.
10536 * Clean up busy records where the busy relations contain empty booking IDs.
10537 *
10538 * @since 1.14 (J) - 1.4.0 (WP)
10539 */
10540 $hanging_busy_ids = [];
10541
10542 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10543 $dbo->setQuery($q);
10544 $removelist = $dbo->loadAssocList();
10545 if ($removelist) {
10546 foreach ($removelist as $hanging_busy) {
10547 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10548 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10549 array_push($hanging_busy_ids, $hanging_busy_id);
10550 }
10551 }
10552 }
10553
10554 // let's check also for ghost records that only occupy the room
10555 $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);";
10556 $dbo->setQuery($q);
10557 $removelist = $dbo->loadAssocList();
10558 if ($removelist) {
10559 foreach ($removelist as $hanging_busy) {
10560 $hanging_busy_id = (int)$hanging_busy['id'];
10561 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10562 array_push($hanging_busy_ids, $hanging_busy_id);
10563 }
10564 }
10565 }
10566
10567 if ($hanging_busy_ids) {
10568 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10569 $dbo->setQuery($q);
10570 $dbo->execute();
10571 }
10572 //
10573
10574 // output the error
10575 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10576 }
10577
10578 $nowdf = VikBooking::getDateFormat(true);
10579 if ($nowdf == "%d/%m/%Y") {
10580 $df = 'd/m/Y';
10581 } elseif ($nowdf == "%m/%d/%Y") {
10582 $df = 'm/d/Y';
10583 } else {
10584 $df = 'Y/m/d';
10585 }
10586 $datesep = VikBooking::getDateSeparator(true);
10587 $currencysymb = VikBooking::getCurrencySymb();
10588 $current_y = date('Y');
10589 $current_ts = time();
10590 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10591
10592 $query = $dbo->getQuery(true);
10593 $query->select('o.*');
10594 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10595 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10596 // include the requested booking IDs and the cancelled reservations for this stay date
10597 $stay_date_info = getdate(strtotime($pstay_date));
10598 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10599 $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) . '))');
10600 // exclude the pending reservations
10601 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10602 } else {
10603 // include only the requested booking IDs
10604 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10605 }
10606 if ($pstatus != 'any') {
10607 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10608 }
10609 if (!empty($pstay_date) && $pstatus == 'any') {
10610 // sort by confirmed status before cancelled status
10611 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10612 $query->order($dbo->qn('o.id') . ' ASC');
10613 }
10614 $dbo->setQuery($query);
10615 $booking_infos = $dbo->loadAssocList();
10616
10617 foreach ($booking_infos as $k => $row) {
10618 // rooms, amounts and guests information
10619 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10620 $rids_involved = [];
10621 $room_names = [];
10622 $totadults = 0;
10623 $totchildren = 0;
10624 foreach ($rooms as $rr) {
10625 $rids_involved[] = $rr['idroom'];
10626 $totadults += $rr['adults'];
10627 $totchildren += $rr['children'];
10628 $room_names[] = $rr['room_name'];
10629 if ($row['split_stay']) {
10630 // do not sum guests in case of split stay booking
10631 $totadults = $rr['adults'];
10632 $totchildren = $rr['children'];
10633 }
10634 }
10635
10636 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10637 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10638 if (!in_array($pidroom, $rids_involved)) {
10639 $is_out_of_scope = true;
10640 if ($psharedcal && count($bookings) === 1) {
10641 $is_out_of_scope = ($row['id'] != $bookings[0]);
10642 }
10643 if ($is_out_of_scope) {
10644 // out of scope reservation, unset it and go to the next one
10645 unset($booking_infos[$k]);
10646 continue;
10647 }
10648 }
10649 }
10650
10651 // included meal plans to be displayed in case of single-room booking
10652 $included_meals = [];
10653 $rplan_name = '';
10654 if (count($rooms) === 1) {
10655 // rate plan name and ID, if any
10656 $active_rplan_id = 0;
10657 if (!empty($rooms[0]['otarplan'])) {
10658 $rplan_name = $rooms[0]['otarplan'];
10659 } else {
10660 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10661 }
10662
10663 // find the included meals
10664 if (!empty($rooms[0]['meals'])) {
10665 // display included meals defined at room-reservation record
10666 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10667 } else {
10668 // fetch default included meals in the selected rate plan
10669 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10670 }
10671 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10672 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10673 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10674 }
10675 }
10676
10677 if ($included_meals) {
10678 $short_incl_meals = [];
10679 foreach ($included_meals as $meal_enum => $meal_name) {
10680 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10681 }
10682 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10683 }
10684
10685 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10686 $booking_infos[$k]['currency_symb'] = $currencysymb;
10687 if ($row['status'] == 'confirmed') {
10688 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10689 if ($row['checkout'] < $current_ts) {
10690 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10691 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10692 if ($row['checked'] == 1) {
10693 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10694 } elseif ($row['checked'] == -1) {
10695 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10696 }
10697 }
10698 } elseif ($row['status'] == 'standby') {
10699 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10700 } elseif ($row['status'] == 'cancelled') {
10701 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10702 } else {
10703 $booking_infos[$k]['status_lbl'] = $row['status'];
10704 }
10705 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10706 if ($booking_infos[$k]['colortag']) {
10707 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10708 }
10709 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10710 $booking_infos[$k]['tot_adults'] = $totadults;
10711 $booking_infos[$k]['tot_children'] = $totchildren;
10712 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10713 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10714
10715 // room indexes
10716 $rindexes = [];
10717 $av_room_indexes = [];
10718 $used_indexes_map = [];
10719 $sub_units_data = [];
10720 $optindexes = [];
10721 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10722 $missing_index = false;
10723 foreach ($rooms as $kor => $or) {
10724 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10725 // cannot build room indexes data
10726 continue;
10727 }
10728
10729 $room_params = json_decode($or['params'], true);
10730 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10731 // no distinctive features information
10732 continue;
10733 }
10734
10735 if (!strlen($or['roomindex'])) {
10736 // turn flag on for missing index when room does support them
10737 $missing_index = true;
10738 // build array with available room indexes
10739 $av_indexes = [];
10740 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10741 foreach ($room_params['features'] as $rind => $rfeatures) {
10742 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10743 continue;
10744 }
10745 foreach ($rfeatures as $fname => $fval) {
10746 if ($fval) {
10747 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10748 break;
10749 }
10750 }
10751 }
10752 if ($av_indexes) {
10753 // push available indexes for this room
10754 $av_room_indexes[$kor] = [
10755 'rid' => $or['idroom'],
10756 'name' => $or['room_name'],
10757 'list' => $av_indexes,
10758 ];
10759 }
10760 // do not proceed any further
10761 continue;
10762 }
10763
10764 // parse distinctive features
10765 foreach ($room_params['features'] as $rind => $rfeatures) {
10766 if ($rind != $or['roomindex']) {
10767 continue;
10768 }
10769 $ind_str = '';
10770 $ind_str_short = '';
10771 foreach ($rfeatures as $fname => $fval) {
10772 if (strlen($fval)) {
10773 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10774 $ind_str_short = $fval;
10775 break;
10776 }
10777 }
10778 if (!isset($rindexes[$or['room_name']])) {
10779 $rindexes[$or['room_name']] = $ind_str;
10780 $sub_units_data[$or['room_name']] = $ind_str_short;
10781 } else {
10782 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10783 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10784 }
10785 break;
10786 }
10787
10788 // build options to switch sub-unit index
10789 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10790 // build the options for switching the room index for this room
10791 foreach ($room_params['features'] as $rind => $rfeatures) {
10792 foreach ($rfeatures as $fname => $fval) {
10793 if (strlen((string)$fval)) {
10794 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10795 break;
10796 }
10797 }
10798 }
10799 }
10800 }
10801
10802 if ($rindexes) {
10803 $booking_infos[$k]['rindexes'] = $rindexes;
10804 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10805 }
10806
10807 if ($optindexes) {
10808 $booking_infos[$k]['optindexes'] = $optindexes;
10809 }
10810
10811 if ($missing_index && $av_room_indexes) {
10812 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10813 }
10814
10815 // include flag for missing room index
10816 $booking_infos[$k]['missing_index'] = $missing_index;
10817
10818 // channel provenience and small logo URL
10819 $ota_logo_img = JText::translate('VBORDFROMSITE');
10820 $booking_avatar_src = null;
10821 $booking_avatar_alt = null;
10822 if (!empty($row['channel'])) {
10823 $channelparts = explode('_', $row['channel']);
10824 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10825 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10826 if ($ota_logo_img === false) {
10827 $ota_logo_img = $otachannel;
10828 } else {
10829 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10830 }
10831 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10832 if ($logo_helper !== false) {
10833 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10834 $booking_avatar_alt = $logo_helper->provenience;
10835 }
10836 }
10837 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10838 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10839 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10840
10841 // Customer Details
10842 $custdata = $row['custdata'];
10843 $custdata_parts = explode("\n", $row['custdata']);
10844 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10845 //get the first two fields
10846 $custvalues = [];
10847 foreach ($custdata_parts as $custdet) {
10848 if (strlen($custdet) < 1) {
10849 continue;
10850 }
10851 $custdet_parts = explode(':', $custdet);
10852 if (count($custdet_parts) >= 2) {
10853 unset($custdet_parts[0]);
10854 array_push($custvalues, trim(implode(':', $custdet_parts)));
10855 }
10856 if (count($custvalues) > 1) {
10857 break;
10858 }
10859 }
10860 if (count($custvalues) > 1) {
10861 $custdata = implode(' ', $custvalues);
10862 }
10863 }
10864 if (strlen($custdata) > 45) {
10865 $custdata = (function_exists('mb_substr') ? mb_substr($custdata, 0, 45, 'UTF-8') : substr($custdata, 0, 45)) . " ...";
10866 }
10867
10868 // customer record details
10869 $customer = [];
10870 $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'];
10871 $dbo->setQuery($q, 0, 1);
10872 $dbo->execute();
10873 if ($dbo->getNumRows()) {
10874 $customer = $dbo->loadAssoc();
10875 if (!empty($customer['first_name'])) {
10876 $custdata = $customer['first_name'].' '.$customer['last_name'];
10877 if (!empty($customer['country'])) {
10878 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10879 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10880 }
10881 }
10882 }
10883 }
10884 $booking_infos[$k]['customer'] = $customer;
10885
10886 // check if a profile picture is available for the customer
10887 if (!empty($customer['pic'])) {
10888 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10889 $booking_avatar_alt = basename($booking_avatar_src);
10890 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10891 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10892 }
10893
10894 // whether this is a closure
10895 $booking_infos[$k]['closure'] = (int)$row['closure'];
10896 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10897
10898 // short customer information
10899 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10900 $booking_infos[$k]['cinfo'] = $custdata;
10901
10902 // formatted dates
10903 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10904 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10905 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10906
10907 // short booking date, check-in, check-out date format
10908 $stay_info_in = getdate($row['checkin']);
10909 $stay_info_out = getdate($row['checkout']);
10910 $str_checkin = date('d', $row['checkin']);
10911 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10912 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10913 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10914 $str_checkout .= ' ' . $stay_info_out['year'];
10915 }
10916 $booking_infos[$k]['checkin_short'] = $str_checkin;
10917 $booking_infos[$k]['checkout_short'] = $str_checkout;
10918 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10919 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10920 }
10921
10922 if (!$booking_infos) {
10923 // output the error
10924 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10925 }
10926
10927 // output the JSON encoded response and exit
10928 VBOHttpDocument::getInstance()->json($booking_infos);
10929 }
10930
10931 public function switchRoomIndex() {
10932 //to be called via ajax
10933 $dbo = JFactory::getDBO();
10934 $bid = VikRequest::getInt('bid', '', 'request');
10935 $rid = VikRequest::getInt('rid', '', 'request');
10936 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10937 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10938 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10939 echo 'e4j.error.#1 Missing Data';
10940 exit;
10941 }
10942 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10943 $dbo->setQuery($q);
10944 $dbo->execute();
10945 if ($dbo->getNumRows() < 1) {
10946 echo 'e4j.error.#2 Record not found';
10947 exit;
10948 }
10949 $rows = $dbo->loadAssocList();
10950 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10951 $dbo->setQuery($q);
10952 $dbo->execute();
10953 echo 'e4j.ok';
10954 exit;
10955 }
10956
10957 public function searchcustomer()
10958 {
10959 // to be called via ajax
10960 $dbo = JFactory::getDbo();
10961
10962 $kw = VikRequest::getString('kw', '', 'request');
10963 $nopin = VikRequest::getInt('nopin', '', 'request');
10964 $email = VikRequest::getInt('email', 0, 'request');
10965 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10966 $no_script = VikRequest::getInt('no_script', 0, 'request');
10967
10968 if (!strlen($kw)) {
10969 VBOHttpDocument::getInstance()->close(200, '');
10970 }
10971
10972 if ($nopin > 0) {
10973 //page all bookings
10974 $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;";
10975 } elseif ($email > 0) {
10976 // page calendar for checking if an email exists
10977 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10978 } else {
10979 //page calendar
10980 $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;";
10981 }
10982 $dbo->setQuery($q);
10983 $customers = $dbo->loadAssocList();
10984
10985 if (!$customers) {
10986 VBOHttpDocument::getInstance()->close(200, '');
10987 }
10988
10989 if ($email > 0) {
10990 VBOHttpDocument::getInstance()->json($customers[0]);
10991 }
10992
10993 $cust_old_fields = array();
10994 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10995 foreach ($customers as $k => $v) {
10996 $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";
10997 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
10998 if (!empty($v['pic'])) {
10999 $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";
11000 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
11001 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
11002 } else {
11003 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
11004 }
11005 $cstring_search .= '</span>';
11006 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
11007 if (!($nopin > 0)) {
11008 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
11009 }
11010 $cstring_search .= '</div>'."\n";
11011 if (!empty($v['cfields'])) {
11012 $oldfields = json_decode($v['cfields'], true);
11013 if (is_array($oldfields) && count($oldfields)) {
11014 $cust_old_fields[$v['id']] = $oldfields;
11015 }
11016 }
11017 }
11018 $cstring_search .= '</div>'."\n";
11019
11020 /**
11021 * Add the necessary JS code for the arrow navigation.
11022 */
11023 $cstring_search_js = '<script type="text/javascript">';
11024 $cstring_search_js .= '
11025 var vboCust = jQuery(".' . $selector . '");
11026 var vboCustSelected = null;
11027 jQuery(window).keydown(function(e) {
11028 if (e.which === 40) {
11029 if (vboCustSelected) {
11030 vboCustSelected.removeClass("' . $selector . '-highligthed");
11031 next = vboCustSelected.next();
11032 if (next.length > 0) {
11033 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11034 } else {
11035 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11036 }
11037 } else {
11038 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11039 }
11040 } else if (e.which === 38) {
11041 if (vboCustSelected) {
11042 vboCustSelected.removeClass("' . $selector . '-highligthed");
11043 next = vboCustSelected.prev();
11044 if (next.length > 0) {
11045 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11046 } else {
11047 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11048 }
11049 } else {
11050 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11051 }
11052 } else if (e.which === 13) {
11053 if (vboCustSelected) {
11054 vboCustSelected.trigger("click");
11055 }
11056 }
11057 });
11058 jQuery(".' . $selector . '").off("hover");
11059 jQuery(".' . $selector . '").hover(function() {
11060 if (vboCustSelected) {
11061 vboCustSelected.removeClass("' . $selector . '-highligthed");
11062 vboCustSelected = null;
11063 }
11064 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
11065 }, function() {
11066 if (vboCustSelected) {
11067 vboCustSelected.removeClass("' . $selector . '-highligthed");
11068 vboCustSelected = null;
11069 }
11070 jQuery(this).removeClass("' . $selector . '-highligthed");
11071 });';
11072 $cstring_search_js .= '</script>';
11073
11074 if (!$no_script) {
11075 // append JS
11076 $cstring_search .= $cstring_search_js;
11077 }
11078
11079 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
11080 }
11081
11082 public function sharesignaturelink() {
11083 //to be called via ajax
11084 $dbo = JFactory::getDBO();
11085 $response = array(
11086 'status' => 0,
11087 'error' => 'Generic Error'
11088 );
11089 $pbid = VikRequest::getInt('bid', '', 'request');
11090 $phow = VikRequest::getString('how', '', 'request');
11091 $pto = VikRequest::getString('to', '', 'request');
11092 $pcustomer = VikRequest::getInt('customer', '', 'request');
11093 $cpin = VikBooking::getCPinIstance();
11094 $customer_info = $cpin->getCustomerByID($pcustomer);
11095 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
11096 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
11097 $dbo->setQuery($q);
11098 $dbo->execute();
11099 if ($dbo->getNumRows() > 0) {
11100 $row = $dbo->loadAssoc();
11101
11102 $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'];
11103 if (VBOPlatformDetection::isWordPress()) {
11104 /**
11105 * @wponly Rewrite URI for front-end signature
11106 */
11107 $share_link = str_replace(JUri::root(), '', $share_link);
11108 $model = JModel::getInstance('vikbooking', 'shortcodes');
11109 $itemid = $model->all('post_id', $full = true);
11110 if (count($itemid)) {
11111 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
11112 }
11113 } else {
11114 /**
11115 * @joomlaonly
11116 */
11117 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
11118 if ($best_menuitem_id) {
11119 $share_base = str_replace(JUri::root(), '', $share_link);
11120 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
11121 }
11122 }
11123
11124 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11125 if ($phow == 'email') {
11126 $sender = VikBooking::getSenderMail();
11127 $vbo_app = VikBooking::getVboApplication();
11128 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
11129 $response['status'] = 1;
11130 } elseif ($phow == 'sms') {
11131 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11132 $sms_api = VikBooking::getSMSAPIClass();
11133 $sms_api_params = VikBooking::getSMSParams();
11134 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
11135 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
11136 $sms_obj = new VikSmsApi(array(), $sms_api_params);
11137 $response_obj = $sms_obj->sendMessage($pto, $share_message);
11138 if ($sms_obj->validateResponse($response_obj)) {
11139 $response['status'] = 1;
11140 } else {
11141 $response['error'] = $sms_obj->getLog();
11142 }
11143 } else {
11144 $response['error'] = 'No SMS Provider Configured';
11145 }
11146 } else {
11147 $response['error'] = 'Invalid Sending Method';
11148 }
11149 } else {
11150 $response['error'] = 'Invalid Booking ID';
11151 }
11152 } else {
11153 $response['error'] = 'Empty values';
11154 }
11155
11156 echo json_encode($response);
11157 exit;
11158 }
11159
11160 public function dayselectioncount() {
11161 //to be called via ajax
11162 $tsinit = VikRequest::getString('dinit', '', 'request');
11163 $tsend = VikRequest::getString('dend', '', 'request');
11164 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
11165 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
11166 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
11167 $diff = $ptsend - $ptsinit;
11168 if ($diff >= 172800) {
11169 $datef = VikBooking::getDateFormat(true);
11170 if ($datef=="%d/%m/%Y") {
11171 $df = 'd-m-Y';
11172 } else {
11173 $df = 'Y-m-d';
11174 }
11175 //minimum 2 days for excluding some days
11176 $daysdiff = floor($diff / 86400);
11177 $infoinit = getdate($ptsinit);
11178 $select = '';
11179 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
11180 for($i = 0; $i <= $daysdiff; $i++) {
11181 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
11182 $infots = getdate($ts);
11183 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
11184 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
11185 }
11186 $select .= '</select></div>';
11187 //excluded days of the week
11188 if ($daysdiff >= 14) {
11189 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
11190 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
11191 $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>';
11192 $select .= '</optgroup>';
11193 $select .= '</select></div>';
11194 }
11195 //
11196 echo $select;
11197 } else {
11198 echo '';
11199 }
11200 } else {
11201 echo '';
11202 }
11203 exit;
11204 }
11205
11206 public function createcheckindoc()
11207 {
11208 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
11209 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11210 }
11211
11212 $cid = VikRequest::getVar('cid', array(0));
11213 $id = $cid[0];
11214
11215 $dbo = JFactory::getDBO();
11216 $mainframe = JFactory::getApplication();
11217 $vbo_tn = VikBooking::getTranslator();
11218 $lang = JFactory::getLanguage();
11219 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11220 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
11221 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
11222 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
11223 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
11224 $dbo->setQuery($q);
11225 $row = $dbo->loadAssoc();
11226 if (!$row) {
11227 $mainframe->redirect('index.php');
11228 exit;
11229 }
11230 if (!empty($row['lang'])) {
11231 if ($lang->getTag() != $row['lang']) {
11232 if (VBOPlatformDetection::isWordPress()) {
11233 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
11234 } else {
11235 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
11236 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
11237 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
11238 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
11239 }
11240 }
11241 if ($vbo_tn->getDefaultLang() != $row['lang']) {
11242 // force the translation to start because contents should be translated
11243 $vbo_tn::$force_tolang = $row['lang'];
11244 }
11245 }
11246 $customer = array();
11247 $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'].";";
11248 $dbo->setQuery($q);
11249 $dbo->execute();
11250 if ($dbo->getNumRows() > 0) {
11251 $customer = $dbo->loadAssoc();
11252 if (!empty($customer['country'])) {
11253 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
11254 $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"/>';
11255 }
11256 }
11257 }
11258 if (!(count($customer) > 0)) {
11259 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11260 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11261 exit;
11262 }
11263 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
11264 //check if the signature has been submitted
11265 $signature_data = '';
11266 $cont_type = '';
11267 if (!empty($psignature)) {
11268 //check whether the format is accepted
11269 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
11270 $parts = explode(';base64,', $psignature);
11271 $cont_type_parts = explode('image/', $parts[0]);
11272 $cont_type = $cont_type_parts[1];
11273 if (!empty($parts[1])) {
11274 $signature_data = base64_decode($parts[1]);
11275 }
11276 }
11277 }
11278 if (!empty($signature_data)) {
11279 //write file
11280 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
11281 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
11282 $fp = fopen($filepath, 'w+');
11283 $bytes = fwrite($fp, $signature_data);
11284 fclose($fp);
11285 if ($bytes !== false && $bytes > 0) {
11286 //update the signature in the DB
11287 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
11288 $dbo->setQuery($q);
11289 $dbo->execute();
11290 $customer['signature'] = $sign_fname;
11291 //resize image for screens with high resolution
11292 if ($ppad_ratio > 1) {
11293 $new_width = floor(($ppad_width / 2));
11294 $creativik = new vikResizer();
11295 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
11296 } else {
11297 /**
11298 * @wponly - trigger files mirroring
11299 */
11300 VikBookingLoader::import('update.manager');
11301 VikBookingUpdateManager::triggerUploadBackup($filepath);
11302 //
11303 }
11304 //
11305 } else {
11306 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
11307 }
11308 }
11309 //
11310 //generate PDF for check-in document by parsing the apposite template file
11311 $booking_rooms = array();
11312 $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'].";";
11313 $dbo->setQuery($q);
11314 $dbo->execute();
11315 if ($dbo->getNumRows() > 0) {
11316 $booking_rooms = $dbo->loadAssocList();
11317 if (!empty($row['lang'])) {
11318 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
11319 }
11320 }
11321 if (!class_exists('TCPDF')) {
11322 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
11323 }
11324 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
11325
11326 /**
11327 * Trigger event to allow third party plugins to return a specific font name.
11328 *
11329 * @since 1.16.0 (J) - 1.6.0 (WP)
11330 */
11331 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
11332 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
11333 $usepdffont = $custom_pdf_font[0];
11334 }
11335
11336 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
11337 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
11338
11339 // build the proper document SID for bc
11340 $doc_sid = $row['sid'] ?: $row['idorderota'] ?: '';
11341 $pdffname = $row['id'] . '_' . $doc_sid . '.pdf';
11342
11343 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
11344 if (file_exists($pathpdf)) @unlink($pathpdf);
11345 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
11346 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
11347 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
11348 //Header for each page of the pdf
11349 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
11350 $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]);
11351 }
11352 //header and footer fonts
11353 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
11354 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
11355 //margins
11356 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
11357 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
11358 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
11359 //
11360 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
11361 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
11362 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
11363 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
11364 $pdf->SetPrintHeader(false);
11365 }
11366 if ($pdfparams['show_footer'] == 0) {
11367 $pdf->SetPrintFooter(false);
11368 }
11369 $pdf->AddPage();
11370 $pdf->writeHTML($checkin_body, true, false, true, false, '');
11371 $pdf->lastPage();
11372 $pdf->Output($pathpdf, 'F');
11373 if (!file_exists($pathpdf)) {
11374 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
11375 } else {
11376 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
11377 $dbo->setQuery($q);
11378 $dbo->execute();
11379 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
11380 /**
11381 * @wponly - trigger files mirroring
11382 */
11383 VikBookingLoader::import('update.manager');
11384 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
11385 //
11386 }
11387 //
11388 /**
11389 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
11390 */
11391 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
11392 exit;
11393 }
11394
11395 public function updatebookingcheckin()
11396 {
11397 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
11398 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11399 }
11400
11401 $cid = VikRequest::getVar('cid', array(0));
11402 $id = $cid[0];
11403
11404 $dbo = JFactory::getDbo();
11405 $app = JFactory::getApplication();
11406
11407 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11408 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
11409 $pguests = VikRequest::getVar('guests', array());
11410 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
11411 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
11412 $valid_actions = array(-1, 0, 1, 2);
11413 if (!in_array($pcheckin_action, $valid_actions)) {
11414 $app->redirect('index.php');
11415 exit;
11416 }
11417 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
11418 $dbo->setQuery($q);
11419 $dbo->execute();
11420 if ($dbo->getNumRows() < 1) {
11421 $app->redirect('index.php');
11422 exit;
11423 }
11424 $row = $dbo->loadAssoc();
11425 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
11426 $dbo->setQuery($q);
11427 $dbo->execute();
11428 if ($dbo->getNumRows() < 1) {
11429 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11430 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11431 exit;
11432 }
11433 $custorder = $dbo->loadAssoc();
11434 //update checked status and new total paid
11435 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
11436 $dbo->setQuery($q);
11437 $dbo->execute();
11438 // Booking History log for new amount paid (payment update)
11439 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
11440 $extra_data = new stdClass;
11441 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
11442 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
11443 }
11444 //
11445 //Booking History
11446 $hist_type = 'A';
11447 if ($pcheckin_action < 0) {
11448 $hist_type = 'Z';
11449 } elseif ($pcheckin_action == 1) {
11450 $hist_type = 'B';
11451 } elseif ($pcheckin_action == 2) {
11452 $hist_type = 'C';
11453 }
11454 $user = JFactory::getUser();
11455 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
11456 //
11457 //Guests Details
11458 $guests_details = array();
11459 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
11460 // grab also the fields for front-end pre check-in
11461 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
11462 //
11463 foreach ($pguests as $ind => $adults) {
11464 foreach ($adults as $aduind => $details) {
11465 foreach ($pax_fields as $key => $v) {
11466 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11467 if (!isset($guests_details[$ind])) {
11468 $guests_details[$ind] = array();
11469 }
11470 if (!isset($guests_details[$ind][$aduind])) {
11471 $guests_details[$ind][$aduind] = array();
11472 }
11473 $guests_details[$ind][$aduind][$key] = $details[$key];
11474 }
11475 }
11476 foreach ($pre_pax_fields as $key => $v) {
11477 if (isset($pax_fields[$key])) {
11478 // we must have parsed this back-end field already
11479 continue;
11480 }
11481 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11482 if (!isset($guests_details[$ind])) {
11483 $guests_details[$ind] = array();
11484 }
11485 if (!isset($guests_details[$ind][$aduind])) {
11486 $guests_details[$ind][$aduind] = array();
11487 }
11488 if (!isset($guests_details[$ind][$aduind][$key])) {
11489 $guests_details[$ind][$aduind][$key] = $details[$key];
11490 }
11491 }
11492 }
11493 }
11494 }
11495
11496 if ($guests_details) {
11497 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
11498 $curpaxdata = json_decode($custorder['pax_data'], true);
11499 if (is_array($curpaxdata) && $curpaxdata) {
11500 // scan new guest registration details
11501 foreach ($guests_details as $ind => $groom) {
11502 foreach ($groom as $aduind => $aduinfo) {
11503 if (isset($curpaxdata[$ind][$aduind])) {
11504 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
11505 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
11506 foreach ($guests_details[$ind][$aduind] as $key => $det) {
11507 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
11508 // this default pax field was specified as empty now, so we cannot merge it
11509 unset($guests_details[$ind][$aduind][$key]);
11510 }
11511 }
11512 }
11513 }
11514 }
11515
11516 /**
11517 * In order to not lose any custom registration data added through PMS reports,
11518 * we scan the previous registration data to ensure we keep them in the update.
11519 *
11520 * @since 1.16.10 (J) - 1.6.10 (WP)
11521 */
11522 foreach ($curpaxdata as $ind => $groom) {
11523 if (!isset($guests_details[$ind])) {
11524 // ignore deleted room registration
11525 continue;
11526 }
11527 foreach ($groom as $aduind => $aduinfo) {
11528 if (!isset($guests_details[$ind][$aduind]) || !is_array($aduinfo)) {
11529 // ignore deleted room-guest registration
11530 continue;
11531 }
11532 foreach ($aduinfo as $field_key => $field_val) {
11533 if (!isset($guests_details[$ind][$aduind][$field_key]) && !empty($field_val)) {
11534 // merge previous room-guest registration data
11535 $guests_details[$ind][$aduind][$field_key] = $field_val;
11536 }
11537 }
11538 }
11539 }
11540 }
11541
11542 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=" . $dbo->q(json_encode($guests_details)) . " WHERE `id`=" . (int) $custorder['id'] . ";";
11543 $dbo->setQuery($q);
11544 $dbo->execute();
11545 }
11546
11547 //'checked' status comments
11548 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11549 $dbo->setQuery($q);
11550 $dbo->execute();
11551
11552 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11553 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11554 exit;
11555 }
11556
11557 public function alterbooking()
11558 {
11559 $dbo = JFactory::getDbo();
11560 $app = JFactory::getApplication();
11561 $user = JFactory::getUser();
11562
11563 $response = array(
11564 'esit' => 1,
11565 'message' => '',
11566 'vcm' => '',
11567 );
11568
11569 // must be a string as it may contain a dash
11570 $pidorder = VikRequest::getString('idorder', '', 'request');
11571 $pidorder = intval(str_replace('-', '', $pidorder));
11572
11573 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11574 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11575 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11576 $ptodate = VikRequest::getString('todate', '', 'request');
11577 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11578 if ($pdebug == 1) {
11579 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11580 exit;
11581 }
11582
11583 $nowdf = VikBooking::getDateFormat(true);
11584 if ($nowdf == "%d/%m/%Y") {
11585 $df = 'd/m/Y';
11586 } elseif ($nowdf == "%m/%d/%Y") {
11587 $df = 'm/d/Y';
11588 } else {
11589 $df = 'Y/m/d';
11590 }
11591 $pcheckinh = 0;
11592 $pcheckinm = 0;
11593 $pcheckouth = 0;
11594 $pcheckoutm = 0;
11595 $timeopst = VikBooking::getTimeOpenStore();
11596 if (is_array($timeopst)) {
11597 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11598 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11599 $pcheckinh = $opent[0];
11600 $pcheckinm = $opent[1];
11601 $pcheckouth = $closet[0];
11602 $pcheckoutm = $closet[1];
11603 }
11604 $info_tsto = getdate(strtotime($ptodate));
11605 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11606 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11607 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11608 $ptodate = date('Y-m-d', $second);
11609 if (!($second > $first)) {
11610 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11611 exit;
11612 }
11613 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11614 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11615 exit;
11616 }
11617
11618 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11619 $dbo->setQuery($q, 0, 1);
11620 $dbo->execute();
11621 if (!$dbo->getNumRows()) {
11622 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11623 exit;
11624 }
11625 $ord = $dbo->loadAssoc();
11626
11627 $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;";
11628 $dbo->setQuery($q);
11629 $dbo->execute();
11630 $ordersrooms = $dbo->loadAssocList();
11631
11632 // store for VCM the current rooms before the modification
11633 $ord['rooms_info'] = $ordersrooms;
11634
11635 // package or custom rate
11636 $is_package = !empty($ord['pkg']) ? true : false;
11637 $is_cust_cost = false;
11638 foreach ($ordersrooms as $kor => $or) {
11639 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11640 $is_cust_cost = true;
11641 break;
11642 }
11643 }
11644
11645 // availability helper
11646 $av_helper = VikBooking::getAvailabilityInstance();
11647
11648 // room stay dates in case of split stay
11649 $room_stay_dates = [];
11650 if ($ord['split_stay']) {
11651 // no need to get the transient based on booking status, as the booking must be confirmed
11652 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11653 // immediately count the number of nights of stay for each split room
11654 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11655 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11656 }
11657 }
11658
11659 // determine if dates have changed
11660 $dates_changed = false;
11661 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11662 $dates_changed = true;
11663 }
11664
11665 $toswitch = array();
11666 $idbooked = array();
11667 $rooms_units = array();
11668 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11669 $dbo->setQuery($q);
11670 $dbo->execute();
11671 $all_rooms = $dbo->loadAssocList();
11672 foreach ($all_rooms as $rr) {
11673 $rooms_units[$rr['id']]['name'] = $rr['name'];
11674 $rooms_units[$rr['id']]['units'] = $rr['units'];
11675 }
11676
11677 // switch room
11678 if ($poldidroom != $pidroom) {
11679 foreach ($ordersrooms as $ind => $or) {
11680 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11681 if (!isset($idbooked[$or['idroom']])) {
11682 $idbooked[$or['idroom']] = 0;
11683 }
11684 // $idbooked is not really needed as switch is never made for the same room id
11685 $idbooked[$or['idroom']]++;
11686 //
11687 $orkey = count($toswitch);
11688 $toswitch[$orkey]['from'] = $or['idroom'];
11689 $toswitch[$orkey]['to'] = $pidroom;
11690 $toswitch[$orkey]['record'] = $or;
11691 $toswitch[$orkey]['record_ind'] = $ind;
11692 break;
11693 }
11694 }
11695 }
11696 if (count($toswitch)) {
11697 foreach ($toswitch as $ksw => $rsw) {
11698 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11699 $room_checkin = $ord['checkin'];
11700 $room_checkout = $ord['checkout'];
11701 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11702 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11703 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11704 }
11705 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11706 // the room is not available
11707 unset($toswitch[$ksw]);
11708 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11709 exit;
11710 }
11711 }
11712 if (count($toswitch)) {
11713 //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)
11714 reset($ordersrooms);
11715 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11716 $dbo->setQuery($q);
11717 $dbo->execute();
11718 //
11719 foreach ($toswitch as $ksw => $rsw) {
11720 // update room reservation record
11721 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11722 $dbo->setQuery($q);
11723 $dbo->execute();
11724 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11725
11726 // update Notes field for this booking to keep track of the previous room that was assigned
11727 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11728 if (!empty($prev_room_name)) {
11729 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11730 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11731 $dbo->setQuery($q);
11732 $dbo->execute();
11733 }
11734
11735 if ($ord['status'] == 'confirmed') {
11736 // update room record in _busy
11737 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'])) {
11738 // in case of a split stay it is fundamental to update the exact busy record ID
11739 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11740 $dbo->setQuery($q);
11741 $dbo->execute();
11742 } else {
11743 // regular processing of a room ID for a reservation, no matter which one, we switch it
11744 $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;";
11745 $dbo->setQuery($q);
11746 $dbo->execute();
11747 if ($dbo->getNumRows() == 1) {
11748 $cur_busy = $dbo->loadAssocList();
11749 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11750 $dbo->setQuery($q);
11751 $dbo->execute();
11752 }
11753 }
11754
11755 // if automated updates enabled, keep $response['vcm'] empty
11756 // Invoke Channel Manager
11757 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11758 $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>';
11759 }
11760 } elseif ($ord['status'] == 'standby') {
11761 // remove record in _tmplock
11762 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11763 $dbo->setQuery($q);
11764 $dbo->execute();
11765 }
11766 }
11767
11768 // check if sub-units should be assigned again when switching room
11769 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11770 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11771 $room_indexes_usemap = [];
11772 foreach ($new_order_rooms as $kor => $or) {
11773 $num = $kor + 1;
11774 // assign room specific unit
11775 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11776 $use_ind_key = 0;
11777 if ($room_indexes) {
11778 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11779 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11780 } else {
11781 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11782 }
11783 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11784 $dbo->setQuery($q);
11785 $dbo->execute();
11786 $room_indexes_usemap[$or['idroom']]++;
11787 }
11788 }
11789 }
11790
11791 // do not terminate the process when there is a switch, proceed to check the dates.
11792 }
11793 }
11794
11795 // change dates
11796 if ($dates_changed) {
11797 if ($ord['split_stay']) {
11798 // we do not allow to drag and change dates for rooms in a split stay reservation
11799 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11800 exit;
11801 }
11802
11803 // total nights of stay
11804 $daysdiff = $ord['days'];
11805
11806 // re-read ordersrooms (as rooms may have been switched)
11807 $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;";
11808 $dbo->setQuery($q);
11809 $dbo->execute();
11810 $ordersrooms = $dbo->loadAssocList();
11811
11812 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11813 $opertwounits = true;
11814 $units_counter = array();
11815 foreach ($ordersrooms as $ind => $or) {
11816 if (!isset($units_counter[$or['idroom']])) {
11817 $units_counter[$or['idroom']] = -1;
11818 }
11819 $units_counter[$or['idroom']]++;
11820 }
11821
11822 foreach ($ordersrooms as $ind => $or) {
11823 $num = $ind + 1;
11824 $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'] . ";";
11825 $dbo->setQuery($check);
11826 $dbo->execute();
11827 if ($dbo->getNumRows() > 0) {
11828 $busy = $dbo->loadAssocList();
11829 foreach ($groupdays as $gday) {
11830 $bfound = 0;
11831 foreach ($busy as $bu) {
11832 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11833 $bfound++;
11834 }
11835 }
11836 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11837 $opertwounits = false;
11838 break 2;
11839 }
11840 }
11841 }
11842 }
11843 if ($opertwounits !== true) {
11844 $response['esit'] = 0;
11845 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11846 echo json_encode($response);
11847 exit;
11848 }
11849
11850 // update dates and busy records
11851 $realback = VikBooking::getHoursRoomAvail() * 3600;
11852 $realback += $second;
11853 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11854 $dbo->setQuery($q);
11855 $dbo->execute();
11856 if ($ord['status'] == 'confirmed') {
11857 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11858 $dbo->setQuery($q);
11859 $dbo->execute();
11860 $allbusy = $dbo->loadAssocList();
11861 foreach ($allbusy as $bb) {
11862 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11863 $dbo->setQuery($q);
11864 $dbo->execute();
11865 }
11866 // if automated updates enabled, keep $response['vcm'] empty
11867 // Invoke Channel Manager
11868 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11869 $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>';
11870 }
11871 }
11872 $response['message'] .= JText::translate('RESUPDATED')."\n";
11873 }
11874
11875 if (count($toswitch)) {
11876 /**
11877 * Rooms have changed so the new rates must be re-calculated.
11878 * Maybe they should be calculated in any case, even if just
11879 * the dates have changed. For the moment the rates are reset.
11880 */
11881 }
11882
11883 // unset any previously booked room due to calendar sharing
11884 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11885 // check if some of the rooms booked have shared calendars
11886 VikBooking::updateSharedCalendars($ord['id']);
11887 //
11888
11889 //Booking History
11890 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11891 //
11892
11893 $vcm_autosync = VikBooking::vcmAutoUpdate();
11894 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11895 //unset the vcm property as no buttons should be displayed when in auto-sync
11896 $response['vcm'] = '';
11897 $vcm_obj = VikBooking::getVcmInvoker();
11898 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11899 $sync_result = $vcm_obj->doSync();
11900 if ($sync_result === false) {
11901 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11902 }
11903 }
11904
11905 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11906 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11907 VikError::raiseNotice('', $response['vcm']);
11908 }
11909
11910 $response['message'] = nl2br($response['message']);
11911 echo json_encode($response);
11912 exit;
11913 }
11914
11915 public function modroomrateplans() {
11916 $dbo = JFactory::getDBO();
11917 $session = JFactory::getSession();
11918 $updforvcm = $session->get('vbVcmRatesUpd', '');
11919 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11920 $pid_room = VikRequest::getInt('id_room', '', 'request');
11921 $pid_price = VikRequest::getInt('id_price', '', 'request');
11922 $ptype = VikRequest::getString('type', '', 'request');
11923 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11924 $ptodate = VikRequest::getString('todate', '', 'request');
11925 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11926 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11927 exit;
11928 }
11929 $price_record = array();
11930 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11931 $dbo->setQuery($q);
11932 $dbo->execute();
11933 if ($dbo->getNumRows() > 0) {
11934 $price_record = $dbo->loadAssoc();
11935 }
11936 if (!count($price_record) > 0) {
11937 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11938 exit;
11939 }
11940 $current_closed = array();
11941 if (!empty($price_record['closingd'])) {
11942 $current_closed = json_decode($price_record['closingd'], true);
11943 }
11944 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11945 $start_ts = strtotime($pfromdate);
11946 $end_ts = strtotime($ptodate);
11947 $infostart = getdate($start_ts);
11948 $all_days = array();
11949 $output = array();
11950 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11951 $all_days[] = date('Y-m-d', $infostart[0]);
11952 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11953 $output[$indkey] = array();
11954 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11955 }
11956 if ($ptype == 'close') {
11957 if (!array_key_exists($pid_room, $current_closed)) {
11958 $current_closed[$pid_room] = array();
11959 }
11960 foreach ($all_days as $daymod) {
11961 if (!in_array($daymod, $current_closed[$pid_room])) {
11962 $current_closed[$pid_room][] = $daymod;
11963 }
11964 }
11965 } else {
11966 //open
11967 if (array_key_exists($pid_room, $current_closed)) {
11968 foreach ($all_days as $daymod) {
11969 if (in_array($daymod, $current_closed[$pid_room])) {
11970 foreach ($current_closed[$pid_room] as $ck => $cv) {
11971 if ($daymod == $cv) {
11972 unset($current_closed[$pid_room][$ck]);
11973 }
11974 }
11975 }
11976 }
11977 } else {
11978 $current_closed[$pid_room] = array();
11979 }
11980 }
11981 if (!count($current_closed[$pid_room]) > 0) {
11982 unset($current_closed[$pid_room]);
11983 }
11984 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11985 $dbo->setQuery($q);
11986 $dbo->execute();
11987 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
11988 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
11989 foreach ($output as $ok => $ov) {
11990 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
11991 }
11992 //update session values
11993 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
11994 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
11995 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
11996 } else {
11997 $updforvcm['dfrom'] = $start_ts;
11998 }
11999 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
12000 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
12001 } else {
12002 $updforvcm['dto'] = $end_ts;
12003 }
12004 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
12005 if (!in_array($pid_room, $updforvcm['rooms'])) {
12006 $updforvcm['rooms'][] = $pid_room;
12007 }
12008 } else {
12009 $updforvcm['rooms'] = array($pid_room);
12010 }
12011 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
12012 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
12013 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
12014 $updforvcm['rplans'][$pid_room][] = $pid_price;
12015 }
12016 } else {
12017 $updforvcm['rplans'][$pid_room] = array($pid_price);
12018 }
12019 } else {
12020 $updforvcm['rplans'] = array($pid_room => array($pid_price));
12021 }
12022 $session->set('vbVcmRatesUpd', $updforvcm);
12023 //
12024 $pdebug = VikRequest::getInt('e4j_debug', '', 'request');
12025 if ($pdebug == 1) {
12026 echo "e4j.error.\n".print_r($current_closed, true)."\n";
12027 echo print_r($output, true)."\n\n";
12028 echo print_r($all_days, true)."\n";
12029 }
12030 echo json_encode($output);
12031 exit;
12032 }
12033
12034 public function icsexportlaunch() {
12035 $dbo = JFactory::getDBO();
12036 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12037 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12038 $pstatus = VikRequest::getString('status', '', 'request');
12039 $validstatus = array('confirmed', 'standby', 'cancelled');
12040 $filterstatus = '';
12041 $filterfirst = 0;
12042 $filtersecond = 0;
12043 $nowdf = VikBooking::getDateFormat(true);
12044 if ($nowdf == "%d/%m/%Y") {
12045 $df = 'd/m/Y';
12046 } elseif ($nowdf == "%m/%d/%Y") {
12047 $df = 'm/d/Y';
12048 } else {
12049 $df = 'Y/m/d';
12050 }
12051 $currencyname = VikBooking::getCurrencyName();
12052 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12053 $filterstatus = $pstatus;
12054 }
12055 if (!empty($pcheckindate)) {
12056 if (VikBooking::dateIsValid($pcheckindate)) {
12057 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12058 $filterfirst = $first;
12059 }
12060 }
12061 if (!empty($pcheckoutdate)) {
12062 if (VikBooking::dateIsValid($pcheckoutdate)) {
12063 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12064 if ($second > $first) {
12065 $filtersecond = $second;
12066 }
12067 }
12068 }
12069 $clause = array();
12070 if ($filterfirst > 0) {
12071 $clause[] = "`o`.`checkin` >= ".$filterfirst;
12072 }
12073 if ($filtersecond > 0) {
12074 $clause[] = "`o`.`checkout` <= ".$filtersecond;
12075 }
12076 if (!empty($filterstatus)) {
12077 $clause[] = "`o`.`status` = '".$filterstatus."'";
12078 }
12079 $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;";
12080 $dbo->setQuery($q);
12081 $dbo->execute();
12082 if ($dbo->getNumRows() > 0) {
12083 $orders = $dbo->loadAssocList();
12084 $icscontent = "BEGIN:VCALENDAR\n";
12085 $icscontent .= "VERSION:2.0\n";
12086 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
12087 $icscontent .= "CALSCALE:GREGORIAN\n";
12088 $str = "";
12089 foreach ($orders as $kord => $ord) {
12090 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12091 continue;
12092 }
12093 $usecurrencyname = $currencyname;
12094 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12095 $statusstr = '';
12096 if ($ord['status'] == 'confirmed') {
12097 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12098 } elseif ($ord['status'] == 'standby') {
12099 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12100 } elseif ($ord['status'] == 'cancelled') {
12101 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12102 }
12103 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
12104 /**
12105 * @wponly Rewrite URI for front-end
12106 */
12107 $uri = str_replace(JUri::root(), '', $uri);
12108 $model = JModel::getInstance('vikbooking', 'shortcodes');
12109 $itemid = $model->best('booking');
12110 if ($itemid) {
12111 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
12112 }
12113 //
12114 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
12115 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12116 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
12117 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
12118 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
12119 $str .= "BEGIN:VEVENT\n";
12120 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12121 $str .= "UID:" . uniqid() . "\n";
12122 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12123 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
12124 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
12125 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
12126 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12127 $str .= "END:VEVENT\n";
12128 }
12129 $icscontent .= $str;
12130 $icscontent .= "END:VCALENDAR\n";
12131 //download file from buffer
12132 header("Content-Type: application/octet-stream; ");
12133 header("Cache-Control: no-store, no-cache");
12134 header('Content-Disposition: attachment; filename="bookings_export.ics"');
12135 $f = fopen('php://output', "w");
12136 fwrite($f, $icscontent);
12137 fclose($f);
12138 exit;
12139 } else {
12140 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
12141 $mainframe = JFactory::getApplication();
12142 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12143 }
12144 }
12145
12146 public function csvexportlaunch()
12147 {
12148 $dbo = JFactory::getDbo();
12149 $app = JFactory::getApplication();
12150
12151 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
12152 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
12153 $pchfilt = VikRequest::getString('chfilt', '', 'request');
12154 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
12155 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12156 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12157 $pstatus = VikRequest::getString('status', '', 'request');
12158 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
12159 $pformat = VikRequest::getString('format', 'csv', 'request');
12160
12161 // let the report class (a generic one) generate the CSV file in the proper format
12162 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
12163
12164 $validstatus = array('confirmed', 'standby', 'cancelled');
12165 $validdates = array('ts', 'checkin', 'checkout');
12166
12167 $filterdate = '';
12168 $filterstatus = '';
12169 $first = 0;
12170 $filterfirst = 0;
12171 $filtersecond = 0;
12172 $nowdf = VikBooking::getDateFormat(true);
12173 if ($nowdf == "%d/%m/%Y") {
12174 $df = 'd/m/Y';
12175 } elseif ($nowdf == "%m/%d/%Y") {
12176 $df = 'm/d/Y';
12177 } else {
12178 $df = 'Y/m/d';
12179 }
12180 $datesep = VikBooking::getDateSeparator(true);
12181 $currencyname = VikBooking::getCurrencyName();
12182
12183 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12184 $filterstatus = $pstatus;
12185 }
12186 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
12187 $filterdate = $pdatefilt;
12188 }
12189 if (!empty($pcheckindate) && !empty($filterdate)) {
12190 if (VikBooking::dateIsValid($pcheckindate)) {
12191 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12192 $filterfirst = $first;
12193 }
12194 }
12195 if (!empty($pcheckoutdate) && !empty($filterdate)) {
12196 if (VikBooking::dateIsValid($pcheckoutdate)) {
12197 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12198 if ($second > $first) {
12199 $filtersecond = $second;
12200 }
12201 }
12202 }
12203 $clause = array();
12204 if ($filterfirst > 0) {
12205 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
12206 }
12207 if ($filtersecond > 0) {
12208 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
12209 }
12210 if (!empty($filterstatus)) {
12211 $clause[] = "`o`.`status` = '".$filterstatus."'";
12212 }
12213 if (!empty($pchfilt)) {
12214 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
12215 }
12216 if (!empty($ppayfilt)) {
12217 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
12218 }
12219 if (!empty($proomfilt)) {
12220 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
12221 }
12222
12223 if (!empty($pcatfilt)) {
12224 $room_cat_ids = array();
12225 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
12226 $dbo->setQuery($q);
12227 $dbo->execute();
12228 if ($dbo->getNumRows()) {
12229 $records = $dbo->loadAssocList();
12230 foreach ($records as $rcat) {
12231 $parts = explode(';', $rcat['idcat']);
12232 if (in_array($pcatfilt, $parts)) {
12233 $room_cat_ids[] = $rcat['id'];
12234 }
12235 }
12236 }
12237 if (count($room_cat_ids)) {
12238 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
12239 }
12240 }
12241
12242 $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;";
12243 $dbo->setQuery($q);
12244 $orders = $dbo->loadAssocList();
12245 if (!$orders) {
12246 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
12247 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12248 $app->close();
12249 }
12250
12251 // options
12252 $all_options = array();
12253 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
12254 $dbo->setQuery($q);
12255 $options = $dbo->loadAssocList();
12256 if ($options) {
12257 foreach ($options as $ok => $ov) {
12258 $all_options[$ov['id']] = $ov;
12259 }
12260 }
12261
12262 // set CSV columns
12263 $report_obj->setReportCols([
12264 [
12265 'label' => JText::translate('VBDASHBOOKINGID'),
12266 ],
12267 [
12268 'label' => JText::translate('VBPVIEWORDERSONE'),
12269 ],
12270 [
12271 'label' => JText::translate('VBCSVCHECKIN'),
12272 ],
12273 [
12274 'label' => JText::translate('VBCSVCHECKOUT'),
12275 ],
12276 [
12277 'label' => JText::translate('VBCSVNIGHTS'),
12278 ],
12279 [
12280 'label' => JText::translate('VBCSVROOM'),
12281 ],
12282 [
12283 'label' => JText::translate('VBCSVPEOPLE'),
12284 ],
12285 [
12286 'label' => JText::translate('VBCSVCUSTINFO'),
12287 ],
12288 [
12289 'label' => JText::translate('ORDER_SPREQUESTS'),
12290 ],
12291 [
12292 'label' => JText::translate('ORDER_NOTES'),
12293 ],
12294 [
12295 'label' => JText::translate('VBCSVCREATEDBY'),
12296 ],
12297 [
12298 'label' => JText::translate('VBCSVCUSTMAIL'),
12299 ],
12300 [
12301 'label' => JText::translate('ORDER_PHONE'),
12302 ],
12303 [
12304 'label' => JText::translate('VBCSVOPTIONS'),
12305 ],
12306 [
12307 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
12308 ],
12309 [
12310 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
12311 ],
12312 [
12313 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
12314 ],
12315 [
12316 'label' => JText::translate('VBCSVTOTAL'),
12317 ],
12318 [
12319 'label' => JText::translate('VBCSVTOTPAID'),
12320 ],
12321 [
12322 'label' => JText::translate('VBCSVTOTTAXES'),
12323 ],
12324 ]);
12325
12326 // prepare the container for the CSV rows
12327 $orderscsv = [];
12328
12329 // availability helper
12330 $av_helper = VikBooking::getAvailabilityInstance();
12331
12332 $room_inds = [];
12333 $room_stay_dates = [];
12334 foreach ($orders as $kord => $ord) {
12335 // room index in this booking
12336 if (!isset($room_inds[$ord['id']])) {
12337 $room_inds[$ord['id']] = -1;
12338 }
12339 $room_inds[$ord['id']]++;
12340
12341 /**
12342 * Split stay reservation.
12343 *
12344 * @since 1.16.0 (J) - 1.6.0 (WP)
12345 */
12346 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
12347 if ($ord['split_stay']) {
12348 if ($ord['status'] == 'confirmed') {
12349 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
12350 } else {
12351 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
12352 }
12353 // immediately count the number of nights of stay for each split room
12354 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
12355 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
12356 // overwrite values for compatibility with non-confirmed bookings
12357 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
12358 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
12359 }
12360 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
12361 // overwrite the whole array
12362 $room_stay_dates[$sps_r_k] = $sps_r_v;
12363 }
12364 }
12365
12366 // determine nights and dates for this room booking
12367 $booking_nights = $ord['days'];
12368 $booking_checkin = $ord['checkin'];
12369 $booking_checkout = $ord['checkout'];
12370 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']) {
12371 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
12372 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
12373 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
12374 }
12375
12376 $usecurrencyname = $currencyname;
12377 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12378 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12379 $custinfostr = str_replace(",", " ", $ord['custdata']);
12380 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
12381 if (count($customer)) {
12382 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
12383 }
12384 $special_requests = '';
12385 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12386 $special_requests = $match[1];
12387 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12388 $special_requests = $match[1];
12389 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
12390 $special_requests = $match[1];
12391 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
12392 $special_requests = $match[1];
12393 }
12394 $paystr = '';
12395 if (!empty($ord['idpayment'])) {
12396 $payparts = explode('=', $ord['idpayment']);
12397 $paystr = $payparts[1];
12398 }
12399 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
12400 $statusstr = '';
12401 if ($ord['status'] == 'confirmed') {
12402 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12403 } elseif ($ord['status'] == 'standby') {
12404 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12405 } elseif ($ord['status'] == 'cancelled') {
12406 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12407 }
12408 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
12409 if ($ord['roomsnum'] > 1) {
12410 // take the cost for the individual room
12411 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
12412 }
12413 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
12414 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12415 // total paid will be printed only for the last room booked
12416 $totalpaidstring = '';
12417 }
12418 $options_str = '';
12419 if (!empty($ord['optionals'])) {
12420 $stepo = explode(";", $ord['optionals']);
12421 foreach ($stepo as $roptkey => $oo) {
12422 if (!empty($oo)) {
12423 $stept = explode(":", $oo);
12424 if (array_key_exists($stept[0], $all_options)) {
12425 $actopt = $all_options[$stept[0]];
12426 $optpcent = false;
12427 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
12428 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
12429 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
12430 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
12431 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
12432 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
12433 $agestept = explode('-', $stept[1]);
12434 $stept[1] = $agestept[0];
12435 $chvar = $agestept[1];
12436 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
12437 $optpcent = true;
12438 }
12439 $actopt['chageintv'] = $chvar;
12440 if (isset($optagenames[($chvar - 1)])) {
12441 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
12442 }
12443 if (isset($optagecosts[($chvar - 1)])) {
12444 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
12445 } else {
12446 $realcost = 0;
12447 }
12448 } else {
12449 // VBO 1.11 - options percentage cost of the room total fee
12450 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
12451 //
12452 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
12453 }
12454 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
12455 $realcost=$actopt['maxprice'];
12456 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
12457 $realcost = $actopt['maxprice'] * $stept[1];
12458 }
12459 }
12460 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
12461 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
12462 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
12463 }
12464 }
12465 }
12466 }
12467
12468 // custom extra costs
12469 if (!empty($ord['extracosts'])) {
12470 $cur_extra_costs = json_decode($ord['extracosts'], true);
12471 foreach ($cur_extra_costs as $eck => $ecv) {
12472 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
12473 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
12474 }
12475 }
12476
12477 // taxes
12478 $taxes_str = '';
12479 if ($ord['tot_taxes'] > 0.00) {
12480 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
12481 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
12482 $tax_breakdown = json_decode($ord['breakdown'], true);
12483 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
12484 if (count($tax_breakdown)) {
12485 foreach ($tax_breakdown as $tbkk => $tbkv) {
12486 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
12487 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
12488 }
12489 }
12490 }
12491 }
12492 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12493 // total taxes will be printed only for the last room booked
12494 $taxes_str = '';
12495 }
12496
12497 // created by
12498 $created_by = '';
12499 if (!empty($ord['ujid'])) {
12500 $creator = new JUser($ord['ujid']);
12501 if (property_exists($creator, 'name')) {
12502 $created_by = $creator->name.' ('.$creator->username.')';
12503 }
12504 }
12505 if (empty($created_by) && !empty($ord['t_first_name'])) {
12506 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
12507 }
12508
12509 // push line for export
12510 $orderscsv[] = [
12511 [
12512 'value' => $ord['id'],
12513 ],
12514 [
12515 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
12516 ],
12517 [
12518 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
12519 ],
12520 [
12521 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
12522 ],
12523 [
12524 'value' => $booking_nights,
12525 ],
12526 [
12527 'value' => $ord['name'],
12528 ],
12529 [
12530 'value' => $peoplestr,
12531 ],
12532 [
12533 'value' => $custinfostr,
12534 ],
12535 [
12536 'value' => $special_requests,
12537 ],
12538 [
12539 'value' => $ord['adminnotes'],
12540 ],
12541 [
12542 'value' => $created_by,
12543 ],
12544 [
12545 'value' => $ord['custmail'],
12546 ],
12547 [
12548 'value' => $ord['phone'],
12549 ],
12550 [
12551 'value' => $options_str,
12552 ],
12553 [
12554 'value' => $paystr,
12555 ],
12556 [
12557 'value' => $ordnumbstr,
12558 ],
12559 [
12560 'value' => $statusstr,
12561 ],
12562 [
12563 'value' => $totalstring,
12564 ],
12565 [
12566 'value' => $totalpaidstring,
12567 ],
12568 [
12569 'value' => $taxes_str,
12570 ],
12571 ];
12572 }
12573
12574 // set CSV rows
12575 $report_obj->setReportRows($orderscsv);
12576
12577 // build lines to export
12578 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12579
12580 // set export file name
12581 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12582
12583 // force the download of the CSV file
12584 $report_obj->outputHeaders();
12585
12586 // send lines to output
12587 $report_obj->outputCSV($csvlines);
12588
12589 exit;
12590 }
12591
12592 public function exportcustomerslaunch() {
12593 $cid = VikRequest::getVar('cid', array(0));
12594 $dbo = JFactory::getDBO();
12595 $pnotes = VikRequest::getInt('notes', '', 'request');
12596 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12597 $ppin = VikRequest::getInt('pin', '', 'request');
12598 $pcountry = VikRequest::getString('country', '', 'request');
12599 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12600 $ptodate = VikRequest::getString('todate', '', 'request');
12601 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12602 $clauses = array();
12603 if (count($cid) > 0 && !empty($cid[0])) {
12604 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12605 }
12606 if (!empty($pcountry)) {
12607 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12608 }
12609 $datescol = '`bk`.`ts`';
12610 if ($pdatefilt > 0) {
12611 if ($pdatefilt == 1) {
12612 $datescol = '`bk`.`ts`';
12613 } elseif ($pdatefilt == 2) {
12614 $datescol = '`bk`.`checkin`';
12615 } elseif ($pdatefilt == 3) {
12616 $datescol = '`bk`.`checkout`';
12617 }
12618 }
12619 if (!empty($pfromdate)) {
12620 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12621 $clauses[] = $datescol.">=".$from_ts;
12622 }
12623 if (!empty($ptodate)) {
12624 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12625 $clauses[] = $datescol."<=".$to_ts;
12626 }
12627 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12628 $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`,".
12629 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12630 "`cy`.`country_3_code`,`cy`.`country_name` ".
12631 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12632 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12633 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12634 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12635 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` ".
12636 "ORDER BY `c`.`last_name` ASC;";
12637 $dbo->setQuery($q);
12638 $dbo->execute();
12639 if (!($dbo->getNumRows() > 0)) {
12640 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12641 $mainframe = JFactory::getApplication();
12642 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12643 exit;
12644 }
12645 $customers = $dbo->loadAssocList();
12646 $csvlines = array();
12647 $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'));
12648 if ($ppin > 0) {
12649 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12650 }
12651 if ($pscanimg > 0) {
12652 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12653 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12654 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12655 }
12656 if ($pnotes > 0) {
12657 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12658 }
12659 $csvlines[] = $csvheadline;
12660 foreach ($customers as $customer) {
12661 $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']);
12662 if ($ppin > 0) {
12663 $csvcustomerline[] = $customer['pin'];
12664 }
12665 if ($pscanimg > 0) {
12666 $csvcustomerline[] = $customer['doctype'];
12667 $csvcustomerline[] = $customer['docnum'];
12668 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12669 }
12670 if ($pnotes > 0) {
12671 $csvcustomerline[] = $customer['notes'];
12672 }
12673 $csvlines[] = $csvcustomerline;
12674 }
12675 header("Content-type: text/csv");
12676 header("Cache-Control: no-store, no-cache");
12677 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12678 $outstream = fopen("php://output", 'w');
12679 foreach ($csvlines as $csvline) {
12680 fputcsv($outstream, $csvline);
12681 }
12682 fclose($outstream);
12683 exit;
12684 }
12685
12686 public function renewsession() {
12687 /*
12688 * @wponly
12689 * We just destroy the session
12690 */
12691 JSessionHandler::destroy();
12692 $mainframe = JFactory::getApplication();
12693 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12694 }
12695
12696 public function trackings() {
12697 VikBookingHelper::printHeader("trackings");
12698
12699 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12700
12701 parent::display();
12702
12703 if (VikBooking::showFooter()) {
12704 VikBookingHelper::printFooter();
12705 }
12706 }
12707
12708 public function trkconfig() {
12709 VikBookingHelper::printHeader("trackings");
12710
12711 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12712
12713 parent::display();
12714
12715 if (VikBooking::showFooter()) {
12716 VikBookingHelper::printFooter();
12717 }
12718 }
12719
12720 public function savetrkconfigstay() {
12721 if (!JSession::checkToken()) {
12722 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12723 }
12724 $this->do_savetrkconfig(true);
12725 }
12726
12727 public function savetrkconfig() {
12728 if (!JSession::checkToken()) {
12729 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12730 }
12731 $this->do_savetrkconfig();
12732 }
12733
12734 private function do_savetrkconfig($stay = false) {
12735 $dbo = JFactory::getDBO();
12736 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12737 $trkenabled = $trkenabled == 1 ? 1 : 0;
12738 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12739 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12740 $trkcampname = VikRequest::getVar('trkcampname', array());
12741 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12742 $trkcampval = VikRequest::getVar('trkcampval', array());
12743 $trkcampaigns = array();
12744 foreach ($trkcampname as $k => $v) {
12745 if (empty($trkcampkey[$k])) {
12746 continue;
12747 }
12748 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12749 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12750 $trkcampaigns[$trkcampkey[$k]] = array(
12751 'key' => $trkcampkey[$k],
12752 'value' => $trkcampval[$k],
12753 'name' => $name,
12754 );
12755 }
12756
12757 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12758 $dbo->setQuery($q);
12759 $dbo->execute();
12760 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12761 $dbo->setQuery($q);
12762 $dbo->execute();
12763 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12764 $dbo->setQuery($q);
12765 $dbo->execute();
12766
12767 $mainframe = JFactory::getApplication();
12768 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12769 }
12770
12771 public function modtracking() {
12772 $dbo = JFactory::getDbo();
12773 $cid = VikRequest::getVar('cid', array());
12774 foreach ($cid as $id) {
12775 if (!empty($id)) {
12776 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12777 $dbo->setQuery($q);
12778 $dbo->execute();
12779 if ($dbo->getNumRows()) {
12780 $data = $dbo->loadAssoc();
12781 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12782 $dbo->setQuery($q);
12783 $dbo->execute();
12784 }
12785 }
12786 }
12787 $mainframe = JFactory::getApplication();
12788 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12789 }
12790
12791 public function removetrackings()
12792 {
12793 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
12794 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
12795 }
12796
12797 $ids = VikRequest::getVar('cid', array());
12798 $dbo = JFactory::getDbo();
12799
12800 foreach ($ids as $d) {
12801 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12802 $dbo->setQuery($q);
12803 $dbo->execute();
12804 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12805 $dbo->setQuery($q);
12806 $dbo->execute();
12807 }
12808
12809 $mainframe = JFactory::getApplication();
12810 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12811 }
12812
12813 /**
12814 * Invokes the Tracker class to obtain
12815 * geo information about the IP addresses.
12816 * This task is called via ajax.
12817 *
12818 * @since 1.11
12819 */
12820 public function getgeoinfo() {
12821 $ips = VikRequest::getVar('ips', array());
12822 if (!count($ips)) {
12823 echo 'e4j.error.empty IPs';
12824 exit;
12825 }
12826
12827 // require the Tracker class without instantiating the object
12828 VikBooking::getTracker(true);
12829 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12830
12831 if ($geo_info === false) {
12832 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12833 exit;
12834 }
12835
12836 // update db values and compose response
12837 $dbo = JFactory::getDbo();
12838 $resp = array();
12839 foreach ($geo_info as $id => $geo) {
12840 if (is_null($geo) || $geo === false) {
12841 continue;
12842 }
12843 // compose geo info string
12844 $geovals = array();
12845 if (!empty($geo['city'])) {
12846 array_push($geovals, $geo['city']);
12847 }
12848 if (!empty($geo['region'])) {
12849 array_push($geovals, $geo['region']);
12850 }
12851 $threecode = '';
12852 $cname = '';
12853 if (!empty($geo['country'])) {
12854 // returned country is a 2-char code, get the 3-char country code
12855 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12856 $dbo->setQuery($q);
12857 $dbo->execute();
12858 if ($dbo->getNumRows()) {
12859 $cinfo = $dbo->loadAssoc();
12860 $threecode = $cinfo['country_3_code'];
12861 $cname = $cinfo['country_name'];
12862 }
12863 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12864 }
12865
12866 // full geo information string
12867 $geoinfostr = implode(', ', $geovals);
12868
12869 // push data to the response pool
12870 $resp[$id] = array();
12871 $resp[$id]['geo'] = $geoinfostr;
12872 if (!empty($cname)) {
12873 $resp[$id]['country'] = $cname;
12874 }
12875 if (!empty($threecode)) {
12876 $resp[$id]['country3'] = $threecode;
12877 }
12878
12879 // update main tracking record
12880 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12881 $dbo->setQuery($q);
12882 $dbo->execute();
12883 }
12884
12885 // output the JSON response
12886 echo json_encode($resp);
12887 exit;
12888 }
12889
12890 /**
12891 * Counts the orphan dates for all published rooms
12892 * depending on their restrictions and booked dates.
12893 * By default, the task takes up to 3 months ahead.
12894 * It is possible to filter the request by rooms and months.
12895 * This task should be called via ajax.
12896 *
12897 * @since 1.11
12898 */
12899 public function orphanscount()
12900 {
12901 $dbo = JFactory::getDbo();
12902 $orphans = array();
12903
12904 $nowdf = VikBooking::getDateFormat();
12905 if ($nowdf == "%d/%m/%Y") {
12906 $df = 'd/m/Y';
12907 } elseif ($nowdf == "%m/%d/%Y") {
12908 $df = 'm/d/Y';
12909 } else {
12910 $df = 'Y/m/d';
12911 }
12912
12913 // global min los
12914 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12915 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12916
12917 // rooms and dates
12918 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12919 $months = VikRequest::getInt('months', 3, 'request');
12920 $from = VikRequest::getString('from', '', 'request');
12921 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12922 if (!empty($from)) {
12923 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12924 if (!empty($fromts)) {
12925 // custom starting date
12926 $today = $fromts;
12927 }
12928 }
12929 $until = strtotime("+{$months} months", $today);
12930
12931 // load all rooms
12932 $rooms = array();
12933 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12934 $dbo->setQuery($q);
12935 $dbo->execute();
12936 if ($dbo->getNumRows()) {
12937 $allrooms = $dbo->loadAssocList();
12938 foreach ($allrooms as $r) {
12939 $rooms[$r['id']] = $r;
12940 }
12941 }
12942 if (!count($rooms)) {
12943 // no rooms found, exit
12944 echo json_encode($orphans);
12945 exit;
12946 }
12947
12948 // load availabilities
12949 $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.");";
12950 $dbo->setQuery($q);
12951 $dbo->execute();
12952 if (!$dbo->getNumRows()) {
12953 // no booked dates found, exit
12954 echo json_encode($orphans);
12955 exit;
12956 }
12957 $busy = $dbo->loadAssocList();
12958
12959 // sort booked dates by room id
12960 $rooms_busy = array();
12961 foreach ($busy as $b) {
12962 if (!isset($rooms_busy[$b['idroom']])) {
12963 $rooms_busy[$b['idroom']] = array();
12964 }
12965 array_push($rooms_busy[$b['idroom']], $b);
12966 }
12967
12968 // load restrictions
12969 $rooms_restr = array();
12970 foreach ($rooms as $rid => $r) {
12971 $restrictions = VikBooking::loadRestrictions(true, array($rid));
12972 if (count($restrictions)) {
12973 $rooms_restr[$rid] = $restrictions;
12974 }
12975 }
12976 if (!count($rooms_restr) && $glob_minlos < 2) {
12977 // no restrictions found and minlos=1, exit
12978 echo json_encode($orphans);
12979 exit;
12980 }
12981
12982 // count availability and minlos per day
12983 $rooms_data = array();
12984 foreach ($rooms as $rid => $r) {
12985 $rooms_data[$rid] = array(
12986 'avail' => array(),
12987 'restr' => array()
12988 );
12989 $nowts = getdate($today);
12990 while ($nowts[0] <= $until) {
12991 $dateind = date('Y-m-d', $nowts[0]);
12992
12993 // remaining availability
12994 if (!isset($rooms_busy[$rid])) {
12995 // no bookings for this room, set full availability for this day
12996 $rooms_data[$rid]['avail'][] = array(
12997 'dt' => $dateind,
12998 'units' => $r['units']
12999 );
13000 } else {
13001 // check remaining availability for this day
13002 $totfound = 0;
13003 foreach ($rooms_busy[$rid] as $b) {
13004 $tmpone = getdate($b['checkin']);
13005 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
13006 $ritts = strtotime($rit);
13007 $tmptwo = getdate($b['checkout']);
13008 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
13009 $conts = strtotime($con);
13010 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
13011 $totfound++;
13012 }
13013 }
13014 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
13015 $rooms_data[$rid]['avail'][] = array(
13016 'dt' => $dateind,
13017 'units' => ($r['units'] - $totfound)
13018 );
13019 }
13020
13021 // restrictions
13022 if (!isset($rooms_restr[$rid])) {
13023 // no restrictions for this room, set global minlos for this day
13024 $rooms_data[$rid]['restr'][] = array(
13025 'dt' => $dateind,
13026 'minlos' => $glob_minlos
13027 );
13028 } else {
13029 // get restriction for this day
13030 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
13031 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13032
13033 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
13034 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
13035
13036 $rooms_data[$rid]['restr'][] = array(
13037 'dt' => $dateind,
13038 'minlos' => $minlos
13039 );
13040 }
13041
13042 // next loop
13043 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13044 $nowts = getdate($dayts);
13045 }
13046 }
13047
13048 // week days and months labels
13049 $days_labels = array(
13050 JText::translate('VBSUNDAY'),
13051 JText::translate('VBMONDAY'),
13052 JText::translate('VBTUESDAY'),
13053 JText::translate('VBWEDNESDAY'),
13054 JText::translate('VBTHURSDAY'),
13055 JText::translate('VBFRIDAY'),
13056 JText::translate('VBSATURDAY')
13057 );
13058 $months_labels = array(
13059 JText::translate('VBMONTHONE'),
13060 JText::translate('VBMONTHTWO'),
13061 JText::translate('VBMONTHTHREE'),
13062 JText::translate('VBMONTHFOUR'),
13063 JText::translate('VBMONTHFIVE'),
13064 JText::translate('VBMONTHSIX'),
13065 JText::translate('VBMONTHSEVEN'),
13066 JText::translate('VBMONTHEIGHT'),
13067 JText::translate('VBMONTHNINE'),
13068 JText::translate('VBMONTHTEN'),
13069 JText::translate('VBMONTHELEVEN'),
13070 JText::translate('VBMONTHTWELVE')
13071 );
13072
13073 // orphan dates calculation method
13074 $calc_method = VikBooking::orphansCalculation();
13075
13076 // parse data and build orphans if any
13077 foreach ($rooms_data as $rid => $data) {
13078 foreach ($data['avail'] as $ind => $av) {
13079 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
13080 // continue, no restriction set or no availability for this day
13081 continue;
13082 }
13083 if ($data['restr'][$ind]['minlos'] < 2) {
13084 // continue, no min los > 1 set for this day
13085 continue;
13086 }
13087 // check if any night after today, until min los, is fully booked
13088 $hasorphans = false;
13089 $forward_count = 0;
13090 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
13091 if (!isset($data['avail'][($ind + $i)])) {
13092 // break loop, no info for this day after
13093 break;
13094 }
13095 if ($data['avail'][($ind + $i)]['units'] > 0) {
13096 // continue, availability found for tomorrow, we need a non available next-day
13097 continue;
13098 }
13099 // orphan found
13100 $hasorphans = true;
13101 $forward_count = $i;
13102 break;
13103 }
13104
13105 /**
13106 * Backward calculation method only if "prevnext".
13107 *
13108 * @since 1.3.0
13109 */
13110 $backward_count = 0;
13111 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
13112 if (!isset($data['avail'][($ind - $i)])) {
13113 // break loop, no info for this prev day
13114 break;
13115 }
13116 if ($data['avail'][($ind - $i)]['units'] > 0) {
13117 // increase free nights going backward
13118 $backward_count++;
13119 }
13120 }
13121 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
13122 // this should not be an orphan date because of enough free days back, or enough free days in between
13123 $hasorphans = false;
13124 }
13125 //
13126
13127 if ($hasorphans) {
13128 // 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
13129 if (!isset($orphans[$rid])) {
13130 $orphans[$rid] = array(
13131 'name' => $rooms[$rid]['name'],
13132 'dates' => array(),
13133 'rdates' => array(),
13134 'linkd' => date($df, strtotime($av['dt']))
13135 );
13136 }
13137 array_push($orphans[$rid]['dates'], $av['dt']);
13138 // build the value for the readable date
13139 $dtinfo = getdate(strtotime($av['dt']));
13140 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
13141 array_push($orphans[$rid]['rdates'], $rdate);
13142 }
13143 }
13144 }
13145
13146 // output response
13147 echo json_encode($orphans);
13148 exit;
13149 }
13150
13151 public function tableaux() {
13152 VikBookingHelper::printHeader("tableaux");
13153
13154 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
13155
13156 parent::display();
13157
13158 if (VikBooking::showFooter()) {
13159 VikBookingHelper::printFooter();
13160 }
13161 }
13162
13163 public function operators() {
13164 VikBookingHelper::printHeader("operators");
13165
13166 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
13167
13168 parent::display();
13169
13170 if (VikBooking::showFooter()) {
13171 VikBookingHelper::printFooter();
13172 }
13173 }
13174
13175 public function newoperator() {
13176 VikBookingHelper::printHeader("operators");
13177
13178 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13179
13180 parent::display();
13181
13182 if (VikBooking::showFooter()) {
13183 VikBookingHelper::printFooter();
13184 }
13185 }
13186
13187 public function editoperator() {
13188 VikBookingHelper::printHeader("operators");
13189
13190 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13191
13192 parent::display();
13193
13194 if (VikBooking::showFooter()) {
13195 VikBookingHelper::printFooter();
13196 }
13197 }
13198
13199 public function updateoperator()
13200 {
13201 if (!JSession::checkToken()) {
13202 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13203 }
13204
13205 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13206 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13207 }
13208
13209 $this->do_updateoperator();
13210 }
13211
13212 public function updateoperatorstay()
13213 {
13214 if (!JSession::checkToken()) {
13215 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13216 }
13217
13218 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13219 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13220 }
13221
13222 $this->do_updateoperator(true);
13223 }
13224
13225 private function do_updateoperator($stay = false)
13226 {
13227 $dbo = JFactory::getDbo();
13228 $app = JFactory::getApplication();
13229 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13230 $plast_name = VikRequest::getString('last_name', '', 'request');
13231 $pemail = VikRequest::getString('email', '', 'request');
13232 $pphone = VikRequest::getString('phone', '', 'request');
13233 $pcode = VikRequest::getString('code', '', 'request');
13234 $pujid = VikRequest::getInt('ujid', '', 'request');
13235 $pwhere = VikRequest::getInt('where', '', 'request');
13236
13237 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
13238 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
13239 $dbo->setQuery($q);
13240 $customer = $dbo->loadAssoc();
13241 if (!$customer) {
13242 $app->redirect("index.php?option=com_vikbooking&task=operators");
13243 exit;
13244 }
13245
13246 $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;";
13247 $dbo->setQuery($q);
13248 $ex_operator = $dbo->loadAssoc();
13249 if (!$ex_operator) {
13250 // update fingerprint for the operator
13251 $fingpt = md5($pwhere . $pemail);
13252
13253 /**
13254 * Operator profile picture (URL or uploaded file).
13255 *
13256 * @since 1.16.9 (J) - 1.6.9 (WP)
13257 */
13258 $operator_pic = VikRequest::getString('pic', '', 'request');
13259 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13260 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13261 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13262 $src = $operator_pic_img['tmp_name'];
13263 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13264 $j = "";
13265 if (is_file($dest.$filename)) {
13266 $j = rand(1, 99999);
13267 while (is_file($dest . $j .$filename)) {
13268 $j++;
13269 }
13270 }
13271 $finaldest = $dest . $j . $filename;
13272 $check = getimagesize($operator_pic_img['tmp_name']);
13273 if (($check[2] & imagetypes())) {
13274 if (VikBooking::uploadFile($src, $finaldest)) {
13275 $operator_pic = $j . $filename;
13276 } else {
13277 VikError::raiseWarning('', 'Error while uploading image');
13278 }
13279 } else {
13280 VikError::raiseWarning('', 'Uploaded file is not an Image');
13281 }
13282 }
13283
13284 // update record
13285 $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;
13286 $dbo->setQuery($q);
13287 $dbo->execute();
13288 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13289 } else {
13290 //email already exists
13291 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>');
13292 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13293 exit;
13294 }
13295 } else {
13296 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13297 }
13298
13299 if ($stay) {
13300 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13301 } else {
13302 $app->redirect("index.php?option=com_vikbooking&task=operators");
13303 }
13304
13305 $app->close();
13306 }
13307
13308 public function saveoperator()
13309 {
13310 if (!JSession::checkToken()) {
13311 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13312 }
13313
13314 $dbo = JFactory::getDbo();
13315 $app = JFactory::getApplication();
13316 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13317 $plast_name = VikRequest::getString('last_name', '', 'request');
13318 $pemail = VikRequest::getString('email', '', 'request');
13319 $pphone = VikRequest::getString('phone', '', 'request');
13320 $pcode = VikRequest::getString('code', '', 'request');
13321 $pujid = VikRequest::getInt('ujid', '', 'request');
13322
13323 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
13324 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
13325 $dbo->setQuery($q);
13326 $ex_operator = $dbo->loadAssoc();
13327 if (!$ex_operator) {
13328 /**
13329 * Operator profile picture (URL or uploaded file).
13330 *
13331 * @since 1.16.9 (J) - 1.6.9 (WP)
13332 */
13333 $operator_pic = VikRequest::getString('pic', '', 'request');
13334 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13335 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13336 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13337 $src = $operator_pic_img['tmp_name'];
13338 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13339 $j = "";
13340 if (is_file($dest.$filename)) {
13341 $j = rand(1, 99999);
13342 while (is_file($dest . $j .$filename)) {
13343 $j++;
13344 }
13345 }
13346 $finaldest = $dest . $j . $filename;
13347 $check = getimagesize($operator_pic_img['tmp_name']);
13348 if (($check[2] & imagetypes())) {
13349 if (VikBooking::uploadFile($src, $finaldest)) {
13350 $operator_pic = $j . $filename;
13351 } else {
13352 VikError::raiseWarning('', 'Error while uploading image');
13353 }
13354 } else {
13355 VikError::raiseWarning('', 'Uploaded file is not an Image');
13356 }
13357 }
13358
13359 $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) . ");";
13360 $dbo->setQuery($q);
13361 $dbo->execute();
13362 $lid = $dbo->insertid();
13363 if (!empty($lid)) {
13364 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13365 // generate fingerprint for the operator
13366 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->q(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
13367 $dbo->setQuery($q);
13368 $dbo->execute();
13369 }
13370 } else {
13371 // email already exists
13372 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>');
13373 }
13374 } else {
13375 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13376 }
13377
13378 $app->redirect("index.php?option=com_vikbooking&task=operators");
13379 $app->close();
13380 }
13381
13382 public function removeoperators()
13383 {
13384 if (!JSession::checkToken()) {
13385 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13386 }
13387
13388 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13389 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13390 }
13391
13392 $ids = VikRequest::getVar('cid', array(0));
13393 if ($ids) {
13394 $dbo = JFactory::getDBO();
13395 foreach ($ids as $d) {
13396 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
13397 $dbo->setQuery($q);
13398 $dbo->execute();
13399 }
13400 }
13401 $mainframe = JFactory::getApplication();
13402 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13403 }
13404
13405 public function canceloperator() {
13406 $mainframe = JFactory::getApplication();
13407 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13408 }
13409
13410 public function cancelcrons() {
13411 $mainframe = JFactory::getApplication();
13412 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
13413 }
13414
13415 public function cancelpackages() {
13416 $mainframe = JFactory::getApplication();
13417 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
13418 }
13419
13420 public function cancelcustomer() {
13421 $mainframe = JFactory::getApplication();
13422 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13423 if (!empty($pgoto)) {
13424 $mainframe->redirect(base64_decode($pgoto));
13425 exit;
13426 }
13427 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
13428 }
13429
13430 public function cancelbusyvcm() {
13431 $mainframe = JFactory::getApplication();
13432 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
13433 }
13434
13435 public function cancelrestriction() {
13436 $mainframe = JFactory::getApplication();
13437 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
13438 }
13439
13440 public function cancelcoupon() {
13441 $mainframe = JFactory::getApplication();
13442 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
13443 }
13444
13445 public function cancelcustomf() {
13446 $mainframe = JFactory::getApplication();
13447 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
13448 }
13449
13450 public function cancelpayment() {
13451 $mainframe = JFactory::getApplication();
13452 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
13453 }
13454
13455 public function cancelseason() {
13456 $mainframe = JFactory::getApplication();
13457 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
13458 }
13459
13460 public function goconfig() {
13461 $mainframe = JFactory::getApplication();
13462 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
13463 }
13464
13465 public function canceledorder() {
13466 $pgoto = VikRequest::getString('goto', 'orders', 'request');
13467 $mainframe = JFactory::getApplication();
13468 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
13469 }
13470
13471 public function cancelbusy() {
13472 $pidorder = VikRequest::getString('idorder', '', 'request');
13473 $pgoto = VikRequest::getString('goto', '', 'request');
13474 $mainframe = JFactory::getApplication();
13475 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
13476 }
13477
13478 public function canceloverv() {
13479 $mainframe = JFactory::getApplication();
13480 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
13481 }
13482
13483 public function canceltableaux() {
13484 $mainframe = JFactory::getApplication();
13485 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
13486 }
13487
13488 public function cancelcalendar() {
13489 $pidroom = VikRequest::getString('idroom', '', 'request');
13490 $mainframe = JFactory::getApplication();
13491 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
13492 }
13493
13494 public function canceloptionals() {
13495 $mainframe = JFactory::getApplication();
13496 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
13497 }
13498
13499 public function cancel() {
13500 $mainframe = JFactory::getApplication();
13501 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
13502 }
13503
13504 public function cancelcarat() {
13505 $mainframe = JFactory::getApplication();
13506 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
13507 }
13508
13509 public function cancelcat() {
13510 $mainframe = JFactory::getApplication();
13511 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
13512 }
13513
13514 public function cancelprice() {
13515 $mainframe = JFactory::getApplication();
13516 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
13517 }
13518
13519 public function canceliva() {
13520 $mainframe = JFactory::getApplication();
13521 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
13522 }
13523
13524 public function canceltrk() {
13525 $mainframe = JFactory::getApplication();
13526 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13527 }
13528
13529 public function canceldash() {
13530 $mainframe = JFactory::getApplication();
13531 $mainframe->redirect("index.php?option=com_vikbooking");
13532 }
13533
13534 public function cancelinvoice() {
13535 $mainframe = JFactory::getApplication();
13536 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13537 if (!empty($pgoto)) {
13538 $mainframe->redirect(base64_decode($pgoto));
13539 exit;
13540 }
13541 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
13542 }
13543
13544 /**
13545 * AJAX upload the customer documents.
13546 *
13547 * @return void
13548 *
13549 * @throws Exception
13550 */
13551 public function upload_customer_document()
13552 {
13553 $input = JFactory::getApplication()->input;
13554 $dbo = JFactory::getDbo();
13555
13556 $customer_id = $input->getUint('customer', 0);
13557
13558 $result = new stdClass;
13559 $result->status = 0;
13560
13561 try
13562 {
13563 $q = $dbo->getQuery(true)
13564 ->select($dbo->qn(array(
13565 'id',
13566 'first_name',
13567 'last_name',
13568 'email',
13569 'docsfolder',
13570 )))
13571 ->from($dbo->qn('#__vikbooking_customers'))
13572 ->where($dbo->qn('id') . ' = ' . $customer_id);
13573
13574 $dbo->setQuery($q, 0, 1);
13575 $dbo->execute();
13576
13577 if (!$dbo->getNumRows())
13578 {
13579 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13580 }
13581
13582 $customer = $dbo->loadObject();
13583
13584 // fetch documents folder path
13585 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13586
13587 // check if we have a valid directory
13588 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
13589 {
13590 // randomize string
13591 $customer->seed = uniqid();
13592
13593 // create blocks for hashed folder
13594 $parts = [
13595 $customer->first_name,
13596 $customer->last_name,
13597 md5(serialize($customer)),
13598 ];
13599
13600 // join fetched parts
13601 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13602
13603 if (strlen($customer->docsfolder) < 16)
13604 {
13605 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13606 }
13607
13608 jimport('joomla.filesystem.folder');
13609
13610 // create a folder for this customer
13611 $created = JFolder::create($dirpath . $customer->docsfolder);
13612
13613 if (!$created)
13614 {
13615 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13616 }
13617
13618 unset($customer->seed);
13619
13620 // update docs folder
13621 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13622 }
13623
13624 // get file from request
13625 $file = $input->files->get('file', array(), 'array');
13626
13627 // try to upload the file
13628 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13629 $result->status = 1;
13630
13631 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13632 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13633 }
13634 catch (Exception $e)
13635 {
13636 $result->error = $e->getMessage();
13637 $result->code = $e->getCode();
13638 }
13639
13640 echo json_encode($result);
13641 exit;
13642 }
13643
13644 /**
13645 * AJAX delete the customer documents.
13646 *
13647 * @return void
13648 *
13649 * @throws Exception
13650 */
13651 public function delete_customer_document()
13652 {
13653 $input = JFactory::getApplication()->input;
13654 $dbo = JFactory::getDbo();
13655
13656 $customer_id = $input->getUint('customer', 0);
13657
13658 $result = new stdClass;
13659 $result->status = 0;
13660
13661 $q = $dbo->getQuery(true)
13662 ->select($dbo->qn('docsfolder'))
13663 ->from($dbo->qn('#__vikbooking_customers'))
13664 ->where($dbo->qn('id') . ' = ' . $customer_id);
13665
13666 $dbo->setQuery($q, 0, 1);
13667 $dbo->execute();
13668
13669 if (!$dbo->getNumRows())
13670 {
13671 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13672 }
13673
13674 $folder = $dbo->loadResult();
13675
13676 if (!$folder)
13677 {
13678 throw new Exception('The customer does not have any documents', 500);
13679 }
13680
13681 $file = $input->getString('file');
13682
13683 if (!$file)
13684 {
13685 throw new Exception('File to remove not specified', 400);
13686 }
13687
13688 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13689
13690 if (!is_file($path))
13691 {
13692 throw new Exception(sprintf('File [%s] not found', $path), 404);
13693 }
13694
13695 jimport('joomla.filesystem.file');
13696
13697 $removed = JFile::delete($path);
13698
13699 echo json_encode(array('status' => (int) $removed));
13700 exit;
13701 }
13702
13703 /**
13704 * AJAX task to invoke a specific report and obtain information.
13705 *
13706 * @since 1.3.0
13707 */
13708 public function get_report_data()
13709 {
13710 $report_name = VikRequest::getString('report_name', '', 'request');
13711 $current_fest = VikRequest::getString('current_fest', '', 'request');
13712 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13713 $current_todate = VikRequest::getString('current_todate', '', 'request');
13714 $step = VikRequest::getString('step', 'weekend', 'request');
13715 $direction = VikRequest::getString('direction', 'load', 'request');
13716 $period = VikRequest::getString('period', 'full', 'request');
13717 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13718 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13719 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13720 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13721 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13722 // idroom can be an array of IDs or just one ID as int/string
13723 $idroom = VikRequest::getVar('idroom', null, 'request');
13724 //
13725
13726 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13727 throw new Exception("Missing request data", 400);
13728 }
13729
13730 // get requested report instance
13731 $report = VikBooking::getReportInstance($report_name);
13732 if (!$report) {
13733 throw new Exception("Report not found", 404);
13734 }
13735
13736 // chart data
13737 if (empty($chart_datatype)) {
13738 $chart_datatype = array(
13739 'type' => 'doughnut',
13740 'depth' => 1,
13741 'keys' => array($krsort),
13742 );
13743 }
13744
13745 // website date format
13746 $df = $report->getDateFormat();
13747
13748 // prepare request params for the report
13749 $rparams = array(
13750 'fromdate' => $current_fromdate,
13751 'todate' => $current_todate,
13752 'period' => $period,
13753 'krsort' => $krsort,
13754 'krorder' => $krorder,
13755 'idroom' => $idroom,
13756 );
13757
13758 // starting dates info and timestamps
13759 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13760 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13761 $from_info = getdate($from_ts);
13762 $to_info = getdate($to_ts);
13763
13764 // the name of the period requested and whether it's a fest
13765 $period_name = '';
13766 $is_fest = null;
13767
13768 if ($direction == 'prev' || $direction == 'next') {
13769 // calculate prev or next dates
13770 if ($step == 'weekend') {
13771 $period_name = JText::translate('VBOWEEKND');
13772 if ($direction == 'next') {
13773 // next weekend from current end date
13774 $next_ts = strtotime("next friday", $to_ts);
13775 } else {
13776 // prev weekend from current start date
13777 $next_ts = strtotime("previous friday", $from_ts);
13778 }
13779 $next_info = getdate($next_ts);
13780 $new_from_ts = $next_ts;
13781 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13782 $rparams['fromdate'] = date($df, $new_from_ts);
13783 $rparams['todate'] = date($df, $new_to_ts);
13784 } elseif ($step == 'week') {
13785 $period_name = JText::translate('VBOWEEK');
13786 if ($direction == 'next') {
13787 // start next week from the current end date
13788 $new_from_ts = $to_ts;
13789 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13790 $rparams['fromdate'] = $rparams['todate'];
13791 $rparams['todate'] = date($df, $new_to_ts);
13792 } else {
13793 // end prev week from the current from date
13794 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13795 $new_to_ts = $from_ts;
13796 $rparams['todate'] = $rparams['fromdate'];
13797 $rparams['fromdate'] = date($df, $new_from_ts);
13798 }
13799 } else {
13800 // month
13801 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13802 if ($direction == 'next') {
13803 // next month from the current from date
13804 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13805 $new_from_ts = $nextmonts;
13806 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13807 $rparams['fromdate'] = date($df, $new_from_ts);
13808 $rparams['todate'] = date($df, $new_to_ts);
13809 } else {
13810 // prev month from the current from date
13811 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13812 $new_from_ts = $nextmonts;
13813 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13814 $rparams['fromdate'] = date($df, $new_from_ts);
13815 $rparams['todate'] = date($df, $new_to_ts);
13816 }
13817 }
13818
13819 // get the next festivities
13820 $fests = VikBooking::getFestivitiesInstance();
13821 $next_fests = $fests->loadFestDates();
13822 if (count($next_fests)) {
13823 // check whether a festivity should be displayed rather than the calculated period of dates
13824 foreach ($next_fests as $fest) {
13825 $fest_found = false;
13826 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13827 $fest_found = true;
13828 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13829 $fest_found = true;
13830 }
13831 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13832 // festivity found before next calculated period
13833 $is_fest = $fest['festinfo'][0]->next_ts;
13834 $period_name = $fest['festinfo'][0]->trans_name;
13835 $new_from_ts = $fest['festinfo'][0]->from_ts;
13836 $new_to_ts = $fest['festinfo'][0]->to_ts;
13837 $rparams['fromdate'] = date($df, $new_from_ts);
13838 $rparams['todate'] = date($df, $new_to_ts);
13839 break;
13840 }
13841 }
13842 }
13843 } else {
13844 // load requested dates by skipping the festivities
13845 $new_from_ts = $from_ts;
13846 $new_to_ts = $to_ts;
13847 }
13848
13849 // invoke report
13850 $report->injectParams($rparams);
13851 $report_values = $report->getReportValues(1);
13852 $report_cols = $report->getColumnsValues();
13853 $report_chart = null;
13854 $report_chart_metas = array();
13855 $chart_meta_data = array(
13856 'keys' => array(
13857 'occupancy',
13858 'tot_bookings',
13859 'nights_booked',
13860 ),
13861 );
13862 $error = null;
13863
13864 if (!count($report_values)) {
13865 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13866 } else {
13867 // get doughnut Chart for the requested key
13868 $report_chart = $report->getChart($chart_datatype);
13869
13870 // get Chart meta data
13871 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13872 if (count($all_chart_metas)) {
13873 // merge all positions into one array
13874 foreach ($all_chart_metas as $pos_metas) {
13875 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13876 }
13877 }
13878
13879 if (empty($period_name)) {
13880 $period_name = $report->getProperty('chartTitle');
13881 }
13882 }
13883
13884 // build response
13885 $response = new stdClass;
13886 $response->error = $error;
13887 $response->fromdate = $rparams['fromdate'];
13888 $response->todate = $rparams['todate'];
13889 $response->in_days = $report->countDaysTo($new_from_ts);
13890 $response->in_days_to = $report->countDaysTo($new_to_ts);
13891 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13892 $response->period_name = $period_name;
13893 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13894 $response->is_fest = $is_fest;
13895 $response->report_chart = $report_chart;
13896 $response->report_cols = $report_cols;
13897 $response->report_values = $report_values;
13898 $response->report_script = $report->getScript();
13899 $response->chart_labels = $report->getProperty('chartJsLabels');
13900 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13901 $response->chart_colors = $report->getProperty('chartJsColors');
13902 $response->chart_data = $report->getProperty('chartJsData');
13903 $response->report_chart_metas = $report_chart_metas;
13904
13905 echo json_encode($response);
13906 exit;
13907 }
13908
13909 /**
13910 * Go to the previous booking.
13911 *
13912 * @uses navigateToBooking()
13913 *
13914 * @since 1.3.0
13915 */
13916 public function prev_booking()
13917 {
13918 $this->navigateToBooking('prev');
13919 }
13920
13921 /**
13922 * Go to the next booking.
13923 *
13924 * @uses navigateToBooking()
13925 *
13926 * @since 1.3.0
13927 */
13928 public function next_booking()
13929 {
13930 $this->navigateToBooking('next');
13931 }
13932
13933 /**
13934 * Given the current booking ID in the request, we navigate
13935 * either to the next or to the previous reservation (if any).
13936 *
13937 * @param string $direction either next or prev.
13938 *
13939 * @return void
13940 *
13941 * @since 1.3.0
13942 */
13943 private function navigateToBooking($direction = 'next')
13944 {
13945 $bid = VikRequest::getInt('whereup', 0, 'request');
13946 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13947 throw new Exception("Invalid request", 400);
13948 }
13949
13950 $dbo = JFactory::getDbo();
13951 $app = JFactory::getApplication();
13952
13953 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13954 $dbo->setQuery($q, 0, 1);
13955 $dbo->execute();
13956 if (!$dbo->getNumRows()) {
13957 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13958 $app->redirect("index.php?option=com_vikbooking&task=orders");
13959 exit;
13960 }
13961
13962 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
13963 exit;
13964 }
13965
13966 /**
13967 * AJAX request: from a list of reservation IDs, we return the ones
13968 * that have a review with the related review ID on VCM.
13969 *
13970 * @since 1.13
13971 */
13972 public function bookings_have_reviews()
13973 {
13974 if (!JSession::checkToken()) {
13975 // missing CSRF-proof token
13976 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13977 }
13978
13979 $dbo = JFactory::getDbo();
13980
13981 $bids = VikRequest::getVar('bids', [], 'request', 'array');
13982 $vcm_installed = class_exists('VikChannelManager');
13983 $withreviews = [];
13984
13985 if ($vcm_installed && $bids) {
13986 $bids = array_filter(array_map('intval', (array) $bids));
13987 $bids = $bids ?: [0];
13988
13989 try {
13990 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
13991 $dbo->setQuery($q);
13992 $reviews = $dbo->loadAssocList();
13993
13994 foreach ($reviews as $r) {
13995 $withreviews[$r['idorder']] = $r['id'];
13996 }
13997 } catch (Exception $e) {
13998 // do nothing, outdated version
13999 }
14000 }
14001
14002 // output list of booking IDs found, if any
14003 VBOHttpDocument::getInstance()->json($withreviews);
14004 }
14005
14006 /**
14007 * AJAX request for adding a new room-day note.
14008 *
14009 * @return void
14010 *
14011 * @since 1.13.5
14012 */
14013 public function add_roomdaynote()
14014 {
14015 $dt = VikRequest::getString('dt', '', 'request');
14016 $idroom = VikRequest::getInt('idroom', 0, 'request');
14017 $subunit = VikRequest::getInt('subunit', 0, 'request');
14018 $type = VikRequest::getString('type', '', 'request');
14019 $type = empty($type) ? 'custom' : $type;
14020 $name = VikRequest::getString('name', '', 'request');
14021 $descr = VikRequest::getString('descr', '', 'request');
14022 $cdays = VikRequest::getInt('cdays', 0, 'request');
14023 $cdays = $cdays < 0 ? 0 : $cdays;
14024 $cdays = $cdays > 365 ? 365 : $cdays;
14025 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
14026 echo 'e4j.error.1';
14027 exit;
14028 }
14029
14030 // reload end date
14031 $end_date = $dt;
14032
14033 // build critical date object
14034 $new_note = array(
14035 'name' => $name,
14036 'type' => $type,
14037 'descr' => $descr,
14038 );
14039
14040 // get object
14041 $notes = VikBooking::getCriticalDatesInstance();
14042
14043 // store the notes for all consecutive dates
14044 for ($i = 0; $i <= $cdays; $i++) {
14045 $store_dt = $dt;
14046 if ($i > 0) {
14047 $dt_info = getdate(strtotime($store_dt));
14048 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
14049 $end_date = $store_dt;
14050 }
14051 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
14052 if (!$result) {
14053 echo 'e4j.error.2';
14054 exit;
14055 }
14056 }
14057
14058 // reload all room day notes for this day for the AJAX response
14059 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
14060
14061 if (!$all_notes || !count($all_notes)) {
14062 // no notes found even after storing it
14063 echo 'e4j.error.3';
14064 exit;
14065 }
14066
14067 echo json_encode($all_notes);
14068 exit;
14069 }
14070
14071 /**
14072 * AJAX request for removing a room day note.
14073 *
14074 * @return void
14075 *
14076 * @since 1.13.5
14077 */
14078 public function remove_roomdaynote()
14079 {
14080 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14081 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14082 }
14083
14084 $dt = VikRequest::getString('dt', '', 'request');
14085 $idroom = VikRequest::getInt('idroom', 0, 'request');
14086 $subunit = VikRequest::getInt('subunit', 0, 'request');
14087 $type = VikRequest::getString('type', '', 'request');
14088 $type = empty($type) ? 'custom' : $type;
14089 $ind = VikRequest::getInt('ind', 0, 'request');
14090 if (empty($dt) || !strtotime($dt)) {
14091 echo 'e4j.error.1';
14092 exit;
14093 }
14094
14095 $notes = VikBooking::getCriticalDatesInstance();
14096 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
14097 if (!$result) {
14098 echo 'e4j.error.2';
14099 exit;
14100 }
14101
14102 echo 'e4j.ok';
14103 exit;
14104 }
14105
14106 /**
14107 * AJAX request for storing an event for a booking.
14108 * Firstly developed for the VCM Reporting API - Guest Misconduct,
14109 * but it can be used for any other purpose.
14110 *
14111 * @return void
14112 *
14113 * @since 1.13.5
14114 */
14115 public function store_booking_history_event()
14116 {
14117 $bid = VikRequest::getInt('bid', 0, 'request');
14118 $event = VikRequest::getString('event', '', 'request');
14119 $descr = VikRequest::getString('descr', '', 'request');
14120
14121 if (empty($bid) || empty($event)) {
14122 throw new Exception("Missing required information", 500);
14123 }
14124
14125 // Booking History
14126 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
14127 //
14128
14129 echo 'e4j.ok';
14130 exit;
14131 }
14132
14133 /**
14134 * AJAX request for updating an option/extra service.
14135 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
14136 * but it can be used for any other purpose.
14137 *
14138 * @return void
14139 *
14140 * @since 1.13.5
14141 */
14142 public function update_option_params()
14143 {
14144 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14145 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14146 }
14147
14148 $optid = VikRequest::getInt('optid', 0, 'request');
14149 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
14150
14151 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
14152 throw new Exception("Missing required information", 500);
14153 }
14154
14155 $dbo = JFactory::getDbo();
14156 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
14157 $dbo->setQuery($q);
14158 $dbo->execute();
14159 if (!$dbo->getNumRows()) {
14160 throw new Exception("Option not found", 404);
14161 }
14162 $cur_params = $dbo->loadResult();
14163 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
14164 $cur_params = !is_array($cur_params) ? array() : $cur_params;
14165
14166 foreach ($oparams as $k => $v) {
14167 if (empty($k)) {
14168 continue;
14169 }
14170 $cur_params[$k] = $v;
14171 }
14172
14173 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
14174 $dbo->setQuery($q);
14175 $dbo->execute();
14176
14177 echo 'e4j.ok';
14178 exit;
14179 }
14180
14181 /**
14182 * Hidden task to clean up duplicate records in certain database tables
14183 * due to a double execution of the installation queries. Ghost records,
14184 * if any, are also removed to clean up issues with hanging records.
14185 *
14186 * @since November 4th 2020
14187 * @since 1.16.3 (J) - 1.6.3 (WP)
14188 */
14189 public function clean_duplicate_records()
14190 {
14191 $dbo = JFactory::getDbo();
14192
14193 $tables_with_duplicates = [
14194 '#__vikbooking_config' => [
14195 'id_key' => 'id',
14196 'compare_key' => 'param',
14197 ],
14198 '#__vikbooking_countries' => [
14199 'id_key' => 'id',
14200 'compare_key' => 'country_3_code',
14201 ],
14202 '#__vikbooking_custfields' => [
14203 'id_key' => 'id',
14204 'compare_key' => 'name',
14205 ],
14206 '#__vikbooking_texts' => [
14207 'id_key' => 'id',
14208 'compare_key' => 'param',
14209 ],
14210 ];
14211
14212 foreach ($tables_with_duplicates as $tblname => $data) {
14213 $doubles = [];
14214 $storage = [];
14215 $rmlist = [];
14216
14217 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
14218 $dbo->setQuery($q);
14219 $rows = $dbo->loadAssocList();
14220 if (!$rows) {
14221 echo "<p>No records found in table {$tblname}</p>";
14222 continue;
14223 }
14224
14225 foreach ($rows as $row) {
14226 if (!isset($doubles[$row[$data['compare_key']]])) {
14227 $doubles[$row[$data['compare_key']]] = 0;
14228 }
14229 $doubles[$row[$data['compare_key']]]++;
14230 if (!isset($storage[$row[$data['compare_key']]])) {
14231 $storage[$row[$data['compare_key']]] = [];
14232 }
14233 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
14234 }
14235
14236 foreach ($doubles as $paramkey => $paramcount) {
14237 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
14238 continue;
14239 }
14240 $exceeding = $paramcount - 1;
14241 for ($x = 0; $x < $exceeding; $x++) {
14242 array_push($rmlist, $storage[$paramkey][$x]);
14243 }
14244 }
14245
14246 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
14247 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
14248 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
14249
14250 if (count($rmlist)) {
14251 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
14252 $dbo->setQuery($q);
14253 $dbo->execute();
14254 }
14255 }
14256
14257 /**
14258 * Clean up busy records where the busy relations contain empty booking IDs.
14259 */
14260 $hanging_busy_ids = [];
14261
14262 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
14263 $dbo->setQuery($q);
14264 $removelist = $dbo->loadAssocList();
14265 if ($removelist) {
14266 foreach ($removelist as $hanging_busy) {
14267 $hanging_busy_id = (int)$hanging_busy['idbusy'];
14268 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14269 array_push($hanging_busy_ids, $hanging_busy_id);
14270 }
14271 }
14272 }
14273
14274 // let's check also for ghost records that only occupy the room
14275 $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);";
14276 $dbo->setQuery($q);
14277 $removelist = $dbo->loadAssocList();
14278 if ($removelist) {
14279 foreach ($removelist as $hanging_busy) {
14280 $hanging_busy_id = (int)$hanging_busy['id'];
14281 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14282 array_push($hanging_busy_ids, $hanging_busy_id);
14283 }
14284 }
14285 }
14286
14287 if ($hanging_busy_ids) {
14288 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
14289 $dbo->setQuery($q);
14290 $dbo->execute();
14291 }
14292
14293 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
14294
14295 return;
14296 }
14297
14298 /**
14299 * Hidden task to scan all database tables of VikBooking and Vik Channel Manager
14300 * to ensure the column `id` is defined as a primary key and got an auto-increment
14301 * extra flag properly defined and set. We've noticed that some third-party plugins
14302 * used to migrate WP sites may break the primary keys, and so new records won't get an ID.
14303 *
14304 * @since 1.16.8 (J) - 1.6.8 (WP)
14305 */
14306 public function fix_autoincrement_tables()
14307 {
14308 $dbo = JFactory::getDbo();
14309
14310 // load all the installed database tables
14311 $tables = $dbo->getTableList();
14312
14313 // get current database prefix
14314 $prefix = $dbo->getPrefix();
14315
14316 // replace prefix with placeholder
14317 $tables = array_map(function($table) use ($prefix)
14318 {
14319 return preg_replace("/^{$prefix}/", '#__', $table);
14320 }, $tables);
14321
14322 // remove all the tables that do not belong to VikBooking/VCM
14323 $tables = array_values(array_filter($tables, function($table)
14324 {
14325 if (preg_match("/^#__vik(?:booking|channelmanager)_config$/", $table))
14326 {
14327 // exclude the configuration table, which will be handled in a different way
14328 return false;
14329 }
14330
14331 return preg_match("/^#__vik(?:booking|channelmanager)_/", $table);
14332 }));
14333
14334 foreach ($tables as $table) {
14335 $columns = $dbo->getTableColumns($table, false);
14336 if (!isset($columns['id']) || empty($columns['id']->Type) || !empty($columns['id']->Extra)) {
14337 continue;
14338 }
14339
14340 echo 'Fixing ' . $table. ' for missing auto-increment<br/><pre>' . print_r($columns['id'], true) . '</pre><br/>';
14341
14342 // set auto-increment and primary key
14343 $dbo->setQuery("ALTER TABLE `{$table}` MODIFY `id` " . $columns['id']->Type . " NOT NULL AUTO_INCREMENT PRIMARY KEY;");
14344 $dbo->execute();
14345
14346 // count next auto-increment
14347 $dbo->setQuery("SELECT MAX(`id`) FROM `{$table}`");
14348 $next_ai = (int) $dbo->loadResult() + 1;
14349
14350 // update next auto-increment value
14351 $dbo->setQuery("ALTER TABLE `{$table}` AUTO_INCREMENT = {$next_ai}");
14352 $dbo->execute();
14353 }
14354 }
14355
14356 /**
14357 * Loads a specific admin widget ID and executes the requested method.
14358 * Useful for loading a newly added widget, or to execute custom methods.
14359 *
14360 * @see this is an AJAX endpoint.
14361 *
14362 * @since 1.14 (J) - 1.4.0 (WP)
14363 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
14364 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14365 */
14366 public function exec_admin_widget()
14367 {
14368 if (!JSession::checkToken()) {
14369 // missing CSRF-proof token
14370 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14371 }
14372
14373 $widget_id = VikRequest::getString('widget_id', '', 'request');
14374 $call = VikRequest::getString('call', '', 'request');
14375 $return = VikRequest::getInt('return', 0, 'request');
14376 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
14377 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
14378 $multitask = VikRequest::getInt('multitask', 0, 'request');
14379
14380 if (empty($widget_id)) {
14381 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
14382 }
14383
14384 if (empty($call) || !is_string($call)) {
14385 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14386 }
14387
14388 // invoke admin widgets helper
14389 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14390 $widget = $widgets_helper->getWidget($widget_id);
14391
14392 if ($widget === false) {
14393 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
14394 }
14395
14396 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
14397 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
14398 }
14399
14400 // get the multitask parser object
14401 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
14402
14403 // check if arguments should be passed
14404 $call_args = [];
14405 if ($multitask && $call === 'render') {
14406 // build the multitask data object and inject it to the args as the first index
14407 $call_args[] = $parser->getData();
14408
14409 // bind options within the widget, if any
14410 $widget->bindOptions($call_args[0]);
14411 } else {
14412 // always bind multitask options, if any
14413 $widget->bindOptions($parser->getOptions());
14414 }
14415
14416 try {
14417 if ($return) {
14418 // invoke the widget's method and get the value returned
14419 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
14420 } else {
14421 // invoke the widget's method within a buffer
14422 ob_start();
14423 if ($call_args) {
14424 $res = call_user_func_array([$widget, $call], $call_args);
14425 } else {
14426 $widget->{$call}();
14427 }
14428 $widget_response = ob_get_contents();
14429 ob_end_clean();
14430 }
14431 } catch (Throwable $e) {
14432 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14433 } catch (Exception $e) {
14434 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14435 }
14436
14437 // prepare response object with a property equal to the called method
14438 $response = new stdClass;
14439 $response->{$call} = $widget_response;
14440
14441 // output the JSON encoded response and exit
14442 VBOHttpDocument::getInstance()->json($response);
14443 }
14444
14445 /**
14446 * Updates the map of admin widgets.
14447 *
14448 * @throws Exception this is an AJAX endpoint.
14449 *
14450 * @since 1.4.0
14451 */
14452 public function save_admin_widgets()
14453 {
14454 if (!JSession::checkToken()) {
14455 // missing CSRF-proof token
14456 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14457 }
14458
14459 // make sure permissions are sufficient
14460 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
14461 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
14462 }
14463
14464 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
14465 if (!is_array($psections) || !count($psections)) {
14466 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
14467 }
14468
14469 // request values are all converted to arrays, so restore the object styling
14470 $psections = json_decode(json_encode($psections));
14471
14472 // update map
14473 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
14474
14475 $response = new stdClass;
14476 $response->status = (int)$result;
14477
14478 // output the JSON encoded response and exit
14479 VBOHttpDocument::getInstance()->json($response);
14480 }
14481
14482 /**
14483 * Restores the default admin widgets map.
14484 *
14485 * @since 1.4.0
14486 */
14487 public function reset_admin_widgets()
14488 {
14489 // reset map and redirect to dashboard
14490 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
14491
14492 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
14493 exit;
14494 }
14495
14496 /**
14497 * Updates the welcome message status for the widget's customizer via AJAX.
14498 *
14499 * @since 1.4.0
14500 */
14501 public function admin_widgets_welcome()
14502 {
14503 if (!JSession::checkToken()) {
14504 // missing CSRF-proof token
14505 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14506 }
14507
14508 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
14509 // update configuration value
14510 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
14511
14512 $response = new stdClass;
14513 $response->status = $hide_welcome;
14514
14515 // output the JSON encoded response and exit
14516 VBOHttpDocument::getInstance()->json($response);
14517 }
14518
14519 public function newcondtext()
14520 {
14521 VikBookingHelper::printHeader("11");
14522
14523 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14524
14525 parent::display();
14526
14527 if (VikBooking::showFooter()) {
14528 VikBookingHelper::printFooter();
14529 }
14530 }
14531
14532 public function editcondtext()
14533 {
14534 VikBookingHelper::printHeader("11");
14535
14536 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
14537
14538 parent::display();
14539
14540 if (VikBooking::showFooter()) {
14541 VikBookingHelper::printFooter();
14542 }
14543 }
14544
14545 public function cancelcondtext()
14546 {
14547 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
14548 }
14549
14550 public function createcondtext()
14551 {
14552 if (!JSession::checkToken()) {
14553 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14554 }
14555
14556 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14557 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14558 }
14559
14560 $this->_doCreateCondText();
14561 }
14562
14563 public function createcondtextstay()
14564 {
14565 if (!JSession::checkToken()) {
14566 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14567 }
14568
14569 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
14570 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14571 }
14572
14573 $this->_doCreateCondText(true);
14574 }
14575
14576 private function _doCreateCondText($stay = false)
14577 {
14578 $dbo = JFactory::getDbo();
14579 $app = JFactory::getApplication();
14580 $rules_helper = VikBooking::getConditionalRulesInstance();
14581 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14582
14583 $condtextname = VikRequest::getString('condtextname', '', 'request');
14584 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14585 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14586 $debug = VikRequest::getInt('debug', 0, 'request');
14587 if (empty($condtextname)) {
14588 $condtextname = date('Y-m-dHis');
14589 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14590 }
14591
14592 $existing_tokens = $rules_helper->getSpecialTags();
14593 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
14594 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
14595 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
14596 exit;
14597 }
14598
14599 $data = new stdClass;
14600 $data->name = $condtextname;
14601 $data->token = $condtexttkn;
14602 $data->rules = json_encode($rules_list);
14603 $data->msg = $msg;
14604 $data->lastupd = JDate::getInstance()->toSql();
14605 $data->debug = $debug;
14606
14607 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
14608
14609 if (isset($data->id)) {
14610 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14611 }
14612
14613 if (!$stay || !isset($data->id)) {
14614 $this->cancelcondtext();
14615 exit;
14616 }
14617
14618 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14619 }
14620
14621 public function updatecondtext()
14622 {
14623 if (!JSession::checkToken()) {
14624 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14625 }
14626
14627 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14628 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14629 }
14630
14631 $this->_doUpdateCondText();
14632 }
14633
14634 public function updatecondtextstay()
14635 {
14636 if (!JSession::checkToken()) {
14637 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14638 }
14639
14640 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14641 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14642 }
14643
14644 $this->_doUpdateCondText(true);
14645 }
14646
14647 private function _doUpdateCondText($stay = false)
14648 {
14649 $dbo = JFactory::getDbo();
14650 $app = JFactory::getApplication();
14651 $rules_helper = VikBooking::getConditionalRulesInstance();
14652 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14653
14654 $pwhere = VikRequest::getInt('where', '', 'request');
14655 $condtextname = VikRequest::getString('condtextname', '', 'request');
14656 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14657 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14658 $debug = VikRequest::getInt('debug', 0, 'request');
14659 if (empty($condtextname)) {
14660 $condtextname = date('Y-m-dHis');
14661 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14662 }
14663
14664 $existing_tokens = $rules_helper->getSpecialTags();
14665 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
14666 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
14667 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
14668 exit;
14669 }
14670
14671 $data = new stdClass;
14672 $data->id = $pwhere;
14673 $data->name = $condtextname;
14674 $data->token = $condtexttkn;
14675 $data->rules = json_encode($rules_list);
14676 $data->msg = $msg;
14677 $data->lastupd = JDate::getInstance()->toSql();
14678 $data->debug = $debug;
14679
14680 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
14681
14682 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14683
14684 if (!$stay) {
14685 $this->cancelcondtext();
14686 exit;
14687 }
14688
14689 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14690 }
14691
14692 public function removecondtext()
14693 {
14694 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14695 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14696 }
14697
14698 $dbo = JFactory::getDbo();
14699 $ids = VikRequest::getVar('cid', array());
14700
14701 VikBooking::getConditionalRulesInstance(true);
14702 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14703
14704 foreach ($ids as $d) {
14705 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14706 $dbo->setQuery($q);
14707 $dbo->execute();
14708 if (!$dbo->getNumRows()) {
14709 continue;
14710 }
14711 $special_tag = $dbo->loadResult();
14712
14713 // remove the token from each template file if it was used before
14714 if (!empty($special_tag)) {
14715 // remove token from all template files
14716 foreach ($templates as $tkey => $tpath) {
14717 // get requested file content
14718 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14719 if (empty($fcontent) || !is_string($fcontent)) {
14720 break;
14721 }
14722 // remove tag from code content
14723 $fcontent = str_replace($special_tag, '', $fcontent);
14724 // update the file code
14725 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14726 }
14727 }
14728
14729 // delete the record
14730 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14731 $dbo->setQuery($q);
14732 $dbo->execute();
14733 }
14734
14735 $this->cancelcondtext();
14736 }
14737
14738 /**
14739 * AJAX endpoint to update one template file with the given tag or styles.
14740 * A JSON response will be echoed by exiting the process.
14741 */
14742 public function condtext_update_tmpl()
14743 {
14744 VikBooking::getConditionalRulesInstance(true);
14745
14746 $tagaction = VikRequest::getString('tagaction', '', 'request');
14747 $tag = VikRequest::getString('tag', '', 'request');
14748 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14749 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14750 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14751
14752 $allowed_actions = array(
14753 'add',
14754 'remove',
14755 'styles',
14756 'restore',
14757 );
14758
14759 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14760 throw new Exception("Invalid request submitted", 500);
14761 }
14762
14763 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14764 throw new Exception("Invalid request submitted - missing tag", 500);
14765 }
14766
14767 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14768 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14769 }
14770
14771 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14772 throw new Exception("No custom CSS classes to parse", 500);
14773 }
14774
14775 if ($tagaction == 'restore') {
14776 // immediately restore the requested file to avoid script interruptions
14777 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14778 }
14779
14780 // get requested file content
14781 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14782 if (empty($fcontent) || !is_string($fcontent)) {
14783 throw new Exception("File not found or its code is unreadable", 404);
14784 }
14785
14786 if ($tagaction == 'remove') {
14787 // remove tag from code content
14788 $fcontent = str_replace($tag, '', $fcontent);
14789 } elseif ($tagaction == 'add') {
14790 // add tag to code content in the same exact position
14791 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14792 } elseif ($tagaction == 'styles') {
14793 // apply the same styling rules
14794 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14795 }
14796
14797 // update the file code
14798 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14799
14800 if (!$res) {
14801 throw new Exception("Could not update the source code of the template file", 500);
14802 }
14803
14804 // parse new HTML content
14805 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14806 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14807 throw new Exception("Could not parse new template file content", 404);
14808 }
14809
14810 // trigger backup/mirroring, if available
14811 if (VBOPlatformDetection::isWordPress()) {
14812 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14813 }
14814
14815 // build output
14816 $output = new stdClass;
14817 $output->newhtml = $newhtmls[$file];
14818 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14819
14820 echo json_encode($output);
14821 exit;
14822 }
14823
14824 /**
14825 * AJAX endpoint to invoke methods of the geocoding helper.
14826 */
14827 public function geocoding_endpoint()
14828 {
14829 $geo = VikBooking::getGeocodingInstance();
14830 $callback = VikRequest::getString('callback', '', 'request');
14831
14832 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14833 throw new Exception("Callback not available", 403);
14834 }
14835
14836 // invoke requested method
14837 $res = $geo->{$callback}();
14838
14839 // prepare response
14840 $response = new stdClass;
14841 $response->{$callback} = $res;
14842
14843 echo json_encode($response);
14844 exit;
14845 }
14846
14847 public function refundtn()
14848 {
14849 //modal box, so we do not set menu or footer
14850
14851 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14852
14853 parent::display();
14854 }
14855
14856 public function do_refundtn()
14857 {
14858 $dbo = JFactory::getDbo();
14859 $app = JFactory::getApplication();
14860
14861 $bid = VikRequest::getInt('bid', 0, 'request');
14862 $amount = VikRequest::getFloat('amount', 0, 'request');
14863 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14864 $tmpl = VikRequest::getString('tmpl', '', 'request');
14865 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14866
14867 $currencysymb = VikBooking::getCurrencySymb();
14868
14869 if (empty($bid) || $amount <= 0) {
14870 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14871 $app->redirect('index.php?option=com_vikbooking');
14872 exit;
14873 }
14874
14875 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14876 $dbo->setQuery($q);
14877 $dbo->execute();
14878 if ($dbo->getNumRows() < 1) {
14879 VikError::raiseWarning('', 'Booking not found');
14880 $app->redirect('index.php?option=com_vikbooking');
14881 exit;
14882 }
14883 $row = $dbo->loadAssoc();
14884
14885 // get booking history instance
14886 $history_obj = VikBooking::getBookingHistoryInstance();
14887 $history_obj->setBid($row['id']);
14888
14889 // get payment information
14890 $payment = VikBooking::getPayment($row['idpayment']);
14891 $tn_driver = is_array($payment) ? $payment['file'] : null;
14892
14893 // transaction data validation callback
14894 $tn_data_callback = function($data) use ($tn_driver) {
14895 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14896 };
14897 // get previous transactions
14898 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14899
14900 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14901 // no previous transactions found
14902 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14903 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14904 exit;
14905 }
14906
14907 // push refund information for the payment gateway
14908 $row['total_to_refund'] = $amount;
14909 $row['transaction'] = $prev_tn_data;
14910 $row['refund_reason'] = $refund_reason;
14911
14912 // push the transaction currency information
14913 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14914
14915 /**
14916 * @wponly The payment gateway is loaded
14917 * through the apposite dispatcher.
14918 */
14919 JLoader::import('adapter.payment.dispatcher');
14920 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14921
14922 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14923 // refund not supported
14924 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14925 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14926 exit;
14927 }
14928
14929 // perform the refund transaction
14930 $array_result = $obj->refund();
14931
14932 if ($array_result['verified'] != 1) {
14933 // raise warning by getting the message
14934 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14935 VikError::raiseWarning('', $array_result['log']);
14936 } else {
14937 VikError::raiseWarning('', 'Operation failed');
14938 }
14939 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14940 exit;
14941 }
14942
14943 /**
14944 * New payment plugins can return the total amount refunded ('tot_paid').
14945 *
14946 * @since 1.15.4 (J) - 1.5.10 (WP)
14947 */
14948 if (!empty($array_result['tot_paid'])) {
14949 // overwrite the requested amount with the returned one
14950 $amount = (float)$array_result['tot_paid'];
14951 }
14952
14953 /**
14954 * The history event extra data will contain the "amount_paid" (refunded).
14955 *
14956 * @since 1.16.9 (J) - 1.6.9 (WP)
14957 */
14958 $history_obj->setExtraData([
14959 'amount_paid' => $amount,
14960 ]);
14961
14962 // update total paid, total and refund columns for the booking
14963 $booking = new stdClass;
14964 $booking->id = $row['id'];
14965 if ($row['totpaid'] > 0) {
14966 $booking->totpaid = $row['totpaid'] - $amount;
14967 }
14968 if ($row['total'] > 0) {
14969 $booking->total = $row['total'] - $amount;
14970 }
14971 $booking->refund = (float)$row['refund'] + $amount;
14972 // update record in db
14973 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
14974
14975 // store the refund event
14976 $event_descr = [
14977 '(' . $payment['name'] . ')',
14978 $refund_reason,
14979 $currencysymb . ' ' . VikBooking::numberFormat($amount),
14980 ];
14981 $history_obj->store('RF', implode("\n", $event_descr));
14982
14983 // display success message and redirect
14984 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
14985 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
14986 exit;
14987 }
14988
14989 /**
14990 * AJAX upload endpoint for media files.
14991 *
14992 * @return void
14993 *
14994 * @throws Exception
14995 *
14996 * @since 1.15.0 (J) - 1.5.0 (WP)
14997 */
14998 public function upload_media_file()
14999 {
15000 $input = JFactory::getApplication()->input;
15001
15002 // allowed types
15003 $type = $input->getString('type', '');
15004 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
15005 if ($type == 'image') {
15006 $mask = "/(image\/.+)$/i";
15007 }
15008
15009 // response object
15010 $result = new stdClass;
15011 $result->status = 0;
15012
15013 try
15014 {
15015 // get file from request
15016 $file = $input->files->get('file', array(), 'array');
15017
15018 // try to upload the file
15019 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
15020 $result->status = 1;
15021
15022 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
15023 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
15024 }
15025 catch (Exception $e)
15026 {
15027 $result->error = $e->getMessage();
15028 $result->code = $e->getCode();
15029 }
15030
15031 echo json_encode($result);
15032 exit;
15033 }
15034
15035 /**
15036 * AJAX endpoint to invoke a report object's method.
15037 *
15038 * @return void
15039 *
15040 * @throws Exception
15041 *
15042 * @since 1.15.0 (J) - 1.5.0 (WP)
15043 */
15044 public function invoke_report()
15045 {
15046 $report_name = VikRequest::getString('report', '', 'request');
15047 $report_call = VikRequest::getString('call', '', 'request');
15048 $params = VikRequest::getVar('params', array(), 'request', 'array');
15049
15050 if (empty($report_name)) {
15051 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
15052 }
15053
15054 if (empty($report_call)) {
15055 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
15056 }
15057
15058 // get requested report instance
15059 $report = VikBooking::getReportInstance($report_name);
15060 if (!$report) {
15061 VBOHttpDocument::getInstance()->close(404, 'Report not found');
15062 }
15063
15064 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
15065 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
15066 }
15067
15068 // call on report's method
15069 $result = $report->{$report_call}($params);
15070
15071 if (is_null($result)) {
15072 VBOHttpDocument::getInstance()->close(400, 'Null response');
15073 }
15074
15075 if (is_scalar($result)) {
15076 // wrap result within an array for a JSON encoded response
15077 VBOHttpDocument::getInstance()->json([$result]);
15078 }
15079
15080 // output the JSON encoded array/object returned
15081 VBOHttpDocument::getInstance()->json($result);
15082 }
15083
15084 /**
15085 * Handles requests for the multitask widgets panel.
15086 *
15087 * @see this is an AJAX endpoint.
15088 *
15089 * @since 1.15.0 (J) - 1.5.0 (WP)
15090 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
15091 */
15092 public function exec_multitask_widgets()
15093 {
15094 if (!JSession::checkToken()) {
15095 // missing CSRF-proof token
15096 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15097 }
15098
15099 $call = VikRequest::getString('call', '', 'request');
15100 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
15101
15102 if (empty($call)) {
15103 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
15104 }
15105
15106 // invoke admin widgets helper
15107 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15108
15109 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
15110 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
15111 }
15112
15113 try {
15114 // invoke the helper's method and get the value returned
15115 if (is_array($call_args) && count($call_args)) {
15116 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
15117 } else {
15118 $result = $widgets_helper->{$call}();
15119 }
15120 } catch (Throwable $e) {
15121 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
15122 } catch (Exception $e) {
15123 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15124 }
15125
15126 // prepare response object with the result property
15127 $response = new stdClass;
15128 $response->result = $result;
15129
15130 // output the JSON response and exit
15131 VBOHttpDocument::getInstance()->json($response);
15132 }
15133
15134 /**
15135 * Handles requests for displaying a browser notification being dispatched.
15136 *
15137 * @see this is an AJAX endpoint.
15138 *
15139 * @since 1.15.0 (J) - 1.5.0 (WP)
15140 */
15141 public function notification_displayer()
15142 {
15143 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
15144
15145 if (empty($payload_str)) {
15146 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
15147 }
15148
15149 // attempt to decode the notification payload
15150 $payload = json_decode($payload_str);
15151
15152 if (!is_object($payload)) {
15153 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
15154 }
15155
15156 // get notification displayer for this type of notification
15157 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
15158 if (!$displayer) {
15159 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
15160 }
15161
15162 // compose the notification display data object
15163 try {
15164 $notif_data = $displayer->getData();
15165 if (!$notif_data) {
15166 throw new Exception('Error building the notification display data', 500);
15167 }
15168 } catch (Exception $e) {
15169 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15170 }
15171
15172 // output the JSON response and exit
15173 VBOHttpDocument::getInstance()->json($notif_data);
15174 }
15175
15176 /**
15177 * Handles requests for watching widgets data and getting
15178 * new events to trigger browser notifications.
15179 *
15180 * @see this is an AJAX endpoint.
15181 *
15182 * @since 1.15.0 (J) - 1.5.0 (WP)
15183 * @since 1.16.8 (J) - 1.6.8 (WP) introduced notification events.
15184 */
15185 public function widgets_watch_data()
15186 {
15187 if (!JSession::checkToken()) {
15188 // missing CSRF-proof token
15189 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15190 }
15191
15192 $app = JFactory::getApplication();
15193
15194 $watch_data_str = $app->input->get('watch_data', '', 'raw');
15195 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
15196
15197 if (empty($watch_data_str)) {
15198 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
15199 }
15200
15201 // attempt to decode the watch-data payload
15202 $watch_data = json_decode($watch_data_str, true);
15203
15204 if (!$watch_data) {
15205 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
15206 }
15207
15208 // check if any pushed data was set
15209 $pushed_data = (array)json_decode($pushed_data_str, true);
15210
15211 // container for new notifications
15212 $notifs_pool = [];
15213
15214 // container for the events data to dispatch
15215 $events_pool = [];
15216
15217 // get admin widgets helper
15218 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15219
15220 foreach ($watch_data as $widget_id => $data) {
15221 // invoke admin widget (with no pre-loading)
15222 $widget_instance = $widgets_helper->getWidget($widget_id);
15223 if (!$widget_instance) {
15224 continue;
15225 }
15226
15227 // build the widget watch data object
15228 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
15229
15230 // check if the widget needs to emit browser notifications
15231 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
15232
15233 // check if the widget needs to emit JavaScript events
15234 $events = $widget_instance->getNotificationEvents($widget_watch_data);
15235
15236 if ($watch_next) {
15237 // update next watch-data object for this widget
15238 $watch_data[$widget_id] = $watch_next;
15239 }
15240
15241 if (is_array($notifications) && $notifications) {
15242 // merge notifications
15243 $notifs_pool = array_merge($notifs_pool, $notifications);
15244 }
15245
15246 if (is_array($events) && $events) {
15247 // push notification events for this widget
15248 $events_pool[] = $events;
15249 }
15250 }
15251
15252 // build the response object
15253 $response = new stdClass;
15254 $response->watch_data = $watch_data;
15255 $response->notifications = $notifs_pool;
15256 $response->events = $events_pool;
15257
15258 // output the JSON response and exit
15259 VBOHttpDocument::getInstance()->json($response);
15260 }
15261
15262 /**
15263 * Outputs a list of CSS assets required to render the admin widgets
15264 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
15265 *
15266 * @see this is an AJAX endpoint.
15267 *
15268 * @since 1.16.0 (J) - 1.6.0 (WP)
15269 */
15270 public function widgets_get_assets()
15271 {
15272 // list of needed CSS asset details
15273 $assets_pool = [];
15274
15275 // appearance preference assets (one or none)
15276 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
15277
15278 if (VBOPlatformDetection::isWordPress()) {
15279 // WordPress (main CSS)
15280 $assets_pool[] = [
15281 'rel' => 'stylesheet',
15282 'id' => 'vbo-style-css',
15283 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15284 'media' => 'all',
15285 ];
15286
15287 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15288 // appearance preference CSS
15289 $assets_pool[] = [
15290 'rel' => 'stylesheet',
15291 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15292 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15293 'media' => 'all',
15294 ];
15295 }
15296 } else {
15297 // Joomla (main CSS)
15298 $assets_pool[] = [
15299 'rel' => 'stylesheet',
15300 'id' => 'vbo-style-css',
15301 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
15302 'media' => 'all',
15303 ];
15304
15305 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15306 // appearance preference CSS
15307 $assets_pool[] = [
15308 'rel' => 'stylesheet',
15309 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15310 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
15311 'media' => 'all',
15312 ];
15313 }
15314 }
15315
15316 // output the JSON response and exit
15317 VBOHttpDocument::getInstance()->json($assets_pool);
15318 }
15319 }
15320