PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
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 1.7.3 1.7.4 All 35 releases
vikbooking / admin / controller.php

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

15,887 lines 596.0 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 {
191 $dt = VikRequest::getString('dt', '', 'request');
192 $type = VikRequest::getString('type', '', 'request');
193 $type = empty($type) ? 'custom' : $type;
194 $name = VikRequest::getString('name', '', 'request');
195 $descr = VikRequest::getString('descr', '', 'request');
196
197 if (empty($name) || empty($dt) || !strtotime($dt)) {
198 VBOHttpDocument::getInstance()->close(400, 'Missing mandatory festivity details');
199 }
200
201 // build fest array
202 $new_fest = [
203 'trans_name' => $name,
204 ];
205
206 $fests = VikBooking::getFestivitiesInstance();
207 $result = $fests->storeFestivity($dt, $new_fest, $type, $descr);
208 if (!$result) {
209 VBOHttpDocument::getInstance()->close(400, 'Could not store festivity details');
210 }
211
212 // reload all festivities for this day for the AJAX response
213 $all_fests = $fests->loadFestDates($dt, $dt);
214 foreach ($all_fests as $k => $v) {
215 // we expect just one record to be returned due to the from/to date limit passed to loadFestDates()
216 VBOHttpDocument::getInstance()->json($v);
217 }
218
219 // no fests found even after storing it
220 VBOHttpDocument::getInstance()->close(404, 'Festivity record not found after saving');
221 }
222
223 /**
224 * AJAX request for removing a fest.
225 *
226 * @return void
227 *
228 * @since 1.2.0
229 */
230 public function remove_fest()
231 {
232 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
233 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
234 }
235
236 $dt = VikRequest::getString('dt', '', 'request');
237 $ind = VikRequest::getInt('ind', 0, 'request');
238 $type = VikRequest::getString('type', '', 'request');
239 $type = empty($type) ? 'custom' : $type;
240 if (empty($dt) || !strtotime($dt)) {
241 echo 'e4j.error.1';
242 exit;
243 }
244
245 $fests = VikBooking::getFestivitiesInstance();
246 $result = $fests->deleteFestivity($dt, $ind, $type);
247 if (!$result) {
248 echo 'e4j.error.2';
249 exit;
250 }
251
252 echo 'e4j.ok';
253 exit;
254 }
255
256 public function einvoicing() {
257 VikBookingHelper::printHeader("einvoicing");
258
259 VikRequest::setVar('view', VikRequest::getCmd('view', 'einvoicing'));
260
261 parent::display();
262
263 if (VikBooking::showFooter()) {
264 VikBookingHelper::printFooter();
265 }
266 }
267
268 public function pmsreports() {
269 if (!JFactory::getUser()->authorise('core.vbo.pms', 'com_vikbooking') && !JFactory::getUser()->authorise('core.vbo.pmsreports', 'com_vikbooking')) {
270 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
271 }
272
273 VikBookingHelper::printHeader("pmsreports");
274
275 VikRequest::setVar('view', VikRequest::getCmd('view', 'pmsreports'));
276
277 parent::display();
278
279 if (VikBooking::showFooter()) {
280 VikBookingHelper::printFooter();
281 }
282 }
283
284 public function ratesoverv() {
285 VikBookingHelper::printHeader("20");
286
287 VikRequest::setVar('view', VikRequest::getCmd('view', 'ratesoverv'));
288
289 parent::display();
290
291 if (VikBooking::showFooter()) {
292 VikBookingHelper::printFooter();
293 }
294 }
295
296 public function stats() {
297 VikBookingHelper::printHeader("stats");
298
299 VikRequest::setVar('view', VikRequest::getCmd('view', 'stats'));
300
301 parent::display();
302
303 if (VikBooking::showFooter()) {
304 VikBookingHelper::printFooter();
305 }
306 }
307
308 /**
309 * AJAX endpoint to calculate the website rates.
310 *
311 * @return void
312 */
313 public function calc_rates()
314 {
315 $response = 'e4j.error.ErrorCode(1) default error';
316 $response_code = 0;
317
318 // availability helper
319 $av_helper = VikBooking::getAvailabilityInstance();
320
321 $currencysymb = VikBooking::getCurrencySymb();
322 $vbo_df = VikBooking::getDateFormat();
323 $df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
324 $id_room = VikRequest::getInt('id_room', 0, 'request');
325 $checkin = VikRequest::getString('checkin', '', 'request');
326 $nights = VikRequest::getInt('num_nights', 1, 'request');
327 $adults = VikRequest::getInt('num_adults', 0, 'request');
328 $children = VikRequest::getInt('num_children', 0, 'request');
329 /**
330 * The page Calendar may call this task via AJAX to obtain information
331 * about the various rate plans and final costs associated.
332 *
333 * @since 1.13 (J) - 1.3.0 (WP)
334 */
335 $only_rates = VikRequest::getInt('only_rates', 0, 'request');
336 $units = VikRequest::getInt('units', 1, 'request');
337 $checkinfdate = VikRequest::getString('checkinfdate', '', 'request');
338 $checkoutfdate = VikRequest::getString('checkoutfdate', '', 'request');
339 if (!empty($checkinfdate) && empty($checkin)) {
340 $checkin = date('Y-m-d', VikBooking::getDateTimestamp($checkinfdate, 0, 0, 0));
341 }
342
343 $checkin_ts = strtotime($checkin);
344 if (empty($checkin_ts)) {
345 $checkin = date('Y-m-d');
346 $checkin_ts = strtotime($checkin);
347 }
348
349 if (!empty($checkoutfdate) && !empty($checkinfdate) && $nights < 2) {
350 // checkout date was given rather than number of nights
351 $checkout_ts = VikBooking::getDateTimestamp($checkoutfdate, 0, 0, 0);
352 $checkout = date('Y-m-d', $checkout_ts);
353 $nights = $av_helper->countNightsOfStay($checkin_ts, $checkout_ts);
354 } else {
355 // calculate checkout depending on number of nights of stay
356 $is_dst = date('I', $checkin_ts);
357 $checkout_ts = $checkin_ts;
358 for ($i = 1; $i <= $nights; $i++) {
359 $checkout_ts += 86400;
360 $is_now_dst = date('I', $checkout_ts);
361 if ($is_dst != $is_now_dst) {
362 if ((int)$is_dst == 1) {
363 $checkout_ts += 3600;
364 } else {
365 $checkout_ts -= 3600;
366 }
367 $is_dst = $is_now_dst;
368 }
369 }
370 $checkout = date('Y-m-d', $checkout_ts);
371 }
372
373 /**
374 * We got rid of the CURL request to the front-end task of VBO "tac_av_l"
375 * by replacing the call with the new helper class VikBookingAvailability.
376 *
377 * @since 1.15.0 (J) - 1.5.0 (WP)
378 */
379 $av_helper->setStayDates($checkin, $checkout);
380 $av_helper->setRoomParty($adults, $children);
381 // build extra params to obtain the necessary data
382 $params = [
383 'hash' => md5('vbo.e4j.vbo'),
384 'req_type' => 'hotel_availability',
385 'nights' => $nights,
386 'num_rooms' => 1,
387 'only_rates' => $only_rates,
388 'forced_room_ids' => $id_room ? [$id_room] : null,
389 ];
390 $arr_res = $av_helper->getRates($params);
391
392 // pricing pool
393 $price_details = [];
394
395 if (is_array($arr_res)) {
396 if (!strlen($av_helper->getError())) {
397 if (array_key_exists($id_room, $arr_res)) {
398 $response = '';
399 foreach ($arr_res[$id_room] as $rate) {
400 // build pricing object
401 $rplan_details = new stdClass;
402 $rplan_details->idprice = $rate['idprice'];
403 $rplan_details->name = $rate['pricename'];
404 $rplan_details->net = $rate['cost'];
405 $rplan_details->fnet = VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['cost']), $currencysymb);
406 $rplan_details->tax = $rate['taxes'];
407 $rplan_details->ftax = VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['taxes']), $currencysymb);
408 $rplan_details->tot = $rate['cost'] + $rate['taxes'];
409 $rplan_details->ftot = VikBooking::formatCurrencyNumber(VikBooking::numberFormat(($rate['cost'] + $rate['taxes'])), $currencysymb);
410 array_push($price_details, $rplan_details);
411 //
412 $extra_response = '';
413 $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 . '">';
414 $response .= '<span class="vbo-calcrates-ratename">'.$rate['pricename'].'</span>';
415 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratenet"><span>'.JText::translate('VBCALCRATESNET').'</span>'.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['cost']), $currencysymb).'</span>';
416 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratetax"><span>'.JText::translate('VBCALCRATESTAX').'</span>'.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['taxes']), $currencysymb).'</span>';
417 if (!empty($rate['city_taxes'])) {
418 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratecitytax"><span>'.JText::translate('VBCALCRATESCITYTAX').'</span>'.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['city_taxes']), $currencysymb).'</span>';
419 }
420 if (!empty($rate['fees'])) {
421 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratefees"><span>'.JText::translate('VBCALCRATESFEES').'</span>'.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($rate['fees']), $currencysymb).'</span>';
422 }
423 if (array_key_exists('affdays', $rate) && $rate['affdays'] > 0) {
424 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-ratespaffdays"><span>'.JText::translate('VBCALCRATESSPAFFDAYS').'</span>'.$rate['affdays'].'</span>';
425 }
426 if (array_key_exists('diffusagediscount', $rate) && count($rate['diffusagediscount']) > 0) {
427 foreach ($rate['diffusagediscount'] as $roomnumb => $disc) {
428 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancydisc"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>- '.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($disc), $currencysymb).'</span>';
429 break;
430 }
431 } elseif (array_key_exists('diffusagecost', $rate) && count($rate['diffusagecost']) > 0) {
432 foreach ($rate['diffusagecost'] as $roomnumb => $charge) {
433 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancycharge"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>+ '.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($charge), $currencysymb).'</span>';
434 break;
435 }
436 }
437 $tot = $rate['cost'] + $rate['taxes'] + $rate['city_taxes'] + $rate['fees'];
438 $tot = round($tot, 2);
439 $response .= '<span class="vbo-calcrates-ratetotal"><span>'.JText::translate('VBCALCRATESTOT').'</span>'.VikBooking::formatCurrencyNumber(VikBooking::numberFormat($tot), $currencysymb).'</span>';
440 if (!empty($extra_response)) {
441 $response .= '<div class="vbo-calcrates-info">'.$extra_response.'</div>';
442 }
443 $response .= '</div>';
444 }
445 } else {
446 $response = 'e4j.error.'.JText::sprintf('VBCALCRATESROOMNOTAVAILCOMBO', date($df, $checkin_ts), date($df, $checkout_ts));
447 /**
448 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
449 *
450 * @since 1.14 (J) - 1.4.0 (WP)
451 */
452 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
453 $response_code = -1;
454 }
455 }
456 } else {
457 $response = 'e4j.error.' . $av_helper->getError();
458 /**
459 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
460 *
461 * @since 1.14 (J) - 1.4.0 (WP)
462 */
463 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
464 $response_code = -1;
465 }
466 }
467 } else {
468 $response = 'e4j.error.' . $av_helper->getError();
469 }
470
471 if (!$arr_res && $id_room && in_array($id_room, $av_helper->getFullyBooked())) {
472 // set the response code to indicate the room is fully booked
473 $response_code = -1;
474 }
475
476 if ($only_rates && strpos($response, 'e4j.error') === false) {
477 VBOHttpDocument::getInstance()->json($price_details);
478 }
479
480 // do not do only echo trim($response); or the currency symbol will not be encoded on some servers
481 $safe_response = array(trim($response));
482 if ($only_rates && !empty($response_code)) {
483 array_push($safe_response, $response_code);
484 }
485
486 VBOHttpDocument::getInstance()->json($safe_response);
487 }
488
489 /**
490 * This is an AJAX endpoint.
491 */
492 public function cron_exec()
493 {
494 ob_start();
495
496 VikRequest::setVar('view', VikRequest::getCmd('view', 'cronexec'));
497
498 parent::display();
499
500 $content = ob_get_contents();
501 ob_end_clean();
502
503 VBOHttpDocument::getInstance()->json([$content]);
504 }
505
506 public function downloadcron()
507 {
508 /**
509 * @wponly no more executable files need to be downloaded for WordPress.
510 */
511 VBOHttpDocument::getInstance()->close(406, 'Cron Jobs must be executed through WPCron');
512 }
513
514 /**
515 * This is an AJAX endpoint.
516 */
517 public function cronlogs()
518 {
519 $dbo = JFactory::getDBO();
520 $pcron_id = VikRequest::getInt('cron_id', '', 'request');
521
522 ob_start();
523
524 $q = "SELECT * FROM `#__vikbooking_cronjobs` WHERE `id`=".(int)$pcron_id.";";
525 $dbo->setQuery($q);
526 $dbo->execute();
527 if ($dbo->getNumRows() == 1) {
528 $cron_data = $dbo->loadAssoc();
529 $cron_data['logs'] = empty($cron_data['logs']) ? '--------' : $cron_data['logs'];
530 echo '<pre>'.print_r($cron_data['logs'], true).'</pre>';
531 }
532
533 $content = ob_get_contents();
534 ob_end_clean();
535
536 VBOHttpDocument::getInstance()->json([$content]);
537 }
538
539 public function packages() {
540 VikBookingHelper::printHeader("packages");
541
542 VikRequest::setVar('view', VikRequest::getCmd('view', 'packages'));
543
544 parent::display();
545
546 if (VikBooking::showFooter()) {
547 VikBookingHelper::printFooter();
548 }
549 }
550
551 public function newpackage() {
552 VikBookingHelper::printHeader("packages");
553
554 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepackage'));
555
556 parent::display();
557
558 if (VikBooking::showFooter()) {
559 VikBookingHelper::printFooter();
560 }
561 }
562
563 public function editpackage() {
564 VikBookingHelper::printHeader("packages");
565
566 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepackage'));
567
568 parent::display();
569
570 if (VikBooking::showFooter()) {
571 VikBookingHelper::printFooter();
572 }
573 }
574
575 public function createpackage()
576 {
577 if (!JSession::checkToken()) {
578 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
579 }
580
581 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
582 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
583 }
584
585 $this->do_createpackage();
586 }
587
588 public function createpackagestay()
589 {
590 if (!JSession::checkToken()) {
591 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
592 }
593
594 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
595 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
596 }
597
598 $this->do_createpackage(true);
599 }
600
601 private function do_createpackage($stay = false) {
602 $dbo = JFactory::getDBO();
603 $mainframe = JFactory::getApplication();
604 $pname = VikRequest::getString('name', '', 'request');
605 $palias = VikRequest::getString('alias', '', 'request');
606 $palias = empty($palias) ? $pname : $palias;
607 $palias = JFilterOutput::stringURLSafe($palias);
608 $pimg = VikRequest::getVar('img', null, 'files', 'array');
609 $pfrom = VikRequest::getString('from', '', 'request');
610 $pto = VikRequest::getString('to', '', 'request');
611 $pexcludeday = VikRequest::getVar('excludeday', array());
612 $strexcldates = array();
613 foreach ($pexcludeday as $exclday) {
614 if (!empty($exclday)) {
615 $strexcldates[] = $exclday;
616 }
617 }
618 $strexcldates = implode(';', $strexcldates);
619 $prooms = VikRequest::getVar('rooms', array());
620 $pminlos = VikRequest::getInt('minlos', '', 'request');
621 $pminlos = $pminlos < 1 ? 1 : $pminlos;
622 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
623 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
624 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
625 $pcost = VikRequest::getFloat('cost', '', 'request');
626 $paliq = VikRequest::getInt('aliq', '', 'request');
627 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
628 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
629 $pperperson = VikRequest::getInt('perperson', '', 'request');
630 $pperperson = $pperperson > 0 ? 1 : 0;
631 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
632 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
633 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
634 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
635 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
636 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
637 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
638 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
639 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
640 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
641 //file upload
642 jimport('joomla.filesystem.file');
643 $gimg = "";
644 if (isset($pimg) && strlen(trim($pimg['name']))) {
645 $pautoresize = VikRequest::getString('autoresize', '', 'request');
646 $presizeto = VikRequest::getInt('resizeto', '', 'request');
647 $creativik = new vikResizer();
648 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
649 $src = $pimg['tmp_name'];
650 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
651 $j = "";
652 if (file_exists($dest.$filename)) {
653 $j = rand(171, 1717);
654 while (file_exists($dest.$j.$filename)) {
655 $j++;
656 }
657 }
658 $finaldest = $dest.$j.$filename;
659 $check = getimagesize($pimg['tmp_name']);
660 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
661 if (VikBooking::uploadFile($src, $finaldest)) {
662 $gimg = $j.$filename;
663 //orig img
664 $origmod = true;
665 if ($pautoresize == "1" && !empty($presizeto)) {
666 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
667 } else {
668 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
669 }
670 //thumb
671 $thumbsize = VikBooking::getThumbSize();
672 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
673 if (!$thumb || !$origmod) {
674 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
675 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
676 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
677 }
678 @unlink($finaldest);
679 } else {
680 VikError::raiseWarning('', 'Error while uploading image');
681 }
682 } else {
683 VikError::raiseWarning('', 'Uploaded file is not an Image');
684 }
685 }
686 //
687 $goto = "index.php?option=com_vikbooking&task=packages";
688 $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.");";
689 $dbo->setQuery($q);
690 $dbo->execute();
691 $lid = $dbo->insertid();
692 if (!empty($lid)) {
693 $mainframe->enqueueMessage(JText::translate('VBOPKGSAVED'));
694 if ($stay) {
695 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$lid;
696 }
697 foreach ($prooms as $roomid) {
698 if (!empty($roomid)) {
699 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$lid.", ".(int)$roomid.");";
700 $dbo->setQuery($q);
701 $dbo->execute();
702 }
703 }
704 }
705 $mainframe->redirect($goto);
706 }
707
708 public function updatepackage()
709 {
710 if (!JSession::checkToken()) {
711 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
712 }
713
714 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
715 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
716 }
717
718 $this->do_updatepackage();
719 }
720
721 public function updatepackagestay()
722 {
723 if (!JSession::checkToken()) {
724 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
725 }
726
727 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
728 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
729 }
730
731 $this->do_updatepackage(true);
732 }
733
734 private function do_updatepackage($stay = false) {
735 $dbo = JFactory::getDBO();
736 $mainframe = JFactory::getApplication();
737 $pwhereup = VikRequest::getInt('whereup', '', 'request');
738 $q = "SELECT * FROM `#__vikbooking_packages` WHERE `id`=".(int)$pwhereup.";";
739 $dbo->setQuery($q);
740 $dbo->execute();
741 if ($dbo->getNumRows() == 1) {
742 $pkg_data = $dbo->loadAssoc();
743 } else {
744 VikError::raiseWarning('', 'Not Found.');
745 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
746 exit;
747 }
748 $pname = VikRequest::getString('name', '', 'request');
749 $palias = VikRequest::getString('alias', '', 'request');
750 $palias = empty($palias) ? $pname : $palias;
751 $palias = JFilterOutput::stringURLSafe($palias);
752 $pimg = VikRequest::getVar('img', null, 'files', 'array');
753 $pfrom = VikRequest::getString('from', '', 'request');
754 $pto = VikRequest::getString('to', '', 'request');
755 $pexcludeday = VikRequest::getVar('excludeday', array());
756 $strexcldates = array();
757 foreach ($pexcludeday as $exclday) {
758 if (!empty($exclday)) {
759 $strexcldates[] = $exclday;
760 }
761 }
762 $strexcldates = implode(';', $strexcldates);
763 $prooms = VikRequest::getVar('rooms', array());
764 $pminlos = VikRequest::getInt('minlos', '', 'request');
765 $pminlos = $pminlos < 1 ? 1 : $pminlos;
766 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
767 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
768 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
769 $pcost = VikRequest::getFloat('cost', '', 'request');
770 $paliq = VikRequest::getInt('aliq', '', 'request');
771 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
772 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
773 $pperperson = VikRequest::getInt('perperson', '', 'request');
774 $pperperson = $pperperson > 0 ? 1 : 0;
775 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
776 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
777 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
778 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
779 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
780 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
781 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
782 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
783 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
784 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
785 //file upload
786 jimport('joomla.filesystem.file');
787 $gimg = "";
788 if (isset($pimg) && strlen(trim($pimg['name']))) {
789 $pautoresize = VikRequest::getString('autoresize', '', 'request');
790 $presizeto = VikRequest::getInt('resizeto', '', 'request');
791 $creativik = new vikResizer();
792 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
793 $src = $pimg['tmp_name'];
794 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
795 $j = "";
796 if (file_exists($dest.$filename)) {
797 $j = rand(171, 1717);
798 while (file_exists($dest.$j.$filename)) {
799 $j++;
800 }
801 }
802 $finaldest = $dest.$j.$filename;
803 $check = getimagesize($pimg['tmp_name']);
804 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
805 if (VikBooking::uploadFile($src, $finaldest)) {
806 $gimg = $j.$filename;
807 //orig img
808 $origmod = true;
809 if ($pautoresize == "1" && !empty($presizeto)) {
810 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
811 } else {
812 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
813 }
814 //thumb
815 $thumbsize = VikBooking::getThumbSize();
816 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
817 if (!$thumb || !$origmod) {
818 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
819 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
820 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
821 }
822 @unlink($finaldest);
823 } else {
824 VikError::raiseWarning('', 'Error while uploading image');
825 }
826 } else {
827 VikError::raiseWarning('', 'Uploaded file is not an Image');
828 }
829 }
830 //
831 $goto = "index.php?option=com_vikbooking&task=packages";
832 $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.";";
833 $dbo->setQuery($q);
834 $dbo->execute();
835 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$pwhereup.";";
836 $dbo->setQuery($q);
837 $dbo->execute();
838 foreach ($prooms as $roomid) {
839 if (!empty($roomid)) {
840 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$pwhereup.", ".(int)$roomid.");";
841 $dbo->setQuery($q);
842 $dbo->execute();
843 }
844 }
845 $mainframe->enqueueMessage(JText::translate('VBOPKGUPDATED'));
846 if ($stay) {
847 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$pwhereup;
848 }
849 $mainframe->redirect($goto);
850 }
851
852 public function removepackages()
853 {
854 if (!JSession::checkToken()) {
855 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
856 }
857
858 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
859 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
860 }
861
862 $ids = VikRequest::getVar('cid', array());
863 $dbo = JFactory::getDbo();
864
865 foreach ($ids as $d) {
866 $q = "DELETE FROM `#__vikbooking_packages` WHERE `id`=".(int)$d.";";
867 $dbo->setQuery($q);
868 $dbo->execute();
869 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$d.";";
870 $dbo->setQuery($q);
871 $dbo->execute();
872 }
873
874 $mainframe = JFactory::getApplication();
875 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
876 }
877
878 public function calendar() {
879 VikBookingHelper::printHeader("19");
880
881 VikRequest::setVar('view', VikRequest::getCmd('view', 'calendar'));
882
883 parent::display();
884
885 if (VikBooking::showFooter()) {
886 VikBookingHelper::printFooter();
887 }
888 }
889
890 public function rooms() {
891 VikBookingHelper::printHeader("7");
892
893 VikRequest::setVar('view', VikRequest::getCmd('view', 'rooms'));
894
895 parent::display();
896
897 if (VikBooking::showFooter()) {
898 VikBookingHelper::printFooter();
899 }
900 }
901
902 public function newroom() {
903 VikBookingHelper::printHeader("7");
904
905 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
906
907 parent::display();
908
909 if (VikBooking::showFooter()) {
910 VikBookingHelper::printFooter();
911 }
912 }
913
914 public function editroom() {
915 VikBookingHelper::printHeader("7");
916
917 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
918
919 parent::display();
920
921 if (VikBooking::showFooter()) {
922 VikBookingHelper::printFooter();
923 }
924 }
925
926 public function createroom()
927 {
928 if (!JSession::checkToken()) {
929 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
930 }
931
932 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
933 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
934 }
935
936 $this->do_createroom();
937 }
938
939 public function createroomstay()
940 {
941 if (!JSession::checkToken()) {
942 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
943 }
944
945 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
946 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
947 }
948
949 $this->do_createroom(true);
950 }
951
952 private function do_createroom($stay = false) {
953 $app = JFactory::getApplication();
954 $pcname = VikRequest::getString('cname', '', 'request');
955 $pccat = VikRequest::getVar('ccat', array(0));
956 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
957 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
958 $pccarat = VikRequest::getVar('ccarat', array(0));
959 $pcoptional = VikRequest::getVar('coptional', array(0));
960 $pcavail = VikRequest::getString('cavail', '', 'request');
961 $pautoresize = VikRequest::getString('autoresize', '', 'request');
962 $presizeto = VikRequest::getString('resizeto', '', 'request');
963 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
964 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
965 $punits = VikRequest::getInt('units', '', 'request');
966 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
967 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
968 $ptoadult = VikRequest::getInt('toadult', '', 'request');
969 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
970 $ptochild = VikRequest::getInt('tochild', '', 'request');
971 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
972 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
973 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
974 $plastavail = VikRequest::getString('lastavail', '', 'request');
975 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
976 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
977 $pcustprice = VikRequest::getString('custprice', '', 'request');
978 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
979 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
980 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
981 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
982 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
983 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
984 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
985 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
986 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
987 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
988 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
989 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
990 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
991 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
992 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
993 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
994 $psefalias = VikRequest::getString('sefalias', '', 'request');
995 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
996 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
997 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
998 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
999 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
1000 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
1001 $pshare_with = VikRequest::getVar('share_with', array());
1002 $scalnights_arr = array();
1003 if (!empty($pseasoncal_nights)) {
1004 $scalnights = explode(',', $pseasoncal_nights);
1005 foreach ($scalnights as $scalnight) {
1006 if (intval(trim($scalnight)) > 0) {
1007 $scalnights_arr[] = intval(trim($scalnight));
1008 }
1009 }
1010 }
1011 if ($scalnights_arr) {
1012 $pseasoncal_nights = implode(', ', $scalnights_arr);
1013 } else {
1014 $pseasoncal_nights = '';
1015 $pseasoncal = 0;
1016 }
1017 $roomparams = [
1018 'lastavail' => $plastavail,
1019 'suggocc' => $psuggocc,
1020 'custprice' => $pcustprice,
1021 'custpricetxt' => $pcustpricetxt,
1022 'custpricesubtxt' => $pcustpricesubtxt,
1023 'reqinfo' => $preqinfo,
1024 'pricecal' => $ppricecal,
1025 'defcalcost' => floatval($pdefcalcost),
1026 'maxminpeople' => $pmaxminpeople,
1027 'seasoncal' => $pseasoncal,
1028 'seasoncal_nights' => $pseasoncal_nights,
1029 'seasoncal_prices' => $pseasoncal_prices,
1030 'seasoncal_restr' => $pseasoncal_restr,
1031 'multi_units' => $pmulti_units,
1032 'custptitle' => $pcustptitle,
1033 'custptitlew' => $pcustptitlew,
1034 'metakeywords' => $pmetakeywords,
1035 'metadescription' => $pmetadescription,
1036 'layout_style' => VikRequest::getString('layout_style', 'default', 'request'),
1037 'checkin' => VikRequest::getString('listing_checkin', '', 'request'),
1038 'checkout' => VikRequest::getString('listing_checkout', '', 'request'),
1039 'instructions' => VikRequest::getString('listing_instructions', '', 'request', VIKREQUEST_ALLOWRAW),
1040 ];
1041 //distinctive features
1042 $roomparams['features'] = array();
1043 if ($punits > 0) {
1044 for ($i=1; $i <= $punits; $i++) {
1045 $distf_name = VikRequest::getVar('feature-name'.$i, array());
1046 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
1047 $distf_value = VikRequest::getVar('feature-value'.$i, array());
1048 foreach ($distf_name as $distf_k => $distf) {
1049 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
1050 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
1051 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
1052 }
1053 }
1054 }
1055 }
1056
1057 /**
1058 * Store room geo params information.
1059 *
1060 * @since 1.14 (J) - 1.4.0 (WP)
1061 */
1062 $geo = VikBooking::getGeocodingInstance();
1063 $geo_params = $geo->getRoomGeoTransient(0);
1064 if ($geo_params !== false) {
1065 // make sure the geocoding service was not turned off
1066 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
1067 if (!$geo_enabled) {
1068 $geo_params->enabled = 0;
1069 }
1070 //
1071 $roomparams['geo'] = $geo_params;
1072 }
1073 //
1074
1075 $roomparamstr = json_encode($roomparams);
1076
1077 if (empty($pcname)) {
1078 $app->enqueueMessage(JText::translate('VBO_PLEASE_FILL_FIELDS'), 'error');
1079 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1080 $app->close();
1081 }
1082
1083 jimport('joomla.filesystem.file');
1084 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1085
1086 $picon = "";
1087 if (($_FILES['cimg'] ?? null) && !intval($_FILES['cimg']['error']) && VikBooking::caniWrite($updpath) && strlen(trim($_FILES['cimg']['name'])) && @is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1088 $safename = JFile::makeSafe(str_replace(' ', '_', strtolower($_FILES['cimg']['name'])));
1089 $j = '';
1090 $pwhere = $updpath . $safename;
1091 if (file_exists($updpath . $safename)) {
1092 $j = 1;
1093 while (file_exists($updpath . $j . $safename)) {
1094 $j++;
1095 }
1096 $pwhere = $updpath . $j . $safename;
1097 }
1098 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1099 @unlink($pwhere);
1100 } elseif (VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere)) {
1101 $picon = $j . $safename;
1102 if ((int) $pautoresize && !empty($presizeto)) {
1103 $origmod = (new VikResizer)->proportionalImage($pwhere, $updpath . 'r_' . $j . $safename, $presizeto, $presizeto);
1104 if ($origmod) {
1105 @unlink($pwhere);
1106 $picon = 'r_' . $j . $safename;
1107 }
1108 }
1109 /**
1110 * Create a mini-thumbnail of the room/listing main photo.
1111 *
1112 * @since 1.17.5 (J) - 1.7.5 (WP)
1113 */
1114 try {
1115 // resize the original image
1116 (new VikResizer)->proportionalImage($pwhere, $updpath . 'mini_' . $picon, 96, 96);
1117 } catch (Throwable $e) {
1118 // silently catch any PHP GD error and continue
1119 }
1120 }
1121 }
1122
1123 // more images
1124 $creativik = new VikResizer;
1125 $bigsdest = $updpath;
1126 $thumbsdest = $updpath;
1127 $dest = $updpath;
1128 $moreimagestr = "";
1129 $arrimgs = array();
1130 $captiontexts = array();
1131 $imgcaptions = array();
1132 foreach ($pimages['name'] as $kk=>$ci) {
1133 if (!empty($ci)) {
1134 $arrimgs[] = $kk;
1135 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1136 }
1137 }
1138 foreach ($arrimgs as $ki => $imgk) {
1139 if (strlen(trim($pimages['name'][$imgk]))) {
1140 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1141 $src = $pimages['tmp_name'][$imgk];
1142 $j = "";
1143 if (file_exists($dest.$filename)) {
1144 $j = rand(171, 1717);
1145 while (file_exists($dest.$j.$filename)) {
1146 $j++;
1147 }
1148 }
1149 $finaldest = $dest.$j.$filename;
1150 $check = getimagesize($pimages['tmp_name'][$imgk]);
1151 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1152 if (VikBooking::uploadFile($src, $finaldest)) {
1153 $gimg = $j.$filename;
1154 //orig img
1155 $origmod = true;
1156 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1157 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1158 } else {
1159 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1160 }
1161 //thumb
1162 $thumbsize = VikBooking::getThumbSize();
1163 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1164 if (!$thumb || !$origmod) {
1165 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1166 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1167 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1168 } else {
1169 $moreimagestr .= $j.$filename.";;";
1170 $imgcaptions[] = $captiontexts[$ki];
1171 }
1172 @unlink($finaldest);
1173 } else {
1174 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1175 }
1176 } else {
1177 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1178 }
1179 }
1180 }
1181 //end more images
1182 if (is_array($pccat) && count($pccat)) {
1183 $pccatdef="";
1184 foreach ($pccat as $ccat) {
1185 if (!empty($ccat)) {
1186 $pccatdef.=$ccat.";";
1187 }
1188 }
1189 } else {
1190 $pccatdef="";
1191 }
1192 if (is_array($pccarat) && count($pccarat)) {
1193 $pccaratdef="";
1194 foreach ($pccarat as $ccarat) {
1195 $pccaratdef.=$ccarat.";";
1196 }
1197 } else {
1198 $pccaratdef="";
1199 }
1200 if (is_array($pcoptional) && count($pcoptional)) {
1201 $pcoptionaldef="";
1202 foreach ($pcoptional as $coptional) {
1203 $pcoptionaldef.=$coptional.";";
1204 }
1205 } else {
1206 $pcoptionaldef="";
1207 }
1208 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1209 if ($pfromadult > $ptoadult) {
1210 $pfromadult = 1;
1211 $ptoadult = 1;
1212 }
1213 if ($pfromchild > $ptochild) {
1214 $pfromchild = 1;
1215 $ptochild = 1;
1216 }
1217 $dbo = JFactory::getDbo();
1218 $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).");";
1219 $dbo->setQuery($q);
1220 $dbo->execute();
1221 $lid = $dbo->insertid();
1222 if (empty($lid)) {
1223 $app->enqueueMessage('Could not store the record on the database', 'error');
1224 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1225 $app->close();
1226 }
1227
1228 /**
1229 * Share availability calendars with other rooms.
1230 *
1231 * @since 1.13
1232 */
1233 // always reset relations for this main room
1234 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$lid};";
1235 $dbo->setQuery($q);
1236 $dbo->execute();
1237 $newxref = array();
1238 foreach ($pshare_with as $cldroom) {
1239 if (!empty($cldroom)) {
1240 array_push($newxref, (int)$cldroom);
1241 }
1242 }
1243 foreach ($newxref as $cldroom) {
1244 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$lid}, {$cldroom});";
1245 $dbo->setQuery($q);
1246 $dbo->execute();
1247 }
1248
1249 /**
1250 * Room upgrade options.
1251 *
1252 * @since 1.16.0 (J) - 1.6.0 (WP)
1253 */
1254 $config = VBOFactory::getConfig();
1255 $room_upgrade_options = [];
1256 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1257 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1258 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1259 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1260 $upgrade_rooms = array_map(function($rid) {
1261 return (int)$rid;
1262 }, $upgrade_rooms);
1263
1264 $room_upgrade_options = [
1265 'rooms' => $upgrade_rooms,
1266 'discount' => $upgrade_discount,
1267 ];
1268 }
1269 $config->set('room_upgrade_options_' . $lid, json_encode($room_upgrade_options));
1270
1271 if ($stay === true) {
1272 $app->enqueueMessage(JText::translate('VBOROOMSAVEOK').' - <a href="index.php?option=com_vikbooking&task=tariffs&cid[]='.$lid.'">'.JText::translate('VBOGOTORATES').'</a>');
1273 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$lid);
1274 $app->close();
1275 }
1276
1277 $app->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$lid);
1278 $app->close();
1279 }
1280
1281 public function updateroom()
1282 {
1283 if (!JSession::checkToken()) {
1284 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1285 }
1286
1287 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1288 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1289 }
1290
1291 $this->do_updateroom();
1292 }
1293
1294 public function updateroomstay()
1295 {
1296 if (!JSession::checkToken()) {
1297 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1298 }
1299
1300 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1301 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1302 }
1303
1304 $this->do_updateroom(true);
1305 }
1306
1307 private function do_updateroom($stay = false)
1308 {
1309 $app = JFactory::getApplication();
1310 $config = VBOFactory::getConfig();
1311 $dbo = JFactory::getDbo();
1312
1313 $pcname = VikRequest::getString('cname', '', 'request');
1314 $pccat = VikRequest::getVar('ccat', array(0));
1315 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
1316 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
1317 $pccarat = VikRequest::getVar('ccarat', array(0));
1318 $pcoptional = VikRequest::getVar('coptional', array(0));
1319 $pcavail = VikRequest::getString('cavail', '', 'request');
1320 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
1321 $pautoresize = VikRequest::getString('autoresize', '', 'request');
1322 $presizeto = VikRequest::getString('resizeto', '', 'request');
1323 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
1324 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
1325 $punits = VikRequest::getInt('units', '', 'request');
1326 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
1327 $pactmoreimgs = VikRequest::getString('actmoreimgs', '', 'request');
1328 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
1329 $ptoadult = VikRequest::getInt('toadult', '', 'request');
1330 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
1331 $ptochild = VikRequest::getInt('tochild', '', 'request');
1332 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array(0));
1333 $padultsdiffval = VikRequest::getVar('adultsdiffval', array(0));
1334 $padultsdiffnum = VikRequest::getVar('adultsdiffnum', array(0));
1335 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array(0));
1336 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array(0));
1337 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
1338 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
1339 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
1340 $plastavail = VikRequest::getString('lastavail', '', 'request');
1341 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
1342 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
1343 $pcustprice = VikRequest::getString('custprice', '', 'request');
1344 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
1345 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
1346 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
1347 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
1348 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
1349 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
1350 $pdefrplan = VikRequest::getInt('defrplan', 0, 'request');
1351 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
1352 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
1353 $pimgsorting = VikRequest::getVar('imgsorting', array());
1354 $pupdatecaption = VikRequest::getInt('updatecaption', '', 'request');
1355 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
1356 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
1357 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
1358 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
1359 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
1360 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
1361 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
1362 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
1363 $psefalias = VikRequest::getString('sefalias', '', 'request');
1364 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
1365 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
1366 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
1367 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
1368 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
1369 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
1370 $pshare_with = VikRequest::getVar('share_with', array());
1371 $scalnights_arr = array();
1372 if (!empty($pseasoncal_nights)) {
1373 $scalnights = explode(',', $pseasoncal_nights);
1374 foreach ($scalnights as $scalnight) {
1375 if (intval(trim($scalnight)) > 0) {
1376 $scalnights_arr[] = intval(trim($scalnight));
1377 }
1378 }
1379 }
1380 if ($scalnights_arr) {
1381 $pseasoncal_nights = implode(', ', $scalnights_arr);
1382 } else {
1383 $pseasoncal_nights = '';
1384 $pseasoncal = 0;
1385 }
1386 $roomparams = [
1387 'lastavail' => $plastavail,
1388 'suggocc' => $psuggocc,
1389 'custprice' => $pcustprice,
1390 'custpricetxt' => $pcustpricetxt,
1391 'custpricesubtxt' => $pcustpricesubtxt,
1392 'reqinfo' => $preqinfo,
1393 'pricecal' => $ppricecal,
1394 'defcalcost' => floatval($pdefcalcost),
1395 'defrplan' => $pdefrplan,
1396 'maxminpeople' => $pmaxminpeople,
1397 'seasoncal' => $pseasoncal,
1398 'seasoncal_nights' => $pseasoncal_nights,
1399 'seasoncal_prices' => $pseasoncal_prices,
1400 'seasoncal_restr' => $pseasoncal_restr,
1401 'multi_units' => $pmulti_units,
1402 'custptitle' => $pcustptitle,
1403 'custptitlew' => $pcustptitlew,
1404 'metakeywords' => $pmetakeywords,
1405 'metadescription' => $pmetadescription,
1406 'layout_style' => VikRequest::getString('layout_style', 'default', 'request'),
1407 'checkin' => VikRequest::getString('listing_checkin', '', 'request'),
1408 'checkout' => VikRequest::getString('listing_checkout', '', 'request'),
1409 'instructions' => VikRequest::getString('listing_instructions', '', 'request', VIKREQUEST_ALLOWRAW),
1410 ];
1411 //distinctive features
1412 $roomparams['features'] = array();
1413 $newfeatures = array();
1414 if ($punits > 0) {
1415 for ($i=1; $i <= $punits; $i++) {
1416 $distf_name = VikRequest::getVar('feature-name'.$i, array());
1417 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
1418 $distf_value = VikRequest::getVar('feature-value'.$i, array());
1419 foreach ($distf_name as $distf_k => $distf) {
1420 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
1421 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
1422 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
1423 if ($distf_k < 1) {
1424 //check only the first feature
1425 $newfeatures[$i][$use_key] = $distf_value[$distf_k];
1426 }
1427 }
1428 }
1429 }
1430 }
1431
1432 // load current room record
1433 $dbo->setQuery(
1434 $dbo->getQuery(true)
1435 ->select('*')
1436 ->from($dbo->qn('#__vikbooking_rooms'))
1437 ->where($dbo->qn('id') . ' = ' . (int) $pwhereup)
1438 );
1439 $prevroom = $dbo->loadAssoc();
1440 if (!$prevroom) {
1441 VBOHttpDocument::getInstance()->close(404, 'Record not found');
1442 }
1443
1444 /**
1445 * Store room geo params information.
1446 *
1447 * @since 1.14 (J) - 1.4.0 (WP)
1448 */
1449 $geo = VikBooking::getGeocodingInstance();
1450 $geo_params = $geo->getRoomGeoTransient($pwhereup);
1451 if ($geo_params !== false) {
1452 // make sure the geocoding service was not turned off
1453 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
1454 if (!$geo_enabled) {
1455 $geo_params->enabled = 0;
1456 }
1457 //
1458 $roomparams['geo'] = $geo_params;
1459 }
1460 //
1461
1462 $roomparamstr = json_encode($roomparams);
1463
1464 jimport('joomla.filesystem.file');
1465 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1466
1467 if (!empty($pcname)) {
1468
1469 $picon = "";
1470 if (($_FILES['cimg'] ?? null) && !intval($_FILES['cimg']['error']) && VikBooking::caniWrite($updpath) && strlen(trim($_FILES['cimg']['name'])) && @is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1471 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['cimg']['name'])));
1472 $j = '';
1473 $pwhere = $updpath . $safename;
1474 if (file_exists($updpath . $safename)) {
1475 $j = 1;
1476 while (file_exists($updpath . $j . $safename)) {
1477 $j++;
1478 }
1479 $pwhere = $updpath . $j . $safename;
1480 }
1481 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1482 @unlink($pwhere);
1483 } elseif (VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere)) {
1484 $picon = $j . $safename;
1485 if ((int) $pautoresize && !empty($presizeto)) {
1486 $origmod = (new VikResizer)->proportionalImage($pwhere, $updpath . 'r_' . $j . $safename, $presizeto, $presizeto);
1487 if ($origmod) {
1488 @unlink($pwhere);
1489 $picon = 'r_' . $j . $safename;
1490 }
1491 }
1492 /**
1493 * Create a mini-thumbnail of the room/listing main photo.
1494 *
1495 * @since 1.17.5 (J) - 1.7.5 (WP)
1496 */
1497 try {
1498 // resize the original image
1499 (new VikResizer)->proportionalImage($pwhere, $updpath . 'mini_' . $picon, 96, 96);
1500 } catch (Throwable $e) {
1501 // silently catch any PHP GD error and continue
1502 }
1503 }
1504 }
1505
1506 /**
1507 * Create a mini-thumbnail of the current room/listing main photo.
1508 *
1509 * @since 1.17.5 (J) - 1.7.5 (WP)
1510 */
1511 if (!$picon && !empty($prevroom['img']) && is_file($updpath . $prevroom['img']) && !is_file($updpath . 'mini_' . $prevroom['img'])) {
1512 try {
1513 // resize the original image
1514 (new VikResizer)->proportionalImage($updpath . $prevroom['img'], $updpath . 'mini_' . $prevroom['img'], 96, 96);
1515 } catch (Throwable $e) {
1516 // silently catch any PHP GD error and continue
1517 }
1518 }
1519
1520 // more images
1521 $creativik = new VikResizer;
1522 $bigsdest = $updpath;
1523 $thumbsdest = $updpath;
1524 $dest = $updpath;
1525 $moreimagestr = $pactmoreimgs;
1526 $arrimgs = array();
1527 $captiontexts = array();
1528 $imgcaptions = array();
1529 //captions of uploaded extra images
1530 if (!empty($pactmoreimgs)) {
1531 $sploimgs = explode(';;', $pactmoreimgs);
1532 foreach ($sploimgs as $ki => $oimg) {
1533 if (!empty($oimg)) {
1534 $oldcaption = VikRequest::getString('caption'.$ki, '', 'request', VIKREQUEST_ALLOWHTML);
1535 $imgcaptions[] = $oldcaption;
1536 }
1537 }
1538 }
1539 //
1540 foreach ($pimages['name'] as $kk=>$ci) {
1541 if (!empty($ci)) {
1542 $arrimgs[] = $kk;
1543 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1544 }
1545 }
1546 foreach ($arrimgs as $ki => $imgk) {
1547 if (strlen(trim($pimages['name'][$imgk]))) {
1548 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1549 $src = $pimages['tmp_name'][$imgk];
1550 $j = "";
1551 if (file_exists($dest.$filename)) {
1552 $j = rand(171, 1717);
1553 while (file_exists($dest.$j.$filename)) {
1554 $j++;
1555 }
1556 }
1557 $finaldest = $dest.$j.$filename;
1558 $check = getimagesize($pimages['tmp_name'][$imgk]);
1559 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1560 if (VikBooking::uploadFile($src, $finaldest)) {
1561 $gimg = $j.$filename;
1562 //orig img
1563 $origmod = true;
1564 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1565 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1566 } else {
1567 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1568 }
1569 //thumb
1570 $thumbsize = VikBooking::getThumbSize();
1571 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1572 if (!$thumb || !$origmod) {
1573 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1574 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1575 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1576 } else {
1577 $moreimagestr .= $j.$filename.";;";
1578 $imgcaptions[] = $captiontexts[$ki];
1579 }
1580 @unlink($finaldest);
1581 } else {
1582 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1583 }
1584 } else {
1585 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1586 }
1587 }
1588 }
1589 //sorting of extra images
1590 $sorted_extraim = array();
1591 $sorted_captions = array();
1592 $extraim_parts = explode(';;', $moreimagestr);
1593 foreach ($pimgsorting as $k => $v) {
1594 $capkey = -1;
1595 if (isset($extraim_parts[$k])) {
1596 $sorted_extraim[] = $v;
1597 foreach ($extraim_parts as $oldk => $oldv) {
1598 if ($oldv == $v) {
1599 $capkey = $oldk;
1600 break;
1601 }
1602 }
1603 }
1604 if (isset($imgcaptions[$capkey])) {
1605 $sorted_captions[] = $imgcaptions[$capkey];
1606 }
1607 }
1608 $tot_sorted_im = count($sorted_extraim);
1609 if ($tot_sorted_im != count($extraim_parts)) {
1610 foreach ($extraim_parts as $k => $v) {
1611 if ($k <= ($tot_sorted_im - 1)) {
1612 continue;
1613 }
1614 $sorted_extraim[] = $v;
1615 if (isset($imgcaptions[$k])) {
1616 $sorted_captions[] = $imgcaptions[$k];
1617 }
1618 }
1619 }
1620 $moreimagestr = implode(';;', $sorted_extraim);
1621 $imgcaptions = $sorted_captions;
1622 //end more images
1623 if (is_array($pccat) && count($pccat)) {
1624 $pccatdef = "";
1625 foreach ($pccat as $ccat) {
1626 if (!empty($ccat)) {
1627 $pccatdef .= $ccat.";";
1628 }
1629 }
1630 } else {
1631 $pccatdef = "";
1632 }
1633 if (is_array($pccarat) && count($pccarat)) {
1634 $pccaratdef = "";
1635 foreach ($pccarat as $ccarat) {
1636 $pccaratdef .= $ccarat.";";
1637 }
1638 } else {
1639 $pccaratdef = "";
1640 }
1641 if (is_array($pcoptional) && count($pcoptional)) {
1642 $pcoptionaldef = "";
1643 foreach ($pcoptional as $coptional) {
1644 $pcoptionaldef .= $coptional.";";
1645 }
1646 } else {
1647 $pcoptionaldef = "";
1648 }
1649 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1650 if ($pfromadult > $ptoadult) {
1651 $pfromadult = 1;
1652 $ptoadult = 1;
1653 }
1654 if ($pfromchild > $ptochild) {
1655 $pfromchild = 1;
1656 $ptochild = 1;
1657 }
1658
1659 //adults charges/discounts
1660 $adchdisctouch = false;
1661 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`='".$pwhereup."';";
1662 $dbo->setQuery($q);
1663 $dbo->execute();
1664 $oldroom = $dbo->loadAssocList();
1665 $oldroom = $oldroom[0];
1666 if ($oldroom['fromadult'] == $pfromadult && $oldroom['toadult'] == $ptoadult) {
1667 if ($oldroom['toadult'] > 1 && $oldroom['fromadult'] < $oldroom['toadult'] && @count($padultsdiffnum) > 0) {
1668 $startadind = $oldroom['fromadult'] > 0 ? $oldroom['fromadult'] : 1;
1669 for($adi = $startadind; $adi <= $oldroom['toadult']; $adi++) {
1670 foreach ($padultsdiffnum as $kad=>$vad) {
1671 if (intval($vad) == intval($adi) && strlen($padultsdiffval[$kad]) > 0) {
1672 $adchdisctouch = true;
1673 $inschdisc = intval($padultsdiffchdisc[$kad]) == 1 ? 1 : 2;
1674 $insvalpcent = intval($padultsdiffvalpcent[$kad]) == 1 ? 1 : 2;
1675 $inspernight = intval($padultsdiffpernight[$kad]) == 1 ? 1 : 0;
1676 $insvalue = floatval($padultsdiffval[$kad]);
1677 //check if it exists
1678 $q = "SELECT `id` FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1679 $dbo->setQuery($q);
1680 $dbo->execute();
1681 if ($dbo->getNumRows() > 0) {
1682 if ($insvalue > 0) {
1683 //update
1684 $q = "UPDATE `#__vikbooking_adultsdiff` SET `chdisc`='".$inschdisc."', `valpcent`='".$insvalpcent."', `value`='".$insvalue."', `pernight`='".$inspernight."' WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1685 $dbo->setQuery($q);
1686 $dbo->execute();
1687 } else {
1688 //delete
1689 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1690 $dbo->setQuery($q);
1691 $dbo->execute();
1692 }
1693 } else {
1694 //insert
1695 $q = "INSERT INTO `#__vikbooking_adultsdiff` (`idroom`,`chdisc`,`valpcent`,`value`,`adults`,`pernight`) VALUES('".$oldroom['id']."', '".$inschdisc."', '".$insvalpcent."', '".$insvalue."', '".$adi."', '".$inspernight."');";
1696 $dbo->setQuery($q);
1697 $dbo->execute();
1698 }
1699 }
1700 }
1701 }
1702 }
1703 } else {
1704 //min and max adults num have changed, delete
1705 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."';";
1706 $dbo->setQuery($q);
1707 $dbo->execute();
1708 }
1709 if ($adchdisctouch == true) {
1710 $app->enqueueMessage(JText::translate('VBUPDROOMADCHDISCSAVED'));
1711 }
1712 //
1713 //check distinctive features if there were any changes
1714 $old_rparams = json_decode($oldroom['params'], true);
1715 $old_rparams = is_array($old_rparams) ? $old_rparams : array();
1716 if (array_key_exists('features', $old_rparams)) {
1717 $oldfeatures = array();
1718 foreach ($old_rparams['features'] as $rnumunit => $oldfeat) {
1719 foreach ($oldfeat as $featname => $featval) {
1720 $oldfeatures[$rnumunit][$featname] = $featval;
1721 break;
1722 }
1723 }
1724 /**
1725 * We reset the sub-unit information to all bookings only in case the new
1726 * number of units is reduced. When we add new units or we modify the contents,
1727 * we keep everything as is for the past reservations.
1728 *
1729 * @since 1.15.2 (J) - 1.5.5 (WP)
1730 */
1731 if ($oldfeatures != $newfeatures && count($newfeatures) < count($oldfeatures)) {
1732 // changes were made to the first index (Room Number by default) of the distinctive features
1733 // set to NULL all the already set roomindexes in bookings
1734 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=NULL WHERE `idroom`=".(int)$oldroom['id'].";";
1735 $dbo->setQuery($q);
1736 $dbo->execute();
1737 }
1738 }
1739 //
1740 $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).";";
1741 $dbo->setQuery($q);
1742 $dbo->execute();
1743
1744 /**
1745 * Share availability calendars with other rooms.
1746 *
1747 * @since 1.13
1748 */
1749 // always reset relations for this main room
1750 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$pwhereup};";
1751 $dbo->setQuery($q);
1752 $dbo->execute();
1753 $newxref = array();
1754 foreach ($pshare_with as $cldroom) {
1755 if (!empty($cldroom)) {
1756 array_push($newxref, (int)$cldroom);
1757 }
1758 }
1759 foreach ($newxref as $cldroom) {
1760 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$pwhereup}, {$cldroom});";
1761 $dbo->setQuery($q);
1762 $dbo->execute();
1763 }
1764
1765 /**
1766 * Room upgrade options.
1767 *
1768 * @since 1.16.0 (J) - 1.6.0 (WP)
1769 */
1770 $room_upgrade_options = [];
1771 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1772 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1773 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1774 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1775 $upgrade_rooms = array_map(function($rid) {
1776 return (int)$rid;
1777 }, $upgrade_rooms);
1778
1779 $room_upgrade_options = [
1780 'rooms' => $upgrade_rooms,
1781 'discount' => $upgrade_discount,
1782 ];
1783 }
1784 $config->set('room_upgrade_options_' . $pwhereup, json_encode($room_upgrade_options));
1785
1786 /**
1787 * Minimum advance booking offset can be defined at room-level (always in hours).
1788 *
1789 * @since 1.18.3 (J) - 1.8.3 (WP)
1790 */
1791 $pmin_adv_notice_room = VikRequest::getInt('min_adv_notice_room', 0, 'request');
1792 $pmindate = VikRequest::getInt('mindate', 0, 'request');
1793 if ($pmin_adv_notice_room && $pmindate >= 0) {
1794 // set value
1795 $config->set("room_{$pwhereup}_min_adv_notice", $pmindate);
1796 } else {
1797 // unset value
1798 $config->set("room_{$pwhereup}_min_adv_notice", null);
1799 }
1800
1801 /**
1802 * Maximum advance booking offset can be defined at room-level.
1803 *
1804 * @since 1.16.3 (J) - 1.6.3 (WP)
1805 */
1806 $pmax_adv_notice_room = VikRequest::getInt('max_adv_notice_room', 0, 'request');
1807 $pmaxdate = VikRequest::getInt('maxdate', 0, 'request');
1808 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
1809 $maxdate_str = '';
1810 if ($pmax_adv_notice_room && $pmaxdate > 0) {
1811 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
1812 $maxdate_str = '+' . $pmaxdate . $pmaxdateinterval;
1813 }
1814 $config->set("room_{$pwhereup}_max_adv_notice", $maxdate_str);
1815
1816 $app->enqueueMessage(JText::translate('VBUPDROOMOK'));
1817 }
1818
1819 if ($pupdatecaption == 1 || $stay === true) {
1820 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$pwhereup);
1821 } else {
1822 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1823 }
1824 }
1825
1826 public function modavail() {
1827 if (!JSession::checkToken() && !JSession::checkToken('get')) {
1828 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1829 }
1830 $cid = VikRequest::getVar('cid', array(0));
1831 $room = $cid[0];
1832 if (!empty($room)) {
1833 $dbo = JFactory::getDBO();
1834 $q = "SELECT `avail` FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($room).";";
1835 $dbo->setQuery($q);
1836 $dbo->execute();
1837 $get = $dbo->loadAssocList();
1838 $q = "UPDATE `#__vikbooking_rooms` SET `avail`='".(intval($get[0]['avail'])==1 ? 0 : 1)."' WHERE `id`=".$dbo->quote($room).";";
1839 $dbo->setQuery($q);
1840 $dbo->execute();
1841 }
1842 $mainframe = JFactory::getApplication();
1843 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1844 }
1845
1846 public function removeroom()
1847 {
1848 if (!JSession::checkToken()) {
1849 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1850 }
1851
1852 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
1853 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1854 }
1855
1856 $ids = VikRequest::getVar('cid', array(0));
1857 if (@count($ids)) {
1858 $dbo = JFactory::getDBO();
1859 foreach ($ids as $d) {
1860 $q = "DELETE FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($d).";";
1861 $dbo->setQuery($q);
1862 $dbo->execute();
1863 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idroom`=".$dbo->quote($d).";";
1864 $dbo->setQuery($q);
1865 $dbo->execute();
1866 }
1867 }
1868 $mainframe = JFactory::getApplication();
1869 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1870 }
1871
1872 public function tariffs() {
1873 VikBookingHelper::printHeader("fares");
1874
1875 VikRequest::setVar('view', VikRequest::getCmd('view', 'tariffs'));
1876
1877 parent::display();
1878
1879 if (VikBooking::showFooter()) {
1880 VikBookingHelper::printFooter();
1881 }
1882 }
1883
1884 public function removetariffs()
1885 {
1886 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
1887 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1888 }
1889
1890 $ids = VikRequest::getVar('cid', array(0));
1891 $proomid = VikRequest::getInt('roomid', '', 'request');
1892 if (@count($ids)) {
1893 $dbo = JFactory::getDBO();
1894 foreach ($ids as $r) {
1895 $x=explode(";", $r);
1896 foreach ($x as $rm) {
1897 if (!empty($rm)) {
1898 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `id`=".$dbo->quote($rm).";";
1899 $dbo->setQuery($q);
1900 $dbo->execute();
1901 }
1902 }
1903 }
1904 }
1905 $mainframe = JFactory::getApplication();
1906 $mainframe->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$proomid);
1907 }
1908
1909 public function editbusy() {
1910 VikBookingHelper::printHeader("8");
1911
1912 VikRequest::setVar('view', VikRequest::getCmd('view', 'editbusy'));
1913
1914 parent::display();
1915
1916 if (VikBooking::showFooter()) {
1917 VikBookingHelper::printFooter();
1918 }
1919 }
1920
1921 public function updatebusy()
1922 {
1923 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1924 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1925 }
1926
1927 $this->do_updatebusy();
1928 }
1929
1930 public function updatebusydoinv()
1931 {
1932 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
1933 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
1934 }
1935
1936 $this->do_updatebusy('geninvoices');
1937 }
1938
1939 private function do_updatebusy($callback = '')
1940 {
1941 $pidorder = VikRequest::getInt('idorder', 0, 'request');
1942 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
1943 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
1944 $pcheckinh = VikRequest::getString('checkinh', '', 'request');
1945 $pcheckinm = VikRequest::getString('checkinm', '', 'request');
1946 $pcheckouth = VikRequest::getString('checkouth', '', 'request');
1947 $pcheckoutm = VikRequest::getString('checkoutm', '', 'request');
1948 $pcustdata = VikRequest::getString('custdata', '', 'request');
1949 $pareprices = VikRequest::getString('areprices', '', 'request');
1950 $ptotpaid = VikRequest::getString('totpaid', '', 'request');
1951 $prefund = VikRequest::getString('refund', '', 'request');
1952 $pfrominv = VikRequest::getInt('frominv', '', 'request');
1953 $pvcm = VikRequest::getInt('vcm', '', 'request');
1954 $pgoto = VikRequest::getString('goto', '', 'request');
1955 $pextracn = VikRequest::getVar('extracn', []);
1956 $pextracc = VikRequest::getVar('extracc', []);
1957 $pextractx = VikRequest::getVar('extractx', []);
1958 /**
1959 * This is a "foreign key" integer value useful for other Vik plugins
1960 * to store custom extra services within a VBO reservation. Another
1961 * custom value "extra foreign data" (extracdata) is added. We also
1962 * support a "type" string useful for VCM to determine the type of service.
1963 *
1964 * @since 1.16.0 (J) - 1.6.0 (WP)
1965 * @since 1.16.1 (J) - 1.6.1 (WP) added the "type" string.
1966 */
1967 $pextractype = VikRequest::getVar('extractype', []);
1968 $pextracfk = VikRequest::getVar('extracfk', []);
1969 $pextracdata = VikRequest::getVar('extracdata', [], 'request', 'array', VIKREQUEST_ALLOWRAW);
1970
1971 $dbo = JFactory::getDbo();
1972 $user = JFactory::getUser();
1973 $app = JFactory::getApplication();
1974
1975 // availability helper
1976 $av_helper = VikBooking::getAvailabilityInstance();
1977
1978 $actnow = time();
1979 $nowdf = VikBooking::getDateFormat(true);
1980 if ($nowdf == "%d/%m/%Y") {
1981 $df = 'd/m/Y';
1982 } elseif ($nowdf == "%m/%d/%Y") {
1983 $df = 'm/d/Y';
1984 } else {
1985 $df = 'Y/m/d';
1986 }
1987
1988 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
1989 $dbo->setQuery($q, 0, 1);
1990 $ord = $dbo->loadAssoc();
1991 if (!$ord) {
1992 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1993 exit;
1994 }
1995
1996 $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;";
1997 $dbo->setQuery($q);
1998 $ordersrooms = $dbo->loadAssocList();
1999
2000 // do not touch this array property because it's used by VCM
2001 $ord['rooms_info'] = $ordersrooms;
2002
2003 // room stay dates in case of split stay
2004 $room_stay_dates = [];
2005 if ($ord['split_stay']) {
2006 if ($ord['status'] == 'confirmed') {
2007 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
2008 } else {
2009 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
2010 }
2011 // immediately count the number of nights of stay for each split room
2012 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
2013 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
2014 // overwrite values for compatibility with non-confirmed bookings
2015 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
2016 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
2017 }
2018 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
2019 // overwrite the whole array
2020 $room_stay_dates[$sps_r_k] = $sps_r_v;
2021 }
2022 }
2023
2024 // package or custom rate
2025 $is_package = !empty($ord['pkg']) ? true : false;
2026 $is_cust_cost = false;
2027 foreach ($ordersrooms as $kor => $or) {
2028 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
2029 $is_cust_cost = true;
2030 break;
2031 }
2032 }
2033
2034 // room switching
2035 $toswitch = array();
2036 $idbooked = array();
2037 $rooms_units = array();
2038
2039 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
2040 $dbo->setQuery($q);
2041 $all_rooms = $dbo->loadAssocList();
2042 foreach ($all_rooms as $rr) {
2043 $rooms_units[$rr['id']]['name'] = $rr['name'];
2044 $rooms_units[$rr['id']]['units'] = $rr['units'];
2045 }
2046
2047 foreach ($ordersrooms as $ind => $or) {
2048 $switch_command = VikRequest::getString('switch_'.$or['id'], '', 'request');
2049 if (!empty($switch_command) && intval($switch_command) != $or['idroom'] && array_key_exists(intval($switch_command), $rooms_units)) {
2050 if (!isset($idbooked[$or['idroom']])) {
2051 $idbooked[$or['idroom']] = 0;
2052 }
2053 $idbooked[$or['idroom']]++;
2054 $orkey = count($toswitch);
2055 $toswitch[$orkey]['from'] = $or['idroom'];
2056 $toswitch[$orkey]['to'] = intval($switch_command);
2057 $toswitch[$orkey]['record'] = $or;
2058 $toswitch[$orkey]['record_ind'] = $ind;
2059 }
2060 }
2061
2062 if (count($toswitch) && (!empty($ordersrooms[0]['idtar']) || $is_package || $is_cust_cost)) {
2063 foreach ($toswitch as $ksw => $rsw) {
2064 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
2065 $room_checkin = $ord['checkin'];
2066 $room_checkout = $ord['checkout'];
2067 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
2068 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
2069 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
2070 }
2071 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
2072 // the room is not available
2073 unset($toswitch[$ksw]);
2074 VikError::raiseWarning('', JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
2075 }
2076 }
2077 if (count($toswitch)) {
2078 // reset first record rate
2079 reset($ordersrooms);
2080 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
2081 $dbo->setQuery($q);
2082 $dbo->execute();
2083
2084 // flag for invoking VCM at a proper time
2085 $vcm_should_run = false;
2086
2087 foreach ($toswitch as $ksw => $rsw) {
2088 // update room reservation record
2089 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=".$rsw['to'].",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$rsw['record']['id'].";";
2090 $dbo->setQuery($q);
2091 $dbo->execute();
2092 $app->enqueueMessage(JText::sprintf('VBSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
2093
2094 // update Notes field for this booking to keep track of the previous room that was assigned
2095 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
2096 if (!empty($prev_room_name)) {
2097 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
2098 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
2099 $dbo->setQuery($q);
2100 $dbo->execute();
2101 }
2102
2103 if ($ord['status'] == 'confirmed') {
2104 // update room record in _busy
2105 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'])) {
2106 // in case of a split stay it is fundamental to update the exact busy record ID
2107 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
2108 $dbo->setQuery($q);
2109 $dbo->execute();
2110 } else {
2111 // regular processing of a room ID for a reservation, no matter which one, we switch it
2112 $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'];
2113 $dbo->setQuery($q, 0, 1);
2114 $cur_busy = $dbo->loadAssoc();
2115 if ($cur_busy) {
2116 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy['id']." AND `idroom`=".$cur_busy['idroom']." LIMIT 1;";
2117 $dbo->setQuery($q);
2118 $dbo->execute();
2119 }
2120 }
2121
2122 /**
2123 * Make sure to take care of the shared calendars before invoking VCM.
2124 * Register the flag to run the Channel Manager and leave the booking
2125 * array unchanged to run just one update request.
2126 *
2127 * @since 1.16.0 (J) - 1.6.0 (WP)
2128 */
2129 $vcm_should_run = true;
2130
2131 } elseif ($ord['status'] == 'standby') {
2132 // remove record in _tmplock
2133 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
2134 $dbo->setQuery($q);
2135 $dbo->execute();
2136 // check if it's a split stay
2137 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
2138 // update room ID in split stay data
2139 $room_stay_dates[$rsw['record_ind']]['idroom'] = $rsw['to'];
2140 // update configuration record
2141 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($room_stay_dates));
2142 }
2143 }
2144 }
2145
2146 // unset any previously booked room due to calendar sharing
2147 VikBooking::cleanSharedCalendarsBusy($ord['id']);
2148 // check if some of the rooms booked have shared calendars
2149 VikBooking::updateSharedCalendars($ord['id']);
2150
2151 if ($vcm_should_run) {
2152 // we can now run the Channel Manager after having updated the shared calendars
2153 $vcm_autosync = VikBooking::vcmAutoUpdate();
2154 if ($vcm_autosync > 0) {
2155 $vcm_obj = VikBooking::getVcmInvoker();
2156 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2157 $sync_result = $vcm_obj->doSync();
2158 if ($sync_result === false) {
2159 $vcm_err = $vcm_obj->getError();
2160 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2161 }
2162 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2163 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>');
2164 }
2165 }
2166
2167 //Booking History
2168 VikBooking::getBookingHistoryInstance($ord['id'])->setPrevBooking($ord)->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
2169 //
2170 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2171 exit;
2172 }
2173 }
2174
2175 // update booking data
2176 $first = VikBooking::getDateTimestamp($pcheckindate, $pcheckinh, $pcheckinm);
2177 $second = VikBooking::getDateTimestamp($pcheckoutdate, $pcheckouth, $pcheckoutm);
2178 if ($second <= $first) {
2179 VikError::raiseWarning('', JText::translate('ERRPREV'));
2180 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2181 exit;
2182 }
2183
2184 $secdiff = $second - $first;
2185 $daysdiff = $secdiff / 86400;
2186 if (is_int($daysdiff)) {
2187 if ($daysdiff < 1) {
2188 $daysdiff = 1;
2189 }
2190 } else {
2191 if ($daysdiff < 1) {
2192 $daysdiff = 1;
2193 } else {
2194 $sum = floor($daysdiff) * 86400;
2195 $newdiff = $secdiff - $sum;
2196 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
2197 if ($maxhmore >= $newdiff) {
2198 $daysdiff = floor($daysdiff);
2199 } else {
2200 $daysdiff = ceil($daysdiff);
2201 }
2202 }
2203 }
2204
2205 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
2206 $opertwounits = true;
2207
2208 $units_counter = array();
2209 $prm_room_oid = VikRequest::getInt('rm_room_oid', 0, 'request');
2210 foreach ($ordersrooms as $ind => $or) {
2211 if (!isset($units_counter[$or['idroom']])) {
2212 $units_counter[$or['idroom']] = -1;
2213 }
2214 if ($prm_room_oid != $or['id']) {
2215 $units_counter[$or['idroom']]++;
2216 }
2217 }
2218
2219 /**
2220 * Split stay data for booking and rooms different stay dates.
2221 *
2222 * @since 1.16.0 (J) - 1.6.0 (WP)
2223 */
2224 $split_stay_data = VikRequest::getVar('split_stay_data', array());
2225 $room_modify_dates = VikRequest::getVar('room_modify_dates', array());
2226 $split_stay_checkins = [];
2227 $split_stay_checkouts = [];
2228
2229 if ($ord['split_stay'] && !empty($split_stay_data)) {
2230 // make sure the min/max split stay dates match the booking global dates
2231 foreach ($split_stay_data as $sps_k => $split_stay) {
2232 if (empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2233 continue;
2234 }
2235 $new_room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2236 $new_room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2237 $split_stay_checkins[] = $new_room_checkin;
2238 $split_stay_checkouts[] = $new_room_checkout;
2239 if (isset($room_stay_dates[$sps_k])) {
2240 $room_stay_dates[$sps_k]['new_checkin'] = $new_room_checkin;
2241 $room_stay_dates[$sps_k]['new_checkout'] = $new_room_checkout;
2242 $room_stay_dates[$sps_k]['new_nights'] = $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout);
2243 }
2244 }
2245 if (empty($split_stay_checkins) || empty($split_stay_checkouts)) {
2246 // error
2247 VikError::raiseWarning('', 'Error, split stay rooms must have their own stay dates matching the booking check-in and check-out dates');
2248 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2249 exit;
2250 }
2251 if (min($split_stay_checkins) != $first) {
2252 // error
2253 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)));
2254 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2255 exit;
2256 }
2257 if (max($split_stay_checkouts) != $second) {
2258 // error
2259 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)));
2260 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2261 exit;
2262 }
2263 }
2264
2265 /**
2266 * We need to make sure the sub-units of the rooms involved are not being overbooked.
2267 * In this case, we simply raise an error message by not stopping the process.
2268 *
2269 * @since 1.13.0 (J) - 1.3.0 (WP)
2270 */
2271 $subunits_involved_bids = array();
2272 //
2273
2274 foreach ($ordersrooms as $ind => $or) {
2275 $num = $ind + 1;
2276 $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'] . ";";
2277 $dbo->setQuery($check);
2278 $busy = $dbo->loadAssocList();
2279 if ($busy) {
2280 // determine the days to consider for the count of the availability
2281 $use_groupdays = $groupdays;
2282 $room_checkin = $first;
2283 $room_checkout = $second;
2284 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'])) {
2285 $use_groupdays = VikBooking::getGroupDays($room_stay_dates[$ind]['new_checkin'], $room_stay_dates[$ind]['new_checkout'], $room_stay_dates[$ind]['new_nights']);
2286 $room_checkin = $room_stay_dates[$ind]['new_checkin'];
2287 $room_checkout = $room_stay_dates[$ind]['new_checkout'];
2288 } elseif (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1 && $ord['status'] == 'confirmed' && VikRequest::getInt('room_modify_dates' . $ind, 0, 'request')) {
2289 // room may have individual stay dates
2290 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2291 // get new stay dates (if changed)
2292 $new_room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2293 $new_room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2294 $new_room_staynights = $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout);
2295 $use_groupdays = VikBooking::getGroupDays($new_room_checkin, $new_room_checkout, $new_room_staynights);
2296 $room_checkin = $new_room_checkin;
2297 $room_checkout = $new_room_checkout;
2298 // inject room stay nights and timestamps
2299 $room_modify_dates[$ind]['stay_nights'] = $new_room_staynights;
2300 $room_modify_dates[$ind]['checkin_ts'] = $new_room_checkin;
2301 $room_modify_dates[$ind]['checkout_ts'] = $new_room_checkout;
2302 }
2303 }
2304
2305 foreach ($use_groupdays as $gday) {
2306 // count units booked for each stay timestamp
2307 $bfound = 0;
2308 foreach ($busy as $bu) {
2309 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
2310 // increase units booked found
2311 $bfound++;
2312 // keep track of the IDs involved to avoid overbooking for the sub-units
2313 if (!empty($or['roomindex'])) {
2314 if (!isset($subunits_involved_bids[$bu['idorder']])) {
2315 $subunits_involved_bids[$bu['idorder']] = array();
2316 }
2317 array_push($subunits_involved_bids[$bu['idorder']], array(
2318 'idroom' => $or['idroom'],
2319 'roomindex' => $or['roomindex'],
2320 ));
2321 }
2322 }
2323 }
2324
2325 // units booked must be greater than zero in case of split stays involving the same room multiple times
2326 $detract_multi_units = $units_counter[$or['idroom']];
2327 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
2328 // split stay bookings never occupy the same room on the same dates
2329 $detract_multi_units = 0;
2330 }
2331 if ($bfound > 0 && $bfound >= ($or['units'] - $detract_multi_units)) {
2332 $opertwounits = false;
2333 break 2;
2334 }
2335
2336 // make sure the room is not temporarily locked while waiting to be paid/confirmed
2337 if ($ord['status'] == 'confirmed' && !VikBooking::roomNotLocked($or['idroom'], $or['units'], $room_checkin, $room_checkout)) {
2338 $opertwounits = false;
2339 break 2;
2340 }
2341 }
2342 }
2343 }
2344
2345 /**
2346 * Make sure no sub-units are overbooked even though the main room is available.
2347 *
2348 * @since 1.13.0 (J) - 1.3.0 (WP)
2349 */
2350 if ($opertwounits === true && $subunits_involved_bids) {
2351 $subunits_involved_bids = array_unique($subunits_involved_bids);
2352 // grab all the information about the bids involved and the related rooms/indexes
2353 $q = "SELECT `or`.`idorder`, `or`.`idroom`, `or`.`roomindex`
2354 FROM `#__vikbooking_ordersrooms` AS `or`
2355 WHERE `or`.`idorder` IN (" . implode(', ', array_keys($subunits_involved_bids)) . ");";
2356 $dbo->setQuery($q);
2357 $involved_data = $dbo->loadAssocList();
2358 foreach ($involved_data as $invb) {
2359 if (empty($invb['roomindex'])) {
2360 continue;
2361 }
2362 foreach ($subunits_involved_bids[$invb['idorder']] as $bookedindex) {
2363 if ($bookedindex['idroom'] == $invb['idroom'] && $bookedindex['roomindex'] == $invb['roomindex']) {
2364 // this same sub-unit is occupied by this booking ID: raise an error message to inform the administrator
2365 $involved_booking = VikBooking::getBookingInfoFromID($invb['idorder']);
2366 $involved_room = VikBooking::getRoomInfo($invb['idroom'], ['name', 'params'], $no_cache = true);
2367 $subunit_name = $invb['roomindex'];
2368 $room_params = (array) json_decode($involved_room['params'] ?? '[]', true);
2369 foreach (($room_params['features'] ?? []) as $rind => $rfeatures) {
2370 if ($rind == $invb['roomindex']) {
2371 foreach ($rfeatures as $fname => $fval) {
2372 if (strlen($fval)) {
2373 $subunit_name = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
2374 break;
2375 }
2376 }
2377 }
2378 }
2379 $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>';
2380 $app->enqueueMessage(
2381 JText::sprintf(
2382 'VBOSUBUNITOVERBOOKEDERR',
2383 $subunit_name,
2384 $involved_room['name'] ?? $invb['idroom'],
2385 date($df, $involved_booking['checkin'] ?? 0),
2386 date($df, $involved_booking['checkout'] ?? 0),
2387 $invb['idorder']
2388 ) . $adjust_link,
2389 'error'
2390 );
2391 }
2392 }
2393 }
2394 }
2395
2396 $forcebooking = VikRequest::getInt('forcebooking', 0, 'request');
2397 if ($opertwounits === true || $forcebooking) {
2398 // update dates, customer information, amount paid and busy records before checking the rates
2399 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
2400 $realback = $turnover_secs + $second;
2401
2402 $newtotalpaid = strlen($ptotpaid) > 0 ? floatval($ptotpaid) : "";
2403 $newrefund = strlen($prefund) > 0 ? floatval($prefund) : null;
2404 $roomsnum = $ord['roomsnum'];
2405
2406 // add room to existing booking
2407 $room_added = false;
2408 $padd_room_id = VikRequest::getInt('add_room_id', '', 'request');
2409 $padd_room_adults = VikRequest::getInt('add_room_adults', 2, 'request');
2410 $padd_room_children = VikRequest::getInt('add_room_children', 0, 'request');
2411 $padd_room_fname = VikRequest::getString('add_room_fname', '', 'request');
2412 $padd_room_lname = VikRequest::getString('add_room_lname', '', 'request');
2413 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2414 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2415 if ($padd_room_id > 0 && ($padd_room_adults + $padd_room_children) > 0) {
2416 // no need to re-validate the availability for this new room, as it was made via JS in the View.
2417 // increase the rooms number for later update, and insert the new room record
2418 $roomsnum++;
2419 $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').");";
2420 $dbo->setQuery($q);
2421 $dbo->execute();
2422 $room_added = true;
2423 }
2424
2425 // remove room from existing booking
2426 $room_removed = false;
2427 $room_removed_index = null;
2428 if ($prm_room_oid > 0 && $roomsnum > 1) {
2429 // check if the requested room record exists for removal
2430 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id'].";";
2431 $dbo->setQuery($q);
2432 $room_before_rm = $dbo->loadAssoc();
2433 if ($room_before_rm) {
2434 // decrease the rooms number for later update, and remove the requested room record
2435 $roomsnum--;
2436 // find the index of this room in the current list before removal
2437 foreach ($ordersrooms as $kor => $or) {
2438 if ($or['id'] == $prm_room_oid) {
2439 $room_removed_index = $kor;
2440 break;
2441 }
2442 }
2443 // go ahead with the deletion of the room record
2444 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id']." LIMIT 1;";
2445 $dbo->setQuery($q);
2446 $dbo->execute();
2447 $room_removed = $room_before_rm['idroom'];
2448 }
2449 }
2450
2451 if ($ord['split_stay'] && !empty($split_stay_data) && count($split_stay_checkins) && ($room_added !== false || $room_removed !== false)) {
2452 // split stay booking (even if only 1 room left) and one room was either added or removed: set new global stay dates
2453 if ($room_removed !== false && isset($room_removed_index) && isset($split_stay_checkins[$room_removed_index])) {
2454 // exclude the split stay dates of this room that was just removed
2455 unset($split_stay_checkins[$room_removed_index], $split_stay_checkouts[$room_removed_index]);
2456 }
2457 if (count($split_stay_checkins) && count($split_stay_checkouts)) {
2458 // if we still have rooms, and we should, update the booking global stay dates
2459 $first = min($split_stay_checkins);
2460 $second = max($split_stay_checkouts);
2461 $daysdiff = $av_helper->countNightsOfStay($first, $second);
2462 }
2463 }
2464
2465 // update booking's basic information (customer data, dates, tot paid, number of rooms, refund)
2466 $basic_booking = new stdClass;
2467 $basic_booking->id = $ord['id'];
2468 $basic_booking->custdata = $pcustdata;
2469 $basic_booking->days = (int)$daysdiff;
2470 $basic_booking->checkin = $first;
2471 $basic_booking->checkout = $second;
2472 if (strlen($newtotalpaid) > 0) {
2473 $basic_booking->totpaid = $newtotalpaid;
2474 }
2475 $basic_booking->roomsnum = (int)$roomsnum;
2476 if ($newrefund !== null) {
2477 $basic_booking->refund = $newrefund;
2478 }
2479 if ($ord['split_stay'] && $roomsnum < 2 && $room_removed !== false) {
2480 // there is no point in keep treating this reservation as a split stay
2481 $basic_booking->split_stay = 0;
2482 }
2483 $dbo->updateObject('#__vikbooking_orders', $basic_booking, 'id');
2484
2485 // Booking History log for new amount paid (payment update)
2486 if ($newtotalpaid > 0 && $newtotalpaid > (float)$ord['totpaid']) {
2487 $extra_data = new stdClass;
2488 $extra_data->amount_paid = ($newtotalpaid - (float)$ord['totpaid']);
2489 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$ord['totpaid'])));
2490 }
2491
2492 // booking history log for new refund amount
2493 if ($newrefund !== null && $newrefund != (float)$ord['refund']) {
2494 // update current refund value
2495 $ord['refund'] = $newrefund;
2496 // store event
2497 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData(null)->store('RU', JText::sprintf('VBO_NEWREFUND_AMOUNT', VikBooking::numberFormat($ord['refund']), VikBooking::numberFormat($newrefund)));
2498 }
2499
2500 // update busy records
2501 if ($ord['status'] == 'confirmed') {
2502 $allbusy = [];
2503 if ($ord['split_stay'] && !empty($split_stay_data)) {
2504 // in case of split stay we need to update the busy records according to the nights selected
2505 foreach ($split_stay_data as $sps_k => $split_stay) {
2506 if (empty($split_stay['idbusy']) || empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2507 // missing data
2508 continue;
2509 }
2510 // get selected dates
2511 $room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2512 $room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2513 $room_realback = $turnover_secs + $room_checkout;
2514 // update the exact record
2515 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$split_stay['idbusy'] . ";";
2516 $dbo->setQuery($q);
2517 $dbo->execute();
2518 }
2519 } else {
2520 // regularly update busy records for all rooms involved
2521 $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'] . ";";
2522 $dbo->setQuery($q);
2523 $allbusy = $dbo->loadAssocList();
2524
2525 foreach ($allbusy as $bb) {
2526 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $first . ", `checkout`=" . $second . ", `realback`=" . $realback . " WHERE `id`=" . $bb['id'] . ";";
2527 $dbo->setQuery($q);
2528 $dbo->execute();
2529 }
2530
2531 if (!$allbusy) {
2532 /**
2533 * If no existing busy records were fetched, it means we have some missing or broken
2534 * records in the database. Proceed with restoring them to occupy the room(s).
2535 *
2536 * @since 1.8.19 (J) - 1.8.9 (WP)
2537 */
2538 $dbo->setQuery(
2539 $dbo->getQuery(true)
2540 ->delete($dbo->qn('#__vikbooking_ordersbusy'))
2541 ->where($dbo->qn('idorder') . ' = ' . (int) $ord['id'])
2542 );
2543 $dbo->execute();
2544 foreach ($ordersrooms as $or) {
2545 if ($room_removed !== false && $or['id'] == $prm_room_oid) {
2546 continue;
2547 }
2548 $restoreBusyRecord = (object) [
2549 'idroom' => $or['idroom'],
2550 'checkin' => $first,
2551 'checkout' => $second,
2552 'realback' => $realback,
2553 ];
2554 $dbo->insertObject('#__vikbooking_busy', $restoreBusyRecord, 'id');
2555 if (!empty($restoreBusyRecord->id)) {
2556 $restoreBusyRelation = (object) [
2557 'idorder' => $ord['id'],
2558 'idbusy' => $restoreBusyRecord->id,
2559 ];
2560 $dbo->insertObject('#__vikbooking_ordersbusy', $restoreBusyRelation, 'id');
2561 }
2562 }
2563 }
2564 }
2565
2566 /**
2567 * Check if some rooms have modified stay dates different than the booking stay dates.
2568 *
2569 * @since 1.16.0 (J) - 1.6.0 (WP)
2570 */
2571 if (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1) {
2572 // load the occupied stay dates for each room in case they were modified
2573 $room_stay_records = $av_helper->loadSplitStayBusyRecords($ord['id']);
2574 // loop over all rooms to check the requested operations
2575 foreach ($ordersrooms as $ind => $or) {
2576 if (!VikRequest::getInt('room_modify_dates' . $ind, 0, 'request') || !isset($room_stay_records[$ind]) || empty($room_stay_records[$ind]['id'])) {
2577 // toggle is disabled or data is missing
2578 continue;
2579 }
2580 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2581 // calculate the check-in and check-out timestamps, we expect them to be different from the global booking dates
2582 $room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2583 $room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2584 $room_realback = $turnover_secs + $room_checkout;
2585 // we don't need to check if the dates are different, we just update the record
2586 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$room_stay_records[$ind]['id'] . ";";
2587 $dbo->setQuery($q);
2588 $dbo->execute();
2589 // inject new room stay timestamps
2590 $ordersrooms[$ind]['modified_checkin'] = $room_checkin;
2591 $ordersrooms[$ind]['modified_checkout'] = $room_checkout;
2592 }
2593 }
2594 }
2595
2596 // add room to existing (confirmed) booking
2597 if ($room_added === true) {
2598 // add busy record for the new room unit
2599 $q = "INSERT INTO `#__vikbooking_busy` (`idroom`,`checkin`,`checkout`,`realback`) VALUES(".$padd_room_id.", ".$dbo->quote($first).", ".$dbo->quote($second).", ".$dbo->quote($realback).");";
2600 $dbo->setQuery($q);
2601 $dbo->execute();
2602 $newbusyid = $dbo->insertid();
2603 $q = "INSERT INTO `#__vikbooking_ordersbusy` (`idorder`,`idbusy`) VALUES(".$ord['id'].", ".(int)$newbusyid.");";
2604 $dbo->setQuery($q);
2605 $dbo->execute();
2606 }
2607
2608 // remove room from existing (confirmed) booking
2609 if ($room_removed !== false) {
2610 // remove busy record for the removed room
2611 if ($ord['split_stay'] && !empty($split_stay_data) && !empty($room_removed_index)) {
2612 // in case of split stay we want to remove the exact dates of the previously booked room
2613 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'])) {
2614 // remove the exact records
2615 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=" . $room_stay_dates[$room_removed_index]['id'] . " AND `idroom`=" . $room_removed . ";";
2616 $dbo->setQuery($q);
2617 $dbo->execute();
2618 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=" . $ord['id'] . " AND `idbusy`=" . $room_stay_dates[$room_removed_index]['id'] . ";";
2619 $dbo->setQuery($q);
2620 $dbo->execute();
2621 }
2622 } else {
2623 // regularly remove the first matching room
2624 foreach ($allbusy as $bb) {
2625 if ($bb['idroom'] == $room_removed) {
2626 // remove the first room with this ID that was booked
2627 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=".$bb['id']." AND `idroom`=".$room_removed.";";
2628 $dbo->setQuery($q);
2629 $dbo->execute();
2630 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".$ord['id']." AND `idbusy`=".$bb['id'].";";
2631 $dbo->setQuery($q);
2632 $dbo->execute();
2633 break;
2634 }
2635 }
2636 }
2637 }
2638
2639 if ($ord['checkin'] != $first || $ord['checkout'] != $second || $room_added === true || $room_removed !== false) {
2640 // unset any previously booked room due to calendar sharing
2641 VikBooking::cleanSharedCalendarsBusy($ord['id']);
2642 // check if some of the rooms booked have shared calendars
2643 VikBooking::updateSharedCalendars($ord['id'], array(), $first, $second);
2644
2645 // invoke Channel Manager
2646 $vcm_autosync = VikBooking::vcmAutoUpdate();
2647 if ($vcm_autosync > 0) {
2648 $vcm_obj = VikBooking::getVcmInvoker();
2649 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2650 $sync_result = $vcm_obj->doSync();
2651 if ($sync_result === false) {
2652 $vcm_err = $vcm_obj->getError();
2653 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2654 }
2655 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2656 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>');
2657 }
2658 //
2659 }
2660 }
2661
2662 $upd_esit = JText::translate('RESUPDATED');
2663
2664 // update the room rates
2665 $isdue = 0;
2666 $tot_taxes = 0;
2667 $tot_city_taxes = 0;
2668 $tot_fees = 0;
2669 $tot_damage_dep = 0;
2670 $doup = true;
2671 $tars = array();
2672 $cust_costs = array();
2673 $rooms_costs_map = array();
2674 $arrpeople = array();
2675 foreach ($ordersrooms as $kor => $or) {
2676 // remove from existing booking
2677 if ($room_removed !== false) {
2678 if ($or['id'] == $prm_room_oid) {
2679 // do not consider this room for the calculation of the new total amount
2680 // we can unset this array for later use, because the channel manager has already been invoked.
2681 unset($ordersrooms[$kor]);
2682 continue;
2683 }
2684 }
2685
2686 // room index starting from 1
2687 $num = $kor + 1;
2688
2689 // default values to be considered
2690 $room_nights = $daysdiff;
2691 $room_checkin = $ord['checkin'];
2692 $room_checkout = $ord['checkout'];
2693 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'])) {
2694 // overwrite default values in case of split-stay booking
2695 $room_nights = $room_stay_dates[$kor]['new_nights'];
2696 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2697 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2698 } elseif (!$ord['split_stay'] && ($room_modify_dates[$kor]['checkin_ts'] ?? null)) {
2699 // overwrite default values in case of multi-room reservation with different stay dates
2700 $room_nights = $room_modify_dates[$kor]['stay_nights'] ?? $room_nights;
2701 $room_checkin = $room_modify_dates[$kor]['checkin_ts'];
2702 $room_checkout = $room_modify_dates[$kor]['checkout_ts'];
2703 }
2704
2705 $padults = VikRequest::getString('adults' . $num, '', 'request');
2706 $pchildren = VikRequest::getString('children' . $num, '', 'request');
2707 $ppets = VikRequest::getInt('pets' . $num, 0, 'request');
2708 if (strlen($padults) || strlen($pchildren)) {
2709 $arrpeople[$num]['adults'] = (int)$padults;
2710 $arrpeople[$num]['children'] = (int)$pchildren;
2711 $arrpeople[$num]['pets'] = $ppets;
2712 }
2713 $ppriceid = VikRequest::getString('priceid'.$num, '', 'request');
2714 $polderpriceid = VikRequest::getString('olderpriceid'.$num, '', 'request');
2715 $ppkgid = VikRequest::getString('pkgid'.$num, '', 'request');
2716 $pcust_cost = VikRequest::getString('cust_cost'.$num, '', 'request');
2717 $paliq = VikRequest::getString('aliq'.$num, '', 'request');
2718 $pcust_cpolicy_id = VikRequest::getInt('cust_cpolicy_id'.$num, 0, 'request');
2719 if ($is_package === true && !empty($ppkgid)) {
2720 $pkg_cost = $or['cust_cost'];
2721 $pkg_idiva = $or['cust_idiva'];
2722 $pkg_info = VikBooking::getPackage($ppkgid);
2723 if (is_array($pkg_info) && count($pkg_info) > 0) {
2724 $use_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : $or['adults'];
2725 $pkg_cost = $pkg_info['pernight_total'] == 1 ? ($pkg_info['cost'] * $room_nights) : $pkg_info['cost'];
2726 $pkg_cost = $pkg_info['perperson'] == 1 ? ($pkg_cost * ($use_adults > 0 ? $use_adults : 1)) : $pkg_cost;
2727 $pkg_cost = VikBooking::sayPackagePlusIva($pkg_cost, $pkg_info['idiva']);
2728 }
2729 $cust_costs[$num] = array('pkgid' => $ppkgid, 'cust_cost' => $pkg_cost, 'aliq' => $pkg_idiva);
2730 $isdue += $pkg_cost;
2731 $cost_minus_tax = VikBooking::sayPackageMinusIva($pkg_cost, $pkg_idiva);
2732 $tot_taxes += ($pkg_cost - $cost_minus_tax);
2733 continue;
2734 }
2735 if (empty($ppriceid) && !empty($pcust_cost) && floatval($pcust_cost) > 0) {
2736 $cust_costs[$num] = [
2737 'cust_cost' => $pcust_cost,
2738 'aliq' => $paliq,
2739 'cust_cpolicy_id' => $pcust_cpolicy_id,
2740 ];
2741 $cost_after_tax = VikBooking::sayPackagePlusIva((float)$pcust_cost, (int)$paliq);
2742 $isdue += $cost_after_tax;
2743 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$pcust_cost, (int)$paliq);
2744 $tot_taxes += ($cost_after_tax - $cost_minus_tax);
2745 continue;
2746 }
2747
2748 // load room rates for the requested rate plan and nights
2749 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `idroom`=" . (int)$or['idroom'] . " AND `days`=" . $room_nights . " AND `idprice`=" . (int)$ppriceid . ";";
2750 $dbo->setQuery($q);
2751 $tar = $dbo->loadAssocList();
2752 if (!$tar) {
2753 $doup = false;
2754 break;
2755 }
2756
2757 /**
2758 * The current price may be different from the price paid at the time of booking.
2759 * Check whether it has been asked to keep the old price of the time of booking.
2760 *
2761 * @since 1.13.0 (J) - 1.3.0 (WP)
2762 */
2763 $old_price_used = false;
2764 if (!empty($polderpriceid)) {
2765 $older_info = explode(':', $polderpriceid);
2766 if ((int)$older_info[0] == (int)$ppriceid) {
2767 $old_price = isset($older_info[1]) ? (float)$older_info[1] : 0;
2768 if ($old_price > 0) {
2769 // we override the 'cost' property of the tar array by taking the previous cost
2770 $old_price_used = true;
2771 $tar[0]['cost'] = $old_price;
2772 }
2773 }
2774 }
2775
2776 if (!$old_price_used) {
2777 // apply seasonal rates
2778 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
2779 }
2780
2781 // different usage
2782 if (!$old_price_used && $or['fromadult'] <= $or['adults'] && $or['toadult'] >= $or['adults']) {
2783 // apply OBP rules
2784 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
2785 }
2786
2787 $cost_plus_tax = VikBooking::sayCostPlusIva($tar[0]['cost'], $tar[0]['idprice']);
2788 $isdue += $cost_plus_tax;
2789 if ($cost_plus_tax == $tar[0]['cost']) {
2790 $cost_minus_tax = VikBooking::sayCostMinusIva($tar[0]['cost'], $tar[0]['idprice']);
2791 $tot_taxes += ($tar[0]['cost'] - $cost_minus_tax);
2792 } else {
2793 $tot_taxes += ($cost_plus_tax - $tar[0]['cost']);
2794 }
2795 $tars[$num] = $tar;
2796 $rooms_costs_map[$num] = $tar[0]['cost'];
2797 }
2798
2799 if ($doup === true) {
2800 if ($room_added === true) {
2801 // add room to existing booking may require to increase the total amount, and taxes
2802 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2803 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2804 if (!empty($padd_room_price) && floatval($padd_room_price) > 0) {
2805 $isdue += (float)$padd_room_price;
2806 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$padd_room_price, (int)$paliq_add_room);
2807 $tot_taxes += ((float)$padd_room_price - $cost_minus_tax);
2808 }
2809 }
2810
2811 // load options
2812 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
2813 $dbo->setQuery($q);
2814 $toptionals = $dbo->loadAssocList();
2815
2816 foreach ($ordersrooms as $kor => $or) {
2817 $num = $kor + 1;
2818
2819 // default values to be considered
2820 $room_nights = $daysdiff;
2821 $room_checkin = $ord['checkin'];
2822 $room_checkout = $ord['checkout'];
2823 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'])) {
2824 // overwrite default values in case of split-stay booking
2825 $room_nights = $room_stay_dates[$kor]['new_nights'];
2826 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2827 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2828 } elseif (!$ord['split_stay'] && ($room_modify_dates[$kor]['checkin_ts'] ?? null)) {
2829 // overwrite default values in case of multi-room reservation with different stay dates
2830 $room_nights = $room_modify_dates[$kor]['stay_nights'] ?? $room_nights;
2831 $room_checkin = $room_modify_dates[$kor]['checkin_ts'];
2832 $room_checkout = $room_modify_dates[$kor]['checkout_ts'];
2833 }
2834
2835 $pt_first_name = VikRequest::getString('t_first_name'.$num, '', 'request');
2836 $pt_last_name = VikRequest::getString('t_last_name'.$num, '', 'request');
2837 $wop = "";
2838
2839 foreach ($toptionals as $opt) {
2840 // option params
2841 $opt_params = !empty($opt['oparams']) ? json_decode($opt['oparams'], true) : [];
2842 $opt_params = is_array($opt_params) ? $opt_params : [];
2843 if (!empty($opt['ageintervals']) && ($or['children'] > 0 || isset($arrpeople[$num]['children']))) {
2844 $tmpvar = VikRequest::getInt('optid'.$num.$opt['id'], []);
2845 if (is_array($tmpvar) && $tmpvar && ($arrpeople[$num]['children'] ?? 0)) {
2846 $opt['quan'] = 1;
2847 $optagenames = VikBooking::getOptionIntervalsAges($opt['ageintervals']);
2848 $optagepcent = VikBooking::getOptionIntervalsPercentage($opt['ageintervals']);
2849 $optageovrct = VikBooking::getOptionIntervalChildOverrides($opt, (isset($arrpeople[$num]) ? $arrpeople[$num]['adults'] : 0), (isset($arrpeople[$num]) ? $arrpeople[$num]['children'] : 0));
2850 $optorigname = $opt['name'];
2851 foreach ($tmpvar as $child_num => $chvar) {
2852 $ageintervals_child_string = isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $opt['ageintervals'];
2853 $optagecosts = VikBooking::getOptionIntervalsCosts($ageintervals_child_string);
2854 $optorigcost = $optagecosts[($chvar - 1)];
2855 $tmp_room_cost = 0;
2856 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
2857 // percentage value of the adults tariff
2858 if ($is_package !== true && array_key_exists($num, $tars)) {
2859 // type of price
2860 $tmp_room_cost = $tars[$num][0]['cost'];
2861 $optorigcost = $tars[$num][0]['cost'] * $optagecosts[($chvar - 1)] / 100;
2862 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2863 // package
2864 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2865 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2866 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2867 // custom rate + custom tax rate
2868 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2869 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2870 }
2871 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
2872 // percentage value of room base cost
2873 if ($is_package !== true && array_key_exists($num, $tars)) {
2874 // type of price
2875 $usecost = isset($tars[$num][0]['room_base_cost']) ? $tars[$num][0]['room_base_cost'] : $tars[$num][0]['cost'];
2876 $tmp_room_cost = $usecost;
2877 $optorigcost = $usecost * $optagecosts[($chvar - 1)] / 100;
2878 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2879 // package
2880 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2881 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2882 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2883 // custom rate + custom tax rate
2884 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2885 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2886 }
2887 }
2888 $opt['cost'] = $optorigcost;
2889 $opt['name'] = $optorigname.' ('.$optagenames[($chvar - 1)].')';
2890 $opt['chageintv'] = $chvar;
2891 $wop.=$opt['id'].":".$opt['quan']."-".$chvar.";";
2892 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $opt['quan']) : ($opt['cost'] * $opt['quan']));
2893 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2894 $realcost = $opt['maxprice'];
2895 }
2896
2897 /**
2898 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
2899 *
2900 * @since 1.17.7 (J) - 1.7.7 (WP)
2901 */
2902 $custom_calc_booking = array_merge($ord, ['days' => $room_nights]);
2903 $custom_calc_booking_room = array_merge($or, ($arrpeople[$num] ?? []), ($tmp_room_cost ? ['room_cost' => $tmp_room_cost] : []));
2904 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$opt, $custom_calc_booking, $custom_calc_booking_room]);
2905 if ($custom_calculation) {
2906 $realcost = (float) $custom_calculation[0];
2907 }
2908
2909 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2910 if ($opt['is_citytax'] == 1) {
2911 $tot_city_taxes += $tmpopr;
2912 } elseif ($opt['is_fee'] == 1) {
2913 $tot_fees += $tmpopr;
2914 } elseif ($opt_params['damagedep'] ?? 0) {
2915 $tot_damage_dep += $tmpopr;
2916 }
2917 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2918 if ($tmpopr == $realcost) {
2919 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
2920 $tot_taxes += ($realcost - $opt_minus_iva);
2921 } else {
2922 $tot_taxes += ($tmpopr - $realcost);
2923 }
2924 //
2925 $isdue += $tmpopr;
2926 }
2927 }
2928 } else {
2929 $tmpvar = VikRequest::getString('optid'.$num.$opt['id'], '', 'request');
2930 if (is_array($tmpvar)) {
2931 // prevent errors for unexpected option configuration, probably missing age intervals
2932 continue;
2933 }
2934 $tmp_room_cost = 0;
2935 // options forced per child fix, no age intervals, like children tourist taxes
2936 $forcedquan = 1;
2937 $forceperday = false;
2938 $forceperchild = false;
2939 if (intval($opt['forcesel']) == 1 && strlen($opt['forceval']) > 0 && strlen($tmpvar) > 0) {
2940 $forceparts = explode("-", $opt['forceval']);
2941 $forcedquan = intval($forceparts[0]);
2942 $forceperday = intval($forceparts[1]) == 1 ? true : false;
2943 $forceperchild = intval($forceparts[2]) == 1 ? true : false;
2944 $tmpvar = $forcedquan;
2945 $tmpvar = $forceperchild === true && array_key_exists($num, $arrpeople) && array_key_exists('children', $arrpeople[$num]) ? ($tmpvar * $arrpeople[$num]['children']) : $tmpvar;
2946 }
2947 //
2948 if (!empty($tmpvar)) {
2949 $wop .= $opt['id'].":".$tmpvar.";";
2950 // options percentage cost of the room total fee
2951 if ($is_package !== true && array_key_exists($num, $tars)) {
2952 // type of price
2953 $tmp_room_cost = $tars[$num][0]['cost'];
2954 $deftar_basecosts = $tars[$num][0]['cost'];
2955 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2956 // package
2957 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2958 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2959 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2960 // custom rate + custom tax rate
2961 $tmp_room_cost = $cust_costs[$num]['cust_cost'];
2962 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2963 }
2964 $opt['cost'] = (int)$opt['pcentroom'] ? ($deftar_basecosts * $opt['cost'] / 100) : $opt['cost'];
2965 //
2966 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $tmpvar) : ($opt['cost'] * $tmpvar));
2967 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2968 $realcost = $opt['maxprice'];
2969 if (intval($opt['hmany']) == 1 && intval($tmpvar) > 1) {
2970 $realcost = $opt['maxprice'] * $tmpvar;
2971 }
2972 }
2973 if ($opt['perperson'] == 1) {
2974 $num_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : 1;
2975 $realcost = $realcost * $num_adults;
2976 }
2977
2978 /**
2979 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
2980 *
2981 * @since 1.17.7 (J) - 1.7.7 (WP)
2982 */
2983 $custom_calc_booking = array_merge($ord, ['days' => $room_nights]);
2984 $custom_calc_booking_room = array_merge($or, ($arrpeople[$num] ?? []), ($tmp_room_cost ? ['room_cost' => $tmp_room_cost] : []));
2985 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$opt, $custom_calc_booking, $custom_calc_booking_room]);
2986 if ($custom_calculation) {
2987 $realcost = (float) $custom_calculation[0];
2988 }
2989
2990 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2991 if ($opt['is_citytax'] == 1) {
2992 $tot_city_taxes += $tmpopr;
2993 } elseif ($opt['is_fee'] == 1) {
2994 $tot_fees += $tmpopr;
2995 } elseif ($opt_params['damagedep'] ?? 0) {
2996 $tot_damage_dep += $tmpopr;
2997 }
2998 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2999 if ($tmpopr == $realcost) {
3000 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
3001 $tot_taxes += ($realcost - $opt_minus_iva);
3002 } else {
3003 $tot_taxes += ($tmpopr - $realcost);
3004 }
3005 //
3006 $isdue += $tmpopr;
3007 }
3008 }
3009 }
3010
3011 $upd_fields = array();
3012 if ($is_package !== true && array_key_exists($num, $tars)) {
3013 // type of price
3014 $upd_fields[] = "`idtar`='".$tars[$num][0]['id']."'";
3015 $upd_fields[] = "`cust_cost`=NULL";
3016 $upd_fields[] = "`cust_idiva`=NULL";
3017 $upd_fields[] = "`cust_cpolicy_id`=NULL";
3018 $upd_fields[] = "`room_cost`=".(array_key_exists($num, $rooms_costs_map) ? $dbo->quote($rooms_costs_map[$num]) : "NULL");
3019 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
3020 // packages do not update name or cost, just set again the same package ID to avoid risks of empty upd_fields to update
3021 $upd_fields[] = "`idtar`=NULL";
3022 $upd_fields[] = "`pkg_id`='".$cust_costs[$num]['pkgid']."'";
3023 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
3024 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
3025 $upd_fields[] = "`cust_cpolicy_id`='" . (int) ($cust_costs[$num]['cust_cpolicy_id'] ?? 0) . "'";
3026 $upd_fields[] = "`room_cost`=NULL";
3027 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
3028 // custom rate + custom tax rate
3029 $upd_fields[] = "`idtar`=NULL";
3030 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
3031 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
3032 $upd_fields[] = "`cust_cpolicy_id`='" . (int) ($cust_costs[$num]['cust_cpolicy_id'] ?? 0) . "'";
3033 $upd_fields[] = "`room_cost`=NULL";
3034 // inject new room price
3035 $ordersrooms[$kor]['modified_price'] = $cust_costs[$num]['cust_cost'];
3036 }
3037 if ($toptionals) {
3038 $upd_fields[] = "`optionals`='".$wop."'";
3039 }
3040 if (!empty($pt_first_name) || !empty($pt_last_name)) {
3041 $upd_fields[] = "`t_first_name`=".$dbo->quote($pt_first_name);
3042 $upd_fields[] = "`t_last_name`=".$dbo->quote($pt_last_name);
3043 }
3044 if (array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num])) {
3045 $upd_fields[] = "`adults`=".intval($arrpeople[$num]['adults']);
3046 $upd_fields[] = "`children`=".intval($arrpeople[$num]['children']);
3047 if (isset($arrpeople[$num]['pets'])) {
3048 $upd_fields[] = "`pets`=" . $arrpeople[$num]['pets'];
3049 }
3050 }
3051
3052 /**
3053 * Meal plans at room-reservation level.
3054 *
3055 * @since 1.16.1 (J) - 1.6.1 (WP)
3056 */
3057 $pmealplans = VikRequest::getVar('mealplan' . $num, []);
3058 $upd_fields[] = "`meals`=" . ($pmealplans ? $dbo->q(json_encode($pmealplans)) : 'NULL');
3059
3060 // calculate the extra costs and increase taxes + isdue
3061 $extracosts_arr = array();
3062 if (count($pextracn) && isset($pextracn[$num]) && count($pextracn[$num])) {
3063 foreach ($pextracn[$num] as $eck => $ecn) {
3064 if ($ecn && array_key_exists($eck, $pextracc[$num]) && is_numeric($pextracc[$num][$eck])) {
3065 $ecidtax = array_key_exists($eck, $pextractx[$num]) && intval($pextractx[$num][$eck]) > 0 ? (int)$pextractx[$num][$eck] : '';
3066 $extracosts_arr[] = array(
3067 'name' => $ecn,
3068 'cost' => (float)$pextracc[$num][$eck],
3069 'idtax' => $ecidtax,
3070 'type' => isset($pextractype[$num][$eck]) ? $pextractype[$num][$eck] : '',
3071 'fk' => isset($pextracfk[$num][$eck]) ? (string)$pextracfk[$num][$eck] : '',
3072 'data' => isset($pextracdata[$num][$eck]) ? json_decode($pextracdata[$num][$eck]) : null,
3073 );
3074 $ecplustax = !empty($ecidtax) ? VikBooking::sayOptionalsPlusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
3075 $ecminustax = !empty($ecidtax) ? VikBooking::sayOptionalsMinusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
3076 $ectottax = (float)$pextracc[$num][$eck] - $ecminustax;
3077 $isdue += $ecplustax;
3078 $tot_taxes += $ectottax;
3079 }
3080 }
3081 }
3082
3083 if ($extracosts_arr) {
3084 $upd_fields[] = "`extracosts`=".$dbo->quote(json_encode($extracosts_arr));
3085 } else {
3086 $upd_fields[] = "`extracosts`=NULL";
3087 }
3088
3089 if ($upd_fields) {
3090 $q = "UPDATE `#__vikbooking_ordersrooms` SET ".implode(', ', $upd_fields)." WHERE `idorder`=".$ord['id']." AND `idroom`='".$or['idroom']."' AND `id`='".$or['id']."';";
3091 $dbo->setQuery($q);
3092 $dbo->execute();
3093 }
3094 }
3095
3096 // update split stay transient record if not confirmed booking
3097 if ($ord['split_stay'] && $ord['status'] != 'confirmed' && !empty($room_stay_dates) && !empty($split_stay_data)) {
3098 /**
3099 * Important: if no rates have been selected for all rooms, we won't enter this inner statement.
3100 * It is necessary to select a rate plan for each room in order to update the split stay data.
3101 */
3102 $new_room_stay_dates = [];
3103 foreach ($room_stay_dates as $kor => $room_stay_info) {
3104 // clone the current information
3105 $clean_room_stay_info = $room_stay_info;
3106 // set new stay values
3107 if (!empty($clean_room_stay_info['checkin_ts'])) {
3108 $clean_room_stay_info['checkin_ts'] = $clean_room_stay_info['new_checkin'];
3109 $clean_room_stay_info['checkout_ts'] = $clean_room_stay_info['new_checkout'];
3110 } else {
3111 $clean_room_stay_info['checkin'] = $clean_room_stay_info['new_checkin'];
3112 $clean_room_stay_info['checkout'] = $clean_room_stay_info['new_checkout'];
3113 }
3114 $clean_room_stay_info['nights'] = $clean_room_stay_info['new_nights'];
3115 // clean up unnecessary keys
3116 unset($clean_room_stay_info['new_checkin'], $clean_room_stay_info['new_checkout'], $clean_room_stay_info['new_nights']);
3117 // push new array info
3118 $new_room_stay_dates[$kor] = $clean_room_stay_info;
3119 }
3120 // update configuration record
3121 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($new_room_stay_dates));
3122 }
3123
3124 // make sure to re-apply the discount with the coupon code
3125 if ($ord['coupon']) {
3126 $expcoupon = explode(";", $ord['coupon']);
3127 $isdue -= $expcoupon[1];
3128 }
3129
3130 // make sure to apply any previously refunded amount
3131 if ($ord['refund'] > 0) {
3132 $isdue -= $ord['refund'];
3133 }
3134
3135 // update totals
3136 $q = "UPDATE `#__vikbooking_orders` SET `total`='".$isdue."', `tot_taxes`='".$tot_taxes."', `tot_city_taxes`='".$tot_city_taxes."', `tot_fees`='".$tot_fees."', `tot_damage_dep`='".$tot_damage_dep."' WHERE `id`=".$ord['id'].";";
3137 $dbo->setQuery($q);
3138 $dbo->execute();
3139 $upd_esit = JText::translate('VBORESRATESUPDATED');
3140
3141 // Customer Booking
3142 if ($ord['status'] == 'confirmed') {
3143 $q = "SELECT `idcustomer` FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$ord['id'].";";
3144 $dbo->setQuery($q);
3145 $customer_id = $dbo->loadResult();
3146 if ($customer_id) {
3147 $cpin = VikBooking::getCPinIstance();
3148 $cpin->is_admin = true;
3149 $cpin->updateBookingCommissions($ord['id'], $customer_id);
3150 }
3151 }
3152
3153 /**
3154 * Check for any OTA reporting action.
3155 *
3156 * @since 1.16.8 (J) - 1.6.8 (WP)
3157 */
3158 if (class_exists('VCMOtaReporting') && VCMOtaReporting::getInstance($ord)->stayChangeAllowed()) {
3159 // check if an OTA reporting action was selected
3160 $ota_stay_change_data = [];
3161 $ota_stay_change_all = $app->input->getInt('ota_stay_change_all', 0);
3162 foreach ($ordersrooms as $kor => $or) {
3163 $ota_stay_change_room = [];
3164 if ($ota_stay_change_all) {
3165 // set room data for stay change
3166 $ota_stay_change_room = [
3167 'idroom' => $or['idroom'],
3168 'checkin' => date('Y-m-d', $first),
3169 'checkout' => date('Y-m-d', $second),
3170 ];
3171 if (isset($or['modified_price'])) {
3172 $ota_stay_change_room['price'] = $or['modified_price'];
3173 }
3174 } elseif ($app->input->getInt('ota_stay_change_room_' . $kor, 0) && !empty($or['modified_checkin']) && !empty($or['modified_checkout'])) {
3175 // set room index data for stay change
3176 $ota_stay_change_room = [
3177 'idroom' => $or['idroom'],
3178 'index' => $kor,
3179 'checkin' => date('Y-m-d', $or['modified_checkin']),
3180 'checkout' => date('Y-m-d', $or['modified_checkout']),
3181 ];
3182 if (isset($or['modified_price'])) {
3183 $ota_stay_change_room['price'] = $or['modified_price'];
3184 }
3185 }
3186 if ($ota_stay_change_room) {
3187 // push room data for stay change
3188 $ota_stay_change_data[] = $ota_stay_change_room;
3189 }
3190 }
3191
3192 if ($ota_stay_change_data) {
3193 // notify the OTA through Vik Channel Manager
3194 $ota_reporting = VCMOtaReporting::getInstance();
3195 $ota_result = $ota_reporting->notifyStayChange($ota_stay_change_data);
3196 if (!$ota_result) {
3197 // enqueue error message
3198 $app->enqueueMessage($ota_reporting->getError(), 'error');
3199 }
3200 }
3201 }
3202 }
3203
3204 // Booking History
3205 $history_descr = "({$user->name}) " . VikBooking::getLogBookingModification($ord, $room_stay_dates);
3206 if (!$opertwounits && $forcebooking) {
3207 $history_descr .= "\n" . JText::translate('VBO_FORCED_BOOKDATES');
3208 }
3209 VikBooking::getBookingHistoryInstance($ord['id'])->setPrevBooking($ord)->store('MB', $history_descr);
3210
3211 // enqueue result message
3212 $app->enqueueMessage($upd_esit);
3213 } else {
3214 VikError::raiseWarning('', JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second));
3215 $allow_force = 1;
3216 $app->enqueueMessage(JText::translate('VBO_BOOKING_SHOULDFORCE'), 'notice');
3217 }
3218
3219 if ($callback == 'geninvoices') {
3220 $app->redirect("index.php?option=com_vikbooking&task=orders&cid[]=".$ord['id']."&confirmgen=1");
3221 } else {
3222 $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" : ""));
3223 }
3224 }
3225
3226 public function removebusy()
3227 {
3228 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
3229 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3230 }
3231
3232 $dbo = JFactory::getDbo();
3233 $app = JFactory::getApplication();
3234
3235 $user = JFactory::getUser();
3236 $config = VBOFactory::getConfig();
3237
3238 $prev_conf_ids = [];
3239 $pidorder = VikRequest::getInt('idorder', 0, 'request');
3240 $pgoto = VikRequest::getString('goto', '', 'request');
3241
3242 $purged = false;
3243
3244 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
3245 $dbo->setQuery($q, 0, 1);
3246 $row = $dbo->loadAssoc();
3247
3248 // check for any cancellation constraints
3249 $canc_denied = false;
3250 if ($row && class_exists('VCMFeesCancellation')) {
3251 // let VCM detect if there are any constraints for the cancellation
3252 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
3253 if ($canc_denied) {
3254 // set error message
3255 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
3256 if ($canc_deny_error) {
3257 $app->enqueueMessage($canc_deny_error, 'error');
3258 }
3259 }
3260 }
3261
3262 if ($row && !$canc_denied) {
3263 // set status to cancelled
3264 if ($row['status'] != 'cancelled') {
3265 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
3266 $dbo->setQuery($q);
3267 $dbo->execute();
3268 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
3269 $dbo->setQuery($q);
3270 $dbo->execute();
3271 if ($row['status'] == 'confirmed') {
3272 $prev_conf_ids[] = $row['id'];
3273 }
3274 // Booking History
3275 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
3276 }
3277
3278 /**
3279 * In case of pending bookings being cancelled, schedule the release through VCM.
3280 *
3281 * @since 1.18.8 (J) - 1.8.8 (WP)
3282 */
3283 if ($row['status'] == 'standby' && method_exists('VCMRequestAvailability', 'setForRelease')) {
3284 // let the CM schedule the release of the involved and unconfirmed booking IDs, if needed
3285 VCMRequestAvailability::getInstance()->setForRelease([$row['id']]);
3286 }
3287
3288 // free records up
3289 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
3290 $dbo->setQuery($q);
3291 $ordbusy = $dbo->loadAssocList();
3292 if ($ordbusy) {
3293 foreach ($ordbusy as $ob) {
3294 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
3295 $dbo->setQuery($q);
3296 $dbo->execute();
3297 }
3298 }
3299
3300 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
3301 $dbo->setQuery($q);
3302 $dbo->execute();
3303
3304 // check for purge removal
3305 if ($row['status'] == 'cancelled') {
3306 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
3307 $dbo->setQuery($q);
3308 $dbo->execute();
3309 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
3310 $dbo->setQuery($q);
3311 $dbo->execute();
3312 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
3313 $dbo->setQuery($q);
3314 $dbo->execute();
3315 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
3316 $dbo->setQuery($q);
3317 $dbo->execute();
3318 // in case of split stay booking, remove the transient
3319 if ($row['split_stay']) {
3320 $config->remove('split_stay_' . $row['id']);
3321 }
3322 // turn flag on
3323 $purged = true;
3324 }
3325
3326 // enqueue message
3327 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
3328 }
3329
3330 if ($prev_conf_ids) {
3331 $prev_conf_ids_str = '';
3332 foreach ($prev_conf_ids as $prev_id) {
3333 $prev_conf_ids_str .= '&cid[]='.$prev_id;
3334 }
3335 //Invoke Channel Manager
3336 $vcm_autosync = VikBooking::vcmAutoUpdate();
3337 if ($vcm_autosync > 0) {
3338 $vcm_obj = VikBooking::getVcmInvoker();
3339 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
3340 $sync_result = $vcm_obj->doSync();
3341 if ($sync_result === false) {
3342 $vcm_err = $vcm_obj->getError();
3343 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
3344 }
3345 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
3346 $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');
3347 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
3348 }
3349 //
3350 }
3351
3352 if ($pgoto == 'overv') {
3353 $app->redirect("index.php?option=com_vikbooking&task=overv");
3354 } elseif (!$purged) {
3355 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pidorder);
3356 } else {
3357 $app->redirect("index.php?option=com_vikbooking&task=orders");
3358 }
3359
3360 $app->close();
3361 }
3362
3363 public function unlockrecords()
3364 {
3365 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
3366 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
3367 }
3368
3369 $ids = VikRequest::getVar('cid', array(0));
3370 if (@count($ids)) {
3371 $dbo = JFactory::getDBO();
3372 foreach ($ids as $d) {
3373 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `id`=".$dbo->quote($d).";";
3374 $dbo->setQuery($q);
3375 $dbo->execute();
3376 }
3377 }
3378 $mainframe = JFactory::getApplication();
3379 $mainframe->redirect("index.php?option=com_vikbooking");
3380 }
3381
3382 public function sortoption() {
3383 if (!JSession::checkToken('get')) {
3384 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3385 }
3386 $sortid = VikRequest::getVar('cid', array(0));
3387 $pmode = VikRequest::getString('mode', '', 'request');
3388 $dbo = JFactory::getDBO();
3389 $mainframe = JFactory::getApplication();
3390 if (!empty($pmode)) {
3391 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
3392 $dbo->setQuery($q);
3393 $dbo->execute();
3394 $totr = $dbo->getNumRows();
3395 if ($totr > 1) {
3396 $data = $dbo->loadAssocList();
3397 if ($pmode == "up") {
3398 foreach ($data as $v) {
3399 if ($v['id'] == $sortid[0]) {
3400 $y = $v['ordering'];
3401 }
3402 }
3403 if ($y && $y > 1) {
3404 $vik = $y - 1;
3405 $found = false;
3406 foreach ($data as $v) {
3407 if (intval($v['ordering']) == intval($vik)) {
3408 $found = true;
3409 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3410 $dbo->setQuery($q);
3411 $dbo->execute();
3412 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3413 $dbo->setQuery($q);
3414 $dbo->execute();
3415 break;
3416 }
3417 }
3418 if (!$found) {
3419 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3420 $dbo->setQuery($q);
3421 $dbo->execute();
3422 }
3423 }
3424 } elseif ($pmode == "down") {
3425 foreach ($data as $v) {
3426 if ($v['id'] == $sortid[0]) {
3427 $y = $v['ordering'];
3428 }
3429 }
3430 if ($y) {
3431 $vik = $y + 1;
3432 $found = false;
3433 foreach ($data as $v) {
3434 if (intval($v['ordering']) == intval($vik)) {
3435 $found = true;
3436 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3437 $dbo->setQuery($q);
3438 $dbo->execute();
3439 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3440 $dbo->setQuery($q);
3441 $dbo->execute();
3442 break;
3443 }
3444 }
3445 if (!$found) {
3446 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3447 $dbo->setQuery($q);
3448 $dbo->execute();
3449 }
3450 }
3451 }
3452 }
3453 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
3454 } else {
3455 $mainframe->redirect("index.php?option=com_vikbooking");
3456 }
3457 }
3458
3459 public function sortpayment() {
3460 if (!JSession::checkToken('get')) {
3461 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3462 }
3463 $cid = VikRequest::getVar('cid', array(0));
3464 $sortid = $cid[0];
3465 $dbo = JFactory::getDBO();
3466 $mainframe = JFactory::getApplication();
3467 $pmode = VikRequest::getString('mode', '', 'request');
3468 if (!empty($pmode) && !empty($sortid)) {
3469 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_gpayments` ORDER BY `#__vikbooking_gpayments`.`ordering` ASC;";
3470 $dbo->setQuery($q);
3471 $dbo->execute();
3472 $totr=$dbo->getNumRows();
3473 if ($totr > 1) {
3474 $data = $dbo->loadAssocList();
3475 if ($pmode == "up") {
3476 foreach ($data as $v) {
3477 if ($v['id'] == $sortid) {
3478 $y = $v['ordering'];
3479 }
3480 }
3481 if ($y && $y > 1) {
3482 $vik = $y - 1;
3483 $found = false;
3484 foreach ($data as $v) {
3485 if (intval($v['ordering']) == intval($vik)) {
3486 $found = true;
3487 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3488 $dbo->setQuery($q);
3489 $dbo->execute();
3490 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3491 $dbo->setQuery($q);
3492 $dbo->execute();
3493 break;
3494 }
3495 }
3496 if (!$found) {
3497 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3498 $dbo->setQuery($q);
3499 $dbo->execute();
3500 }
3501 }
3502 } elseif ($pmode == "down") {
3503 foreach ($data as $v) {
3504 if ($v['id'] == $sortid) {
3505 $y = $v['ordering'];
3506 }
3507 }
3508 if ($y) {
3509 $vik = $y + 1;
3510 $found = false;
3511 foreach ($data as $v) {
3512 if (intval($v['ordering']) == intval($vik)) {
3513 $found=true;
3514 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3515 $dbo->setQuery($q);
3516 $dbo->execute();
3517 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3518 $dbo->setQuery($q);
3519 $dbo->execute();
3520 break;
3521 }
3522 }
3523 if (!$found) {
3524 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3525 $dbo->setQuery($q);
3526 $dbo->execute();
3527 }
3528 }
3529 }
3530 }
3531 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3532 } else {
3533 $mainframe->redirect("index.php?option=com_vikbooking");
3534 }
3535 }
3536
3537 public function sortcarat() {
3538 if (!JSession::checkToken('get')) {
3539 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3540 }
3541 $sortid = VikRequest::getVar('cid', array(0));
3542 $pmode = VikRequest::getString('mode', '', 'request');
3543 $dbo = JFactory::getDBO();
3544 $mainframe = JFactory::getApplication();
3545 if (!empty($pmode)) {
3546 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` ASC;";
3547 $dbo->setQuery($q);
3548 $dbo->execute();
3549 $totr = $dbo->getNumRows();
3550 if ($totr > 1) {
3551 $data = $dbo->loadAssocList();
3552 if ($pmode == "up") {
3553 foreach ($data as $v) {
3554 if ($v['id'] == $sortid[0]) {
3555 $y = $v['ordering'];
3556 }
3557 }
3558 if ($y && $y > 1) {
3559 $vik = $y - 1;
3560 $found = false;
3561 foreach ($data as $v) {
3562 if (intval($v['ordering']) == intval($vik)) {
3563 $found = true;
3564 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3565 $dbo->setQuery($q);
3566 $dbo->execute();
3567 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3568 $dbo->setQuery($q);
3569 $dbo->execute();
3570 break;
3571 }
3572 }
3573 if (!$found) {
3574 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3575 $dbo->setQuery($q);
3576 $dbo->execute();
3577 }
3578 }
3579 } elseif ($pmode == "down") {
3580 foreach ($data as $v) {
3581 if ($v['id'] == $sortid[0]) {
3582 $y = $v['ordering'];
3583 }
3584 }
3585 if ($y) {
3586 $vik = $y + 1;
3587 $found = false;
3588 foreach ($data as $v) {
3589 if (intval($v['ordering']) == intval($vik)) {
3590 $found = true;
3591 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3592 $dbo->setQuery($q);
3593 $dbo->execute();
3594 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3595 $dbo->setQuery($q);
3596 $dbo->execute();
3597 break;
3598 }
3599 }
3600 if (!$found) {
3601 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3602 $dbo->setQuery($q);
3603 $dbo->execute();
3604 }
3605 }
3606 }
3607 }
3608 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
3609 } else {
3610 $mainframe->redirect("index.php?option=com_vikbooking");
3611 }
3612 }
3613
3614 public function resendordemail() {
3615 $this->do_resendorderemail();
3616 }
3617
3618 public function sendcancordemail() {
3619 $this->do_resendorderemail(true);
3620 }
3621
3622 private function do_resendorderemail($cancellation = false)
3623 {
3624 $dbo = JFactory::getDbo();
3625 $app = JFactory::getApplication();
3626 $vbo_tn = VikBooking::getTranslator();
3627
3628 $cid = VikRequest::getVar('cid', array(0));
3629 $oid = (int)$cid[0];
3630
3631 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $oid . ";";
3632 $dbo->setQuery($q);
3633 $dbo->execute();
3634 if (!$dbo->getNumRows()) {
3635 $app->redirect("index.php?option=com_vikbooking&task=orders");
3636 $app->close();
3637 }
3638 $order = $dbo->loadAssoc();
3639
3640 // check if the language in use is the same as the one used during the checkout
3641 if (!empty($order['lang'])) {
3642 $lang = JFactory::getLanguage();
3643 if ($lang->getTag() != $order['lang']) {
3644 $lang->load('com_vikbooking', (VBOPlatformDetection::isWordPress() ? VIKBOOKING_LANG : JPATH_ADMINISTRATOR), $order['lang'], true);
3645 if (defined('_JEXEC') && !defined('ABSPATH')) {
3646 $lang->load('joomla', JPATH_ADMINISTRATOR, $order['lang'], true);
3647 }
3648 }
3649 if ($vbo_tn->getDefaultLang() != $order['lang']) {
3650 // force the translation to start because contents should be translated
3651 $vbo_tn::$force_tolang = $order['lang'];
3652 }
3653 }
3654
3655 // availability helper
3656 $av_helper = VikBooking::getAvailabilityInstance();
3657
3658 /**
3659 * Split stay reservation.
3660 *
3661 * @since 1.16.0 (J) - 1.6.0 (WP)
3662 */
3663 $room_stay_dates = [];
3664 if ($order['split_stay']) {
3665 if ($order['status'] == 'confirmed') {
3666 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($order['id']);
3667 } else {
3668 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
3669 }
3670 // immediately count the number of nights of stay for each split room
3671 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
3672 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
3673 // overwrite values for compatibility with non-confirmed bookings
3674 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
3675 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
3676 }
3677 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
3678 // overwrite the whole array
3679 $room_stay_dates[$sps_r_k] = $sps_r_v;
3680 }
3681 }
3682
3683 // load rooms booked
3684 $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;";
3685 $dbo->setQuery($q);
3686 $dbo->execute();
3687 $ordersrooms = $dbo->loadAssocList();
3688 $vbo_tn->translateContents($ordersrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
3689
3690 $ftitle = VikBooking::getFrontTitle();
3691 $currencyname = VikBooking::getCurrencyName();
3692
3693 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
3694 $realback = $turnover_secs + $order['checkout'];
3695
3696 $rooms = array();
3697 $tars = array();
3698 $arrpeople = array();
3699 $is_package = !empty($order['pkg']) ? true : false;
3700 $nowts = time();
3701 foreach ($ordersrooms as $kor => $or) {
3702 $num = $kor + 1;
3703 $rooms[$num] = $or;
3704 $arrpeople[$num]['adults'] = $or['adults'];
3705 $arrpeople[$num]['children'] = $or['children'];
3706 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3707 // package or custom cost set from the back-end
3708 continue;
3709 }
3710
3711 // determine the proper values for this room
3712 $room_nights = $order['days'];
3713 $room_checkin = $order['checkin'];
3714 $room_checkout = $order['checkout'];
3715 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3716 $room_nights = $room_stay_dates[$kor]['nights'];
3717 $room_checkin = $room_stay_dates[$kor]['checkin'];
3718 $room_checkout = $room_stay_dates[$kor]['checkout'];
3719 }
3720
3721 // load tariff
3722 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=" . (int)$or['idtar'] . ";";
3723 $dbo->setQuery($q);
3724 $dbo->execute();
3725 if ($dbo->getNumRows() > 0) {
3726 $tar = $dbo->loadAssocList();
3727 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
3728
3729 // different usage
3730 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
3731
3732 $tars[$num] = $tar[0];
3733 } else {
3734 VikError::raiseWarning('', JText::translate('VBERRNOFAREFOUND'));
3735 }
3736 }
3737
3738 $secdiff = $order['checkout'] - $order['checkin'];
3739 $daysdiff = $secdiff / 86400;
3740 if (is_int($daysdiff)) {
3741 if ($daysdiff < 1) {
3742 $daysdiff = 1;
3743 }
3744 } else {
3745 if ($daysdiff < 1) {
3746 $daysdiff = 1;
3747 } else {
3748 $sum = floor($daysdiff) * 86400;
3749 $newdiff = $secdiff - $sum;
3750 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
3751 if ($maxhmore >= $newdiff) {
3752 $daysdiff = floor($daysdiff);
3753 } else {
3754 $daysdiff = ceil($daysdiff);
3755 }
3756 }
3757 }
3758
3759 $isdue = 0;
3760 $pricestr = array();
3761 $optstr = array();
3762 foreach ($ordersrooms as $kor => $or) {
3763 $num = $kor + 1;
3764
3765 // determine the proper values for this room
3766 $room_nights = $order['days'];
3767 $room_checkin = $order['checkin'];
3768 $room_checkout = $order['checkout'];
3769 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3770 $room_nights = $room_stay_dates[$kor]['nights'];
3771 $room_checkin = $room_stay_dates[$kor]['checkin'];
3772 $room_checkout = $room_stay_dates[$kor]['checkout'];
3773 }
3774
3775 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3776 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
3777 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
3778 $isdue += $calctar;
3779 $pricestr[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? ucwords($or['otarplan']) : JText::translate('VBOROOMCUSTRATEPLAN'))).": ".$calctar." ".$currencyname;
3780 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
3781 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3782 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
3783 $tars[$num]['calctar'] = $calctar;
3784 $isdue += $calctar;
3785 $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'] : "");
3786 }
3787 if (!empty($or['optionals'])) {
3788 $stepo = explode(";", $or['optionals']);
3789 foreach ($stepo as $roptkey => $oo) {
3790 if (empty($oo)) {
3791 continue;
3792 }
3793 $stept = explode(":", $oo);
3794 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=" . $dbo->quote($stept[0]) . ";";
3795 $dbo->setQuery($q);
3796 $dbo->execute();
3797 if (!$dbo->getNumRows()) {
3798 continue;
3799 }
3800 $actopt = $dbo->loadAssocList();
3801 $vbo_tn->translateContents($actopt, '#__vikbooking_optionals', array(), array(), (!empty($order['lang']) ? $order['lang'] : null));
3802 $chvar = '';
3803 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
3804 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
3805 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
3806 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
3807 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
3808 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
3809 $agestept = explode('-', $stept[1]);
3810 $stept[1] = $agestept[0];
3811 $chvar = $agestept[1];
3812 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
3813 //percentage value of the adults tariff
3814 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3815 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3816 } else {
3817 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3818 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3819 }
3820 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
3821 //VBO 1.10 - percentage value of room base cost
3822 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3823 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3824 } else {
3825 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
3826 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3827 }
3828 }
3829 $actopt[0]['chageintv'] = $chvar;
3830 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
3831 $actopt[0]['quan'] = $stept[1];
3832 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
3833 } else {
3834 $actopt[0]['quan'] = $stept[1];
3835 // VBO 1.11 - options percentage cost of the room total fee
3836 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3837 $deftar_basecosts = $or['cust_cost'];
3838 } else {
3839 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3840 }
3841 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
3842 //
3843 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
3844 }
3845 if (!empty($actopt[0]['maxprice']) && $actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
3846 $realcost = $actopt[0]['maxprice'];
3847 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
3848 $realcost = $actopt[0]['maxprice'] * $stept[1];
3849 }
3850 }
3851 if ($actopt[0]['perperson'] == 1) {
3852 $realcost = $realcost * $or['adults'];
3853 }
3854
3855 /**
3856 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
3857 *
3858 * @since 1.17.7 (J) - 1.7.7 (WP)
3859 */
3860 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$actopt[0], $order, $or]);
3861 if ($custom_calculation) {
3862 $realcost = (float) $custom_calculation[0];
3863 }
3864
3865 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
3866 $isdue += $tmpopr;
3867 $optstr[$num][] = ($stept[1] > 1 ? $stept[1] . " " : "") . $actopt[0]['name'] . ": " . $tmpopr . " " . $currencyname . "\n";
3868 }
3869 }
3870
3871 // custom extra costs
3872 if (!empty($or['extracosts'])) {
3873 $cur_extra_costs = json_decode($or['extracosts'], true);
3874 foreach ($cur_extra_costs as $eck => $ecv) {
3875 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
3876 $isdue += $ecplustax;
3877 $optstr[$num][] = $ecv['name'] . ": " . $ecplustax . " " . $currencyname."\n";
3878 }
3879 }
3880 }
3881
3882 // coupon
3883 $usedcoupon = false;
3884 $origisdue = $isdue;
3885 if (strlen($order['coupon']) > 0) {
3886 $usedcoupon = true;
3887 $expcoupon = explode(";", $order['coupon']);
3888 $isdue = $isdue - $expcoupon[1];
3889 }
3890
3891 // make sure to apply any previously refunded amount
3892 if ($order['refund'] > 0) {
3893 $isdue -= $order['refund'];
3894 }
3895
3896 // ConfirmationNumber
3897 $confirmnumber = $order['confirmnumber'];
3898
3899 $esit_mess = JText::sprintf('VBORDEREMAILRESENT', $order['custmail']);
3900 $status_str = JText::translate('VBCOMPLETED');
3901 if ($cancellation) {
3902 $confirmnumber = '';
3903 $esit_mess = JText::sprintf('VBCANCORDEREMAILSENT', $order['custmail']);
3904 $status_str = JText::translate('VBCANCELLED');
3905 } elseif ($order['status'] == 'standby') {
3906 $confirmnumber = '';
3907 $status_str = JText::translate('VBWAITINGFORPAYMENT');
3908 }
3909 $app->enqueueMessage($esit_mess);
3910
3911 // force the original total amount if rates have changed
3912 if (number_format($isdue, 2) != number_format($order['total'], 2)) {
3913 $isdue = $order['total'];
3914 }
3915
3916 // send email notification to guest (by ignoring the configuration settings)
3917 VikBooking::sendBookingEmail($order['id'], ['guest'], $send = true, $no_config = true);
3918
3919 if ($cancellation) {
3920 /**
3921 * If "send cancellation email", we log the event in the history.
3922 *
3923 * @since 1.14 (J) - 1.4.0 (WP)
3924 */
3925 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('EC');
3926 } else {
3927 /**
3928 * Instead, we store an event log to remind that the email was re-sent to the guest
3929 *
3930 * @since 1.16.3 (J) - 1.6.3 (WP)
3931 */
3932 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('ER', $esit_mess);
3933 }
3934
3935 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$oid);
3936 $app->close();
3937 }
3938
3939 public function setordconfirmed()
3940 {
3941 $app = JFactory::getApplication();
3942
3943 // the booking ID to confirm
3944 $cid = VikRequest::getVar('cid', array(0));
3945 $oid = (int) $cid[0];
3946
3947 // notify the customer unless it was a re-confirmation
3948 $pskip = $app->input->getInt('skip_notification', 0);
3949
3950 // access the reservation model
3951 $model = VBOModelReservation::getInstance();
3952
3953 // set the booking to confirmed
3954 $confirmed = $model->setConfirmed([
3955 'booking_id' => $oid,
3956 'notify' => (bool) (!$pskip),
3957 ]);
3958
3959 if (!$confirmed) {
3960 $error = $model->getError();
3961 if (!is_string($error) || !$error) {
3962 $error = 'Could not confirm the reservation';
3963 }
3964
3965 // enqueue error message
3966 $app->enqueueMessage($error, 'error');
3967 } else {
3968 // enqueue success message
3969 $app->enqueueMessage(JText::translate('VBORDERSETASCONF'));
3970 }
3971
3972 // redirect
3973 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3974 $app->close();
3975 }
3976
3977 public function payments() {
3978 VikBookingHelper::printHeader("14");
3979
3980 VikRequest::setVar('view', VikRequest::getCmd('view', 'payments'));
3981
3982 parent::display();
3983
3984 if (VikBooking::showFooter()) {
3985 VikBookingHelper::printFooter();
3986 }
3987 }
3988
3989 public function newpayment() {
3990 VikBookingHelper::printHeader("14");
3991
3992 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
3993
3994 parent::display();
3995
3996 if (VikBooking::showFooter()) {
3997 VikBookingHelper::printFooter();
3998 }
3999 }
4000
4001 public function editpayment() {
4002 VikBookingHelper::printHeader("14");
4003
4004 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
4005
4006 parent::display();
4007
4008 if (VikBooking::showFooter()) {
4009 VikBookingHelper::printFooter();
4010 }
4011 }
4012
4013 public function createpayment()
4014 {
4015 if (!JSession::checkToken()) {
4016 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4017 }
4018
4019 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4020 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4021 }
4022
4023 $mainframe = JFactory::getApplication();
4024 $pname = VikRequest::getString('name', '', 'request');
4025 $ppayment = VikRequest::getString('payment', '', 'request');
4026 $ppublished = VikRequest::getString('published', '', 'request');
4027 $pcharge = VikRequest::getFloat('charge', '', 'request');
4028 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4029 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4030 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4031 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4032 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWHTML);
4033 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4034 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4035 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4036 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4037 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4038 $plogo = VikRequest::getString('logo', '', 'request');
4039 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4040 $pidrooms = VikRequest::getVar('idrooms', array());
4041 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4042 $payparamarr = array();
4043 $payparamstr = '';
4044 if (count($vikpaymentparams) > 0) {
4045 foreach ($vikpaymentparams as $setting => $cont) {
4046 if (strlen($setting) > 0) {
4047 $payparamarr[$setting] = $cont;
4048 }
4049 }
4050 if (count($payparamarr) > 0) {
4051 $payparamstr = json_encode($payparamarr);
4052 }
4053 }
4054
4055 $dbo = JFactory::getDbo();
4056
4057 $set_idrooms = [];
4058 if (empty($pall_rooms) && !empty($pidrooms)) {
4059 $pidrooms = array_map(function($idroom) {
4060 return (int)$idroom;
4061 }, $pidrooms);
4062 foreach ($pidrooms as $idroom) {
4063 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4064 continue;
4065 }
4066 $set_idrooms[] = $idroom;
4067 }
4068 }
4069
4070 if (!empty($pname) && !empty($ppayment)) {
4071 $setpub = $ppublished == "1" ? 1 : 0;
4072 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4073 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4074 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment).";";
4075 $dbo->setQuery($q);
4076 $dbo->execute();
4077 if ($dbo->getNumRows() >= 0) {
4078 $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') . ");";
4079 $dbo->setQuery($q);
4080 $dbo->execute();
4081 $mainframe->enqueueMessage(JText::translate('VBPAYMENTSAVED'));
4082 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4083 } else {
4084 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4085 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4086 }
4087 } else {
4088 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4089 }
4090 }
4091
4092 public function updatepayment()
4093 {
4094 if (!JSession::checkToken()) {
4095 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4096 }
4097
4098 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4099 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4100 }
4101
4102 $this->do_updatepayment($stay = false);
4103 }
4104
4105 public function updatepaymentstay()
4106 {
4107 if (!JSession::checkToken()) {
4108 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4109 }
4110
4111 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4112 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4113 }
4114
4115 $this->do_updatepayment($stay = true);
4116 }
4117
4118 protected function do_updatepayment($stay = false)
4119 {
4120 $mainframe = JFactory::getApplication();
4121
4122 $pwhere = VikRequest::getString('where', '', 'request');
4123 $pname = VikRequest::getString('name', '', 'request');
4124 $ppayment = VikRequest::getString('payment', '', 'request');
4125 $ppublished = VikRequest::getString('published', '', 'request');
4126 $pcharge = VikRequest::getFloat('charge', '', 'request');
4127 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4128 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4129 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4130 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4131 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWRAW);
4132 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4133 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4134 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4135 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4136 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4137 $plogo = VikRequest::getString('logo', '', 'request');
4138 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4139 $pidrooms = VikRequest::getVar('idrooms', array());
4140 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4141 $payparamarr = array();
4142 $payparamstr = '';
4143 if (count($vikpaymentparams) > 0) {
4144 foreach ($vikpaymentparams as $setting => $cont) {
4145 if (strlen($setting) > 0) {
4146 $payparamarr[$setting] = $cont;
4147 }
4148 }
4149 if (count($payparamarr) > 0) {
4150 $payparamstr = json_encode($payparamarr);
4151 }
4152 }
4153
4154 $dbo = JFactory::getDbo();
4155
4156 $set_idrooms = [];
4157 if (empty($pall_rooms) && !empty($pidrooms)) {
4158 $pidrooms = array_map(function($idroom) {
4159 return (int)$idroom;
4160 }, $pidrooms);
4161 foreach ($pidrooms as $idroom) {
4162 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4163 continue;
4164 }
4165 $set_idrooms[] = $idroom;
4166 }
4167 }
4168
4169 if (!empty($pname) && !empty($ppayment) && !empty($pwhere)) {
4170 $setpub = $ppublished == "1" ? 1 : 0;
4171 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4172 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4173 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment)." AND `id`!='".$pwhere."';";
4174 $dbo->setQuery($q);
4175 $dbo->execute();
4176 if ($dbo->getNumRows() >= 0) {
4177 $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).";";
4178 $dbo->setQuery($q);
4179 $dbo->execute();
4180
4181 $mainframe->enqueueMessage(JText::translate('VBPAYMENTUPDATED'));
4182 if ($stay) {
4183 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4184 } else {
4185 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4186 }
4187 } else {
4188 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4189 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4190 }
4191 } else {
4192 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4193 }
4194 }
4195
4196 public function removepayments()
4197 {
4198 if (!JSession::checkToken()) {
4199 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4200 }
4201
4202 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
4203 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4204 }
4205
4206 $ids = VikRequest::getVar('cid', array(0));
4207 if ($ids) {
4208 $dbo = JFactory::getDBO();
4209 foreach ($ids as $d) {
4210 $q = "DELETE FROM `#__vikbooking_gpayments` WHERE `id`=".$dbo->quote($d).";";
4211 $dbo->setQuery($q);
4212 $dbo->execute();
4213 }
4214 }
4215 $mainframe = JFactory::getApplication();
4216 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4217 }
4218
4219 public function modavailpayment() {
4220 if (!JSession::checkToken('get')) {
4221 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4222 }
4223 $cid = VikRequest::getVar('cid', array(0));
4224 $idp = $cid[0];
4225 if (!empty($idp)) {
4226 $dbo = JFactory::getDBO();
4227 $q = "SELECT `published` FROM `#__vikbooking_gpayments` WHERE `id`=".intval($idp).";";
4228 $dbo->setQuery($q);
4229 $dbo->execute();
4230 $get = $dbo->loadAssocList();
4231 $q = "UPDATE `#__vikbooking_gpayments` SET `published`=".(intval($get[0]['published']) == 1 ? '0' : '1')." WHERE `id`=".intval($idp).";";
4232 $dbo->setQuery($q);
4233 $dbo->execute();
4234 }
4235 $mainframe = JFactory::getApplication();
4236 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4237 }
4238
4239 public function seasons() {
4240 VikBookingHelper::printHeader("13");
4241
4242 VikRequest::setVar('view', VikRequest::getCmd('view', 'seasons'));
4243
4244 parent::display();
4245
4246 if (VikBooking::showFooter()) {
4247 VikBookingHelper::printFooter();
4248 }
4249 }
4250
4251 public function newseason() {
4252 VikBookingHelper::printHeader("13");
4253
4254 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4255
4256 parent::display();
4257
4258 if (VikBooking::showFooter()) {
4259 VikBookingHelper::printFooter();
4260 }
4261 }
4262
4263 public function editseason() {
4264 VikBookingHelper::printHeader("13");
4265
4266 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4267
4268 parent::display();
4269
4270 if (VikBooking::showFooter()) {
4271 VikBookingHelper::printFooter();
4272 }
4273 }
4274
4275 public function updateseason()
4276 {
4277 if (!JSession::checkToken()) {
4278 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4279 }
4280
4281 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4282 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4283 }
4284
4285 $this->do_updateseason();
4286 }
4287
4288 public function updateseasonstay()
4289 {
4290 if (!JSession::checkToken()) {
4291 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4292 }
4293
4294 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
4295 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4296 }
4297
4298 $this->do_updateseason(true);
4299 }
4300
4301 private function do_updateseason($stay = false)
4302 {
4303 $app = JFactory::getApplication();
4304 $dbo = JFactory::getDbo();
4305 $session = JFactory::getSession();
4306
4307 $pwhere = VikRequest::getInt('where', 0, 'request');
4308
4309 $pfrom = VikRequest::getString('from', '', 'request');
4310 $pto = VikRequest::getString('to', '', 'request');
4311 $ptype = VikRequest::getString('type', '', 'request');
4312 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4313 $pidrooms = VikRequest::getVar('idrooms', array());
4314 $pidprices = VikRequest::getVar('idprices', array());
4315 $pwdays = VikRequest::getVar('wdays', array());
4316 $pspname = VikRequest::getString('spname', '', 'request');
4317 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4318 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4319 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4320 $pyeartied = $pyeartied == 1 ? 1 : 0;
4321 $tieyear = 0;
4322 $ppromo = VikRequest::getInt('promo', 0, 'request');
4323 $ppromo = $ppromo == 1 ? 1 : 0;
4324 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4325 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4326 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4327 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4328 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4329 $proundmode = VikRequest::getString('roundmode', '', 'request');
4330 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4331 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4332 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4333 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4334 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4335 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4336 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4337 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4338 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4339 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4340 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4341 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4342 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4343 $occupancy_ovr = array();
4344 $losverridestr = "";
4345
4346 $updforvcm = $session->get('vbVcmRatesUpd', '');
4347 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4348
4349 // check null dates
4350 if ($dbo->getNullDate() == $pfrom) {
4351 $pfrom = '';
4352 }
4353 if ($dbo->getNullDate() == $pto) {
4354 $pto = '';
4355 }
4356
4357 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4358 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4359 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4360 exit;
4361 }
4362
4363 $skipseason = false;
4364 if (empty($pfrom) || empty($pto)) {
4365 $skipseason = true;
4366 }
4367 $skipdays = false;
4368 $wdaystr = null;
4369 if (count($pwdays) == 0) {
4370 $skipdays = true;
4371 } else {
4372 $wdaystr = "";
4373 foreach ($pwdays as $wd) {
4374 $wdaystr .= $wd.';';
4375 }
4376 }
4377 $roomstr = "";
4378 $roomids = array();
4379 foreach ($pidrooms as $room) {
4380 if (empty($room)) {
4381 continue;
4382 }
4383 $roomstr .= "-".$room."-,";
4384 $roomids[] = (int)$room;
4385 }
4386 $pricestr = "";
4387 $priceids = array();
4388 foreach ($pidprices as $price) {
4389 if (empty($price)) {
4390 continue;
4391 }
4392 $pricestr .= "-".$price."-,";
4393 $priceids[] = (int)$price;
4394 }
4395 $valid = true;
4396 $double_records = array();
4397 $sfrom = null;
4398 $sto = null;
4399
4400 // value overrides
4401 if ($pnightsoverrides && $pvaluesoverrides) {
4402 foreach ($pnightsoverrides as $ko => $no) {
4403 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4404 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4405 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4406 }
4407 }
4408 }
4409
4410 if (!$skipseason) {
4411 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4412 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4413
4414 if ($second > 0 && $second == $first) {
4415 $second += 86399;
4416 }
4417
4418 if (!($second > $first)) {
4419 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4420 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4421 exit;
4422 }
4423
4424 $baseone = getdate($first);
4425 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4426 $sfrom = $baseone[0] - $basets;
4427 $basetwo = getdate($second);
4428 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4429 $sto = $basetwo[0] - $basets;
4430
4431 // check leap year
4432 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4433 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4434 if ($baseone[0] > $leapts) {
4435 $sfrom -= 86400;
4436 /**
4437 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4438 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4439 *
4440 * @since July 2nd 2019
4441 */
4442 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4443 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4444 if ($basetwo[0] > $leapts) {
4445 $sto -= date('d-m', $baseone[0]) != '31-12' && date('d-m', $basetwo[0]) == '31-12' ? 1 : 86400;
4446 }
4447 }
4448 }
4449 }
4450
4451 // tied to the year
4452 if ($pyeartied == 1) {
4453 $tieyear = $baseone['year'];
4454 }
4455
4456 // Occupancy Override
4457 if (count($padultsdiffval) > 0) {
4458 foreach ($padultsdiffval as $rid => $valovr_arr) {
4459 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4460 continue;
4461 }
4462 foreach ($valovr_arr as $occ => $valovr) {
4463 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4464 continue;
4465 }
4466 if (!array_key_exists($rid, $occupancy_ovr)) {
4467 $occupancy_ovr[$rid] = array();
4468 }
4469 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4470 }
4471 }
4472 }
4473
4474 // check if seasons dates are valid
4475 $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").";";
4476 $dbo->setQuery($q);
4477 $similar = $dbo->loadAssocList();
4478 if ($similar) {
4479 $valid = false;
4480 foreach ($similar as $sim) {
4481 $double_records[] = $sim['spname'];
4482 }
4483 }
4484
4485 $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").";";
4486 $dbo->setQuery($q);
4487 $similar = $dbo->loadAssocList();
4488 if ($similar) {
4489 $valid = false;
4490 foreach ($similar as $sim) {
4491 $double_records[] = $sim['spname'];
4492 }
4493 }
4494
4495 $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").";";
4496 $dbo->setQuery($q);
4497 $dbo->execute();
4498 $similar = $dbo->loadAssocList();
4499 if ($similar) {
4500 $valid = false;
4501 foreach ($similar as $sim) {
4502 $double_records[] = $sim['spname'];
4503 }
4504 }
4505 }
4506
4507 // fetch previous record before the update
4508 $q = $dbo->getQuery(true)
4509 ->select('*')
4510 ->from($dbo->qn('#__vikbooking_seasons'))
4511 ->where($dbo->qn('id') . ' = ' . $pwhere);
4512 $dbo->setQuery($q, 0, 1);
4513 $prev_record = $dbo->loadAssoc();
4514
4515 if (!$valid || !$prev_record) {
4516 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').($double_records ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4517 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4518 exit;
4519 }
4520
4521 /**
4522 * Attempt to access the promotion handlers in advance to perform additional validations.
4523 *
4524 * @since 1.16.4 (J) - 1.6.4 (WP)
4525 */
4526 try {
4527 $promo_handlers = VikBooking::getPromotionHandlers();
4528 } catch (Exception $e) {
4529 // reset the value
4530 $promo_handlers = [];
4531 }
4532
4533 if (!$prev_record['promo'] && $ppromo && $promo_handlers) {
4534 // channels supporting promotions are available, and a regular special price is
4535 // being converted into a promotion - this is not allowed so we make it a non-promotion.
4536 $ppromo = 0;
4537 $app->enqueueMessage(JText::translate('VBO_NOPROMO_UPD_CHANNELS'), 'warning');
4538 }
4539
4540 if ($promo_handlers && $proundmode) {
4541 /**
4542 * Always disallow rounding when channels supporting promotions are available.
4543 *
4544 * @since 1.18.3 (J) - 1.8.3 (WP)
4545 */
4546 $proundmode = '';
4547 $app->enqueueMessage(sprintf('%s: %s.', JText::translate('VBNEWSEASONROUNDCOST'), JText::translate('VBPARAMPRICECALENDARDISABLED')), 'warning');
4548 }
4549
4550 // update record
4551 $upd_record = new stdClass;
4552 $upd_record->id = $prev_record['id'];
4553 $upd_record->type = $ptype == "1" ? 1 : 2;
4554 $upd_record->from = $sfrom;
4555 $upd_record->to = $sto;
4556 $upd_record->diffcost = $pdiffcost;
4557 $upd_record->idrooms = $roomstr;
4558 $upd_record->spname = $pspname;
4559 $upd_record->wdays = $wdaystr;
4560 $upd_record->checkinincl = $pcheckinincl;
4561 $upd_record->val_pcent = $pval_pcent;
4562 $upd_record->losoverride = $losverridestr;
4563 $upd_record->roundmode = !empty($proundmode) ? $proundmode : null;
4564 $upd_record->year = $pyeartied == 1 ? $tieyear : null;
4565 $upd_record->idprices = $pricestr;
4566 $upd_record->promo = $ppromo;
4567 $upd_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4568 $upd_record->promotxt = $ppromotxt;
4569 $upd_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4570 $upd_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4571 $upd_record->promolastmin = (int)$promolastmin;
4572 $upd_record->promofinalprice = $ppromofinalprice;
4573
4574 $dbo->updateObject('#__vikbooking_seasons', $upd_record, 'id', $nulls = true);
4575
4576 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
4577
4578 // update session values
4579 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4580 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4581 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4582 } else {
4583 $updforvcm['dfrom'] = $first;
4584 }
4585 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4586 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4587 } else {
4588 $updforvcm['dto'] = $second;
4589 }
4590 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4591 foreach ($roomids as $rid) {
4592 if (!in_array($rid, $updforvcm['rooms'])) {
4593 $updforvcm['rooms'][] = $rid;
4594 }
4595 }
4596 } else {
4597 $updforvcm['rooms'] = $roomids;
4598 }
4599 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4600 foreach ($roomids as $rid) {
4601 if (array_key_exists($rid, $updforvcm['rplans'])) {
4602 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4603 } else {
4604 $updforvcm['rplans'][$rid] = $priceids;
4605 }
4606 }
4607 } else {
4608 $updforvcm['rplans'] = array();
4609 foreach ($roomids as $rid) {
4610 $updforvcm['rplans'][$rid] = $priceids;
4611 }
4612 }
4613 $session->set('vbVcmRatesUpd', $updforvcm);
4614
4615 /**
4616 * Query promotion handlers, if any, to trigger the update/delete promotion event.
4617 *
4618 * @since 1.15.0 (J) - 1.5.0 (WP)
4619 * @since 1.16.4 (J) - 1.6.4 (WP) added control to perform a delete operation.
4620 */
4621 $promo_update_type = $prev_record['promo'] && !$ppromo ? 'triggerDelete' : 'triggerUpdate';
4622 $promo_method_type = $prev_record['promo'] && !$ppromo ? 'delete' : 'update';
4623 try {
4624 if ($ppromo && is_array($promo_handlers) && $promo_handlers) {
4625 foreach ($promo_handlers as $promo_handler) {
4626 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, $promo_update_type)) {
4627 // outdated handler object
4628 continue;
4629 }
4630 if (!is_callable(array($promo_handler->instance, $promo_update_type)) || !$promo_handler->instance->{$promo_update_type}()) {
4631 // promotion handler does not support update/delete promotion event
4632 continue;
4633 }
4634 // invoke the update/delete promotion event for this handler
4635 $ch_result = $promo_handler->instance->createPromotion(['vbo_promo_id' => $pwhere], $promo_method_type);
4636 if (!$ch_result) {
4637 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
4638 }
4639 }
4640 }
4641 } catch (Exception $e) {
4642 // do nothing
4643 }
4644
4645 if ($stay) {
4646 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4647 } else {
4648 $app->redirect("index.php?option=com_vikbooking&task=seasons");
4649 }
4650 $app->close();
4651 }
4652
4653 public function createseason()
4654 {
4655 if (!JSession::checkToken()) {
4656 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4657 }
4658
4659 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4660 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4661 }
4662
4663 $this->do_createseason();
4664 }
4665
4666 public function createseason_new()
4667 {
4668 if (!JSession::checkToken()) {
4669 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4670 }
4671
4672 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
4673 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
4674 }
4675
4676 $this->do_createseason(true);
4677 }
4678
4679 private function do_createseason($andnew = false)
4680 {
4681 $app = JFactory::getApplication();
4682 $dbo = JFactory::getDbo();
4683 $session = JFactory::getSession();
4684
4685 $pfrom = VikRequest::getString('from', '', 'request');
4686 $pto = VikRequest::getString('to', '', 'request');
4687 $ptype = VikRequest::getString('type', '', 'request');
4688 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4689 $pidrooms = VikRequest::getVar('idrooms', array());
4690 $pidprices = VikRequest::getVar('idprices', array());
4691 $pwdays = VikRequest::getVar('wdays', array());
4692 $pspname = VikRequest::getString('spname', '', 'request');
4693 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4694 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4695 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4696 $pyeartied = $pyeartied == 1 ? 1 : 0;
4697 $tieyear = 0;
4698 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4699 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4700 $proundmode = VikRequest::getString('roundmode', '', 'request');
4701 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4702 $ppromo = VikRequest::getInt('promo', 0, 'request');
4703 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4704 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4705 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4706 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4707 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4708 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4709 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4710 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4711 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4712 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4713 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4714 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4715 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4716 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4717 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4718 $pchannels = VikRequest::getVar('channels', array());
4719 $occupancy_ovr = array();
4720 $losverridestr = "";
4721
4722 $updforvcm = $session->get('vbVcmRatesUpd', '');
4723 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4724
4725 // check null dates
4726 if ($dbo->getNullDate() == $pfrom) {
4727 $pfrom = '';
4728 }
4729 if ($dbo->getNullDate() == $pto) {
4730 $pto = '';
4731 }
4732
4733 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4734 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4735 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4736 exit;
4737 }
4738
4739 $skipseason = false;
4740 if (empty($pfrom) || empty($pto)) {
4741 $skipseason = true;
4742 }
4743 $skipdays = false;
4744 $wdaystr = null;
4745 if (!$pwdays) {
4746 $skipdays = true;
4747 } else {
4748 $wdaystr = "";
4749 foreach ($pwdays as $wd) {
4750 $wdaystr .= $wd.';';
4751 }
4752 }
4753 $roomstr = "";
4754 $roomids = array();
4755 foreach ($pidrooms as $room) {
4756 if (empty($room)) {
4757 continue;
4758 }
4759 $roomstr .= "-".$room."-,";
4760 $roomids[] = (int)$room;
4761 }
4762 $pricestr = "";
4763 $priceids = array();
4764 foreach ($pidprices as $price) {
4765 if (empty($price)) {
4766 continue;
4767 }
4768 $pricestr .= "-".$price."-,";
4769 $priceids[] = (int)$price;
4770 }
4771 $valid = true;
4772 $double_records = array();
4773 $sfrom = null;
4774 $sto = null;
4775
4776 // value overrides
4777 if ($pnightsoverrides && $pvaluesoverrides) {
4778 foreach ($pnightsoverrides as $ko => $no) {
4779 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4780 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4781 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4782 }
4783 }
4784 }
4785
4786 if (!$skipseason) {
4787 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4788 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4789
4790 if ($second > 0 && $second == $first) {
4791 $second += 86399;
4792 }
4793
4794 if (!($second > $first)) {
4795 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4796 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4797 exit;
4798 }
4799
4800 $baseone = getdate($first);
4801 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4802 $sfrom = $baseone[0] - $basets;
4803 $basetwo = getdate($second);
4804 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4805 $sto = $basetwo[0] - $basets;
4806
4807 // check leap year
4808 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4809 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4810 if ($baseone[0] > $leapts) {
4811 $sfrom -= 86400;
4812 /**
4813 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4814 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4815 *
4816 * @since July 2nd 2019
4817 */
4818 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4819 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4820 if ($basetwo[0] > $leapts) {
4821 $sto -= date('d-m', $baseone[0]) != '31-12' && date('d-m', $basetwo[0]) == '31-12' ? 1 : 86400;
4822 }
4823 }
4824 }
4825 }
4826
4827 // tied to the year
4828 if ($pyeartied == 1) {
4829 $tieyear = $baseone['year'];
4830 }
4831
4832 // Occupancy Override
4833 if ($padultsdiffval) {
4834 foreach ($padultsdiffval as $rid => $valovr_arr) {
4835 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4836 continue;
4837 }
4838 foreach ($valovr_arr as $occ => $valovr) {
4839 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4840 continue;
4841 }
4842 if (!array_key_exists($rid, $occupancy_ovr)) {
4843 $occupancy_ovr[$rid] = array();
4844 }
4845 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4846 }
4847 }
4848 }
4849
4850 // check if seasons dates are valid
4851 $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").";";
4852 $dbo->setQuery($q);
4853 $similar = $dbo->loadAssocList();
4854 if ($similar) {
4855 $valid = false;
4856 foreach ($similar as $sim) {
4857 $double_records[] = $sim['spname'];
4858 }
4859 }
4860
4861 $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").";";
4862 $dbo->setQuery($q);
4863 $similar = $dbo->loadAssocList();
4864 if ($similar) {
4865 $valid = false;
4866 foreach ($similar as $sim) {
4867 $double_records[] = $sim['spname'];
4868 }
4869 }
4870
4871 $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").";";
4872 $dbo->setQuery($q);
4873 $similar = $dbo->loadAssocList();
4874 if ($similar) {
4875 $valid = false;
4876 foreach ($similar as $sim) {
4877 $double_records[] = $sim['spname'];
4878 }
4879 }
4880 }
4881
4882 if (!$valid && !$ppromo) {
4883 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').(count($double_records) ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4884 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4885 exit;
4886 }
4887
4888 if ($pchannels && $proundmode) {
4889 /**
4890 * Always disallow rounding when channels supporting promotions are available.
4891 *
4892 * @since 1.18.3 (J) - 1.8.3 (WP)
4893 */
4894 $proundmode = '';
4895 $app->enqueueMessage(sprintf('%s: %s.', JText::translate('VBNEWSEASONROUNDCOST'), JText::translate('VBPARAMPRICECALENDARDISABLED')), 'warning');
4896 }
4897
4898 // insert new record
4899 $sea_record = new stdClass;
4900 $sea_record->type = $ptype == "1" ? 1 : 2;
4901 $sea_record->from = $sfrom;
4902 $sea_record->to = $sto;
4903 $sea_record->diffcost = $pdiffcost;
4904 $sea_record->idrooms = $roomstr;
4905 $sea_record->spname = $pspname;
4906 $sea_record->wdays = $wdaystr;
4907 $sea_record->checkinincl = $pcheckinincl;
4908 $sea_record->val_pcent = $pval_pcent;
4909 $sea_record->losoverride = $losverridestr;
4910 $sea_record->roundmode = !empty($proundmode) ? $proundmode : null;
4911 $sea_record->year = $pyeartied == 1 ? $tieyear : null;
4912 $sea_record->idprices = $pricestr;
4913 $sea_record->promo = $ppromo == 1 ? 1 : 0;
4914 $sea_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4915 $sea_record->promotxt = $ppromotxt;
4916 $sea_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4917 $sea_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4918 $sea_record->promolastmin = (int)$promolastmin;
4919 $sea_record->promofinalprice = $ppromofinalprice;
4920
4921 $dbo->insertObject('#__vikbooking_seasons', $sea_record, 'id');
4922
4923 $vbo_promo_id = $sea_record->id;
4924
4925 $app->enqueueMessage(JText::translate('VBSEASONSAVED'));
4926
4927 // update session values
4928 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4929 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4930 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4931 } else {
4932 $updforvcm['dfrom'] = $first;
4933 }
4934 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4935 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4936 } else {
4937 $updforvcm['dto'] = $second;
4938 }
4939 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4940 foreach ($roomids as $rid) {
4941 if (!in_array($rid, $updforvcm['rooms'])) {
4942 $updforvcm['rooms'][] = $rid;
4943 }
4944 }
4945 } else {
4946 $updforvcm['rooms'] = $roomids;
4947 }
4948 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4949 foreach ($roomids as $rid) {
4950 if (array_key_exists($rid, $updforvcm['rplans'])) {
4951 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4952 } else {
4953 $updforvcm['rplans'][$rid] = $priceids;
4954 }
4955 }
4956 } else {
4957 $updforvcm['rplans'] = array();
4958 foreach ($roomids as $rid) {
4959 $updforvcm['rplans'][$rid] = $priceids;
4960 }
4961 }
4962 if (!$ppromo) {
4963 $session->set('vbVcmRatesUpd', $updforvcm);
4964 }
4965
4966 /**
4967 * Create the promotion also on the selected channels
4968 *
4969 * @since 1.13.0 (J) - 1.3.0 (WP)
4970 */
4971 if ($ppromo && $pchannels) {
4972 foreach ($pchannels as $channel_key) {
4973 $promo_obj = VikBooking::getPromotionHandlers($channel_key);
4974 if (!is_object($promo_obj)) {
4975 continue;
4976 }
4977 /**
4978 * We inject for VCM the ID of the newly created promotion in VBO.
4979 *
4980 * @since 1.15.0 (J) - 1.5.0 (WP)
4981 */
4982 $ch_result = $promo_obj->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'new');
4983 if (!$ch_result) {
4984 VikError::raiseWarning('', $promo_obj->getName() . ': ' . $promo_obj->getError());
4985 } else {
4986 $resp = $promo_obj->getResponse();
4987 $app->enqueueMessage($promo_obj->getName() . ': ' . JText::translate('VBOCHPROMOSUCCESS') . (!empty($resp) ? ' (' . str_replace('e4j.ok.', '', $resp) . ')' : ''));
4988 // in case of success, unset the current session values in VCM
4989 $session->set('vcmBPromo', '');
4990 }
4991 }
4992 }
4993
4994 $app->redirect("index.php?option=com_vikbooking&task=".($andnew ? 'newseason' : 'seasons'));
4995 $app->close();
4996 }
4997
4998 public function removeseasons()
4999 {
5000 if (!JSession::checkToken()) {
5001 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5002 }
5003
5004 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5005 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5006 }
5007
5008 $app = JFactory::getApplication();
5009 $dbo = JFactory::getDbo();
5010
5011 $ids = VikRequest::getVar('cid', array(0));
5012 $pidroom = VikRequest::getInt('idroom', '', 'request');
5013 $pwhere = VikRequest::getInt('where', '', 'request');
5014 if (!empty($pwhere)) {
5015 $ids[] = $pwhere;
5016 }
5017 $tot_removed = array();
5018 $prev_promos = array();
5019 foreach ($ids as $d) {
5020 if (empty($d)) {
5021 continue;
5022 }
5023 // check if it was a promotion
5024 $q = "SELECT `id` FROM `#__vikbooking_seasons` WHERE `id`=" . (int)$d . " AND `promo`=1;";
5025 $dbo->setQuery($q);
5026 $dbo->execute();
5027 if ($dbo->getNumRows()) {
5028 // push it as a previous promo
5029 array_push($prev_promos, $d);
5030 }
5031
5032 // delete the record
5033 $q = "DELETE FROM `#__vikbooking_seasons` WHERE `id`=".$dbo->quote($d).";";
5034 $dbo->setQuery($q);
5035 $dbo->execute();
5036 $tot_removed[] = $d;
5037 }
5038
5039 /**
5040 * Query promotion handlers, if any, to trigger the delete promotion event.
5041 *
5042 * @since 1.15.0 (J) - 1.5.0 (WP)
5043 */
5044 $promo_handlers = VikBooking::getPromotionHandlers();
5045 foreach ($prev_promos as $vbo_promo_id) {
5046 try {
5047 if (is_array($promo_handlers)) {
5048 foreach ($promo_handlers as $promo_handler) {
5049 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, 'triggerDelete')) {
5050 // outdated handler object
5051 continue;
5052 }
5053 if (!is_callable(array($promo_handler->instance, 'triggerDelete')) || !$promo_handler->instance->triggerDelete()) {
5054 // promotion handler does not support delete promotion event
5055 continue;
5056 }
5057 // invoke the delete promotion event for this handler
5058 $ch_result = $promo_handler->instance->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'delete');
5059 if (!$ch_result) {
5060 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
5061 }
5062 }
5063 }
5064 } catch (Exception $e) {
5065 // do nothing
5066 }
5067 }
5068
5069 $app->enqueueMessage(JText::sprintf('VBRECORDSREMOVED', count($tot_removed)));
5070 $app->redirect("index.php?option=com_vikbooking&task=seasons".(!empty($pidroom) ? '&idroom='.$pidroom : ''));
5071 $app->close();
5072 }
5073
5074 public function updatecustomer()
5075 {
5076 if (!JSession::checkToken()) {
5077 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5078 }
5079
5080 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5081 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5082 }
5083
5084 $this->do_updatecustomer();
5085 }
5086
5087 public function updatecustomerstay()
5088 {
5089 if (!JSession::checkToken()) {
5090 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5091 }
5092
5093 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5094 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5095 }
5096
5097 $this->do_updatecustomer(true);
5098 }
5099
5100 private function do_updatecustomer($stay = false) {
5101 $dbo = JFactory::getDbo();
5102 $mainframe = JFactory::getApplication();
5103 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5104 $plast_name = VikRequest::getString('last_name', '', 'request');
5105 $pcompany = VikRequest::getString('company', '', 'request');
5106 $pvat = VikRequest::getString('vat', '', 'request');
5107 $pemail = VikRequest::getString('email', '', 'request');
5108 $pphone = VikRequest::getString('phone', '', 'request');
5109 $pcountry = VikRequest::getString('country', '', 'request');
5110 $pstate = VikRequest::getString('state', '', 'request');
5111 $ppin = VikRequest::getString('pin', '', 'request');
5112 $pujid = VikRequest::getInt('ujid', '', 'request');
5113 $paddress = VikRequest::getString('address', '', 'request');
5114 $pcity = VikRequest::getString('city', '', 'request');
5115 $pzip = VikRequest::getString('zip', '', 'request');
5116 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5117 $ppec = VikRequest::getString('pec', '', 'request');
5118 $precipcode = VikRequest::getString('recipcode', '', 'request');
5119 $pgender = VikRequest::getString('gender', '', 'request');
5120 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5121 $pbdate = VikRequest::getString('bdate', '', 'request');
5122 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5123 $pdoctype = VikRequest::getString('doctype', '', 'request');
5124 $pdocnum = VikRequest::getString('docnum', '', 'request');
5125 $pnotes = VikRequest::getString('notes', '', 'request');
5126 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5127 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5128 $pcommission = VikRequest::getFloat('commission', '', 'request');
5129 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5130 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5131 $pchname = VikRequest::getString('chname', '', 'request');
5132 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5133 $pwhere = VikRequest::getInt('where', '', 'request');
5134 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5135 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5136 $pbid = VikRequest::getInt('bid', '', 'request');
5137 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5138 if (!empty($pwhere) && !empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5139 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `id`=".(int)$pwhere." LIMIT 1;";
5140 $dbo->setQuery($q);
5141 $dbo->execute();
5142 if ($dbo->getNumRows() == 1) {
5143 $customer = $dbo->loadAssoc();
5144 } else {
5145 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5146 exit;
5147 }
5148 /**
5149 * Existing customers are recognized by equal first name, last name and email address.
5150 *
5151 * @since 1.3.0
5152 */
5153 $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;";
5154 $dbo->setQuery($q);
5155 $dbo->execute();
5156 if ($dbo->getNumRows() == 0) {
5157 $cpin = VikBooking::getCPinIstance();
5158 if (empty($ppin)) {
5159 $ppin = $customer['pin'];
5160 } elseif ($cpin->pinExists($ppin, $customer['pin'])) {
5161 $ppin = $cpin->generateUniquePin();
5162 }
5163 //file upload
5164 jimport('joomla.filesystem.file');
5165 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5166 $gimg = "";
5167 if (isset($pimg) && strlen(trim($pimg['name']))) {
5168 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5169 $src = $pimg['tmp_name'];
5170 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5171 $j = "";
5172 if (file_exists($dest.$filename)) {
5173 $j = rand(171, 1717);
5174 while (file_exists($dest.$j.$filename)) {
5175 $j++;
5176 }
5177 }
5178 $finaldest = $dest.$j.$filename;
5179 $check = getimagesize($pimg['tmp_name']);
5180 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5181 if (VikBooking::uploadFile($src, $finaldest)) {
5182 $gimg = $j.$filename;
5183 } else {
5184 VikError::raiseWarning('', 'Error while uploading image');
5185 }
5186 } else {
5187 VikError::raiseWarning('', 'Uploaded file is not an Image');
5188 }
5189 } elseif (!empty($pscandocimg)) {
5190 $gimg = $pscandocimg;
5191 }
5192 //
5193 $pischannel = $pischannel > 0 ? 1 : 0;
5194 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5195 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5196 $pchname = str_replace(' ', '', trim($pchname));
5197 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5198 $chparams = array(
5199 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5200 'calccmmon' => $pcalccmmon,
5201 'applycmmon' => $papplycmmon,
5202 'chcolor' => $pchcolor,
5203 'chname' => $pchname
5204 );
5205
5206 /**
5207 * Customer profile picture (URL or uploaded file).
5208 *
5209 * @since 1.15.3 (J) - 1.5.5 (WP)
5210 */
5211 $customer_pic = VikRequest::getString('pic', '', 'request');
5212 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5213 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5214 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5215 $src = $customer_pic_img['tmp_name'];
5216 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5217 $j = "";
5218 if (is_file($dest.$filename)) {
5219 $j = rand(1, 99999);
5220 while (is_file($dest . $j .$filename)) {
5221 $j++;
5222 }
5223 }
5224 $finaldest = $dest . $j . $filename;
5225 $check = getimagesize($customer_pic_img['tmp_name']);
5226 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
5227 if (VikBooking::uploadFile($src, $finaldest)) {
5228 $customer_pic = $j . $filename;
5229 } else {
5230 VikError::raiseWarning('', 'Error while uploading image');
5231 }
5232 } else {
5233 VikError::raiseWarning('', 'Uploaded file is not an Image');
5234 }
5235 }
5236
5237 // update customer object
5238 $new_customer = new stdClass;
5239 $new_customer->id = (int)$pwhere;
5240 $new_customer->first_name = $pfirst_name;
5241 $new_customer->last_name = $plast_name;
5242 $new_customer->email = $pemail;
5243 $new_customer->phone = $pphone;
5244 $new_customer->country = $pcountry;
5245 $new_customer->pin = $ppin;
5246 $new_customer->ujid = $pujid;
5247 $new_customer->address = $paddress;
5248 $new_customer->city = $pcity;
5249 $new_customer->zip = $pzip;
5250 $new_customer->state = $pstate;
5251 $new_customer->doctype = $pdoctype;
5252 $new_customer->docnum = $pdocnum;
5253 if (!empty($gimg)) {
5254 $new_customer->docimg = $gimg;
5255 }
5256 $new_customer->notes = $pnotes;
5257 $new_customer->ischannel = $pischannel;
5258 $new_customer->chdata = json_encode($chparams);
5259 $new_customer->company = $pcompany;
5260 $new_customer->vat = $pvat;
5261 $new_customer->gender = $pgender;
5262 $new_customer->bdate = $pbdate;
5263 $new_customer->pbirth = $ppbirth;
5264 $new_customer->fisccode = $pfisccode;
5265 $new_customer->pec = $ppec;
5266 $new_customer->recipcode = $precipcode;
5267 $new_customer->pic = $customer_pic;
5268 /**
5269 * We need to update the previous information stored through
5270 * the custom fields when making a reservation for/by this client.
5271 *
5272 * @since 1.13
5273 */
5274 $skip_prev_fields = array(
5275 'id',
5276 'ujid',
5277 'docimg',
5278 'ischannel',
5279 'chdata',
5280 'notes',
5281 );
5282 if (!empty($customer['cfields'])) {
5283 $custf_info = json_decode($customer['cfields'], true);
5284 foreach ($new_customer as $fname => $fnewval) {
5285 if (!isset($customer[$fname]) || in_array($fname, $skip_prev_fields)) {
5286 continue;
5287 }
5288 // seek for old value in custom fields submitted
5289 foreach ($custf_info as $k => $v) {
5290 if (!empty($customer[$fname]) && $v == $customer[$fname]) {
5291 // field found, replace it with the new value
5292 $custf_info[$k] = $fnewval;
5293 }
5294 }
5295 }
5296 // update value on db
5297 $new_customer->cfields = json_encode($custf_info);
5298 }
5299
5300 // trigger the customer before-update event
5301 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = true);
5302
5303 // update customer record
5304 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5305
5306 // trigger the customer after-save event
5307 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = false);
5308
5309 // update all the bookings affected by this Customer ID as a sales channel
5310 $source_name = 'customer'.$pwhere.'_'.$pchname;
5311 if ($pischannel > 0) {
5312 $oid_clause = '';
5313 if ($customer['ischannel'] < 1) {
5314 //Was not a sales channel but now it is, so update all his bookings
5315 $q = "SELECT `o`.`idorderota`, `co`.`idorder`
5316 FROM `#__vikbooking_customers_orders` AS `co`
5317 LEFT JOIN `#__vikbooking_orders` AS `o` ON `co`.`idorder`=`o`.`id`
5318 WHERE `co`.`idcustomer`=".$customer['id'].";";
5319 $dbo->setQuery($q);
5320 $all_bids = $dbo->loadAssocList();
5321 if ($all_bids) {
5322 $bids = array();
5323 foreach ($all_bids as $bid) {
5324 if (empty($idorderota) && !in_array($bid['idorder'], $bids)) {
5325 $bids[] = $bid['idorder'];
5326 }
5327 }
5328 if ($bids) {
5329 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5330 }
5331 }
5332 }
5333 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5334 } else {
5335 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5336 }
5337 $dbo->setQuery($q);
5338 $dbo->execute();
5339 //
5340 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5341 } else {
5342 //email already exists
5343 $ex_customer = $dbo->loadAssoc();
5344 //check if coming from the Check-in view or not
5345 if (!empty($pcheckin) && !empty($pbid)) {
5346 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5347 /**
5348 * @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
5349 */
5350 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5351 //
5352 exit;
5353 } elseif (!empty($pgoto)) {
5354 // check if coming from a specific task
5355 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5356 $mainframe->redirect(base64_decode($pgoto));
5357 exit;
5358 } else {
5359 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>');
5360 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5361 exit;
5362 }
5363 }
5364 }
5365
5366 //check if coming from the Check-in view
5367 if (!empty($pcheckin) && !empty($pbid)) {
5368 /**
5369 * @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
5370 */
5371 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5372 exit;
5373 }
5374
5375 if ($stay) {
5376 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5377 exit;
5378 }
5379
5380 // check if coming from a specific task
5381 if (!empty($pgoto)) {
5382 $mainframe->redirect(base64_decode($pgoto));
5383 exit;
5384 }
5385
5386 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5387 }
5388
5389 public function savecustomer() {
5390 if (!JSession::checkToken()) {
5391 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5392 }
5393 $dbo = JFactory::getDbo();
5394 $mainframe = JFactory::getApplication();
5395 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5396 $plast_name = VikRequest::getString('last_name', '', 'request');
5397 $pcompany = VikRequest::getString('company', '', 'request');
5398 $pvat = VikRequest::getString('vat', '', 'request');
5399 $pemail = VikRequest::getString('email', '', 'request');
5400 $pphone = VikRequest::getString('phone', '', 'request');
5401 $pcountry = VikRequest::getString('country', '', 'request');
5402 $pstate = VikRequest::getString('state', '', 'request');
5403 $ppin = VikRequest::getString('pin', '', 'request');
5404 $pujid = VikRequest::getInt('ujid', '', 'request');
5405 $paddress = VikRequest::getString('address', '', 'request');
5406 $pcity = VikRequest::getString('city', '', 'request');
5407 $pzip = VikRequest::getString('zip', '', 'request');
5408 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5409 $ppec = VikRequest::getString('pec', '', 'request');
5410 $precipcode = VikRequest::getString('recipcode', '', 'request');
5411 $pgender = VikRequest::getString('gender', '', 'request');
5412 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5413 $pbdate = VikRequest::getString('bdate', '', 'request');
5414 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5415 $pdoctype = VikRequest::getString('doctype', '', 'request');
5416 $pdocnum = VikRequest::getString('docnum', '', 'request');
5417 $pnotes = VikRequest::getString('notes', '', 'request');
5418 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5419 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5420 $pcommission = VikRequest::getFloat('commission', '', 'request');
5421 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5422 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5423 $pchname = VikRequest::getString('chname', '', 'request');
5424 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5425 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5426 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5427 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5428 $pbid = VikRequest::getInt('bid', '', 'request');
5429 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5430 $cpin = VikBooking::getCPinIstance();
5431 /**
5432 * Existing customers are recognized by equal first name, last name and email address.
5433 *
5434 * @since 1.3.0
5435 */
5436 $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;";
5437 $dbo->setQuery($q);
5438 $dbo->execute();
5439 if ($dbo->getNumRows() == 0) {
5440 if (empty($ppin)) {
5441 $ppin = $cpin->generateUniquePin();
5442 } elseif ($cpin->pinExists($ppin)) {
5443 $ppin = $cpin->generateUniquePin();
5444 }
5445 //file upload
5446 jimport('joomla.filesystem.file');
5447 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5448 $gimg = "";
5449 if (isset($pimg) && strlen(trim($pimg['name']))) {
5450 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5451 $src = $pimg['tmp_name'];
5452 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5453 $j = "";
5454 if (file_exists($dest.$filename)) {
5455 $j = rand(171, 1717);
5456 while (file_exists($dest.$j.$filename)) {
5457 $j++;
5458 }
5459 }
5460 $finaldest = $dest.$j.$filename;
5461 $check = getimagesize($pimg['tmp_name']);
5462 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5463 if (VikBooking::uploadFile($src, $finaldest)) {
5464 $gimg = $j.$filename;
5465 } else {
5466 VikError::raiseWarning('', 'Error while uploading image');
5467 }
5468 } else {
5469 VikError::raiseWarning('', 'Uploaded file is not an Image');
5470 }
5471 } elseif (!empty($pscandocimg)) {
5472 $gimg = $pscandocimg;
5473 }
5474 //
5475 $pischannel = $pischannel > 0 ? 1 : 0;
5476 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5477 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5478 $pchname = str_replace(' ', '', trim($pchname));
5479 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5480 $chparams = array(
5481 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5482 'calccmmon' => $pcalccmmon,
5483 'applycmmon' => $papplycmmon,
5484 'chcolor' => $pchcolor,
5485 'chname' => $pchname
5486 );
5487
5488 /**
5489 * Customer profile picture (URL or uploaded file).
5490 *
5491 * @since 1.15.3 (J) - 1.5.5 (WP)
5492 */
5493 $customer_pic = VikRequest::getString('pic', '', 'request');
5494 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5495 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5496 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5497 $src = $customer_pic_img['tmp_name'];
5498 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5499 $j = "";
5500 if (is_file($dest.$filename)) {
5501 $j = rand(1, 99999);
5502 while (is_file($dest . $j .$filename)) {
5503 $j++;
5504 }
5505 }
5506 $finaldest = $dest . $j . $filename;
5507 $check = getimagesize($customer_pic_img['tmp_name']);
5508 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
5509 if (VikBooking::uploadFile($src, $finaldest)) {
5510 $customer_pic = $j . $filename;
5511 } else {
5512 VikError::raiseWarning('', 'Error while uploading image');
5513 }
5514 } else {
5515 VikError::raiseWarning('', 'Uploaded file is not an Image');
5516 }
5517 }
5518
5519 // build customer record
5520 $customer_obj = new stdClass;
5521 $customer_obj->first_name = $pfirst_name;
5522 $customer_obj->last_name = $plast_name;
5523 $customer_obj->email = $pemail;
5524 $customer_obj->phone = $pphone;
5525 $customer_obj->country = $pcountry;
5526 $customer_obj->pin = $ppin;
5527 $customer_obj->ujid = $pujid;
5528 $customer_obj->address = $paddress;
5529 $customer_obj->city = $pcity;
5530 $customer_obj->zip = $pzip;
5531 $customer_obj->state = $pstate;
5532 $customer_obj->doctype = $pdoctype;
5533 $customer_obj->docnum = $pdocnum;
5534 $customer_obj->docimg = $gimg;
5535 $customer_obj->notes = $pnotes;
5536 $customer_obj->ischannel = $pischannel;
5537 $customer_obj->chdata = json_encode($chparams);
5538 $customer_obj->company = $pcompany;
5539 $customer_obj->vat = $pvat;
5540 $customer_obj->gender = $pgender;
5541 $customer_obj->bdate = $pbdate;
5542 $customer_obj->pbirth = $ppbirth;
5543 $customer_obj->fisccode = $pfisccode;
5544 $customer_obj->pec = $ppec;
5545 $customer_obj->recipcode = $precipcode;
5546 $customer_obj->pic = !empty($customer_pic) ? $customer_pic : null;
5547
5548 // trigger the customer before-insert event
5549 $cpin->pluginCustomerSync(0, 'insert', (array)$customer_obj, $before = true);
5550
5551 // insert the new customer record
5552 $dbo->insertObject('#__vikbooking_customers', $customer_obj, 'id');
5553 $lid = isset($customer_obj->id) ? $customer_obj->id : null;
5554
5555 // trigger the customer after-save event
5556 $cpin->pluginCustomerSync($lid, 'insert', (array)$customer_obj, $before = false);
5557
5558 if (!empty($lid)) {
5559 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5560 //check if coming from the Check-in view
5561 if (!empty($pcheckin) && !empty($pbid)) {
5562 $cpin->setNewPin($ppin);
5563 $cpin->setNewCustomerId($lid);
5564 $cpin->saveCustomerBooking($pbid);
5565 /**
5566 * @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
5567 */
5568 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5569 //
5570 exit;
5571 }
5572 // check if coming from a specific task
5573 if (!empty($pgoto) && !empty($pbid)) {
5574 $cpin->setNewPin($ppin);
5575 $cpin->setNewCustomerId($lid);
5576 $cpin->saveCustomerBooking($pbid);
5577 $mainframe->redirect(base64_decode($pgoto));
5578 exit;
5579 }
5580 }
5581 } else {
5582 //email already exists
5583 $ex_customer = $dbo->loadAssoc();
5584 //check if coming from the Check-in view or not
5585 if (!empty($pcheckin) && !empty($pbid)) {
5586 $cpin->setNewPin($ex_customer['pin']);
5587 $cpin->setNewCustomerId($ex_customer['id']);
5588 $cpin->saveCustomerBooking($pbid);
5589 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5590 /**
5591 * @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
5592 */
5593 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5594 //
5595 exit;
5596 } elseif (!empty($pgoto) && !empty($pbid)) {
5597 // check if coming from a specific task
5598 $cpin->setNewPin($ex_customer['pin']);
5599 $cpin->setNewCustomerId($ex_customer['id']);
5600 $cpin->saveCustomerBooking($pbid);
5601 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5602 $mainframe->redirect(base64_decode($pgoto));
5603 exit;
5604 } else {
5605 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>');
5606 }
5607 }
5608 }
5609 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5610 }
5611
5612 public function customers() {
5613 VikBookingHelper::printHeader("22");
5614
5615 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5616
5617 parent::display();
5618
5619 if (VikBooking::showFooter()) {
5620 VikBookingHelper::printFooter();
5621 }
5622 }
5623
5624 public function newcustomer() {
5625 VikBookingHelper::printHeader("22");
5626
5627 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5628
5629 parent::display();
5630
5631 if (VikBooking::showFooter()) {
5632 VikBookingHelper::printFooter();
5633 }
5634 }
5635
5636 public function editcustomer() {
5637 VikBookingHelper::printHeader("22");
5638
5639 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5640
5641 parent::display();
5642
5643 if (VikBooking::showFooter()) {
5644 VikBookingHelper::printFooter();
5645 }
5646 }
5647
5648 public function removecustomers()
5649 {
5650 if (!JSession::checkToken()) {
5651 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5652 }
5653
5654 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
5655 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5656 }
5657
5658 $ids = VikRequest::getVar('cid', array(0));
5659 if ($ids) {
5660 $dbo = JFactory::getDBO();
5661 $cpin = VikBooking::getCPinIstance();
5662 foreach ($ids as $d) {
5663 $cpin->pluginCustomerSync($d, 'delete');
5664 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5665 $dbo->setQuery($q);
5666 $dbo->execute();
5667 }
5668 }
5669 $mainframe = JFactory::getApplication();
5670 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5671 }
5672
5673 public function restrictions() {
5674 VikBookingHelper::printHeader("restrictions");
5675
5676 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5677
5678 parent::display();
5679
5680 if (VikBooking::showFooter()) {
5681 VikBookingHelper::printFooter();
5682 }
5683 }
5684
5685 public function newrestriction() {
5686 VikBookingHelper::printHeader("restrictions");
5687
5688 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5689
5690 parent::display();
5691
5692 if (VikBooking::showFooter()) {
5693 VikBookingHelper::printFooter();
5694 }
5695 }
5696
5697 public function editrestriction() {
5698 VikBookingHelper::printHeader("restrictions");
5699
5700 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5701
5702 parent::display();
5703
5704 if (VikBooking::showFooter()) {
5705 VikBookingHelper::printFooter();
5706 }
5707 }
5708
5709 public function createrestriction()
5710 {
5711 if (!JSession::checkToken()) {
5712 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5713 }
5714
5715 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
5716 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5717 }
5718
5719 $dbo = JFactory::getDBO();
5720 $session = JFactory::getSession();
5721 $mainframe = JFactory::getApplication();
5722 $updforvcm = $session->get('vbVcmRatesUpd', '');
5723 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5724 $pname = VikRequest::getString('name', '', 'request');
5725 $pmonth = VikRequest::getInt('month', '', 'request');
5726 $pmonth = empty($pmonth) ? 0 : $pmonth;
5727 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5728 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5729 $pdto = VikRequest::getString('dto', '', 'request');
5730 $pwday = VikRequest::getString('wday', '', 'request');
5731 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5732 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5733 $pcomboa = VikRequest::getString('comboa', '', 'request');
5734 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5735 $pcombob = VikRequest::getString('combob', '', 'request');
5736 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5737 $pcomboc = VikRequest::getString('comboc', '', 'request');
5738 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5739 $pcombod = VikRequest::getString('combod', '', 'request');
5740 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5741 $combostr = '';
5742 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5743 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5744 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5745 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5746 $pminlos = VikRequest::getInt('minlos', '', 'request');
5747 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5748 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5749 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5750 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5751 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5752 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5753 $pallrooms = $pallrooms == "1" ? 1 : 0;
5754 $pidrooms = VikRequest::getVar('idrooms', array(0));
5755 $ridr = '';
5756 $roomidsforsess = array();
5757 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5758 foreach ($pidrooms as $idr) {
5759 if (empty($idr)) {
5760 continue;
5761 }
5762 $ridr .= '-'.$idr.'-;';
5763 $roomidsforsess[] = (int)$idr;
5764 }
5765 } elseif ($pallrooms > 0) {
5766 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5767 $dbo->setQuery($q);
5768 $dbo->execute();
5769 if ($dbo->getNumRows() > 0) {
5770 $fetchids = $dbo->loadAssocList();
5771 foreach ($fetchids as $fetchid) {
5772 $roomidsforsess[] = (int)$fetchid['id'];
5773 }
5774 }
5775 }
5776 $pcta = VikRequest::getInt('cta', '', 'request');
5777 $pctd = VikRequest::getInt('ctd', '', 'request');
5778 $pctad = VikRequest::getVar('ctad', array());
5779 $pctdd = VikRequest::getVar('ctdd', array());
5780 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5781 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5782 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5783 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5784 // exit;
5785 }
5786
5787 //check if there are restrictions for this month
5788 if ($pmonth > 0) {
5789 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5790 $dbo->setQuery($q);
5791 $dbo->execute();
5792 if ($dbo->getNumRows() > 0) {
5793 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5794 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5795 exit;
5796 }
5797 $pdfrom = 0;
5798 $pdto = 0;
5799 } else {
5800 //dates range
5801 if (empty($pdfrom) || empty($pdto)) {
5802 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5803 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5804 exit;
5805 } else {
5806 $housto = $pdfrom == $pdto ? 23 : 0;
5807 $minsto = $pdfrom == $pdto ? 59 : 0;
5808 $secsto = $pdfrom == $pdto ? 59 : 0;
5809 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5810 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5811 }
5812 if ($pdfrom > $pdto) {
5813 // invalid dates in the past
5814 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5815 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5816 exit;
5817 }
5818 }
5819 //CTA and CTD
5820 $setcta = array();
5821 $setctd = array();
5822 if ($pcta > 0 && count($pctad) > 0) {
5823 foreach ($pctad as $ctwd) {
5824 if (strlen($ctwd)) {
5825 $setcta[] = '-'.(int)$ctwd.'-';
5826 }
5827 }
5828 }
5829 if ($pctd > 0 && count($pctdd) > 0) {
5830 foreach ($pctdd as $ctwd) {
5831 if (strlen($ctwd)) {
5832 $setctd[] = '-'.(int)$ctwd.'-';
5833 }
5834 }
5835 }
5836 //
5837 //update session values
5838 if (!($pdfrom > 0)) {
5839 $attemptyear = (int)date('Y');
5840 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5841 if ($attemptfrom < time()) {
5842 $attemptyear++;
5843 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5844 }
5845 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5846 } else {
5847 $attemptfrom = $pdfrom;
5848 $attemptto = $pdto;
5849 }
5850 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5851 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5852 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5853 } else {
5854 $updforvcm['dfrom'] = $attemptfrom;
5855 }
5856 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5857 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5858 } else {
5859 $updforvcm['dto'] = $attemptto;
5860 }
5861 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5862 foreach ($roomidsforsess as $rid) {
5863 if (!in_array($rid, $updforvcm['rooms'])) {
5864 $updforvcm['rooms'][] = $rid;
5865 }
5866 }
5867 } else {
5868 $updforvcm['rooms'] = $roomidsforsess;
5869 }
5870 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5871 $updforvcm['rplans'] = array();
5872 }
5873 $session->set('vbVcmRatesUpd', $updforvcm);
5874 //
5875 $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").");";
5876 $dbo->setQuery($q);
5877 $dbo->execute();
5878 $lid = $dbo->insertid();
5879 if (!empty($lid)) {
5880 /**
5881 * Repeat restriction on the selected week days until the limit
5882 *
5883 * @since 1.13
5884 */
5885 $prepeat = VikRequest::getInt('repeat', 0, 'request');
5886 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
5887 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
5888 $repeat_intervals = array();
5889 $start = getdate($pdfrom);
5890 $end = getdate($pdto);
5891 $wdays = array();
5892 while ($start[0] <= $end[0]) {
5893 // push requested week day
5894 array_push($wdays, $start['wday']);
5895 // next day
5896 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
5897 }
5898 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
5899 if (count($wdays) < 7 && $dtuntil > $pdto) {
5900 // increment end date for the repeat
5901 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5902 //
5903 $until_info = getdate($dtuntil);
5904 $interval = array();
5905 while ($end[0] <= $until_info[0]) {
5906 if (in_array($end['wday'], $wdays)) {
5907 if (!isset($interval['from'])) {
5908 $interval['from'] = $end[0];
5909 }
5910 $interval['to'] = $end[0];
5911 } else {
5912 if (isset($interval['from'])) {
5913 // append interval
5914 array_push($repeat_intervals, $interval);
5915 // reset interval
5916 $interval = array();
5917 }
5918 }
5919 // next day
5920 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5921 }
5922 if (isset($interval['from'])) {
5923 // append last hanging interval
5924 array_push($repeat_intervals, $interval);
5925 }
5926 if (count($repeat_intervals)) {
5927 // create the repeated records for the calculated intervals
5928 $repeat_count = 2;
5929 foreach ($repeat_intervals as $rp) {
5930 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
5931 // adjust time in case of equal dates (1 single day restriction)
5932 $rpfrom = getdate($rp['from']);
5933 $rpto = getdate($rp['to']);
5934 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
5935 /**
5936 * The end date of the restriction must cover the whole day until 23:59:59.
5937 *
5938 * @since 1.15.4 (J) - 1.5.4 (WP)
5939 */
5940 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
5941 }
5942 // adjust name
5943 $restr_rp_name = $pname . " #{$repeat_count}";
5944 //
5945 $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").");";
5946 $dbo->setQuery($q);
5947 $dbo->execute();
5948 $lid = $dbo->insertid();
5949 if (!empty($lid)) {
5950 $repeat_count++;
5951 }
5952 }
5953 }
5954 }
5955 }
5956 //
5957 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5958 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5959 } else {
5960 VikError::raiseWarning('', 'Error while saving');
5961 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5962 }
5963 }
5964
5965 public function updaterestriction()
5966 {
5967 if (!JSession::checkToken()) {
5968 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5969 }
5970
5971 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
5972 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
5973 }
5974
5975 $dbo = JFactory::getDBO();
5976 $session = JFactory::getSession();
5977 $mainframe = JFactory::getApplication();
5978 $updforvcm = $session->get('vbVcmRatesUpd', '');
5979 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5980 $pwhere = VikRequest::getInt('where', '', 'request');
5981 $pname = VikRequest::getString('name', '', 'request');
5982 $pmonth = VikRequest::getInt('month', '', 'request');
5983 $pmonth = empty($pmonth) ? 0 : $pmonth;
5984 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5985 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5986 $pdto = VikRequest::getString('dto', '', 'request');
5987 $pwday = VikRequest::getString('wday', '', 'request');
5988 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5989 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5990 $pcomboa = VikRequest::getString('comboa', '', 'request');
5991 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5992 $pcombob = VikRequest::getString('combob', '', 'request');
5993 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5994 $pcomboc = VikRequest::getString('comboc', '', 'request');
5995 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5996 $pcombod = VikRequest::getString('combod', '', 'request');
5997 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5998 $combostr = '';
5999 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
6000 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
6001 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
6002 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
6003 $pminlos = VikRequest::getInt('minlos', '', 'request');
6004 $pminlos = $pminlos < 1 ? 1 : $pminlos;
6005 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
6006 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
6007 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
6008 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
6009 $pallrooms = VikRequest::getString('allrooms', '', 'request');
6010 $pallrooms = $pallrooms == "1" ? 1 : 0;
6011 $pidrooms = VikRequest::getVar('idrooms', array(0));
6012 $ridr = '';
6013 $roomidsforsess = array();
6014 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
6015 foreach ($pidrooms as $idr) {
6016 if (empty($idr)) {
6017 continue;
6018 }
6019 $ridr .= '-'.$idr.'-;';
6020 $roomidsforsess[] = (int)$idr;
6021 }
6022 } elseif ($pallrooms > 0) {
6023 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
6024 $dbo->setQuery($q);
6025 $dbo->execute();
6026 if ($dbo->getNumRows() > 0) {
6027 $fetchids = $dbo->loadAssocList();
6028 foreach ($fetchids as $fetchid) {
6029 $roomidsforsess[] = (int)$fetchid['id'];
6030 }
6031 }
6032 }
6033 $pcta = VikRequest::getInt('cta', '', 'request');
6034 $pctd = VikRequest::getInt('ctd', '', 'request');
6035 $pctad = VikRequest::getVar('ctad', array());
6036 $pctdd = VikRequest::getVar('ctdd', array());
6037 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
6038 // VBO 1.11 - we now allow restrictions with just 1 night of stay
6039 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
6040 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6041 // exit;
6042 }
6043 //check if there are restrictions for this month
6044 if ($pmonth > 0) {
6045 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
6046 $dbo->setQuery($q);
6047 $dbo->execute();
6048 if ($dbo->getNumRows() > 0) {
6049 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
6050 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6051 exit;
6052 }
6053 $pdfrom = 0;
6054 $pdto = 0;
6055 } else {
6056 //dates range
6057 if (empty($pdfrom) || empty($pdto)) {
6058 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6059 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6060 exit;
6061 } else {
6062 $housto = $pdfrom == $pdto ? 23 : 0;
6063 $minsto = $pdfrom == $pdto ? 59 : 0;
6064 $secsto = $pdfrom == $pdto ? 59 : 0;
6065 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
6066 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
6067 }
6068 if ($pdfrom > $pdto) {
6069 // invalid dates in the past
6070 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
6071 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
6072 exit;
6073 }
6074 }
6075 //CTA and CTD
6076 $setcta = array();
6077 $setctd = array();
6078 if ($pcta > 0 && count($pctad) > 0) {
6079 foreach ($pctad as $ctwd) {
6080 if (strlen($ctwd)) {
6081 $setcta[] = '-'.(int)$ctwd.'-';
6082 }
6083 }
6084 }
6085 if ($pctd > 0 && count($pctdd) > 0) {
6086 foreach ($pctdd as $ctwd) {
6087 if (strlen($ctwd)) {
6088 $setctd[] = '-'.(int)$ctwd.'-';
6089 }
6090 }
6091 }
6092 //
6093 //update session values
6094 if (!($pdfrom > 0)) {
6095 $attemptyear = (int)date('Y');
6096 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6097 if ($attemptfrom < time()) {
6098 $attemptyear++;
6099 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6100 }
6101 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
6102 } else {
6103 $attemptfrom = $pdfrom;
6104 $attemptto = $pdto;
6105 }
6106 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
6107 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
6108 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
6109 } else {
6110 $updforvcm['dfrom'] = $attemptfrom;
6111 }
6112 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
6113 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
6114 } else {
6115 $updforvcm['dto'] = $attemptto;
6116 }
6117 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
6118 foreach ($roomidsforsess as $rid) {
6119 if (!in_array($rid, $updforvcm['rooms'])) {
6120 $updforvcm['rooms'][] = $rid;
6121 }
6122 }
6123 } else {
6124 $updforvcm['rooms'] = $roomidsforsess;
6125 }
6126 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6127 $updforvcm['rplans'] = array();
6128 }
6129 $session->set('vbVcmRatesUpd', $updforvcm);
6130 //
6131 $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."';";
6132 $dbo->setQuery($q);
6133 $dbo->execute();
6134 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6135 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6136 }
6137
6138 public function removerestrictions()
6139 {
6140 if (!JSession::checkToken()) {
6141 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6142 }
6143
6144 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6145 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6146 }
6147
6148 $ids = VikRequest::getVar('cid', array(0));
6149 if ($ids) {
6150 $dbo = JFactory::getDBO();
6151 foreach ($ids as $d) {
6152 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6153 $dbo->setQuery($q);
6154 $dbo->execute();
6155 }
6156 }
6157 $mainframe = JFactory::getApplication();
6158 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6159 }
6160
6161 public function prices() {
6162 VikBookingHelper::printHeader("1");
6163
6164 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6165
6166 parent::display();
6167
6168 if (VikBooking::showFooter()) {
6169 VikBookingHelper::printFooter();
6170 }
6171 }
6172
6173 public function newprice() {
6174 VikBookingHelper::printHeader("1");
6175
6176 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6177
6178 parent::display();
6179
6180 if (VikBooking::showFooter()) {
6181 VikBookingHelper::printFooter();
6182 }
6183 }
6184
6185 public function editprice() {
6186 VikBookingHelper::printHeader("1");
6187
6188 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6189
6190 parent::display();
6191
6192 if (VikBooking::showFooter()) {
6193 VikBookingHelper::printFooter();
6194 }
6195 }
6196
6197 public function createprice()
6198 {
6199 if (!JSession::checkToken()) {
6200 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6201 }
6202
6203 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6204 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6205 }
6206
6207 $this->do_createprice();
6208 }
6209
6210 public function createprice_new()
6211 {
6212 if (!JSession::checkToken()) {
6213 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6214 }
6215
6216 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6217 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6218 }
6219
6220 $this->do_createprice(true);
6221 }
6222
6223 private function do_createprice($new = false)
6224 {
6225 $app = JFactory::getApplication();
6226 $dbo = JFactory::getDbo();
6227
6228 $pprice = VikRequest::getString('price', '', 'request');
6229 $pattr = VikRequest::getString('attr', '', 'request');
6230 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6231 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6232 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6233 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6234 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6235 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6236 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6237 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6238 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6239 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6240 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6241
6242 $is_derived = $app->input->getInt('is_derived', 0);
6243 $derived_id = $app->input->getUInt('derived_id', 0);
6244 $derived_data = $app->input->get('derived_data', [], 'array');
6245
6246 $parent_id = 0;
6247 $derived_info = null;
6248
6249 if ($is_derived && $derived_id && $derived_data) {
6250 $parent_id = $derived_id;
6251 $derived_info = $derived_data;
6252 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6253 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6254 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6255 $derived_info['follow_restr'] = isset($derived_info['follow_restr']) ? 1 : 0;
6256 if (!$derived_info['value']) {
6257 $parent_id = 0;
6258 $derived_info = null;
6259 }
6260 }
6261
6262 if (!empty($pprice)) {
6263 $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') . ");";
6264 $dbo->setQuery($q);
6265 $dbo->execute();
6266
6267 $new_rplan_id = $dbo->insertid();
6268
6269 /**
6270 * Allow to populate base rates for newly created rate plan for all room types using the parent rate.
6271 *
6272 * @since 1.18.6 (J) - 1.8.6 (WP)
6273 */
6274 if ($app->input->getBool('set_derived_rates', false) && $is_derived && $derived_id && $derived_info) {
6275 // find all rooms with base rates defined for the parent rate plan
6276 $dbo->setQuery(
6277 $dbo->getQuery(true)
6278 ->select($dbo->qn('idroom'))
6279 ->from($dbo->qn('#__vikbooking_dispcost'))
6280 ->where($dbo->qn('idprice') . ' = ' . $derived_id)
6281 ->group($dbo->qn('idroom'))
6282 ->order($dbo->qn('idroom') . ' ASC')
6283 );
6284 $populateRoomIds = array_map('intval', $dbo->loadColumn());
6285
6286 // determine rates table range of nights of stays
6287 $fromNights = $pminlos ?: 1;
6288 $maxNights = $app->input->getUInt('set_max_nights') ?: $pminlos ?: 1;
6289 $maxNights = $maxNights < $fromNights ? $fromNights : $maxNights;
6290
6291 // fetch base rates for all the involved room types
6292 $dbo->setQuery(
6293 $dbo->getQuery(true)
6294 ->select([
6295 $dbo->qn('idroom'),
6296 $dbo->qn('days'),
6297 $dbo->qn('cost'),
6298 ])
6299 ->from($dbo->qn('#__vikbooking_dispcost'))
6300 ->where($dbo->qn('idroom') . ' IN (' . implode(', ', $populateRoomIds) . ')')
6301 ->where($dbo->qn('idprice') . ' = ' . $derived_id)
6302 ->order($dbo->qn('idroom') . ' ASC')
6303 ->order($dbo->qn('days') . ' ASC')
6304 );
6305 $roomBaseRates = $dbo->loadAssocList();
6306
6307 // iterate all rooms involved
6308 foreach ($populateRoomIds as $roomId) {
6309 // loop through the interval of nights of stay
6310 for ($n = $fromNights; $n <= $maxNights; $n++) {
6311 // fetch current room rate in parent rate plan
6312 $roomParentNightlyRate = 0;
6313 $roomParentExactRate = 0;
6314 foreach ($roomBaseRates as $roomBaseRate) {
6315 if ($roomBaseRate['idroom'] != $roomId) {
6316 // ignore room
6317 continue;
6318 }
6319 if (!$roomParentNightlyRate) {
6320 // set rate for the lowest number of nights of stay
6321 $roomParentNightlyRate = $roomBaseRate['cost'] / ($roomBaseRate['days'] ?: 1);
6322 }
6323 if ($roomBaseRate['days'] == $n) {
6324 // set room exact rate for this number of nights of stay
6325 $roomParentExactRate = $roomBaseRate['cost'];
6326 // do not proceed
6327 break;
6328 }
6329 }
6330
6331 if (!$roomParentNightlyRate) {
6332 // missing pricing information from parent rate plan
6333 continue;
6334 }
6335
6336 // determine the cost to apply for the newly created derived rate plan
6337 $nightlyDerivedRate = $roomParentExactRate ?: $roomParentNightlyRate;
6338
6339 // check how the new rate was derived
6340 if ($derived_info['mode'] == 'charge') {
6341 // increase rate
6342 if ($derived_info['type'] == 'absolute') {
6343 // fixed increase
6344 $nightlyDerivedRate += $derived_info['value'];
6345 } else {
6346 // percent increase
6347 $nightlyDerivedRate *= (100 + $derived_info['value']) / 100;
6348 }
6349 } else {
6350 // discount rate
6351 if ($derived_info['type'] == 'absolute') {
6352 // fixed discount
6353 $nightlyDerivedRate -= $derived_info['value'];
6354 } else {
6355 // percent discount
6356 $nightlyDerivedRate *= (100 - $derived_info['value']) / 100;
6357 }
6358 }
6359
6360 if (!$roomParentExactRate) {
6361 // multiply rate by number of nights of stay if started from the parent lowest number of nights
6362 $nightlyDerivedRate *= $n;
6363 }
6364
6365 // build new room base rate record
6366 $rateRecord = [
6367 'idroom' => $roomId,
6368 'days' => $n,
6369 'idprice' => $new_rplan_id,
6370 'cost' => round($nightlyDerivedRate, 2),
6371 ];
6372
6373 // cast to object
6374 $rateRecord = (object) $rateRecord;
6375
6376 // insert record
6377 $dbo->insertObject('#__vikbooking_dispcost', $rateRecord, 'id');
6378 }
6379 }
6380 }
6381 }
6382
6383 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6384 $app->close();
6385 }
6386
6387 public function updateprice()
6388 {
6389 if (!JSession::checkToken()) {
6390 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6391 }
6392
6393 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6394 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6395 }
6396
6397 $this->do_updateprice();
6398 }
6399
6400 public function updatepricestay()
6401 {
6402 if (!JSession::checkToken()) {
6403 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6404 }
6405
6406 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6407 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6408 }
6409
6410 $this->do_updateprice(true);
6411 }
6412
6413 private function do_updateprice($stay = false)
6414 {
6415 $app = JFactory::getApplication();
6416 $dbo = JFactory::getDbo();
6417
6418 $pprice = VikRequest::getString('price', '', 'request');
6419 $pattr = VikRequest::getString('attr', '', 'request');
6420 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6421 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6422 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6423 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6424 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6425 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6426 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6427 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6428 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6429 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6430 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6431 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6432
6433 $is_derived = $app->input->getInt('is_derived', 0);
6434 $derived_id = $app->input->getUInt('derived_id', 0);
6435 $derived_data = $app->input->get('derived_data', [], 'array');
6436
6437 $parent_id = 0;
6438 $derived_info = null;
6439
6440 if ($is_derived && $derived_id && $derived_data) {
6441 $parent_id = $derived_id;
6442 $derived_info = $derived_data;
6443 $derived_info['mode'] = ($derived_info['mode'] ?? '') == 'charge' ? 'charge' : 'discount';
6444 $derived_info['type'] = ($derived_info['type'] ?? '') == 'absolute' ? 'absolute' : 'percent';
6445 $derived_info['value'] = (float) ($derived_info['value'] ?? 0);
6446 $derived_info['follow_restr'] = isset($derived_info['follow_restr']) ? 1 : 0;
6447 if (!$derived_info['value']) {
6448 $parent_id = 0;
6449 $derived_info = null;
6450 }
6451 }
6452
6453 if (!empty($pprice) && $pwhereup) {
6454 $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) . ";";
6455 $dbo->setQuery($q);
6456 $dbo->execute();
6457 }
6458
6459 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6460 $app->close();
6461 }
6462
6463 public function removeprice()
6464 {
6465 if (!JSession::checkToken()) {
6466 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6467 }
6468
6469 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6470 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6471 }
6472
6473 $ids = VikRequest::getVar('cid', array(0));
6474 if ($ids) {
6475 $dbo = JFactory::getDBO();
6476 foreach ($ids as $d) {
6477 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6478 $dbo->setQuery($q);
6479 $dbo->execute();
6480 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6481 $dbo->setQuery($q);
6482 $dbo->execute();
6483 }
6484 }
6485 $mainframe = JFactory::getApplication();
6486 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6487 }
6488
6489 public function iva() {
6490 VikBookingHelper::printHeader("2");
6491
6492 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6493
6494 parent::display();
6495
6496 if (VikBooking::showFooter()) {
6497 VikBookingHelper::printFooter();
6498 }
6499 }
6500
6501 public function newiva() {
6502 VikBookingHelper::printHeader("2");
6503
6504 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6505
6506 parent::display();
6507
6508 if (VikBooking::showFooter()) {
6509 VikBookingHelper::printFooter();
6510 }
6511 }
6512
6513 public function editiva() {
6514 VikBookingHelper::printHeader("2");
6515
6516 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6517
6518 parent::display();
6519
6520 if (VikBooking::showFooter()) {
6521 VikBookingHelper::printFooter();
6522 }
6523 }
6524
6525 public function createiva()
6526 {
6527 if (!JSession::checkToken()) {
6528 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6529 }
6530
6531 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6532 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6533 }
6534
6535 $paliqname = VikRequest::getString('aliqname', '', 'request');
6536 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6537 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6538 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6539 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6540 if (!empty($paliqperc)) {
6541 $dbo = JFactory::getDBO();
6542 $breakdown_str = '';
6543 if (count($pbreakdown_name) > 0) {
6544 $breakdown_values = array();
6545 $bkcount = 0;
6546 $tot_sub_aliq = 0;
6547 foreach ($pbreakdown_name as $key => $subtax) {
6548 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6549 $breakdown_values[$bkcount]['name'] = $subtax;
6550 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6551 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6552 $bkcount++;
6553 }
6554 }
6555 if (count($breakdown_values) > 0) {
6556 $breakdown_str = json_encode($breakdown_values);
6557 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6558 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6559 }
6560 }
6561 }
6562 $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').");";
6563 $dbo->setQuery($q);
6564 $dbo->execute();
6565 }
6566 $mainframe = JFactory::getApplication();
6567 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6568 }
6569
6570 public function updateiva()
6571 {
6572 if (!JSession::checkToken()) {
6573 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6574 }
6575
6576 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6577 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6578 }
6579
6580 $paliqname = VikRequest::getString('aliqname', '', 'request');
6581 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6582 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6583 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6584 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6585 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6586 if (!empty($paliqperc)) {
6587 $dbo = JFactory::getDBO();
6588 $breakdown_str = '';
6589 if (count($pbreakdown_name) > 0) {
6590 $breakdown_values = array();
6591 $bkcount = 0;
6592 $tot_sub_aliq = 0;
6593 foreach ($pbreakdown_name as $key => $subtax) {
6594 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6595 $breakdown_values[$bkcount]['name'] = $subtax;
6596 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6597 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6598 $bkcount++;
6599 }
6600 }
6601 if (count($breakdown_values) > 0) {
6602 $breakdown_str = json_encode($breakdown_values);
6603 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6604 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6605 }
6606 }
6607 }
6608 $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).";";
6609 $dbo->setQuery($q);
6610 $dbo->execute();
6611 }
6612 $mainframe = JFactory::getApplication();
6613 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6614 }
6615
6616 public function removeiva()
6617 {
6618 if (!JSession::checkToken()) {
6619 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6620 }
6621
6622 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6623 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6624 }
6625
6626 $ids = VikRequest::getVar('cid', array(0));
6627 if ($ids) {
6628 $dbo = JFactory::getDBO();
6629 foreach ($ids as $d) {
6630 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6631 $dbo->setQuery($q);
6632 $dbo->execute();
6633 }
6634 }
6635 $mainframe = JFactory::getApplication();
6636 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6637 }
6638
6639 public function categories() {
6640 VikBookingHelper::printHeader("4");
6641
6642 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6643
6644 parent::display();
6645
6646 if (VikBooking::showFooter()) {
6647 VikBookingHelper::printFooter();
6648 }
6649 }
6650
6651 public function newcat() {
6652 VikBookingHelper::printHeader("4");
6653
6654 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6655
6656 parent::display();
6657
6658 if (VikBooking::showFooter()) {
6659 VikBookingHelper::printFooter();
6660 }
6661 }
6662
6663 public function editcat() {
6664 VikBookingHelper::printHeader("4");
6665
6666 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6667
6668 parent::display();
6669
6670 if (VikBooking::showFooter()) {
6671 VikBookingHelper::printFooter();
6672 }
6673 }
6674
6675 public function createcat()
6676 {
6677 if (!JSession::checkToken()) {
6678 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6679 }
6680
6681 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6682 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6683 }
6684
6685 $pcatname = VikRequest::getString('catname', '', 'request');
6686 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6687 if (!empty($pcatname)) {
6688 $dbo = JFactory::getDBO();
6689 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6690 $dbo->setQuery($q);
6691 $dbo->execute();
6692 }
6693 $mainframe = JFactory::getApplication();
6694 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6695 }
6696
6697 public function updatecat()
6698 {
6699 if (!JSession::checkToken()) {
6700 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6701 }
6702
6703 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6704 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6705 }
6706
6707 $pcatname = VikRequest::getString('catname', '', 'request');
6708 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6709 $pwhereup = VikRequest::getString('whereup', '', 'request');
6710 if (!empty($pcatname)) {
6711 $dbo = JFactory::getDBO();
6712 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6713 $dbo->setQuery($q);
6714 $dbo->execute();
6715 }
6716 $mainframe = JFactory::getApplication();
6717 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6718 }
6719
6720 public function removecat()
6721 {
6722 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
6723 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6724 }
6725
6726 $ids = VikRequest::getVar('cid', array(0));
6727 if ($ids) {
6728 $dbo = JFactory::getDBO();
6729 foreach ($ids as $d) {
6730 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6731 $dbo->setQuery($q);
6732 $dbo->execute();
6733 }
6734 }
6735 $mainframe = JFactory::getApplication();
6736 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6737 }
6738
6739 public function carat() {
6740 VikBookingHelper::printHeader("5");
6741
6742 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6743
6744 parent::display();
6745
6746 if (VikBooking::showFooter()) {
6747 VikBookingHelper::printFooter();
6748 }
6749 }
6750
6751 public function newcarat() {
6752 VikBookingHelper::printHeader("5");
6753
6754 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6755
6756 parent::display();
6757
6758 if (VikBooking::showFooter()) {
6759 VikBookingHelper::printFooter();
6760 }
6761 }
6762
6763 public function editcarat() {
6764 VikBookingHelper::printHeader("5");
6765
6766 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6767
6768 parent::display();
6769
6770 if (VikBooking::showFooter()) {
6771 VikBookingHelper::printFooter();
6772 }
6773 }
6774
6775 public function createcarat()
6776 {
6777 if (!JSession::checkToken()) {
6778 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6779 }
6780
6781 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
6782 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6783 }
6784
6785 $pcaratname = VikRequest::getString('caratname', '', 'request');
6786 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6787 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6788 $presizeto = VikRequest::getString('resizeto', '', 'request');
6789 $pidrooms = VikRequest::getVar('idrooms', array());
6790 if (!empty($pcaratname)) {
6791 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6792 jimport('joomla.filesystem.file');
6793 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6794 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6795 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6796 if (file_exists($updpath.$safename)) {
6797 $j=1;
6798 while (file_exists($updpath.$j.$safename)) {
6799 $j++;
6800 }
6801 $pwhere=$updpath.$j.$safename;
6802 } else {
6803 $j="";
6804 $pwhere=$updpath.$safename;
6805 }
6806 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6807 @unlink($pwhere);
6808 $picon="";
6809 } else {
6810 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6811 @chmod($pwhere, 0644);
6812 $picon=$j.$safename;
6813 if ($pautoresize=="1" && !empty($presizeto)) {
6814 $eforj = new vikResizer();
6815 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6816 if ($origmod) {
6817 @unlink($pwhere);
6818 $picon='r_'.$j.$safename;
6819 }
6820 }
6821 }
6822 } else {
6823 $picon="";
6824 }
6825 } else {
6826 $picon="";
6827 }
6828 $dbo = JFactory::getDbo();
6829 // get new ordering
6830 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6831 $dbo->setQuery($q);
6832 $dbo->execute();
6833 if ($dbo->getNumRows()) {
6834 $newsortnum = $dbo->loadResult() + 1;
6835 } else {
6836 $newsortnum = 1;
6837 }
6838 $pordering = VikRequest::getInt('ordering', 0, 'request');
6839 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6840 //
6841 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6842 $dbo->setQuery($q);
6843 $dbo->execute();
6844
6845 $new_carat_id = $dbo->insertid();
6846 if (!empty($new_carat_id)) {
6847 // assign/unset carat-rooms relations
6848 $rooms_with_carat = array();
6849 if (count($pidrooms)) {
6850 // assign this new carat to the requested rooms
6851 foreach ($pidrooms as $idroom) {
6852 if (empty($idroom)) {
6853 continue;
6854 }
6855 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6856 $dbo->setQuery($q);
6857 $dbo->execute();
6858 if (!$dbo->getNumRows()) {
6859 continue;
6860 }
6861 $room_data = $dbo->loadAssoc();
6862 array_push($rooms_with_carat, $room_data['id']);
6863 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6864 if (in_array((string)$new_carat_id, $current_carats)) {
6865 continue;
6866 }
6867 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6868 // make sure we do not concatenate a real ID to 0
6869 $current_carats = array();
6870 }
6871 array_push($current_carats, $new_carat_id);
6872 $new_opts = implode(';', $current_carats) . ';';
6873 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6874 $dbo->setQuery($q);
6875 $dbo->execute();
6876 }
6877 }
6878 if (!count($rooms_with_carat)) {
6879 // get all rooms to unset this carat (if previously set)
6880 array_push($rooms_with_carat, '0');
6881 }
6882 // unset the carat from the other rooms that may have it
6883 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6884 $dbo->setQuery($q);
6885 $dbo->execute();
6886 if ($dbo->getNumRows()) {
6887 $unset_rooms_carat = $dbo->loadAssocList();
6888 foreach ($unset_rooms_carat as $room_data) {
6889 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6890 if (!in_array((string)$new_carat_id, $current_carats)) {
6891 // this room is not using this carat
6892 continue;
6893 }
6894 $caratkey = array_search((string)$new_carat_id, $current_carats);
6895 if ($caratkey === false) {
6896 // key not found
6897 continue;
6898 }
6899 // unset this carat ID from the string
6900 unset($current_carats[$caratkey]);
6901 if (!count($current_carats)) {
6902 // a room with no carats assigned will be listed as "0;"
6903 $current_carats = array(0);
6904 }
6905 $new_opts = implode(';', $current_carats) . ';';
6906 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6907 $dbo->setQuery($q);
6908 $dbo->execute();
6909 }
6910 }
6911 //
6912 }
6913 }
6914 $mainframe = JFactory::getApplication();
6915 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6916 }
6917
6918 public function updatecarat()
6919 {
6920 if (!JSession::checkToken()) {
6921 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6922 }
6923
6924 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
6925 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
6926 }
6927
6928 $pcaratname = VikRequest::getString('caratname', '', 'request');
6929 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWRAW);
6930 $pwhereup = VikRequest::getString('whereup', '', 'request');
6931 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6932 $presizeto = VikRequest::getString('resizeto', '', 'request');
6933 $pidrooms = VikRequest::getVar('idrooms', array());
6934 $pordering = VikRequest::getInt('ordering', 1, 'request');
6935 if (!empty($pcaratname)) {
6936 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6937 jimport('joomla.filesystem.file');
6938 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6939 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6940 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6941 if (file_exists($updpath.$safename)) {
6942 $j=1;
6943 while (file_exists($updpath.$j.$safename)) {
6944 $j++;
6945 }
6946 $pwhere=$updpath.$j.$safename;
6947 } else {
6948 $j="";
6949 $pwhere=$updpath.$safename;
6950 }
6951 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6952 @unlink($pwhere);
6953 $picon="";
6954 } else {
6955 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6956 @chmod($pwhere, 0644);
6957 $picon=$j.$safename;
6958 if ($pautoresize=="1" && !empty($presizeto)) {
6959 $eforj = new vikResizer();
6960 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6961 if ($origmod) {
6962 @unlink($pwhere);
6963 $picon='r_'.$j.$safename;
6964 }
6965 }
6966 }
6967 } else {
6968 $picon="";
6969 }
6970 } else {
6971 $picon="";
6972 }
6973 $dbo = JFactory::getDbo();
6974 $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).";";
6975 $dbo->setQuery($q);
6976 $dbo->execute();
6977
6978 // assign/unset carat-rooms relations
6979 $rooms_with_carat = array();
6980 if (count($pidrooms)) {
6981 // assign this new carat to the requested rooms
6982 foreach ($pidrooms as $idroom) {
6983 if (empty($idroom)) {
6984 continue;
6985 }
6986 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6987 $dbo->setQuery($q);
6988 $dbo->execute();
6989 if (!$dbo->getNumRows()) {
6990 continue;
6991 }
6992 $room_data = $dbo->loadAssoc();
6993 array_push($rooms_with_carat, $room_data['id']);
6994 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6995 if (in_array((string)$pwhereup, $current_carats)) {
6996 continue;
6997 }
6998 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6999 // make sure we do not concatenate a real ID to 0
7000 $current_carats = array();
7001 }
7002 array_push($current_carats, $pwhereup);
7003 $new_carats = implode(';', $current_carats) . ';';
7004 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7005 $dbo->setQuery($q);
7006 $dbo->execute();
7007 }
7008 }
7009 if (!count($rooms_with_carat)) {
7010 // get all rooms to unset this carat (if previously set)
7011 array_push($rooms_with_carat, '0');
7012 }
7013 // unset the carat from the other rooms that may have it
7014 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
7015 $dbo->setQuery($q);
7016 $dbo->execute();
7017 if ($dbo->getNumRows()) {
7018 $unset_rooms_carat = $dbo->loadAssocList();
7019 foreach ($unset_rooms_carat as $room_data) {
7020 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
7021 if (!in_array((string)$pwhereup, $current_carats)) {
7022 // this room is not using this carat
7023 continue;
7024 }
7025 $caratkey = array_search((string)$pwhereup, $current_carats);
7026 if ($caratkey === false) {
7027 // key not found
7028 continue;
7029 }
7030 // unset this carat ID from the string
7031 unset($current_carats[$caratkey]);
7032 if (!count($current_carats)) {
7033 // a room with no carats assigned will be listed as "0;"
7034 $current_carats = array(0);
7035 }
7036 $new_carats = implode(';', $current_carats) . ';';
7037 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
7038 $dbo->setQuery($q);
7039 $dbo->execute();
7040 }
7041 }
7042 //
7043 }
7044 $mainframe = JFactory::getApplication();
7045 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7046 }
7047
7048 public function removecarat()
7049 {
7050 if (!JSession::checkToken()) {
7051 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7052 }
7053
7054 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7055 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7056 }
7057
7058 $ids = VikRequest::getVar('cid', array(0));
7059 if ($ids) {
7060 $dbo = JFactory::getDBO();
7061 foreach ($ids as $d) {
7062 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7063 $dbo->setQuery($q);
7064 $dbo->execute();
7065 if ($dbo->getNumRows() == 1) {
7066 $rows = $dbo->loadAssocList();
7067 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
7068 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
7069 }
7070 }
7071 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
7072 $dbo->setQuery($q);
7073 $dbo->execute();
7074 }
7075 }
7076 $mainframe = JFactory::getApplication();
7077 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
7078 }
7079
7080 public function coupons() {
7081 VikBookingHelper::printHeader("17");
7082
7083 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
7084
7085 parent::display();
7086
7087 if (VikBooking::showFooter()) {
7088 VikBookingHelper::printFooter();
7089 }
7090 }
7091
7092 public function newcoupon() {
7093 VikBookingHelper::printHeader("17");
7094
7095 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7096
7097 parent::display();
7098
7099 if (VikBooking::showFooter()) {
7100 VikBookingHelper::printFooter();
7101 }
7102 }
7103
7104 public function editcoupon() {
7105 VikBookingHelper::printHeader("17");
7106
7107 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
7108
7109 parent::display();
7110
7111 if (VikBooking::showFooter()) {
7112 VikBookingHelper::printFooter();
7113 }
7114 }
7115
7116 public function createcoupon()
7117 {
7118 if (!JSession::checkToken()) {
7119 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7120 }
7121
7122 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7123 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7124 }
7125
7126 $pcode = VikRequest::getString('code', '', 'request');
7127 $pvalue = VikRequest::getString('value', '', 'request');
7128 $pfrom = VikRequest::getString('from', '', 'request');
7129 $pto = VikRequest::getString('to', '', 'request');
7130 $pidrooms = VikRequest::getVar('idrooms', array(0));
7131 $ptype = VikRequest::getString('type', '', 'request');
7132 $ptype = $ptype == "1" ? 1 : 2;
7133 $ppercentot = VikRequest::getString('percentot', '', 'request');
7134 $ppercentot = $ppercentot == "1" ? 1 : 2;
7135 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7136 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7137 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7138 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7139 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7140 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7141 $pcustomers = VikRequest::getVar('customers', array());
7142 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7143 $stridrooms = "";
7144 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7145 foreach ($pidrooms as $ch) {
7146 if (!empty($ch)) {
7147 $stridrooms .= ";".$ch.";";
7148 }
7149 }
7150 }
7151 $strdatevalid = "";
7152 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7153 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7154 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7155 if ($first < $second) {
7156 $strdatevalid .= $first."-".$second;
7157 }
7158 }
7159
7160 $dbo = JFactory::getDbo();
7161 $app = JFactory::getApplication();
7162
7163 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
7164 $dbo->setQuery($q);
7165 $dbo->execute();
7166 if ($dbo->getNumRows() > 0) {
7167 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7168 } else {
7169 $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) . ");";
7170 $dbo->setQuery($q);
7171 $dbo->execute();
7172
7173 $id_coupon = $dbo->insertid();
7174
7175 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7176
7177 // check if this coupon should be assigned to specific customers
7178 foreach ($pcustomers as $id_customer) {
7179 $customer_coupon = new stdClass;
7180 $customer_coupon->idcustomer = (int)$id_customer;
7181 $customer_coupon->idcoupon = (int)$id_coupon;
7182 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7183
7184 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7185 }
7186 }
7187 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7188 }
7189
7190 public function updatecoupon()
7191 {
7192 if (!JSession::checkToken()) {
7193 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7194 }
7195
7196 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7197 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7198 }
7199
7200 $this->do_updatecoupon($stay = false);
7201 }
7202
7203 public function updatecoupon_stay()
7204 {
7205 if (!JSession::checkToken()) {
7206 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7207 }
7208
7209 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7210 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7211 }
7212
7213 $this->do_updatecoupon($stay = true);
7214 }
7215
7216 protected function do_updatecoupon($stay = false)
7217 {
7218 if (!JSession::checkToken()) {
7219 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7220 }
7221 $pcode = VikRequest::getString('code', '', 'request');
7222 $pvalue = VikRequest::getString('value', '', 'request');
7223 $pfrom = VikRequest::getString('from', '', 'request');
7224 $pto = VikRequest::getString('to', '', 'request');
7225 $pidrooms = VikRequest::getVar('idrooms', array(0));
7226 $pwhere = VikRequest::getInt('where', 0, 'request');
7227 $ptype = VikRequest::getString('type', '', 'request');
7228 $ptype = $ptype == "1" ? 1 : 2;
7229 $ppercentot = VikRequest::getString('percentot', '', 'request');
7230 $ppercentot = $ppercentot == "1" ? 1 : 2;
7231 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
7232 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
7233 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
7234 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
7235 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
7236 $pminlos = VikRequest::getInt('minlos', 0, 'request');
7237 $pcustomers = VikRequest::getVar('customers', array());
7238 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
7239 $stridrooms = "";
7240 if (count($pidrooms) > 0 && $pallvehicles != 1) {
7241 foreach ($pidrooms as $ch) {
7242 if (!empty($ch)) {
7243 $stridrooms .= ";".$ch.";";
7244 }
7245 }
7246 }
7247 $strdatevalid = "";
7248 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
7249 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
7250 $second = VikBooking::getDateTimestamp($pto, 0, 0);
7251 if ($first < $second) {
7252 $strdatevalid .= $first."-".$second;
7253 }
7254 }
7255
7256 $dbo = JFactory::getDbo();
7257 $app = JFactory::getApplication();
7258
7259 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
7260 $dbo->setQuery($q);
7261 $dbo->execute();
7262 if ($dbo->getNumRows() > 0) {
7263 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
7264 } else {
7265 $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 . ";";
7266 $dbo->setQuery($q);
7267 $dbo->execute();
7268
7269 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
7270
7271 // clean up any previously created record with customers
7272 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
7273 $dbo->setQuery($q);
7274 $dbo->execute();
7275
7276 // check if this coupon should be assigned to specific customers
7277 foreach ($pcustomers as $id_customer) {
7278 $customer_coupon = new stdClass;
7279 $customer_coupon->idcustomer = (int)$id_customer;
7280 $customer_coupon->idcoupon = (int)$pwhere;
7281 $customer_coupon->automatic = $pautomatic ? 1 : 0;
7282
7283 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
7284 }
7285 }
7286
7287 if ($stay) {
7288 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
7289 } else {
7290 $app->redirect("index.php?option=com_vikbooking&task=coupons");
7291 }
7292 }
7293
7294 public function removecoupons()
7295 {
7296 if (!JSession::checkToken()) {
7297 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7298 }
7299
7300 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7301 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7302 }
7303
7304 $dbo = JFactory::getDbo();
7305
7306 $ids = VikRequest::getVar('cid', array(0));
7307
7308 if ($ids) {
7309 foreach ($ids as $d) {
7310 // delete coupon record
7311 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
7312 $dbo->setQuery($q);
7313 $dbo->execute();
7314
7315 // clean up any previously created record with customers
7316 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
7317 $dbo->setQuery($q);
7318 $dbo->execute();
7319 }
7320 }
7321
7322 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
7323 }
7324
7325 public function removemoreimgs()
7326 {
7327 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7328 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7329 }
7330
7331 $mainframe = JFactory::getApplication();
7332 $proomid = VikRequest::getInt('roomid', '', 'request');
7333 $pimgind = VikRequest::getInt('imgind', '', 'request');
7334 if (!strlen($pimgind)) {
7335 $mainframe->redirect("index.php?option=com_vikbooking");
7336 exit;
7337 }
7338 $dbo = JFactory::getDBO();
7339 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
7340 $dbo->setQuery($q);
7341 $dbo->execute();
7342 $row = $dbo->loadAssoc();
7343 $actmore = $row['moreimgs'];
7344 if (!empty($actmore)) {
7345 $actsplit = explode(';;', $actmore);
7346 $captions = json_decode($row['imgcaptions'], true);
7347 $captions = !is_array($captions) ? array() : $captions;
7348 if ($pimgind < 0) {
7349 foreach ($actsplit as $img) {
7350 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
7351 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
7352 }
7353 // reset images and captions
7354 $actsplit = array();
7355 $captions = array();
7356 } else {
7357 if (array_key_exists($pimgind, $actsplit)) {
7358 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
7359 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
7360 // unset current image
7361 unset($actsplit[$pimgind]);
7362 // unset caption if exists
7363 if (isset($captions[$pimgind])) {
7364 unset($captions[$pimgind]);
7365 $captions = array_values($captions);
7366 }
7367 }
7368 }
7369 $newstr = "";
7370 foreach ($actsplit as $oi) {
7371 if (!empty($oi)) {
7372 $newstr .= $oi.';;';
7373 }
7374 }
7375 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
7376 $dbo->setQuery($q);
7377 $dbo->execute();
7378 }
7379 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
7380 }
7381
7382 public function sortfield() {
7383 if (!JSession::checkToken('get')) {
7384 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7385 }
7386 $mainframe = JFactory::getApplication();
7387 $sortid = VikRequest::getVar('cid', array(0));
7388 $pmode = VikRequest::getString('mode', '', 'request');
7389 $dbo = JFactory::getDBO();
7390 if (!empty($pmode)) {
7391 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7392 $dbo->setQuery($q);
7393 $dbo->execute();
7394 $totr=$dbo->getNumRows();
7395 if ($totr > 1) {
7396 $data = $dbo->loadAssocList();
7397 if ($pmode == "up") {
7398 foreach ($data as $v) {
7399 if ($v['id'] == $sortid[0]) {
7400 $y = $v['ordering'];
7401 }
7402 }
7403 if ($y && $y > 1) {
7404 $vik = $y - 1;
7405 $found = false;
7406 foreach ($data as $v) {
7407 if (intval($v['ordering']) == intval($vik)) {
7408 $found=true;
7409 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7410 $dbo->setQuery($q);
7411 $dbo->execute();
7412 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7413 $dbo->setQuery($q);
7414 $dbo->execute();
7415 break;
7416 }
7417 }
7418 if (!$found) {
7419 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7420 $dbo->setQuery($q);
7421 $dbo->execute();
7422 }
7423 }
7424 } elseif ($pmode == "down") {
7425 foreach ($data as $v) {
7426 if ($v['id'] == $sortid[0]) {
7427 $y = $v['ordering'];
7428 }
7429 }
7430 if ($y) {
7431 $vik = $y + 1;
7432 $found = false;
7433 foreach ($data as $v) {
7434 if (intval($v['ordering']) == intval($vik)) {
7435 $found=true;
7436 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7437 $dbo->setQuery($q);
7438 $dbo->execute();
7439 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7440 $dbo->setQuery($q);
7441 $dbo->execute();
7442 break;
7443 }
7444 }
7445 if (!$found) {
7446 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7447 $dbo->setQuery($q);
7448 $dbo->execute();
7449 }
7450 }
7451 }
7452 }
7453 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7454 } else {
7455 $mainframe->redirect("index.php?option=com_vikbooking");
7456 }
7457 }
7458
7459 public function customf() {
7460 VikBookingHelper::printHeader("16");
7461
7462 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7463
7464 parent::display();
7465
7466 if (VikBooking::showFooter()) {
7467 VikBookingHelper::printFooter();
7468 }
7469 }
7470
7471 public function newcustomf() {
7472 VikBookingHelper::printHeader("16");
7473
7474 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7475
7476 parent::display();
7477
7478 if (VikBooking::showFooter()) {
7479 VikBookingHelper::printFooter();
7480 }
7481 }
7482
7483 public function editcustomf() {
7484 VikBookingHelper::printHeader("16");
7485
7486 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7487
7488 parent::display();
7489
7490 if (VikBooking::showFooter()) {
7491 VikBookingHelper::printFooter();
7492 }
7493 }
7494
7495 public function createcustomf()
7496 {
7497 if (!JSession::checkToken()) {
7498 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7499 }
7500
7501 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
7502 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7503 }
7504
7505 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7506 $ptype = VikRequest::getString('type', '', 'request');
7507 $pchoose = VikRequest::getVar('choose', array(0));
7508 $prequired = VikRequest::getString('required', '', 'request');
7509 $prequired = $prequired == "1" ? 1 : 0;
7510 $pflag = VikRequest::getString('flag', '', 'request');
7511 $pisemail = $pflag == 'isemail' ? 1 : 0;
7512 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7513 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7514 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7515 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7516 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7517 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7518 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7519 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7520 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7521 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7522 $fieldflag = '';
7523 if ($pisaddress == 1) {
7524 $fieldflag = 'address';
7525 } elseif ($piscity == 1) {
7526 $fieldflag = 'city';
7527 } elseif ($piszip == 1) {
7528 $fieldflag = 'zip';
7529 } elseif ($piscompany == 1) {
7530 $fieldflag = 'company';
7531 } elseif ($pisvat == 1) {
7532 $fieldflag = 'vat';
7533 } elseif ($pisfisccode == 1) {
7534 $fieldflag = 'fisccode';
7535 } elseif ($pispec == 1) {
7536 $fieldflag = 'pec';
7537 } elseif ($pisrecipcode == 1) {
7538 $fieldflag = 'recipcode';
7539 }
7540 $ppoplink = VikRequest::getString('poplink', '', 'request');
7541 $choosestr = "";
7542 if (is_array($pchoose)) {
7543 foreach ($pchoose as $ch) {
7544 if (!empty($ch)) {
7545 $choosestr .= $ch.";;__;;";
7546 }
7547 }
7548 }
7549 $defvalue = VikRequest::getString('defvalue', '', 'request');
7550
7551 $dbo = JFactory::getDbo();
7552
7553 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7554 $dbo->setQuery($q);
7555 $dbo->execute();
7556 if ($dbo->getNumRows() == 1) {
7557 $getlast = $dbo->loadResult();
7558 $newsortnum = $getlast + 1;
7559 } else {
7560 $newsortnum = 1;
7561 }
7562 $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).");";
7563 $dbo->setQuery($q);
7564 $dbo->execute();
7565 $mainframe = JFactory::getApplication();
7566 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7567 }
7568
7569 public function updatecustomf()
7570 {
7571 if (!JSession::checkToken()) {
7572 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7573 }
7574
7575 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
7576 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7577 }
7578
7579 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7580 $ptype = VikRequest::getString('type', '', 'request');
7581 $pchoose = VikRequest::getVar('choose', array(0));
7582 $prequired = VikRequest::getString('required', '', 'request');
7583 $prequired = $prequired == "1" ? 1 : 0;
7584 $pflag = VikRequest::getString('flag', '', 'request');
7585 $pisemail = $pflag == 'isemail' ? 1 : 0;
7586 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7587 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7588 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7589 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7590 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7591 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7592 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7593 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7594 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7595 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7596 $fieldflag = '';
7597 if ($pisaddress == 1) {
7598 $fieldflag = 'address';
7599 } elseif ($piscity == 1) {
7600 $fieldflag = 'city';
7601 } elseif ($piszip == 1) {
7602 $fieldflag = 'zip';
7603 } elseif ($piscompany == 1) {
7604 $fieldflag = 'company';
7605 } elseif ($pisvat == 1) {
7606 $fieldflag = 'vat';
7607 } elseif ($pisfisccode == 1) {
7608 $fieldflag = 'fisccode';
7609 } elseif ($pispec == 1) {
7610 $fieldflag = 'pec';
7611 } elseif ($pisrecipcode == 1) {
7612 $fieldflag = 'recipcode';
7613 }
7614 $ppoplink = VikRequest::getString('poplink', '', 'request');
7615 $pwhere = VikRequest::getInt('where', '', 'request');
7616 $choosestr = "";
7617 if (is_array($pchoose)) {
7618 foreach ($pchoose as $ch) {
7619 if (!empty($ch)) {
7620 $choosestr .= $ch.";;__;;";
7621 }
7622 }
7623 }
7624 $defvalue = VikRequest::getString('defvalue', '', 'request');
7625
7626 $dbo = JFactory::getDbo();
7627
7628 $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).";";
7629 $dbo->setQuery($q);
7630 $dbo->execute();
7631 $mainframe = JFactory::getApplication();
7632 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7633 }
7634
7635 public function removecustomf()
7636 {
7637 if (!JSession::checkToken()) {
7638 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7639 }
7640
7641 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7642 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7643 }
7644
7645 $ids = VikRequest::getVar('cid', array(0));
7646 if ($ids) {
7647 $dbo = JFactory::getDBO();
7648 foreach ($ids as $d) {
7649 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7650 $dbo->setQuery($q);
7651 $dbo->execute();
7652 }
7653 }
7654 $mainframe = JFactory::getApplication();
7655 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7656 }
7657
7658 public function overv() {
7659 VikBookingHelper::printHeader("15");
7660
7661 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7662
7663 parent::display();
7664
7665 if (VikBooking::showFooter()) {
7666 VikBookingHelper::printFooter();
7667 }
7668 }
7669
7670 public function translations() {
7671 VikBookingHelper::printHeader("21");
7672
7673 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7674
7675 parent::display();
7676
7677 if (VikBooking::showFooter()) {
7678 VikBookingHelper::printFooter();
7679 }
7680 }
7681
7682 public function savetranslation() {
7683 if (!JSession::checkToken()) {
7684 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7685 }
7686 $this->do_savetranslation();
7687 }
7688
7689 public function savetranslationstay() {
7690 if (!JSession::checkToken()) {
7691 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7692 }
7693 $this->do_savetranslation(true);
7694 }
7695
7696 private function do_savetranslation($stay = false) {
7697 $dbo = JFactory::getDBO();
7698 $mainframe = JFactory::getApplication();
7699 $vbo_tn = VikBooking::getTranslator();
7700 $table = VikRequest::getString('vbo_table', '', 'request');
7701 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7702 $langs = $vbo_tn->getLanguagesList();
7703 $xml_tables = $vbo_tn->getTranslationTables();
7704 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7705 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7706 $tn_saved = 0;
7707 $table_cols = $vbo_tn->getTableColumns($table);
7708 foreach ($langs as $ltag => $lang) {
7709 if ($ltag == $vbo_tn->default_lang) {
7710 continue;
7711 }
7712 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7713 foreach ($tn[$ltag] as $reference_id => $translation) {
7714 $lang_translation = array();
7715 foreach ($table_cols as $field => $fdetails) {
7716 if (!array_key_exists($field, $translation)) {
7717 continue;
7718 }
7719 $ftype = $fdetails['type'];
7720 if ($ftype == 'skip') {
7721 continue;
7722 }
7723
7724 if (is_array($translation[$field])) {
7725 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7726 if (!is_string($tn_field_v)) {
7727 continue;
7728 }
7729 // replace any possible placeholder for special tags
7730 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7731 return $match[2];
7732 }, $translation[$field][$tn_field_k]);
7733 }
7734 } elseif (!empty($translation[$field])) {
7735 // replace any possible placeholder for special tags
7736 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7737 return $match[2];
7738 }, $translation[$field]);
7739 }
7740
7741 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7742 $translation[$field] = json_encode($translation[$field]);
7743 }
7744 $lang_translation[$field] = $translation[$field];
7745 }
7746 if (count($lang_translation) > 0) {
7747 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7748 $dbo->setQuery($q);
7749 $dbo->execute();
7750 if ($dbo->getNumRows() > 0) {
7751 $last_id = $dbo->loadResult();
7752 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7753 } else {
7754 $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)).");";
7755 }
7756 $dbo->setQuery($q);
7757 $dbo->execute();
7758 $tn_saved++;
7759 }
7760 }
7761 }
7762 }
7763 if ($tn_saved > 0) {
7764 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7765 }
7766 } else {
7767 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7768 }
7769 $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);
7770 }
7771
7772 public function choosebusy() {
7773 VikBookingHelper::printHeader("8");
7774
7775 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7776
7777 parent::display();
7778
7779 if (VikBooking::showFooter()) {
7780 VikBookingHelper::printFooter();
7781 }
7782 }
7783
7784 public function orders() {
7785 VikBookingHelper::printHeader("8");
7786
7787 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7788
7789 parent::display();
7790
7791 if (VikBooking::showFooter()) {
7792 VikBookingHelper::printFooter();
7793 }
7794 }
7795
7796 public function vieworders() {
7797 //alias method of orders() for backward compatibility with VCM
7798 $this->orders();
7799 }
7800
7801 public function editorder() {
7802 VikBookingHelper::printHeader("8");
7803
7804 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7805
7806 parent::display();
7807
7808 if (VikBooking::showFooter()) {
7809 VikBookingHelper::printFooter();
7810 }
7811 }
7812
7813 public function removeorders()
7814 {
7815 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
7816 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7817 }
7818
7819 $dbo = JFactory::getDbo();
7820 $app = JFactory::getApplication();
7821
7822 $ids = VikRequest::getVar('cid', array(0));
7823 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7824
7825 $user = JFactory::getUser();
7826 $config = VBOFactory::getConfig();
7827
7828 $prev_conf_ids = [];
7829 $purged = false;
7830
7831 $tot_cancs = 0;
7832
7833 if (is_array($ids) && count($ids)) {
7834 foreach ($ids as $d) {
7835 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7836 $dbo->setQuery($q, 0, 1);
7837 $row = $dbo->loadAssoc();
7838
7839 // check for any cancellation constraints
7840 $canc_denied = false;
7841 if ($row && class_exists('VCMFeesCancellation')) {
7842 // let VCM detect if there are any constraints for the cancellation
7843 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7844 if ($canc_denied) {
7845 // set error message
7846 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7847 if ($canc_deny_error) {
7848 $app->enqueueMessage($canc_deny_error, 'error');
7849 }
7850 }
7851 }
7852
7853 if ($row && !$canc_denied) {
7854 // increase counter
7855 $tot_cancs++;
7856
7857 // set status to cancelled
7858 if ($row['status'] != 'cancelled') {
7859 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7860 $dbo->setQuery($q);
7861 $dbo->execute();
7862 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7863 $dbo->setQuery($q);
7864 $dbo->execute();
7865 if ($row['status'] == 'confirmed') {
7866 $prev_conf_ids[] = $row['id'];
7867 }
7868 // Booking History
7869 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7870 }
7871
7872 /**
7873 * In case of pending bookings being cancelled, schedule the release through VCM.
7874 *
7875 * @since 1.18.8 (J) - 1.8.8 (WP)
7876 */
7877 if ($row['status'] == 'standby' && method_exists('VCMRequestAvailability', 'setForRelease')) {
7878 // let the CM schedule the release of the involved and unconfirmed booking IDs, if needed
7879 VCMRequestAvailability::getInstance()->setForRelease([$row['id']]);
7880 }
7881
7882 // free records up
7883 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7884 $dbo->setQuery($q);
7885 $ordbusy = $dbo->loadAssocList();
7886 if ($ordbusy) {
7887 foreach ($ordbusy as $ob) {
7888 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7889 $dbo->setQuery($q);
7890 $dbo->execute();
7891 }
7892 }
7893
7894 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7895 $dbo->setQuery($q);
7896 $dbo->execute();
7897
7898 // check for purge removal
7899 if ($row['status'] == 'cancelled') {
7900 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7901 $dbo->setQuery($q);
7902 $dbo->execute();
7903 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7904 $dbo->setQuery($q);
7905 $dbo->execute();
7906 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7907 $dbo->setQuery($q);
7908 $dbo->execute();
7909 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7910 $dbo->setQuery($q);
7911 $dbo->execute();
7912 // in case of split stay booking, remove the transient
7913 if ($row['split_stay']) {
7914 $config->remove('split_stay_' . $row['id']);
7915 }
7916 // turn flag on
7917 $purged = true;
7918 }
7919 }
7920 }
7921
7922 if ($tot_cancs) {
7923 // enqueue system message
7924 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7925 }
7926 }
7927
7928 if ($prev_conf_ids) {
7929 $prev_conf_ids_str = '';
7930 foreach ($prev_conf_ids as $prev_id) {
7931 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7932 }
7933 //Invoke Channel Manager
7934 $vcm_autosync = VikBooking::vcmAutoUpdate();
7935 if ($vcm_autosync > 0) {
7936 $vcm_obj = VikBooking::getVcmInvoker();
7937 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7938 $sync_result = $vcm_obj->doSync();
7939 if ($sync_result === false) {
7940 $vcm_err = $vcm_obj->getError();
7941 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7942 }
7943 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7944 $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');
7945 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7946 }
7947 //
7948 }
7949
7950 if (!empty($pgoto)) {
7951 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7952 if ($purged) {
7953 // go back to the bookings list page
7954 $app->redirect("index.php?option=com_vikbooking&task=orders");
7955 } else {
7956 // go back to the booking details page
7957 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7958 }
7959 exit;
7960 }
7961 // we expect the goto URL to be base64 encoded
7962 $app->redirect(base64_decode($pgoto));
7963 exit;
7964 }
7965
7966 // go back to the bookings list page
7967 $app->redirect("index.php?option=com_vikbooking&task=orders");
7968 }
7969
7970 public function config() {
7971 VikBookingHelper::printHeader("11");
7972
7973 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7974
7975 parent::display();
7976
7977 if (VikBooking::showFooter()) {
7978 VikBookingHelper::printFooter();
7979 }
7980 }
7981
7982 public function saveconfig()
7983 {
7984 if (!JSession::checkToken()) {
7985 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7986 }
7987
7988 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking') || !JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
7989 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
7990 }
7991
7992 $dbo = JFactory::getDbo();
7993 $app = JFactory::getApplication();
7994
7995 $config = VBOFactory::getConfig();
7996
7997 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7998 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7999 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
8000 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
8001 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
8002 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
8003 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
8004 $pdateformat = VikRequest::getString('dateformat', '', 'request');
8005 $pdatesep = VikRequest::getString('datesep', '', 'request');
8006 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
8007 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
8008 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
8009 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
8010 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
8011 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
8012 $ptokenform = VikRequest::getString('tokenform', '', 'request');
8013 $padminemail = VikRequest::getString('adminemail', '', 'request');
8014 $psenderemail = VikRequest::getString('senderemail', '', 'request');
8015 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
8016 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
8017 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
8018 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
8019 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
8020 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
8021 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
8022 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
8023 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
8024 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
8025 $pusefa = VikRequest::getInt('usefa', '', 'request');
8026 $pusefa = $pusefa > 0 ? 1 : 0;
8027 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
8028 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
8029 $pcalendar = VikRequest::getString('calendar', '', 'request');
8030 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
8031 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
8032 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
8033 $penablepin = VikRequest::getString('enablepin', '', 'request');
8034 $penablepin = $penablepin == "1" ? 1 : 0;
8035 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
8036 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
8037 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
8038 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
8039 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
8040 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
8041 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
8042 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
8043 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
8044 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
8045 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
8046 $pnumadultsfrom = '1';
8047 $pnumadultsto = '10';
8048 }
8049 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
8050 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
8051 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
8052 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
8053 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
8054 $pnumadultsfrom = '1';
8055 $pnumadultsto = '4';
8056 }
8057 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
8058 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
8059 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
8060 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
8061 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
8062 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
8063 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
8064 $pcronkey = VikRequest::getString('cronkey', '', 'request');
8065 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
8066 $pcdsto = VikRequest::getVar('cdsto', array());
8067 $closing_dates = array();
8068 if (count($pcdsfrom)) {
8069 foreach ($pcdsfrom as $kcd => $vcdfrom) {
8070 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
8071 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
8072 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
8073 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
8074 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
8075 if (!in_array($cdval, $closing_dates)) {
8076 $closing_dates[] = $cdval;
8077 }
8078 }
8079 }
8080 }
8081 }
8082 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
8083 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
8084 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
8085 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8086 if ($pvbosef === 1) {
8087 if (!$vbosef) {
8088 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
8089 }
8090 } else {
8091 if ($vbosef) {
8092 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
8093 }
8094 }
8095 $pmultilang = VikRequest::getString('multilang', '', 'request');
8096 $pmultilang = $pmultilang == "1" ? 1 : 0;
8097 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
8098 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
8099 /**
8100 * Chat params and configuration settings
8101 *
8102 * @since 1.12
8103 */
8104 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
8105 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
8106 $config->set('chatenabled', $pchatenabled);
8107
8108 // chat params
8109 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
8110 $chat_res_status = array();
8111 foreach ($pchat_res_status as $chatrs) {
8112 if (!empty($chatrs)) {
8113 array_push($chat_res_status, $chatrs);
8114 }
8115 }
8116 $chatparams = new stdClass;
8117 $chatparams->res_status = $chat_res_status;
8118 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
8119 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
8120
8121 $config->set('chatparams', $chatparams);
8122 }
8123
8124 /**
8125 * Pre check-in configuration settings
8126 *
8127 * @since 1.12
8128 */
8129 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
8130 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
8131
8132 $config->set('precheckinenabled', $pprecheckinenabled);
8133 // this may be a negative integer, it should not be unsigned
8134 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
8135
8136 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
8137 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
8138 $config->set('upselling', $pupsellingenabled);
8139
8140 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
8141 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
8142 $config->set('orphanscalculation', $porphanscal);
8143
8144 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
8145 $config->set('searchrestmpl', $psrcrtpl);
8146
8147 /**
8148 * Guest Reviews settings
8149 *
8150 * @since 1.13
8151 */
8152 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
8153 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
8154 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
8155 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
8156 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
8157 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
8158 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
8159 $config->set('grenabled', $pgrenabled);
8160 $config->set('grminchars', $pgrminchars);
8161 $config->set('grappr', $pgrappr);
8162 $config->set('grtype', $pgrtype);
8163 try {
8164 // always truncate service names (this query may require special permissions)
8165 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
8166 $dbo->setQuery($q);
8167 $dbo->execute();
8168 } catch (Exception $e) {
8169 // do nothing
8170 }
8171 foreach ($pgrsrv as $srvname) {
8172 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
8173 $dbo->setQuery($q);
8174 $dbo->execute();
8175 }
8176
8177 /**
8178 * Preferred countries ordering, or custom countries.
8179 *
8180 * @since 1.14 (J) - 1.3.11 (WP)
8181 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
8182 */
8183 $pref_countries = VikRequest::getVar('pref_countries', array());
8184 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
8185 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
8186 if (!empty($cust_pref_countries)) {
8187 $all_custom_prefcountries = array();
8188 $cust_pref_countries = explode(',', $cust_pref_countries);
8189 foreach ($cust_pref_countries as $cust_pref_country) {
8190 $cust_pref_country = trim(strtolower($cust_pref_country));
8191 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
8192 continue;
8193 }
8194 array_push($all_custom_prefcountries, $cust_pref_country);
8195 }
8196 if (count($all_custom_prefcountries)) {
8197 $pref_countries = $all_custom_prefcountries;
8198 }
8199 }
8200 $config->set('preferred_countries', $pref_countries);
8201 //
8202
8203 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
8204 $config->set('gmapskey', $gmapskey);
8205
8206 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
8207 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
8208 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
8209 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
8210 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
8211 $pref_colors = array(
8212 'textcolor' => $pref_textcolor,
8213 'bgcolor' => $pref_bgcolor,
8214 'fontcolor' => $pref_fontcolor,
8215 'bgcolorhov' => $pref_bgcolorhov,
8216 'fontcolorhov' => $pref_fontcolorhov,
8217 );
8218 $config->set('pref_colors', $pref_colors);
8219
8220 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
8221 $config->set('interactive_map', $interactive_map);
8222 $config->set('search_filters', VikRequest::getInt('search_filters', 0, 'request'));
8223
8224 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
8225 $config->set('noemptydecimals', $noemptydecimals);
8226
8227 /**
8228 * Appearance preferences (light, auto, dark mode).
8229 *
8230 * @since 1.15.0 (J) - 1.5.0 (WP)
8231 * @since 1.16.10 (J) - 1.6.10 (WP) mirrored on VCM.
8232 */
8233 $appearance_pref = VikRequest::getString('appearance_pref', '');
8234 $config->set('appearance_pref', $appearance_pref);
8235 if (class_exists('VCMFactory')) {
8236 VCMFactory::getConfig()->set('appearance_pref', $appearance_pref);
8237 }
8238
8239 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
8240 $picon = "";
8241 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
8242 jimport('joomla.filesystem.file');
8243 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
8244 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
8245 if (file_exists($res_backend_path.$safename)) {
8246 $j = 1;
8247 while (file_exists($res_backend_path.$j.$safename)) {
8248 $j++;
8249 }
8250 $pwhere = $res_backend_path.$j.$safename;
8251 } else {
8252 $j = "";
8253 $pwhere = $res_backend_path.$safename;
8254 }
8255 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8256 @unlink($pwhere);
8257 $picon = "";
8258 } else {
8259 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
8260 @chmod($pwhere, 0644);
8261 $picon = $j.$safename;
8262 }
8263 }
8264 if (!empty($picon)) {
8265 $config->set('sitelogo', $picon);
8266 }
8267 }
8268 $pbackicon = "";
8269 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
8270 jimport('joomla.filesystem.file');
8271 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
8272 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
8273 if (file_exists($res_backend_path.$safename)) {
8274 $j = 1;
8275 while (file_exists($res_backend_path.$j.$safename)) {
8276 $j++;
8277 }
8278 $pwhere = $res_backend_path.$j.$safename;
8279 } else {
8280 $j = "";
8281 $pwhere = $res_backend_path.$safename;
8282 }
8283 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8284 @unlink($pwhere);
8285 $pbackicon = "";
8286 } else {
8287 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
8288 @chmod($pwhere, 0644);
8289 $pbackicon = $j.$safename;
8290 }
8291 }
8292 if (!empty($pbackicon)) {
8293 $config->set('backlogo', $pbackicon);
8294 }
8295 }
8296 $config->set('vcmautoupd', $pvcmautoupd);
8297 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
8298 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
8299 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
8300 $config->set('searchsuggestions', $psearchsuggestions);
8301 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
8302 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
8303 $config->set('search_show_busy_listings', $app->input->getInt('search_show_busy_listings', 0));
8304 $config->set('search_link_roomdetails', $app->input->getInt('search_link_roomdetails', 0));
8305
8306 // translatable text
8307 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
8308 $dbo->setQuery($q);
8309 $dbo->execute();
8310
8311 // translatable text
8312 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
8313 $dbo->setQuery($q);
8314 $dbo->execute();
8315
8316 // translatable text
8317 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
8318 $dbo->setQuery($q);
8319 $dbo->execute();
8320
8321 // terms and conditions
8322 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
8323 $dbo->setQuery($q);
8324 $dbo->execute();
8325 if ($dbo->getNumRows() > 0) {
8326 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
8327 $dbo->setQuery($q);
8328 $dbo->execute();
8329 } else {
8330 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
8331 $dbo->setQuery($q);
8332 $dbo->execute();
8333 }
8334
8335 $config->set('adminemail', $padminemail);
8336 $config->set('senderemail', $psenderemail);
8337 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
8338 $config->set('datesep', $pdatesep);
8339 $config->set('resmodcanc', $presmodcanc);
8340 $config->set('resmodcancmin', $presmodcancmin);
8341 $config->set('minuteslock', $pminuteslock);
8342 $config->set('minautoremove', $pminautoremove);
8343
8344 $openingh = $ptimeopenstorefh * 3600;
8345 $openingm = $ptimeopenstorefm * 60;
8346 $openingts = $openingh + $openingm;
8347 $closingh = $ptimeopenstoreth * 3600;
8348 $closingm = $ptimeopenstoretm * 60;
8349 $closingts = $closingh + $closingm;
8350 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
8351 $prevtimes = $config->get('timeopenstore', '');
8352 if ($prevtimes != $openingts . "-" . $closingts) {
8353 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
8354 $dbo->setQuery($q);
8355 $dbo->execute();
8356 if ($dbo->getNumRows() > 0) {
8357 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
8358 /**
8359 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
8360 * for all reservations to avoid issues with the availability.
8361 *
8362 * @since August 29th 2018
8363 */
8364 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>');
8365 //
8366 }
8367 }
8368 $config->set('timeopenstore', $openingts . "-" . $closingts);
8369
8370 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
8371 $phoursmorebookingback = "0";
8372 if ($closingts > $openingts) {
8373 $diffcheck = ($closingts - $openingts) / 3600;
8374 $phoursmorebookingback = ceil($diffcheck);
8375 }
8376 $config->set('hoursmorebookingback', $phoursmorebookingback);
8377 $config->set('hoursmoreroomavail', '0');
8378 $config->set('multilang', $pmultilang);
8379 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
8380 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
8381 $config->set('todaybookings', $ptodaybookings);
8382 $config->set('bootstrap', $ploadbootstrap);
8383 $config->set('usefa', $pusefa);
8384 $config->set('loadjquery', $ploadjquery);
8385 $config->set('calendar', $pcalendar ?: 'jqueryui');
8386 $config->set('dboptimizetime', $app->input->getString('dboptimizetime', ''));
8387 $config->set('enablecoupons', $penablecoupons);
8388 $config->set('enablepin', $penablepin);
8389 $config->set('mindaysadvance', $pmindaysadvance);
8390 $config->set('autodefcalnights', $pautodefcalnights);
8391 $config->set('numrooms', $pnumrooms);
8392 $config->set('numadults', $confnumadults);
8393 $config->set('numchildren', $confnumchildren);
8394 $config->set('closingdates', $closing_dates);
8395 $config->set('smartsearch', $psmartsearch);
8396 $config->set('maxdate', $maxdate_str);
8397 $config->set('cronkey', $pcronkey);
8398
8399 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
8400 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
8401 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
8402 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
8403 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
8404 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
8405 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
8406 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
8407 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
8408 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
8409 $pnumdecimals = intval($pnumdecimals);
8410 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
8411 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
8412 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
8413 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
8414 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
8415 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
8416 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
8417 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
8418 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
8419 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
8420 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
8421 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
8422 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
8423 $pbctagname = VikRequest::getVar('bctagname', array());
8424 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
8425 $pbctagrule = VikRequest::getVar('bctagrule', array());
8426 $bctags_arr = array();
8427 $bctags_rules = array();
8428 if (count($pbctagname) > 0) {
8429 foreach ($pbctagname as $bctk => $bctv) {
8430 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
8431 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
8432 $bctags_rules[] = $pbctagrule[$bctk];
8433 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8434 }
8435 }
8436 }
8437 }
8438 //theme
8439 $ptheme = VikRequest::getString('theme', '', 'request');
8440 if (empty($ptheme) || $ptheme == 'default') {
8441 $ptheme = 'default';
8442 } else {
8443 $validtheme = false;
8444 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8445 if (count($themes) > 0) {
8446 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8447 foreach ($themes as $th) {
8448 if (is_dir($th)) {
8449 $tname = str_replace($strip, '', $th);
8450 if ($tname == $ptheme) {
8451 $validtheme = true;
8452 break;
8453 }
8454 }
8455 }
8456 }
8457 if ($validtheme == false) {
8458 $ptheme = 'default';
8459 }
8460 }
8461 $config->set('theme', $ptheme);
8462 //
8463 $config->set('showpartlyreserved', $pshowpartlyreserved);
8464 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8465 $config->set('numcalendars', $pnumcalendars);
8466
8467 // record may not be set
8468 $config->set('thumbsize', $pthumbsize);
8469
8470 $config->set('firstwday', $pfirstwday);
8471
8472 // translatable text
8473 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8474 $dbo->setQuery($q);
8475 $dbo->execute();
8476
8477 $config->set('fronttitletag', $pfronttitletag);
8478 $config->set('fronttitletagclass', $pfronttitletagclass);
8479 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8480
8481 // translatable texts
8482 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8483 $dbo->setQuery($q);
8484 $dbo->execute();
8485 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8486 $dbo->setQuery($q);
8487 $dbo->execute();
8488
8489 $config->set('currencyname', $pcurrencyname);
8490 $config->set('currencysymb', $pcurrencysymb);
8491 $config->set('currencypos', $app->input->getAlnum('currencypos', 'before'));
8492 $config->set('currencycodepp', $pcurrencycodepp);
8493 $config->set('numberformat', $numberformatstr);
8494 // bookings color tags
8495 $config->set('bookingsctags', $bctags_arr);
8496
8497 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8498 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8499 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8500 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8501 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8502 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8503 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8504 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8505 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8506 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8507 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8508 $pmultipay = VikRequest::getString('multipay', '', 'request');
8509 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8510 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8511 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8512 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8513 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8514
8515 // translatable text
8516 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8517 $dbo->setQuery($q);
8518 $dbo->execute();
8519 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8520 $dbo->setQuery($q);
8521 $dbo->execute();
8522
8523 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8524 $config->set('taxsummary', $ptaxsummary);
8525 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8526
8527 $config->set('ccpaypal', $pccpaypal);
8528 $config->set('payaccpercent', $ppayaccpercent);
8529 $config->set('typedeposit', $ptypedeposit);
8530 $config->set('depoverrides', $pdepoverrides);
8531 $config->set('multipay', $pmultipay);
8532 $config->set('depifdaysadv', $pdepifdaysadv);
8533 $config->set('nodepnonrefund', $pnodepnonrefund);
8534 $config->set('depcustchoice', $pdepcustchoice);
8535 $config->set('depbalancedays', $app->input->getInt('depbalancedays', null));
8536
8537 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8538 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8539 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8540 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8541 $config->set('emailsendwhen', $psendemailwhen);
8542 $config->set('attachical', $pattachical);
8543
8544 // SMS APIs
8545 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8546 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8547 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8548 $psmssendto = VikRequest::getVar('smssendto', array());
8549 $sms_sendto = array();
8550 foreach ($psmssendto as $sto) {
8551 if (in_array($sto, array('admin', 'customer'))) {
8552 $sms_sendto[] = $sto;
8553 }
8554 }
8555 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8556 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8557 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8558 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8559 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8560 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8561 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8562 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8563 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8564 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8565 $smsparamarr = array();
8566 if (count($viksmsparams) > 0) {
8567 foreach ($viksmsparams as $setting => $cont) {
8568 if (strlen($setting) > 0) {
8569 $smsparamarr[$setting] = $cont;
8570 }
8571 }
8572 }
8573 $config->set('smsapi', $psmsapi);
8574 $config->set('smsautosend', $psmsautosend);
8575 $config->set('smssendto', $sms_sendto);
8576 $config->set('smssendwhen', $psmssendwhen);
8577 $config->set('smsadminphone', $psmsadminphone);
8578 $config->set('smsparams', $smsparamarr);
8579
8580 // translatable texts
8581 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8582 $dbo->setQuery($q);
8583 $dbo->execute();
8584 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8585 $dbo->setQuery($q);
8586 $dbo->execute();
8587 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8588 $dbo->setQuery($q);
8589 $dbo->execute();
8590 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8591 $dbo->setQuery($q);
8592 $dbo->execute();
8593 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8594 $dbo->setQuery($q);
8595 $dbo->execute();
8596 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8597 $dbo->setQuery($q);
8598 $dbo->execute();
8599
8600 /**
8601 * Backup settings
8602 *
8603 * @since 1.15.0 (J) - 1.5.0 (WP)
8604 */
8605 $backup_type = $app->input->getString('backuptype', 'full');
8606 $backup_folder = $app->input->getString('backupfolder', '');
8607
8608 $tmp = $app->get('tmp_path');
8609
8610 if (!$backup_folder)
8611 {
8612 // path not specified, use temporary folder
8613 $backup_folder = $tmp;
8614 }
8615
8616 $current = $config->get('backupfolder');
8617
8618 if (!$current)
8619 {
8620 // path was missing, use temporary folder
8621 $current = $tmp;
8622 }
8623
8624 // check whether the backup folder has been moved
8625 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8626 {
8627 $backupModel = new VBOModelBackup();
8628
8629 // backup folder moved, try to copy all the existing overrides
8630 if (!$backupModel->moveArchives($backup_folder))
8631 {
8632 // iterate all errors and display them
8633 foreach ($backupModel->getErrors() as $error)
8634 {
8635 $app->enqueueMessage($error, 'warning');
8636 }
8637 }
8638 }
8639
8640 // save configuration
8641 $config->set('backuptype', $backup_type);
8642 $config->set('backupfolder', $backup_folder);
8643
8644 /**
8645 * Check-in data collection type.
8646 *
8647 * @since 1.15.0 (J) - 1.5.0 (WP)
8648 */
8649 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8650
8651 /**
8652 * Front-end appearance.
8653 *
8654 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8655 */
8656 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8657
8658 /**
8659 * Split stays.
8660 *
8661 * @since 1.16.0 (J) - 1.6.0 (WP)
8662 */
8663 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8664 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8665 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8666 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8667
8668 /**
8669 * Re-build Web App manifest file to let the event trigger.
8670 *
8671 * @since 1.16.5 (J) - 1.6.5 (WP)
8672 */
8673 try {
8674 VBOWebappManifest::build();
8675 } catch (Exception $e) {
8676 // do nothing
8677 }
8678
8679 // redirect
8680 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8681 $app->redirect('index.php?option=com_vikbooking&task=config');
8682 $app->close();
8683 }
8684
8685 /**
8686 * Task to unify the check-in and check-out times for all reservations.
8687 */
8688 public function unifycheckinout()
8689 {
8690 $dbo = JFactory::getDbo();
8691 $app = JFactory::getApplication();
8692 $user = JFactory::getUser();
8693
8694 $fh = VikRequest::getInt('fh', 12, 'request');
8695 $fm = VikRequest::getInt('fm', 0, 'request');
8696 $th = VikRequest::getInt('th', 10, 'request');
8697 $tm = VikRequest::getInt('tm', 0, 'request');
8698
8699 $now = time();
8700 $totmod = 0;
8701 $totbookmod = 0;
8702
8703 // query all busy records
8704 $q = $dbo->getQuery(true)
8705 ->select('*')
8706 ->from($dbo->qn('#__vikbooking_busy'));
8707
8708 $dbo->setQuery($q);
8709 $records = $dbo->loadAssocList();
8710
8711 foreach ($records as $v) {
8712 $info_start = getdate($v['checkin']);
8713 $info_end = getdate($v['checkout']);
8714 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8715 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8716
8717 $q = $dbo->getQuery(true)
8718 ->update($dbo->qn('#__vikbooking_busy'))
8719 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8720 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8721 ->set($dbo->qn('realback') . ' = ' . $new_end)
8722 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8723
8724 $dbo->setQuery($q, 0, 1);
8725 $dbo->execute();
8726
8727 $totmod++;
8728 }
8729
8730 // query all bookings
8731 $q = $dbo->getQuery(true)
8732 ->select($dbo->qn([
8733 'id',
8734 'days',
8735 'checkin',
8736 'checkout',
8737 'total',
8738 ]))
8739 ->from($dbo->qn('#__vikbooking_orders'))
8740 ->order($dbo->qn('checkin') . ' DESC');
8741
8742 $dbo->setQuery($q);
8743 $records = $dbo->loadAssocList();
8744
8745 foreach ($records as $v) {
8746 $info_start = getdate($v['checkin']);
8747 $info_end = getdate($v['checkout']);
8748 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8749 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8750
8751 $q = $dbo->getQuery(true)
8752 ->update($dbo->qn('#__vikbooking_orders'))
8753 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8754 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8755 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8756
8757 $dbo->setQuery($q, 0, 1);
8758 $dbo->execute();
8759
8760 /**
8761 * In case the operation changed the check-in/check-out time for this booking,
8762 * store a new history record for a booking modification.
8763 *
8764 * @since 1.16.6 (J) - 1.6.6 (WP)
8765 */
8766 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8767 // Booking History
8768 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8769 }
8770
8771 $totbookmod++;
8772 }
8773
8774 $app->enqueueMessage('OK: ' . $totbookmod);
8775 $app->redirect("index.php?option=com_vikbooking&task=config");
8776 $app->close();
8777 }
8778
8779 public function savetmplfile()
8780 {
8781 $app = JFactory::getApplication();
8782
8783 if (!JSession::checkToken()) {
8784 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
8785 }
8786
8787 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
8788 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8789 }
8790
8791 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8792 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8793 $pajax = VikRequest::getInt('ajax', 0, 'request');
8794
8795 // default status
8796 $result = [
8797 'status' => 0,
8798 'message' => 'Generic error',
8799 ];
8800
8801 $exists = file_exists($fpath) ? true : false;
8802 if (!$exists) {
8803 $fpath = urldecode($fpath);
8804 }
8805 $fpath = file_exists($fpath) ? $fpath : '';
8806 if (!empty($fpath)) {
8807 $fp = fopen($fpath, 'wb');
8808 $byt = (int) fwrite($fp, $pcont);
8809 fclose($fp);
8810 if ($byt > 0) {
8811 // success
8812 $result = [
8813 'status' => 1,
8814 'message' => JText::translate('VBOUPDTMPLFILEOK'),
8815 ];
8816
8817 if (VBOPlatformDetection::isWordPress()) {
8818 /**
8819 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8820 */
8821 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8822 }
8823 } else {
8824 // error
8825 $result = [
8826 'status' => 0,
8827 'message' => JText::translate('VBOUPDTMPLFILENOBYTES'),
8828 ];
8829 }
8830 } else {
8831 // error
8832 $result = [
8833 'status' => 0,
8834 'message' => JText::translate('VBOUPDTMPLFILEERR'),
8835 ];
8836 }
8837
8838 if ($pajax) {
8839 if ($result['status']) {
8840 VBOHttpDocument::getInstance($app)->json($result);
8841 } else {
8842 VBOHttpDocument::getInstance($app)->close(500, $result['message']);
8843 }
8844 } else {
8845 if ($result['status']) {
8846 $app->enqueueMessage($result['message']);
8847 } else {
8848 VikError::raiseWarning('', $result['message']);
8849 }
8850 }
8851
8852 $app->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8853 $app->close();
8854 }
8855
8856 public function edittmplfile()
8857 {
8858 // this view should be rendered through AJAX
8859 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8860
8861 if (JFactory::getApplication()->input->getBool('ajax') && VBOPlatformDetection::isJoomla()) {
8862 /**
8863 * @todo This needs to be changed for Joomla in the future versions.
8864 * Right now no HTML document tree is being added as an AJAX response, because
8865 * the View output is captured within a buffer, but the CodeMirror will not work.
8866 * In case the View was rendered normally and sent to output, the CodeMirror would
8867 * work fine, but the response appended to the modal body would contain HTML head tags
8868 * and so accessing the language definitions through JS would fail after the first response.
8869 * The solution for both Joomla and WordPress is probably to use a completely different endpoint
8870 * that returns just the file buffer/content, and maybe the file type, so that who makes the requests
8871 * can set the content and render the proper CodeMirror editor manually at runtime.
8872 */
8873
8874 // start output buffer
8875 ob_start();
8876
8877 try {
8878 // display view
8879 parent::display();
8880 } catch (Exception $e) {
8881 // clear output buffer
8882 ob_end_clean();
8883
8884 // raise error
8885 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
8886 }
8887
8888 // obtain view HTML from buffer
8889 $html = ob_get_contents();
8890
8891 // clear output buffer
8892 ob_end_clean();
8893
8894 // encode HTML in JSON to avoid encoding issues
8895 VBOHttpDocument::getInstance()->json(json_encode($html));
8896
8897 } else {
8898 // regular view display
8899 parent::display();
8900 }
8901 }
8902
8903 public function tmplfileprew() {
8904 //modal box, so we do not set menu or footer
8905
8906 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8907
8908 parent::display();
8909 }
8910
8911 public function invoices() {
8912 VikBookingHelper::printHeader("invoices");
8913
8914 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8915
8916 parent::display();
8917
8918 if (VikBooking::showFooter()) {
8919 VikBookingHelper::printFooter();
8920 }
8921 }
8922
8923 public function newmaninvoice() {
8924 VikBookingHelper::printHeader("invoices");
8925
8926 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8927
8928 parent::display();
8929
8930 if (VikBooking::showFooter()) {
8931 VikBookingHelper::printFooter();
8932 }
8933 }
8934
8935 public function editmaninvoice() {
8936 VikBookingHelper::printHeader("invoices");
8937
8938 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8939
8940 parent::display();
8941
8942 if (VikBooking::showFooter()) {
8943 VikBookingHelper::printFooter();
8944 }
8945 }
8946
8947 public function savemaninvoice() {
8948 if (!JSession::checkToken()) {
8949 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8950 }
8951 $this->do_storemaninvoice('save');
8952 $mainframe = JFactory::getApplication();
8953 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8954 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8955 if (!empty($pgoto)) {
8956 $mainframe->redirect(base64_decode($pgoto));
8957 exit;
8958 }
8959 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8960 }
8961
8962 public function updatemaninvoice()
8963 {
8964 if (!JSession::checkToken()) {
8965 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8966 }
8967
8968 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8969 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8970 }
8971
8972 $invid = VikRequest::getInt('whereup', 0, 'request');
8973 $this->do_storemaninvoice('update', $invid);
8974 $mainframe = JFactory::getApplication();
8975 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8976 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8977 if (!empty($pgoto)) {
8978 $mainframe->redirect(base64_decode($pgoto));
8979 exit;
8980 }
8981 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8982 }
8983
8984 public function updatemaninvoicestay()
8985 {
8986 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
8987 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
8988 }
8989
8990 $invid = VikRequest::getInt('whereup', 0, 'request');
8991 $this->do_storemaninvoice('updatestay', $invid);
8992 $mainframe = JFactory::getApplication();
8993 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8994 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8995 if (!empty($pgoto)) {
8996 $mainframe->redirect(base64_decode($pgoto));
8997 exit;
8998 }
8999 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
9000 }
9001
9002 private function do_storemaninvoice($action, $invid = 0) {
9003 $dbo = JFactory::getDBO();
9004 $mainframe = JFactory::getApplication();
9005 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
9006 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
9007 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
9008 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
9009 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
9010 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
9011 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
9012 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
9013 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
9014 if (empty($pidcustomer)) {
9015 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
9016 $mainframe->redirect($error_uri);
9017 exit;
9018 }
9019 $services = VikRequest::getVar('service', array());
9020 $nets = VikRequest::getVar('net', array());
9021 $aliqs = VikRequest::getVar('aliq', array());
9022 $taxs = VikRequest::getVar('tax', array());
9023 $tots = VikRequest::getVar('tot', array());
9024 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
9025 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
9026 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
9027 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
9028 VikError::raiseWarning('', 'Missing data.');
9029 $mainframe->redirect($error_uri);
9030 exit;
9031 }
9032 $rawcont = array(
9033 'rows' => array(),
9034 'totalnet' => $ptotalnet,
9035 'totaltax' => $ptotaltax,
9036 'totaltot' => $ptotaltot,
9037 'notes' => $pinvoice_notes,
9038 );
9039 foreach ($services as $k => $service) {
9040 if (empty($service)) {
9041 continue;
9042 }
9043 array_push($rawcont['rows'], array(
9044 'service' => $service,
9045 'net' => (float)$nets[$k],
9046 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
9047 'tax' => (float)$taxs[$k],
9048 'tot' => (float)$tots[$k],
9049 ));
9050 }
9051 // store/update manual invoice
9052 $nowts = time();
9053 $retval = 0;
9054 if (strpos($action, 'save') !== false) {
9055 $pdffname = $nowts . '_' . rand() . '.pdf';
9056 $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)).");";
9057 $dbo->setQuery($q);
9058 $dbo->execute();
9059 $retval = $dbo->insertid();
9060 } else {
9061 // fetch old record
9062 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
9063 $dbo->setQuery($q);
9064 $dbo->execute();
9065 if (!$dbo->getNumRows()) {
9066 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
9067 $mainframe->redirect($error_uri);
9068 exit;
9069 }
9070 $previnvoice = $dbo->loadAssoc();
9071 //
9072 $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'].";";
9073 $dbo->setQuery($q);
9074 $dbo->execute();
9075 $retval = $previnvoice['id'];
9076 }
9077 // update config values for the invoice
9078 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
9079 $dbo->setQuery($q);
9080 $dbo->execute();
9081 // generate the custom invoice
9082 $result = VikBooking::generateCustomInvoice($retval);
9083 //
9084 $nextinv = VikBooking::getNextInvoiceNumber();
9085 $updatenum = ($pinvoice_num >= $nextinv);
9086 if ($updatenum) {
9087 /**
9088 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
9089 * to avoid conflicts with the drivers for the e-invoices generation.
9090 */
9091 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9092 $dbo->setQuery($q);
9093 $dbo->execute();
9094 }
9095
9096 return $retval;
9097 }
9098
9099 public function downloadinvoices() {
9100 $ids = VikRequest::getVar('cid', array(0));
9101 if (@count($ids) > 0) {
9102 $dbo = JFactory::getDBO();
9103 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
9104 $dbo->setQuery($q);
9105 $dbo->execute();
9106 if ($dbo->getNumRows() > 0) {
9107 $invoices = $dbo->loadAssocList();
9108 if (!(count($invoices) > 1)) {
9109 //Single Invoice Download
9110 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
9111 header("Content-type:application/pdf");
9112 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
9113 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
9114 exit;
9115 }
9116 } else {
9117 //Multiple Invoices Download
9118 $to_zip = array();
9119 foreach ($invoices as $k => $invoice) {
9120 $to_zip[$k]['name'] = $invoice['file_name'];
9121 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
9122 }
9123 if (class_exists('ZipArchive')) {
9124 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
9125 $zip = new ZipArchive;
9126 $zip->open($zip_path, ZipArchive::CREATE);
9127 foreach ($to_zip as $k => $zipv) {
9128 $zip->addFile($zipv['path'], $zipv['name']);
9129 }
9130 $zip->close();
9131 header("Content-type:application/zip");
9132 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
9133 header("Content-Length:".filesize($zip_path));
9134 readfile($zip_path);
9135 unlink($zip_path);
9136 exit;
9137 } else {
9138 //Class ZipArchive does not exist
9139 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
9140 }
9141 }
9142 }
9143 }
9144 $mainframe = JFactory::getApplication();
9145 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9146 }
9147
9148 public function resendinvoices() {
9149 $ids = VikRequest::getVar('cid', array(0));
9150 $mainframe = JFactory::getApplication();
9151 if (!(count($ids) > 0)) {
9152 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9153 exit;
9154 }
9155 $dbo = JFactory::getDBO();
9156 $invoices = array();
9157 $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` ".
9158 "FROM `#__vikbooking_invoices` AS `i` " .
9159 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
9160 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
9161 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
9162 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
9163 $dbo->setQuery($q);
9164 $dbo->execute();
9165 if ($dbo->getNumRows() > 0) {
9166 $invoices = $dbo->loadAssocList();
9167 }
9168 if (!(count($invoices) > 0)) {
9169 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9170 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9171 exit;
9172 }
9173 $tot_generated = 0;
9174 $tot_sent = 0;
9175 foreach ($invoices as $bkey => $invoice) {
9176 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
9177 $invoices[$bkey] = $invoice;
9178 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
9179 if ($send_res !== false) {
9180 $tot_sent++;
9181 }
9182 }
9183 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9184 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9185 }
9186
9187 public function removeinvoices()
9188 {
9189 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9190 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9191 }
9192
9193 $ids = VikRequest::getVar('cid', array());
9194 $tot_removed = 0;
9195 $dbo = JFactory::getDbo();
9196
9197 foreach ($ids as $d) {
9198 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9199 $dbo->setQuery($q);
9200 $cur_invoice = $dbo->loadAssoc();
9201 if ($cur_invoice) {
9202 $invoice_fpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'];
9203 if (is_file($invoice_fpath)) {
9204 unlink($invoice_fpath);
9205 }
9206 if (VBOPlatformDetection::isWordPress()) {
9207 /**
9208 * @wponly - trigger files mirroring for deletion
9209 */
9210 VikBookingLoader::import('update.manager');
9211 VikBookingUpdateManager::triggerDeletionBackup($invoice_fpath);
9212 }
9213 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
9214 $dbo->setQuery($q);
9215 $dbo->execute();
9216 $tot_removed++;
9217 }
9218 }
9219
9220 $mainframe = JFactory::getApplication();
9221 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
9222 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
9223 }
9224
9225 public function geninvoices()
9226 {
9227 $dbo = JFactory::getDbo();
9228 $app = JFactory::getApplication();
9229
9230 $ids = VikRequest::getVar('cid', array());
9231
9232 if (!$ids) {
9233 $app->redirect("index.php?option=com_vikbooking&task=orders");
9234 exit;
9235 }
9236
9237 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
9238 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
9239 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
9240 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
9241 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
9242 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
9243 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
9244 $pinvoice_send = $pinvoice_send > 0 ? true : false;
9245 $increment_inv = true;
9246 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
9247
9248 // if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
9249 if (count($ids) === 1) {
9250 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
9251 $dbo->setQuery($q);
9252 $dbo->execute();
9253 if ($dbo->getNumRows() == 1) {
9254 $increment_inv = false;
9255 }
9256 }
9257
9258 // get bookings
9259 $dbo->setQuery(
9260 $dbo->getQuery(true)
9261 ->select($dbo->qn('o') . '.*')
9262 ->select($dbo->qn('co.idcustomer'))
9263 ->select('CONCAT_WS(\' \', ' . $dbo->qn('c.first_name') . ', ' . $dbo->qn('c.last_name') . ') AS ' . $dbo->qn('customer_name'))
9264 ->select([
9265 $dbo->qn('c.pin', 'customer_pin'),
9266 $dbo->qn('nat.country_name'),
9267 ])
9268 ->from($dbo->qn('#__vikbooking_orders', 'o'))
9269 ->leftJoin($dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $dbo->qn('co.idorder') . ' = ' . $dbo->qn('o.id'))
9270 ->leftJoin($dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $dbo->qn('c.id') . ' = ' . $dbo->qn('co.idcustomer'))
9271 ->leftJoin($dbo->qn('#__vikbooking_countries', 'nat') . ' ON ' . $dbo->qn('nat.country_3_code') . ' = ' . $dbo->qn('o.country'))
9272 ->where($dbo->qn('o.id') . ' IN (' . implode(', ', array_map('intval', $ids)) . ')')
9273 ->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed'))
9274 ->where($dbo->qn('o.total') . ' > 0')
9275 ->order($dbo->qn('o.id') . ' ASC')
9276 );
9277
9278 $bookings = $dbo->loadAssocList();
9279
9280 if (!$bookings) {
9281 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
9282 $app->redirect("index.php?option=com_vikbooking&task=orders");
9283 exit;
9284 }
9285
9286 $tot_generated = 0;
9287 $tot_sent = 0;
9288 foreach ($bookings as $bkey => $booking) {
9289 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
9290 if ($gen_res !== false && $gen_res > 0) {
9291 $tot_generated++;
9292 $pinvoice_num++;
9293 if ($pinvoice_send) {
9294 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
9295 if ($send_res !== false) {
9296 $tot_sent++;
9297 }
9298 }
9299 } else {
9300 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
9301 }
9302 }
9303
9304 if ($tot_generated > 0 && $increment_inv === true) {
9305 /**
9306 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
9307 * to avoid conflicts with the drivers for the e-invoices generation.
9308 */
9309 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
9310 $dbo->setQuery($q);
9311 $dbo->execute();
9312 }
9313
9314 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
9315 $dbo->setQuery($q);
9316 $dbo->execute();
9317
9318 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
9319 $dbo->setQuery($q);
9320 $dbo->execute();
9321
9322 $app->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
9323
9324 if ($pconfirmgen > 0) {
9325 $app->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
9326 } elseif (count($bookings) === 1) {
9327 // go to the back-end booking details page
9328 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
9329 } else {
9330 $app->redirect("index.php?option=com_vikbooking&task=orders");
9331 }
9332 }
9333
9334 public function optionals() {
9335 VikBookingHelper::printHeader("6");
9336
9337 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
9338
9339 parent::display();
9340
9341 if (VikBooking::showFooter()) {
9342 VikBookingHelper::printFooter();
9343 }
9344 }
9345
9346 public function newoptionals() {
9347 VikBookingHelper::printHeader("6");
9348
9349 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9350
9351 parent::display();
9352
9353 if (VikBooking::showFooter()) {
9354 VikBookingHelper::printFooter();
9355 }
9356 }
9357
9358 public function editoptional() {
9359 VikBookingHelper::printHeader("6");
9360
9361 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
9362
9363 parent::display();
9364
9365 if (VikBooking::showFooter()) {
9366 VikBookingHelper::printFooter();
9367 }
9368 }
9369
9370 public function updateoptional()
9371 {
9372 if (!JSession::checkToken()) {
9373 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9374 }
9375
9376 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9377 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9378 }
9379
9380 $this->do_updateoptional();
9381 }
9382
9383 public function updateoptionalstay()
9384 {
9385 if (!JSession::checkToken()) {
9386 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9387 }
9388
9389 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
9390 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9391 }
9392
9393 $this->do_updateoptional(true);
9394 }
9395
9396 private function do_updateoptional($stay = false) {
9397 $dbo = JFactory::getDbo();
9398 $app = JFactory::getApplication();
9399 $poptname = VikRequest::getString('optname', '', 'request');
9400 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9401 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9402 $poptperday = VikRequest::getString('optperday', '', 'request');
9403 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9404 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9405 $popthmany = VikRequest::getString('opthmany', '', 'request');
9406 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9407 $pwhereup = VikRequest::getString('whereup', '', 'request');
9408 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9409 $presizeto = VikRequest::getString('resizeto', '', 'request');
9410 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9411 $pifchildren = $pifchildren == "1" ? 1 : 0;
9412 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9413 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9414 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9415 $pforceval = VikRequest::getString('forceval', '', 'request');
9416 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9417 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9418 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9419 $pforcesel = $pforcesel == "1" ? 1 : 0;
9420 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9421 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9422 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9423 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9424 $pagefrom = VikRequest::getVar('agefrom', array());
9425 $pageto = VikRequest::getVar('ageto', array());
9426 $pagecost = VikRequest::getVar('agecost', array());
9427 $pagectype = VikRequest::getVar('agectype', array());
9428 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9429 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9430 $pavto = VikRequest::getString('avto', '', 'request');
9431 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9432 $pidrooms = VikRequest::getVar('idrooms', array());
9433 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9434 if ($pforcesel == 1) {
9435 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9436 } else {
9437 $strforceval = "";
9438 }
9439 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9440 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9441 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9442 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9443 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9444 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9445 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9446 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9447 $minguests = VikRequest::getInt('minguests', 0, 'request');
9448 $minguests_conflict = false;
9449 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9450 if ($minguestsnum >= $maxguestsnum) {
9451 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9452 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9453 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9454 }
9455 }
9456 if (!$minguests || $minguests_conflict !== false) {
9457 $minguestsnum = 0;
9458 $maxguestsnum = 0;
9459 if ($minguests_conflict !== false) {
9460 // raise warning, but do not stop the process
9461 VikError::raiseWarning('', $minguests_conflict);
9462 }
9463 }
9464 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9465 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9466 $custom_checkinout = VikRequest::getInt('custom_checkinout', 0, 'request');
9467 $set_checkin = VikRequest::getInt('set_checkin', 0, 'request');
9468 $set_checkout = VikRequest::getInt('set_checkout', 0, 'request');
9469 if (!$custom_checkinout) {
9470 $set_checkin = 0;
9471 $set_checkout = 0;
9472 }
9473 if ((!$set_checkin && !$set_checkout) || $set_checkin == $set_checkout) {
9474 // check-in and check-out times should not be equal or both empty
9475 $custom_checkinout = 0;
9476 }
9477 $damagedep_settings = $damagedep ? ((array) $app->input->get('damagedep_settings', [], 'array')) : [];
9478 $oparams = [
9479 'minguestsnum' => $minguestsnum,
9480 'mingueststype' => $mingueststype,
9481 'maxguestsnum' => $maxguestsnum,
9482 'maxgueststype' => $maxgueststype,
9483 'damagedep' => $damagedep,
9484 'damagedep_settings' => $damagedep_settings,
9485 'pet_fee' => $pet_fee,
9486 'custom_checkinout' => $custom_checkinout,
9487 'set_checkin' => $set_checkin,
9488 'set_checkout' => $set_checkout,
9489 ];
9490 /**
9491 * We fetch the previous params to merge them with the new ones
9492 * in case some properties have been set somewhere else.
9493 * For example, the damage deposit transmission to Booking.com.
9494 */
9495 $cur_oparams = array();
9496 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
9497 $dbo->setQuery($q);
9498 $dbo->execute();
9499 if ($dbo->getNumRows()) {
9500 $cur_oparams = $dbo->loadResult();
9501 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
9502 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
9503 // merge previous params with the new ones to get the new values
9504 $oparams = array_merge($cur_oparams, $oparams);
9505 }
9506
9507 /**
9508 * Ensure options of type city tax never get a tax rate.
9509 *
9510 * @since 1.18.3 (J) - 1.8.3 (WP)
9511 */
9512 if ($pis_citytax) {
9513 $poptaliq = 0;
9514 }
9515
9516 if (!empty($poptname)) {
9517 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9518 jimport('joomla.filesystem.file');
9519 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9520 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9521 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9522 if (file_exists($updpath.$safename)) {
9523 $j=1;
9524 while (file_exists($updpath.$j.$safename)) {
9525 $j++;
9526 }
9527 $pwhere=$updpath.$j.$safename;
9528 } else {
9529 $j="";
9530 $pwhere=$updpath.$safename;
9531 }
9532 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9533 @unlink($pwhere);
9534 $picon="";
9535 } else {
9536 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9537 @chmod($pwhere, 0644);
9538 $picon=$j.$safename;
9539 if ($pautoresize=="1" && !empty($presizeto)) {
9540 $eforj = new vikResizer();
9541 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9542 if ($origmod) {
9543 @unlink($pwhere);
9544 $picon='r_'.$j.$safename;
9545 }
9546 }
9547 }
9548 } else {
9549 $picon="";
9550 }
9551 } else {
9552 $picon="";
9553 }
9554 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
9555 $poptperperson=($poptperperson=="each" ? "1" : "0");
9556 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
9557 $ageintervalstr = '';
9558 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9559 foreach ($pagefrom as $kage => $vage) {
9560 $afrom = intval($vage);
9561 $ato = intval($pageto[$kage]);
9562 $acost = floatval($pagecost[$kage]);
9563 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9564 if ($ato < $afrom) $ato = $afrom;
9565 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9566 }
9567 }
9568 $ageintervalstr = rtrim($ageintervalstr, ';;');
9569 if (!empty($ageintervalstr)) {
9570 $pforcesel = 1;
9571 }
9572 }
9573 $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).";";
9574 $dbo->setQuery($q);
9575 $dbo->execute();
9576 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
9577
9578 // assign/unset option-rooms relations
9579 $rooms_with_opt = array();
9580 if (count($pidrooms)) {
9581 // assign this new option to the requested rooms
9582 foreach ($pidrooms as $idroom) {
9583 if (empty($idroom)) {
9584 continue;
9585 }
9586 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9587 $dbo->setQuery($q);
9588 $dbo->execute();
9589 if (!$dbo->getNumRows()) {
9590 continue;
9591 }
9592 $room_data = $dbo->loadAssoc();
9593 array_push($rooms_with_opt, $room_data['id']);
9594 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9595 if (in_array((string)$pwhereup, $current_opts)) {
9596 continue;
9597 }
9598 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9599 // make sure we do not concatenate a real ID to 0
9600 $current_opts = array();
9601 }
9602 array_push($current_opts, $pwhereup);
9603 $new_opts = implode(';', $current_opts) . ';';
9604 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9605 $dbo->setQuery($q);
9606 $dbo->execute();
9607 }
9608 }
9609 if (!count($rooms_with_opt)) {
9610 // get all rooms to unset this option (if previously set)
9611 array_push($rooms_with_opt, '0');
9612 }
9613 // unset the option from the other rooms that may have it
9614 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9615 $dbo->setQuery($q);
9616 $dbo->execute();
9617 if ($dbo->getNumRows()) {
9618 $unset_rooms_opt = $dbo->loadAssocList();
9619 foreach ($unset_rooms_opt as $room_data) {
9620 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9621 if (!in_array((string)$pwhereup, $current_opts)) {
9622 // this room is not using this option
9623 continue;
9624 }
9625 $optkey = array_search((string)$pwhereup, $current_opts);
9626 if ($optkey === false) {
9627 // key not found
9628 continue;
9629 }
9630 // unset this option ID from the string
9631 unset($current_opts[$optkey]);
9632 if (!count($current_opts)) {
9633 // a room with no options assigned will be listed as "0;"
9634 $current_opts = array(0);
9635 }
9636 $new_opts = implode(';', $current_opts) . ';';
9637 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9638 $dbo->setQuery($q);
9639 $dbo->execute();
9640 }
9641 }
9642 //
9643
9644 }
9645 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9646 }
9647
9648 public function createoptionals()
9649 {
9650 if (!JSession::checkToken()) {
9651 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9652 }
9653
9654 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9655 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9656 }
9657
9658 $this->do_createoptionals();
9659 }
9660
9661 public function createoptionalsstay()
9662 {
9663 if (!JSession::checkToken()) {
9664 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9665 }
9666
9667 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
9668 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9669 }
9670
9671 $this->do_createoptionals(true);
9672 }
9673
9674 private function do_createoptionals($stay = false)
9675 {
9676 $app = JFactory::getApplication();
9677 $dbo = JFactory::getDbo();
9678
9679 $poptname = VikRequest::getString('optname', '', 'request');
9680 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9681 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9682 $poptperday = VikRequest::getString('optperday', '', 'request');
9683 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9684 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9685 $popthmany = VikRequest::getString('opthmany', '', 'request');
9686 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9687 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9688 $presizeto = VikRequest::getString('resizeto', '', 'request');
9689 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9690 $pifchildren = $pifchildren == "1" ? 1 : 0;
9691 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9692 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9693 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9694 $pforceval = VikRequest::getString('forceval', '', 'request');
9695 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9696 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9697 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9698 $pforcesel = $pforcesel == "1" ? 1 : 0;
9699 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9700 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9701 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9702 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9703 $pagefrom = VikRequest::getVar('agefrom', array());
9704 $pageto = VikRequest::getVar('ageto', array());
9705 $pagecost = VikRequest::getVar('agecost', array());
9706 $pagectype = VikRequest::getVar('agectype', array());
9707 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9708 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9709 $pavto = VikRequest::getString('avto', '', 'request');
9710 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9711 $pidrooms = VikRequest::getVar('idrooms', array());
9712 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9713 if ($pforcesel == 1) {
9714 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9715 } else {
9716 $strforceval = "";
9717 }
9718 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9719 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9720 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9721 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9722 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9723 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9724 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9725 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9726 $minguests = VikRequest::getInt('minguests', 0, 'request');
9727 $minguests_conflict = false;
9728 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9729 if ($minguestsnum >= $maxguestsnum) {
9730 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9731 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9732 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9733 }
9734 }
9735 if (!$minguests || $minguests_conflict !== false) {
9736 $minguestsnum = 0;
9737 $maxguestsnum = 0;
9738 if ($minguests_conflict !== false) {
9739 // raise warning, but do not stop the process
9740 VikError::raiseWarning('', $minguests_conflict);
9741 }
9742 }
9743 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9744 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9745 $custom_checkinout = VikRequest::getInt('custom_checkinout', 0, 'request');
9746 $set_checkin = VikRequest::getInt('set_checkin', 0, 'request');
9747 $set_checkout = VikRequest::getInt('set_checkout', 0, 'request');
9748 if (!$custom_checkinout) {
9749 $set_checkin = 0;
9750 $set_checkout = 0;
9751 }
9752 if ((!$set_checkin && !$set_checkout) || $set_checkin == $set_checkout) {
9753 // check-in and check-out times should not be equal or both empty
9754 $custom_checkinout = 0;
9755 }
9756 $damagedep_settings = $damagedep ? ((array) $app->input->get('damagedep_settings', [], 'array')) : [];
9757 $oparams = [
9758 'minguestsnum' => $minguestsnum,
9759 'mingueststype' => $mingueststype,
9760 'maxguestsnum' => $maxguestsnum,
9761 'maxgueststype' => $maxgueststype,
9762 'damagedep' => $damagedep,
9763 'damagedep_settings' => $damagedep_settings,
9764 'pet_fee' => $pet_fee,
9765 'custom_checkinout' => $custom_checkinout,
9766 'set_checkin' => $set_checkin,
9767 'set_checkout' => $set_checkout,
9768 ];
9769
9770 /**
9771 * Ensure options of type city tax never get a tax rate.
9772 *
9773 * @since 1.18.3 (J) - 1.8.3 (WP)
9774 */
9775 if ($pis_citytax) {
9776 $poptaliq = 0;
9777 }
9778
9779 if (!empty($poptname)) {
9780 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9781 jimport('joomla.filesystem.file');
9782 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9783 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9784 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9785 if (file_exists($updpath.$safename)) {
9786 $j = 1;
9787 while (file_exists($updpath.$j.$safename)) {
9788 $j++;
9789 }
9790 $pwhere = $updpath.$j.$safename;
9791 } else {
9792 $j = "";
9793 $pwhere = $updpath.$safename;
9794 }
9795 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9796 @unlink($pwhere);
9797 $picon = "";
9798 } else {
9799 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9800 @chmod($pwhere, 0644);
9801 $picon = $j.$safename;
9802 if ($pautoresize == "1" && !empty($presizeto)) {
9803 $eforj = new vikResizer();
9804 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9805 if ($origmod) {
9806 @unlink($pwhere);
9807 $picon = 'r_'.$j.$safename;
9808 }
9809 }
9810 }
9811 } else {
9812 $picon = "";
9813 }
9814 } else {
9815 $picon = "";
9816 }
9817 $poptperday = ($poptperday == "each" ? "1" : "0");
9818 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9819 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9820 $ageintervalstr = '';
9821 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9822 foreach ($pagefrom as $kage => $vage) {
9823 $afrom = intval($vage);
9824 $ato = intval($pageto[$kage]);
9825 $acost = floatval($pagecost[$kage]);
9826 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9827 if ($ato < $afrom) $ato = $afrom;
9828 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9829 }
9830 }
9831 $ageintervalstr = rtrim($ageintervalstr, ';;');
9832 if (!empty($ageintervalstr)) {
9833 $pforcesel = 1;
9834 }
9835 }
9836 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9837 $dbo->setQuery($q);
9838 $dbo->execute();
9839 if ($dbo->getNumRows() == 1) {
9840 $getlast = $dbo->loadResult();
9841 $newsortnum = $getlast + 1;
9842 } else {
9843 $newsortnum = 1;
9844 }
9845 $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)) . ");";
9846 $dbo->setQuery($q);
9847 $dbo->execute();
9848 $newoptid = $dbo->insertid();
9849
9850 if (!empty($newoptid)) {
9851 // assign/unset option-rooms relations
9852 $rooms_with_opt = array();
9853 if (count($pidrooms)) {
9854 // assign this new option to the requested rooms
9855 foreach ($pidrooms as $idroom) {
9856 if (empty($idroom)) {
9857 continue;
9858 }
9859 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9860 $dbo->setQuery($q);
9861 $dbo->execute();
9862 if (!$dbo->getNumRows()) {
9863 continue;
9864 }
9865 $room_data = $dbo->loadAssoc();
9866 array_push($rooms_with_opt, $room_data['id']);
9867 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9868 if (in_array((string)$newoptid, $current_opts)) {
9869 continue;
9870 }
9871 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9872 // make sure we do not concatenate a real ID to 0
9873 $current_opts = array();
9874 }
9875 array_push($current_opts, $newoptid);
9876 $new_opts = implode(';', $current_opts) . ';';
9877 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9878 $dbo->setQuery($q);
9879 $dbo->execute();
9880 }
9881 }
9882 if (!count($rooms_with_opt)) {
9883 // get all rooms to unset this option (if previously set)
9884 array_push($rooms_with_opt, '0');
9885 }
9886 // unset the option from the other rooms that may have it
9887 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9888 $dbo->setQuery($q);
9889 $dbo->execute();
9890 if ($dbo->getNumRows()) {
9891 $unset_rooms_opt = $dbo->loadAssocList();
9892 foreach ($unset_rooms_opt as $room_data) {
9893 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9894 if (!in_array((string)$newoptid, $current_opts)) {
9895 // this room is not using this option
9896 continue;
9897 }
9898 $optkey = array_search((string)$newoptid, $current_opts);
9899 if ($optkey === false) {
9900 // key not found
9901 continue;
9902 }
9903 // unset this option ID from the string
9904 unset($current_opts[$optkey]);
9905 if (!count($current_opts)) {
9906 // a room with no options assigned will be listed as "0;"
9907 $current_opts = array(0);
9908 }
9909 $new_opts = implode(';', $current_opts) . ';';
9910 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9911 $dbo->setQuery($q);
9912 $dbo->execute();
9913 }
9914 }
9915 //
9916 }
9917
9918 }
9919 $mainframe = JFactory::getApplication();
9920 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9921 }
9922
9923 public function removeoptionals()
9924 {
9925 if (!JSession::checkToken()) {
9926 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9927 }
9928
9929 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
9930 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
9931 }
9932
9933 $ids = VikRequest::getVar('cid', array(0));
9934 if ($ids) {
9935 $dbo = JFactory::getDbo();
9936 foreach ($ids as $d) {
9937 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9938 $dbo->setQuery($q);
9939 $dbo->execute();
9940 if ($dbo->getNumRows() == 1) {
9941 $rows = $dbo->loadAssocList();
9942 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9943 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9944 }
9945 }
9946 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9947 $dbo->setQuery($q);
9948 $dbo->execute();
9949 }
9950 }
9951 $mainframe = JFactory::getApplication();
9952 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9953 }
9954
9955 public function sendcustomsms() {
9956 $mainframe = JFactory::getApplication();
9957 $pphone = VikRequest::getString('phone', '', 'request');
9958 $psmscont = VikRequest::getString('smscont', '', 'request');
9959 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9960 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9961 if (!empty($pphone) && !empty($psmscont)) {
9962 $sms_api = VikBooking::getSMSAPIClass();
9963 $sms_api_params = VikBooking::getSMSParams();
9964 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9965 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9966 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9967 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9968 if ( !$sms_obj->validateResponse($response_obj) ) {
9969 VikError::raiseWarning('', $sms_obj->getLog());
9970 } else {
9971 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9972 }
9973 } else {
9974 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9975 }
9976 } else {
9977 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9978 }
9979 $mainframe->redirect($pgoto);
9980 }
9981
9982 public function sendcustomemail() {
9983 $dbo = JFactory::getDbo();
9984 $mainframe = JFactory::getApplication();
9985 $vbo_tn = VikBooking::getTranslator();
9986 $pbid = VikRequest::getInt('bid', '', 'request');
9987 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9988 $pemail = VikRequest::getString('email', '', 'request');
9989 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9990 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9991 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9992 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9993 if (!empty($pemail) && !empty($pemailcont)) {
9994 $email_attach = null;
9995 jimport('joomla.filesystem.file');
9996 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9997 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9998 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9999 $src = $pemailattch['tmp_name'];
10000 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
10001 $j = "";
10002 if (file_exists($dest.$filename)) {
10003 $j = rand(171, 1717);
10004 while (file_exists($dest.$j.$filename)) {
10005 $j++;
10006 }
10007 }
10008 $finaldest = $dest.$j.$filename;
10009 if (VikBooking::uploadFile($src, $finaldest)) {
10010 $email_attach = $finaldest;
10011 } else {
10012 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
10013 $mainframe->redirect($pgoto);
10014 exit;
10015 }
10016 }
10017 //VBO 1.10 - special tags for the custom email template files and messages
10018 $orig_mail_cont = $pemailcont;
10019 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
10020 // replace any possible placeholder for special tags
10021 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
10022 return $match[2];
10023 }, $pemailcont);
10024
10025 $booking = array();
10026 $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.";";
10027 $dbo->setQuery($q);
10028 $dbo->execute();
10029 if ($dbo->getNumRows() > 0) {
10030 $booking = $dbo->loadAssoc();
10031 }
10032 $booking_rooms = array();
10033 $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.";";
10034 $dbo->setQuery($q);
10035 $dbo->execute();
10036 if ($dbo->getNumRows() > 0) {
10037 $booking_rooms = $dbo->loadAssocList();
10038 if (!empty($booking['lang'])) {
10039 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
10040 }
10041 }
10042 //we use the same parsing function as the one for the Customer SMS Template
10043 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
10044 }
10045 //
10046 // allow the use of token {booking_id} in subject
10047 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
10048 //
10049 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
10050 $pemailcont = !$is_html ? nl2br($pemailcont) : $pemailcont;
10051 $vbo_app = VikBooking::getVboApplication();
10052 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
10053 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
10054 if ($email_attach !== null) {
10055 @unlink($email_attach);
10056 }
10057 //Booking History
10058 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
10059 //
10060 //Save email template for future sending
10061 $config_rec_exists = false;
10062 $emtpl = array(
10063 'emailsubj' => $pemailsubj,
10064 'emailcont' => $orig_mail_cont,
10065 'emailfrom' => $pemailfrom
10066 );
10067 $cur_emtpl = array();
10068 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
10069 $dbo->setQuery($q);
10070 $dbo->execute();
10071 if ($dbo->getNumRows() > 0) {
10072 $config_rec_exists = true;
10073 $cur_emtpl = $dbo->loadResult();
10074 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
10075 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
10076 }
10077 if (count($cur_emtpl) > 0) {
10078 $existing_subj = false;
10079 foreach ($cur_emtpl as $emk => $emv) {
10080 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
10081 $cur_emtpl[$emk] = $emtpl;
10082 $existing_subj = true;
10083 break;
10084 }
10085 }
10086 if ($existing_subj === false) {
10087 $cur_emtpl[] = $emtpl;
10088 }
10089 } else {
10090 $cur_emtpl[] = $emtpl;
10091 }
10092 if (count($cur_emtpl) > 10) {
10093 //Max 10 templates to avoid problems with the size of the field and truncated json strings
10094 $exceed = count($cur_emtpl) - 10;
10095 for ($tl=0; $tl < $exceed; $tl++) {
10096 unset($cur_emtpl[$tl]);
10097 }
10098 $cur_emtpl = array_values($cur_emtpl);
10099 }
10100 if ($config_rec_exists === true) {
10101 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
10102 $dbo->setQuery($q);
10103 $dbo->execute();
10104 } else {
10105 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
10106 $dbo->setQuery($q);
10107 $dbo->execute();
10108 }
10109 //
10110 } else {
10111 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
10112 }
10113 $mainframe->redirect($pgoto);
10114 }
10115
10116 public function rmcustomemailtpl() {
10117 $cid = VikRequest::getVar('cid', array(0));
10118 $oid = $cid[0];
10119 $dbo = JFactory::getDBO();
10120 $mainframe = JFactory::getApplication();
10121 $tplind = VikRequest::getInt('tplind', '', 'request');
10122 if (empty($oid) || !(strlen($tplind) > 0)) {
10123 VikError::raiseWarning('', 'Missing Data.');
10124 $mainframe->redirect('index.php?option=com_vikbooking');
10125 exit;
10126 }
10127 $cur_emtpl = array();
10128 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
10129 $dbo->setQuery($q);
10130 $dbo->execute();
10131 if ($dbo->getNumRows() > 0) {
10132 $cur_emtpl = $dbo->loadResult();
10133 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
10134 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
10135 } else {
10136 VikError::raiseWarning('', 'Missing Templates Record.');
10137 $mainframe->redirect('index.php?option=com_vikbooking');
10138 exit;
10139 }
10140 if (array_key_exists($tplind, $cur_emtpl)) {
10141 unset($cur_emtpl[$tplind]);
10142 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
10143 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
10144 $dbo->setQuery($q);
10145 $dbo->execute();
10146 }
10147 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
10148 exit;
10149 }
10150
10151 public function exportcustomers() {
10152 //we do not set the menu for this view
10153
10154 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
10155
10156 parent::display();
10157
10158 if (VikBooking::showFooter()) {
10159 VikBookingHelper::printFooter();
10160 }
10161 }
10162
10163 public function csvexportprepare() {
10164 //modal box, so we do not set menu or footer
10165
10166 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
10167
10168 parent::display();
10169 }
10170
10171 public function icsexportprepare() {
10172 //modal box, so we do not set menu or footer
10173
10174 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
10175
10176 parent::display();
10177 }
10178
10179 public function bookingcheckin() {
10180 //modal box, so we do not set menu or footer
10181
10182 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
10183
10184 parent::display();
10185 }
10186
10187 public function gencheckindoc() {
10188 //modal box, so we do not set menu or footer
10189
10190 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
10191
10192 parent::display();
10193 }
10194
10195 public function checkversion() {
10196 //to be called via ajax
10197 $params = new stdClass;
10198 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10199 $params->alias = 'com_vikbooking';
10200
10201 $result = array();
10202
10203 if (!count($result)) {
10204 $result = new stdClass;
10205 $result->status = 0;
10206 } else {
10207 $result = $result[0];
10208 }
10209
10210 echo json_encode($result);
10211 exit;
10212 }
10213
10214 public function updateprogram() {
10215 $params = new stdClass;
10216 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10217 $params->alias = 'com_vikbooking';
10218
10219 $result = array();
10220
10221 if (!count($result) || !$result[0]) {
10222 if (class_exists('JEventDispatcher')) {
10223 $dispatcher = JEventDispatcher::getInstance();
10224 $result = $dispatcher->trigger('checkVersion', array(&$params));
10225 } else {
10226 $app = JFactory::getApplication();
10227 if (method_exists($app, 'triggerEvent')) {
10228 $result = $app->triggerEvent('checkVersion', array(&$params));
10229 }
10230 }
10231 }
10232
10233 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
10234 exit('Error, plugin disabled');
10235 }
10236
10237 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
10238
10239 VikBookingHelper::pUpdateProgram($result[0]->response);
10240 }
10241
10242 public function updateprogramlaunch() {
10243 $params = new stdClass;
10244 $params->version = VIKBOOKING_SOFTWARE_VERSION;
10245 $params->alias = 'com_vikbooking';
10246
10247 $json = new stdClass;
10248 $json->status = false;
10249
10250 echo json_encode($json);
10251 exit;
10252 }
10253
10254 public function invoke_vcm()
10255 {
10256 $app = JFactory::getApplication();
10257
10258 $oids = VikRequest::getVar('cid', []);
10259 $sync_type = VikRequest::getString('stype', 'new', 'request');
10260 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
10261 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
10262 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
10263 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
10264
10265 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
10266 $app->redirect("index.php?option=com_vikbooking&task=orders");
10267 $app->close();
10268 }
10269
10270 $result = VikBooking::getVcmInvoker()
10271 ->setOids($oids)
10272 ->setSyncType($sync_type)
10273 ->setOriginalBooking($original_booking_js, true)
10274 ->doSync();
10275
10276 if ($result === true) {
10277 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
10278 } else {
10279 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
10280 }
10281
10282 if (!empty($return_url)) {
10283 $app->redirect($return_url);
10284 } else {
10285 $app->redirect("index.php?option=com_vikbooking&task=orders");
10286 }
10287
10288 $app->close();
10289 }
10290
10291 public function multiphotosupload() {
10292 jimport('joomla.filesystem.file');
10293
10294 $dbo = JFactory::getDBO();
10295 $proomid = VikRequest::getInt('roomid', '', 'request');
10296
10297 $resp = array('files' => array());
10298 $error_messages = array(
10299 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
10300 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
10301 3 => 'The uploaded file was only partially uploaded',
10302 4 => 'No file was uploaded',
10303 6 => 'Missing a temporary folder',
10304 7 => 'Failed to write file to disk',
10305 8 => 'A PHP extension stopped the file upload',
10306 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
10307 'max_file_size' => 'File is too big',
10308 'min_file_size' => 'File is too small',
10309 'accept_file_types' => 'Filetype not allowed',
10310 'max_number_of_files' => 'Maximum number of files exceeded',
10311 'max_width' => 'Image exceeds maximum width',
10312 'min_width' => 'Image requires a minimum width',
10313 'max_height' => 'Image exceeds maximum height',
10314 'min_height' => 'Image requires a minimum height',
10315 'abort' => 'File upload aborted',
10316 'image_resize' => 'Failed to resize image',
10317 'vbo_type' => 'The file type cannot be accepted',
10318 'vbo_jupload' => 'The upload has failed. Check your CMS settings and permissions',
10319 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
10320 );
10321
10322 $creativik = new vikResizer();
10323 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
10324 $bigsdest = $updpath;
10325 $thumbsdest = $updpath;
10326 $dest = $updpath;
10327 $moreimagestr = '';
10328 $cur_captions = json_encode(array());
10329
10330 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
10331 $dbo->setQuery($q);
10332 $dbo->execute();
10333 if ($dbo->getNumRows() == 1) {
10334 $photo_data = $dbo->loadAssocList();
10335 $cur_captions = $photo_data[0]['imgcaptions'];
10336 $cur_photos = $photo_data[0]['moreimgs'];
10337 if (!empty($cur_photos)) {
10338 $moreimagestr .= $cur_photos;
10339 }
10340 }
10341
10342 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
10343
10344 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
10345 foreach ($bulkphotos['name'] as $updk => $photoname) {
10346 $uploaded_image = array();
10347 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
10348 $src = $bulkphotos['tmp_name'][$updk];
10349 $j = "";
10350 if (file_exists($dest.$filename)) {
10351 $j = rand(171, 1717);
10352 while (file_exists($dest.$j.$filename)) {
10353 $j++;
10354 }
10355 }
10356 $finaldest=$dest.$j.$filename;
10357 $is_error = false;
10358 $err_key = '';
10359 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
10360 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
10361 $is_error = true;
10362 $err_key = $bulkphotos['error'][$updk];
10363 }
10364 }
10365 if (!$is_error) {
10366 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
10367 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
10368 if (VikBooking::uploadFile($src, $finaldest)) {
10369 $gimg = $j.$filename;
10370 //orig img
10371 $origmod = true;
10372 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
10373 //thumb
10374 $thumbsize = VikBooking::getThumbSize();
10375 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
10376 if (!$thumb || !$origmod) {
10377 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
10378 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
10379 $is_error = true;
10380 $err_key = 'vbo_perm';
10381 } else {
10382 $moreimagestr.=$j.$filename.";;";
10383 }
10384 @unlink($finaldest);
10385 } else {
10386 $is_error = true;
10387 $err_key = 'vbo_jupload';
10388 }
10389 } else {
10390 $is_error = true;
10391 $err_key = 'vbo_type';
10392 }
10393 }
10394 $img = new stdClass();
10395 if ($is_error) {
10396 $img->name = '';
10397 $img->size = '';
10398 $img->type = '';
10399 $img->url = '';
10400 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
10401 } else {
10402 $img->name = $photoname;
10403 $img->size = $bulkphotos['size'][$updk];
10404 $img->type = $bulkphotos['type'][$updk];
10405 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
10406 }
10407 $resp['files'][] = $img;
10408 }
10409 } else {
10410 $res = new stdClass();
10411 $res->name = '';
10412 $res->size = '';
10413 $res->type = '';
10414 $res->url = '';
10415 $res->error = 'No images received for upload';
10416 $resp['files'][] = $res;
10417 }
10418 //Update current extra images string
10419 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
10420 $dbo->setQuery($q);
10421 $dbo->execute();
10422 $resp['actmoreimgs'] = $moreimagestr;
10423 //Update current extra images uploaded
10424 $cur_thumbs = '';
10425 $morei=explode(';;', $moreimagestr);
10426 if (@count($morei) > 0) {
10427 $imgcaptions = json_decode($cur_captions, true);
10428 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
10429 $cur_thumbs .= '<ul class="vbo-sortable">';
10430 foreach ($morei as $ki => $mi) {
10431 if (!empty($mi)) {
10432 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
10433 $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>';
10434 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
10435 $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>';
10436 $cur_thumbs .= '</li>';
10437 }
10438 }
10439 $cur_thumbs .= '</ul>';
10440 $cur_thumbs .= '<br clear="all"/>';
10441 }
10442 $resp['currentthumbs'] = $cur_thumbs;
10443
10444 echo json_encode($resp);
10445 exit;
10446 }
10447
10448 public function loadsmsbalance() {
10449 //to be called via ajax
10450 $html = 'Error1 [N/A]';
10451 $sms_api = VikBooking::getSMSAPIClass();
10452 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
10453 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10454 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
10455 if (method_exists('VikSmsApi', 'estimate')) {
10456 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
10457 if ( $array_result->errorCode != 0 ) {
10458 $html = 'Error3 ['.$array_result->errorMsg.']';
10459 } else {
10460 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
10461 }
10462 } else {
10463 $html = 'Error2 [N/A]';
10464 }
10465 }
10466 echo $html;
10467 exit;
10468 }
10469
10470 public function loadsmsparams() {
10471 //to be called via ajax
10472 $html = '---------';
10473 $phpfile = VikRequest::getString('phpfile', '', 'request');
10474 if (!empty($phpfile)) {
10475 $sms_api = VikBooking::getSMSAPIClass();
10476 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
10477 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
10478 }
10479 echo $html;
10480 exit;
10481 }
10482
10483 public function loadcronparams() {
10484 //to be called via ajax
10485 $html = '---------';
10486 $phpfile = VikRequest::getString('phpfile', '', 'request');
10487 if (!empty($phpfile)) {
10488 $html = VikBooking::displayCronParameters($phpfile);
10489 }
10490 echo $html;
10491 exit;
10492 }
10493
10494 public function loadpaymentparams() {
10495 //to be called via ajax
10496 $html = '<p>---------</p>';
10497 $phpfile = VikRequest::getString('phpfile', '', 'request');
10498 if (!empty($phpfile)) {
10499 $html = VikBooking::displayPaymentParameters($phpfile);
10500 }
10501 echo $html;
10502 exit;
10503 }
10504
10505 public function setbookingtag() {
10506 //to be called via ajax
10507 $dbo = JFactory::getDBO();
10508 $pidorder = VikRequest::getInt('idorder', '', 'request');
10509 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
10510 if (!empty($pidorder) && $ptagkey >= 0) {
10511 $all_tags = VikBooking::loadBookingsColorTags();
10512 if (array_key_exists($ptagkey, $all_tags)) {
10513 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
10514 $dbo->setQuery($q);
10515 $dbo->execute();
10516 if ($dbo->getNumRows() > 0) {
10517 $newcolortag = json_encode($all_tags[$ptagkey]);
10518 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
10519 $dbo->setQuery($q);
10520 $dbo->execute();
10521 $newcolortag = $all_tags[$ptagkey];
10522 $newcolortag['name'] = JText::translate($newcolortag['name']);
10523 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
10524 echo json_encode($newcolortag);
10525 } else {
10526 echo 'e4j.error.Booking ('.$pidorder.') not found';
10527 }
10528 } else {
10529 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
10530 }
10531 } else {
10532 echo 'e4j.error.Missing Data';
10533 }
10534 exit;
10535 }
10536
10537 public function updatereceiptnum() {
10538 //to be called via ajax
10539 $pnewnum = VikRequest::getInt('newnum', '', 'request');
10540 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
10541 $poid = VikRequest::getInt('oid', '', 'request');
10542 if ($pnewnum > 0) {
10543 VikBooking::getNextReceiptNumber($poid, $pnewnum);
10544 VikBooking::getReceiptNotes($pnewnotes);
10545 //Booking History
10546 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
10547 //
10548 echo 'e4j.ok';
10549 exit;
10550 }
10551 echo 'e4j.error';
10552 exit;
10553 }
10554
10555 /**
10556 * AJAX endpoint to check if a room ID is available on specific dates.
10557 */
10558 public function isroombookable()
10559 {
10560 $app = JFactory::getApplication();
10561 $dbo = JFactory::getDbo();
10562
10563 $prid = $app->input->getUInt('rid', 0);
10564 $pfdate = $app->input->getString('fdate', '');
10565 $ptdate = $app->input->getString('tdate', '');
10566
10567 if (empty($prid) || empty($pfdate) || empty($ptdate)) {
10568 VBOHttpDocument::getInstance($app)->close(400, 'Missing request values.');
10569 }
10570
10571 $res = [
10572 'status' => 0,
10573 'err' => '',
10574 ];
10575
10576 $room_info = VikBooking::getRoomInfo($prid);
10577 if (!$room_info) {
10578 VBOHttpDocument::getInstance($app)->close(404, 'Room not found.');
10579 }
10580
10581 $pcheckinh = 0;
10582 $pcheckinm = 0;
10583 $pcheckouth = 0;
10584 $pcheckoutm = 0;
10585 $timeopst = VikBooking::getTimeOpenStore();
10586 if (is_array($timeopst)) {
10587 $opent = VikBooking::getHoursMinutes($timeopst[0]);
10588 $closet = VikBooking::getHoursMinutes($timeopst[1]);
10589 $pcheckinh = $opent[0];
10590 $pcheckinm = $opent[1];
10591 $pcheckouth = $closet[0];
10592 $pcheckoutm = $closet[1];
10593 }
10594
10595 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
10596 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
10597
10598 if (!empty($from_ts) && !empty($to_ts) && VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts)) {
10599 $res['status'] = 1;
10600 } else {
10601 if (empty($from_ts) || empty($to_ts)) {
10602 $res['err'] = 'Invalid dates';
10603 } else {
10604 // not available
10605 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
10606 }
10607 }
10608
10609 // send response to output
10610 VBOHttpDocument::getInstance($app)->json($res);
10611 }
10612
10613 public function uploadsnapshot() {
10614 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
10615 /**
10616 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
10617 * The old snapshot collection script with Flash no longer works in 2021.
10618 *
10619 * @since 1.14 (J) - 1.4.0 (WP)
10620 */
10621 $result = null;
10622 try {
10623 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path, 'png,jpg,jpeg');
10624 } catch (RuntimeException $e) {
10625 echo "e4j.error.Error " . $e->getMessage();
10626 exit;
10627 }
10628
10629 if (!is_object($result)) {
10630 echo "e4j.error.Invalid upload response";
10631 exit;
10632 }
10633
10634 echo $result->filename;
10635 exit;
10636 }
10637
10638 public function checkvcmrateschanges() {
10639 //to be called via ajax
10640 $session = JFactory::getSession();
10641 $ret = array('changesCount' => 0, 'changesData' => '');
10642 $updforvcm = $session->get('vbVcmRatesUpd', '');
10643 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
10644 $ret['changesCount'] = $updforvcm['count'];
10645 $ret['changesData'] = $updforvcm;
10646 }
10647
10648 echo json_encode($ret);
10649 exit;
10650 }
10651
10652 /**
10653 * AJAX endpoint to load the details of one or more bookings.
10654 *
10655 * @return void
10656 *
10657 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10658 */
10659 public function getbookingsinfo()
10660 {
10661 //to be called via ajax
10662 $dbo = JFactory::getDbo();
10663
10664 $booking_infos = [];
10665 $bookings = [];
10666
10667 $pidorders = VikRequest::getString('idorders', '', 'request');
10668 $psubroom = VikRequest::getString('subroom', '', 'request');
10669 $pstatus = VikRequest::getString('status', '', 'request');
10670 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10671 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10672 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10673
10674 if (!empty($pidorders)) {
10675 $bookings = explode(',', $pidorders);
10676 foreach ($bookings as $k => $v) {
10677 $v = intval(str_replace('-', '', $v));
10678 if (empty($v)) {
10679 unset($bookings[$k]);
10680 continue;
10681 }
10682 $bookings[$k] = $v;
10683 }
10684 }
10685 $bookings = array_values($bookings);
10686
10687 if (!$bookings) {
10688 /**
10689 * AJAX requests made by the page availability overview may contain empty booking IDs
10690 * due to SQL errors that only occupied the room, but could not save the booking record.
10691 * Clean up busy records where the busy relations contain empty booking IDs.
10692 *
10693 * @since 1.14 (J) - 1.4.0 (WP)
10694 */
10695 $hanging_busy_ids = [];
10696
10697 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10698 $dbo->setQuery($q);
10699 $removelist = $dbo->loadAssocList();
10700 if ($removelist) {
10701 foreach ($removelist as $hanging_busy) {
10702 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10703 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10704 array_push($hanging_busy_ids, $hanging_busy_id);
10705 }
10706 }
10707 }
10708
10709 // let's check also for ghost records that only occupy the room
10710 $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);";
10711 $dbo->setQuery($q);
10712 $removelist = $dbo->loadAssocList();
10713 if ($removelist) {
10714 foreach ($removelist as $hanging_busy) {
10715 $hanging_busy_id = (int)$hanging_busy['id'];
10716 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10717 array_push($hanging_busy_ids, $hanging_busy_id);
10718 }
10719 }
10720 }
10721
10722 if ($hanging_busy_ids) {
10723 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10724 $dbo->setQuery($q);
10725 $dbo->execute();
10726 }
10727 //
10728
10729 // output the error
10730 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10731 }
10732
10733 $nowdf = VikBooking::getDateFormat(true);
10734 if ($nowdf == "%d/%m/%Y") {
10735 $df = 'd/m/Y';
10736 } elseif ($nowdf == "%m/%d/%Y") {
10737 $df = 'm/d/Y';
10738 } else {
10739 $df = 'Y/m/d';
10740 }
10741 $datesep = VikBooking::getDateSeparator(true);
10742 $currencysymb = VikBooking::getCurrencySymb();
10743 $current_y = date('Y');
10744 $current_ts = time();
10745 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10746
10747 $query = $dbo->getQuery(true);
10748 $query->select('o.*');
10749 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10750 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10751 // include the requested booking IDs and the cancelled reservations for this stay date
10752 $stay_date_info = getdate(strtotime($pstay_date));
10753 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10754 $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) . '))');
10755 // exclude the pending reservations
10756 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10757 } else {
10758 // include only the requested booking IDs
10759 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10760 }
10761 if ($pstatus != 'any') {
10762 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10763 }
10764 if (!empty($pstay_date) && $pstatus == 'any') {
10765 // sort by confirmed status before cancelled status
10766 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10767 $query->order($dbo->qn('o.id') . ' ASC');
10768 }
10769 $dbo->setQuery($query);
10770 $booking_infos = $dbo->loadAssocList();
10771
10772 foreach ($booking_infos as $k => $row) {
10773 // rooms, amounts and guests information
10774 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10775 $rids_involved = [];
10776 $room_names = [];
10777 $totadults = 0;
10778 $totchildren = 0;
10779 foreach ($rooms as $rr) {
10780 $rids_involved[] = $rr['idroom'];
10781 $totadults += $rr['adults'];
10782 $totchildren += $rr['children'];
10783 $room_names[] = $rr['room_name'];
10784 if ($row['split_stay']) {
10785 // do not sum guests in case of split stay booking
10786 $totadults = $rr['adults'];
10787 $totchildren = $rr['children'];
10788 }
10789 }
10790
10791 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10792 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10793 if (!in_array($pidroom, $rids_involved)) {
10794 $is_out_of_scope = true;
10795 if ($psharedcal && count($bookings) === 1) {
10796 $is_out_of_scope = ($row['id'] != $bookings[0]);
10797 }
10798 if ($is_out_of_scope) {
10799 // out of scope reservation, unset it and go to the next one
10800 unset($booking_infos[$k]);
10801 continue;
10802 }
10803 }
10804 }
10805
10806 // included meal plans to be displayed in case of single-room booking
10807 $included_meals = [];
10808 $rplan_name = '';
10809 if (count($rooms) === 1) {
10810 // rate plan name and ID, if any
10811 $active_rplan_id = 0;
10812 if (!empty($rooms[0]['otarplan'])) {
10813 $rplan_name = $rooms[0]['otarplan'];
10814 } else {
10815 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10816 }
10817
10818 // find the included meals
10819 if (!empty($rooms[0]['meals'])) {
10820 // display included meals defined at room-reservation record
10821 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10822 } else {
10823 // fetch default included meals in the selected rate plan
10824 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10825 }
10826 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10827 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10828 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10829 }
10830 }
10831
10832 if ($included_meals) {
10833 $short_incl_meals = [];
10834 foreach ($included_meals as $meal_enum => $meal_name) {
10835 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10836 }
10837 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10838 }
10839
10840 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10841 $booking_infos[$k]['currency_symb'] = $currencysymb;
10842 if ($row['status'] == 'confirmed') {
10843 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10844 if ($row['checkout'] < $current_ts) {
10845 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10846 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10847 if ($row['checked'] == 1) {
10848 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10849 } elseif ($row['checked'] == -1) {
10850 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10851 }
10852 }
10853 } elseif ($row['status'] == 'standby') {
10854 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10855 } elseif ($row['status'] == 'cancelled') {
10856 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10857 } else {
10858 $booking_infos[$k]['status_lbl'] = $row['status'];
10859 }
10860 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10861 if ($booking_infos[$k]['colortag']) {
10862 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10863 }
10864 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10865 $booking_infos[$k]['tot_adults'] = $totadults;
10866 $booking_infos[$k]['tot_children'] = $totchildren;
10867 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10868 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10869
10870 // room indexes
10871 $rindexes = [];
10872 $av_room_indexes = [];
10873 $used_indexes_map = [];
10874 $sub_units_data = [];
10875 $optindexes = [];
10876 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10877 $missing_index = false;
10878 foreach ($rooms as $kor => $or) {
10879 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10880 // cannot build room indexes data
10881 continue;
10882 }
10883
10884 $room_params = json_decode($or['params'], true);
10885 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10886 // no distinctive features information
10887 continue;
10888 }
10889
10890 if (!strlen($or['roomindex'])) {
10891 // turn flag on for missing index when room does support them
10892 $missing_index = true;
10893 // build array with available room indexes
10894 $av_indexes = [];
10895 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10896 foreach ($room_params['features'] as $rind => $rfeatures) {
10897 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10898 continue;
10899 }
10900 foreach ($rfeatures as $fname => $fval) {
10901 if ($fval) {
10902 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10903 break;
10904 }
10905 }
10906 }
10907 if ($av_indexes) {
10908 // push available indexes for this room
10909 $av_room_indexes[$kor] = [
10910 'rid' => $or['idroom'],
10911 'name' => $or['room_name'],
10912 'list' => $av_indexes,
10913 ];
10914 }
10915 // do not proceed any further
10916 continue;
10917 }
10918
10919 // parse distinctive features
10920 foreach ($room_params['features'] as $rind => $rfeatures) {
10921 if ($rind != $or['roomindex']) {
10922 continue;
10923 }
10924 $ind_str = '';
10925 $ind_str_short = '';
10926 foreach ($rfeatures as $fname => $fval) {
10927 if (strlen($fval)) {
10928 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10929 $ind_str_short = $fval;
10930 break;
10931 }
10932 }
10933 if (!isset($rindexes[$or['room_name']])) {
10934 $rindexes[$or['room_name']] = $ind_str;
10935 $sub_units_data[$or['room_name']] = $ind_str_short;
10936 } else {
10937 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10938 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10939 }
10940 break;
10941 }
10942
10943 // build options to switch sub-unit index
10944 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10945 // build the options for switching the room index for this room
10946 foreach ($room_params['features'] as $rind => $rfeatures) {
10947 foreach ($rfeatures as $fname => $fval) {
10948 if (strlen((string)$fval)) {
10949 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10950 break;
10951 }
10952 }
10953 }
10954 }
10955 }
10956
10957 if ($rindexes) {
10958 $booking_infos[$k]['rindexes'] = $rindexes;
10959 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10960 }
10961
10962 if ($optindexes) {
10963 $booking_infos[$k]['optindexes'] = $optindexes;
10964 }
10965
10966 if ($missing_index && $av_room_indexes) {
10967 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10968 }
10969
10970 // include flag for missing room index
10971 $booking_infos[$k]['missing_index'] = $missing_index;
10972
10973 // channel provenience and small logo URL
10974 $ota_logo_img = JText::translate('VBORDFROMSITE');
10975 $booking_avatar_src = null;
10976 $booking_avatar_alt = null;
10977 if (!empty($row['channel'])) {
10978 $channelparts = explode('_', $row['channel']);
10979 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10980 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10981 if ($ota_logo_img === false) {
10982 $ota_logo_img = $otachannel;
10983 } else {
10984 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10985 }
10986 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10987 if ($logo_helper !== false) {
10988 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10989 $booking_avatar_alt = $logo_helper->provenience;
10990 }
10991 }
10992 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10993 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10994 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10995
10996 // Customer Details
10997 $custdata = $row['custdata'];
10998 $custdata_parts = explode("\n", $row['custdata']);
10999 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
11000 //get the first two fields
11001 $custvalues = [];
11002 foreach ($custdata_parts as $custdet) {
11003 if (strlen($custdet) < 1) {
11004 continue;
11005 }
11006 $custdet_parts = explode(':', $custdet);
11007 if (count($custdet_parts) >= 2) {
11008 unset($custdet_parts[0]);
11009 array_push($custvalues, trim(implode(':', $custdet_parts)));
11010 }
11011 if (count($custvalues) > 1) {
11012 break;
11013 }
11014 }
11015 if (count($custvalues) > 1) {
11016 $custdata = implode(' ', $custvalues);
11017 }
11018 }
11019 if (strlen($custdata) > 45) {
11020 $custdata = (function_exists('mb_substr') ? mb_substr($custdata, 0, 45, 'UTF-8') : substr($custdata, 0, 45)) . " ...";
11021 }
11022
11023 // customer record details
11024 $customer = [];
11025 $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'];
11026 $dbo->setQuery($q, 0, 1);
11027 $dbo->execute();
11028 if ($dbo->getNumRows()) {
11029 $customer = $dbo->loadAssoc();
11030 if (!empty($customer['first_name'])) {
11031 $custdata = $customer['first_name'].' '.$customer['last_name'];
11032 if (!empty($customer['country'])) {
11033 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
11034 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
11035 }
11036 }
11037 }
11038 }
11039 $booking_infos[$k]['customer'] = $customer;
11040
11041 // check if a profile picture is available for the customer
11042 if (!empty($customer['pic'])) {
11043 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
11044 $booking_avatar_alt = basename($booking_avatar_src);
11045 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
11046 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
11047 }
11048
11049 // whether this is a closure
11050 $booking_infos[$k]['closure'] = (int)$row['closure'];
11051 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
11052
11053 // short customer information
11054 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
11055 $booking_infos[$k]['cinfo'] = $custdata;
11056
11057 // formatted dates
11058 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
11059 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
11060 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
11061
11062 // short booking date, check-in, check-out date format
11063 $stay_info_in = getdate($row['checkin']);
11064 $stay_info_out = getdate($row['checkout']);
11065 $str_checkin = date('d', $row['checkin']);
11066 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
11067 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
11068 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
11069 $str_checkout .= ' ' . $stay_info_out['year'];
11070 }
11071 $booking_infos[$k]['checkin_short'] = $str_checkin;
11072 $booking_infos[$k]['checkout_short'] = $str_checkout;
11073 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
11074 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
11075 }
11076
11077 if (!$booking_infos) {
11078 if (!empty($pidroom) && $psharedcal) {
11079 // when this flag is enabled, we are excluding bookings not made directly
11080 // for the given room type ID, hence we may get an empty list due to shared calendars
11081 VBOHttpDocument::getInstance()->close(500, 'No bookings made directly for this room-type.');
11082 }
11083 // output the error
11084 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
11085 }
11086
11087 // output the JSON encoded response and exit
11088 VBOHttpDocument::getInstance()->json($booking_infos);
11089 }
11090
11091 /**
11092 * AJAX endpoint to switch a booking room index.
11093 *
11094 * @return void
11095 *
11096 * @since 1.18.2 (J) - 1.8.2 (WP) method refactored.
11097 * @since 1.18.7 (J) - 1.8.7 (WP) introduced history update.
11098 */
11099 public function switchRoomIndex()
11100 {
11101 if (!JSession::checkToken()) {
11102 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
11103 }
11104
11105 $app = JFactory::getApplication();
11106 $dbo = JFactory::getDbo();
11107
11108 $bid = $app->input->getInt('bid', 0);
11109 $rid = $app->input->getInt('rid', 0);
11110 $old_rindex = $app->input->getInt('old_rindex', 0);
11111 $new_rindex = $app->input->getInt('new_rindex', 0);
11112 $is_tmp_row = $app->input->getBool('is_tmp_row', false);
11113 $is_from_tmp_row = $app->input->getBool('is_from_tmp_row', false);
11114
11115 if (empty($bid) || empty($rid) || (empty($old_rindex) && !$is_from_tmp_row) || (empty($new_rindex) && !$is_tmp_row) || $new_rindex < 0) {
11116 // abort for missing or invalid room indexes
11117 VBOHttpDocument::getInstance($app)->close(200, 'e4j.error.#1 Missing Data');
11118 }
11119
11120 // fetch the current booking room record
11121 $dbo->setQuery(
11122 $dbo->getQuery(true)
11123 ->select('*')
11124 ->from($dbo->qn('#__vikbooking_ordersrooms'))
11125 ->where($dbo->qn('idorder') . ' = ' . $bid)
11126 ->where($dbo->qn('idroom') . ' = ' . $rid)
11127 ->where($dbo->qn('roomindex') . ((empty($old_rindex) || $old_rindex == -1) && $is_from_tmp_row ? ' IS NULL' : ' = ' . $old_rindex))
11128 ->order($dbo->qn('id') . ' ASC')
11129 );
11130 $roomRow = $dbo->loadAssoc();
11131
11132 if (!$roomRow) {
11133 // abort for record not found
11134 VBOHttpDocument::getInstance($app)->close(200, 'e4j.error.#2 Record not found');
11135 }
11136
11137 // load booking and booking rooms data for the history before updating
11138 $booking = VikBooking::getBookingInfoFromID($bid);
11139 $prev_booking_rooms = VikBooking::loadOrdersRoomsData($bid);
11140 $current_booking_rooms = $prev_booking_rooms;
11141 // update new room index for current booking rooms
11142 foreach ($current_booking_rooms as $k => $booking_room) {
11143 if ($booking_room['id'] == $roomRow['id']) {
11144 // update new room index
11145 $current_booking_rooms[$k]['roomindex'] = empty($new_rindex) && $is_tmp_row ? null : $new_rindex;
11146 break;
11147 }
11148 }
11149
11150 // update booking room record by switching sub-unit
11151 $dbo->setQuery(
11152 $dbo->getQuery(true)
11153 ->update($dbo->qn('#__vikbooking_ordersrooms'))
11154 ->set($dbo->qn('roomindex') . ' = ' . (empty($new_rindex) && $is_tmp_row ? 'NULL' : $new_rindex))
11155 ->where($dbo->qn('id') . ' = ' . (int) $roomRow['id'])
11156 );
11157 $dbo->execute();
11158
11159 // update history record by setting the proper bookings data
11160 $user = JFactory::getUser();
11161 VikBooking::getBookingHistoryInstance($bid)
11162 ->setPrevBooking(array_merge($booking, ['rooms_info' => $prev_booking_rooms]))
11163 ->setBookingData($booking, $current_booking_rooms)
11164 ->store(
11165 'MB',
11166 sprintf(
11167 '%s [%d → %d]',
11168 JText::translate('VBODEFAULTDISTFEATUREONE'),
11169 (int) $roomRow['roomindex'],
11170 (int) (empty($new_rindex) && $is_tmp_row ? 0 : $new_rindex)
11171 ) . " ({$user->name})"
11172 );
11173
11174 // process completed
11175 VBOHttpDocument::getInstance($app)->close(200, 'e4j.ok');
11176 }
11177
11178 public function searchcustomer()
11179 {
11180 // to be called via ajax
11181 $dbo = JFactory::getDbo();
11182
11183 $kw = VikRequest::getString('kw', '', 'request');
11184 $nopin = VikRequest::getInt('nopin', '', 'request');
11185 $email = VikRequest::getInt('email', 0, 'request');
11186 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
11187 $no_script = VikRequest::getInt('no_script', 0, 'request');
11188
11189 if (!strlen($kw)) {
11190 VBOHttpDocument::getInstance()->close(200, '');
11191 }
11192
11193 if ($nopin > 0) {
11194 //page all bookings
11195 $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;";
11196 } elseif ($email > 0) {
11197 // page calendar for checking if an email exists
11198 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
11199 } else {
11200 //page calendar
11201 $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;";
11202 }
11203 $dbo->setQuery($q);
11204 $customers = $dbo->loadAssocList();
11205
11206 if (!$customers) {
11207 VBOHttpDocument::getInstance()->close(200, '');
11208 }
11209
11210 if ($email > 0) {
11211 VBOHttpDocument::getInstance()->json($customers[0]);
11212 }
11213
11214 $cust_old_fields = array();
11215 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
11216 foreach ($customers as $k => $v) {
11217 $cstring_search .= '<div class="' . $selector . '" data-custid="' . (int) $v['id'] . '" data-email="' . htmlspecialchars($v['email']) . '" data-phone="' . htmlspecialchars($v['phone']) . '" data-country="' . htmlspecialchars($v['country']) . '" data-pin="' . htmlspecialchars($v['pin']) . '" data-firstname="' . htmlspecialchars($v['first_name']) . '" data-lastname="' . htmlspecialchars($v['last_name']) . '">'."\n";
11218 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
11219 if (!empty($v['pic'])) {
11220 $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";
11221 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
11222 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
11223 } else {
11224 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
11225 }
11226 $cstring_search .= '</span>';
11227 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
11228 if (!($nopin > 0)) {
11229 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
11230 }
11231 $cstring_search .= '</div>'."\n";
11232 if (!empty($v['cfields'])) {
11233 $oldfields = json_decode($v['cfields'], true);
11234 if (is_array($oldfields) && count($oldfields)) {
11235 $cust_old_fields[$v['id']] = $oldfields;
11236 }
11237 }
11238 }
11239 $cstring_search .= '</div>'."\n";
11240
11241 /**
11242 * Add the necessary JS code for the arrow navigation.
11243 */
11244 $cstring_search_js = '<script type="text/javascript">';
11245 $cstring_search_js .= '
11246 var vboCust = jQuery(".' . $selector . '");
11247 var vboCustSelected = null;
11248 var vboCustomerNavigationFn = (e) => {
11249 if (e.which === 40) {
11250 if (vboCustSelected) {
11251 vboCustSelected.removeClass("' . $selector . '-highligthed");
11252 next = vboCustSelected.next();
11253 if (next.length > 0) {
11254 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11255 } else {
11256 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11257 }
11258 } else {
11259 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
11260 }
11261 } else if (e.which === 38) {
11262 if (vboCustSelected) {
11263 vboCustSelected.removeClass("' . $selector . '-highligthed");
11264 next = vboCustSelected.prev();
11265 if (next.length > 0) {
11266 vboCustSelected = next.addClass("' . $selector . '-highligthed");
11267 } else {
11268 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11269 }
11270 } else {
11271 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
11272 }
11273 } else if (e.which === 13) {
11274 if (vboCustSelected) {
11275 vboCustSelected.trigger("click");
11276 }
11277 }
11278 };
11279 jQuery(window).off("keydown", vboCustomerNavigationFn);
11280 jQuery(window).keydown(vboCustomerNavigationFn);
11281 document.addEventListener("vbo-search-customers-navigation-dismissed", (e) => {
11282 jQuery(window).off("keydown", vboCustomerNavigationFn);
11283 })
11284 jQuery(".' . $selector . '").off("hover");
11285 jQuery(".' . $selector . '").hover(function() {
11286 if (vboCustSelected) {
11287 vboCustSelected.removeClass("' . $selector . '-highligthed");
11288 vboCustSelected = null;
11289 }
11290 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
11291 }, function() {
11292 if (vboCustSelected) {
11293 vboCustSelected.removeClass("' . $selector . '-highligthed");
11294 vboCustSelected = null;
11295 }
11296 jQuery(this).removeClass("' . $selector . '-highligthed");
11297 });';
11298 $cstring_search_js .= '</script>';
11299
11300 if (!$no_script) {
11301 // append JS
11302 $cstring_search .= $cstring_search_js;
11303 }
11304
11305 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
11306 }
11307
11308 public function sharesignaturelink() {
11309 //to be called via ajax
11310 $dbo = JFactory::getDBO();
11311 $response = array(
11312 'status' => 0,
11313 'error' => 'Generic Error'
11314 );
11315 $pbid = VikRequest::getInt('bid', '', 'request');
11316 $phow = VikRequest::getString('how', '', 'request');
11317 $pto = VikRequest::getString('to', '', 'request');
11318 $pcustomer = VikRequest::getInt('customer', '', 'request');
11319 $cpin = VikBooking::getCPinIstance();
11320 $customer_info = $cpin->getCustomerByID($pcustomer);
11321 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
11322 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
11323 $dbo->setQuery($q);
11324 $dbo->execute();
11325 if ($dbo->getNumRows() > 0) {
11326 $row = $dbo->loadAssoc();
11327
11328 $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'];
11329 if (VBOPlatformDetection::isWordPress()) {
11330 /**
11331 * @wponly Rewrite URI for front-end signature
11332 */
11333 $share_link = str_replace(JUri::root(), '', $share_link);
11334 $model = JModel::getInstance('vikbooking', 'shortcodes');
11335 $itemid = $model->all('post_id', $full = true);
11336 if (count($itemid)) {
11337 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
11338 }
11339 } else {
11340 /**
11341 * @joomlaonly
11342 */
11343 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
11344 if ($best_menuitem_id) {
11345 $share_base = str_replace(JUri::root(), '', $share_link);
11346 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
11347 }
11348 }
11349
11350 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11351 if ($phow == 'email') {
11352 $sender = VikBooking::getSenderMail();
11353 $vbo_app = VikBooking::getVboApplication();
11354 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
11355 $response['status'] = 1;
11356 } elseif ($phow == 'sms') {
11357 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
11358 $sms_api = VikBooking::getSMSAPIClass();
11359 $sms_api_params = VikBooking::getSMSParams();
11360 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
11361 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
11362 $sms_obj = new VikSmsApi(array(), $sms_api_params);
11363 $response_obj = $sms_obj->sendMessage($pto, $share_message);
11364 if ($sms_obj->validateResponse($response_obj)) {
11365 $response['status'] = 1;
11366 } else {
11367 $response['error'] = $sms_obj->getLog();
11368 }
11369 } else {
11370 $response['error'] = 'No SMS Provider Configured';
11371 }
11372 } else {
11373 $response['error'] = 'Invalid Sending Method';
11374 }
11375 } else {
11376 $response['error'] = 'Invalid Booking ID';
11377 }
11378 } else {
11379 $response['error'] = 'Empty values';
11380 }
11381
11382 echo json_encode($response);
11383 exit;
11384 }
11385
11386 public function dayselectioncount() {
11387 //to be called via ajax
11388 $tsinit = VikRequest::getString('dinit', '', 'request');
11389 $tsend = VikRequest::getString('dend', '', 'request');
11390 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
11391 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
11392 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
11393 $diff = $ptsend - $ptsinit;
11394 if ($diff >= 172800) {
11395 $datef = VikBooking::getDateFormat(true);
11396 if ($datef=="%d/%m/%Y") {
11397 $df = 'd-m-Y';
11398 } else {
11399 $df = 'Y-m-d';
11400 }
11401 //minimum 2 days for excluding some days
11402 $daysdiff = floor($diff / 86400);
11403 $infoinit = getdate($ptsinit);
11404 $select = '';
11405 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
11406 for($i = 0; $i <= $daysdiff; $i++) {
11407 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
11408 $infots = getdate($ts);
11409 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
11410 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
11411 }
11412 $select .= '</select></div>';
11413 //excluded days of the week
11414 if ($daysdiff >= 14) {
11415 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
11416 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
11417 $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>';
11418 $select .= '</optgroup>';
11419 $select .= '</select></div>';
11420 }
11421 //
11422 echo $select;
11423 } else {
11424 echo '';
11425 }
11426 } else {
11427 echo '';
11428 }
11429 exit;
11430 }
11431
11432 public function createcheckindoc()
11433 {
11434 if (!JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking')) {
11435 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11436 }
11437
11438 $cid = VikRequest::getVar('cid', array(0));
11439 $id = $cid[0];
11440
11441 $dbo = JFactory::getDBO();
11442 $mainframe = JFactory::getApplication();
11443 $vbo_tn = VikBooking::getTranslator();
11444 $lang = JFactory::getLanguage();
11445 $ptmpl = VikRequest::getString('tmpl', '', 'request');
11446 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
11447 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
11448 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
11449 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
11450 $dbo->setQuery($q);
11451 $row = $dbo->loadAssoc();
11452 if (!$row) {
11453 $mainframe->redirect('index.php');
11454 exit;
11455 }
11456 if (!empty($row['lang'])) {
11457 if ($lang->getTag() != $row['lang']) {
11458 if (VBOPlatformDetection::isWordPress()) {
11459 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
11460 } else {
11461 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
11462 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
11463 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
11464 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
11465 }
11466 }
11467 if ($vbo_tn->getDefaultLang() != $row['lang']) {
11468 // force the translation to start because contents should be translated
11469 $vbo_tn::$force_tolang = $row['lang'];
11470 }
11471 }
11472 $customer = array();
11473 $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'].";";
11474 $dbo->setQuery($q);
11475 $dbo->execute();
11476 if ($dbo->getNumRows() > 0) {
11477 $customer = $dbo->loadAssoc();
11478 if (!empty($customer['country'])) {
11479 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
11480 $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"/>';
11481 }
11482 }
11483 }
11484 if (!(count($customer) > 0)) {
11485 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11486 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11487 exit;
11488 }
11489 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
11490 //check if the signature has been submitted
11491 $signature_data = '';
11492 $cont_type = '';
11493 if (!empty($psignature)) {
11494 //check whether the format is accepted
11495 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
11496 $parts = explode(';base64,', $psignature);
11497 $cont_type_parts = explode('image/', $parts[0]);
11498 $cont_type = $cont_type_parts[1];
11499 if (!empty($parts[1])) {
11500 $signature_data = base64_decode($parts[1]);
11501 }
11502 }
11503 }
11504 if (!empty($signature_data)) {
11505 //write file
11506 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
11507 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
11508 $fp = fopen($filepath, 'w+');
11509 $bytes = fwrite($fp, $signature_data);
11510 fclose($fp);
11511 if ($bytes !== false && $bytes > 0) {
11512 //update the signature in the DB
11513 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
11514 $dbo->setQuery($q);
11515 $dbo->execute();
11516 $customer['signature'] = $sign_fname;
11517 //resize image for screens with high resolution
11518 if ($ppad_ratio > 1) {
11519 $new_width = floor(($ppad_width / 2));
11520 $creativik = new vikResizer();
11521 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
11522 } else {
11523 /**
11524 * @wponly - trigger files mirroring
11525 */
11526 VikBookingLoader::import('update.manager');
11527 VikBookingUpdateManager::triggerUploadBackup($filepath);
11528 //
11529 }
11530 //
11531 } else {
11532 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
11533 }
11534 }
11535 //
11536 //generate PDF for check-in document by parsing the apposite template file
11537 $booking_rooms = array();
11538 $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'].";";
11539 $dbo->setQuery($q);
11540 $dbo->execute();
11541 if ($dbo->getNumRows() > 0) {
11542 $booking_rooms = $dbo->loadAssocList();
11543 if (!empty($row['lang'])) {
11544 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
11545 }
11546 }
11547 if (!class_exists('TCPDF')) {
11548 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
11549 }
11550 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
11551
11552 /**
11553 * Trigger event to allow third party plugins to return a specific font name.
11554 *
11555 * @since 1.16.0 (J) - 1.6.0 (WP)
11556 */
11557 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
11558 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
11559 $usepdffont = $custom_pdf_font[0];
11560 }
11561
11562 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
11563 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
11564
11565 // build the proper document SID for bc
11566 $doc_sid = $row['sid'] ?: $row['idorderota'] ?: '';
11567 $pdffname = $row['id'] . '_' . $doc_sid . '.pdf';
11568
11569 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
11570 if (file_exists($pathpdf)) @unlink($pathpdf);
11571 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
11572 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
11573 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
11574 //Header for each page of the pdf
11575 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
11576 $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]);
11577 }
11578 //header and footer fonts
11579 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
11580 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
11581 //margins
11582 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
11583 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
11584 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
11585 //
11586 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
11587 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
11588 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
11589 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
11590 $pdf->SetPrintHeader(false);
11591 }
11592 if ($pdfparams['show_footer'] == 0) {
11593 $pdf->SetPrintFooter(false);
11594 }
11595 $pdf->AddPage();
11596 $pdf->writeHTML($checkin_body, true, false, true, false, '');
11597 $pdf->lastPage();
11598 $pdf->Output($pathpdf, 'F');
11599 if (!file_exists($pathpdf)) {
11600 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
11601 } else {
11602 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
11603 $dbo->setQuery($q);
11604 $dbo->execute();
11605 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
11606 /**
11607 * @wponly - trigger files mirroring
11608 */
11609 VikBookingLoader::import('update.manager');
11610 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
11611 //
11612 }
11613 //
11614 /**
11615 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
11616 */
11617 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
11618 exit;
11619 }
11620
11621 public function updatebookingcheckin()
11622 {
11623 if (!JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking')) {
11624 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
11625 }
11626
11627 $cid = VikRequest::getVar('cid', array(0));
11628 $id = $cid[0];
11629
11630 $dbo = JFactory::getDbo();
11631 $app = JFactory::getApplication();
11632
11633 $ptmpl = $app->input->getString('tmpl', '');
11634 $pnewtotpaid = $app->input->getFloat('newtotpaid', 0);
11635 $pguests = $app->input->get('guests', [], 'array');
11636 $pcomments = JComponentHelper::filterText($app->input->get('comments', '', 'raw'));
11637 $pcheckin_action = $app->input->getInt('checkin_action', 0);
11638 $valid_actions = array(-1, 0, 1, 2);
11639 if (!in_array($pcheckin_action, $valid_actions)) {
11640 $app->redirect('index.php');
11641 exit;
11642 }
11643 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
11644 $dbo->setQuery($q);
11645 $dbo->execute();
11646 if ($dbo->getNumRows() < 1) {
11647 $app->redirect('index.php');
11648 exit;
11649 }
11650 $row = $dbo->loadAssoc();
11651 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
11652 $dbo->setQuery($q);
11653 $dbo->execute();
11654 if ($dbo->getNumRows() < 1) {
11655 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
11656 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
11657 exit;
11658 }
11659 $custorder = $dbo->loadAssoc();
11660 //update checked status and new total paid
11661 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
11662 $dbo->setQuery($q);
11663 $dbo->execute();
11664 // Booking History log for new amount paid (payment update)
11665 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
11666 $extra_data = new stdClass;
11667 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
11668 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
11669 }
11670 //
11671 //Booking History
11672 $hist_type = 'A';
11673 if ($pcheckin_action < 0) {
11674 $hist_type = 'Z';
11675 } elseif ($pcheckin_action == 1) {
11676 $hist_type = 'B';
11677 } elseif ($pcheckin_action == 2) {
11678 $hist_type = 'C';
11679 }
11680 $user = JFactory::getUser();
11681 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
11682 //
11683 //Guests Details
11684 $guests_details = array();
11685 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
11686 // grab also the fields for front-end pre check-in
11687 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
11688 //
11689 foreach ($pguests as $ind => $adults) {
11690 foreach ($adults as $aduind => $details) {
11691 foreach ($pax_fields as $key => $v) {
11692 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11693 if (!isset($guests_details[$ind])) {
11694 $guests_details[$ind] = array();
11695 }
11696 if (!isset($guests_details[$ind][$aduind])) {
11697 $guests_details[$ind][$aduind] = array();
11698 }
11699 $guests_details[$ind][$aduind][$key] = $details[$key];
11700 }
11701 }
11702 foreach ($pre_pax_fields as $key => $v) {
11703 if (isset($pax_fields[$key])) {
11704 // we must have parsed this back-end field already
11705 continue;
11706 }
11707 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11708 if (!isset($guests_details[$ind])) {
11709 $guests_details[$ind] = array();
11710 }
11711 if (!isset($guests_details[$ind][$aduind])) {
11712 $guests_details[$ind][$aduind] = array();
11713 }
11714 if (!isset($guests_details[$ind][$aduind][$key])) {
11715 $guests_details[$ind][$aduind][$key] = $details[$key];
11716 }
11717 }
11718 }
11719 }
11720 }
11721
11722 if ($guests_details) {
11723 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
11724 $curpaxdata = json_decode($custorder['pax_data'], true);
11725 if (is_array($curpaxdata) && $curpaxdata) {
11726 // scan new guest registration details
11727 foreach ($guests_details as $ind => $groom) {
11728 foreach ($groom as $aduind => $aduinfo) {
11729 if (isset($curpaxdata[$ind][$aduind])) {
11730 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
11731 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
11732 foreach ($guests_details[$ind][$aduind] as $key => $det) {
11733 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
11734 // this default pax field was specified as empty now, so we cannot merge it
11735 unset($guests_details[$ind][$aduind][$key]);
11736 }
11737 }
11738 }
11739 }
11740 }
11741
11742 /**
11743 * In order to not lose any custom registration data added through PMS reports,
11744 * we scan the previous registration data to ensure we keep them in the update.
11745 *
11746 * @since 1.16.10 (J) - 1.6.10 (WP)
11747 */
11748 foreach ($curpaxdata as $ind => $groom) {
11749 if (!isset($guests_details[$ind])) {
11750 // ignore deleted room registration
11751 continue;
11752 }
11753 foreach ($groom as $aduind => $aduinfo) {
11754 if (!isset($guests_details[$ind][$aduind]) || !is_array($aduinfo)) {
11755 // ignore deleted room-guest registration
11756 continue;
11757 }
11758 foreach ($aduinfo as $field_key => $field_val) {
11759 if (!isset($guests_details[$ind][$aduind][$field_key]) && !empty($field_val)) {
11760 // merge previous room-guest registration data
11761 $guests_details[$ind][$aduind][$field_key] = $field_val;
11762 }
11763 }
11764 }
11765 }
11766 }
11767
11768 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=" . $dbo->q(json_encode($guests_details)) . " WHERE `id`=" . (int) $custorder['id'] . ";";
11769 $dbo->setQuery($q);
11770 $dbo->execute();
11771 }
11772
11773 //'checked' status comments
11774 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11775 $dbo->setQuery($q);
11776 $dbo->execute();
11777
11778 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11779 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11780 exit;
11781 }
11782
11783 public function alterbooking()
11784 {
11785 $dbo = JFactory::getDbo();
11786 $app = JFactory::getApplication();
11787 $user = JFactory::getUser();
11788
11789 $response = array(
11790 'esit' => 1,
11791 'message' => '',
11792 'vcm' => '',
11793 );
11794
11795 // must be a string as it may contain a dash
11796 $pidorder = VikRequest::getString('idorder', '', 'request');
11797 $pidorder = intval(str_replace('-', '', $pidorder));
11798
11799 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11800 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11801 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11802 $ptodate = VikRequest::getString('todate', '', 'request');
11803 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11804 if ($pdebug == 1) {
11805 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11806 exit;
11807 }
11808
11809 $nowdf = VikBooking::getDateFormat(true);
11810 if ($nowdf == "%d/%m/%Y") {
11811 $df = 'd/m/Y';
11812 } elseif ($nowdf == "%m/%d/%Y") {
11813 $df = 'm/d/Y';
11814 } else {
11815 $df = 'Y/m/d';
11816 }
11817 $pcheckinh = 0;
11818 $pcheckinm = 0;
11819 $pcheckouth = 0;
11820 $pcheckoutm = 0;
11821 $timeopst = VikBooking::getTimeOpenStore();
11822 if (is_array($timeopst)) {
11823 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11824 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11825 $pcheckinh = $opent[0];
11826 $pcheckinm = $opent[1];
11827 $pcheckouth = $closet[0];
11828 $pcheckoutm = $closet[1];
11829 }
11830 $info_tsto = getdate(strtotime($ptodate));
11831 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11832 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11833 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11834 $ptodate = date('Y-m-d', $second);
11835 if (!($second > $first)) {
11836 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11837 exit;
11838 }
11839 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11840 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11841 exit;
11842 }
11843
11844 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11845 $dbo->setQuery($q, 0, 1);
11846 $dbo->execute();
11847 if (!$dbo->getNumRows()) {
11848 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11849 exit;
11850 }
11851 $ord = $dbo->loadAssoc();
11852
11853 $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;";
11854 $dbo->setQuery($q);
11855 $dbo->execute();
11856 $ordersrooms = $dbo->loadAssocList();
11857
11858 // store for VCM the current rooms before the modification
11859 $ord['rooms_info'] = $ordersrooms;
11860
11861 // package or custom rate
11862 $is_package = !empty($ord['pkg']) ? true : false;
11863 $is_cust_cost = false;
11864 foreach ($ordersrooms as $kor => $or) {
11865 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11866 $is_cust_cost = true;
11867 break;
11868 }
11869 }
11870
11871 // availability helper
11872 $av_helper = VikBooking::getAvailabilityInstance();
11873
11874 // room stay dates in case of split stay
11875 $room_stay_dates = [];
11876 if ($ord['split_stay']) {
11877 // no need to get the transient based on booking status, as the booking must be confirmed
11878 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11879 // immediately count the number of nights of stay for each split room
11880 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11881 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11882 }
11883 }
11884
11885 // determine if dates have changed
11886 $dates_changed = false;
11887 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11888 $dates_changed = true;
11889 }
11890
11891 $toswitch = array();
11892 $idbooked = array();
11893 $rooms_units = array();
11894 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11895 $dbo->setQuery($q);
11896 $dbo->execute();
11897 $all_rooms = $dbo->loadAssocList();
11898 foreach ($all_rooms as $rr) {
11899 $rooms_units[$rr['id']]['name'] = $rr['name'];
11900 $rooms_units[$rr['id']]['units'] = $rr['units'];
11901 }
11902
11903 // switch room
11904 if ($poldidroom != $pidroom) {
11905 foreach ($ordersrooms as $ind => $or) {
11906 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11907 if (!isset($idbooked[$or['idroom']])) {
11908 $idbooked[$or['idroom']] = 0;
11909 }
11910 // $idbooked is not really needed as switch is never made for the same room id
11911 $idbooked[$or['idroom']]++;
11912 //
11913 $orkey = count($toswitch);
11914 $toswitch[$orkey]['from'] = $or['idroom'];
11915 $toswitch[$orkey]['to'] = $pidroom;
11916 $toswitch[$orkey]['record'] = $or;
11917 $toswitch[$orkey]['record_ind'] = $ind;
11918 break;
11919 }
11920 }
11921 }
11922 if (count($toswitch)) {
11923 foreach ($toswitch as $ksw => $rsw) {
11924 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11925 $room_checkin = $ord['checkin'];
11926 $room_checkout = $ord['checkout'];
11927 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11928 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11929 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11930 }
11931 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11932 // the room is not available
11933 unset($toswitch[$ksw]);
11934 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11935 exit;
11936 }
11937 }
11938 if (count($toswitch)) {
11939 //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)
11940 reset($ordersrooms);
11941 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11942 $dbo->setQuery($q);
11943 $dbo->execute();
11944 //
11945 foreach ($toswitch as $ksw => $rsw) {
11946 // update room reservation record
11947 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11948 $dbo->setQuery($q);
11949 $dbo->execute();
11950 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11951
11952 // update Notes field for this booking to keep track of the previous room that was assigned
11953 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11954 if (!empty($prev_room_name)) {
11955 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11956 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11957 $dbo->setQuery($q);
11958 $dbo->execute();
11959 }
11960
11961 if ($ord['status'] == 'confirmed') {
11962 // update room record in _busy
11963 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'])) {
11964 // in case of a split stay it is fundamental to update the exact busy record ID
11965 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11966 $dbo->setQuery($q);
11967 $dbo->execute();
11968 } else {
11969 // regular processing of a room ID for a reservation, no matter which one, we switch it
11970 $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;";
11971 $dbo->setQuery($q);
11972 $dbo->execute();
11973 if ($dbo->getNumRows() == 1) {
11974 $cur_busy = $dbo->loadAssocList();
11975 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11976 $dbo->setQuery($q);
11977 $dbo->execute();
11978 }
11979 }
11980
11981 // if automated updates enabled, keep $response['vcm'] empty
11982 // Invoke Channel Manager
11983 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11984 $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>';
11985 }
11986 } elseif ($ord['status'] == 'standby') {
11987 // remove record in _tmplock
11988 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11989 $dbo->setQuery($q);
11990 $dbo->execute();
11991 }
11992 }
11993
11994 // check if sub-units should be assigned again when switching room
11995 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11996 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11997 $room_indexes_usemap = [];
11998 foreach ($new_order_rooms as $kor => $or) {
11999 $num = $kor + 1;
12000 // assign room specific unit
12001 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
12002 $use_ind_key = 0;
12003 if ($room_indexes) {
12004 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
12005 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
12006 } else {
12007 $use_ind_key = $room_indexes_usemap[$or['idroom']];
12008 }
12009 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
12010 $dbo->setQuery($q);
12011 $dbo->execute();
12012 $room_indexes_usemap[$or['idroom']]++;
12013 }
12014 }
12015 }
12016
12017 // do not terminate the process when there is a switch, proceed to check the dates.
12018 }
12019 }
12020
12021 // change dates
12022 if ($dates_changed) {
12023 if ($ord['split_stay']) {
12024 // we do not allow to drag and change dates for rooms in a split stay reservation
12025 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
12026 exit;
12027 }
12028
12029 // total nights of stay
12030 $daysdiff = $ord['days'];
12031
12032 // re-read ordersrooms (as rooms may have been switched)
12033 $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;";
12034 $dbo->setQuery($q);
12035 $dbo->execute();
12036 $ordersrooms = $dbo->loadAssocList();
12037
12038 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
12039 $opertwounits = true;
12040 $units_counter = array();
12041 foreach ($ordersrooms as $ind => $or) {
12042 if (!isset($units_counter[$or['idroom']])) {
12043 $units_counter[$or['idroom']] = -1;
12044 }
12045 $units_counter[$or['idroom']]++;
12046 }
12047
12048 foreach ($ordersrooms as $ind => $or) {
12049 $num = $ind + 1;
12050 $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'] . ";";
12051 $dbo->setQuery($check);
12052 $dbo->execute();
12053 if ($dbo->getNumRows() > 0) {
12054 $busy = $dbo->loadAssocList();
12055 foreach ($groupdays as $gday) {
12056 $bfound = 0;
12057 foreach ($busy as $bu) {
12058 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
12059 $bfound++;
12060 }
12061 }
12062 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
12063 $opertwounits = false;
12064 break 2;
12065 }
12066 }
12067 }
12068 }
12069 if ($opertwounits !== true) {
12070 $response['esit'] = 0;
12071 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
12072 echo json_encode($response);
12073 exit;
12074 }
12075
12076 // update dates and busy records
12077 $realback = VikBooking::getHoursRoomAvail() * 3600;
12078 $realback += $second;
12079 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
12080 $dbo->setQuery($q);
12081 $dbo->execute();
12082 if ($ord['status'] == 'confirmed') {
12083 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
12084 $dbo->setQuery($q);
12085 $dbo->execute();
12086 $allbusy = $dbo->loadAssocList();
12087 foreach ($allbusy as $bb) {
12088 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
12089 $dbo->setQuery($q);
12090 $dbo->execute();
12091 }
12092 // if automated updates enabled, keep $response['vcm'] empty
12093 // Invoke Channel Manager
12094 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
12095 $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>';
12096 }
12097 }
12098 $response['message'] .= JText::translate('RESUPDATED')."\n";
12099 }
12100
12101 if (count($toswitch)) {
12102 /**
12103 * Rooms have changed so the new rates must be re-calculated.
12104 * Maybe they should be calculated in any case, even if just
12105 * the dates have changed. For the moment the rates are reset.
12106 */
12107 }
12108
12109 // unset any previously booked room due to calendar sharing
12110 VikBooking::cleanSharedCalendarsBusy($ord['id']);
12111 // check if some of the rooms booked have shared calendars
12112 VikBooking::updateSharedCalendars($ord['id']);
12113 //
12114
12115 //Booking History
12116 VikBooking::getBookingHistoryInstance($ord['id'])->setPrevBooking($ord)->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
12117 //
12118
12119 $vcm_autosync = VikBooking::vcmAutoUpdate();
12120 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
12121 //unset the vcm property as no buttons should be displayed when in auto-sync
12122 $response['vcm'] = '';
12123 $vcm_obj = VikBooking::getVcmInvoker();
12124 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
12125 $sync_result = $vcm_obj->doSync();
12126 if ($sync_result === false) {
12127 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
12128 }
12129 }
12130
12131 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
12132 if ($response['esit'] < 1 && !empty($response['vcm'])) {
12133 VikError::raiseNotice('', $response['vcm']);
12134 }
12135
12136 $response['message'] = nl2br($response['message']);
12137 echo json_encode($response);
12138 exit;
12139 }
12140
12141 public function modroomrateplans()
12142 {
12143 $dbo = JFactory::getDbo();
12144 $session = JFactory::getSession();
12145
12146 $updforvcm = $session->get('vbVcmRatesUpd', '');
12147 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
12148
12149 $pid_room = VikRequest::getInt('id_room', '', 'request');
12150 $pid_price = VikRequest::getInt('id_price', '', 'request');
12151 $ptype = VikRequest::getString('type', '', 'request');
12152 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12153 $ptodate = VikRequest::getString('todate', '', 'request');
12154
12155 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
12156 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
12157 exit;
12158 }
12159
12160 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
12161 $dbo->setQuery($q);
12162 $price_record = $dbo->loadAssoc();
12163
12164 if (!$price_record) {
12165 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
12166 exit;
12167 }
12168
12169 $current_closed = array();
12170 if (!empty($price_record['closingd'])) {
12171 $current_closed = json_decode($price_record['closingd'], true);
12172 }
12173 $current_closed = !is_array($current_closed) ? array() : $current_closed;
12174
12175 $start_ts = strtotime($pfromdate);
12176 $end_ts = strtotime($ptodate);
12177 $infostart = getdate($start_ts);
12178 $all_days = array();
12179 $output = array();
12180 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
12181 $all_days[] = date('Y-m-d', $infostart[0]);
12182 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
12183 $output[$indkey] = array();
12184 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
12185 }
12186
12187 if ($ptype == 'close') {
12188 // close
12189 if (!array_key_exists($pid_room, $current_closed)) {
12190 $current_closed[$pid_room] = array();
12191 }
12192 foreach ($all_days as $daymod) {
12193 if (!in_array($daymod, $current_closed[$pid_room])) {
12194 $current_closed[$pid_room][] = $daymod;
12195 }
12196 }
12197 } else {
12198 // open
12199 if (array_key_exists($pid_room, $current_closed)) {
12200 foreach ($all_days as $daymod) {
12201 if (in_array($daymod, $current_closed[$pid_room])) {
12202 foreach ($current_closed[$pid_room] as $ck => $cv) {
12203 if ($daymod == $cv) {
12204 unset($current_closed[$pid_room][$ck]);
12205 }
12206 }
12207 }
12208 }
12209 } else {
12210 $current_closed[$pid_room] = array();
12211 }
12212 }
12213
12214 if (!$current_closed[$pid_room]) {
12215 unset($current_closed[$pid_room]);
12216 }
12217
12218 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
12219 $dbo->setQuery($q);
12220 $dbo->execute();
12221
12222 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
12223 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
12224
12225 foreach ($output as $ok => $ov) {
12226 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
12227 }
12228
12229 // build new session values
12230 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
12231
12232 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
12233 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
12234 } else {
12235 $updforvcm['dfrom'] = $start_ts;
12236 }
12237
12238 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
12239 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
12240 } else {
12241 $updforvcm['dto'] = $end_ts;
12242 }
12243
12244 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
12245 if (!in_array($pid_room, $updforvcm['rooms'])) {
12246 $updforvcm['rooms'][] = $pid_room;
12247 }
12248 } else {
12249 $updforvcm['rooms'] = array($pid_room);
12250 }
12251
12252 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
12253 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
12254 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
12255 $updforvcm['rplans'][$pid_room][] = $pid_price;
12256 }
12257 } else {
12258 $updforvcm['rplans'][$pid_room] = array($pid_price);
12259 }
12260 } else {
12261 $updforvcm['rplans'] = array($pid_room => array($pid_price));
12262 }
12263
12264 /**
12265 * Rather than suggesting the administrator to manually invoke VCM to launch a Bulk Action,
12266 * we try to silently trigger an automatic bulk action before updating the session values.
12267 *
12268 * @since 1.17.1 (J) - 1.7.1 (WP)
12269 * @since 1.17.5 (J) - 1.7.5 (WP) the "rate_id" property is passed along the auto-bulk data.
12270 */
12271 $rates_aligned = false;
12272 try {
12273 if (class_exists('VikChannelManager')) {
12274 $rates_aligned = VikChannelManager::autoBulkActions([
12275 'from_date' => $pfromdate,
12276 'to_date' => $ptodate,
12277 'forced_rooms' => [$pid_room],
12278 'rate_id' => $pid_price,
12279 'update' => 'rates',
12280 ]);
12281 }
12282 } catch (Throwable $e) {
12283 // do nothing
12284 $rates_aligned = false;
12285 }
12286
12287 if (!$rates_aligned) {
12288 // update session values
12289 $session->set('vbVcmRatesUpd', $updforvcm);
12290 }
12291
12292 echo json_encode($output);
12293 exit;
12294 }
12295
12296 public function icsexportlaunch() {
12297 $dbo = JFactory::getDBO();
12298 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12299 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12300 $pstatus = VikRequest::getString('status', '', 'request');
12301 $validstatus = array('confirmed', 'standby', 'cancelled');
12302 $filterstatus = '';
12303 $filterfirst = 0;
12304 $filtersecond = 0;
12305 $nowdf = VikBooking::getDateFormat(true);
12306 if ($nowdf == "%d/%m/%Y") {
12307 $df = 'd/m/Y';
12308 } elseif ($nowdf == "%m/%d/%Y") {
12309 $df = 'm/d/Y';
12310 } else {
12311 $df = 'Y/m/d';
12312 }
12313 $currencyname = VikBooking::getCurrencyName();
12314 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12315 $filterstatus = $pstatus;
12316 }
12317 if (!empty($pcheckindate)) {
12318 if (VikBooking::dateIsValid($pcheckindate)) {
12319 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12320 $filterfirst = $first;
12321 }
12322 }
12323 if (!empty($pcheckoutdate)) {
12324 if (VikBooking::dateIsValid($pcheckoutdate)) {
12325 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12326 if ($second > $first) {
12327 $filtersecond = $second;
12328 }
12329 }
12330 }
12331 $clause = array();
12332 if ($filterfirst > 0) {
12333 $clause[] = "`o`.`checkin` >= ".$filterfirst;
12334 }
12335 if ($filtersecond > 0) {
12336 $clause[] = "`o`.`checkout` <= ".$filtersecond;
12337 }
12338 if (!empty($filterstatus)) {
12339 $clause[] = "`o`.`status` = '".$filterstatus."'";
12340 }
12341 $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;";
12342 $dbo->setQuery($q);
12343 $dbo->execute();
12344 if ($dbo->getNumRows() > 0) {
12345 $orders = $dbo->loadAssocList();
12346 $icscontent = "BEGIN:VCALENDAR\n";
12347 $icscontent .= "VERSION:2.0\n";
12348 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
12349 $icscontent .= "CALSCALE:GREGORIAN\n";
12350 $str = "";
12351 foreach ($orders as $kord => $ord) {
12352 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12353 continue;
12354 }
12355 $usecurrencyname = $currencyname;
12356 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12357 $statusstr = '';
12358 if ($ord['status'] == 'confirmed') {
12359 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12360 } elseif ($ord['status'] == 'standby') {
12361 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12362 } elseif ($ord['status'] == 'cancelled') {
12363 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12364 }
12365 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
12366 /**
12367 * @wponly Rewrite URI for front-end
12368 */
12369 $uri = str_replace(JUri::root(), '', $uri);
12370 $model = JModel::getInstance('vikbooking', 'shortcodes');
12371 $itemid = $model->best('booking');
12372 if ($itemid) {
12373 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
12374 }
12375 //
12376 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
12377 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12378 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
12379 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
12380 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
12381 $str .= "BEGIN:VEVENT\n";
12382 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12383 $str .= "UID:" . uniqid() . "\n";
12384 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12385 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
12386 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
12387 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
12388 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
12389 $str .= "END:VEVENT\n";
12390 }
12391 $icscontent .= $str;
12392 $icscontent .= "END:VCALENDAR\n";
12393 //download file from buffer
12394 header("Content-Type: application/octet-stream; ");
12395 header("Cache-Control: no-store, no-cache");
12396 header('Content-Disposition: attachment; filename="bookings_export.ics"');
12397 $f = fopen('php://output', "w");
12398 fwrite($f, $icscontent);
12399 fclose($f);
12400 exit;
12401 } else {
12402 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
12403 $mainframe = JFactory::getApplication();
12404 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12405 }
12406 }
12407
12408 public function csvexportlaunch()
12409 {
12410 $dbo = JFactory::getDbo();
12411 $app = JFactory::getApplication();
12412
12413 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
12414 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
12415 $pchfilt = VikRequest::getString('chfilt', '', 'request');
12416 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
12417 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
12418 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
12419 $pstatus = VikRequest::getString('status', '', 'request');
12420 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
12421 $pformat = VikRequest::getString('format', 'csv', 'request');
12422
12423 // let the report class (a generic one) generate the CSV file in the proper format
12424 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
12425
12426 $validstatus = array('confirmed', 'standby', 'cancelled');
12427 $validdates = array('ts', 'checkin', 'checkout');
12428
12429 $filterdate = '';
12430 $filterstatus = '';
12431 $first = 0;
12432 $filterfirst = 0;
12433 $filtersecond = 0;
12434 $nowdf = VikBooking::getDateFormat(true);
12435 if ($nowdf == "%d/%m/%Y") {
12436 $df = 'd/m/Y';
12437 } elseif ($nowdf == "%m/%d/%Y") {
12438 $df = 'm/d/Y';
12439 } else {
12440 $df = 'Y/m/d';
12441 }
12442 $datesep = VikBooking::getDateSeparator(true);
12443 $currencyname = VikBooking::getCurrencyName();
12444
12445 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
12446 $filterstatus = $pstatus;
12447 }
12448 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
12449 $filterdate = $pdatefilt;
12450 }
12451 if (!empty($pcheckindate) && !empty($filterdate)) {
12452 if (VikBooking::dateIsValid($pcheckindate)) {
12453 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
12454 $filterfirst = $first;
12455 }
12456 }
12457 if (!empty($pcheckoutdate) && !empty($filterdate)) {
12458 if (VikBooking::dateIsValid($pcheckoutdate)) {
12459 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
12460 if ($second > $first) {
12461 $filtersecond = $second;
12462 }
12463 }
12464 }
12465 $clause = array();
12466 if ($filterfirst > 0) {
12467 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
12468 }
12469 if ($filtersecond > 0) {
12470 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
12471 }
12472 if (!empty($filterstatus)) {
12473 $clause[] = "`o`.`status` = '".$filterstatus."'";
12474 }
12475 if (!empty($pchfilt)) {
12476 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
12477 }
12478 if (!empty($ppayfilt)) {
12479 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
12480 }
12481 if (!empty($proomfilt)) {
12482 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
12483 }
12484
12485 if (!empty($pcatfilt)) {
12486 $room_cat_ids = array();
12487 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
12488 $dbo->setQuery($q);
12489 $dbo->execute();
12490 if ($dbo->getNumRows()) {
12491 $records = $dbo->loadAssocList();
12492 foreach ($records as $rcat) {
12493 $parts = explode(';', $rcat['idcat']);
12494 if (in_array($pcatfilt, $parts)) {
12495 $room_cat_ids[] = $rcat['id'];
12496 }
12497 }
12498 }
12499 if (count($room_cat_ids)) {
12500 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
12501 }
12502 }
12503
12504 $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;";
12505 $dbo->setQuery($q);
12506 $orders = $dbo->loadAssocList();
12507 if (!$orders) {
12508 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
12509 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
12510 $app->close();
12511 }
12512
12513 // options
12514 $all_options = array();
12515 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
12516 $dbo->setQuery($q);
12517 $options = $dbo->loadAssocList();
12518 if ($options) {
12519 foreach ($options as $ok => $ov) {
12520 $all_options[$ov['id']] = $ov;
12521 }
12522 }
12523
12524 // build columns
12525 $columns = [
12526 [
12527 'label' => JText::translate('VBDASHBOOKINGID'),
12528 ],
12529 [
12530 'label' => JText::translate('VBPVIEWORDERSONE'),
12531 ],
12532 [
12533 'label' => JText::translate('VBCSVCHECKIN'),
12534 ],
12535 [
12536 'label' => JText::translate('VBCSVCHECKOUT'),
12537 ],
12538 [
12539 'label' => JText::translate('VBCSVNIGHTS'),
12540 ],
12541 [
12542 'label' => JText::translate('VBCSVROOM'),
12543 ],
12544 [
12545 'label' => JText::translate('VBCSVPEOPLE'),
12546 ],
12547 [
12548 'label' => JText::translate('VBCSVCUSTINFO'),
12549 ],
12550 [
12551 'label' => JText::translate('ORDER_SPREQUESTS'),
12552 ],
12553 [
12554 'label' => JText::translate('ORDER_NOTES'),
12555 ],
12556 [
12557 'label' => JText::translate('VBCSVCREATEDBY'),
12558 ],
12559 [
12560 'label' => JText::translate('VBCSVCUSTMAIL'),
12561 ],
12562 [
12563 'label' => JText::translate('ORDER_PHONE'),
12564 ],
12565 [
12566 'label' => JText::translate('VBCSVOPTIONS'),
12567 ],
12568 [
12569 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
12570 ],
12571 [
12572 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
12573 ],
12574 [
12575 'label' => JText::translate('VBOCHANNEL'),
12576 ],
12577 [
12578 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
12579 ],
12580 [
12581 'label' => JText::translate('VBCSVTOTAL'),
12582 ],
12583 [
12584 'label' => JText::translate('VBCSVTOTPAID'),
12585 ],
12586 [
12587 'label' => JText::translate('VBCSVTOTTAXES'),
12588 ],
12589 ];
12590
12591 // booking cancellation details
12592 $cancellation_timestamps = [];
12593
12594 if (empty($filterstatus) || $filterstatus === 'cancelled') {
12595 // insert column for cancellation date at index 2
12596 array_splice($columns, 2, 0, [['label' => JText::translate('VBO_CANC_DATE')]]);
12597 // gather all cancelled bookings, if any
12598 $cancellation_ids = [];
12599 foreach ($orders as $order) {
12600 if ($order['status'] === 'cancelled' && !in_array($order['id'], $cancellation_ids)) {
12601 $cancellation_ids[] = $order['id'];
12602 }
12603 }
12604 if ($cancellation_ids && $cancHistoryEvents = VikBooking::getBookingHistoryInstance(0)->getBookingEventsType('cancelled')) {
12605 // list of booking IDs with cancellation events processed
12606 $cancBidsProcessed = [];
12607
12608 // query the database to fetch the needed history records
12609 $dbo->setQuery(
12610 $dbo->getQuery(true)
12611 ->select([
12612 $dbo->qn('idorder'),
12613 $dbo->qn('dt'),
12614 ])
12615 ->from($dbo->qn('#__vikbooking_orderhistory'))
12616 ->where($dbo->qn('idorder') . ' IN (' . implode(', ', array_map('intval', $cancellation_ids)) . ')')
12617 ->where($dbo->qn('type') . ' IN (' . implode(', ', array_map([$dbo, 'q'], $cancHistoryEvents)) . ')')
12618 ->order($dbo->qn('idorder') . ' ASC')
12619 ->order($dbo->qn('dt') . ' ASC')
12620 );
12621
12622 // scan all booking cancellation records
12623 foreach ($dbo->loadAssocList() as $cancRecord) {
12624 if (!($cancBidsProcessed[$cancRecord['idorder']] ?? 0)) {
12625 // turn flag on to process this booking only once and get the earliest (first) cancellation
12626 $cancBidsProcessed[$cancRecord['idorder']] = 1;
12627
12628 // convert the cancellation date from UTC to local timezone and set booking cancellation timestamp
12629 $cancellation_timestamps[$cancRecord['idorder']] = JHtml::fetch('date', $cancRecord['dt'], 'U');
12630 }
12631 }
12632 }
12633 }
12634
12635 // set CSV columns
12636 $report_obj->setReportCols($columns);
12637
12638 // prepare the container for the CSV rows
12639 $orderscsv = [];
12640
12641 // availability helper
12642 $av_helper = VikBooking::getAvailabilityInstance();
12643
12644 $room_inds = [];
12645 $room_stay_dates = [];
12646 foreach ($orders as $kord => $ord) {
12647 // room index in this booking
12648 if (!isset($room_inds[$ord['id']])) {
12649 $room_inds[$ord['id']] = -1;
12650 }
12651 $room_inds[$ord['id']]++;
12652
12653 /**
12654 * Split stay reservation.
12655 *
12656 * @since 1.16.0 (J) - 1.6.0 (WP)
12657 */
12658 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
12659 if ($ord['split_stay']) {
12660 if ($ord['status'] == 'confirmed') {
12661 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
12662 } else {
12663 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
12664 }
12665 // immediately count the number of nights of stay for each split room
12666 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
12667 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
12668 // overwrite values for compatibility with non-confirmed bookings
12669 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
12670 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
12671 }
12672 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
12673 // overwrite the whole array
12674 $room_stay_dates[$sps_r_k] = $sps_r_v;
12675 }
12676 }
12677
12678 // determine nights and dates for this room booking
12679 $booking_nights = $ord['days'];
12680 $booking_checkin = $ord['checkin'];
12681 $booking_checkout = $ord['checkout'];
12682 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']) {
12683 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
12684 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
12685 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
12686 }
12687
12688 $usecurrencyname = $currencyname;
12689 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
12690 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
12691 $custinfostr = str_replace(",", " ", $ord['custdata']);
12692 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
12693 if (count($customer)) {
12694 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
12695 }
12696 $special_requests = '';
12697 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12698 $special_requests = $match[1];
12699 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
12700 $special_requests = $match[1];
12701 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
12702 $special_requests = $match[1];
12703 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
12704 $special_requests = $match[1];
12705 }
12706 $paystr = '';
12707 if (!empty($ord['idpayment'])) {
12708 $payparts = explode('=', $ord['idpayment']);
12709 $paystr = $payparts[1];
12710 }
12711 $ordnumbstr = $ord['id'] . ' - ' . $ord['confirmnumber'] . (!empty($ord['idorderota']) ? ' (' . $ord['idorderota'] . ')' : '');
12712 $bookingSource = JText::translate('VBORDFROMSITE');
12713 if (!empty($ord['channel']) && !empty($ord['idorderota'])) {
12714 $chparts = explode('_', $ord['channel']);
12715 $bookingSource = ($chparts[1] ?? '') ?: $chparts[0];
12716 }
12717 $statusstr = '';
12718 if ($ord['status'] == 'confirmed') {
12719 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
12720 } elseif ($ord['status'] == 'standby') {
12721 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
12722 } elseif ($ord['status'] == 'cancelled') {
12723 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
12724 }
12725 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
12726 if ($ord['roomsnum'] > 1) {
12727 // take the cost for the individual room
12728 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
12729 }
12730 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
12731 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12732 // total paid will be printed only for the last room booked
12733 $totalpaidstring = '';
12734 }
12735 $options_str = '';
12736 if (!empty($ord['optionals'])) {
12737 $stepo = explode(";", $ord['optionals']);
12738 foreach ($stepo as $roptkey => $oo) {
12739 if (!empty($oo)) {
12740 $stept = explode(":", $oo);
12741 if (array_key_exists($stept[0], $all_options)) {
12742 $actopt = $all_options[$stept[0]];
12743 $optpcent = false;
12744 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
12745 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
12746 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
12747 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
12748 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
12749 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
12750 $agestept = explode('-', $stept[1]);
12751 $stept[1] = $agestept[0];
12752 $chvar = $agestept[1];
12753 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
12754 $optpcent = true;
12755 }
12756 $actopt['chageintv'] = $chvar;
12757 if (isset($optagenames[($chvar - 1)])) {
12758 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
12759 }
12760 if (isset($optagecosts[($chvar - 1)])) {
12761 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
12762 } else {
12763 $realcost = 0;
12764 }
12765 } else {
12766 // VBO 1.11 - options percentage cost of the room total fee
12767 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
12768 //
12769 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
12770 }
12771 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
12772 $realcost=$actopt['maxprice'];
12773 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
12774 $realcost = $actopt['maxprice'] * $stept[1];
12775 }
12776 }
12777 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
12778
12779 /**
12780 * Trigger event to allow third party plugins to apply a custom calculation for the option/extra fee or tax.
12781 *
12782 * @since 1.17.7 (J) - 1.7.7 (WP)
12783 */
12784 $custom_calculation = VBOFactory::getPlatform()->getDispatcher()->filter('onCalculateBookingOptionFeeCost', [$realcost, &$actopt, $ord, $ord]);
12785 if ($custom_calculation) {
12786 $realcost = (float) $custom_calculation[0];
12787 }
12788
12789 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
12790 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
12791 }
12792 }
12793 }
12794 }
12795
12796 // custom extra costs
12797 if (!empty($ord['extracosts'])) {
12798 $cur_extra_costs = json_decode($ord['extracosts'], true);
12799 foreach ($cur_extra_costs as $eck => $ecv) {
12800 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
12801 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
12802 }
12803 }
12804
12805 // taxes
12806 $taxes_str = '';
12807 if ($ord['tot_taxes'] > 0.00) {
12808 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
12809 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
12810 $tax_breakdown = json_decode($ord['breakdown'], true);
12811 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
12812 if (count($tax_breakdown)) {
12813 foreach ($tax_breakdown as $tbkk => $tbkv) {
12814 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
12815 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
12816 }
12817 }
12818 }
12819 }
12820 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12821 // total taxes will be printed only for the last room booked
12822 $taxes_str = '';
12823 }
12824
12825 // created by
12826 $created_by = '';
12827 if (!empty($ord['ujid'])) {
12828 $creator = new JUser($ord['ujid']);
12829 if (property_exists($creator, 'name')) {
12830 $created_by = $creator->name.' ('.$creator->username.')';
12831 }
12832 }
12833 if (empty($created_by) && !empty($ord['t_first_name'])) {
12834 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
12835 }
12836
12837 // build CSV line data
12838 $line_data = [
12839 [
12840 'value' => $ord['id'],
12841 ],
12842 [
12843 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
12844 ],
12845 [
12846 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
12847 ],
12848 [
12849 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
12850 ],
12851 [
12852 'value' => $booking_nights,
12853 ],
12854 [
12855 'value' => $ord['name'],
12856 ],
12857 [
12858 'value' => $peoplestr,
12859 ],
12860 [
12861 'value' => $custinfostr,
12862 ],
12863 [
12864 'value' => $special_requests,
12865 ],
12866 [
12867 'value' => $ord['adminnotes'],
12868 ],
12869 [
12870 'value' => $created_by,
12871 ],
12872 [
12873 'value' => $ord['custmail'],
12874 ],
12875 [
12876 'value' => $ord['phone'],
12877 ],
12878 [
12879 'value' => $options_str,
12880 ],
12881 [
12882 'value' => $paystr,
12883 ],
12884 [
12885 'value' => $ordnumbstr,
12886 ],
12887 [
12888 'value' => $bookingSource,
12889 ],
12890 [
12891 'value' => $statusstr,
12892 ],
12893 [
12894 'value' => $totalstring,
12895 ],
12896 [
12897 'value' => $totalpaidstring,
12898 ],
12899 [
12900 'value' => $taxes_str,
12901 ],
12902 ];
12903
12904 if (empty($filterstatus) || $filterstatus === 'cancelled') {
12905 // obtain cancellation date for this booking
12906 $booking_canc_date = $cancellation_timestamps[$ord['id']] ?? '';
12907 if ($booking_canc_date) {
12908 $booking_canc_date = date(str_replace("/", $datesep, $df), $booking_canc_date);
12909 }
12910 // insert column for cancellation date at index 2
12911 array_splice($line_data, 2, 0, [['value' => $booking_canc_date]]);
12912 }
12913
12914 // push line for export
12915 $orderscsv[] = $line_data;
12916 }
12917
12918 // set CSV rows
12919 $report_obj->setReportRows($orderscsv);
12920
12921 // build lines to export
12922 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12923
12924 // set export file name
12925 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12926
12927 // force the download of the CSV file
12928 $report_obj->outputHeaders();
12929
12930 // send lines to output
12931 $report_obj->outputCSV($csvlines);
12932
12933 exit;
12934 }
12935
12936 public function exportcustomerslaunch() {
12937 $cid = VikRequest::getVar('cid', array(0));
12938 $dbo = JFactory::getDBO();
12939 $pnotes = VikRequest::getInt('notes', '', 'request');
12940 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12941 $ppin = VikRequest::getInt('pin', '', 'request');
12942 $pcountry = VikRequest::getString('country', '', 'request');
12943 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12944 $ptodate = VikRequest::getString('todate', '', 'request');
12945 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12946 $clauses = array();
12947 if (count($cid) > 0 && !empty($cid[0])) {
12948 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12949 }
12950 if (!empty($pcountry)) {
12951 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12952 }
12953 $datescol = '`bk`.`ts`';
12954 if ($pdatefilt > 0) {
12955 if ($pdatefilt == 1) {
12956 $datescol = '`bk`.`ts`';
12957 } elseif ($pdatefilt == 2) {
12958 $datescol = '`bk`.`checkin`';
12959 } elseif ($pdatefilt == 3) {
12960 $datescol = '`bk`.`checkout`';
12961 }
12962 }
12963 if (!empty($pfromdate)) {
12964 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12965 $clauses[] = $datescol.">=".$from_ts;
12966 }
12967 if (!empty($ptodate)) {
12968 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12969 $clauses[] = $datescol."<=".$to_ts;
12970 }
12971 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12972 $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`,".
12973 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12974 "`cy`.`country_3_code`,`cy`.`country_name` ".
12975 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12976 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12977 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12978 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12979 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` ".
12980 "ORDER BY `c`.`last_name` ASC;";
12981 $dbo->setQuery($q);
12982 $customers = $dbo->loadAssocList();
12983 if (!$customers) {
12984 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12985 $mainframe = JFactory::getApplication();
12986 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12987 exit;
12988 }
12989 $csvlines = [];
12990 $csvheadline = [
12991 'ID',
12992 JText::translate('VBCUSTOMERLASTNAME'),
12993 JText::translate('VBCUSTOMERFIRSTNAME'),
12994 JText::translate('VBCUSTOMEREMAIL'),
12995 JText::translate('VBCUSTOMERPHONE'),
12996 JText::translate('VBCUSTOMERADDRESS'),
12997 JText::translate('VBCUSTOMERCITY'),
12998 JText::translate('VBCUSTOMERZIP'),
12999 JText::translate('VBCUSTOMERCOUNTRY'),
13000 JText::translate('VBCUSTOMERGENDER'),
13001 JText::translate('ORDER_DBIRTH'),
13002 JText::translate('VBCUSTOMERTOTBOOKINGS'),
13003 ];
13004 if ($ppin > 0) {
13005 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
13006 }
13007 if ($pscanimg > 0) {
13008 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
13009 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
13010 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
13011 }
13012 if ($pnotes > 0) {
13013 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
13014 }
13015 $csvlines[] = $csvheadline;
13016 foreach ($customers as $customer) {
13017 $csvcustomerline = [
13018 $customer['id'],
13019 $customer['last_name'],
13020 $customer['first_name'],
13021 $customer['email'],
13022 $customer['phone'],
13023 $customer['address'],
13024 $customer['city'],
13025 $customer['zip'],
13026 $customer['country_name'],
13027 $customer['gender'],
13028 $customer['bdate'],
13029 $customer['tot_bookings'],
13030 ];
13031 if ($ppin > 0) {
13032 $csvcustomerline[] = $customer['pin'];
13033 }
13034 if ($pscanimg > 0) {
13035 $csvcustomerline[] = $customer['doctype'];
13036 $csvcustomerline[] = $customer['docnum'];
13037 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
13038 }
13039 if ($pnotes > 0) {
13040 $csvcustomerline[] = $customer['notes'];
13041 }
13042 $csvlines[] = $csvcustomerline;
13043 }
13044 header("Content-type: text/csv");
13045 header("Cache-Control: no-store, no-cache");
13046 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
13047 $outstream = fopen("php://output", 'w');
13048 foreach ($csvlines as $csvline) {
13049 fputcsv($outstream, $csvline, $separator = ',', $enclosure = '"', $escape = '');
13050 }
13051 fclose($outstream);
13052 exit;
13053 }
13054
13055 public function renewsession() {
13056 /*
13057 * @wponly
13058 * We just destroy the session
13059 */
13060 JSessionHandler::destroy();
13061 $mainframe = JFactory::getApplication();
13062 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
13063 }
13064
13065 public function trackings() {
13066 VikBookingHelper::printHeader("trackings");
13067
13068 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
13069
13070 parent::display();
13071
13072 if (VikBooking::showFooter()) {
13073 VikBookingHelper::printFooter();
13074 }
13075 }
13076
13077 public function trkconfig() {
13078 VikBookingHelper::printHeader("trackings");
13079
13080 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
13081
13082 parent::display();
13083
13084 if (VikBooking::showFooter()) {
13085 VikBookingHelper::printFooter();
13086 }
13087 }
13088
13089 public function savetrkconfigstay() {
13090 if (!JSession::checkToken()) {
13091 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13092 }
13093 $this->do_savetrkconfig(true);
13094 }
13095
13096 public function savetrkconfig() {
13097 if (!JSession::checkToken()) {
13098 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13099 }
13100 $this->do_savetrkconfig();
13101 }
13102
13103 private function do_savetrkconfig($stay = false) {
13104 $dbo = JFactory::getDBO();
13105 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
13106 $trkenabled = $trkenabled == 1 ? 1 : 0;
13107 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
13108 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
13109 $trkcampname = VikRequest::getVar('trkcampname', array());
13110 $trkcampkey = VikRequest::getVar('trkcampkey', array());
13111 $trkcampval = VikRequest::getVar('trkcampval', array());
13112 $trkcampaigns = array();
13113 foreach ($trkcampname as $k => $v) {
13114 if (empty($trkcampkey[$k])) {
13115 continue;
13116 }
13117 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
13118 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
13119 $trkcampaigns[$trkcampkey[$k]] = array(
13120 'key' => $trkcampkey[$k],
13121 'value' => $trkcampval[$k],
13122 'name' => $name,
13123 );
13124 }
13125
13126 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
13127 $dbo->setQuery($q);
13128 $dbo->execute();
13129 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
13130 $dbo->setQuery($q);
13131 $dbo->execute();
13132 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
13133 $dbo->setQuery($q);
13134 $dbo->execute();
13135
13136 $mainframe = JFactory::getApplication();
13137 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
13138 }
13139
13140 public function modtracking() {
13141 $dbo = JFactory::getDbo();
13142 $cid = VikRequest::getVar('cid', array());
13143 foreach ($cid as $id) {
13144 if (!empty($id)) {
13145 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
13146 $dbo->setQuery($q);
13147 $dbo->execute();
13148 if ($dbo->getNumRows()) {
13149 $data = $dbo->loadAssoc();
13150 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
13151 $dbo->setQuery($q);
13152 $dbo->execute();
13153 }
13154 }
13155 }
13156 $mainframe = JFactory::getApplication();
13157 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13158 }
13159
13160 public function removetrackings()
13161 {
13162 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13163 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13164 }
13165
13166 $ids = VikRequest::getVar('cid', array());
13167 $dbo = JFactory::getDbo();
13168
13169 foreach ($ids as $d) {
13170 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
13171 $dbo->setQuery($q);
13172 $dbo->execute();
13173 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
13174 $dbo->setQuery($q);
13175 $dbo->execute();
13176 }
13177
13178 $mainframe = JFactory::getApplication();
13179 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13180 }
13181
13182 /**
13183 * Invokes the Tracker class to obtain
13184 * geo information about the IP addresses.
13185 * This task is called via ajax.
13186 *
13187 * @since 1.11
13188 */
13189 public function getgeoinfo() {
13190 $ips = VikRequest::getVar('ips', array());
13191 if (!count($ips)) {
13192 echo 'e4j.error.empty IPs';
13193 exit;
13194 }
13195
13196 // require the Tracker class without instantiating the object
13197 VikBooking::getTracker(true);
13198 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
13199
13200 if ($geo_info === false) {
13201 echo 'e4j.error.Tracker error, could not get geo info from IPs';
13202 exit;
13203 }
13204
13205 // update db values and compose response
13206 $dbo = JFactory::getDbo();
13207 $resp = array();
13208 foreach ($geo_info as $id => $geo) {
13209 if (is_null($geo) || $geo === false) {
13210 continue;
13211 }
13212 // compose geo info string
13213 $geovals = array();
13214 if (!empty($geo['city'])) {
13215 array_push($geovals, $geo['city']);
13216 }
13217 if (!empty($geo['region'])) {
13218 array_push($geovals, $geo['region']);
13219 }
13220 $threecode = '';
13221 $cname = '';
13222 if (!empty($geo['country'])) {
13223 // returned country is a 2-char code, get the 3-char country code
13224 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
13225 $dbo->setQuery($q);
13226 $dbo->execute();
13227 if ($dbo->getNumRows()) {
13228 $cinfo = $dbo->loadAssoc();
13229 $threecode = $cinfo['country_3_code'];
13230 $cname = $cinfo['country_name'];
13231 }
13232 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
13233 }
13234
13235 // full geo information string
13236 $geoinfostr = implode(', ', $geovals);
13237
13238 // push data to the response pool
13239 $resp[$id] = array();
13240 $resp[$id]['geo'] = $geoinfostr;
13241 if (!empty($cname)) {
13242 $resp[$id]['country'] = $cname;
13243 }
13244 if (!empty($threecode)) {
13245 $resp[$id]['country3'] = $threecode;
13246 }
13247
13248 // update main tracking record
13249 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
13250 $dbo->setQuery($q);
13251 $dbo->execute();
13252 }
13253
13254 // output the JSON response
13255 echo json_encode($resp);
13256 exit;
13257 }
13258
13259 /**
13260 * Counts the orphan dates for all published rooms
13261 * depending on their restrictions and booked dates.
13262 * By default, the task takes up to 3 months ahead.
13263 * It is possible to filter the request by rooms and months.
13264 * This task should be called via ajax.
13265 *
13266 * @since 1.11
13267 */
13268 public function orphanscount()
13269 {
13270 $dbo = JFactory::getDbo();
13271 $orphans = array();
13272
13273 $nowdf = VikBooking::getDateFormat();
13274 if ($nowdf == "%d/%m/%Y") {
13275 $df = 'd/m/Y';
13276 } elseif ($nowdf == "%m/%d/%Y") {
13277 $df = 'm/d/Y';
13278 } else {
13279 $df = 'Y/m/d';
13280 }
13281
13282 // global min los
13283 $glob_minlos = VikBooking::getDefaultNightsCalendar();
13284 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
13285
13286 // rooms and dates
13287 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
13288 $months = VikRequest::getInt('months', 3, 'request');
13289 $from = VikRequest::getString('from', '', 'request');
13290 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
13291 if (!empty($from)) {
13292 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
13293 if (!empty($fromts)) {
13294 // custom starting date
13295 $today = $fromts;
13296 }
13297 }
13298 $until = strtotime("+{$months} months", $today);
13299
13300 // load all rooms
13301 $rooms = array();
13302 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
13303 $dbo->setQuery($q);
13304 $dbo->execute();
13305 if ($dbo->getNumRows()) {
13306 $allrooms = $dbo->loadAssocList();
13307 foreach ($allrooms as $r) {
13308 $rooms[$r['id']] = $r;
13309 }
13310 }
13311 if (!count($rooms)) {
13312 // no rooms found, exit
13313 echo json_encode($orphans);
13314 exit;
13315 }
13316
13317 // load availabilities
13318 $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.");";
13319 $dbo->setQuery($q);
13320 $dbo->execute();
13321 if (!$dbo->getNumRows()) {
13322 // no booked dates found, exit
13323 echo json_encode($orphans);
13324 exit;
13325 }
13326 $busy = $dbo->loadAssocList();
13327
13328 // sort booked dates by room id
13329 $rooms_busy = array();
13330 foreach ($busy as $b) {
13331 if (!isset($rooms_busy[$b['idroom']])) {
13332 $rooms_busy[$b['idroom']] = array();
13333 }
13334 array_push($rooms_busy[$b['idroom']], $b);
13335 }
13336
13337 // load restrictions
13338 $rooms_restr = array();
13339 foreach ($rooms as $rid => $r) {
13340 $restrictions = VikBooking::loadRestrictions(true, array($rid));
13341 if (count($restrictions)) {
13342 $rooms_restr[$rid] = $restrictions;
13343 }
13344 }
13345 if (!count($rooms_restr) && $glob_minlos < 2) {
13346 // no restrictions found and minlos=1, exit
13347 echo json_encode($orphans);
13348 exit;
13349 }
13350
13351 // count availability and minlos per day
13352 $rooms_data = array();
13353 foreach ($rooms as $rid => $r) {
13354 $rooms_data[$rid] = array(
13355 'avail' => array(),
13356 'restr' => array()
13357 );
13358 $nowts = getdate($today);
13359 while ($nowts[0] <= $until) {
13360 $dateind = date('Y-m-d', $nowts[0]);
13361
13362 // remaining availability
13363 if (!isset($rooms_busy[$rid])) {
13364 // no bookings for this room, set full availability for this day
13365 $rooms_data[$rid]['avail'][] = array(
13366 'dt' => $dateind,
13367 'units' => $r['units']
13368 );
13369 } else {
13370 // check remaining availability for this day
13371 $totfound = 0;
13372 foreach ($rooms_busy[$rid] as $b) {
13373 $tmpone = getdate($b['checkin']);
13374 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
13375 $ritts = strtotime($rit);
13376 $tmptwo = getdate($b['checkout']);
13377 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
13378 $conts = strtotime($con);
13379 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
13380 $totfound++;
13381 }
13382 }
13383 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
13384 $rooms_data[$rid]['avail'][] = array(
13385 'dt' => $dateind,
13386 'units' => ($r['units'] - $totfound)
13387 );
13388 }
13389
13390 // restrictions
13391 if (!isset($rooms_restr[$rid])) {
13392 // no restrictions for this room, set global minlos for this day
13393 $rooms_data[$rid]['restr'][] = array(
13394 'dt' => $dateind,
13395 'minlos' => $glob_minlos
13396 );
13397 } else {
13398 // get restriction for this day
13399 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
13400 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13401
13402 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
13403 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
13404
13405 $rooms_data[$rid]['restr'][] = array(
13406 'dt' => $dateind,
13407 'minlos' => $minlos
13408 );
13409 }
13410
13411 // next loop
13412 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
13413 $nowts = getdate($dayts);
13414 }
13415 }
13416
13417 // week days and months labels
13418 $days_labels = array(
13419 JText::translate('VBSUNDAY'),
13420 JText::translate('VBMONDAY'),
13421 JText::translate('VBTUESDAY'),
13422 JText::translate('VBWEDNESDAY'),
13423 JText::translate('VBTHURSDAY'),
13424 JText::translate('VBFRIDAY'),
13425 JText::translate('VBSATURDAY')
13426 );
13427 $months_labels = array(
13428 JText::translate('VBMONTHONE'),
13429 JText::translate('VBMONTHTWO'),
13430 JText::translate('VBMONTHTHREE'),
13431 JText::translate('VBMONTHFOUR'),
13432 JText::translate('VBMONTHFIVE'),
13433 JText::translate('VBMONTHSIX'),
13434 JText::translate('VBMONTHSEVEN'),
13435 JText::translate('VBMONTHEIGHT'),
13436 JText::translate('VBMONTHNINE'),
13437 JText::translate('VBMONTHTEN'),
13438 JText::translate('VBMONTHELEVEN'),
13439 JText::translate('VBMONTHTWELVE')
13440 );
13441
13442 // orphan dates calculation method
13443 $calc_method = VikBooking::orphansCalculation();
13444
13445 // parse data and build orphans if any
13446 foreach ($rooms_data as $rid => $data) {
13447 foreach ($data['avail'] as $ind => $av) {
13448 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
13449 // continue, no restriction set or no availability for this day
13450 continue;
13451 }
13452 if ($data['restr'][$ind]['minlos'] < 2) {
13453 // continue, no min los > 1 set for this day
13454 continue;
13455 }
13456 // check if any night after today, until min los, is fully booked
13457 $hasorphans = false;
13458 $forward_count = 0;
13459 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
13460 if (!isset($data['avail'][($ind + $i)])) {
13461 // break loop, no info for this day after
13462 break;
13463 }
13464 if ($data['avail'][($ind + $i)]['units'] > 0) {
13465 // continue, availability found for tomorrow, we need a non available next-day
13466 continue;
13467 }
13468 // orphan found
13469 $hasorphans = true;
13470 $forward_count = $i;
13471 break;
13472 }
13473
13474 /**
13475 * Backward calculation method only if "prevnext".
13476 *
13477 * @since 1.3.0
13478 */
13479 $backward_count = 0;
13480 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
13481 if (!isset($data['avail'][($ind - $i)])) {
13482 // break loop, no info for this prev day
13483 break;
13484 }
13485 if ($data['avail'][($ind - $i)]['units'] > 0) {
13486 // increase free nights going backward
13487 $backward_count++;
13488 }
13489 }
13490 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
13491 // this should not be an orphan date because of enough free days back, or enough free days in between
13492 $hasorphans = false;
13493 }
13494 //
13495
13496 if ($hasorphans) {
13497 // 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
13498 if (!isset($orphans[$rid])) {
13499 $orphans[$rid] = array(
13500 'name' => $rooms[$rid]['name'],
13501 'dates' => array(),
13502 'rdates' => array(),
13503 'linkd' => date($df, strtotime($av['dt']))
13504 );
13505 }
13506 array_push($orphans[$rid]['dates'], $av['dt']);
13507 // build the value for the readable date
13508 $dtinfo = getdate(strtotime($av['dt']));
13509 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
13510 array_push($orphans[$rid]['rdates'], $rdate);
13511 }
13512 }
13513 }
13514
13515 // output response
13516 echo json_encode($orphans);
13517 exit;
13518 }
13519
13520 public function tableaux() {
13521 VikBookingHelper::printHeader("tableaux");
13522
13523 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
13524
13525 parent::display();
13526
13527 if (VikBooking::showFooter()) {
13528 VikBookingHelper::printFooter();
13529 }
13530 }
13531
13532 public function operators() {
13533 VikBookingHelper::printHeader("operators");
13534
13535 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
13536
13537 parent::display();
13538
13539 if (VikBooking::showFooter()) {
13540 VikBookingHelper::printFooter();
13541 }
13542 }
13543
13544 public function newoperator() {
13545 VikBookingHelper::printHeader("operators");
13546
13547 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13548
13549 parent::display();
13550
13551 if (VikBooking::showFooter()) {
13552 VikBookingHelper::printFooter();
13553 }
13554 }
13555
13556 public function editoperator() {
13557 VikBookingHelper::printHeader("operators");
13558
13559 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
13560
13561 parent::display();
13562
13563 if (VikBooking::showFooter()) {
13564 VikBookingHelper::printFooter();
13565 }
13566 }
13567
13568 public function updateoperator()
13569 {
13570 if (!JSession::checkToken()) {
13571 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13572 }
13573
13574 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13575 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13576 }
13577
13578 $this->do_updateoperator();
13579 }
13580
13581 public function updateoperatorstay()
13582 {
13583 if (!JSession::checkToken()) {
13584 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13585 }
13586
13587 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
13588 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13589 }
13590
13591 $this->do_updateoperator(true);
13592 }
13593
13594 private function do_updateoperator($stay = false)
13595 {
13596 $dbo = JFactory::getDbo();
13597 $app = JFactory::getApplication();
13598 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13599 $plast_name = VikRequest::getString('last_name', '', 'request');
13600 $pemail = VikRequest::getString('email', '', 'request');
13601 $pphone = VikRequest::getString('phone', '', 'request');
13602 $pcode = VikRequest::getString('code', '', 'request');
13603 $pujid = VikRequest::getInt('ujid', '', 'request');
13604 $pwhere = VikRequest::getInt('where', '', 'request');
13605
13606 $work_days_week = (array) $app->input->get('work_days_week', [], 'array');
13607 $work_days_exceptions = (array) $app->input->get('work_days_exceptions', [], 'array');
13608
13609 // normalize to linear arrays
13610 $work_days_week_schedule = array_combine(array_keys($work_days_week), array_values($work_days_week));
13611 $work_days_week = [];
13612 foreach ($work_days_week_schedule as $wday => $whours) {
13613 $work_days_week[] = [
13614 'wday' => $wday,
13615 'hours' => $whours,
13616 ];
13617 }
13618 foreach ($work_days_exceptions as &$wexceptions) {
13619 if (is_scalar($wexceptions)) {
13620 $wexceptions = json_decode($wexceptions, true);
13621 }
13622 }
13623 unset($wexceptions);
13624
13625 if (!empty($pfirst_name) && !empty($pemail) && !empty($pcode)) {
13626 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
13627 $dbo->setQuery($q);
13628 $customer = $dbo->loadAssoc();
13629 if (!$customer) {
13630 $app->redirect("index.php?option=com_vikbooking&task=operators");
13631 exit;
13632 }
13633
13634 $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;";
13635 $dbo->setQuery($q);
13636 $ex_operator = $dbo->loadAssoc();
13637 if (!$ex_operator) {
13638 // update fingerprint for the operator
13639 $fingpt = md5($pwhere . $pemail);
13640
13641 /**
13642 * Operator profile picture (URL or uploaded file).
13643 *
13644 * @since 1.16.9 (J) - 1.6.9 (WP)
13645 */
13646 $operator_pic = VikRequest::getString('pic', '', 'request');
13647 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13648 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13649 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13650 $src = $operator_pic_img['tmp_name'];
13651 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13652 $j = "";
13653 if (is_file($dest.$filename)) {
13654 $j = rand(1, 99999);
13655 while (is_file($dest . $j .$filename)) {
13656 $j++;
13657 }
13658 }
13659 $finaldest = $dest . $j . $filename;
13660 $check = getimagesize($operator_pic_img['tmp_name']);
13661 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
13662 if (VikBooking::uploadFile($src, $finaldest)) {
13663 $operator_pic = $j . $filename;
13664 } else {
13665 VikError::raiseWarning('', 'Error while uploading image');
13666 }
13667 } else {
13668 VikError::raiseWarning('', 'Uploaded file is not an Image');
13669 }
13670 }
13671
13672 // update record
13673 $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) . ",`work_days_week`=" . ($work_days_week ? $dbo->q(json_encode($work_days_week)) : 'NULL') . ",`work_days_exceptions`=" . ($work_days_exceptions ? $dbo->q(json_encode($work_days_exceptions)) : 'NULL') . " WHERE `id`=" . (int)$pwhere;
13674 $dbo->setQuery($q);
13675 $dbo->execute();
13676 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13677 } else {
13678 //email already exists
13679 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>');
13680 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13681 exit;
13682 }
13683 } else {
13684 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13685 }
13686
13687 if ($stay) {
13688 $app->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
13689 } else {
13690 $app->redirect("index.php?option=com_vikbooking&task=operators");
13691 }
13692
13693 $app->close();
13694 }
13695
13696 public function saveoperator()
13697 {
13698 if (!JSession::checkToken()) {
13699 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13700 }
13701
13702 $dbo = JFactory::getDbo();
13703 $app = JFactory::getApplication();
13704 $pfirst_name = VikRequest::getString('first_name', '', 'request');
13705 $plast_name = VikRequest::getString('last_name', '', 'request');
13706 $pemail = VikRequest::getString('email', '', 'request');
13707 $pphone = VikRequest::getString('phone', '', 'request');
13708 $pcode = VikRequest::getString('code', '', 'request');
13709 $pujid = VikRequest::getInt('ujid', '', 'request');
13710
13711 $work_days_week = (array) $app->input->get('work_days_week', [], 'array');
13712 $work_days_exceptions = (array) $app->input->get('work_days_exceptions', [], 'array');
13713
13714 // normalize to linear arrays
13715 $work_days_week_schedule = array_combine(array_keys($work_days_week), array_values($work_days_week));
13716 $work_days_week = [];
13717 foreach ($work_days_week_schedule as $wday => $whours) {
13718 $work_days_week[] = [
13719 'wday' => $wday,
13720 'hours' => $whours,
13721 ];
13722 }
13723 foreach ($work_days_exceptions as &$wexceptions) {
13724 if (is_scalar($wexceptions)) {
13725 $wexceptions = json_decode($wexceptions, true);
13726 }
13727 }
13728 unset($wexceptions);
13729
13730 if (!empty($pfirst_name) && !empty($pemail) && !empty($pcode)) {
13731 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
13732 $dbo->setQuery($q);
13733 $ex_operator = $dbo->loadAssoc();
13734 if (!$ex_operator) {
13735 /**
13736 * Operator profile picture (URL or uploaded file).
13737 *
13738 * @since 1.16.9 (J) - 1.6.9 (WP)
13739 */
13740 $operator_pic = VikRequest::getString('pic', '', 'request');
13741 $operator_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
13742 if (is_array($operator_pic_img) && !empty($operator_pic_img['name'])) {
13743 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($operator_pic_img['name'])));
13744 $src = $operator_pic_img['tmp_name'];
13745 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
13746 $j = "";
13747 if (is_file($dest.$filename)) {
13748 $j = rand(1, 99999);
13749 while (is_file($dest . $j .$filename)) {
13750 $j++;
13751 }
13752 }
13753 $finaldest = $dest . $j . $filename;
13754 $check = getimagesize($operator_pic_img['tmp_name']);
13755 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
13756 if (VikBooking::uploadFile($src, $finaldest)) {
13757 $operator_pic = $j . $filename;
13758 } else {
13759 VikError::raiseWarning('', 'Error while uploading image');
13760 }
13761 } else {
13762 VikError::raiseWarning('', 'Uploaded file is not an Image');
13763 }
13764 }
13765
13766 $q = "INSERT INTO `#__vikbooking_operators` (`first_name`,`last_name`,`email`,`phone`,`code`,`ujid`,`pic`,`work_days_week`,`work_days_exceptions`) 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) . ", " . ($work_days_week ? $dbo->q(json_encode($work_days_week)) : 'NULL') . ", " . ($work_days_exceptions ? $dbo->q(json_encode($work_days_exceptions)) : 'NULL') . ");";
13767 $dbo->setQuery($q);
13768 $dbo->execute();
13769 $lid = $dbo->insertid();
13770 if (!empty($lid)) {
13771 $app->enqueueMessage(JText::translate('VBOPERATORSAVED'));
13772 // generate fingerprint for the operator
13773 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->q(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
13774 $dbo->setQuery($q);
13775 $dbo->execute();
13776 }
13777 } else {
13778 // email already exists
13779 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>');
13780 }
13781 } else {
13782 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
13783 }
13784
13785 $app->redirect("index.php?option=com_vikbooking&task=operators");
13786 $app->close();
13787 }
13788
13789 public function removeoperators()
13790 {
13791 if (!JSession::checkToken()) {
13792 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13793 }
13794
13795 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
13796 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
13797 }
13798
13799 $ids = VikRequest::getVar('cid', array(0));
13800 if ($ids) {
13801 $dbo = JFactory::getDBO();
13802 foreach ($ids as $d) {
13803 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
13804 $dbo->setQuery($q);
13805 $dbo->execute();
13806 }
13807 }
13808 $mainframe = JFactory::getApplication();
13809 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13810 }
13811
13812 public function canceloperator() {
13813 $mainframe = JFactory::getApplication();
13814 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
13815 }
13816
13817 public function cancelcrons() {
13818 $mainframe = JFactory::getApplication();
13819 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
13820 }
13821
13822 public function cancelpackages() {
13823 $mainframe = JFactory::getApplication();
13824 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
13825 }
13826
13827 public function cancelcustomer() {
13828 $mainframe = JFactory::getApplication();
13829 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13830 if (!empty($pgoto)) {
13831 $mainframe->redirect(base64_decode($pgoto));
13832 exit;
13833 }
13834 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
13835 }
13836
13837 public function cancelbusyvcm() {
13838 $mainframe = JFactory::getApplication();
13839 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
13840 }
13841
13842 public function cancelrestriction() {
13843 $mainframe = JFactory::getApplication();
13844 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
13845 }
13846
13847 public function cancelcoupon() {
13848 $mainframe = JFactory::getApplication();
13849 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
13850 }
13851
13852 public function cancelcustomf() {
13853 $mainframe = JFactory::getApplication();
13854 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
13855 }
13856
13857 public function cancelpayment() {
13858 $mainframe = JFactory::getApplication();
13859 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
13860 }
13861
13862 public function cancelseason() {
13863 $mainframe = JFactory::getApplication();
13864 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
13865 }
13866
13867 public function goconfig() {
13868 $mainframe = JFactory::getApplication();
13869 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
13870 }
13871
13872 public function canceledorder() {
13873 $pgoto = VikRequest::getString('goto', 'orders', 'request');
13874 $mainframe = JFactory::getApplication();
13875 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
13876 }
13877
13878 public function cancelbusy() {
13879 $pidorder = VikRequest::getString('idorder', '', 'request');
13880 $pgoto = VikRequest::getString('goto', '', 'request');
13881 $mainframe = JFactory::getApplication();
13882 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
13883 }
13884
13885 public function canceloverv() {
13886 $mainframe = JFactory::getApplication();
13887 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
13888 }
13889
13890 public function canceltableaux() {
13891 $mainframe = JFactory::getApplication();
13892 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
13893 }
13894
13895 public function cancelcalendar() {
13896 $pidroom = VikRequest::getString('idroom', '', 'request');
13897 $mainframe = JFactory::getApplication();
13898 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
13899 }
13900
13901 public function canceloptionals() {
13902 $mainframe = JFactory::getApplication();
13903 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
13904 }
13905
13906 public function cancel() {
13907 $mainframe = JFactory::getApplication();
13908 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
13909 }
13910
13911 public function cancelcarat() {
13912 $mainframe = JFactory::getApplication();
13913 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
13914 }
13915
13916 public function cancelcat() {
13917 $mainframe = JFactory::getApplication();
13918 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
13919 }
13920
13921 public function cancelprice() {
13922 $mainframe = JFactory::getApplication();
13923 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
13924 }
13925
13926 public function canceliva() {
13927 $mainframe = JFactory::getApplication();
13928 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
13929 }
13930
13931 public function canceltrk() {
13932 $mainframe = JFactory::getApplication();
13933 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13934 }
13935
13936 public function canceldash() {
13937 $mainframe = JFactory::getApplication();
13938 $mainframe->redirect("index.php?option=com_vikbooking");
13939 }
13940
13941 public function cancelinvoice() {
13942 $mainframe = JFactory::getApplication();
13943 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13944 if (!empty($pgoto)) {
13945 $mainframe->redirect(base64_decode($pgoto));
13946 exit;
13947 }
13948 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
13949 }
13950
13951 /**
13952 * AJAX upload the customer documents.
13953 *
13954 * @return void
13955 *
13956 * @throws Exception
13957 */
13958 public function upload_customer_document()
13959 {
13960 $app = JFactory::getApplication();
13961
13962 if (!JSession::checkToken()) {
13963 // missing CSRF-proof token
13964 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
13965 }
13966
13967 $dbo = JFactory::getDbo();
13968 $input = $app->input;
13969
13970 $customer_id = $input->getUint('customer', 0);
13971
13972 $result = new stdClass;
13973 $result->status = 0;
13974
13975 try
13976 {
13977 $q = $dbo->getQuery(true)
13978 ->select($dbo->qn(array(
13979 'id',
13980 'first_name',
13981 'last_name',
13982 'email',
13983 'docsfolder',
13984 )))
13985 ->from($dbo->qn('#__vikbooking_customers'))
13986 ->where($dbo->qn('id') . ' = ' . $customer_id);
13987
13988 $dbo->setQuery($q, 0, 1);
13989 $customer = $dbo->loadObject();
13990
13991 if (!$customer)
13992 {
13993 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13994 }
13995
13996 // fetch documents folder path
13997 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13998
13999 // check if we have a valid directory
14000 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
14001 {
14002 // randomize string
14003 $customer->seed = uniqid();
14004
14005 // create blocks for hashed folder
14006 $parts = [
14007 $customer->first_name,
14008 $customer->last_name,
14009 md5(serialize($customer)),
14010 ];
14011
14012 // join fetched parts
14013 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
14014
14015 if (strlen($customer->docsfolder) < 16)
14016 {
14017 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
14018 }
14019
14020 jimport('joomla.filesystem.folder');
14021
14022 // create a folder for this customer
14023 $created = JFolder::create($dirpath . $customer->docsfolder);
14024
14025 if (!$created)
14026 {
14027 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
14028 }
14029
14030 unset($customer->seed);
14031
14032 // update docs folder
14033 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
14034 }
14035
14036 // get file from request
14037 $file = $input->files->get('file', array(), 'array');
14038
14039 // try to upload the file
14040 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, 'png,jpg,jpeg,bmp,heic,zip,rar,pdf,doc,docx,rtf,odt,pages,xls,xlsx,csv,ods,numbers,txt,md');
14041 $result->status = 1;
14042
14043 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
14044 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
14045 }
14046 catch (Exception $e)
14047 {
14048 $result->error = $e->getMessage();
14049 $result->code = $e->getCode();
14050 }
14051
14052 VBOHttpDocument::getInstance($app)->json($result);
14053 }
14054
14055 /**
14056 * AJAX delete the customer documents.
14057 *
14058 * @return void
14059 *
14060 * @throws Exception
14061 */
14062 public function delete_customer_document()
14063 {
14064 $app = JFactory::getApplication();
14065
14066 if (!JSession::checkToken()) {
14067 // missing CSRF-proof token
14068 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
14069 }
14070
14071 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14072 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14073 }
14074
14075 $dbo = JFactory::getDbo();
14076 $input = $app->input;
14077
14078 $customer_id = $input->getUint('customer', 0);
14079
14080 $result = new stdClass;
14081 $result->status = 0;
14082
14083 $q = $dbo->getQuery(true)
14084 ->select($dbo->qn('docsfolder'))
14085 ->from($dbo->qn('#__vikbooking_customers'))
14086 ->where($dbo->qn('id') . ' = ' . $customer_id);
14087
14088 $dbo->setQuery($q, 0, 1);
14089 $dbo->execute();
14090
14091 if (!$dbo->getNumRows())
14092 {
14093 VBOHttpDocument::getInstance($app)->close(404, sprintf('Customer [%d] not found', $customer_id));
14094 }
14095
14096 $folder = $dbo->loadResult();
14097
14098 if (!$folder)
14099 {
14100 VBOHttpDocument::getInstance($app)->close(500, 'The customer does not have any documents');
14101 }
14102
14103 $file = $input->getString('file');
14104
14105 if (!$file)
14106 {
14107 VBOHttpDocument::getInstance($app)->close(400, 'File to remove not specified');
14108 }
14109
14110 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
14111
14112 if (!is_file($path))
14113 {
14114 VBOHttpDocument::getInstance($app)->close(404, sprintf('File [%s] not found', $path));
14115 }
14116
14117 /**
14118 * Accept only non-traversal paths under the customer docs folder.
14119 *
14120 * @since 1.18.13 (J) - 1.8.13 (WP)
14121 */
14122 $path = realpath($path);
14123
14124 if (!$path || strpos($path, VBO_CUSTOMERS_PATH) !== 0)
14125 {
14126 VBOHttpDocument::getInstance($app)->close(403, 'Path not allowed for file deletion.');
14127 }
14128
14129 $removed = JFile::delete($path);
14130
14131 VBOHttpDocument::getInstance($app)->json(array('status' => (int) $removed));
14132 }
14133
14134 /**
14135 * AJAX task to invoke a specific report and obtain information.
14136 *
14137 * @since 1.3.0
14138 */
14139 public function get_report_data()
14140 {
14141 $report_name = VikRequest::getString('report_name', '', 'request');
14142 $current_fest = VikRequest::getString('current_fest', '', 'request');
14143 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
14144 $current_todate = VikRequest::getString('current_todate', '', 'request');
14145 $step = VikRequest::getString('step', 'weekend', 'request');
14146 $direction = VikRequest::getString('direction', 'load', 'request');
14147 $period = VikRequest::getString('period', 'full', 'request');
14148 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
14149 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
14150 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
14151 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
14152 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
14153 // idroom can be an array of IDs or just one ID as int/string
14154 $idroom = VikRequest::getVar('idroom', null, 'request');
14155 //
14156
14157 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
14158 throw new Exception("Missing request data", 400);
14159 }
14160
14161 // get requested report instance
14162 $report = VikBooking::getReportInstance($report_name);
14163 if (!$report) {
14164 throw new Exception("Report not found", 404);
14165 }
14166
14167 // chart data
14168 if (empty($chart_datatype)) {
14169 $chart_datatype = array(
14170 'type' => 'doughnut',
14171 'depth' => 1,
14172 'keys' => array($krsort),
14173 );
14174 }
14175
14176 // website date format
14177 $df = $report->getDateFormat();
14178
14179 // prepare request params for the report
14180 $rparams = array(
14181 'fromdate' => $current_fromdate,
14182 'todate' => $current_todate,
14183 'period' => $period,
14184 'krsort' => $krsort,
14185 'krorder' => $krorder,
14186 'idroom' => $idroom,
14187 );
14188
14189 // starting dates info and timestamps
14190 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
14191 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
14192 $from_info = getdate($from_ts);
14193 $to_info = getdate($to_ts);
14194
14195 // the name of the period requested and whether it's a fest
14196 $period_name = '';
14197 $is_fest = null;
14198
14199 if ($direction == 'prev' || $direction == 'next') {
14200 // calculate prev or next dates
14201 if ($step == 'weekend') {
14202 $period_name = JText::translate('VBOWEEKND');
14203 if ($direction == 'next') {
14204 // next weekend from current end date
14205 $next_ts = strtotime("next friday", $to_ts);
14206 } else {
14207 // prev weekend from current start date
14208 $next_ts = strtotime("previous friday", $from_ts);
14209 }
14210 $next_info = getdate($next_ts);
14211 $new_from_ts = $next_ts;
14212 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
14213 $rparams['fromdate'] = date($df, $new_from_ts);
14214 $rparams['todate'] = date($df, $new_to_ts);
14215 } elseif ($step == 'week') {
14216 $period_name = JText::translate('VBOWEEK');
14217 if ($direction == 'next') {
14218 // start next week from the current end date
14219 $new_from_ts = $to_ts;
14220 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
14221 $rparams['fromdate'] = $rparams['todate'];
14222 $rparams['todate'] = date($df, $new_to_ts);
14223 } else {
14224 // end prev week from the current from date
14225 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
14226 $new_to_ts = $from_ts;
14227 $rparams['todate'] = $rparams['fromdate'];
14228 $rparams['fromdate'] = date($df, $new_from_ts);
14229 }
14230 } else {
14231 // month
14232 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
14233 if ($direction == 'next') {
14234 // next month from the current from date
14235 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
14236 $new_from_ts = $nextmonts;
14237 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
14238 $rparams['fromdate'] = date($df, $new_from_ts);
14239 $rparams['todate'] = date($df, $new_to_ts);
14240 } else {
14241 // prev month from the current from date
14242 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
14243 $new_from_ts = $nextmonts;
14244 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
14245 $rparams['fromdate'] = date($df, $new_from_ts);
14246 $rparams['todate'] = date($df, $new_to_ts);
14247 }
14248 }
14249
14250 // get the next festivities
14251 $fests = VikBooking::getFestivitiesInstance();
14252 $next_fests = $fests->loadFestDates();
14253 if (count($next_fests)) {
14254 // check whether a festivity should be displayed rather than the calculated period of dates
14255 foreach ($next_fests as $fest) {
14256 $fest_found = false;
14257 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
14258 $fest_found = true;
14259 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
14260 $fest_found = true;
14261 }
14262 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
14263 // festivity found before next calculated period
14264 $is_fest = $fest['festinfo'][0]->next_ts;
14265 $period_name = $fest['festinfo'][0]->trans_name;
14266 $new_from_ts = $fest['festinfo'][0]->from_ts;
14267 $new_to_ts = $fest['festinfo'][0]->to_ts;
14268 $rparams['fromdate'] = date($df, $new_from_ts);
14269 $rparams['todate'] = date($df, $new_to_ts);
14270 break;
14271 }
14272 }
14273 }
14274 } else {
14275 // load requested dates by skipping the festivities
14276 $new_from_ts = $from_ts;
14277 $new_to_ts = $to_ts;
14278 }
14279
14280 // invoke report
14281 $report->injectParams($rparams);
14282 $report_values = $report->getReportValues(1);
14283 $report_cols = $report->getColumnsValues();
14284 $report_chart = null;
14285 $report_chart_metas = array();
14286 $chart_meta_data = array(
14287 'keys' => array(
14288 'occupancy',
14289 'tot_bookings',
14290 'nights_booked',
14291 ),
14292 );
14293 $error = null;
14294
14295 if (!count($report_values)) {
14296 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
14297 } else {
14298 // get doughnut Chart for the requested key
14299 $report_chart = $report->getChart((array) $chart_datatype);
14300
14301 // get Chart meta data
14302 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
14303 if (count($all_chart_metas)) {
14304 // merge all positions into one array
14305 foreach ($all_chart_metas as $pos_metas) {
14306 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
14307 }
14308 }
14309
14310 if (empty($period_name)) {
14311 $period_name = $report->getProperty('chartTitle');
14312 }
14313 }
14314
14315 // build response
14316 $response = new stdClass;
14317 $response->error = $error;
14318 $response->fromdate = $rparams['fromdate'];
14319 $response->todate = $rparams['todate'];
14320 $response->in_days = $report->countDaysTo($new_from_ts);
14321 $response->in_days_to = $report->countDaysTo($new_to_ts);
14322 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
14323 $response->period_name = $period_name;
14324 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
14325 $response->is_fest = $is_fest;
14326 $response->report_chart = $report_chart;
14327 $response->report_cols = $report_cols;
14328 $response->report_values = $report_values;
14329 $response->report_script = $report->getScript();
14330 $response->chart_labels = $report->getProperty('chartJsLabels');
14331 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
14332 $response->chart_colors = $report->getProperty('chartJsColors');
14333 $response->chart_data = $report->getProperty('chartJsData');
14334 $response->report_chart_metas = $report_chart_metas;
14335
14336 echo json_encode($response);
14337 exit;
14338 }
14339
14340 /**
14341 * Go to the previous booking.
14342 *
14343 * @uses navigateToBooking()
14344 *
14345 * @since 1.3.0
14346 */
14347 public function prev_booking()
14348 {
14349 $this->navigateToBooking('prev');
14350 }
14351
14352 /**
14353 * Go to the next booking.
14354 *
14355 * @uses navigateToBooking()
14356 *
14357 * @since 1.3.0
14358 */
14359 public function next_booking()
14360 {
14361 $this->navigateToBooking('next');
14362 }
14363
14364 /**
14365 * Given the current booking ID in the request, we navigate
14366 * either to the next or to the previous reservation (if any).
14367 *
14368 * @param string $direction either next or prev.
14369 *
14370 * @return void
14371 *
14372 * @since 1.3.0
14373 */
14374 private function navigateToBooking($direction = 'next')
14375 {
14376 $bid = VikRequest::getInt('whereup', 0, 'request');
14377 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
14378 throw new Exception("Invalid request", 400);
14379 }
14380
14381 $dbo = JFactory::getDbo();
14382 $app = JFactory::getApplication();
14383
14384 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
14385 $dbo->setQuery($q, 0, 1);
14386 $dbo->execute();
14387 if (!$dbo->getNumRows()) {
14388 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
14389 $app->redirect("index.php?option=com_vikbooking&task=orders");
14390 exit;
14391 }
14392
14393 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
14394 exit;
14395 }
14396
14397 /**
14398 * AJAX request: from a list of reservation IDs, we return the ones
14399 * that have a review with the related review ID on VCM.
14400 *
14401 * @since 1.13
14402 */
14403 public function bookings_have_reviews()
14404 {
14405 if (!JSession::checkToken()) {
14406 // missing CSRF-proof token
14407 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14408 }
14409
14410 $dbo = JFactory::getDbo();
14411
14412 $bids = VikRequest::getVar('bids', [], 'request', 'array');
14413 $vcm_installed = class_exists('VikChannelManager');
14414 $withreviews = [];
14415
14416 if ($vcm_installed && $bids) {
14417 $bids = array_filter(array_map('intval', (array) $bids));
14418 $bids = $bids ?: [0];
14419
14420 try {
14421 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
14422 $dbo->setQuery($q);
14423 $reviews = $dbo->loadAssocList();
14424
14425 foreach ($reviews as $r) {
14426 $withreviews[$r['idorder']] = $r['id'];
14427 }
14428 } catch (Exception $e) {
14429 // do nothing, outdated version
14430 }
14431 }
14432
14433 // output list of booking IDs found, if any
14434 VBOHttpDocument::getInstance()->json($withreviews);
14435 }
14436
14437 /**
14438 * AJAX request for adding a new room-day note.
14439 *
14440 * @return void
14441 *
14442 * @since 1.13.5
14443 */
14444 public function add_roomdaynote()
14445 {
14446 $dt = VikRequest::getString('dt', '', 'request');
14447 $idroom = VikRequest::getInt('idroom', 0, 'request');
14448 $subunit = VikRequest::getInt('subunit', 0, 'request');
14449 $type = VikRequest::getString('type', '', 'request');
14450 $type = empty($type) ? 'custom' : $type;
14451 $name = VikRequest::getString('name', '', 'request');
14452 $descr = VikRequest::getString('descr', '', 'request');
14453 $cdays = VikRequest::getInt('cdays', 0, 'request');
14454 $cdays = $cdays < 0 ? 0 : $cdays;
14455 $cdays = $cdays > 365 ? 365 : $cdays;
14456 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
14457 echo 'e4j.error.1';
14458 exit;
14459 }
14460
14461 // reload end date
14462 $end_date = $dt;
14463
14464 // build critical date object
14465 $new_note = array(
14466 'name' => $name,
14467 'type' => $type,
14468 'descr' => $descr,
14469 );
14470
14471 // get object
14472 $notes = VikBooking::getCriticalDatesInstance();
14473
14474 // store the notes for all consecutive dates
14475 for ($i = 0; $i <= $cdays; $i++) {
14476 $store_dt = $dt;
14477 if ($i > 0) {
14478 $dt_info = getdate(strtotime($store_dt));
14479 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
14480 $end_date = $store_dt;
14481 }
14482 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
14483 if (!$result) {
14484 echo 'e4j.error.2';
14485 exit;
14486 }
14487 }
14488
14489 // reload all room day notes for this day for the AJAX response
14490 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
14491
14492 if (!$all_notes || !count($all_notes)) {
14493 // no notes found even after storing it
14494 echo 'e4j.error.3';
14495 exit;
14496 }
14497
14498 echo json_encode($all_notes);
14499 exit;
14500 }
14501
14502 /**
14503 * AJAX request for removing a room day note.
14504 *
14505 * @return void
14506 *
14507 * @since 1.13.5
14508 */
14509 public function remove_roomdaynote()
14510 {
14511 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
14512 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14513 }
14514
14515 $dt = VikRequest::getString('dt', '', 'request');
14516 $idroom = VikRequest::getInt('idroom', 0, 'request');
14517 $subunit = VikRequest::getInt('subunit', 0, 'request');
14518 $type = VikRequest::getString('type', '', 'request');
14519 $type = empty($type) ? 'custom' : $type;
14520 $ind = VikRequest::getInt('ind', 0, 'request');
14521 if (empty($dt) || !strtotime($dt)) {
14522 echo 'e4j.error.1';
14523 exit;
14524 }
14525
14526 $notes = VikBooking::getCriticalDatesInstance();
14527 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
14528 if (!$result) {
14529 echo 'e4j.error.2';
14530 exit;
14531 }
14532
14533 echo 'e4j.ok';
14534 exit;
14535 }
14536
14537 /**
14538 * AJAX request for storing an event for a booking.
14539 * Firstly developed for the VCM Reporting API - Guest Misconduct,
14540 * but it can be used for any other purpose.
14541 *
14542 * @return void
14543 *
14544 * @since 1.13.5
14545 */
14546 public function store_booking_history_event()
14547 {
14548 $bid = VikRequest::getInt('bid', 0, 'request');
14549 $event = VikRequest::getString('event', '', 'request');
14550 $descr = VikRequest::getString('descr', '', 'request');
14551
14552 if (empty($bid) || empty($event)) {
14553 throw new Exception("Missing required information", 500);
14554 }
14555
14556 // Booking History
14557 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
14558 //
14559
14560 echo 'e4j.ok';
14561 exit;
14562 }
14563
14564 /**
14565 * AJAX request for updating an option/extra service.
14566 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
14567 * but it can be used for any other purpose.
14568 *
14569 * @return void
14570 *
14571 * @since 1.13.5
14572 */
14573 public function update_option_params()
14574 {
14575 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
14576 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14577 }
14578
14579 $optid = VikRequest::getInt('optid', 0, 'request');
14580 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
14581
14582 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
14583 throw new Exception("Missing required information", 500);
14584 }
14585
14586 $dbo = JFactory::getDbo();
14587 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
14588 $dbo->setQuery($q);
14589 $dbo->execute();
14590 if (!$dbo->getNumRows()) {
14591 throw new Exception("Option not found", 404);
14592 }
14593 $cur_params = $dbo->loadResult();
14594 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
14595 $cur_params = !is_array($cur_params) ? array() : $cur_params;
14596
14597 foreach ($oparams as $k => $v) {
14598 if (empty($k)) {
14599 continue;
14600 }
14601 $cur_params[$k] = $v;
14602 }
14603
14604 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
14605 $dbo->setQuery($q);
14606 $dbo->execute();
14607
14608 echo 'e4j.ok';
14609 exit;
14610 }
14611
14612 /**
14613 * Hidden task to clean up duplicate records in certain database tables
14614 * due to a double execution of the installation queries. Ghost records,
14615 * if any, are also removed to clean up issues with hanging records.
14616 *
14617 * @since November 4th 2020
14618 * @since 1.16.3 (J) - 1.6.3 (WP)
14619 */
14620 public function clean_duplicate_records()
14621 {
14622 if (!JFactory::getUser()->authorise('core.admin', 'com_vikbooking')) {
14623 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14624 }
14625
14626 $dbo = JFactory::getDbo();
14627
14628 $tables_with_duplicates = [
14629 '#__vikbooking_config' => [
14630 'id_key' => 'id',
14631 'compare_key' => 'param',
14632 ],
14633 '#__vikbooking_countries' => [
14634 'id_key' => 'id',
14635 'compare_key' => 'country_3_code',
14636 ],
14637 '#__vikbooking_custfields' => [
14638 'id_key' => 'id',
14639 'compare_key' => 'name',
14640 ],
14641 '#__vikbooking_texts' => [
14642 'id_key' => 'id',
14643 'compare_key' => 'param',
14644 ],
14645 ];
14646
14647 foreach ($tables_with_duplicates as $tblname => $data) {
14648 $doubles = [];
14649 $storage = [];
14650 $rmlist = [];
14651
14652 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
14653 $dbo->setQuery($q);
14654 $rows = $dbo->loadAssocList();
14655 if (!$rows) {
14656 echo "<p>No records found in table {$tblname}</p>";
14657 continue;
14658 }
14659
14660 foreach ($rows as $row) {
14661 if (!isset($doubles[$row[$data['compare_key']]])) {
14662 $doubles[$row[$data['compare_key']]] = 0;
14663 }
14664 $doubles[$row[$data['compare_key']]]++;
14665 if (!isset($storage[$row[$data['compare_key']]])) {
14666 $storage[$row[$data['compare_key']]] = [];
14667 }
14668 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
14669 }
14670
14671 foreach ($doubles as $paramkey => $paramcount) {
14672 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
14673 continue;
14674 }
14675 $exceeding = $paramcount - 1;
14676 for ($x = 0; $x < $exceeding; $x++) {
14677 array_push($rmlist, $storage[$paramkey][$x]);
14678 }
14679 }
14680
14681 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
14682 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
14683 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
14684
14685 if (count($rmlist)) {
14686 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
14687 $dbo->setQuery($q);
14688 $dbo->execute();
14689 }
14690 }
14691
14692 /**
14693 * Clean up busy records where the busy relations contain empty booking IDs.
14694 */
14695 $hanging_busy_ids = [];
14696
14697 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
14698 $dbo->setQuery($q);
14699 $removelist = $dbo->loadAssocList();
14700 if ($removelist) {
14701 foreach ($removelist as $hanging_busy) {
14702 $hanging_busy_id = (int)$hanging_busy['idbusy'];
14703 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14704 array_push($hanging_busy_ids, $hanging_busy_id);
14705 }
14706 }
14707 }
14708
14709 // let's check also for ghost records that only occupy the room
14710 $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);";
14711 $dbo->setQuery($q);
14712 $removelist = $dbo->loadAssocList();
14713 if ($removelist) {
14714 foreach ($removelist as $hanging_busy) {
14715 $hanging_busy_id = (int)$hanging_busy['id'];
14716 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
14717 array_push($hanging_busy_ids, $hanging_busy_id);
14718 }
14719 }
14720 }
14721
14722 if ($hanging_busy_ids) {
14723 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
14724 $dbo->setQuery($q);
14725 $dbo->execute();
14726 }
14727
14728 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
14729
14730 return;
14731 }
14732
14733 /**
14734 * Hidden task to scan all database tables of VikBooking and Vik Channel Manager
14735 * to ensure the column `id` is defined as a primary key and got an auto-increment
14736 * extra flag properly defined and set. We've noticed that some third-party plugins
14737 * used to migrate WP sites may break the primary keys, and so new records won't get an ID.
14738 *
14739 * @since 1.16.8 (J) - 1.6.8 (WP)
14740 */
14741 public function fix_autoincrement_tables()
14742 {
14743 if (!JFactory::getUser()->authorise('core.admin', 'com_vikbooking')) {
14744 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14745 }
14746
14747 $dbo = JFactory::getDbo();
14748
14749 // load all the installed database tables
14750 $tables = $dbo->getTableList();
14751
14752 // get current database prefix
14753 $prefix = $dbo->getPrefix();
14754
14755 // replace prefix with placeholder
14756 $tables = array_map(function($table) use ($prefix)
14757 {
14758 return preg_replace("/^{$prefix}/", '#__', $table);
14759 }, $tables);
14760
14761 // remove all the tables that do not belong to VikBooking/VCM
14762 $tables = array_values(array_filter($tables, function($table)
14763 {
14764 if (preg_match("/^#__vik(?:booking|channelmanager)_config$/", $table))
14765 {
14766 // exclude the configuration table, which will be handled in a different way
14767 return false;
14768 }
14769
14770 return preg_match("/^#__vik(?:booking|channelmanager)_/", $table);
14771 }));
14772
14773 foreach ($tables as $table) {
14774 $columns = $dbo->getTableColumns($table, false);
14775 if (!isset($columns['id']) || empty($columns['id']->Type) || !empty($columns['id']->Extra)) {
14776 continue;
14777 }
14778
14779 echo 'Fixing ' . $table. ' for missing auto-increment<br/><pre>' . print_r($columns['id'], true) . '</pre><br/>';
14780
14781 // set auto-increment and primary key
14782 $dbo->setQuery("ALTER TABLE `{$table}` MODIFY `id` " . $columns['id']->Type . " NOT NULL AUTO_INCREMENT PRIMARY KEY;");
14783 $dbo->execute();
14784
14785 // count next auto-increment
14786 $dbo->setQuery("SELECT MAX(`id`) FROM `{$table}`");
14787 $next_ai = (int) $dbo->loadResult() + 1;
14788
14789 // update next auto-increment value
14790 $dbo->setQuery("ALTER TABLE `{$table}` AUTO_INCREMENT = {$next_ai}");
14791 $dbo->execute();
14792 }
14793 }
14794
14795 /**
14796 * Hidden task to (re-)run the update queries from a given plugin version.
14797 * Useful to ensure the database structure is up-to-date and no update queries went lost.
14798 *
14799 * @since 1.17.6 (J) - 1.7.6 (WP)
14800 */
14801 public function run_update_queries()
14802 {
14803 $app = JFactory::getApplication();
14804 $dbo = JFactory::getDbo();
14805
14806 if (!JFactory::getUser()->authorise('core.admin', 'com_vikbooking')) {
14807 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
14808 }
14809
14810 $from_version = $app->input->getString('from_version');
14811
14812 if (empty($from_version)) {
14813 VBOHttpDocument::getInstance()->close(400, 'Missing from version value.');
14814 }
14815
14816 // determine the SQL updates directory path
14817 $sql_updates_path = '';
14818 if (VBOPlatformDetection::isWordPress()) {
14819 $sql_updates_path = implode(DIRECTORY_SEPARATOR, [VIKBOOKING_BASE, 'sql', 'update', 'mysql']);
14820 } else {
14821 $sql_updates_path = implode(DIRECTORY_SEPARATOR, [VBO_ADMIN_PATH, 'sql', 'updates', 'mysql']);
14822 }
14823
14824 if (!$sql_updates_path || !is_dir($sql_updates_path)) {
14825 VBOHttpDocument::getInstance()->close(500, 'Could not find SQL updates path.');
14826 }
14827
14828 // read all SQL update files
14829 $sql_update_files = JFolder::files($sql_updates_path, '\.sql', $recurse = false, $full = true);
14830
14831 // filter SQL files with just the valid ones
14832 $sql_update_files = array_filter($sql_update_files, function($sql_update_file) use ($from_version) {
14833 $file_version = basename($sql_update_file, '.sql');
14834 return version_compare($file_version, $from_version, '>=');
14835 });
14836
14837 // sort files by version ascending
14838 usort($sql_update_files, function($a, $b) {
14839 return version_compare(basename($a, '.sql'), basename($b, '.sql'));
14840 });
14841
14842 if (!$sql_update_files) {
14843 VBOHttpDocument::getInstance()->close(500, sprintf('Could not find any suitable SQL update file from version %s.', $from_version));
14844 }
14845
14846 $success_queries = 0;
14847
14848 foreach ($sql_update_files as $file) {
14849 $handle = fopen($file, 'r');
14850
14851 $bytes = '';
14852 while (!feof($handle)) {
14853 $bytes .= fread($handle, 8192);
14854 }
14855
14856 fclose($handle);
14857
14858 if (VBOPlatformDetection::isWordPress()) {
14859 $queries_list = JDatabaseHelper::splitSql($bytes);
14860 } else {
14861 try {
14862 if (class_exists('JDatabaseDriver')) {
14863 $queries_list = JDatabaseDriver::splitSql($bytes);
14864 } else {
14865 $queries_list = Joomla\Database\DatabaseDriver::splitSql($bytes);
14866 }
14867 } catch(Throwable $e) {
14868 $app->enqueueMessage(sprintf('Error splitting queries: %s', $e->getMessage()), 'error');
14869 $queries_list = [];
14870 }
14871 }
14872
14873 foreach ($queries_list as $q) {
14874 try {
14875 $dbo->setQuery($q);
14876 $result = $dbo->execute();
14877 } catch (Exception $e) {
14878 $result = false;
14879 $app->enqueueMessage(sprintf('Error executing query: %s', $e->getMessage()), 'warning');
14880 }
14881
14882 if ($result) {
14883 $success_queries++;
14884 }
14885 }
14886 }
14887
14888 if ($success_queries) {
14889 $app->enqueueMessage(sprintf('Successful queries: %d', $success_queries), 'success');
14890 }
14891
14892 // send response to output
14893 echo '<pre>'.print_r($sql_update_files, true).'</pre><br/>';
14894 }
14895
14896 /**
14897 * Loads a specific admin widget ID and executes the requested method.
14898 * Useful for loading a newly added widget, or to execute custom methods.
14899 *
14900 * @see this is an AJAX endpoint.
14901 *
14902 * @since 1.14 (J) - 1.4.0 (WP)
14903 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
14904 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14905 */
14906 public function exec_admin_widget()
14907 {
14908 if (!JSession::checkToken()) {
14909 // missing CSRF-proof token
14910 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14911 }
14912
14913 $widget_id = VikRequest::getString('widget_id', '', 'request');
14914 $call = VikRequest::getString('call', '', 'request');
14915 $return = VikRequest::getInt('return', 0, 'request');
14916 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
14917 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
14918 $multitask = VikRequest::getInt('multitask', 0, 'request');
14919
14920 if (empty($widget_id)) {
14921 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
14922 }
14923
14924 if (empty($call) || !is_string($call)) {
14925 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14926 }
14927
14928 // invoke admin widgets helper
14929 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14930 $widget = $widgets_helper->getWidget($widget_id);
14931
14932 if ($widget === false) {
14933 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
14934 }
14935
14936 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
14937 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
14938 }
14939
14940 // get the multitask parser object
14941 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
14942
14943 // check if arguments should be passed
14944 $call_args = [];
14945 if ($multitask && $call === 'render') {
14946 // build the multitask data object and inject it to the args as the first index
14947 $call_args[] = $parser->getData();
14948
14949 // bind options within the widget, if any
14950 $widget->bindOptions($call_args[0]);
14951 } else {
14952 // always bind multitask options, if any
14953 $widget->bindOptions($parser->getOptions());
14954 }
14955
14956 try {
14957 if ($return) {
14958 // invoke the widget's method and get the value returned
14959 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
14960 } else {
14961 // invoke the widget's method within a buffer
14962 ob_start();
14963 if ($call_args) {
14964 $res = call_user_func_array([$widget, $call], $call_args);
14965 } else {
14966 $widget->{$call}();
14967 }
14968 $widget_response = ob_get_contents();
14969 ob_end_clean();
14970 }
14971 } catch (Throwable $e) {
14972 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, sprintf("%s\n%s at line %d", $e->getMessage(), $e->getFile(), $e->getLine()));
14973 } catch (Exception $e) {
14974 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14975 }
14976
14977 // prepare response object with a property equal to the called method
14978 $response = new stdClass;
14979 $response->{$call} = $widget_response;
14980
14981 // output the JSON encoded response and exit
14982 VBOHttpDocument::getInstance()->json($response);
14983 }
14984
14985 /**
14986 * Updates the map of admin widgets.
14987 *
14988 * @throws Exception this is an AJAX endpoint.
14989 *
14990 * @since 1.4.0
14991 */
14992 public function save_admin_widgets()
14993 {
14994 if (!JSession::checkToken()) {
14995 // missing CSRF-proof token
14996 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14997 }
14998
14999 // make sure permissions are sufficient
15000 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
15001 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
15002 }
15003
15004 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
15005 if (!is_array($psections) || !count($psections)) {
15006 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
15007 }
15008
15009 // request values are all converted to arrays, so restore the object styling
15010 $psections = json_decode(json_encode($psections));
15011
15012 // update map
15013 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
15014
15015 $response = new stdClass;
15016 $response->status = (int)$result;
15017
15018 // output the JSON encoded response and exit
15019 VBOHttpDocument::getInstance()->json($response);
15020 }
15021
15022 /**
15023 * Restores the default admin widgets map.
15024 *
15025 * @since 1.4.0
15026 */
15027 public function reset_admin_widgets()
15028 {
15029 // reset map and redirect to dashboard
15030 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
15031
15032 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
15033 exit;
15034 }
15035
15036 /**
15037 * Updates the welcome message status for the widget's customizer via AJAX.
15038 *
15039 * @since 1.4.0
15040 */
15041 public function admin_widgets_welcome()
15042 {
15043 if (!JSession::checkToken()) {
15044 // missing CSRF-proof token
15045 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15046 }
15047
15048 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
15049 // update configuration value
15050 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
15051
15052 $response = new stdClass;
15053 $response->status = $hide_welcome;
15054
15055 // output the JSON encoded response and exit
15056 VBOHttpDocument::getInstance()->json($response);
15057 }
15058
15059 public function newcondtext()
15060 {
15061 VikBookingHelper::printHeader("11");
15062
15063 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
15064
15065 parent::display();
15066
15067 if (VikBooking::showFooter()) {
15068 VikBookingHelper::printFooter();
15069 }
15070 }
15071
15072 public function editcondtext()
15073 {
15074 VikBookingHelper::printHeader("11");
15075
15076 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
15077
15078 parent::display();
15079
15080 if (VikBooking::showFooter()) {
15081 VikBookingHelper::printFooter();
15082 }
15083 }
15084
15085 public function cancelcondtext()
15086 {
15087 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
15088 }
15089
15090 public function createcondtext()
15091 {
15092 if (!JSession::checkToken()) {
15093 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
15094 }
15095
15096 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
15097 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
15098 }
15099
15100 $this->_doCreateCondText();
15101 }
15102
15103 public function createcondtextstay()
15104 {
15105 if (!JSession::checkToken()) {
15106 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
15107 }
15108
15109 if (!JFactory::getUser()->authorise('core.create', 'com_vikbooking')) {
15110 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
15111 }
15112
15113 $this->_doCreateCondText(true);
15114 }
15115
15116 private function _doCreateCondText($stay = false)
15117 {
15118 $dbo = JFactory::getDbo();
15119 $app = JFactory::getApplication();
15120 $rules_helper = VikBooking::getConditionalRulesInstance();
15121 $rules_list = $rules_helper->composeRulesParamsFromRequest();
15122
15123 $condtextname = VikRequest::getString('condtextname', '', 'request');
15124 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
15125 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
15126 $debug = VikRequest::getInt('debug', 0, 'request');
15127 if (empty($condtextname)) {
15128 $condtextname = date('Y-m-dHis');
15129 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
15130 }
15131
15132 $existing_tokens = $rules_helper->getSpecialTags();
15133 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
15134 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
15135 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
15136 exit;
15137 }
15138
15139 $data = new stdClass;
15140 $data->name = $condtextname;
15141 $data->token = $condtexttkn;
15142 $data->rules = json_encode($rules_list);
15143 $data->msg = $msg;
15144 $data->lastupd = JDate::getInstance()->toSql();
15145 $data->debug = $debug;
15146
15147 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
15148
15149 if (isset($data->id)) {
15150 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
15151 }
15152
15153 if (!$stay || !isset($data->id)) {
15154 $this->cancelcondtext();
15155 exit;
15156 }
15157
15158 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
15159 }
15160
15161 public function updatecondtext()
15162 {
15163 if (!JSession::checkToken()) {
15164 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
15165 }
15166
15167 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
15168 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
15169 }
15170
15171 $this->_doUpdateCondText();
15172 }
15173
15174 public function updatecondtextstay()
15175 {
15176 if (!JSession::checkToken()) {
15177 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
15178 }
15179
15180 if (!JFactory::getUser()->authorise('core.edit', 'com_vikbooking')) {
15181 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
15182 }
15183
15184 $this->_doUpdateCondText(true);
15185 }
15186
15187 private function _doUpdateCondText($stay = false)
15188 {
15189 $dbo = JFactory::getDbo();
15190 $app = JFactory::getApplication();
15191 $rules_helper = VikBooking::getConditionalRulesInstance();
15192 $rules_list = $rules_helper->composeRulesParamsFromRequest();
15193
15194 $pwhere = VikRequest::getInt('where', '', 'request');
15195 $condtextname = VikRequest::getString('condtextname', '', 'request');
15196 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
15197 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
15198 $debug = VikRequest::getInt('debug', 0, 'request');
15199 if (empty($condtextname)) {
15200 $condtextname = date('Y-m-dHis');
15201 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
15202 }
15203
15204 $existing_tokens = $rules_helper->getSpecialTags();
15205 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
15206 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
15207 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
15208 exit;
15209 }
15210
15211 $data = new stdClass;
15212 $data->id = $pwhere;
15213 $data->name = $condtextname;
15214 $data->token = $condtexttkn;
15215 $data->rules = json_encode($rules_list);
15216 $data->msg = $msg;
15217 $data->lastupd = JDate::getInstance()->toSql();
15218 $data->debug = $debug;
15219
15220 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
15221
15222 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
15223
15224 if (!$stay) {
15225 $this->cancelcondtext();
15226 exit;
15227 }
15228
15229 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
15230 }
15231
15232 public function removecondtext()
15233 {
15234 if (!JFactory::getUser()->authorise('core.delete', 'com_vikbooking')) {
15235 VBOHttpDocument::getInstance()->close(403, JText::translate('JERROR_ALERTNOAUTHOR'));
15236 }
15237
15238 $dbo = JFactory::getDbo();
15239 $ids = VikRequest::getVar('cid', array());
15240
15241 VikBooking::getConditionalRulesInstance(true);
15242 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
15243
15244 foreach ($ids as $d) {
15245 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
15246 $dbo->setQuery($q);
15247 $dbo->execute();
15248 if (!$dbo->getNumRows()) {
15249 continue;
15250 }
15251 $special_tag = $dbo->loadResult();
15252
15253 // remove the token from each template file if it was used before
15254 if (!empty($special_tag)) {
15255 // remove token from all template files
15256 foreach ($templates as $tkey => $tpath) {
15257 // get requested file content
15258 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
15259 if (empty($fcontent) || !is_string($fcontent)) {
15260 break;
15261 }
15262 // remove tag from code content
15263 $fcontent = str_replace($special_tag, '', $fcontent);
15264 // update the file code
15265 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
15266 }
15267 }
15268
15269 // delete the record
15270 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
15271 $dbo->setQuery($q);
15272 $dbo->execute();
15273 }
15274
15275 $this->cancelcondtext();
15276 }
15277
15278 /**
15279 * AJAX endpoint to update one template file with the given tag or styles.
15280 * A JSON response will be echoed by exiting the process.
15281 */
15282 public function condtext_update_tmpl()
15283 {
15284 VikBooking::getConditionalRulesInstance(true);
15285
15286 $tagaction = VikRequest::getString('tagaction', '', 'request');
15287 $tag = VikRequest::getString('tag', '', 'request');
15288 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
15289 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
15290 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
15291
15292 $allowed_actions = array(
15293 'add',
15294 'remove',
15295 'styles',
15296 'restore',
15297 );
15298
15299 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
15300 throw new Exception("Invalid request submitted", 500);
15301 }
15302
15303 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
15304 throw new Exception("Invalid request submitted - missing tag", 500);
15305 }
15306
15307 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
15308 throw new Exception("Invalid request submitted - missing new HTML content", 500);
15309 }
15310
15311 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
15312 throw new Exception("No custom CSS classes to parse", 500);
15313 }
15314
15315 if ($tagaction == 'restore') {
15316 // immediately restore the requested file to avoid script interruptions
15317 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
15318 }
15319
15320 // get requested file content
15321 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
15322 if (empty($fcontent) || !is_string($fcontent)) {
15323 throw new Exception("File not found or its code is unreadable", 404);
15324 }
15325
15326 if ($tagaction == 'remove') {
15327 // remove tag from code content
15328 $fcontent = str_replace($tag, '', $fcontent);
15329 } elseif ($tagaction == 'add') {
15330 // add tag to code content in the same exact position
15331 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
15332 } elseif ($tagaction == 'styles') {
15333 // apply the same styling rules
15334 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
15335 }
15336
15337 // update the file code
15338 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
15339
15340 if (!$res) {
15341 throw new Exception("Could not update the source code of the template file", 500);
15342 }
15343
15344 // parse new HTML content
15345 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
15346 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
15347 throw new Exception("Could not parse new template file content", 404);
15348 }
15349
15350 // trigger backup/mirroring, if available
15351 if (VBOPlatformDetection::isWordPress()) {
15352 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
15353 }
15354
15355 // build output
15356 $output = new stdClass;
15357 $output->newhtml = $newhtmls[$file];
15358 $output->log = VikBookingHelperConditionalRules::getEditingLog();
15359
15360 echo json_encode($output);
15361 exit;
15362 }
15363
15364 /**
15365 * AJAX endpoint to invoke methods of the geocoding helper.
15366 */
15367 public function geocoding_endpoint()
15368 {
15369 $geo = VikBooking::getGeocodingInstance();
15370 $callback = VikRequest::getString('callback', '', 'request');
15371
15372 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
15373 throw new Exception("Callback not available", 403);
15374 }
15375
15376 // invoke requested method
15377 $res = $geo->{$callback}();
15378
15379 // prepare response
15380 $response = new stdClass;
15381 $response->{$callback} = $res;
15382
15383 echo json_encode($response);
15384 exit;
15385 }
15386
15387 public function refundtn()
15388 {
15389 //modal box, so we do not set menu or footer
15390
15391 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
15392
15393 parent::display();
15394 }
15395
15396 public function do_refundtn()
15397 {
15398 $dbo = JFactory::getDbo();
15399 $app = JFactory::getApplication();
15400
15401 $bid = VikRequest::getInt('bid', 0, 'request');
15402 $amount = VikRequest::getFloat('amount', 0, 'request');
15403 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
15404 $tmpl = VikRequest::getString('tmpl', '', 'request');
15405 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
15406
15407 $currencysymb = VikBooking::getCurrencySymb();
15408
15409 if (empty($bid) || $amount <= 0) {
15410 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
15411 $app->redirect('index.php?option=com_vikbooking');
15412 exit;
15413 }
15414
15415 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
15416 $dbo->setQuery($q);
15417 $row = $dbo->loadAssoc();
15418 if (!$row) {
15419 VikError::raiseWarning('', 'Booking not found');
15420 $app->redirect('index.php?option=com_vikbooking');
15421 exit;
15422 }
15423
15424 // get booking history instance
15425 $history_obj = VikBooking::getBookingHistoryInstance();
15426 $history_obj->setBid($row['id']);
15427
15428 // get payment information
15429 $payment = VikBooking::getPayment($row['idpayment']);
15430 $tn_driver = is_array($payment) ? $payment['file'] : null;
15431
15432 // transaction data validation callback
15433 $tn_data_callback = function($data) use ($tn_driver) {
15434 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
15435 };
15436 // get previous transactions
15437 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
15438
15439 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
15440 // no previous transactions found
15441 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
15442 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
15443 exit;
15444 }
15445
15446 // push refund information for the payment gateway
15447 $row['total_to_refund'] = $amount;
15448 $row['transaction'] = $prev_tn_data;
15449 $row['refund_reason'] = $refund_reason;
15450
15451 // push the transaction currency information
15452 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
15453
15454 /**
15455 * Trigger event to allow third-party plugins to manipulate the transaction data.
15456 *
15457 * @since 1.18.5 (J) - 1.8.5 (WP)
15458 */
15459 VBOFactory::getPlatform()->getDispatcher()->trigger('onInitRefundTransaction', [&$row, &$payment['params']]);
15460
15461 if (VBOPlatformDetection::isWordPress()) {
15462 /**
15463 * @wponly The payment gateway is loaded
15464 * through the apposite dispatcher.
15465 */
15466 JLoader::import('adapter.payment.dispatcher');
15467 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
15468 } else {
15469 /**
15470 * @joomlaonly The Payment Factory library will invoke the gateway.
15471 *
15472 * @since 1.14.3
15473 */
15474 require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'payments' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'factory.php';
15475 $obj = VBOPaymentFactory::getPaymentInstance($payment['file'], $row, $payment['params']);
15476 }
15477
15478 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
15479 // refund not supported
15480 VikError::raiseWarning('', 'The selected payment method does not support refunds');
15481 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
15482 exit;
15483 }
15484
15485 // perform the refund transaction
15486 $array_result = $obj->refund();
15487
15488 if ($array_result['verified'] != 1) {
15489 // raise warning by getting the message
15490 if (!empty($array_result['log']) && is_string($array_result['log'])) {
15491 VikError::raiseWarning('', $array_result['log']);
15492 } else {
15493 VikError::raiseWarning('', 'Operation failed');
15494 }
15495 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
15496 exit;
15497 }
15498
15499 /**
15500 * New payment plugins can return the total amount refunded ('tot_paid').
15501 *
15502 * @since 1.15.4 (J) - 1.5.10 (WP)
15503 */
15504 if (!empty($array_result['tot_paid'])) {
15505 // overwrite the requested amount with the returned one
15506 $amount = (float)$array_result['tot_paid'];
15507 }
15508
15509 /**
15510 * The history event extra data will contain the "amount_paid" (refunded).
15511 *
15512 * @since 1.16.9 (J) - 1.6.9 (WP)
15513 */
15514 $history_obj->setExtraData([
15515 'amount_paid' => $amount,
15516 ]);
15517
15518 // update total paid, total and refund columns for the booking
15519 $booking = new stdClass;
15520 $booking->id = $row['id'];
15521 if ($row['totpaid'] > 0) {
15522 $booking->totpaid = $row['totpaid'] - $amount;
15523 }
15524 if ($row['total'] > 0) {
15525 $booking->total = $row['total'] - $amount;
15526 }
15527 $booking->refund = (float)$row['refund'] + $amount;
15528 // update record in db
15529 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
15530
15531 // store the refund event
15532 $event_descr = [
15533 '(' . $payment['name'] . ')',
15534 $refund_reason,
15535 $currencysymb . ' ' . VikBooking::numberFormat($amount),
15536 ];
15537 $history_obj->store('RF', implode("\n", $event_descr));
15538
15539 // display success message and redirect
15540 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
15541 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
15542 exit;
15543 }
15544
15545 /**
15546 * AJAX upload endpoint for media files.
15547 *
15548 * @return void
15549 *
15550 * @throws Exception
15551 *
15552 * @since 1.15.0 (J) - 1.5.0 (WP)
15553 */
15554 public function upload_media_file()
15555 {
15556 $input = JFactory::getApplication()->input;
15557
15558 // allowed types
15559 $type = $input->getString('type', '');
15560 $mask = 'png,apng,jpg,jpeg,bmp,heic,webp,gif,ico,svg';
15561
15562 if ($type != 'image') {
15563 $mask .= ',zip,rar,pdf,doc,docx,rtf,odt,pages,xls,xlsx,csv,ods,numbers,txt,md';
15564 }
15565
15566 // response object
15567 $result = new stdClass;
15568 $result->status = 0;
15569
15570 try
15571 {
15572 // get file from request
15573 $file = $input->files->get('file', array(), 'array');
15574
15575 // try to upload the file
15576 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
15577 $result->status = 1;
15578
15579 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
15580 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
15581 }
15582 catch (Exception $e)
15583 {
15584 $result->error = $e->getMessage();
15585 $result->code = $e->getCode();
15586 }
15587
15588 echo json_encode($result);
15589 exit;
15590 }
15591
15592 /**
15593 * AJAX endpoint to invoke a report object's method.
15594 *
15595 * @return void
15596 *
15597 * @since 1.15.0 (J) - 1.5.0 (WP)
15598 * @since 1.18.6 (J) - 1.8.6 (WP) added support for "call_args".
15599 */
15600 public function invoke_report()
15601 {
15602 $app = JFactory::getApplication();
15603
15604 $report_name = $app->input->getString('report', '');
15605 $report_call = $app->input->getString('call', '');
15606 $call_args = $app->input->get('call_args', [], 'array');
15607 $params = $app->input->get('params', [], 'array');
15608
15609 if (empty($report_name)) {
15610 VBOHttpDocument::getInstance($app)->close(400, 'Missing report name');
15611 }
15612
15613 if (empty($report_call)) {
15614 VBOHttpDocument::getInstance($app)->close(400, 'Missing report call');
15615 }
15616
15617 // get requested report instance
15618 $report = VikBooking::getReportInstance($report_name);
15619 if (!$report) {
15620 VBOHttpDocument::getInstance($app)->close(404, 'Report not found');
15621 }
15622
15623 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
15624 VBOHttpDocument::getInstance($app)->close(403, sprintf('Cannot call [%s] on report', $report_call));
15625 }
15626
15627 try {
15628 // call on report's method
15629 if ($call_args) {
15630 $result = call_user_func_array([$report, $report_call], $call_args);
15631 } else {
15632 $result = $report->{$report_call}($params);
15633 }
15634 } catch (Exception $e) {
15635 VBOHttpDocument::getInstance($app)->close($e->getCode() ?: 500, $e->getMessage());
15636 }
15637
15638 if (is_null($result)) {
15639 VBOHttpDocument::getInstance($app)->close(400, 'Null response');
15640 }
15641
15642 if (is_scalar($result)) {
15643 // wrap result within an array for a JSON encoded response
15644 VBOHttpDocument::getInstance($app)->json([$result]);
15645 }
15646
15647 // output the JSON encoded array/object returned
15648 VBOHttpDocument::getInstance($app)->json($result);
15649 }
15650
15651 /**
15652 * Handles requests for the multitask widgets panel.
15653 *
15654 * @see this is an AJAX endpoint.
15655 *
15656 * @since 1.15.0 (J) - 1.5.0 (WP)
15657 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
15658 */
15659 public function exec_multitask_widgets()
15660 {
15661 if (!JSession::checkToken()) {
15662 // missing CSRF-proof token
15663 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15664 }
15665
15666 $call = VikRequest::getString('call', '', 'request');
15667 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
15668
15669 if (empty($call)) {
15670 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
15671 }
15672
15673 // invoke admin widgets helper
15674 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15675
15676 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
15677 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
15678 }
15679
15680 try {
15681 // invoke the helper's method and get the value returned
15682 if (is_array($call_args) && count($call_args)) {
15683 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
15684 } else {
15685 $result = $widgets_helper->{$call}();
15686 }
15687 } catch (Throwable $e) {
15688 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, sprintf("%s\n%s at line %d", $e->getMessage(), $e->getFile(), $e->getLine()));
15689 } catch (Exception $e) {
15690 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15691 }
15692
15693 // prepare response object with the result property
15694 $response = new stdClass;
15695 $response->result = $result;
15696
15697 // output the JSON response and exit
15698 VBOHttpDocument::getInstance()->json($response);
15699 }
15700
15701 /**
15702 * Handles requests for displaying a browser notification being dispatched.
15703 *
15704 * @see this is an AJAX endpoint.
15705 *
15706 * @since 1.15.0 (J) - 1.5.0 (WP)
15707 */
15708 public function notification_displayer()
15709 {
15710 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
15711
15712 if (empty($payload_str)) {
15713 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
15714 }
15715
15716 // attempt to decode the notification payload
15717 $payload = json_decode($payload_str);
15718
15719 if (!is_object($payload)) {
15720 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
15721 }
15722
15723 // get notification displayer for this type of notification
15724 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
15725 if (!$displayer) {
15726 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
15727 }
15728
15729 // compose the notification display data object
15730 try {
15731 $notif_data = $displayer->getData();
15732 if (!$notif_data) {
15733 throw new Exception('Error building the notification display data', 500);
15734 }
15735 } catch (Exception $e) {
15736 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
15737 }
15738
15739 // output the JSON response and exit
15740 VBOHttpDocument::getInstance()->json($notif_data);
15741 }
15742
15743 /**
15744 * Handles requests for watching widgets data and getting
15745 * new events to trigger browser notifications.
15746 *
15747 * @see this is an AJAX endpoint.
15748 *
15749 * @since 1.15.0 (J) - 1.5.0 (WP)
15750 * @since 1.16.8 (J) - 1.6.8 (WP) introduced notification events.
15751 */
15752 public function widgets_watch_data()
15753 {
15754 if (!JSession::checkToken()) {
15755 // missing CSRF-proof token
15756 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
15757 }
15758
15759 $app = JFactory::getApplication();
15760
15761 $watch_data_str = $app->input->get('watch_data', '', 'raw');
15762 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
15763
15764 if (empty($watch_data_str)) {
15765 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
15766 }
15767
15768 // attempt to decode the watch-data payload
15769 $watch_data = json_decode($watch_data_str, true);
15770
15771 if (!$watch_data) {
15772 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
15773 }
15774
15775 // check if any pushed data was set
15776 $pushed_data = (array)json_decode($pushed_data_str, true);
15777
15778 // container for new notifications
15779 $notifs_pool = [];
15780
15781 // container for the events data to dispatch
15782 $events_pool = [];
15783
15784 // get admin widgets helper
15785 $widgets_helper = VikBooking::getAdminWidgetsInstance();
15786
15787 foreach ($watch_data as $widget_id => $data) {
15788 // invoke admin widget (with no pre-loading)
15789 $widget_instance = $widgets_helper->getWidget($widget_id);
15790 if (!$widget_instance) {
15791 continue;
15792 }
15793
15794 // build the widget watch data object
15795 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
15796
15797 // check if the widget needs to emit browser notifications
15798 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
15799
15800 // check if the widget needs to emit JavaScript events
15801 $events = $widget_instance->getNotificationEvents($widget_watch_data);
15802
15803 if ($watch_next) {
15804 // update next watch-data object for this widget
15805 $watch_data[$widget_id] = $watch_next;
15806 }
15807
15808 if (is_array($notifications) && $notifications) {
15809 // merge notifications
15810 $notifs_pool = array_merge($notifs_pool, $notifications);
15811 }
15812
15813 if (is_array($events) && $events) {
15814 // push notification events for this widget
15815 $events_pool[] = $events;
15816 }
15817 }
15818
15819 // build the response object
15820 $response = new stdClass;
15821 $response->watch_data = $watch_data;
15822 $response->notifications = $notifs_pool;
15823 $response->events = $events_pool;
15824
15825 // output the JSON response and exit
15826 VBOHttpDocument::getInstance()->json($response);
15827 }
15828
15829 /**
15830 * Outputs a list of CSS assets required to render the admin widgets
15831 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
15832 *
15833 * @see this is an AJAX endpoint.
15834 *
15835 * @since 1.16.0 (J) - 1.6.0 (WP)
15836 */
15837 public function widgets_get_assets()
15838 {
15839 // list of needed CSS asset details
15840 $assets_pool = [];
15841
15842 // appearance preference assets (one or none)
15843 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
15844
15845 if (VBOPlatformDetection::isWordPress()) {
15846 // WordPress (main CSS)
15847 $assets_pool[] = [
15848 'rel' => 'stylesheet',
15849 'id' => 'vbo-style-css',
15850 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15851 'media' => 'all',
15852 ];
15853
15854 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15855 // appearance preference CSS
15856 $assets_pool[] = [
15857 'rel' => 'stylesheet',
15858 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15859 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
15860 'media' => 'all',
15861 ];
15862 }
15863 } else {
15864 // Joomla (main CSS)
15865 $assets_pool[] = [
15866 'rel' => 'stylesheet',
15867 'id' => 'vbo-style-css',
15868 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
15869 'media' => 'all',
15870 ];
15871
15872 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
15873 // appearance preference CSS
15874 $assets_pool[] = [
15875 'rel' => 'stylesheet',
15876 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
15877 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
15878 'media' => 'all',
15879 ];
15880 }
15881 }
15882
15883 // output the JSON response and exit
15884 VBOHttpDocument::getInstance()->json($assets_pool);
15885 }
15886 }
15887