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

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

14,652 lines 559.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 // import Joomla controller library
14 jimport('joomla.application.component.controller');
15
16 class VikBookingController extends JControllerVikBooking
17 {
18 /**
19 * Default controller's method when no task is defined,
20 * or no method exists for that task. If a View is requested.
21 * attempts to set it, otherwise sets the default View.
22 */
23 public function display($cachable = false, $urlparams = array()) {
24
25 $view = VikRequest::getVar('view', '');
26 $header_val = '';
27
28 if (!empty($view)) {
29 $header_val = $view;
30 VikRequest::setVar('view', $view);
31 } else {
32 $header_val = '18';
33 VikRequest::setVar('view', 'dashboard');
34 }
35
36 $hide_menu = JFactory::getApplication()->input->getBool('hide_menu', false);
37
38 if ($hide_menu === false)
39 {
40 VikBookingHelper::printHeader($header_val);
41 }
42
43 parent::display();
44
45 if (VikBooking::showFooter() && $hide_menu === false) {
46 VikBookingHelper::printFooter();
47 }
48 }
49
50 /**
51 * AJAX request for building dynamic donut charts.
52 *
53 * @return void
54 *
55 * @since 1.12.1
56 */
57 public function donut_charts_data() {
58 $fromdt = VikRequest::getString('fromdt', date('Y-m-d'), 'request');
59 $direction = VikRequest::getString('direction', 'next', 'request');
60 $days = VikRequest::getInt('days', 7, 'request');
61 if (empty($fromdt) || !strtotime($fromdt) || empty($days) || $days < 1) {
62 throw new Exception('Missing required data', 400);
63 }
64
65 $from_info = getdate(strtotime($fromdt));
66 if ($direction != 'next') {
67 // fromdt is always the next day after the end of the loop, so the very first next day from the last displayed
68 $from_info = getdate(mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - ($days * 2)), $from_info['year']));
69 }
70 // always push the start date to the last second (23:59:59)
71 $from_info = getdate(mktime(23, 59, 59, $from_info['mon'], $from_info['mday'], $from_info['year']));
72
73 // months front-end language map
74 $monthsmap = array(
75 JText::translate('VBSHORTMONTHONE'),
76 JText::translate('VBSHORTMONTHTWO'),
77 JText::translate('VBSHORTMONTHTHREE'),
78 JText::translate('VBSHORTMONTHFOUR'),
79 JText::translate('VBSHORTMONTHFIVE'),
80 JText::translate('VBSHORTMONTHSIX'),
81 JText::translate('VBSHORTMONTHSEVEN'),
82 JText::translate('VBSHORTMONTHEIGHT'),
83 JText::translate('VBSHORTMONTHNINE'),
84 JText::translate('VBSHORTMONTHTEN'),
85 JText::translate('VBSHORTMONTHELEVEN'),
86 JText::translate('VBSHORTMONTHTWELVE'),
87 );
88
89 // weekdays front-end language map
90 $wdaysmap = array(
91 JText::translate('VBSUNDAY'),
92 JText::translate('VBMONDAY'),
93 JText::translate('VBTUESDAY'),
94 JText::translate('VBWEDNESDAY'),
95 JText::translate('VBTHURSDAY'),
96 JText::translate('VBFRIDAY'),
97 JText::translate('VBSATURDAY'),
98 );
99
100 // gather information about the rooms and availability
101 $dbo = JFactory::getDbo();
102 $all_rooms_ids = array();
103 $unpublished_rooms = array();
104 $todayymd = date('Y-m-d');
105 $q = "SELECT `id`,`name`,`units`,`params`,`avail` FROM `#__vikbooking_rooms`;";
106 $dbo->setQuery($q);
107 $dbo->execute();
108 if ($dbo->getNumRows()) {
109 $all_rooms = $dbo->loadAssocList();
110 foreach ($all_rooms as $k => $r) {
111 if ($r['avail'] < 1) {
112 $unpublished_rooms[] = $r['id'];
113 }
114 $all_rooms_ids[$r['id']] = $r['name'];
115 }
116 }
117 $q = "SELECT SUM(`units`) FROM `#__vikbooking_rooms` WHERE `avail`=1;";
118 $dbo->setQuery($q);
119 $dbo->execute();
120 $tot_rooms_units = (int)$dbo->loadResult();
121
122 // load busy records
123 $expected_max_ts = mktime(23, 59, 59, $from_info['mon'], ($from_info['mday'] + $days), $from_info['year']);
124 $busy = VikBooking::loadBusyRecordsUnclosed(array_keys($all_rooms_ids), $from_info[0], $expected_max_ts);
125
126 // response body
127 $response = new stdClass;
128 $response->prevweek = ($todayymd != date('Y-m-d', $from_info[0]));
129 $response->nextweek = true;
130 $response->fromd = date('Y-m-d', $from_info[0]);
131 $response->tot_units = $tot_rooms_units;
132 $response->data = array();
133
134 for ($i = 0; $i < $days; $i++) {
135 $tot_booked_today = 0;
136 $today_ts = $from_info[0];
137 $data_obj = new stdClass;
138 $data_obj->ymd = date('Y-m-d', $from_info[0]);
139 $data_obj->lbl = $wdaysmap[(int)$from_info['wday']] . ', ' . $from_info['mday'];
140 $data_obj->lbl = $data_obj->ymd == $todayymd ? JText::translate('VBTODAY') . ', ' . $data_obj->lbl : $data_obj->lbl . ' ' . $monthsmap[($from_info['mon'] - 1)];
141 foreach ($busy as $idroom => $rbusy) {
142 if (in_array($idroom, $unpublished_rooms)) {
143 continue;
144 }
145 foreach ($rbusy as $b) {
146 $tmpone = getdate($b['checkin']);
147 $ritts = mktime(0, 0, 0, $tmpone['mon'], $tmpone['mday'], $tmpone['year']);
148 $tmptwo = getdate($b['checkout']);
149 $conts = mktime(0, 0, 0, $tmptwo['mon'], $tmptwo['mday'], $tmptwo['year']);
150 if ($today_ts >= $ritts && $today_ts < $conts) {
151 $tot_booked_today++;
152 }
153 }
154 }
155
156 $data_obj->tot_booked = $tot_booked_today;
157 $percentage_booked = round((100 * $tot_booked_today / $tot_rooms_units), 2);
158
159 $data_obj->color = '#ff4d4d'; //red
160 if ($percentage_booked > 33 && $percentage_booked <= 66) {
161 $data_obj->color = '#ffa64d'; //orange
162 } elseif ($percentage_booked > 66 && $percentage_booked < 100) {
163 $data_obj->color = '#2a762c'; //green
164 } elseif ($percentage_booked >= 100) {
165 $data_obj->color = '#2482b4'; //light-blue
166 }
167
168 // push today's data
169 array_push($response->data, $data_obj);
170
171 // next day
172 $from_info = getdate(mktime(23, 59, 59, $from_info['mon'], ($from_info['mday'] + 1), $from_info['year']));
173 }
174
175 // update last date (not displayed/included)
176 $response->tod = date('Y-m-d', $from_info[0]);
177
178 echo json_encode($response);
179 exit;
180 }
181
182 /**
183 * AJAX request for adding a new fest.
184 *
185 * @return void
186 *
187 * @since 1.2.0
188 */
189 public function add_fest() {
190 $dt = VikRequest::getString('dt', '', 'request');
191 $type = VikRequest::getString('type', '', 'request');
192 $type = empty($type) ? 'custom' : $type;
193 $name = VikRequest::getString('name', '', 'request');
194 $descr = VikRequest::getString('descr', '', 'request');
195 if (empty($name) || empty($dt) || !strtotime($dt)) {
196 echo 'e4j.error.1';
197 exit;
198 }
199 // build fest array
200 $new_fest = array(
201 'trans_name' => $name
202 );
203
204 $fests = VikBooking::getFestivitiesInstance();
205 $result = $fests->storeFestivity($dt, $new_fest, $type, $descr);
206 if (!$result) {
207 echo 'e4j.error.2';
208 exit;
209 }
210
211 // reload all festivities for this day for the AJAX response
212 $all_fests = $fests->loadFestDates($dt, $dt);
213 foreach ($all_fests as $k => $v) {
214 // we expect just one record to be returned due to the from/to date limit passed to loadFestDates()
215 echo json_encode($v);
216 exit;
217 }
218
219 // no fests found even after storing it
220 echo 'e4j.error.3';
221 exit;
222 }
223
224 /**
225 * AJAX request for removing a fest.
226 *
227 * @return void
228 *
229 * @since 1.2.0
230 */
231 public function remove_fest() {
232 $dt = VikRequest::getString('dt', '', 'request');
233 $ind = VikRequest::getInt('ind', 0, 'request');
234 $type = VikRequest::getString('type', '', 'request');
235 $type = empty($type) ? 'custom' : $type;
236 if (empty($dt) || !strtotime($dt)) {
237 echo 'e4j.error.1';
238 exit;
239 }
240
241 $fests = VikBooking::getFestivitiesInstance();
242 $result = $fests->deleteFestivity($dt, $ind, $type);
243 if (!$result) {
244 echo 'e4j.error.2';
245 exit;
246 }
247
248 echo 'e4j.ok';
249 exit;
250 }
251
252 public function einvoicing() {
253 VikBookingHelper::printHeader("einvoicing");
254
255 VikRequest::setVar('view', VikRequest::getCmd('view', 'einvoicing'));
256
257 parent::display();
258
259 if (VikBooking::showFooter()) {
260 VikBookingHelper::printFooter();
261 }
262 }
263
264 public function pmsreports() {
265 VikBookingHelper::printHeader("pmsreports");
266
267 VikRequest::setVar('view', VikRequest::getCmd('view', 'pmsreports'));
268
269 parent::display();
270
271 if (VikBooking::showFooter()) {
272 VikBookingHelper::printFooter();
273 }
274 }
275
276 public function ratesoverv() {
277 VikBookingHelper::printHeader("20");
278
279 VikRequest::setVar('view', VikRequest::getCmd('view', 'ratesoverv'));
280
281 parent::display();
282
283 if (VikBooking::showFooter()) {
284 VikBookingHelper::printFooter();
285 }
286 }
287
288 public function stats() {
289 VikBookingHelper::printHeader("stats");
290
291 VikRequest::setVar('view', VikRequest::getCmd('view', 'stats'));
292
293 parent::display();
294
295 if (VikBooking::showFooter()) {
296 VikBookingHelper::printFooter();
297 }
298 }
299
300 /**
301 * AJAX endpoint to calculate the website rates.
302 *
303 * @return void
304 */
305 public function calc_rates()
306 {
307 $response = 'e4j.error.ErrorCode(1) Server is blocking the self-request';
308 $response_code = 0;
309
310 // availability helper
311 $av_helper = VikBooking::getAvailabilityInstance();
312
313 $currencysymb = VikBooking::getCurrencySymb();
314 $vbo_df = VikBooking::getDateFormat();
315 $df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y/m/d');
316 $id_room = VikRequest::getInt('id_room', '', 'request');
317 $checkin = VikRequest::getString('checkin', '', 'request');
318 $nights = VikRequest::getInt('num_nights', 1, 'request');
319 $adults = VikRequest::getInt('num_adults', 0, 'request');
320 $children = VikRequest::getInt('num_children', 0, 'request');
321 /**
322 * The page Calendar may call this task via AJAX to obtain information
323 * about the various rate plans and final costs associated.
324 *
325 * @since 1.13 (J) - 1.3.0 (WP)
326 */
327 $only_rates = VikRequest::getInt('only_rates', 0, 'request');
328 $units = VikRequest::getInt('units', 1, 'request');
329 $checkinfdate = VikRequest::getString('checkinfdate', '', 'request');
330 $checkoutfdate = VikRequest::getString('checkoutfdate', '', 'request');
331 if (!empty($checkinfdate) && empty($checkin)) {
332 $checkin = date('Y-m-d', VikBooking::getDateTimestamp($checkinfdate, 0, 0, 0));
333 }
334
335 $checkin_ts = strtotime($checkin);
336 if (empty($checkin_ts)) {
337 $checkin = date('Y-m-d');
338 $checkin_ts = strtotime($checkin);
339 }
340
341 if (!empty($checkoutfdate) && !empty($checkinfdate) && $nights < 2) {
342 // checkout date was given rather than number of nights
343 $checkout_ts = VikBooking::getDateTimestamp($checkoutfdate, 0, 0, 0);
344 $checkout = date('Y-m-d', $checkout_ts);
345 $nights = $av_helper->countNightsOfStay($checkin_ts, $checkout_ts);
346 } else {
347 // calculate checkout depending on number of nights of stay
348 $is_dst = date('I', $checkin_ts);
349 $checkout_ts = $checkin_ts;
350 for ($i = 1; $i <= $nights; $i++) {
351 $checkout_ts += 86400;
352 $is_now_dst = date('I', $checkout_ts);
353 if ($is_dst != $is_now_dst) {
354 if ((int)$is_dst == 1) {
355 $checkout_ts += 3600;
356 } else {
357 $checkout_ts -= 3600;
358 }
359 $is_dst = $is_now_dst;
360 }
361 }
362 $checkout = date('Y-m-d', $checkout_ts);
363 }
364
365 /**
366 * We got rid of the CURL request to the front-end task of VBO "tac_av_l"
367 * by replacing the call with the new helper class VikBookingAvailability.
368 *
369 * @since 1.15.0 (J) - 1.5.0 (WP)
370 */
371 $av_helper->setStayDates($checkin, $checkout);
372 $av_helper->setRoomParty($adults, $children);
373 // build extra params to obtain the necessary data
374 $params = array(
375 'hash' => md5('vbo.e4j.vbo'),
376 'req_type' => 'hotel_availability',
377 'nights' => $nights,
378 'num_rooms' => 1,
379 'only_rates' => $only_rates,
380 );
381 $arr_res = $av_helper->getRates($params);
382
383 // pricing pool
384 $price_details = array();
385
386 if (is_array($arr_res)) {
387 if (!strlen($av_helper->getError())) {
388 if (array_key_exists($id_room, $arr_res)) {
389 $response = '';
390 foreach ($arr_res[$id_room] as $rate) {
391 // build pricing object
392 $rplan_details = new stdClass;
393 $rplan_details->idprice = $rate['idprice'];
394 $rplan_details->name = $rate['pricename'];
395 $rplan_details->net = $rate['cost'];
396 $rplan_details->fnet = $currencysymb . ' ' . VikBooking::numberFormat($rate['cost']);
397 $rplan_details->tax = $rate['taxes'];
398 $rplan_details->ftax = $currencysymb . ' ' . VikBooking::numberFormat($rate['taxes']);
399 $rplan_details->tot = $rate['cost'] + $rate['taxes'];
400 $rplan_details->ftot = $currencysymb . ' ' . VikBooking::numberFormat(($rate['cost'] + $rate['taxes']));
401 array_push($price_details, $rplan_details);
402 //
403 $extra_response = '';
404 $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 . '">';
405 $response .= '<span class="vbo-calcrates-ratename">'.$rate['pricename'].'</span>';
406 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratenet"><span>'.JText::translate('VBCALCRATESNET').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['cost']).'</span>';
407 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratetax"><span>'.JText::translate('VBCALCRATESTAX').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['taxes']).'</span>';
408 if (!empty($rate['city_taxes'])) {
409 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratecitytax"><span>'.JText::translate('VBCALCRATESCITYTAX').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['city_taxes']).'</span>';
410 }
411 if (!empty($rate['fees'])) {
412 $response .= '<span class="vbo-calcrates-pricedet vbo-calcrates-ratefees"><span>'.JText::translate('VBCALCRATESFEES').'</span>'.$currencysymb.' '.VikBooking::numberFormat($rate['fees']).'</span>';
413 }
414 if (array_key_exists('affdays', $rate) && $rate['affdays'] > 0) {
415 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-ratespaffdays"><span>'.JText::translate('VBCALCRATESSPAFFDAYS').'</span>'.$rate['affdays'].'</span>';
416 }
417 if (array_key_exists('diffusagediscount', $rate) && count($rate['diffusagediscount']) > 0) {
418 foreach ($rate['diffusagediscount'] as $roomnumb => $disc) {
419 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancydisc"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>- '.$currencysymb.' '.VikBooking::numberFormat($disc).'</span>';
420 break;
421 }
422 } elseif (array_key_exists('diffusagecost', $rate) && count($rate['diffusagecost']) > 0) {
423 foreach ($rate['diffusagecost'] as $roomnumb => $charge) {
424 $extra_response .= '<span class="vbo-calcrates-extrapricedet vbo-calcrates-rateoccupancycharge"><span>'.JText::sprintf('VBCALCRATESADUOCCUPANCY', $rate['diffusage']).'</span>+ '.$currencysymb.' '.VikBooking::numberFormat($charge).'</span>';
425 break;
426 }
427 }
428 $tot = $rate['cost'] + $rate['taxes'] + $rate['city_taxes'] + $rate['fees'];
429 $tot = round($tot, 2);
430 $response .= '<span class="vbo-calcrates-ratetotal"><span>'.JText::translate('VBCALCRATESTOT').'</span>'.$currencysymb.' '.VikBooking::numberFormat($tot).'</span>';
431 if (!empty($extra_response)) {
432 $response .= '<div class="vbo-calcrates-info">'.$extra_response.'</div>';
433 }
434 $response .= '</div>';
435 }
436 } else {
437 $response = 'e4j.error.'.JText::sprintf('VBCALCRATESROOMNOTAVAILCOMBO', date($df, $checkin_ts), date($df, $checkout_ts));
438 /**
439 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
440 *
441 * @since 1.14 (J) - 1.4.0 (WP)
442 */
443 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
444 $response_code = -1;
445 }
446 }
447 } else {
448 $response = 'e4j.error.' . $av_helper->getError();
449 /**
450 * Set a response code so that the View calendar can understand that the room is not available or has no rates.
451 *
452 * @since 1.14 (J) - 1.4.0 (WP)
453 */
454 if (isset($arr_res['fullybooked']) && in_array($id_room, $arr_res['fullybooked'])) {
455 $response_code = -1;
456 }
457 }
458 } else {
459 $response = 'e4j.error.' . $av_helper->getError();
460 }
461
462 if ($only_rates && strpos($response, 'e4j.error') === false) {
463 echo json_encode($price_details);
464 exit;
465 }
466
467 // do not do only echo trim($response); or the currency symbol will not be encoded on some servers
468 $safe_response = array(trim($response));
469 if ($only_rates && !empty($response_code)) {
470 array_push($safe_response, $response_code);
471 }
472
473 echo json_encode($safe_response);
474 exit;
475 }
476
477 /**
478 * This is an AJAX endpoint.
479 */
480 public function cron_exec()
481 {
482 ob_start();
483
484 VikRequest::setVar('view', VikRequest::getCmd('view', 'cronexec'));
485
486 parent::display();
487
488 $content = ob_get_contents();
489 ob_end_clean();
490
491 VBOHttpDocument::getInstance()->json([$content]);
492 }
493
494 public function downloadcron()
495 {
496 /**
497 * @wponly no more executable files need to be downloaded for WordPress.
498 */
499 VBOHttpDocument::getInstance()->close(406, 'Cron Jobs must be executed through WPCron');
500 }
501
502 /**
503 * This is an AJAX endpoint.
504 */
505 public function cronlogs()
506 {
507 $dbo = JFactory::getDBO();
508 $pcron_id = VikRequest::getInt('cron_id', '', 'request');
509
510 ob_start();
511
512 $q = "SELECT * FROM `#__vikbooking_cronjobs` WHERE `id`=".(int)$pcron_id.";";
513 $dbo->setQuery($q);
514 $dbo->execute();
515 if ($dbo->getNumRows() == 1) {
516 $cron_data = $dbo->loadAssoc();
517 $cron_data['logs'] = empty($cron_data['logs']) ? '--------' : $cron_data['logs'];
518 echo '<pre>'.print_r($cron_data['logs'], true).'</pre>';
519 }
520
521 $content = ob_get_contents();
522 ob_end_clean();
523
524 VBOHttpDocument::getInstance()->json([$content]);
525 }
526
527 public function packages() {
528 VikBookingHelper::printHeader("packages");
529
530 VikRequest::setVar('view', VikRequest::getCmd('view', 'packages'));
531
532 parent::display();
533
534 if (VikBooking::showFooter()) {
535 VikBookingHelper::printFooter();
536 }
537 }
538
539 public function newpackage() {
540 VikBookingHelper::printHeader("packages");
541
542 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepackage'));
543
544 parent::display();
545
546 if (VikBooking::showFooter()) {
547 VikBookingHelper::printFooter();
548 }
549 }
550
551 public function editpackage() {
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 createpackage() {
564 if (!JSession::checkToken()) {
565 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
566 }
567 $this->do_createpackage();
568 }
569
570 public function createpackagestay() {
571 if (!JSession::checkToken()) {
572 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
573 }
574 $this->do_createpackage(true);
575 }
576
577 private function do_createpackage($stay = false) {
578 $dbo = JFactory::getDBO();
579 $mainframe = JFactory::getApplication();
580 $pname = VikRequest::getString('name', '', 'request');
581 $palias = VikRequest::getString('alias', '', 'request');
582 $palias = empty($palias) ? $pname : $palias;
583 $palias = JFilterOutput::stringURLSafe($palias);
584 $pimg = VikRequest::getVar('img', null, 'files', 'array');
585 $pfrom = VikRequest::getString('from', '', 'request');
586 $pto = VikRequest::getString('to', '', 'request');
587 $pexcludeday = VikRequest::getVar('excludeday', array());
588 $strexcldates = array();
589 foreach ($pexcludeday as $exclday) {
590 if (!empty($exclday)) {
591 $strexcldates[] = $exclday;
592 }
593 }
594 $strexcldates = implode(';', $strexcldates);
595 $prooms = VikRequest::getVar('rooms', array());
596 $pminlos = VikRequest::getInt('minlos', '', 'request');
597 $pminlos = $pminlos < 1 ? 1 : $pminlos;
598 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
599 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
600 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
601 $pcost = VikRequest::getFloat('cost', '', 'request');
602 $paliq = VikRequest::getInt('aliq', '', 'request');
603 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
604 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
605 $pperperson = VikRequest::getInt('perperson', '', 'request');
606 $pperperson = $pperperson > 0 ? 1 : 0;
607 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
608 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
609 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
610 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
611 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
612 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
613 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
614 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
615 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
616 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
617 //file upload
618 jimport('joomla.filesystem.file');
619 $gimg = "";
620 if (isset($pimg) && strlen(trim($pimg['name']))) {
621 $pautoresize = VikRequest::getString('autoresize', '', 'request');
622 $presizeto = VikRequest::getInt('resizeto', '', 'request');
623 $creativik = new vikResizer();
624 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
625 $src = $pimg['tmp_name'];
626 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
627 $j = "";
628 if (file_exists($dest.$filename)) {
629 $j = rand(171, 1717);
630 while (file_exists($dest.$j.$filename)) {
631 $j++;
632 }
633 }
634 $finaldest = $dest.$j.$filename;
635 $check = getimagesize($pimg['tmp_name']);
636 if ($check[2] & imagetypes()) {
637 if (VikBooking::uploadFile($src, $finaldest)) {
638 $gimg = $j.$filename;
639 //orig img
640 $origmod = true;
641 if ($pautoresize == "1" && !empty($presizeto)) {
642 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
643 } else {
644 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
645 }
646 //thumb
647 $thumbsize = VikBooking::getThumbSize();
648 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
649 if (!$thumb || !$origmod) {
650 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
651 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
652 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
653 }
654 @unlink($finaldest);
655 } else {
656 VikError::raiseWarning('', 'Error while uploading image');
657 }
658 } else {
659 VikError::raiseWarning('', 'Uploaded file is not an Image');
660 }
661 }
662 //
663 $goto = "index.php?option=com_vikbooking&task=packages";
664 $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.");";
665 $dbo->setQuery($q);
666 $dbo->execute();
667 $lid = $dbo->insertid();
668 if (!empty($lid)) {
669 $mainframe->enqueueMessage(JText::translate('VBOPKGSAVED'));
670 if ($stay) {
671 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$lid;
672 }
673 foreach ($prooms as $roomid) {
674 if (!empty($roomid)) {
675 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$lid.", ".(int)$roomid.");";
676 $dbo->setQuery($q);
677 $dbo->execute();
678 }
679 }
680 }
681 $mainframe->redirect($goto);
682 }
683
684 public function updatepackage() {
685 if (!JSession::checkToken()) {
686 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
687 }
688 $this->do_updatepackage();
689 }
690
691 public function updatepackagestay() {
692 if (!JSession::checkToken()) {
693 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
694 }
695 $this->do_updatepackage(true);
696 }
697
698 private function do_updatepackage($stay = false) {
699 $dbo = JFactory::getDBO();
700 $mainframe = JFactory::getApplication();
701 $pwhereup = VikRequest::getInt('whereup', '', 'request');
702 $q = "SELECT * FROM `#__vikbooking_packages` WHERE `id`=".(int)$pwhereup.";";
703 $dbo->setQuery($q);
704 $dbo->execute();
705 if ($dbo->getNumRows() == 1) {
706 $pkg_data = $dbo->loadAssoc();
707 } else {
708 VikError::raiseWarning('', 'Not Found.');
709 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
710 exit;
711 }
712 $pname = VikRequest::getString('name', '', 'request');
713 $palias = VikRequest::getString('alias', '', 'request');
714 $palias = empty($palias) ? $pname : $palias;
715 $palias = JFilterOutput::stringURLSafe($palias);
716 $pimg = VikRequest::getVar('img', null, 'files', 'array');
717 $pfrom = VikRequest::getString('from', '', 'request');
718 $pto = VikRequest::getString('to', '', 'request');
719 $pexcludeday = VikRequest::getVar('excludeday', array());
720 $strexcldates = array();
721 foreach ($pexcludeday as $exclday) {
722 if (!empty($exclday)) {
723 $strexcldates[] = $exclday;
724 }
725 }
726 $strexcldates = implode(';', $strexcldates);
727 $prooms = VikRequest::getVar('rooms', array());
728 $pminlos = VikRequest::getInt('minlos', '', 'request');
729 $pminlos = $pminlos < 1 ? 1 : $pminlos;
730 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
731 $pmaxlos = $pmaxlos < 0 ? 0 : $pmaxlos;
732 $pmaxlos = $pmaxlos < $pminlos ? 0 : $pmaxlos;
733 $pcost = VikRequest::getFloat('cost', '', 'request');
734 $paliq = VikRequest::getInt('aliq', '', 'request');
735 $ppernight_total = VikRequest::getInt('pernight_total', '', 'request');
736 $ppernight_total = $ppernight_total == 1 ? 1 : 2;
737 $pperperson = VikRequest::getInt('perperson', '', 'request');
738 $pperperson = $pperperson > 0 ? 1 : 0;
739 $pshowoptions = VikRequest::getInt('showoptions', '', 'request');
740 $pshowoptions = $pshowoptions >= 1 && $pshowoptions <= 3 ? $pshowoptions : 1;
741 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWRAW);
742 $pshortdescr = VikRequest::getString('shortdescr', '', 'request', VIKREQUEST_ALLOWHTML);
743 $pconditions = VikRequest::getString('conditions', '', 'request', VIKREQUEST_ALLOWRAW);
744 $pbenefits = VikRequest::getString('benefits', '', 'request', VIKREQUEST_ALLOWHTML);
745 $ptsinit = VikBooking::getDateTimestamp($pfrom, '0', '0');
746 $ptsend = VikBooking::getDateTimestamp($pto, '23', '59');
747 $ptsinit = empty($ptsinit) ? time() : $ptsinit;
748 $ptsend = empty($ptsend) || $ptsend < $ptsinit ? $ptsinit : $ptsend;
749 //file upload
750 jimport('joomla.filesystem.file');
751 $gimg = "";
752 if (isset($pimg) && strlen(trim($pimg['name']))) {
753 $pautoresize = VikRequest::getString('autoresize', '', 'request');
754 $presizeto = VikRequest::getInt('resizeto', '', 'request');
755 $creativik = new vikResizer();
756 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimg['name'])));
757 $src = $pimg['tmp_name'];
758 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
759 $j = "";
760 if (file_exists($dest.$filename)) {
761 $j = rand(171, 1717);
762 while (file_exists($dest.$j.$filename)) {
763 $j++;
764 }
765 }
766 $finaldest = $dest.$j.$filename;
767 $check = getimagesize($pimg['tmp_name']);
768 if ($check[2] & imagetypes()) {
769 if (VikBooking::uploadFile($src, $finaldest)) {
770 $gimg = $j.$filename;
771 //orig img
772 $origmod = true;
773 if ($pautoresize == "1" && !empty($presizeto)) {
774 $origmod = $creativik->proportionalImage($finaldest, $dest.'big_'.$j.$filename, $presizeto, $presizeto);
775 } else {
776 VikBooking::uploadFile($finaldest, $dest.'big_'.$j.$filename, true);
777 }
778 //thumb
779 $thumbsize = VikBooking::getThumbSize();
780 $thumb = $creativik->proportionalImage($finaldest, $dest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
781 if (!$thumb || !$origmod) {
782 if (file_exists($dest.'big_'.$j.$filename)) @unlink($dest.'big_'.$j.$filename);
783 if (file_exists($dest.'thumb_'.$j.$filename)) @unlink($dest.'thumb_'.$j.$filename);
784 VikError::raiseWarning('', 'Error Uploading the File: '.$pimg['name']);
785 }
786 @unlink($finaldest);
787 } else {
788 VikError::raiseWarning('', 'Error while uploading image');
789 }
790 } else {
791 VikError::raiseWarning('', 'Uploaded file is not an Image');
792 }
793 }
794 //
795 $goto = "index.php?option=com_vikbooking&task=packages";
796 $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.";";
797 $dbo->setQuery($q);
798 $dbo->execute();
799 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$pwhereup.";";
800 $dbo->setQuery($q);
801 $dbo->execute();
802 foreach ($prooms as $roomid) {
803 if (!empty($roomid)) {
804 $q = "INSERT INTO `#__vikbooking_packages_rooms` (`idpackage`,`idroom`) VALUES (".(int)$pwhereup.", ".(int)$roomid.");";
805 $dbo->setQuery($q);
806 $dbo->execute();
807 }
808 }
809 $mainframe->enqueueMessage(JText::translate('VBOPKGUPDATED'));
810 if ($stay) {
811 $goto = "index.php?option=com_vikbooking&task=editpackage&cid[]=".$pwhereup;
812 }
813 $mainframe->redirect($goto);
814 }
815
816 public function removepackages() {
817 if (!JSession::checkToken()) {
818 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
819 }
820 $ids = VikRequest::getVar('cid', array());
821 $dbo = JFactory::getDbo();
822
823 foreach ($ids as $d) {
824 $q = "DELETE FROM `#__vikbooking_packages` WHERE `id`=".(int)$d.";";
825 $dbo->setQuery($q);
826 $dbo->execute();
827 $q = "DELETE FROM `#__vikbooking_packages_rooms` WHERE `idpackage`=".(int)$d.";";
828 $dbo->setQuery($q);
829 $dbo->execute();
830 }
831
832 $mainframe = JFactory::getApplication();
833 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
834 }
835
836 public function calendar() {
837 VikBookingHelper::printHeader("19");
838
839 VikRequest::setVar('view', VikRequest::getCmd('view', 'calendar'));
840
841 parent::display();
842
843 if (VikBooking::showFooter()) {
844 VikBookingHelper::printFooter();
845 }
846 }
847
848 public function rooms() {
849 VikBookingHelper::printHeader("7");
850
851 VikRequest::setVar('view', VikRequest::getCmd('view', 'rooms'));
852
853 parent::display();
854
855 if (VikBooking::showFooter()) {
856 VikBookingHelper::printFooter();
857 }
858 }
859
860 public function newroom() {
861 VikBookingHelper::printHeader("7");
862
863 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
864
865 parent::display();
866
867 if (VikBooking::showFooter()) {
868 VikBookingHelper::printFooter();
869 }
870 }
871
872 public function editroom() {
873 VikBookingHelper::printHeader("7");
874
875 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageroom'));
876
877 parent::display();
878
879 if (VikBooking::showFooter()) {
880 VikBookingHelper::printFooter();
881 }
882 }
883
884 public function createroom() {
885 if (!JSession::checkToken()) {
886 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
887 }
888 $this->do_createroom();
889 }
890
891 public function createroomstay() {
892 if (!JSession::checkToken()) {
893 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
894 }
895 $this->do_createroom(true);
896 }
897
898 private function do_createroom($stay = false) {
899 $app = JFactory::getApplication();
900 $pcname = VikRequest::getString('cname', '', 'request');
901 $pccat = VikRequest::getVar('ccat', array(0));
902 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
903 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
904 $pccarat = VikRequest::getVar('ccarat', array(0));
905 $pcoptional = VikRequest::getVar('coptional', array(0));
906 $pcavail = VikRequest::getString('cavail', '', 'request');
907 $pautoresize = VikRequest::getString('autoresize', '', 'request');
908 $presizeto = VikRequest::getString('resizeto', '', 'request');
909 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
910 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
911 $punits = VikRequest::getInt('units', '', 'request');
912 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
913 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
914 $ptoadult = VikRequest::getInt('toadult', '', 'request');
915 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
916 $ptochild = VikRequest::getInt('tochild', '', 'request');
917 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
918 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
919 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
920 $plastavail = VikRequest::getString('lastavail', '', 'request');
921 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
922 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
923 $pcustprice = VikRequest::getString('custprice', '', 'request');
924 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
925 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
926 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
927 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
928 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
929 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
930 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
931 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
932 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
933 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
934 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
935 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
936 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
937 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
938 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
939 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
940 $psefalias = VikRequest::getString('sefalias', '', 'request');
941 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
942 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
943 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
944 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
945 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
946 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
947 $pshare_with = VikRequest::getVar('share_with', array());
948 $scalnights_arr = array();
949 if (!empty($pseasoncal_nights)) {
950 $scalnights = explode(',', $pseasoncal_nights);
951 foreach ($scalnights as $scalnight) {
952 if (intval(trim($scalnight)) > 0) {
953 $scalnights_arr[] = intval(trim($scalnight));
954 }
955 }
956 }
957 if (count($scalnights_arr) > 0) {
958 $pseasoncal_nights = implode(', ', $scalnights_arr);
959 } else {
960 $pseasoncal_nights = '';
961 $pseasoncal = 0;
962 }
963 $roomparams = array('lastavail' => $plastavail, 'suggocc' => $psuggocc, 'custprice' => $pcustprice, 'custpricetxt' => $pcustpricetxt, 'custpricesubtxt' => $pcustpricesubtxt, 'reqinfo' => $preqinfo, 'pricecal' => $ppricecal, 'defcalcost' => floatval($pdefcalcost), 'maxminpeople' => $pmaxminpeople, 'seasoncal' => $pseasoncal, 'seasoncal_nights' => $pseasoncal_nights, 'seasoncal_prices' => $pseasoncal_prices, 'seasoncal_restr' => $pseasoncal_restr, 'multi_units' => $pmulti_units, 'custptitle' => $pcustptitle, 'custptitlew' => $pcustptitlew, 'metakeywords' => $pmetakeywords, 'metadescription' => $pmetadescription);
964 //distinctive features
965 $roomparams['features'] = array();
966 if ($punits > 0) {
967 for ($i=1; $i <= $punits; $i++) {
968 $distf_name = VikRequest::getVar('feature-name'.$i, array());
969 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
970 $distf_value = VikRequest::getVar('feature-value'.$i, array());
971 foreach ($distf_name as $distf_k => $distf) {
972 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
973 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
974 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
975 }
976 }
977 }
978 }
979
980 /**
981 * Store room geo params information.
982 *
983 * @since 1.14 (J) - 1.4.0 (WP)
984 */
985 $geo = VikBooking::getGeocodingInstance();
986 $geo_params = $geo->getRoomGeoTransient(0);
987 if ($geo_params !== false) {
988 // make sure the geocoding service was not turned off
989 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
990 if (!$geo_enabled) {
991 $geo_params->enabled = 0;
992 }
993 //
994 $roomparams['geo'] = $geo_params;
995 }
996 //
997
998 $roomparamstr = json_encode($roomparams);
999
1000 if (empty($pcname)) {
1001 $app->enqueueMessage(JText::translate('VBO_PLEASE_FILL_FIELDS'), 'error');
1002 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1003 $app->close();
1004 }
1005
1006 jimport('joomla.filesystem.file');
1007 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1008
1009 if (intval($_FILES['cimg']['error']) == 0 && VikBooking::caniWrite($updpath) && trim($_FILES['cimg']['name'])!="") {
1010 if (@is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1011 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['cimg']['name'])));
1012 if (file_exists($updpath.$safename)) {
1013 $j = 1;
1014 while (file_exists($updpath.$j.$safename)) {
1015 $j++;
1016 }
1017 $pwhere = $updpath.$j.$safename;
1018 } else {
1019 $j = "";
1020 $pwhere = $updpath.$safename;
1021 }
1022 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1023 @unlink($pwhere);
1024 $picon = "";
1025 } else {
1026 VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere);
1027 @chmod($pwhere, 0644);
1028 $picon = $j.$safename;
1029 if ($pautoresize=="1" && !empty($presizeto)) {
1030 $eforj = new vikResizer();
1031 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
1032 if ($origmod) {
1033 @unlink($pwhere);
1034 $picon = 'r_'.$j.$safename;
1035 }
1036 }
1037 }
1038 } else {
1039 $picon = "";
1040 }
1041 } else {
1042 $picon = "";
1043 }
1044 //more images
1045 $creativik = new vikResizer();
1046 $bigsdest = $updpath;
1047 $thumbsdest = $updpath;
1048 $dest = $updpath;
1049 $moreimagestr = "";
1050 $arrimgs = array();
1051 $captiontexts = array();
1052 $imgcaptions = array();
1053 foreach ($pimages['name'] as $kk=>$ci) {
1054 if (!empty($ci)) {
1055 $arrimgs[] = $kk;
1056 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1057 }
1058 }
1059 foreach ($arrimgs as $ki => $imgk) {
1060 if (strlen(trim($pimages['name'][$imgk]))) {
1061 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1062 $src = $pimages['tmp_name'][$imgk];
1063 $j = "";
1064 if (file_exists($dest.$filename)) {
1065 $j = rand(171, 1717);
1066 while (file_exists($dest.$j.$filename)) {
1067 $j++;
1068 }
1069 }
1070 $finaldest = $dest.$j.$filename;
1071 $check = getimagesize($pimages['tmp_name'][$imgk]);
1072 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1073 if (VikBooking::uploadFile($src, $finaldest)) {
1074 $gimg = $j.$filename;
1075 //orig img
1076 $origmod = true;
1077 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1078 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1079 } else {
1080 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1081 }
1082 //thumb
1083 $thumbsize = VikBooking::getThumbSize();
1084 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1085 if (!$thumb || !$origmod) {
1086 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1087 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1088 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1089 } else {
1090 $moreimagestr .= $j.$filename.";;";
1091 $imgcaptions[] = $captiontexts[$ki];
1092 }
1093 @unlink($finaldest);
1094 } else {
1095 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1096 }
1097 } else {
1098 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1099 }
1100 }
1101 }
1102 //end more images
1103 if (is_array($pccat) && count($pccat)) {
1104 $pccatdef="";
1105 foreach ($pccat as $ccat) {
1106 if (!empty($ccat)) {
1107 $pccatdef.=$ccat.";";
1108 }
1109 }
1110 } else {
1111 $pccatdef="";
1112 }
1113 if (is_array($pccarat) && count($pccarat)) {
1114 $pccaratdef="";
1115 foreach ($pccarat as $ccarat) {
1116 $pccaratdef.=$ccarat.";";
1117 }
1118 } else {
1119 $pccaratdef="";
1120 }
1121 if (is_array($pcoptional) && count($pcoptional)) {
1122 $pcoptionaldef="";
1123 foreach ($pcoptional as $coptional) {
1124 $pcoptionaldef.=$coptional.";";
1125 }
1126 } else {
1127 $pcoptionaldef="";
1128 }
1129 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1130 if ($pfromadult > $ptoadult) {
1131 $pfromadult = 1;
1132 $ptoadult = 1;
1133 }
1134 if ($pfromchild > $ptochild) {
1135 $pfromchild = 1;
1136 $ptochild = 1;
1137 }
1138 $dbo = JFactory::getDbo();
1139 $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).");";
1140 $dbo->setQuery($q);
1141 $dbo->execute();
1142 $lid = $dbo->insertid();
1143 if (empty($lid)) {
1144 $app->enqueueMessage('Could not store the record on the database', 'error');
1145 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1146 $app->close();
1147 }
1148
1149 /**
1150 * Share availability calendars with other rooms.
1151 *
1152 * @since 1.13
1153 */
1154 // always reset relations for this main room
1155 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$lid};";
1156 $dbo->setQuery($q);
1157 $dbo->execute();
1158 $newxref = array();
1159 foreach ($pshare_with as $cldroom) {
1160 if (!empty($cldroom)) {
1161 array_push($newxref, (int)$cldroom);
1162 }
1163 }
1164 foreach ($newxref as $cldroom) {
1165 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$lid}, {$cldroom});";
1166 $dbo->setQuery($q);
1167 $dbo->execute();
1168 }
1169
1170 /**
1171 * Room upgrade options.
1172 *
1173 * @since 1.16.0 (J) - 1.6.0 (WP)
1174 */
1175 $config = VBOFactory::getConfig();
1176 $room_upgrade_options = [];
1177 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1178 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1179 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1180 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1181 $upgrade_rooms = array_map(function($rid) {
1182 return (int)$rid;
1183 }, $upgrade_rooms);
1184
1185 $room_upgrade_options = [
1186 'rooms' => $upgrade_rooms,
1187 'discount' => $upgrade_discount,
1188 ];
1189 }
1190 $config->set('room_upgrade_options_' . $lid, json_encode($room_upgrade_options));
1191
1192 if ($stay === true) {
1193 $app->enqueueMessage(JText::translate('VBOROOMSAVEOK').' - <a href="index.php?option=com_vikbooking&task=tariffs&cid[]='.$lid.'">'.JText::translate('VBOGOTORATES').'</a>');
1194 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$lid);
1195 $app->close();
1196 }
1197
1198 $app->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$lid);
1199 $app->close();
1200 }
1201
1202 public function updateroom() {
1203 if (!JSession::checkToken()) {
1204 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1205 }
1206 $this->do_updateroom();
1207 }
1208
1209 public function updateroomstay() {
1210 if (!JSession::checkToken()) {
1211 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1212 }
1213 $this->do_updateroom(true);
1214 }
1215
1216 private function do_updateroom($stay = false)
1217 {
1218 $app = JFactory::getApplication();
1219 $config = VBOFactory::getConfig();
1220
1221 $pcname = VikRequest::getString('cname', '', 'request');
1222 $pccat = VikRequest::getVar('ccat', array(0));
1223 $pcdescr = VikRequest::getString('cdescr', '', 'request', VIKREQUEST_ALLOWRAW);
1224 $psmalldesc = VikRequest::getString('smalldesc', '', 'request', VIKREQUEST_ALLOWRAW);
1225 $pccarat = VikRequest::getVar('ccarat', array(0));
1226 $pcoptional = VikRequest::getVar('coptional', array(0));
1227 $pcavail = VikRequest::getString('cavail', '', 'request');
1228 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
1229 $pautoresize = VikRequest::getString('autoresize', '', 'request');
1230 $presizeto = VikRequest::getString('resizeto', '', 'request');
1231 $pautoresizemore = VikRequest::getString('autoresizemore', '', 'request');
1232 $presizetomore = VikRequest::getString('resizetomore', '', 'request');
1233 $punits = VikRequest::getInt('units', '', 'request');
1234 $pimages = VikRequest::getVar('cimgmore', null, 'files', 'array');
1235 $pactmoreimgs = VikRequest::getString('actmoreimgs', '', 'request');
1236 $pfromadult = VikRequest::getInt('fromadult', '', 'request');
1237 $ptoadult = VikRequest::getInt('toadult', '', 'request');
1238 $pfromchild = VikRequest::getInt('fromchild', '', 'request');
1239 $ptochild = VikRequest::getInt('tochild', '', 'request');
1240 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array(0));
1241 $padultsdiffval = VikRequest::getVar('adultsdiffval', array(0));
1242 $padultsdiffnum = VikRequest::getVar('adultsdiffnum', array(0));
1243 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array(0));
1244 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array(0));
1245 $ptotpeople = VikRequest::getInt('totpeople', '', 'request');
1246 $pmintotpeople = VikRequest::getInt('mintotpeople', '', 'request');
1247 $pmintotpeople = $pmintotpeople < 1 ? 1 : $pmintotpeople;
1248 $plastavail = VikRequest::getString('lastavail', '', 'request');
1249 $plastavail = empty($plastavail) ? 0 : intval($plastavail);
1250 $psuggocc = VikRequest::getInt('suggocc', 1, 'request');
1251 $pcustprice = VikRequest::getString('custprice', '', 'request');
1252 $pcustprice = empty($pcustprice) ? '' : floatval($pcustprice);
1253 $pcustpricetxt = VikRequest::getString('custpricetxt', '', 'request', VIKREQUEST_ALLOWRAW);
1254 $pcustpricesubtxt = VikRequest::getString('custpricesubtxt', '', 'request', VIKREQUEST_ALLOWRAW);
1255 $preqinfo = VikRequest::getInt('reqinfo', '', 'request');
1256 $ppricecal = VikRequest::getInt('pricecal', '', 'request');
1257 $pdefcalcost = VikRequest::getString('defcalcost', '', 'request');
1258 $pdefrplan = VikRequest::getInt('defrplan', 0, 'request');
1259 $pmaxminpeople = VikRequest::getString('maxminpeople', '', 'request');
1260 $pcimgcaption = VikRequest::getVar('cimgcaption', array());
1261 $pimgsorting = VikRequest::getVar('imgsorting', array());
1262 $pupdatecaption = VikRequest::getInt('updatecaption', '', 'request');
1263 $pmaxminpeople = in_array($pmaxminpeople, array('0', '1', '2', '3', '4', '5')) ? $pmaxminpeople : '0';
1264 $pseasoncal = VikRequest::getInt('seasoncal', 0, 'request');
1265 $pseasoncal = $pseasoncal >= 0 || $pseasoncal <= 3 ? $pseasoncal : 0;
1266 $pseasoncal_nights = VikRequest::getString('seasoncal_nights', '', 'request');
1267 $pseasoncal_prices = VikRequest::getString('seasoncal_prices', '', 'request');
1268 $pseasoncal_restr = VikRequest::getString('seasoncal_restr', '', 'request');
1269 $pmulti_units = VikRequest::getInt('multi_units', '', 'request');
1270 $pmulti_units = $punits > 1 ? $pmulti_units : 0;
1271 $psefalias = VikRequest::getString('sefalias', '', 'request');
1272 $psefalias = empty($psefalias) ? JFilterOutput::stringURLSafe($pcname) : JFilterOutput::stringURLSafe($psefalias);
1273 $pcustptitle = VikRequest::getString('custptitle', '', 'request');
1274 $pcustptitlew = VikRequest::getString('custptitlew', '', 'request');
1275 $pcustptitlew = in_array($pcustptitlew, array('before', 'after', 'replace')) ? $pcustptitlew : 'before';
1276 $pmetakeywords = VikRequest::getString('metakeywords', '', 'request');
1277 $pmetadescription = VikRequest::getString('metadescription', '', 'request');
1278 $pshare_with = VikRequest::getVar('share_with', array());
1279 $scalnights_arr = array();
1280 if (!empty($pseasoncal_nights)) {
1281 $scalnights = explode(',', $pseasoncal_nights);
1282 foreach ($scalnights as $scalnight) {
1283 if (intval(trim($scalnight)) > 0) {
1284 $scalnights_arr[] = intval(trim($scalnight));
1285 }
1286 }
1287 }
1288 if (count($scalnights_arr) > 0) {
1289 $pseasoncal_nights = implode(', ', $scalnights_arr);
1290 } else {
1291 $pseasoncal_nights = '';
1292 $pseasoncal = 0;
1293 }
1294 $roomparams = [
1295 'lastavail' => $plastavail,
1296 'suggocc' => $psuggocc,
1297 'custprice' => $pcustprice,
1298 'custpricetxt' => $pcustpricetxt,
1299 'custpricesubtxt' => $pcustpricesubtxt,
1300 'reqinfo' => $preqinfo,
1301 'pricecal' => $ppricecal,
1302 'defcalcost' => floatval($pdefcalcost),
1303 'defrplan' => $pdefrplan,
1304 'maxminpeople' => $pmaxminpeople,
1305 'seasoncal' => $pseasoncal,
1306 'seasoncal_nights' => $pseasoncal_nights,
1307 'seasoncal_prices' => $pseasoncal_prices,
1308 'seasoncal_restr' => $pseasoncal_restr,
1309 'multi_units' => $pmulti_units,
1310 'custptitle' => $pcustptitle,
1311 'custptitlew' => $pcustptitlew,
1312 'metakeywords' => $pmetakeywords,
1313 'metadescription' => $pmetadescription,
1314 ];
1315 //distinctive features
1316 $roomparams['features'] = array();
1317 $newfeatures = array();
1318 if ($punits > 0) {
1319 for ($i=1; $i <= $punits; $i++) {
1320 $distf_name = VikRequest::getVar('feature-name'.$i, array());
1321 $distf_lang = VikRequest::getVar('feature-lang'.$i, array());
1322 $distf_value = VikRequest::getVar('feature-value'.$i, array());
1323 foreach ($distf_name as $distf_k => $distf) {
1324 if (strlen($distf) > 0 && strlen($distf_value[$distf_k]) > 0) {
1325 $use_key = strlen($distf_lang[$distf_k]) > 0 ? $distf_lang[$distf_k] : $distf;
1326 $roomparams['features'][$i][$use_key] = $distf_value[$distf_k];
1327 if ($distf_k < 1) {
1328 //check only the first feature
1329 $newfeatures[$i][$use_key] = $distf_value[$distf_k];
1330 }
1331 }
1332 }
1333 }
1334 }
1335
1336 /**
1337 * Store room geo params information.
1338 *
1339 * @since 1.14 (J) - 1.4.0 (WP)
1340 */
1341 $geo = VikBooking::getGeocodingInstance();
1342 $geo_params = $geo->getRoomGeoTransient($pwhereup);
1343 if ($geo_params !== false) {
1344 // make sure the geocoding service was not turned off
1345 $geo_enabled = VikRequest::getInt('geo_enabled', 0, 'request');
1346 if (!$geo_enabled) {
1347 $geo_params->enabled = 0;
1348 }
1349 //
1350 $roomparams['geo'] = $geo_params;
1351 }
1352 //
1353
1354 $roomparamstr = json_encode($roomparams);
1355
1356 jimport('joomla.filesystem.file');
1357 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
1358 if (!empty($pcname)) {
1359 if (intval($_FILES['cimg']['error']) == 0 && VikBooking::caniWrite($updpath) && trim($_FILES['cimg']['name'])!="") {
1360 if (@is_uploaded_file($_FILES['cimg']['tmp_name'])) {
1361 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['cimg']['name'])));
1362 if (file_exists($updpath.$safename)) {
1363 $j = 1;
1364 while (file_exists($updpath.$j.$safename)) {
1365 $j++;
1366 }
1367 $pwhere = $updpath.$j.$safename;
1368 } else {
1369 $j = "";
1370 $pwhere = $updpath.$safename;
1371 }
1372 if (!getimagesize($_FILES['cimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
1373 @unlink($pwhere);
1374 $picon = "";
1375 } else {
1376 VikBooking::uploadFile($_FILES['cimg']['tmp_name'], $pwhere);
1377 @chmod($pwhere, 0644);
1378 $picon = $j.$safename;
1379 if ($pautoresize == "1" && !empty($presizeto)) {
1380 $eforj = new vikResizer();
1381 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
1382 if ($origmod) {
1383 @unlink($pwhere);
1384 $picon = 'r_'.$j.$safename;
1385 }
1386 }
1387 }
1388 } else {
1389 $picon = "";
1390 }
1391 } else {
1392 $picon = "";
1393 }
1394 //more images
1395 $creativik = new vikResizer();
1396 $bigsdest = $updpath;
1397 $thumbsdest = $updpath;
1398 $dest = $updpath;
1399 $moreimagestr = $pactmoreimgs;
1400 $arrimgs = array();
1401 $captiontexts = array();
1402 $imgcaptions = array();
1403 //captions of uploaded extra images
1404 if (!empty($pactmoreimgs)) {
1405 $sploimgs = explode(';;', $pactmoreimgs);
1406 foreach ($sploimgs as $ki => $oimg) {
1407 if (!empty($oimg)) {
1408 $oldcaption = VikRequest::getString('caption'.$ki, '', 'request', VIKREQUEST_ALLOWHTML);
1409 $imgcaptions[] = $oldcaption;
1410 }
1411 }
1412 }
1413 //
1414 foreach ($pimages['name'] as $kk=>$ci) {
1415 if (!empty($ci)) {
1416 $arrimgs[] = $kk;
1417 $captiontexts[] = isset($pcimgcaption[$kk]) ? $pcimgcaption[$kk] : '';
1418 }
1419 }
1420 foreach ($arrimgs as $ki => $imgk) {
1421 if (strlen(trim($pimages['name'][$imgk]))) {
1422 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pimages['name'][$imgk])));
1423 $src = $pimages['tmp_name'][$imgk];
1424 $j = "";
1425 if (file_exists($dest.$filename)) {
1426 $j = rand(171, 1717);
1427 while (file_exists($dest.$j.$filename)) {
1428 $j++;
1429 }
1430 }
1431 $finaldest = $dest.$j.$filename;
1432 $check = getimagesize($pimages['tmp_name'][$imgk]);
1433 if (($check[2] & imagetypes()) && preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $filename)) {
1434 if (VikBooking::uploadFile($src, $finaldest)) {
1435 $gimg = $j.$filename;
1436 //orig img
1437 $origmod = true;
1438 if ($pautoresizemore == "1" && !empty($presizetomore)) {
1439 $origmod = $creativik->proportionalImage($finaldest, $bigsdest.'big_'.$j.$filename, $presizetomore, $presizetomore);
1440 } else {
1441 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
1442 }
1443 //thumb
1444 $thumbsize = VikBooking::getThumbSize();
1445 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
1446 if (!$thumb || !$origmod) {
1447 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
1448 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
1449 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1450 } else {
1451 $moreimagestr .= $j.$filename.";;";
1452 $imgcaptions[] = $captiontexts[$ki];
1453 }
1454 @unlink($finaldest);
1455 } else {
1456 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1457 }
1458 } else {
1459 VikError::raiseWarning('', 'Error While Uploading the File: '.$pimages['name'][$imgk]);
1460 }
1461 }
1462 }
1463 //sorting of extra images
1464 $sorted_extraim = array();
1465 $sorted_captions = array();
1466 $extraim_parts = explode(';;', $moreimagestr);
1467 foreach ($pimgsorting as $k => $v) {
1468 $capkey = -1;
1469 if (isset($extraim_parts[$k])) {
1470 $sorted_extraim[] = $v;
1471 foreach ($extraim_parts as $oldk => $oldv) {
1472 if ($oldv == $v) {
1473 $capkey = $oldk;
1474 break;
1475 }
1476 }
1477 }
1478 if (isset($imgcaptions[$capkey])) {
1479 $sorted_captions[] = $imgcaptions[$capkey];
1480 }
1481 }
1482 $tot_sorted_im = count($sorted_extraim);
1483 if ($tot_sorted_im != count($extraim_parts)) {
1484 foreach ($extraim_parts as $k => $v) {
1485 if ($k <= ($tot_sorted_im - 1)) {
1486 continue;
1487 }
1488 $sorted_extraim[] = $v;
1489 if (isset($imgcaptions[$k])) {
1490 $sorted_captions[] = $imgcaptions[$k];
1491 }
1492 }
1493 }
1494 $moreimagestr = implode(';;', $sorted_extraim);
1495 $imgcaptions = $sorted_captions;
1496 //end more images
1497 if (is_array($pccat) && count($pccat)) {
1498 $pccatdef = "";
1499 foreach ($pccat as $ccat) {
1500 if (!empty($ccat)) {
1501 $pccatdef .= $ccat.";";
1502 }
1503 }
1504 } else {
1505 $pccatdef = "";
1506 }
1507 if (is_array($pccarat) && count($pccarat)) {
1508 $pccaratdef = "";
1509 foreach ($pccarat as $ccarat) {
1510 $pccaratdef .= $ccarat.";";
1511 }
1512 } else {
1513 $pccaratdef = "";
1514 }
1515 if (is_array($pcoptional) && count($pcoptional)) {
1516 $pcoptionaldef = "";
1517 foreach ($pcoptional as $coptional) {
1518 $pcoptionaldef .= $coptional.";";
1519 }
1520 } else {
1521 $pcoptionaldef = "";
1522 }
1523 $pcavaildef=($pcavail=="yes" ? "1" : "0");
1524 if ($pfromadult > $ptoadult) {
1525 $pfromadult = 1;
1526 $ptoadult = 1;
1527 }
1528 if ($pfromchild > $ptochild) {
1529 $pfromchild = 1;
1530 $ptochild = 1;
1531 }
1532 $dbo = JFactory::getDBO();
1533 //adults charges/discounts
1534 $adchdisctouch = false;
1535 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`='".$pwhereup."';";
1536 $dbo->setQuery($q);
1537 $dbo->execute();
1538 $oldroom = $dbo->loadAssocList();
1539 $oldroom = $oldroom[0];
1540 if ($oldroom['fromadult'] == $pfromadult && $oldroom['toadult'] == $ptoadult) {
1541 if ($oldroom['toadult'] > 1 && $oldroom['fromadult'] < $oldroom['toadult'] && @count($padultsdiffnum) > 0) {
1542 $startadind = $oldroom['fromadult'] > 0 ? $oldroom['fromadult'] : 1;
1543 for($adi = $startadind; $adi <= $oldroom['toadult']; $adi++) {
1544 foreach ($padultsdiffnum as $kad=>$vad) {
1545 if (intval($vad) == intval($adi) && strlen($padultsdiffval[$kad]) > 0) {
1546 $adchdisctouch = true;
1547 $inschdisc = intval($padultsdiffchdisc[$kad]) == 1 ? 1 : 2;
1548 $insvalpcent = intval($padultsdiffvalpcent[$kad]) == 1 ? 1 : 2;
1549 $inspernight = intval($padultsdiffpernight[$kad]) == 1 ? 1 : 0;
1550 $insvalue = floatval($padultsdiffval[$kad]);
1551 //check if it exists
1552 $q = "SELECT `id` FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1553 $dbo->setQuery($q);
1554 $dbo->execute();
1555 if ($dbo->getNumRows() > 0) {
1556 if ($insvalue > 0) {
1557 //update
1558 $q = "UPDATE `#__vikbooking_adultsdiff` SET `chdisc`='".$inschdisc."', `valpcent`='".$insvalpcent."', `value`='".$insvalue."', `pernight`='".$inspernight."' WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1559 $dbo->setQuery($q);
1560 $dbo->execute();
1561 } else {
1562 //delete
1563 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."' AND `adults`='".$adi."';";
1564 $dbo->setQuery($q);
1565 $dbo->execute();
1566 }
1567 } else {
1568 //insert
1569 $q = "INSERT INTO `#__vikbooking_adultsdiff` (`idroom`,`chdisc`,`valpcent`,`value`,`adults`,`pernight`) VALUES('".$oldroom['id']."', '".$inschdisc."', '".$insvalpcent."', '".$insvalue."', '".$adi."', '".$inspernight."');";
1570 $dbo->setQuery($q);
1571 $dbo->execute();
1572 }
1573 }
1574 }
1575 }
1576 }
1577 } else {
1578 //min and max adults num have changed, delete
1579 $q = "DELETE FROM `#__vikbooking_adultsdiff` WHERE `idroom`='".$oldroom['id']."';";
1580 $dbo->setQuery($q);
1581 $dbo->execute();
1582 }
1583 if ($adchdisctouch == true) {
1584 $app->enqueueMessage(JText::translate('VBUPDROOMADCHDISCSAVED'));
1585 }
1586 //
1587 //check distinctive features if there were any changes
1588 $old_rparams = json_decode($oldroom['params'], true);
1589 $old_rparams = is_array($old_rparams) ? $old_rparams : array();
1590 if (array_key_exists('features', $old_rparams)) {
1591 $oldfeatures = array();
1592 foreach ($old_rparams['features'] as $rnumunit => $oldfeat) {
1593 foreach ($oldfeat as $featname => $featval) {
1594 $oldfeatures[$rnumunit][$featname] = $featval;
1595 break;
1596 }
1597 }
1598 /**
1599 * We reset the sub-unit information to all bookings only in case the new
1600 * number of units is reduced. When we add new units or we modify the contents,
1601 * we keep everything as is for the past reservations.
1602 *
1603 * @since 1.15.2 (J) - 1.5.5 (WP)
1604 */
1605 if ($oldfeatures != $newfeatures && count($newfeatures) < count($oldfeatures)) {
1606 // changes were made to the first index (Room Number by default) of the distinctive features
1607 // set to NULL all the already set roomindexes in bookings
1608 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=NULL WHERE `idroom`=".(int)$oldroom['id'].";";
1609 $dbo->setQuery($q);
1610 $dbo->execute();
1611 }
1612 }
1613 //
1614 $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).";";
1615 $dbo->setQuery($q);
1616 $dbo->execute();
1617
1618 /**
1619 * Share availability calendars with other rooms.
1620 *
1621 * @since 1.13
1622 */
1623 // always reset relations for this main room
1624 $q = "DELETE FROM `#__vikbooking_calendars_xref` WHERE `mainroom`={$pwhereup};";
1625 $dbo->setQuery($q);
1626 $dbo->execute();
1627 $newxref = array();
1628 foreach ($pshare_with as $cldroom) {
1629 if (!empty($cldroom)) {
1630 array_push($newxref, (int)$cldroom);
1631 }
1632 }
1633 foreach ($newxref as $cldroom) {
1634 $q = "INSERT INTO `#__vikbooking_calendars_xref` (`mainroom`, `childroom`) VALUES ({$pwhereup}, {$cldroom});";
1635 $dbo->setQuery($q);
1636 $dbo->execute();
1637 }
1638
1639 /**
1640 * Room upgrade options.
1641 *
1642 * @since 1.16.0 (J) - 1.6.0 (WP)
1643 */
1644 $room_upgrade_options = [];
1645 $room_upgrade = VikRequest::getInt('room_upgrade', 0, 'request');
1646 $upgrade_rooms = VikRequest::getVar('upgrade_rooms', array());
1647 $upgrade_discount = VikRequest::getFloat('upgrade_discount', 0, 'request');
1648 if ($room_upgrade && is_array($upgrade_rooms) && count($upgrade_rooms)) {
1649 $upgrade_rooms = array_map(function($rid) {
1650 return (int)$rid;
1651 }, $upgrade_rooms);
1652
1653 $room_upgrade_options = [
1654 'rooms' => $upgrade_rooms,
1655 'discount' => $upgrade_discount,
1656 ];
1657 }
1658 $config->set('room_upgrade_options_' . $pwhereup, json_encode($room_upgrade_options));
1659
1660 /**
1661 * Maximum advance booking offset can be defined at room-level. TODO
1662 *
1663 * @since 1.16.3 (J) - 1.6.3 (WP)
1664 */
1665 $pmax_adv_notice_room = VikRequest::getInt('max_adv_notice_room', 0, 'request');
1666 $pmaxdate = VikRequest::getInt('maxdate', 0, 'request');
1667 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
1668 $maxdate_str = '';
1669 if ($pmax_adv_notice_room && $pmaxdate > 0) {
1670 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
1671 $maxdate_str = '+' . $pmaxdate . $pmaxdateinterval;
1672 }
1673 $config->set("room_{$pwhereup}_max_adv_notice", $maxdate_str);
1674
1675 $app->enqueueMessage(JText::translate('VBUPDROOMOK'));
1676 }
1677
1678 if ($pupdatecaption == 1 || $stay === true) {
1679 $app->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$pwhereup);
1680 } else {
1681 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1682 }
1683 }
1684
1685 public function modavail() {
1686 if (!JSession::checkToken() && !JSession::checkToken('get')) {
1687 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1688 }
1689 $cid = VikRequest::getVar('cid', array(0));
1690 $room = $cid[0];
1691 if (!empty($room)) {
1692 $dbo = JFactory::getDBO();
1693 $q = "SELECT `avail` FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($room).";";
1694 $dbo->setQuery($q);
1695 $dbo->execute();
1696 $get = $dbo->loadAssocList();
1697 $q = "UPDATE `#__vikbooking_rooms` SET `avail`='".(intval($get[0]['avail'])==1 ? 0 : 1)."' WHERE `id`=".$dbo->quote($room).";";
1698 $dbo->setQuery($q);
1699 $dbo->execute();
1700 }
1701 $mainframe = JFactory::getApplication();
1702 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1703 }
1704
1705 public function removeroom() {
1706 if (!JSession::checkToken()) {
1707 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
1708 }
1709 $ids = VikRequest::getVar('cid', array(0));
1710 if (@count($ids)) {
1711 $dbo = JFactory::getDBO();
1712 foreach ($ids as $d) {
1713 $q = "DELETE FROM `#__vikbooking_rooms` WHERE `id`=".$dbo->quote($d).";";
1714 $dbo->setQuery($q);
1715 $dbo->execute();
1716 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idroom`=".$dbo->quote($d).";";
1717 $dbo->setQuery($q);
1718 $dbo->execute();
1719 }
1720 }
1721 $mainframe = JFactory::getApplication();
1722 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
1723 }
1724
1725 public function tariffs() {
1726 VikBookingHelper::printHeader("fares");
1727
1728 VikRequest::setVar('view', VikRequest::getCmd('view', 'tariffs'));
1729
1730 parent::display();
1731
1732 if (VikBooking::showFooter()) {
1733 VikBookingHelper::printFooter();
1734 }
1735 }
1736
1737 public function removetariffs() {
1738 $ids = VikRequest::getVar('cid', array(0));
1739 $proomid = VikRequest::getInt('roomid', '', 'request');
1740 if (@count($ids)) {
1741 $dbo = JFactory::getDBO();
1742 foreach ($ids as $r) {
1743 $x=explode(";", $r);
1744 foreach ($x as $rm) {
1745 if (!empty($rm)) {
1746 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `id`=".$dbo->quote($rm).";";
1747 $dbo->setQuery($q);
1748 $dbo->execute();
1749 }
1750 }
1751 }
1752 }
1753 $mainframe = JFactory::getApplication();
1754 $mainframe->redirect("index.php?option=com_vikbooking&task=tariffs&cid[]=".$proomid);
1755 }
1756
1757 public function editbusy() {
1758 VikBookingHelper::printHeader("8");
1759
1760 VikRequest::setVar('view', VikRequest::getCmd('view', 'editbusy'));
1761
1762 parent::display();
1763
1764 if (VikBooking::showFooter()) {
1765 VikBookingHelper::printFooter();
1766 }
1767 }
1768
1769 public function updatebusy()
1770 {
1771 $this->do_updatebusy();
1772 }
1773
1774 public function updatebusydoinv()
1775 {
1776 $this->do_updatebusy('geninvoices');
1777 }
1778
1779 private function do_updatebusy($callback = '')
1780 {
1781 $pidorder = VikRequest::getInt('idorder', 0, 'request');
1782 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
1783 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
1784 $pcheckinh = VikRequest::getString('checkinh', '', 'request');
1785 $pcheckinm = VikRequest::getString('checkinm', '', 'request');
1786 $pcheckouth = VikRequest::getString('checkouth', '', 'request');
1787 $pcheckoutm = VikRequest::getString('checkoutm', '', 'request');
1788 $pcustdata = VikRequest::getString('custdata', '', 'request');
1789 $pareprices = VikRequest::getString('areprices', '', 'request');
1790 $ptotpaid = VikRequest::getString('totpaid', '', 'request');
1791 $prefund = VikRequest::getString('refund', '', 'request');
1792 $pfrominv = VikRequest::getInt('frominv', '', 'request');
1793 $pvcm = VikRequest::getInt('vcm', '', 'request');
1794 $pgoto = VikRequest::getString('goto', '', 'request');
1795 $pextracn = VikRequest::getVar('extracn', []);
1796 $pextracc = VikRequest::getVar('extracc', []);
1797 $pextractx = VikRequest::getVar('extractx', []);
1798 /**
1799 * This is a "foreign key" integer value useful for other Vik plugins
1800 * to store custom extra services within a VBO reservation. Another
1801 * custom value "extra foreign data" (extracdata) is added. We also
1802 * support a "type" string useful for VCM to determine the type of service.
1803 *
1804 * @since 1.16.0 (J) - 1.6.0 (WP)
1805 * @since 1.16.1 (J) - 1.6.1 (WP) added the "type" string.
1806 */
1807 $pextractype = VikRequest::getVar('extractype', []);
1808 $pextracfk = VikRequest::getVar('extracfk', []);
1809 $pextracdata = VikRequest::getVar('extracdata', [], 'request', 'array', VIKREQUEST_ALLOWRAW);
1810
1811 $dbo = JFactory::getDbo();
1812 $user = JFactory::getUser();
1813 $app = JFactory::getApplication();
1814
1815 // availability helper
1816 $av_helper = VikBooking::getAvailabilityInstance();
1817
1818 $actnow = time();
1819 $nowdf = VikBooking::getDateFormat(true);
1820 if ($nowdf == "%d/%m/%Y") {
1821 $df = 'd/m/Y';
1822 } elseif ($nowdf == "%m/%d/%Y") {
1823 $df = 'm/d/Y';
1824 } else {
1825 $df = 'Y/m/d';
1826 }
1827
1828 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
1829 $dbo->setQuery($q, 0, 1);
1830 $dbo->execute();
1831 if (!$dbo->getNumRows()) {
1832 $app->redirect("index.php?option=com_vikbooking&task=rooms");
1833 exit;
1834 }
1835
1836 $ord = $dbo->loadAssoc();
1837
1838 $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;";
1839 $dbo->setQuery($q);
1840 $dbo->execute();
1841 $ordersrooms = $dbo->loadAssocList();
1842
1843 // do not touch this array property because it's used by VCM
1844 $ord['rooms_info'] = $ordersrooms;
1845
1846 // room stay dates in case of split stay
1847 $room_stay_dates = [];
1848 if ($ord['split_stay']) {
1849 if ($ord['status'] == 'confirmed') {
1850 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
1851 } else {
1852 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
1853 }
1854 // immediately count the number of nights of stay for each split room
1855 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
1856 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
1857 // overwrite values for compatibility with non-confirmed bookings
1858 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
1859 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
1860 }
1861 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
1862 // overwrite the whole array
1863 $room_stay_dates[$sps_r_k] = $sps_r_v;
1864 }
1865 }
1866
1867 // package or custom rate
1868 $is_package = !empty($ord['pkg']) ? true : false;
1869 $is_cust_cost = false;
1870 foreach ($ordersrooms as $kor => $or) {
1871 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
1872 $is_cust_cost = true;
1873 break;
1874 }
1875 }
1876
1877 // room switching
1878 $toswitch = array();
1879 $idbooked = array();
1880 $rooms_units = array();
1881
1882 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
1883 $dbo->setQuery($q);
1884 $dbo->execute();
1885 $all_rooms = $dbo->loadAssocList();
1886 foreach ($all_rooms as $rr) {
1887 $rooms_units[$rr['id']]['name'] = $rr['name'];
1888 $rooms_units[$rr['id']]['units'] = $rr['units'];
1889 }
1890
1891 foreach ($ordersrooms as $ind => $or) {
1892 $switch_command = VikRequest::getString('switch_'.$or['id'], '', 'request');
1893 if (!empty($switch_command) && intval($switch_command) != $or['idroom'] && array_key_exists(intval($switch_command), $rooms_units)) {
1894 if (!isset($idbooked[$or['idroom']])) {
1895 $idbooked[$or['idroom']] = 0;
1896 }
1897 $idbooked[$or['idroom']]++;
1898 $orkey = count($toswitch);
1899 $toswitch[$orkey]['from'] = $or['idroom'];
1900 $toswitch[$orkey]['to'] = intval($switch_command);
1901 $toswitch[$orkey]['record'] = $or;
1902 $toswitch[$orkey]['record_ind'] = $ind;
1903 }
1904 }
1905
1906 if (count($toswitch) && (!empty($ordersrooms[0]['idtar']) || $is_package || $is_cust_cost)) {
1907 foreach ($toswitch as $ksw => $rsw) {
1908 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
1909 $room_checkin = $ord['checkin'];
1910 $room_checkout = $ord['checkout'];
1911 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
1912 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
1913 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
1914 }
1915 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
1916 // the room is not available
1917 unset($toswitch[$ksw]);
1918 VikError::raiseWarning('', JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
1919 }
1920 }
1921 if (count($toswitch)) {
1922 // reset first record rate
1923 reset($ordersrooms);
1924 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
1925 $dbo->setQuery($q);
1926 $dbo->execute();
1927
1928 // flag for invoking VCM at a proper time
1929 $vcm_should_run = false;
1930
1931 foreach ($toswitch as $ksw => $rsw) {
1932 // update room reservation record
1933 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=".$rsw['to'].",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$rsw['record']['id'].";";
1934 $dbo->setQuery($q);
1935 $dbo->execute();
1936 $app->enqueueMessage(JText::sprintf('VBSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']));
1937
1938 // update Notes field for this booking to keep track of the previous room that was assigned
1939 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
1940 if (!empty($prev_room_name)) {
1941 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
1942 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
1943 $dbo->setQuery($q);
1944 $dbo->execute();
1945 }
1946
1947 if ($ord['status'] == 'confirmed') {
1948 // update room record in _busy
1949 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'])) {
1950 // in case of a split stay it is fundamental to update the exact busy record ID
1951 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
1952 $dbo->setQuery($q);
1953 $dbo->execute();
1954 } else {
1955 // regular processing of a room ID for a reservation, no matter which one, we switch it
1956 $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;";
1957 $dbo->setQuery($q);
1958 $dbo->execute();
1959 if ($dbo->getNumRows() == 1) {
1960 $cur_busy = $dbo->loadAssocList();
1961 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
1962 $dbo->setQuery($q);
1963 $dbo->execute();
1964 }
1965 }
1966
1967 /**
1968 * Make sure to take care of the shared calendars before invoking VCM.
1969 * Register the flag to run the Channel Manager and leave the booking
1970 * array unchanged to run just one update request.
1971 *
1972 * @since 1.16.0 (J) - 1.6.0 (WP)
1973 */
1974 $vcm_should_run = true;
1975
1976 } elseif ($ord['status'] == 'standby') {
1977 // remove record in _tmplock
1978 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
1979 $dbo->setQuery($q);
1980 $dbo->execute();
1981 // check if it's a split stay
1982 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
1983 // update room ID in split stay data
1984 $room_stay_dates[$rsw['record_ind']]['idroom'] = $rsw['to'];
1985 // update configuration record
1986 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($room_stay_dates));
1987 }
1988 }
1989 }
1990
1991 // unset any previously booked room due to calendar sharing
1992 VikBooking::cleanSharedCalendarsBusy($ord['id']);
1993 // check if some of the rooms booked have shared calendars
1994 VikBooking::updateSharedCalendars($ord['id']);
1995
1996 if ($vcm_should_run) {
1997 // we can now run the Channel Manager after having updated the shared calendars
1998 $vcm_autosync = VikBooking::vcmAutoUpdate();
1999 if ($vcm_autosync > 0) {
2000 $vcm_obj = VikBooking::getVcmInvoker();
2001 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2002 $sync_result = $vcm_obj->doSync();
2003 if ($sync_result === false) {
2004 $vcm_err = $vcm_obj->getError();
2005 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2006 }
2007 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2008 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>');
2009 }
2010 }
2011
2012 //Booking History
2013 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
2014 //
2015 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2016 exit;
2017 }
2018 }
2019
2020 // update booking data
2021 $first = VikBooking::getDateTimestamp($pcheckindate, $pcheckinh, $pcheckinm);
2022 $second = VikBooking::getDateTimestamp($pcheckoutdate, $pcheckouth, $pcheckoutm);
2023 if ($second <= $first) {
2024 VikError::raiseWarning('', JText::translate('ERRPREV'));
2025 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2026 exit;
2027 }
2028
2029 $secdiff = $second - $first;
2030 $daysdiff = $secdiff / 86400;
2031 if (is_int($daysdiff)) {
2032 if ($daysdiff < 1) {
2033 $daysdiff = 1;
2034 }
2035 } else {
2036 if ($daysdiff < 1) {
2037 $daysdiff = 1;
2038 } else {
2039 $sum = floor($daysdiff) * 86400;
2040 $newdiff = $secdiff - $sum;
2041 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
2042 if ($maxhmore >= $newdiff) {
2043 $daysdiff = floor($daysdiff);
2044 } else {
2045 $daysdiff = ceil($daysdiff);
2046 }
2047 }
2048 }
2049
2050 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
2051 $opertwounits = true;
2052
2053 $units_counter = array();
2054 $prm_room_oid = VikRequest::getInt('rm_room_oid', 0, 'request');
2055 foreach ($ordersrooms as $ind => $or) {
2056 if (!isset($units_counter[$or['idroom']])) {
2057 $units_counter[$or['idroom']] = -1;
2058 }
2059 if ($prm_room_oid != $or['id']) {
2060 $units_counter[$or['idroom']]++;
2061 }
2062 }
2063
2064 /**
2065 * Split stay data for booking and rooms different stay dates.
2066 *
2067 * @since 1.16.0 (J) - 1.6.0 (WP)
2068 */
2069 $split_stay_data = VikRequest::getVar('split_stay_data', array());
2070 $room_modify_dates = VikRequest::getVar('room_modify_dates', array());
2071 $split_stay_checkins = [];
2072 $split_stay_checkouts = [];
2073
2074 if ($ord['split_stay'] && !empty($split_stay_data)) {
2075 // make sure the min/max split stay dates match the booking global dates
2076 foreach ($split_stay_data as $sps_k => $split_stay) {
2077 if (empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2078 continue;
2079 }
2080 $new_room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2081 $new_room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2082 $split_stay_checkins[] = $new_room_checkin;
2083 $split_stay_checkouts[] = $new_room_checkout;
2084 if (isset($room_stay_dates[$sps_k])) {
2085 $room_stay_dates[$sps_k]['new_checkin'] = $new_room_checkin;
2086 $room_stay_dates[$sps_k]['new_checkout'] = $new_room_checkout;
2087 $room_stay_dates[$sps_k]['new_nights'] = $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout);
2088 }
2089 }
2090 if (empty($split_stay_checkins) || empty($split_stay_checkouts)) {
2091 // error
2092 VikError::raiseWarning('', 'Error, split stay rooms must have their own stay dates matching the booking check-in and check-out dates');
2093 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2094 exit;
2095 }
2096 if (min($split_stay_checkins) != $first) {
2097 // error
2098 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)));
2099 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2100 exit;
2101 }
2102 if (max($split_stay_checkouts) != $second) {
2103 // error
2104 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)));
2105 $app->redirect("index.php?option=com_vikbooking&task=editbusy".($pvcm == 1 ? '&vcm=1' : '').($pfrominv == 1 ? '&frominv=1' : '')."&cid[]=".$ord['id'].($pgoto == 'overv' ? "&goto=overv" : ""));
2106 exit;
2107 }
2108 }
2109
2110 /**
2111 * We need to make sure the sub-units of the rooms involved are not being overbooked.
2112 * In this case, we simply raise an error message by not stopping the process.
2113 *
2114 * @since 1.13.0 (J) - 1.3.0 (WP)
2115 */
2116 $subunits_involved_bids = array();
2117 //
2118
2119 foreach ($ordersrooms as $ind => $or) {
2120 $num = $ind + 1;
2121 $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'] . ";";
2122 $dbo->setQuery($check);
2123 $dbo->execute();
2124 if ($dbo->getNumRows() > 0) {
2125 $busy = $dbo->loadAssocList();
2126
2127 // determine the days to consider for the count of the availability
2128 $use_groupdays = $groupdays;
2129 $room_checkin = $first;
2130 $room_checkout = $second;
2131 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'])) {
2132 $use_groupdays = VikBooking::getGroupDays($room_stay_dates[$ind]['new_checkin'], $room_stay_dates[$ind]['new_checkout'], $room_stay_dates[$ind]['new_nights']);
2133 $room_checkin = $room_stay_dates[$ind]['new_checkin'];
2134 $room_checkout = $room_stay_dates[$ind]['new_checkout'];
2135 } elseif (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1 && $ord['status'] == 'confirmed' && VikRequest::getInt('room_modify_dates' . $ind, 0, 'request')) {
2136 // room may have individual stay dates
2137 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2138 // get new stay dates (if changed)
2139 $new_room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2140 $new_room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2141 $use_groupdays = VikBooking::getGroupDays($new_room_checkin, $new_room_checkout, $av_helper->countNightsOfStay($new_room_checkin, $new_room_checkout));
2142 $room_checkin = $new_room_checkin;
2143 $room_checkout = $new_room_checkout;
2144 }
2145 }
2146
2147 foreach ($use_groupdays as $gday) {
2148 // count units booked for each stay timestamp
2149 $bfound = 0;
2150 foreach ($busy as $bu) {
2151 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
2152 // increase units booked found
2153 $bfound++;
2154 // keep track of the IDs involved to avoid overbooking for the sub-units
2155 if (!empty($or['roomindex'])) {
2156 if (!isset($subunits_involved_bids[$bu['idorder']])) {
2157 $subunits_involved_bids[$bu['idorder']] = array();
2158 }
2159 array_push($subunits_involved_bids[$bu['idorder']], array(
2160 'idroom' => $or['idroom'],
2161 'roomindex' => $or['roomindex'],
2162 ));
2163 }
2164 }
2165 }
2166
2167 // units booked must be greater than zero in case of split stays involving the same room multiple times
2168 $detract_multi_units = $units_counter[$or['idroom']];
2169 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
2170 // split stay bookings never occupy the same room on the same dates
2171 $detract_multi_units = 0;
2172 }
2173 if ($bfound > 0 && $bfound >= ($or['units'] - $detract_multi_units)) {
2174 $opertwounits = false;
2175 break 2;
2176 }
2177
2178 // make sure the room is not temporarily locked while waiting to be paid/confirmed
2179 if ($ord['status'] == 'confirmed' && !VikBooking::roomNotLocked($or['idroom'], $or['units'], $room_checkin, $room_checkout)) {
2180 $opertwounits = false;
2181 break 2;
2182 }
2183 }
2184 }
2185 }
2186
2187 /**
2188 * Make sure no sub-units are overbooked even though the main room is available.
2189 *
2190 * @since 1.13.0 (J) - 1.3.0 (WP)
2191 */
2192 if ($opertwounits === true && count($subunits_involved_bids)) {
2193 $subunits_involved_bids = array_unique($subunits_involved_bids);
2194 // grab all the information about the bids involved and the related rooms/indexes
2195 $q = "SELECT `or`.`idorder`, `or`.`idroom`, `or`.`roomindex`, `o`.`checkin`, `o`.`checkout`, `r`.`name`, `r`.`params`
2196 FROM `#__vikbooking_ordersrooms` AS `or` LEFT JOIN `#__vikbooking_orders` AS `o` ON `or`.`idorder`=`o`.`id`
2197 LEFT JOIN `#__vikbooking_rooms` AS `r` ON `or`.`idroom`=`r`.`id`
2198 WHERE `or`.`idorder` IN (" . implode(', ', array_keys($subunits_involved_bids)) . ");";
2199 $dbo->setQuery($q);
2200 $dbo->execute();
2201 if ($dbo->getNumRows()) {
2202 $involved_data = $dbo->loadAssocList();
2203 foreach ($involved_data as $invb) {
2204 if (empty($invb['roomindex'])) {
2205 continue;
2206 }
2207 foreach ($subunits_involved_bids[$invb['idorder']] as $bookedindex) {
2208 if ($bookedindex['idroom'] == $invb['idroom'] && $bookedindex['roomindex'] == $invb['roomindex']) {
2209 // this same sub-unit is occupied by this booking ID: raise an error message to inform the administrator
2210 $subunit_name = $invb['roomindex'];
2211 $room_params = json_decode($invb['params'], true);
2212 if (is_array($room_params) && isset($room_params['features']) && @count($room_params['features'])) {
2213 foreach ($room_params['features'] as $rind => $rfeatures) {
2214 if ($rind == $invb['roomindex']) {
2215 foreach ($rfeatures as $fname => $fval) {
2216 if (strlen($fval)) {
2217 $subunit_name = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
2218 break;
2219 }
2220 }
2221 }
2222 }
2223 }
2224 $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>';
2225 VikError::raiseWarning('', JText::sprintf('VBOSUBUNITOVERBOOKEDERR', $subunit_name, $invb['name'], date($df, $invb['checkin']), date($df, $invb['checkout']), $invb['idorder']) . $adjust_link);
2226 }
2227 }
2228 }
2229 }
2230 }
2231
2232 $forcebooking = VikRequest::getInt('forcebooking', 0, 'request');
2233 if ($opertwounits === true || $forcebooking) {
2234 // update dates, customer information, amount paid and busy records before checking the rates
2235 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
2236 $realback = $turnover_secs + $second;
2237
2238 $newtotalpaid = strlen($ptotpaid) > 0 ? floatval($ptotpaid) : "";
2239 $newrefund = strlen($prefund) > 0 ? floatval($prefund) : null;
2240 $roomsnum = $ord['roomsnum'];
2241
2242 // add room to existing booking
2243 $room_added = false;
2244 $padd_room_id = VikRequest::getInt('add_room_id', '', 'request');
2245 $padd_room_adults = VikRequest::getInt('add_room_adults', 2, 'request');
2246 $padd_room_children = VikRequest::getInt('add_room_children', 0, 'request');
2247 $padd_room_fname = VikRequest::getString('add_room_fname', '', 'request');
2248 $padd_room_lname = VikRequest::getString('add_room_lname', '', 'request');
2249 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2250 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2251 if ($padd_room_id > 0 && ($padd_room_adults + $padd_room_children) > 0) {
2252 // no need to re-validate the availability for this new room, as it was made via JS in the View.
2253 // increase the rooms number for later update, and insert the new room record
2254 $roomsnum++;
2255 $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').");";
2256 $dbo->setQuery($q);
2257 $dbo->execute();
2258 $room_added = true;
2259 }
2260
2261 // remove room from existing booking
2262 $room_removed = false;
2263 $room_removed_index = null;
2264 if ($prm_room_oid > 0 && $roomsnum > 1) {
2265 // check if the requested room record exists for removal
2266 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id'].";";
2267 $dbo->setQuery($q);
2268 $dbo->execute();
2269 if ($dbo->getNumRows() == 1) {
2270 $room_before_rm = $dbo->loadAssoc();
2271 // decrease the rooms number for later update, and remove the requested room record
2272 $roomsnum--;
2273 // find the index of this room in the current list before removal
2274 foreach ($ordersrooms as $kor => $or) {
2275 if ($or['id'] == $prm_room_oid) {
2276 $room_removed_index = $kor;
2277 break;
2278 }
2279 }
2280 // go ahead with the deletion of the room record
2281 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `id`=".$prm_room_oid." AND `idorder`=".$ord['id']." LIMIT 1;";
2282 $dbo->setQuery($q);
2283 $dbo->execute();
2284 $room_removed = $room_before_rm['idroom'];
2285 }
2286 }
2287
2288 if ($ord['split_stay'] && !empty($split_stay_data) && count($split_stay_checkins) && ($room_added !== false || $room_removed !== false)) {
2289 // split stay booking (even if only 1 room left) and one room was either added or removed: set new global stay dates
2290 if ($room_removed !== false && isset($room_removed_index) && isset($split_stay_checkins[$room_removed_index])) {
2291 // exclude the split stay dates of this room that was just removed
2292 unset($split_stay_checkins[$room_removed_index], $split_stay_checkouts[$room_removed_index]);
2293 }
2294 if (count($split_stay_checkins) && count($split_stay_checkouts)) {
2295 // if we still have rooms, and we should, update the booking global stay dates
2296 $first = min($split_stay_checkins);
2297 $second = max($split_stay_checkouts);
2298 $daysdiff = $av_helper->countNightsOfStay($first, $second);
2299 }
2300 }
2301
2302 // update booking's basic information (customer data, dates, tot paid, number of rooms, refund)
2303 $basic_booking = new stdClass;
2304 $basic_booking->id = $ord['id'];
2305 $basic_booking->custdata = $pcustdata;
2306 $basic_booking->days = (int)$daysdiff;
2307 $basic_booking->checkin = $first;
2308 $basic_booking->checkout = $second;
2309 if (strlen($newtotalpaid) > 0) {
2310 $basic_booking->totpaid = $newtotalpaid;
2311 }
2312 $basic_booking->roomsnum = (int)$roomsnum;
2313 if ($newrefund !== null) {
2314 $basic_booking->refund = $newrefund;
2315 }
2316 if ($ord['split_stay'] && $roomsnum < 2 && $room_removed !== false) {
2317 // there is no point in keep treating this reservation as a split stay
2318 $basic_booking->split_stay = 0;
2319 }
2320 $dbo->updateObject('#__vikbooking_orders', $basic_booking, 'id');
2321
2322 // Booking History log for new amount paid (payment update)
2323 if ($newtotalpaid > 0 && $newtotalpaid > (float)$ord['totpaid']) {
2324 $extra_data = new stdClass;
2325 $extra_data->amount_paid = ($newtotalpaid - (float)$ord['totpaid']);
2326 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$ord['totpaid'])));
2327 }
2328
2329 // booking history log for new refund amount
2330 if ($newrefund !== null && $newrefund != (float)$ord['refund']) {
2331 // update current refund value
2332 $ord['refund'] = $newrefund;
2333 // store event
2334 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->setExtraData(null)->store('RU', JText::sprintf('VBO_NEWREFUND_AMOUNT', VikBooking::numberFormat($ord['refund']), VikBooking::numberFormat($newrefund)));
2335 }
2336
2337 // update busy records
2338 if ($ord['status'] == 'confirmed') {
2339 $allbusy = [];
2340 if ($ord['split_stay'] && !empty($split_stay_data)) {
2341 // in case of split stay we need to update the busy records according to the nights selected
2342 foreach ($split_stay_data as $sps_k => $split_stay) {
2343 if (empty($split_stay['idbusy']) || empty($split_stay['checkin']) || empty($split_stay['checkout'])) {
2344 // missing data
2345 continue;
2346 }
2347 // get selected dates
2348 $room_checkin = VikBooking::getDateTimestamp($split_stay['checkin'], $pcheckinh, $pcheckinm);
2349 $room_checkout = VikBooking::getDateTimestamp($split_stay['checkout'], $pcheckouth, $pcheckoutm);
2350 $room_realback = $turnover_secs + $room_checkout;
2351 // update the exact record
2352 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$split_stay['idbusy'] . ";";
2353 $dbo->setQuery($q);
2354 $dbo->execute();
2355 }
2356 } else {
2357 // regularly update busy records for all rooms involved
2358 $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'] . ";";
2359 $dbo->setQuery($q);
2360 $dbo->execute();
2361 $allbusy = $dbo->loadAssocList();
2362 foreach ($allbusy as $bb) {
2363 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $first . ", `checkout`=" . $second . ", `realback`=" . $realback . " WHERE `id`=" . $bb['id'] . ";";
2364 $dbo->setQuery($q);
2365 $dbo->execute();
2366 }
2367 }
2368
2369 /**
2370 * Check if some rooms have modified stay dates different than the booking stay dates.
2371 *
2372 * @since 1.16.0 (J) - 1.6.0 (WP)
2373 */
2374 if (!$ord['split_stay'] && !$ord['closure'] && $ord['roomsnum'] > 1 && $ord['days'] > 1) {
2375 // load the occupied stay dates for each room in case they were modified
2376 $room_stay_records = $av_helper->loadSplitStayBusyRecords($ord['id']);
2377 // loop over all rooms to check the requested operations
2378 foreach ($ordersrooms as $ind => $or) {
2379 if (!VikRequest::getInt('room_modify_dates' . $ind, 0, 'request') || !isset($room_stay_records[$ind]) || empty($room_stay_records[$ind]['id'])) {
2380 // toggle is disabled or data is missing
2381 continue;
2382 }
2383 if (isset($room_modify_dates[$ind]) && !empty($room_modify_dates[$ind]['checkin']) && !empty($room_modify_dates[$ind]['checkout'])) {
2384 // calculate the check-in and check-out timestamps, we expect them to be different from the global booking dates
2385 $room_checkin = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkin'], $pcheckinh, $pcheckinm);
2386 $room_checkout = VikBooking::getDateTimestamp($room_modify_dates[$ind]['checkout'], $pcheckouth, $pcheckoutm);
2387 $room_realback = $turnover_secs + $room_checkout;
2388 // we don't need to check if the dates are different, we just update the record
2389 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=" . $room_checkin . ", `checkout`=" . $room_checkout . ", `realback`=" . $room_realback . " WHERE `id`=" . (int)$room_stay_records[$ind]['id'] . ";";
2390 $dbo->setQuery($q);
2391 $dbo->execute();
2392 }
2393 }
2394 }
2395
2396 // add room to existing (confirmed) booking
2397 if ($room_added === true) {
2398 // add busy record for the new room unit
2399 $q = "INSERT INTO `#__vikbooking_busy` (`idroom`,`checkin`,`checkout`,`realback`) VALUES(".$padd_room_id.", ".$dbo->quote($first).", ".$dbo->quote($second).", ".$dbo->quote($realback).");";
2400 $dbo->setQuery($q);
2401 $dbo->execute();
2402 $newbusyid = $dbo->insertid();
2403 $q = "INSERT INTO `#__vikbooking_ordersbusy` (`idorder`,`idbusy`) VALUES(".$ord['id'].", ".(int)$newbusyid.");";
2404 $dbo->setQuery($q);
2405 $dbo->execute();
2406 }
2407
2408 // remove room from existing (confirmed) booking
2409 if ($room_removed !== false) {
2410 // remove busy record for the removed room
2411 if ($ord['split_stay'] && !empty($split_stay_data) && !empty($room_removed_index)) {
2412 // in case of split stay we want to remove the exact dates of the previously booked room
2413 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'])) {
2414 // remove the exact records
2415 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=" . $room_stay_dates[$room_removed_index]['id'] . " AND `idroom`=" . $room_removed . ";";
2416 $dbo->setQuery($q);
2417 $dbo->execute();
2418 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=" . $ord['id'] . " AND `idbusy`=" . $room_stay_dates[$room_removed_index]['id'] . ";";
2419 $dbo->setQuery($q);
2420 $dbo->execute();
2421 }
2422 } else {
2423 // regularly remove the first matching room
2424 foreach ($allbusy as $bb) {
2425 if ($bb['idroom'] == $room_removed) {
2426 // remove the first room with this ID that was booked
2427 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`=".$bb['id']." AND `idroom`=".$room_removed.";";
2428 $dbo->setQuery($q);
2429 $dbo->execute();
2430 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".$ord['id']." AND `idbusy`=".$bb['id'].";";
2431 $dbo->setQuery($q);
2432 $dbo->execute();
2433 break;
2434 }
2435 }
2436 }
2437 }
2438
2439 if ($ord['checkin'] != $first || $ord['checkout'] != $second || $room_added === true || $room_removed !== false) {
2440 // unset any previously booked room due to calendar sharing
2441 VikBooking::cleanSharedCalendarsBusy($ord['id']);
2442 // check if some of the rooms booked have shared calendars
2443 VikBooking::updateSharedCalendars($ord['id'], array(), $first, $second);
2444
2445 // invoke Channel Manager
2446 $vcm_autosync = VikBooking::vcmAutoUpdate();
2447 if ($vcm_autosync > 0) {
2448 $vcm_obj = VikBooking::getVcmInvoker();
2449 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
2450 $sync_result = $vcm_obj->doSync();
2451 if ($sync_result === false) {
2452 $vcm_err = $vcm_obj->getError();
2453 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
2454 }
2455 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
2456 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>');
2457 }
2458 //
2459 }
2460 }
2461
2462 $upd_esit = JText::translate('RESUPDATED');
2463
2464 // update the room rates
2465 $isdue = 0;
2466 $tot_taxes = 0;
2467 $tot_city_taxes = 0;
2468 $tot_fees = 0;
2469 $doup = true;
2470 $tars = array();
2471 $cust_costs = array();
2472 $rooms_costs_map = array();
2473 $arrpeople = array();
2474 foreach ($ordersrooms as $kor => $or) {
2475 // remove from existing booking
2476 if ($room_removed !== false) {
2477 if ($or['id'] == $prm_room_oid) {
2478 // do not consider this room for the calculation of the new total amount
2479 // we can unset this array for later use, because the channel manager has already been invoked.
2480 unset($ordersrooms[$kor]);
2481 continue;
2482 }
2483 }
2484
2485 // room index starting from 1
2486 $num = $kor + 1;
2487
2488 // default values to be considered
2489 $room_nights = $daysdiff;
2490 $room_checkin = $ord['checkin'];
2491 $room_checkout = $ord['checkout'];
2492 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'])) {
2493 $room_nights = $room_stay_dates[$kor]['new_nights'];
2494 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2495 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2496 }
2497
2498 $padults = VikRequest::getString('adults' . $num, '', 'request');
2499 $pchildren = VikRequest::getString('children' . $num, '', 'request');
2500 $ppets = VikRequest::getInt('pets' . $num, 0, 'request');
2501 if (strlen($padults) || strlen($pchildren)) {
2502 $arrpeople[$num]['adults'] = (int)$padults;
2503 $arrpeople[$num]['children'] = (int)$pchildren;
2504 $arrpeople[$num]['pets'] = $ppets;
2505 }
2506 $ppriceid = VikRequest::getString('priceid'.$num, '', 'request');
2507 $polderpriceid = VikRequest::getString('olderpriceid'.$num, '', 'request');
2508 $ppkgid = VikRequest::getString('pkgid'.$num, '', 'request');
2509 $pcust_cost = VikRequest::getString('cust_cost'.$num, '', 'request');
2510 $paliq = VikRequest::getString('aliq'.$num, '', 'request');
2511 if ($is_package === true && !empty($ppkgid)) {
2512 $pkg_cost = $or['cust_cost'];
2513 $pkg_idiva = $or['cust_idiva'];
2514 $pkg_info = VikBooking::getPackage($ppkgid);
2515 if (is_array($pkg_info) && count($pkg_info) > 0) {
2516 $use_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : $or['adults'];
2517 $pkg_cost = $pkg_info['pernight_total'] == 1 ? ($pkg_info['cost'] * $room_nights) : $pkg_info['cost'];
2518 $pkg_cost = $pkg_info['perperson'] == 1 ? ($pkg_cost * ($use_adults > 0 ? $use_adults : 1)) : $pkg_cost;
2519 $pkg_cost = VikBooking::sayPackagePlusIva($pkg_cost, $pkg_info['idiva']);
2520 }
2521 $cust_costs[$num] = array('pkgid' => $ppkgid, 'cust_cost' => $pkg_cost, 'aliq' => $pkg_idiva);
2522 $isdue += $pkg_cost;
2523 $cost_minus_tax = VikBooking::sayPackageMinusIva($pkg_cost, $pkg_idiva);
2524 $tot_taxes += ($pkg_cost - $cost_minus_tax);
2525 continue;
2526 }
2527 if (empty($ppriceid) && !empty($pcust_cost) && floatval($pcust_cost) > 0) {
2528 $cust_costs[$num] = array('cust_cost' => $pcust_cost, 'aliq' => $paliq);
2529 $cost_after_tax = VikBooking::sayPackagePlusIva((float)$pcust_cost, (int)$paliq);
2530 $isdue += $cost_after_tax;
2531 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$pcust_cost, (int)$paliq);
2532 $tot_taxes += ($cost_after_tax - $cost_minus_tax);
2533 continue;
2534 }
2535
2536 // load room rates for the requested rate plan and nights
2537 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `idroom`=" . (int)$or['idroom'] . " AND `days`=" . $room_nights . " AND `idprice`=" . (int)$ppriceid . ";";
2538 $dbo->setQuery($q);
2539 $dbo->execute();
2540 if (!$dbo->getNumRows()) {
2541 $doup = false;
2542 break;
2543 }
2544
2545 // load room tariffs
2546 $tar = $dbo->loadAssocList();
2547
2548 /**
2549 * The current price may be different from the price paid at the time of booking.
2550 * Check whether it has been asked to keep the old price of the time of booking.
2551 *
2552 * @since 1.13.0 (J) - 1.3.0 (WP)
2553 */
2554 $old_price_used = false;
2555 if (!empty($polderpriceid)) {
2556 $older_info = explode(':', $polderpriceid);
2557 if ((int)$older_info[0] == (int)$ppriceid) {
2558 $old_price = isset($older_info[1]) ? (float)$older_info[1] : 0;
2559 if ($old_price > 0) {
2560 // we override the 'cost' property of the tar array by taking the previous cost
2561 $old_price_used = true;
2562 $tar[0]['cost'] = $old_price;
2563 }
2564 }
2565 }
2566
2567 if (!$old_price_used) {
2568 // apply seasonal rates
2569 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
2570 }
2571
2572 // different usage
2573 if (!$old_price_used && $or['fromadult'] <= $or['adults'] && $or['toadult'] >= $or['adults']) {
2574 // apply OBP rules
2575 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
2576 }
2577
2578 $cost_plus_tax = VikBooking::sayCostPlusIva($tar[0]['cost'], $tar[0]['idprice']);
2579 $isdue += $cost_plus_tax;
2580 if ($cost_plus_tax == $tar[0]['cost']) {
2581 $cost_minus_tax = VikBooking::sayCostMinusIva($tar[0]['cost'], $tar[0]['idprice']);
2582 $tot_taxes += ($tar[0]['cost'] - $cost_minus_tax);
2583 } else {
2584 $tot_taxes += ($cost_plus_tax - $tar[0]['cost']);
2585 }
2586 $tars[$num] = $tar;
2587 $rooms_costs_map[$num] = $tar[0]['cost'];
2588 }
2589
2590 if ($doup === true) {
2591 if ($room_added === true) {
2592 // add room to existing booking may require to increase the total amount, and taxes
2593 $padd_room_price = VikRequest::getFloat('add_room_price', 0, 'request');
2594 $paliq_add_room = VikRequest::getInt('aliq_add_room', 0, 'request');
2595 if (!empty($padd_room_price) && floatval($padd_room_price) > 0) {
2596 $isdue += (float)$padd_room_price;
2597 $cost_minus_tax = VikBooking::sayPackageMinusIva((float)$padd_room_price, (int)$paliq_add_room);
2598 $tot_taxes += ((float)$padd_room_price - $cost_minus_tax);
2599 }
2600 }
2601 $toptionals = '';
2602 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
2603 $dbo->setQuery($q);
2604 $dbo->execute();
2605 if ($dbo->getNumRows() > 0) {
2606 $toptionals = $dbo->loadAssocList();
2607 }
2608 foreach ($ordersrooms as $kor => $or) {
2609 $num = $kor + 1;
2610
2611 // default values to be considered
2612 $room_nights = $daysdiff;
2613 $room_checkin = $ord['checkin'];
2614 $room_checkout = $ord['checkout'];
2615 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'])) {
2616 $room_nights = $room_stay_dates[$kor]['new_nights'];
2617 $room_checkin = $room_stay_dates[$kor]['new_checkin'];
2618 $room_checkout = $room_stay_dates[$kor]['new_checkout'];
2619 }
2620
2621 $pt_first_name = VikRequest::getString('t_first_name'.$num, '', 'request');
2622 $pt_last_name = VikRequest::getString('t_last_name'.$num, '', 'request');
2623 $wop = "";
2624 if (is_array($toptionals)) {
2625 foreach ($toptionals as $opt) {
2626 if (!empty($opt['ageintervals']) && ($or['children'] > 0 || (array_key_exists($num, $arrpeople) && array_key_exists('children', $arrpeople[$num]))) ) {
2627 $tmpvar = VikRequest::getInt('optid'.$num.$opt['id'], []);
2628 if (is_array($tmpvar) && $tmpvar) {
2629 $opt['quan'] = 1;
2630 $optagenames = VikBooking::getOptionIntervalsAges($opt['ageintervals']);
2631 $optagepcent = VikBooking::getOptionIntervalsPercentage($opt['ageintervals']);
2632 $optageovrct = VikBooking::getOptionIntervalChildOverrides($opt, (isset($arrpeople[$num]) ? $arrpeople[$num]['adults'] : 0), (isset($arrpeople[$num]) ? $arrpeople[$num]['children'] : 0));
2633 $optorigname = $opt['name'];
2634 foreach ($tmpvar as $child_num => $chvar) {
2635 $ageintervals_child_string = isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $opt['ageintervals'];
2636 $optagecosts = VikBooking::getOptionIntervalsCosts($ageintervals_child_string);
2637 $optorigcost = $optagecosts[($chvar - 1)];
2638 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
2639 //percentage value of the adults tariff
2640 if ($is_package !== true && array_key_exists($num, $tars)) {
2641 //type of price
2642 $optorigcost = $tars[$num][0]['cost'] * $optagecosts[($chvar - 1)] / 100;
2643 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2644 //package
2645 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2646 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2647 //custom rate + custom tax rate
2648 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2649 }
2650 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
2651 //VBO 1.10 - percentage value of room base cost
2652 if ($is_package !== true && array_key_exists($num, $tars)) {
2653 //type of price
2654 $usecost = isset($tars[$num][0]['room_base_cost']) ? $tars[$num][0]['room_base_cost'] : $tars[$num][0]['cost'];
2655 $optorigcost = $usecost * $optagecosts[($chvar - 1)] / 100;
2656 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2657 //package
2658 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2659 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2660 //custom rate + custom tax rate
2661 $optorigcost = $cust_costs[$num]['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
2662 }
2663 }
2664 $opt['cost'] = $optorigcost;
2665 $opt['name'] = $optorigname.' ('.$optagenames[($chvar - 1)].')';
2666 $opt['chageintv'] = $chvar;
2667 $wop.=$opt['id'].":".$opt['quan']."-".$chvar.";";
2668 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $opt['quan']) : ($opt['cost'] * $opt['quan']));
2669 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2670 $realcost = $opt['maxprice'];
2671 }
2672 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2673 if ($opt['is_citytax'] == 1) {
2674 $tot_city_taxes += $tmpopr;
2675 } elseif ($opt['is_fee'] == 1) {
2676 $tot_fees += $tmpopr;
2677 }
2678 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2679 if ($tmpopr == $realcost) {
2680 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
2681 $tot_taxes += ($realcost - $opt_minus_iva);
2682 } else {
2683 $tot_taxes += ($tmpopr - $realcost);
2684 }
2685 //
2686 $isdue += $tmpopr;
2687 }
2688 }
2689 } else {
2690 $tmpvar = VikRequest::getString('optid'.$num.$opt['id'], '', 'request');
2691 //options forced per child fix, no age intervals, like children tourist taxes
2692 $forcedquan = 1;
2693 $forceperday = false;
2694 $forceperchild = false;
2695 if (intval($opt['forcesel']) == 1 && strlen($opt['forceval']) > 0 && strlen($tmpvar) > 0) {
2696 $forceparts = explode("-", $opt['forceval']);
2697 $forcedquan = intval($forceparts[0]);
2698 $forceperday = intval($forceparts[1]) == 1 ? true : false;
2699 $forceperchild = intval($forceparts[2]) == 1 ? true : false;
2700 $tmpvar = $forcedquan;
2701 $tmpvar = $forceperchild === true && array_key_exists($num, $arrpeople) && array_key_exists('children', $arrpeople[$num]) ? ($tmpvar * $arrpeople[$num]['children']) : $tmpvar;
2702 }
2703 //
2704 if (!empty($tmpvar)) {
2705 $wop .= $opt['id'].":".$tmpvar.";";
2706 // VBO 1.11 - options percentage cost of the room total fee
2707 if ($is_package !== true && array_key_exists($num, $tars)) {
2708 //type of price
2709 $deftar_basecosts = $tars[$num][0]['cost'];
2710 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2711 //package
2712 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2713 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2714 //custom rate + custom tax rate
2715 $deftar_basecosts = $cust_costs[$num]['cust_cost'];
2716 }
2717 $opt['cost'] = (int)$opt['pcentroom'] ? ($deftar_basecosts * $opt['cost'] / 100) : $opt['cost'];
2718 //
2719 $realcost = (intval($opt['perday']) == 1 ? ($opt['cost'] * $room_nights * $tmpvar) : ($opt['cost'] * $tmpvar));
2720 if (!empty($opt['maxprice']) && $opt['maxprice'] > 0 && $realcost > $opt['maxprice']) {
2721 $realcost = $opt['maxprice'];
2722 if (intval($opt['hmany']) == 1 && intval($tmpvar) > 1) {
2723 $realcost = $opt['maxprice'] * $tmpvar;
2724 }
2725 }
2726 if ($opt['perperson'] == 1) {
2727 $num_adults = array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num]) ? $arrpeople[$num]['adults'] : 1;
2728 $realcost = $realcost * $num_adults;
2729 }
2730 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $opt['idiva']);
2731 if ($opt['is_citytax'] == 1) {
2732 $tot_city_taxes += $tmpopr;
2733 } elseif ($opt['is_fee'] == 1) {
2734 $tot_fees += $tmpopr;
2735 }
2736 // VBO 1.11 - always calculate the amount of tax no matter if this is already a tax or a fee
2737 if ($tmpopr == $realcost) {
2738 $opt_minus_iva = VikBooking::sayOptionalsMinusIva($realcost, $opt['idiva']);
2739 $tot_taxes += ($realcost - $opt_minus_iva);
2740 } else {
2741 $tot_taxes += ($tmpopr - $realcost);
2742 }
2743 //
2744 $isdue += $tmpopr;
2745 }
2746 }
2747 }
2748 }
2749
2750 $upd_fields = array();
2751 if ($is_package !== true && array_key_exists($num, $tars)) {
2752 //type of price
2753 $upd_fields[] = "`idtar`='".$tars[$num][0]['id']."'";
2754 $upd_fields[] = "`cust_cost`=NULL";
2755 $upd_fields[] = "`cust_idiva`=NULL";
2756 $upd_fields[] = "`room_cost`=".(array_key_exists($num, $rooms_costs_map) ? $dbo->quote($rooms_costs_map[$num]) : "NULL");
2757 } elseif ($is_package === true && array_key_exists($num, $cust_costs)) {
2758 //packages do not update name or cost, just set again the same package ID to avoid risks of empty upd_fields to update
2759 $upd_fields[] = "`idtar`=NULL";
2760 $upd_fields[] = "`pkg_id`='".$cust_costs[$num]['pkgid']."'";
2761 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
2762 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
2763 $upd_fields[] = "`room_cost`=NULL";
2764 } elseif (array_key_exists($num, $cust_costs) && array_key_exists('cust_cost', $cust_costs[$num])) {
2765 //custom rate + custom tax rate
2766 $upd_fields[] = "`idtar`=NULL";
2767 $upd_fields[] = "`cust_cost`='".$cust_costs[$num]['cust_cost']."'";
2768 $upd_fields[] = "`cust_idiva`='".$cust_costs[$num]['aliq']."'";
2769 $upd_fields[] = "`room_cost`=NULL";
2770 }
2771 if (is_array($toptionals)) {
2772 $upd_fields[] = "`optionals`='".$wop."'";
2773 }
2774 if (!empty($pt_first_name) || !empty($pt_last_name)) {
2775 $upd_fields[] = "`t_first_name`=".$dbo->quote($pt_first_name);
2776 $upd_fields[] = "`t_last_name`=".$dbo->quote($pt_last_name);
2777 }
2778 if (array_key_exists($num, $arrpeople) && array_key_exists('adults', $arrpeople[$num])) {
2779 $upd_fields[] = "`adults`=".intval($arrpeople[$num]['adults']);
2780 $upd_fields[] = "`children`=".intval($arrpeople[$num]['children']);
2781 if (isset($arrpeople[$num]['pets'])) {
2782 $upd_fields[] = "`pets`=" . $arrpeople[$num]['pets'];
2783 }
2784 }
2785
2786 /**
2787 * Meal plans at room-reservation level.
2788 *
2789 * @since 1.16.1 (J) - 1.6.1 (WP)
2790 */
2791 $pmealplans = VikRequest::getVar('mealplan' . $num, []);
2792 $upd_fields[] = "`meals`=" . ($pmealplans ? $dbo->q(json_encode($pmealplans)) : 'NULL');
2793
2794 //calculate the extra costs and increase taxes + isdue
2795 $extracosts_arr = array();
2796 if (count($pextracn) && isset($pextracn[$num]) && count($pextracn[$num])) {
2797 foreach ($pextracn[$num] as $eck => $ecn) {
2798 if (strlen($ecn) > 0 && array_key_exists($eck, $pextracc[$num]) && is_numeric($pextracc[$num][$eck])) {
2799 $ecidtax = array_key_exists($eck, $pextractx[$num]) && intval($pextractx[$num][$eck]) > 0 ? (int)$pextractx[$num][$eck] : '';
2800 $extracosts_arr[] = array(
2801 'name' => $ecn,
2802 'cost' => (float)$pextracc[$num][$eck],
2803 'idtax' => $ecidtax,
2804 'type' => isset($pextractype[$num][$eck]) ? $pextractype[$num][$eck] : '',
2805 'fk' => isset($pextracfk[$num][$eck]) ? (string)$pextracfk[$num][$eck] : '',
2806 'data' => isset($pextracdata[$num][$eck]) ? json_decode($pextracdata[$num][$eck]) : null,
2807 );
2808 $ecplustax = !empty($ecidtax) ? VikBooking::sayOptionalsPlusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
2809 $ecminustax = !empty($ecidtax) ? VikBooking::sayOptionalsMinusIva((float)$pextracc[$num][$eck], $ecidtax) : (float)$pextracc[$num][$eck];
2810 $ectottax = (float)$pextracc[$num][$eck] - $ecminustax;
2811 $isdue += $ecplustax;
2812 $tot_taxes += $ectottax;
2813 }
2814 }
2815 }
2816 if (count($extracosts_arr) > 0) {
2817 $upd_fields[] = "`extracosts`=".$dbo->quote(json_encode($extracosts_arr));
2818 } else {
2819 $upd_fields[] = "`extracosts`=NULL";
2820 }
2821 //end extra costs
2822 if (count($upd_fields) > 0) {
2823 $q = "UPDATE `#__vikbooking_ordersrooms` SET ".implode(', ', $upd_fields)." WHERE `idorder`=".$ord['id']." AND `idroom`='".$or['idroom']."' AND `id`='".$or['id']."';";
2824 $dbo->setQuery($q);
2825 $dbo->execute();
2826 }
2827 }
2828
2829 // update split stay transient record if not confirmed booking
2830 if ($ord['split_stay'] && $ord['status'] != 'confirmed' && !empty($room_stay_dates) && !empty($split_stay_data)) {
2831 /**
2832 * Important: if no rates have been selected for all rooms, we won't enter this inner statement.
2833 * It is necessary to select a rate plan for each room in order to update the split stay data.
2834 */
2835 $new_room_stay_dates = [];
2836 foreach ($room_stay_dates as $kor => $room_stay_info) {
2837 // clone the current information
2838 $clean_room_stay_info = $room_stay_info;
2839 // set new stay values
2840 if (!empty($clean_room_stay_info['checkin_ts'])) {
2841 $clean_room_stay_info['checkin_ts'] = $clean_room_stay_info['new_checkin'];
2842 $clean_room_stay_info['checkout_ts'] = $clean_room_stay_info['new_checkout'];
2843 } else {
2844 $clean_room_stay_info['checkin'] = $clean_room_stay_info['new_checkin'];
2845 $clean_room_stay_info['checkout'] = $clean_room_stay_info['new_checkout'];
2846 }
2847 $clean_room_stay_info['nights'] = $clean_room_stay_info['new_nights'];
2848 // clean up unnecessary keys
2849 unset($clean_room_stay_info['new_checkin'], $clean_room_stay_info['new_checkout'], $clean_room_stay_info['new_nights']);
2850 // push new array info
2851 $new_room_stay_dates[$kor] = $clean_room_stay_info;
2852 }
2853 // update configuration record
2854 VBOFactory::getConfig()->set('split_stay_' . $ord['id'], json_encode($new_room_stay_dates));
2855 }
2856
2857 // make sure to re-apply the discount with the coupon code
2858 if (strlen($ord['coupon']) > 0) {
2859 $expcoupon = explode(";", $ord['coupon']);
2860 $isdue -= $expcoupon[1];
2861 }
2862
2863 // make sure to apply any previously refunded amount
2864 if ($ord['refund'] > 0) {
2865 $isdue -= $ord['refund'];
2866 }
2867
2868 // update totals
2869 $q = "UPDATE `#__vikbooking_orders` SET `total`='".$isdue."', `tot_taxes`='".$tot_taxes."', `tot_city_taxes`='".$tot_city_taxes."', `tot_fees`='".$tot_fees."' WHERE `id`=".$ord['id'].";";
2870 $dbo->setQuery($q);
2871 $dbo->execute();
2872 $upd_esit = JText::translate('VBORESRATESUPDATED');
2873
2874 // Customer Booking
2875 if ($ord['status'] == 'confirmed') {
2876 $q = "SELECT `idcustomer` FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$ord['id'].";";
2877 $dbo->setQuery($q);
2878 $dbo->execute();
2879 if ($dbo->getNumRows() > 0) {
2880 $customer_id = $dbo->loadResult();
2881 $cpin = VikBooking::getCPinIstance();
2882 $cpin->is_admin = true;
2883 $cpin->updateBookingCommissions($ord['id'], $customer_id);
2884 }
2885 }
2886 }
2887 //Booking History
2888 $history_descr = "({$user->name}) " . VikBooking::getLogBookingModification($ord, $room_stay_dates);
2889 if (!$opertwounits && $forcebooking) {
2890 $history_descr .= "\n" . JText::translate('VBO_FORCED_BOOKDATES');
2891 }
2892 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', $history_descr);
2893 //
2894 $app->enqueueMessage($upd_esit);
2895 } else {
2896 VikError::raiseWarning('', JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second));
2897 $allow_force = 1;
2898 $app->enqueueMessage(JText::translate('VBO_BOOKING_SHOULDFORCE'), 'notice');
2899 }
2900
2901 if ($callback == 'geninvoices') {
2902 $app->redirect("index.php?option=com_vikbooking&task=orders&cid[]=".$ord['id']."&confirmgen=1");
2903 } else {
2904 $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" : ""));
2905 }
2906 }
2907
2908 public function removebusy()
2909 {
2910 $dbo = JFactory::getDbo();
2911 $app = JFactory::getApplication();
2912
2913 $user = JFactory::getUser();
2914 $config = VBOFactory::getConfig();
2915
2916 $prev_conf_ids = [];
2917 $pidorder = VikRequest::getInt('idorder', 0, 'request');
2918 $pgoto = VikRequest::getString('goto', '', 'request');
2919
2920 $purged = false;
2921
2922 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder;
2923 $dbo->setQuery($q, 0, 1);
2924 $row = $dbo->loadAssoc();
2925
2926 // check for any cancellation constraints
2927 $canc_denied = false;
2928 if ($row && class_exists('VCMFeesCancellation')) {
2929 // let VCM detect if there are any constraints for the cancellation
2930 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
2931 if ($canc_denied) {
2932 // set error message
2933 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
2934 if ($canc_deny_error) {
2935 $app->enqueueMessage($canc_deny_error, 'error');
2936 }
2937 }
2938 }
2939
2940 if ($row && !$canc_denied) {
2941 // set status to cancelled
2942 if ($row['status'] != 'cancelled') {
2943 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
2944 $dbo->setQuery($q);
2945 $dbo->execute();
2946 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
2947 $dbo->setQuery($q);
2948 $dbo->execute();
2949 if ($row['status'] == 'confirmed') {
2950 $prev_conf_ids[] = $row['id'];
2951 }
2952 // Booking History
2953 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
2954 }
2955
2956 // free records up
2957 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
2958 $dbo->setQuery($q);
2959 $ordbusy = $dbo->loadAssocList();
2960 if ($ordbusy) {
2961 foreach ($ordbusy as $ob) {
2962 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
2963 $dbo->setQuery($q);
2964 $dbo->execute();
2965 }
2966 }
2967
2968 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
2969 $dbo->setQuery($q);
2970 $dbo->execute();
2971
2972 // check for purge removal
2973 if ($row['status'] == 'cancelled') {
2974 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
2975 $dbo->setQuery($q);
2976 $dbo->execute();
2977 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
2978 $dbo->setQuery($q);
2979 $dbo->execute();
2980 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
2981 $dbo->setQuery($q);
2982 $dbo->execute();
2983 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
2984 $dbo->setQuery($q);
2985 $dbo->execute();
2986 // in case of split stay booking, remove the transient
2987 if ($row['split_stay']) {
2988 $config->remove('split_stay_' . $row['id']);
2989 }
2990 // turn flag on
2991 $purged = true;
2992 }
2993
2994 // enqueue message
2995 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
2996 }
2997
2998 if ($prev_conf_ids) {
2999 $prev_conf_ids_str = '';
3000 foreach ($prev_conf_ids as $prev_id) {
3001 $prev_conf_ids_str .= '&cid[]='.$prev_id;
3002 }
3003 //Invoke Channel Manager
3004 $vcm_autosync = VikBooking::vcmAutoUpdate();
3005 if ($vcm_autosync > 0) {
3006 $vcm_obj = VikBooking::getVcmInvoker();
3007 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
3008 $sync_result = $vcm_obj->doSync();
3009 if ($sync_result === false) {
3010 $vcm_err = $vcm_obj->getError();
3011 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
3012 }
3013 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
3014 $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');
3015 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
3016 }
3017 //
3018 }
3019
3020 if ($pgoto == 'overv') {
3021 $app->redirect("index.php?option=com_vikbooking&task=overv");
3022 } elseif (!$purged) {
3023 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pidorder);
3024 } else {
3025 $app->redirect("index.php?option=com_vikbooking&task=orders");
3026 }
3027
3028 $app->close();
3029 }
3030
3031 public function unlockrecords() {
3032 $ids = VikRequest::getVar('cid', array(0));
3033 if (@count($ids)) {
3034 $dbo = JFactory::getDBO();
3035 foreach ($ids as $d) {
3036 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `id`=".$dbo->quote($d).";";
3037 $dbo->setQuery($q);
3038 $dbo->execute();
3039 }
3040 }
3041 $mainframe = JFactory::getApplication();
3042 $mainframe->redirect("index.php?option=com_vikbooking");
3043 }
3044
3045 public function sortoption() {
3046 if (!JSession::checkToken('get')) {
3047 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3048 }
3049 $sortid = VikRequest::getVar('cid', array(0));
3050 $pmode = VikRequest::getString('mode', '', 'request');
3051 $dbo = JFactory::getDBO();
3052 $mainframe = JFactory::getApplication();
3053 if (!empty($pmode)) {
3054 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
3055 $dbo->setQuery($q);
3056 $dbo->execute();
3057 $totr = $dbo->getNumRows();
3058 if ($totr > 1) {
3059 $data = $dbo->loadAssocList();
3060 if ($pmode == "up") {
3061 foreach ($data as $v) {
3062 if ($v['id'] == $sortid[0]) {
3063 $y = $v['ordering'];
3064 }
3065 }
3066 if ($y && $y > 1) {
3067 $vik = $y - 1;
3068 $found = false;
3069 foreach ($data as $v) {
3070 if (intval($v['ordering']) == intval($vik)) {
3071 $found = true;
3072 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3073 $dbo->setQuery($q);
3074 $dbo->execute();
3075 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3076 $dbo->setQuery($q);
3077 $dbo->execute();
3078 break;
3079 }
3080 }
3081 if (!$found) {
3082 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3083 $dbo->setQuery($q);
3084 $dbo->execute();
3085 }
3086 }
3087 } elseif ($pmode == "down") {
3088 foreach ($data as $v) {
3089 if ($v['id'] == $sortid[0]) {
3090 $y = $v['ordering'];
3091 }
3092 }
3093 if ($y) {
3094 $vik = $y + 1;
3095 $found = false;
3096 foreach ($data as $v) {
3097 if (intval($v['ordering']) == intval($vik)) {
3098 $found = true;
3099 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3100 $dbo->setQuery($q);
3101 $dbo->execute();
3102 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3103 $dbo->setQuery($q);
3104 $dbo->execute();
3105 break;
3106 }
3107 }
3108 if (!$found) {
3109 $q = "UPDATE `#__vikbooking_optionals` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3110 $dbo->setQuery($q);
3111 $dbo->execute();
3112 }
3113 }
3114 }
3115 }
3116 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
3117 } else {
3118 $mainframe->redirect("index.php?option=com_vikbooking");
3119 }
3120 }
3121
3122 public function sortpayment() {
3123 if (!JSession::checkToken('get')) {
3124 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3125 }
3126 $cid = VikRequest::getVar('cid', array(0));
3127 $sortid = $cid[0];
3128 $dbo = JFactory::getDBO();
3129 $mainframe = JFactory::getApplication();
3130 $pmode = VikRequest::getString('mode', '', 'request');
3131 if (!empty($pmode) && !empty($sortid)) {
3132 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_gpayments` ORDER BY `#__vikbooking_gpayments`.`ordering` ASC;";
3133 $dbo->setQuery($q);
3134 $dbo->execute();
3135 $totr=$dbo->getNumRows();
3136 if ($totr > 1) {
3137 $data = $dbo->loadAssocList();
3138 if ($pmode == "up") {
3139 foreach ($data as $v) {
3140 if ($v['id'] == $sortid) {
3141 $y = $v['ordering'];
3142 }
3143 }
3144 if ($y && $y > 1) {
3145 $vik = $y - 1;
3146 $found = false;
3147 foreach ($data as $v) {
3148 if (intval($v['ordering']) == intval($vik)) {
3149 $found = true;
3150 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3151 $dbo->setQuery($q);
3152 $dbo->execute();
3153 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3154 $dbo->setQuery($q);
3155 $dbo->execute();
3156 break;
3157 }
3158 }
3159 if (!$found) {
3160 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3161 $dbo->setQuery($q);
3162 $dbo->execute();
3163 }
3164 }
3165 } elseif ($pmode == "down") {
3166 foreach ($data as $v) {
3167 if ($v['id'] == $sortid) {
3168 $y = $v['ordering'];
3169 }
3170 }
3171 if ($y) {
3172 $vik = $y + 1;
3173 $found = false;
3174 foreach ($data as $v) {
3175 if (intval($v['ordering']) == intval($vik)) {
3176 $found=true;
3177 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3178 $dbo->setQuery($q);
3179 $dbo->execute();
3180 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3181 $dbo->setQuery($q);
3182 $dbo->execute();
3183 break;
3184 }
3185 }
3186 if (!$found) {
3187 $q = "UPDATE `#__vikbooking_gpayments` SET `ordering`='".$vik."' WHERE `id`='".$sortid."' LIMIT 1;";
3188 $dbo->setQuery($q);
3189 $dbo->execute();
3190 }
3191 }
3192 }
3193 }
3194 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
3195 } else {
3196 $mainframe->redirect("index.php?option=com_vikbooking");
3197 }
3198 }
3199
3200 public function sortcarat() {
3201 if (!JSession::checkToken('get')) {
3202 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
3203 }
3204 $sortid = VikRequest::getVar('cid', array(0));
3205 $pmode = VikRequest::getString('mode', '', 'request');
3206 $dbo = JFactory::getDBO();
3207 $mainframe = JFactory::getApplication();
3208 if (!empty($pmode)) {
3209 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` ASC;";
3210 $dbo->setQuery($q);
3211 $dbo->execute();
3212 $totr = $dbo->getNumRows();
3213 if ($totr > 1) {
3214 $data = $dbo->loadAssocList();
3215 if ($pmode == "up") {
3216 foreach ($data as $v) {
3217 if ($v['id'] == $sortid[0]) {
3218 $y = $v['ordering'];
3219 }
3220 }
3221 if ($y && $y > 1) {
3222 $vik = $y - 1;
3223 $found = false;
3224 foreach ($data as $v) {
3225 if (intval($v['ordering']) == intval($vik)) {
3226 $found = true;
3227 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3228 $dbo->setQuery($q);
3229 $dbo->execute();
3230 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3231 $dbo->setQuery($q);
3232 $dbo->execute();
3233 break;
3234 }
3235 }
3236 if (!$found) {
3237 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3238 $dbo->setQuery($q);
3239 $dbo->execute();
3240 }
3241 }
3242 } elseif ($pmode == "down") {
3243 foreach ($data as $v) {
3244 if ($v['id'] == $sortid[0]) {
3245 $y = $v['ordering'];
3246 }
3247 }
3248 if ($y) {
3249 $vik = $y + 1;
3250 $found = false;
3251 foreach ($data as $v) {
3252 if (intval($v['ordering']) == intval($vik)) {
3253 $found = true;
3254 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
3255 $dbo->setQuery($q);
3256 $dbo->execute();
3257 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3258 $dbo->setQuery($q);
3259 $dbo->execute();
3260 break;
3261 }
3262 }
3263 if (!$found) {
3264 $q = "UPDATE `#__vikbooking_characteristics` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
3265 $dbo->setQuery($q);
3266 $dbo->execute();
3267 }
3268 }
3269 }
3270 }
3271 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
3272 } else {
3273 $mainframe->redirect("index.php?option=com_vikbooking");
3274 }
3275 }
3276
3277 public function resendordemail() {
3278 $this->do_resendorderemail();
3279 }
3280
3281 public function sendcancordemail() {
3282 $this->do_resendorderemail(true);
3283 }
3284
3285 private function do_resendorderemail($cancellation = false)
3286 {
3287 $dbo = JFactory::getDbo();
3288 $app = JFactory::getApplication();
3289 $vbo_tn = VikBooking::getTranslator();
3290
3291 $cid = VikRequest::getVar('cid', array(0));
3292 $oid = (int)$cid[0];
3293
3294 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $oid . ";";
3295 $dbo->setQuery($q);
3296 $dbo->execute();
3297 if (!$dbo->getNumRows()) {
3298 $app->redirect("index.php?option=com_vikbooking&task=orders");
3299 $app->close();
3300 }
3301 $order = $dbo->loadAssoc();
3302
3303 // check if the language in use is the same as the one used during the checkout
3304 if (!empty($order['lang'])) {
3305 $lang = JFactory::getLanguage();
3306 if ($lang->getTag() != $order['lang']) {
3307 $lang->load('com_vikbooking', (VBOPlatformDetection::isWordPress() ? VIKBOOKING_LANG : JPATH_ADMINISTRATOR), $order['lang'], true);
3308 if (defined('_JEXEC') && !defined('ABSPATH')) {
3309 $lang->load('joomla', JPATH_ADMINISTRATOR, $order['lang'], true);
3310 }
3311 }
3312 if ($vbo_tn->getDefaultLang() != $order['lang']) {
3313 // force the translation to start because contents should be translated
3314 $vbo_tn::$force_tolang = $order['lang'];
3315 }
3316 }
3317
3318 // availability helper
3319 $av_helper = VikBooking::getAvailabilityInstance();
3320
3321 /**
3322 * Split stay reservation.
3323 *
3324 * @since 1.16.0 (J) - 1.6.0 (WP)
3325 */
3326 $room_stay_dates = [];
3327 if ($order['split_stay']) {
3328 if ($order['status'] == 'confirmed') {
3329 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($order['id']);
3330 } else {
3331 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
3332 }
3333 // immediately count the number of nights of stay for each split room
3334 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
3335 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
3336 // overwrite values for compatibility with non-confirmed bookings
3337 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
3338 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
3339 }
3340 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
3341 // overwrite the whole array
3342 $room_stay_dates[$sps_r_k] = $sps_r_v;
3343 }
3344 }
3345
3346 // load rooms booked
3347 $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;";
3348 $dbo->setQuery($q);
3349 $dbo->execute();
3350 $ordersrooms = $dbo->loadAssocList();
3351 $vbo_tn->translateContents($ordersrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
3352
3353 $ftitle = VikBooking::getFrontTitle();
3354 $currencyname = VikBooking::getCurrencyName();
3355
3356 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
3357 $realback = $turnover_secs + $order['checkout'];
3358
3359 $rooms = array();
3360 $tars = array();
3361 $arrpeople = array();
3362 $is_package = !empty($order['pkg']) ? true : false;
3363 $nowts = time();
3364 foreach ($ordersrooms as $kor => $or) {
3365 $num = $kor + 1;
3366 $rooms[$num] = $or;
3367 $arrpeople[$num]['adults'] = $or['adults'];
3368 $arrpeople[$num]['children'] = $or['children'];
3369 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3370 // package or custom cost set from the back-end
3371 continue;
3372 }
3373
3374 // determine the proper values for this room
3375 $room_nights = $order['days'];
3376 $room_checkin = $order['checkin'];
3377 $room_checkout = $order['checkout'];
3378 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3379 $room_nights = $room_stay_dates[$kor]['nights'];
3380 $room_checkin = $room_stay_dates[$kor]['checkin'];
3381 $room_checkout = $room_stay_dates[$kor]['checkout'];
3382 }
3383
3384 // load tariff
3385 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=" . (int)$or['idtar'] . ";";
3386 $dbo->setQuery($q);
3387 $dbo->execute();
3388 if ($dbo->getNumRows() > 0) {
3389 $tar = $dbo->loadAssocList();
3390 $tar = VikBooking::applySeasonsRoom($tar, $room_checkin, $room_checkout);
3391
3392 // different usage
3393 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
3394
3395 $tars[$num] = $tar[0];
3396 } else {
3397 VikError::raiseWarning('', JText::translate('VBERRNOFAREFOUND'));
3398 }
3399 }
3400
3401 $secdiff = $order['checkout'] - $order['checkin'];
3402 $daysdiff = $secdiff / 86400;
3403 if (is_int($daysdiff)) {
3404 if ($daysdiff < 1) {
3405 $daysdiff = 1;
3406 }
3407 } else {
3408 if ($daysdiff < 1) {
3409 $daysdiff = 1;
3410 } else {
3411 $sum = floor($daysdiff) * 86400;
3412 $newdiff = $secdiff - $sum;
3413 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
3414 if ($maxhmore >= $newdiff) {
3415 $daysdiff = floor($daysdiff);
3416 } else {
3417 $daysdiff = ceil($daysdiff);
3418 }
3419 }
3420 }
3421
3422 $isdue = 0;
3423 $pricestr = array();
3424 $optstr = array();
3425 foreach ($ordersrooms as $kor => $or) {
3426 $num = $kor + 1;
3427
3428 // determine the proper values for this room
3429 $room_nights = $order['days'];
3430 $room_checkin = $order['checkin'];
3431 $room_checkout = $order['checkout'];
3432 if ($order['split_stay'] && !empty($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3433 $room_nights = $room_stay_dates[$kor]['nights'];
3434 $room_checkin = $room_stay_dates[$kor]['checkin'];
3435 $room_checkout = $room_stay_dates[$kor]['checkout'];
3436 }
3437
3438 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3439 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
3440 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
3441 $isdue += $calctar;
3442 $pricestr[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? ucwords($or['otarplan']) : JText::translate('VBOROOMCUSTRATEPLAN'))).": ".$calctar." ".$currencyname;
3443 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
3444 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3445 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
3446 $tars[$num]['calctar'] = $calctar;
3447 $isdue += $calctar;
3448 $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'] : "");
3449 }
3450 if (!empty($or['optionals'])) {
3451 $stepo = explode(";", $or['optionals']);
3452 foreach ($stepo as $roptkey => $oo) {
3453 if (empty($oo)) {
3454 continue;
3455 }
3456 $stept = explode(":", $oo);
3457 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=" . $dbo->quote($stept[0]) . ";";
3458 $dbo->setQuery($q);
3459 $dbo->execute();
3460 if (!$dbo->getNumRows()) {
3461 continue;
3462 }
3463 $actopt = $dbo->loadAssocList();
3464 $vbo_tn->translateContents($actopt, '#__vikbooking_optionals', array(), array(), (!empty($order['lang']) ? $order['lang'] : null));
3465 $chvar = '';
3466 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
3467 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
3468 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
3469 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
3470 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
3471 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
3472 $agestept = explode('-', $stept[1]);
3473 $stept[1] = $agestept[0];
3474 $chvar = $agestept[1];
3475 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
3476 //percentage value of the adults tariff
3477 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3478 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3479 } else {
3480 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3481 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3482 }
3483 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
3484 //VBO 1.10 - percentage value of room base cost
3485 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3486 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3487 } else {
3488 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
3489 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3490 }
3491 }
3492 $actopt[0]['chageintv'] = $chvar;
3493 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
3494 $actopt[0]['quan'] = $stept[1];
3495 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
3496 } else {
3497 $actopt[0]['quan'] = $stept[1];
3498 // VBO 1.11 - options percentage cost of the room total fee
3499 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3500 $deftar_basecosts = $or['cust_cost'];
3501 } else {
3502 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3503 }
3504 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
3505 //
3506 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
3507 }
3508 if (!empty($actopt[0]['maxprice']) && $actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
3509 $realcost = $actopt[0]['maxprice'];
3510 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
3511 $realcost = $actopt[0]['maxprice'] * $stept[1];
3512 }
3513 }
3514 if ($actopt[0]['perperson'] == 1) {
3515 $realcost = $realcost * $or['adults'];
3516 }
3517 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
3518 $isdue += $tmpopr;
3519 $optstr[$num][] = ($stept[1] > 1 ? $stept[1] . " " : "") . $actopt[0]['name'] . ": " . $tmpopr . " " . $currencyname . "\n";
3520 }
3521 }
3522
3523 // custom extra costs
3524 if (!empty($or['extracosts'])) {
3525 $cur_extra_costs = json_decode($or['extracosts'], true);
3526 foreach ($cur_extra_costs as $eck => $ecv) {
3527 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
3528 $isdue += $ecplustax;
3529 $optstr[$num][] = $ecv['name'] . ": " . $ecplustax . " " . $currencyname."\n";
3530 }
3531 }
3532 }
3533
3534 // coupon
3535 $usedcoupon = false;
3536 $origisdue = $isdue;
3537 if (strlen($order['coupon']) > 0) {
3538 $usedcoupon = true;
3539 $expcoupon = explode(";", $order['coupon']);
3540 $isdue = $isdue - $expcoupon[1];
3541 }
3542
3543 // make sure to apply any previously refunded amount
3544 if ($order['refund'] > 0) {
3545 $isdue -= $order['refund'];
3546 }
3547
3548 // ConfirmationNumber
3549 $confirmnumber = $order['confirmnumber'];
3550
3551 $esit_mess = JText::sprintf('VBORDEREMAILRESENT', $order['custmail']);
3552 $status_str = JText::translate('VBCOMPLETED');
3553 if ($cancellation) {
3554 $confirmnumber = '';
3555 $esit_mess = JText::sprintf('VBCANCORDEREMAILSENT', $order['custmail']);
3556 $status_str = JText::translate('VBCANCELLED');
3557 } elseif ($order['status'] == 'standby') {
3558 $confirmnumber = '';
3559 $status_str = JText::translate('VBWAITINGFORPAYMENT');
3560 }
3561 $app->enqueueMessage($esit_mess);
3562
3563 // force the original total amount if rates have changed
3564 if (number_format($isdue, 2) != number_format($order['total'], 2)) {
3565 $isdue = $order['total'];
3566 }
3567
3568 // send email notification to guest (by ignoring the configuration settings)
3569 VikBooking::sendBookingEmail($order['id'], ['guest'], $send = true, $no_config = true);
3570
3571 if ($cancellation) {
3572 /**
3573 * If "send cancellation email", we log the event in the history.
3574 *
3575 * @since 1.14 (J) - 1.4.0 (WP)
3576 */
3577 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('EC');
3578 } else {
3579 /**
3580 * Instead, we store an event log to remind that the email was re-sent to the guest
3581 *
3582 * @since 1.16.3 (J) - 1.6.3 (WP)
3583 */
3584 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('ER', $esit_mess);
3585 }
3586
3587 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$oid);
3588 $app->close();
3589 }
3590
3591 public function setordconfirmed()
3592 {
3593 $dbo = JFactory::getDbo();
3594 $app = JFactory::getApplication();
3595
3596 $cid = VikRequest::getVar('cid', array(0));
3597 $oid = $cid[0];
3598
3599 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . (int)$oid . " AND `status` != 'confirmed';";
3600 $dbo->setQuery($q);
3601 $dbo->execute();
3602 if (!$dbo->getNumRows()) {
3603 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3604 exit;
3605 }
3606 $order = $dbo->loadAssoc();
3607
3608 /**
3609 * Memorize the original booking status for VCM in case of OTA booking.
3610 *
3611 * @since 1.14 (J) - 1.4.0 (WP)
3612 */
3613 $original_book_status = null;
3614 if (!empty($order['idorderota']) && !empty($order['channel'])) {
3615 $original_book_status = $order['status'];
3616 }
3617
3618 // availability helper
3619 $av_helper = VikBooking::getAvailabilityInstance();
3620
3621 // room stay dates in case of split stay
3622 $room_stay_dates = [];
3623 if ($order['split_stay']) {
3624 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $order['id'], []);
3625 }
3626
3627 $vbo_tn = VikBooking::getTranslator();
3628 // check if the language in use is the same as the one used during the checkout
3629 if (!empty($order['lang'])) {
3630 $lang = JFactory::getLanguage();
3631 if ($lang->getTag() != $order['lang']) {
3632 $lang->load('com_vikbooking', (VBOPlatformDetection::isWordPress() ? VIKBOOKING_LANG : JPATH_ADMINISTRATOR), $order['lang'], true);
3633 if (defined('_JEXEC') && !defined('ABSPATH')) {
3634 $lang->load('joomla', JPATH_ADMINISTRATOR, $order['lang'], true);
3635 }
3636 }
3637 if ($vbo_tn->getDefaultLang() != $order['lang']) {
3638 // force the translation to start because contents should be translated
3639 $vbo_tn::$force_tolang = $order['lang'];
3640 }
3641 }
3642
3643 // load order rooms
3644 $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;";
3645 $dbo->setQuery($q);
3646 $dbo->execute();
3647 $ordersrooms = $dbo->loadAssocList();
3648 $vbo_tn->translateContents($ordersrooms, '#__vikbooking_rooms', array('id' => 'r_reference_id'));
3649
3650 $currencyname = VikBooking::getCurrencyName();
3651 $turnover_secs = VikBooking::getHoursRoomAvail() * 3600;
3652 $realback = $turnover_secs + $order['checkout'];
3653 $allbook = true;
3654 $notavail = [];
3655
3656 /**
3657 * We need to calculate a minus operator for each room that was booked more than once.
3658 * In case we are confirming a booking for more than one unit of the same room, we need to
3659 * make sure the calculation is made properly, as only one unit of that room could be free.
3660 *
3661 * @since 1.13 (J) - 1.3.0 (WP)
3662 */
3663 $units_minus_oper = [];
3664 foreach ($ordersrooms as $ind => $or) {
3665 if (!isset($units_minus_oper[$or['idroom']])) {
3666 $units_minus_oper[$or['idroom']] = -1;
3667 }
3668 // increase counter
3669 $units_minus_oper[$or['idroom']]++;
3670 if (!empty($room_stay_dates)) {
3671 // split stay rooms never have the same stay dates, but they should also be different rooms
3672 $units_minus_oper[$or['idroom']] = 0;
3673 }
3674 }
3675
3676 foreach ($ordersrooms as $ind => $or) {
3677 // determine proper values for this room
3678 $room_stay_checkin = $order['checkin'];
3679 $room_stay_checkout = $order['checkout'];
3680 $room_stay_nights = $order['days'];
3681 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
3682 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
3683 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
3684 $room_stay_nights = $av_helper->countNightsOfStay($room_stay_checkin, $room_stay_checkout);
3685 // inject nights calculated for this room
3686 $room_stay_dates[$ind]['nights'] = $room_stay_nights;
3687 }
3688
3689 // check if the room is available
3690 if (!VikBooking::roomBookable($or['idroom'], ($or['units'] - $units_minus_oper[$or['idroom']]), $room_stay_checkin, $room_stay_checkout)) {
3691 $allbook = false;
3692 $notavail[] = $or['name']." (".JText::translate('VBMAILADULTS').": ".$or['adults'].($or['children'] > 0 ? " - ".JText::translate('VBMAILCHILDREN').": ".$or['children'] : "").")";
3693 }
3694 }
3695
3696 if (!$allbook) {
3697 VikError::raiseWarning('', JText::translate('VBERRCONFORDERNOTAVROOM').' '.implode(", ", $notavail).'<br/>'.JText::translate('VBUNABLESETRESCONF'));
3698 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3699 exit;
3700 }
3701
3702 $rooms = [];
3703 $tars = [];
3704 $arrpeople = [];
3705 $is_package = !empty($order['pkg']) ? true : false;
3706 $rooms_booked = [];
3707 foreach ($ordersrooms as $ind => $or) {
3708 // push room booked
3709 array_push($rooms_booked, (int)$or['idroom']);
3710
3711 // determine proper values for this room
3712 $room_stay_checkin = $order['checkin'];
3713 $room_stay_checkout = $order['checkout'];
3714 $room_stay_realback = $realback;
3715 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$ind]) && $room_stay_dates[$ind]['idroom'] == $or['idroom']) {
3716 $room_stay_checkin = !empty($room_stay_dates[$ind]['checkin_ts']) ? $room_stay_dates[$ind]['checkin_ts'] : $room_stay_dates[$ind]['checkin'];
3717 $room_stay_checkout = !empty($room_stay_dates[$ind]['checkout_ts']) ? $room_stay_dates[$ind]['checkout_ts'] : $room_stay_dates[$ind]['checkout'];
3718 $room_stay_realback = $turnover_secs + $room_stay_checkout;
3719 }
3720
3721 $q = "INSERT INTO `#__vikbooking_busy` (`idroom`,`checkin`,`checkout`,`realback`) VALUES(" . (int)$or['idroom'] . ", " . (int)$room_stay_checkin . ", " . (int)$room_stay_checkout . ", " . (int)$room_stay_realback . ");";
3722 $dbo->setQuery($q);
3723 $dbo->execute();
3724 $lid = $dbo->insertid();
3725
3726 $q = "INSERT INTO `#__vikbooking_ordersbusy` (`idorder`,`idbusy`) VALUES(" . (int)$oid . ", " . (int)$lid . ");";
3727 $dbo->setQuery($q);
3728 $dbo->execute();
3729 }
3730
3731 // update status
3732 $q = "UPDATE `#__vikbooking_orders` SET `status`='confirmed' WHERE `id`=" . (int)$order['id'] . ";";
3733 $dbo->setQuery($q);
3734 $dbo->execute();
3735
3736 // remove any previous temporary locked record
3737 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . (int)$order['id'] . ";";
3738 $dbo->setQuery($q);
3739 $dbo->execute();
3740
3741 // Booking History
3742 $now_user = JFactory::getUser();
3743 VikBooking::getBookingHistoryInstance()->setBid($order['id'])->store('TC', "({$now_user->name})");
3744
3745 // check if some of the rooms booked have shared calendars
3746 VikBooking::updateSharedCalendars($order['id'], $rooms_booked, $order['checkin'], $order['checkout']);
3747
3748 // send mail
3749 $ftitle = VikBooking::getFrontTitle();
3750 $nowts = time();
3751 // assign room specific unit
3752 $set_room_indexes = VikBooking::autoRoomUnit();
3753 $room_indexes_usemap = [];
3754
3755 foreach ($ordersrooms as $kor => $or) {
3756 $num = $kor + 1;
3757
3758 // determine proper values for this room
3759 $room_stay_checkin = $order['checkin'];
3760 $room_stay_checkout = $order['checkout'];
3761 $room_stay_nights = $order['days'];
3762 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3763 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
3764 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
3765 $room_stay_nights = $room_stay_dates[$kor]['nights'];
3766 }
3767
3768 $rooms[$num] = $or;
3769 $arrpeople[$num]['adults'] = $or['adults'];
3770 $arrpeople[$num]['children'] = $or['children'];
3771
3772 // assign room specific unit
3773 if ($set_room_indexes === true) {
3774 $room_indexes = VikBooking::getRoomUnitNumsAvailable($order, $or['r_reference_id']);
3775 $use_ind_key = 0;
3776 if (count($room_indexes)) {
3777 if (!array_key_exists($or['r_reference_id'], $room_indexes_usemap)) {
3778 $room_indexes_usemap[$or['r_reference_id']] = $use_ind_key;
3779 } else {
3780 $use_ind_key = $room_indexes_usemap[$or['r_reference_id']];
3781 }
3782 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
3783 $dbo->setQuery($q);
3784 $dbo->execute();
3785 // update rooms references for the customer email sending function
3786 $rooms[$num]['roomindex'] = (int)$room_indexes[$use_ind_key];
3787 //
3788 $room_indexes_usemap[$or['r_reference_id']]++;
3789 }
3790 }
3791
3792 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3793 // package or custom cost set from the back-end
3794 continue;
3795 }
3796
3797 $q = "SELECT * FROM `#__vikbooking_dispcost` WHERE `id`=" . (int)$or['idtar'] . ";";
3798 $dbo->setQuery($q);
3799 $dbo->execute();
3800 if ($dbo->getNumRows() > 0) {
3801 $tar = $dbo->loadAssocList();
3802 $tar = VikBooking::applySeasonsRoom($tar, $room_stay_checkin, $room_stay_checkout);
3803
3804 // different usage
3805 $tar = VBORoomHelper::getInstance()->applyOBPRules($tar, $or, $or['adults']);
3806
3807 $tars[$num] = $tar[0];
3808 } else {
3809 VikError::raiseWarning('', JText::translate('VBERRNOFAREFOUND'));
3810 }
3811 }
3812
3813 $pcheckin = $order['checkin'];
3814 $pcheckout = $order['checkout'];
3815 $secdiff = $pcheckout - $pcheckin;
3816 $daysdiff = $secdiff / 86400;
3817 if (is_int($daysdiff)) {
3818 if ($daysdiff < 1) {
3819 $daysdiff = 1;
3820 }
3821 } else {
3822 if ($daysdiff < 1) {
3823 $daysdiff = 1;
3824 } else {
3825 $sum = floor($daysdiff) * 86400;
3826 $newdiff = $secdiff - $sum;
3827 $maxhmore = VikBooking::getHoursMoreRb() * 3600;
3828 if ($maxhmore >= $newdiff) {
3829 $daysdiff = floor($daysdiff);
3830 } else {
3831 $daysdiff = ceil($daysdiff);
3832 }
3833 }
3834 }
3835
3836 $isdue = 0;
3837 $pricestr = [];
3838 $optstr = [];
3839 foreach ($ordersrooms as $kor => $or) {
3840 $num = $kor + 1;
3841
3842 // determine proper values for this room
3843 $room_stay_checkin = $order['checkin'];
3844 $room_stay_checkout = $order['checkout'];
3845 $room_stay_nights = $order['days'];
3846 if ($order['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$kor]) && $room_stay_dates[$kor]['idroom'] == $or['idroom']) {
3847 $room_stay_checkin = !empty($room_stay_dates[$kor]['checkin_ts']) ? $room_stay_dates[$kor]['checkin_ts'] : $room_stay_dates[$kor]['checkin'];
3848 $room_stay_checkout = !empty($room_stay_dates[$kor]['checkout_ts']) ? $room_stay_dates[$kor]['checkout_ts'] : $room_stay_dates[$kor]['checkout'];
3849 $room_stay_nights = $room_stay_dates[$kor]['nights'];
3850 }
3851
3852 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3853 // package cost or cust_cost may not be inclusive of taxes if prices tax included is off
3854 $calctar = VikBooking::sayPackagePlusIva($or['cust_cost'], $or['cust_idiva']);
3855 $isdue += $calctar;
3856 $pricestr[$num] = (!empty($or['pkg_name']) ? $or['pkg_name'] : (!empty($or['otarplan']) ? ucwords($or['otarplan']) : JText::translate('VBOROOMCUSTRATEPLAN'))).": ".$calctar." ".$currencyname;
3857 } elseif (array_key_exists($num, $tars) && is_array($tars[$num])) {
3858 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3859 $calctar = VikBooking::sayCostPlusIva($display_rate, $tars[$num]['idprice']);
3860 $tars[$num]['calctar'] = $calctar;
3861 $isdue += $calctar;
3862 $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'] : "");
3863 }
3864 if (!empty($or['optionals'])) {
3865 $stepo = explode(";", $or['optionals']);
3866 foreach ($stepo as $roptkey => $oo) {
3867 if (empty($oo)) {
3868 continue;
3869 }
3870 $stept = explode(":", $oo);
3871 $q = "SELECT * FROM `#__vikbooking_optionals` WHERE `id`=" . $dbo->quote($stept[0]) . ";";
3872 $dbo->setQuery($q);
3873 $dbo->execute();
3874 if (!$dbo->getNumRows()) {
3875 continue;
3876 }
3877 $actopt = $dbo->loadAssocList();
3878 $vbo_tn->translateContents($actopt, '#__vikbooking_optionals');
3879 $chvar = '';
3880 if (!empty($actopt[0]['ageintervals']) && $or['children'] > 0 && strstr($stept[1], '-') != false) {
3881 $optagenames = VikBooking::getOptionIntervalsAges($actopt[0]['ageintervals']);
3882 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt[0]['ageintervals']);
3883 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt[0], $or['adults'], $or['children']);
3884 $child_num = VikBooking::getRoomOptionChildNumber($or['optionals'], $actopt[0]['id'], $roptkey, $or['children']);
3885 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt[0]['ageintervals']);
3886 $agestept = explode('-', $stept[1]);
3887 $stept[1] = $agestept[0];
3888 $chvar = $agestept[1];
3889 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 1) {
3890 //percentage value of the adults tariff
3891 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3892 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3893 } else {
3894 $display_rate = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3895 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3896 }
3897 } elseif (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] == 2) {
3898 //VBO 1.10 - percentage value of room base cost
3899 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3900 $optagecosts[($chvar - 1)] = $or['cust_cost'] * $optagecosts[($chvar - 1)] / 100;
3901 } else {
3902 $display_rate = isset($tars[$num]['room_base_cost']) ? $tars[$num]['room_base_cost'] : (!empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost']);
3903 $optagecosts[($chvar - 1)] = $display_rate * $optagecosts[($chvar - 1)] / 100;
3904 }
3905 }
3906 $actopt[0]['chageintv'] = $chvar;
3907 $actopt[0]['name'] .= ' ('.$optagenames[($chvar - 1)].')';
3908 $actopt[0]['quan'] = $stept[1];
3909 $realcost = (intval($actopt[0]['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $room_stay_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
3910 } else {
3911 $actopt[0]['quan'] = $stept[1];
3912 // VBO 1.11 - options percentage cost of the room total fee
3913 if ($is_package === true || (!empty($or['cust_cost']) && $or['cust_cost'] > 0.00)) {
3914 $deftar_basecosts = $or['cust_cost'];
3915 } else {
3916 $deftar_basecosts = !empty($or['room_cost']) ? $or['room_cost'] : $tars[$num]['cost'];
3917 }
3918 $actopt[0]['cost'] = (int)$actopt[0]['pcentroom'] ? ($deftar_basecosts * $actopt[0]['cost'] / 100) : $actopt[0]['cost'];
3919 //
3920 $realcost = (intval($actopt[0]['perday']) == 1 ? ($actopt[0]['cost'] * $room_stay_nights * $stept[1]) : ($actopt[0]['cost'] * $stept[1]));
3921 }
3922 if (!empty($actopt[0]['maxprice']) && $actopt[0]['maxprice'] > 0 && $realcost > $actopt[0]['maxprice']) {
3923 $realcost = $actopt[0]['maxprice'];
3924 if (intval($actopt[0]['hmany']) == 1 && intval($stept[1]) > 1) {
3925 $realcost = $actopt[0]['maxprice'] * $stept[1];
3926 }
3927 }
3928 if ($actopt[0]['perperson'] == 1) {
3929 $realcost = $realcost * $or['adults'];
3930 }
3931 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt[0]['idiva']);
3932 $isdue += $tmpopr;
3933 $optstr[$num][] = ($stept[1] > 1 ? $stept[1] . " " : "") . $actopt[0]['name'] . ": " . $tmpopr . " " . $currencyname . "\n";
3934 }
3935 }
3936
3937 // custom extra costs
3938 if (!empty($or['extracosts'])) {
3939 $cur_extra_costs = json_decode($or['extracosts'], true);
3940 foreach ($cur_extra_costs as $eck => $ecv) {
3941 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
3942 $isdue += $ecplustax;
3943 $optstr[$num][] = $ecv['name'] . ": " . $ecplustax . " " . $currencyname."\n";
3944 }
3945 }
3946 }
3947
3948 // coupon
3949 $usedcoupon = false;
3950 $origisdue = $isdue;
3951 if (strlen($order['coupon']) > 0) {
3952 $usedcoupon = true;
3953 $expcoupon = explode(";", $order['coupon']);
3954 $isdue = $isdue - $expcoupon[1];
3955 }
3956
3957 // make sure to apply any previously refunded amount
3958 if ($order['refund'] > 0) {
3959 $isdue -= $order['refund'];
3960 }
3961
3962 // ConfirmationNumber
3963 $confirmnumber = VikBooking::generateConfirmNumber($order['id'], true);
3964
3965 $app->enqueueMessage(JText::translate('VBORDERSETASCONF'));
3966
3967 // notify the customer unless it was a re-confirmation
3968 $pskip = VikRequest::getInt('skip_notification', 0, 'request');
3969 if ($pskip < 1) {
3970 // send email notification to guest
3971 VikBooking::sendBookingEmail($order['id'], array('guest'));
3972
3973 // SMS skipping the administrator
3974 VikBooking::sendBookingSMS($order['id'], array('admin'));
3975 }
3976
3977 // Invoke Channel Manager
3978 $vcm_autosync = VikBooking::vcmAutoUpdate();
3979 if ($vcm_autosync > 0) {
3980 $vcm_obj = VikBooking::getVcmInvoker();
3981 $vcm_obj->setOids(array($order['id']))->setSyncType('new')->setOriginalStatuses(array($original_book_status));
3982 $sync_result = $vcm_obj->doSync();
3983 if ($sync_result === false) {
3984 $vcm_err = $vcm_obj->getError();
3985 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
3986 }
3987 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
3988 $vcm_sync_url = 'index.php?option=com_vikbooking&task=invoke_vcm&stype=new&cid[]='.$order['id'].'&returl='.urlencode('index.php?option=com_vikbooking&task=editorder&cid[]='.$order['id']);
3989 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
3990 }
3991
3992 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $oid);
3993 }
3994
3995 public function payments() {
3996 VikBookingHelper::printHeader("14");
3997
3998 VikRequest::setVar('view', VikRequest::getCmd('view', 'payments'));
3999
4000 parent::display();
4001
4002 if (VikBooking::showFooter()) {
4003 VikBookingHelper::printFooter();
4004 }
4005 }
4006
4007 public function newpayment() {
4008 VikBookingHelper::printHeader("14");
4009
4010 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
4011
4012 parent::display();
4013
4014 if (VikBooking::showFooter()) {
4015 VikBookingHelper::printFooter();
4016 }
4017 }
4018
4019 public function editpayment() {
4020 VikBookingHelper::printHeader("14");
4021
4022 VikRequest::setVar('view', VikRequest::getCmd('view', 'managepayment'));
4023
4024 parent::display();
4025
4026 if (VikBooking::showFooter()) {
4027 VikBookingHelper::printFooter();
4028 }
4029 }
4030
4031 public function createpayment() {
4032 if (!JSession::checkToken()) {
4033 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4034 }
4035 $mainframe = JFactory::getApplication();
4036 $pname = VikRequest::getString('name', '', 'request');
4037 $ppayment = VikRequest::getString('payment', '', 'request');
4038 $ppublished = VikRequest::getString('published', '', 'request');
4039 $pcharge = VikRequest::getFloat('charge', '', 'request');
4040 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4041 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4042 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4043 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4044 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWHTML);
4045 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4046 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4047 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4048 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4049 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4050 $plogo = VikRequest::getString('logo', '', 'request');
4051 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4052 $pidrooms = VikRequest::getVar('idrooms', array());
4053 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4054 $payparamarr = array();
4055 $payparamstr = '';
4056 if (count($vikpaymentparams) > 0) {
4057 foreach ($vikpaymentparams as $setting => $cont) {
4058 if (strlen($setting) > 0) {
4059 $payparamarr[$setting] = $cont;
4060 }
4061 }
4062 if (count($payparamarr) > 0) {
4063 $payparamstr = json_encode($payparamarr);
4064 }
4065 }
4066
4067 $dbo = JFactory::getDbo();
4068
4069 $set_idrooms = [];
4070 if (empty($pall_rooms) && !empty($pidrooms)) {
4071 $pidrooms = array_map(function($idroom) {
4072 return (int)$idroom;
4073 }, $pidrooms);
4074 foreach ($pidrooms as $idroom) {
4075 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4076 continue;
4077 }
4078 $set_idrooms[] = $idroom;
4079 }
4080 }
4081
4082 if (!empty($pname) && !empty($ppayment)) {
4083 $setpub = $ppublished == "1" ? 1 : 0;
4084 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4085 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4086 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment).";";
4087 $dbo->setQuery($q);
4088 $dbo->execute();
4089 if ($dbo->getNumRows() >= 0) {
4090 $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') . ");";
4091 $dbo->setQuery($q);
4092 $dbo->execute();
4093 $mainframe->enqueueMessage(JText::translate('VBPAYMENTSAVED'));
4094 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4095 } else {
4096 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4097 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4098 }
4099 } else {
4100 $mainframe->redirect("index.php?option=com_vikbooking&task=newpayment");
4101 }
4102 }
4103
4104 public function updatepayment()
4105 {
4106 if (!JSession::checkToken()) {
4107 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4108 }
4109
4110 $this->do_updatepayment($stay = false);
4111 }
4112
4113 public function updatepaymentstay()
4114 {
4115 if (!JSession::checkToken()) {
4116 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4117 }
4118
4119 $this->do_updatepayment($stay = true);
4120 }
4121
4122 protected function do_updatepayment($stay = false)
4123 {
4124 $mainframe = JFactory::getApplication();
4125
4126 $pwhere = VikRequest::getString('where', '', 'request');
4127 $pname = VikRequest::getString('name', '', 'request');
4128 $ppayment = VikRequest::getString('payment', '', 'request');
4129 $ppublished = VikRequest::getString('published', '', 'request');
4130 $pcharge = VikRequest::getFloat('charge', '', 'request');
4131 $psetconfirmed = VikRequest::getString('setconfirmed', '', 'request');
4132 $phidenonrefund = VikRequest::getInt('hidenonrefund', '', 'request');
4133 $ponlynonrefund = VikRequest::getInt('onlynonrefund', '', 'request');
4134 $pshownotealw = VikRequest::getString('shownotealw', '', 'request');
4135 $pnote = VikRequest::getString('note', '', 'request', VIKREQUEST_ALLOWRAW);
4136 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4137 $pval_pcent = !in_array($pval_pcent, array('1', '2')) ? 1 : $pval_pcent;
4138 $pch_disc = VikRequest::getString('ch_disc', '', 'request');
4139 $pch_disc = !in_array($pch_disc, array('1', '2')) ? 1 : $pch_disc;
4140 $poutposition = VikRequest::getString('outposition', 'top', 'request');
4141 $plogo = VikRequest::getString('logo', '', 'request');
4142 $pall_rooms = VikRequest::getInt('all_rooms', 0, 'request');
4143 $pidrooms = VikRequest::getVar('idrooms', array());
4144 $vikpaymentparams = VikRequest::getVar('vikpaymentparams', array(0));
4145 $payparamarr = array();
4146 $payparamstr = '';
4147 if (count($vikpaymentparams) > 0) {
4148 foreach ($vikpaymentparams as $setting => $cont) {
4149 if (strlen($setting) > 0) {
4150 $payparamarr[$setting] = $cont;
4151 }
4152 }
4153 if (count($payparamarr) > 0) {
4154 $payparamstr = json_encode($payparamarr);
4155 }
4156 }
4157
4158 $dbo = JFactory::getDbo();
4159
4160 $set_idrooms = [];
4161 if (empty($pall_rooms) && !empty($pidrooms)) {
4162 $pidrooms = array_map(function($idroom) {
4163 return (int)$idroom;
4164 }, $pidrooms);
4165 foreach ($pidrooms as $idroom) {
4166 if (empty($idroom) || in_array($idroom, $set_idrooms)) {
4167 continue;
4168 }
4169 $set_idrooms[] = $idroom;
4170 }
4171 }
4172
4173 if (!empty($pname) && !empty($ppayment) && !empty($pwhere)) {
4174 $setpub = $ppublished == "1" ? 1 : 0;
4175 $psetconfirmed = $psetconfirmed == "1" ? 1 : 0;
4176 $pshownotealw = $pshownotealw == "1" ? 1 : 0;
4177 $q = "SELECT `id` FROM `#__vikbooking_gpayments` WHERE `file`=".$dbo->quote($ppayment)." AND `id`!='".$pwhere."';";
4178 $dbo->setQuery($q);
4179 $dbo->execute();
4180 if ($dbo->getNumRows() >= 0) {
4181 $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).";";
4182 $dbo->setQuery($q);
4183 $dbo->execute();
4184
4185 $mainframe->enqueueMessage(JText::translate('VBPAYMENTUPDATED'));
4186 if ($stay) {
4187 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4188 } else {
4189 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4190 }
4191 } else {
4192 VikError::raiseWarning('', JText::translate('ERRINVFILEPAYMENT'));
4193 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4194 }
4195 } else {
4196 $mainframe->redirect("index.php?option=com_vikbooking&task=editpayment&cid[]=".$pwhere);
4197 }
4198 }
4199
4200 public function removepayments() {
4201 if (!JSession::checkToken()) {
4202 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4203 }
4204 $ids = VikRequest::getVar('cid', array(0));
4205 if (@count($ids)) {
4206 $dbo = JFactory::getDBO();
4207 foreach ($ids as $d) {
4208 $q = "DELETE FROM `#__vikbooking_gpayments` WHERE `id`=".$dbo->quote($d).";";
4209 $dbo->setQuery($q);
4210 $dbo->execute();
4211 }
4212 }
4213 $mainframe = JFactory::getApplication();
4214 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4215 }
4216
4217 public function modavailpayment() {
4218 if (!JSession::checkToken('get')) {
4219 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4220 }
4221 $cid = VikRequest::getVar('cid', array(0));
4222 $idp = $cid[0];
4223 if (!empty($idp)) {
4224 $dbo = JFactory::getDBO();
4225 $q = "SELECT `published` FROM `#__vikbooking_gpayments` WHERE `id`=".intval($idp).";";
4226 $dbo->setQuery($q);
4227 $dbo->execute();
4228 $get = $dbo->loadAssocList();
4229 $q = "UPDATE `#__vikbooking_gpayments` SET `published`=".(intval($get[0]['published']) == 1 ? '0' : '1')." WHERE `id`=".intval($idp).";";
4230 $dbo->setQuery($q);
4231 $dbo->execute();
4232 }
4233 $mainframe = JFactory::getApplication();
4234 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
4235 }
4236
4237 public function seasons() {
4238 VikBookingHelper::printHeader("13");
4239
4240 VikRequest::setVar('view', VikRequest::getCmd('view', 'seasons'));
4241
4242 parent::display();
4243
4244 if (VikBooking::showFooter()) {
4245 VikBookingHelper::printFooter();
4246 }
4247 }
4248
4249 public function newseason() {
4250 VikBookingHelper::printHeader("13");
4251
4252 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4253
4254 parent::display();
4255
4256 if (VikBooking::showFooter()) {
4257 VikBookingHelper::printFooter();
4258 }
4259 }
4260
4261 public function editseason() {
4262 VikBookingHelper::printHeader("13");
4263
4264 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageseason'));
4265
4266 parent::display();
4267
4268 if (VikBooking::showFooter()) {
4269 VikBookingHelper::printFooter();
4270 }
4271 }
4272
4273 public function updateseason()
4274 {
4275 if (!JSession::checkToken()) {
4276 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4277 }
4278 $this->do_updateseason();
4279 }
4280
4281 public function updateseasonstay()
4282 {
4283 if (!JSession::checkToken()) {
4284 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4285 }
4286 $this->do_updateseason(true);
4287 }
4288
4289 private function do_updateseason($stay = false)
4290 {
4291 $app = JFactory::getApplication();
4292 $dbo = JFactory::getDbo();
4293 $session = JFactory::getSession();
4294
4295 $pwhere = VikRequest::getInt('where', 0, 'request');
4296
4297 $pfrom = VikRequest::getString('from', '', 'request');
4298 $pto = VikRequest::getString('to', '', 'request');
4299 $ptype = VikRequest::getString('type', '', 'request');
4300 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4301 $pidrooms = VikRequest::getVar('idrooms', array());
4302 $pidprices = VikRequest::getVar('idprices', array());
4303 $pwdays = VikRequest::getVar('wdays', array());
4304 $pspname = VikRequest::getString('spname', '', 'request');
4305 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4306 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4307 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4308 $pyeartied = $pyeartied == 1 ? 1 : 0;
4309 $tieyear = 0;
4310 $ppromo = VikRequest::getInt('promo', 0, 'request');
4311 $ppromo = $ppromo == 1 ? 1 : 0;
4312 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4313 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4314 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4315 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4316 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4317 $proundmode = VikRequest::getString('roundmode', '', 'request');
4318 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4319 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4320 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4321 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4322 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4323 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4324 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4325 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4326 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4327 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4328 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4329 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4330 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4331 $occupancy_ovr = array();
4332 $losverridestr = "";
4333
4334 $updforvcm = $session->get('vbVcmRatesUpd', '');
4335 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4336
4337 // check null dates
4338 if ($dbo->getNullDate() == $pfrom) {
4339 $pfrom = '';
4340 }
4341 if ($dbo->getNullDate() == $pto) {
4342 $pto = '';
4343 }
4344
4345 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4346 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4347 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4348 exit;
4349 }
4350
4351 $skipseason = false;
4352 if (empty($pfrom) || empty($pto)) {
4353 $skipseason = true;
4354 }
4355 $skipdays = false;
4356 $wdaystr = null;
4357 if (count($pwdays) == 0) {
4358 $skipdays = true;
4359 } else {
4360 $wdaystr = "";
4361 foreach ($pwdays as $wd) {
4362 $wdaystr .= $wd.';';
4363 }
4364 }
4365 $roomstr = "";
4366 $roomids = array();
4367 foreach ($pidrooms as $room) {
4368 if (empty($room)) {
4369 continue;
4370 }
4371 $roomstr .= "-".$room."-,";
4372 $roomids[] = (int)$room;
4373 }
4374 $pricestr = "";
4375 $priceids = array();
4376 foreach ($pidprices as $price) {
4377 if (empty($price)) {
4378 continue;
4379 }
4380 $pricestr .= "-".$price."-,";
4381 $priceids[] = (int)$price;
4382 }
4383 $valid = true;
4384 $double_records = array();
4385 $sfrom = null;
4386 $sto = null;
4387
4388 // value overrides
4389 if ($pnightsoverrides && $pvaluesoverrides) {
4390 foreach ($pnightsoverrides as $ko => $no) {
4391 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4392 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4393 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4394 }
4395 }
4396 }
4397
4398 if (!$skipseason) {
4399 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4400 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4401
4402 if ($second > 0 && $second == $first) {
4403 $second += 86399;
4404 }
4405
4406 if (!($second > $first)) {
4407 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4408 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4409 exit;
4410 }
4411
4412 $baseone = getdate($first);
4413 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4414 $sfrom = $baseone[0] - $basets;
4415 $basetwo = getdate($second);
4416 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4417 $sto = $basetwo[0] - $basets;
4418
4419 // check leap year
4420 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4421 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4422 if ($baseone[0] > $leapts) {
4423 $sfrom -= 86400;
4424 /**
4425 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4426 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4427 *
4428 * @since July 2nd 2019
4429 */
4430 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4431 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4432 if ($basetwo[0] > $leapts) {
4433 $sto -= 86400;
4434 }
4435 }
4436 }
4437 }
4438
4439 // tied to the year
4440 if ($pyeartied == 1) {
4441 $tieyear = $baseone['year'];
4442 }
4443
4444 // Occupancy Override
4445 if (count($padultsdiffval) > 0) {
4446 foreach ($padultsdiffval as $rid => $valovr_arr) {
4447 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4448 continue;
4449 }
4450 foreach ($valovr_arr as $occ => $valovr) {
4451 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4452 continue;
4453 }
4454 if (!array_key_exists($rid, $occupancy_ovr)) {
4455 $occupancy_ovr[$rid] = array();
4456 }
4457 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4458 }
4459 }
4460 }
4461
4462 // check if seasons dates are valid
4463 $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").";";
4464 $dbo->setQuery($q);
4465 $similar = $dbo->loadAssocList();
4466 if ($similar) {
4467 $valid = false;
4468 foreach ($similar as $sim) {
4469 $double_records[] = $sim['spname'];
4470 }
4471 }
4472
4473 $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").";";
4474 $dbo->setQuery($q);
4475 $similar = $dbo->loadAssocList();
4476 if ($similar) {
4477 $valid = false;
4478 foreach ($similar as $sim) {
4479 $double_records[] = $sim['spname'];
4480 }
4481 }
4482
4483 $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").";";
4484 $dbo->setQuery($q);
4485 $dbo->execute();
4486 $similar = $dbo->loadAssocList();
4487 if ($similar) {
4488 $valid = false;
4489 foreach ($similar as $sim) {
4490 $double_records[] = $sim['spname'];
4491 }
4492 }
4493 }
4494
4495 // fetch previous record before the update
4496 $q = $dbo->getQuery(true)
4497 ->select('*')
4498 ->from($dbo->qn('#__vikbooking_seasons'))
4499 ->where($dbo->qn('id') . ' = ' . $pwhere);
4500 $dbo->setQuery($q, 0, 1);
4501 $prev_record = $dbo->loadAssoc();
4502
4503 if (!$valid || !$prev_record) {
4504 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').($double_records ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4505 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4506 exit;
4507 }
4508
4509 /**
4510 * Attempt to access the promotion handlers in advance to perform additional validations.
4511 *
4512 * @since 1.16.4 (J) - 1.6.4 (WP)
4513 */
4514 try {
4515 $promo_handlers = VikBooking::getPromotionHandlers();
4516 } catch (Exception $e) {
4517 // reset the value
4518 $promo_handlers = [];
4519 }
4520
4521 if (!$prev_record['promo'] && $ppromo && $promo_handlers) {
4522 // channels supporting promotions are available, and a regular special price is
4523 // being converted into a promotion - this is not allowed so we make it a non-promotion.
4524 $ppromo = 0;
4525 $app->enqueueMessage(JText::translate('VBO_NOPROMO_UPD_CHANNELS'), 'warning');
4526 }
4527
4528 // update record
4529 $upd_record = new stdClass;
4530 $upd_record->id = $prev_record['id'];
4531 $upd_record->type = $ptype == "1" ? 1 : 2;
4532 $upd_record->from = $sfrom;
4533 $upd_record->to = $sto;
4534 $upd_record->diffcost = $pdiffcost;
4535 $upd_record->idrooms = $roomstr;
4536 $upd_record->spname = $pspname;
4537 $upd_record->wdays = $wdaystr;
4538 $upd_record->checkinincl = $pcheckinincl;
4539 $upd_record->val_pcent = $pval_pcent;
4540 $upd_record->losoverride = $losverridestr;
4541 $upd_record->roundmode = !empty($proundmode) ? $proundmode : null;
4542 $upd_record->year = $pyeartied == 1 ? $tieyear : null;
4543 $upd_record->idprices = $pricestr;
4544 $upd_record->promo = $ppromo;
4545 $upd_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4546 $upd_record->promotxt = $ppromotxt;
4547 $upd_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4548 $upd_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4549 $upd_record->promolastmin = (int)$promolastmin;
4550 $upd_record->promofinalprice = $ppromofinalprice;
4551
4552 $dbo->updateObject('#__vikbooking_seasons', $upd_record, 'id', $nulls = true);
4553
4554 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
4555
4556 // update session values
4557 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4558 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4559 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4560 } else {
4561 $updforvcm['dfrom'] = $first;
4562 }
4563 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4564 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4565 } else {
4566 $updforvcm['dto'] = $second;
4567 }
4568 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4569 foreach ($roomids as $rid) {
4570 if (!in_array($rid, $updforvcm['rooms'])) {
4571 $updforvcm['rooms'][] = $rid;
4572 }
4573 }
4574 } else {
4575 $updforvcm['rooms'] = $roomids;
4576 }
4577 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4578 foreach ($roomids as $rid) {
4579 if (array_key_exists($rid, $updforvcm['rplans'])) {
4580 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4581 } else {
4582 $updforvcm['rplans'][$rid] = $priceids;
4583 }
4584 }
4585 } else {
4586 $updforvcm['rplans'] = array();
4587 foreach ($roomids as $rid) {
4588 $updforvcm['rplans'][$rid] = $priceids;
4589 }
4590 }
4591 $session->set('vbVcmRatesUpd', $updforvcm);
4592
4593 /**
4594 * Query promotion handlers, if any, to trigger the update/delete promotion event.
4595 *
4596 * @since 1.15.0 (J) - 1.5.0 (WP)
4597 * @since 1.16.4 (J) - 1.6.4 (WP) added control to perform a delete operation.
4598 */
4599 $promo_update_type = $prev_record['promo'] && !$ppromo ? 'triggerDelete' : 'triggerUpdate';
4600 $promo_method_type = $prev_record['promo'] && !$ppromo ? 'delete' : 'update';
4601 try {
4602 if ($ppromo && is_array($promo_handlers) && $promo_handlers) {
4603 foreach ($promo_handlers as $promo_handler) {
4604 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, $promo_update_type)) {
4605 // outdated handler object
4606 continue;
4607 }
4608 if (!is_callable(array($promo_handler->instance, $promo_update_type)) || !$promo_handler->instance->{$promo_update_type}()) {
4609 // promotion handler does not support update/delete promotion event
4610 continue;
4611 }
4612 // invoke the update/delete promotion event for this handler
4613 $ch_result = $promo_handler->instance->createPromotion(['vbo_promo_id' => $pwhere], $promo_method_type);
4614 if (!$ch_result) {
4615 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
4616 }
4617 }
4618 }
4619 } catch (Exception $e) {
4620 // do nothing
4621 }
4622
4623 if ($stay) {
4624 $app->redirect("index.php?option=com_vikbooking&task=editseason&cid[]=" . $pwhere);
4625 } else {
4626 $app->redirect("index.php?option=com_vikbooking&task=seasons");
4627 }
4628 $app->close();
4629 }
4630
4631 public function createseason()
4632 {
4633 if (!JSession::checkToken()) {
4634 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4635 }
4636 $this->do_createseason();
4637 }
4638
4639 public function createseason_new()
4640 {
4641 if (!JSession::checkToken()) {
4642 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4643 }
4644 $this->do_createseason(true);
4645 }
4646
4647 private function do_createseason($andnew = false)
4648 {
4649 $app = JFactory::getApplication();
4650 $dbo = JFactory::getDbo();
4651 $session = JFactory::getSession();
4652
4653 $pfrom = VikRequest::getString('from', '', 'request');
4654 $pto = VikRequest::getString('to', '', 'request');
4655 $ptype = VikRequest::getString('type', '', 'request');
4656 $pdiffcost = VikRequest::getFloat('diffcost', '', 'request');
4657 $pidrooms = VikRequest::getVar('idrooms', array());
4658 $pidprices = VikRequest::getVar('idprices', array());
4659 $pwdays = VikRequest::getVar('wdays', array());
4660 $pspname = VikRequest::getString('spname', '', 'request');
4661 $pcheckinincl = VikRequest::getString('checkinincl', '', 'request');
4662 $pcheckinincl = $pcheckinincl == 1 ? 1 : 0;
4663 $pyeartied = VikRequest::getInt('yeartied', 0, 'request');
4664 $pyeartied = $pyeartied == 1 ? 1 : 0;
4665 $tieyear = 0;
4666 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4667 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4668 $proundmode = VikRequest::getString('roundmode', '', 'request');
4669 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4670 $ppromo = VikRequest::getInt('promo', 0, 'request');
4671 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4672 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4673 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4674 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4675 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4676 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4677 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4678 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4679 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4680 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4681 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4682 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4683 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4684 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4685 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4686 $pchannels = VikRequest::getVar('channels', array());
4687 $occupancy_ovr = array();
4688 $losverridestr = "";
4689
4690 $updforvcm = $session->get('vbVcmRatesUpd', '');
4691 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4692
4693 // check null dates
4694 if ($dbo->getNullDate() == $pfrom) {
4695 $pfrom = '';
4696 }
4697 if ($dbo->getNullDate() == $pto) {
4698 $pto = '';
4699 }
4700
4701 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4702 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4703 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4704 exit;
4705 }
4706
4707 $skipseason = false;
4708 if (empty($pfrom) || empty($pto)) {
4709 $skipseason = true;
4710 }
4711 $skipdays = false;
4712 $wdaystr = null;
4713 if (!$pwdays) {
4714 $skipdays = true;
4715 } else {
4716 $wdaystr = "";
4717 foreach ($pwdays as $wd) {
4718 $wdaystr .= $wd.';';
4719 }
4720 }
4721 $roomstr = "";
4722 $roomids = array();
4723 foreach ($pidrooms as $room) {
4724 if (empty($room)) {
4725 continue;
4726 }
4727 $roomstr .= "-".$room."-,";
4728 $roomids[] = (int)$room;
4729 }
4730 $pricestr = "";
4731 $priceids = array();
4732 foreach ($pidprices as $price) {
4733 if (empty($price)) {
4734 continue;
4735 }
4736 $pricestr .= "-".$price."-,";
4737 $priceids[] = (int)$price;
4738 }
4739 $valid = true;
4740 $double_records = array();
4741 $sfrom = null;
4742 $sto = null;
4743
4744 // value overrides
4745 if ($pnightsoverrides && $pvaluesoverrides) {
4746 foreach ($pnightsoverrides as $ko => $no) {
4747 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4748 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4749 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4750 }
4751 }
4752 }
4753
4754 if (!$skipseason) {
4755 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4756 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4757
4758 if ($second > 0 && $second == $first) {
4759 $second += 86399;
4760 }
4761
4762 if (!($second > $first)) {
4763 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4764 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4765 exit;
4766 }
4767
4768 $baseone = getdate($first);
4769 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4770 $sfrom = $baseone[0] - $basets;
4771 $basetwo = getdate($second);
4772 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4773 $sto = $basetwo[0] - $basets;
4774
4775 // check leap year
4776 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4777 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4778 if ($baseone[0] > $leapts) {
4779 $sfrom -= 86400;
4780 /**
4781 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4782 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4783 *
4784 * @since July 2nd 2019
4785 */
4786 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4787 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4788 if ($basetwo[0] > $leapts) {
4789 $sto -= 86400;
4790 }
4791 }
4792 }
4793 }
4794
4795 // tied to the year
4796 if ($pyeartied == 1) {
4797 $tieyear = $baseone['year'];
4798 }
4799
4800 // Occupancy Override
4801 if ($padultsdiffval) {
4802 foreach ($padultsdiffval as $rid => $valovr_arr) {
4803 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4804 continue;
4805 }
4806 foreach ($valovr_arr as $occ => $valovr) {
4807 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4808 continue;
4809 }
4810 if (!array_key_exists($rid, $occupancy_ovr)) {
4811 $occupancy_ovr[$rid] = array();
4812 }
4813 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4814 }
4815 }
4816 }
4817
4818 // check if seasons dates are valid
4819 $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").";";
4820 $dbo->setQuery($q);
4821 $similar = $dbo->loadAssocList();
4822 if ($similar) {
4823 $valid = false;
4824 foreach ($similar as $sim) {
4825 $double_records[] = $sim['spname'];
4826 }
4827 }
4828
4829 $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").";";
4830 $dbo->setQuery($q);
4831 $similar = $dbo->loadAssocList();
4832 if ($similar) {
4833 $valid = false;
4834 foreach ($similar as $sim) {
4835 $double_records[] = $sim['spname'];
4836 }
4837 }
4838
4839 $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").";";
4840 $dbo->setQuery($q);
4841 $similar = $dbo->loadAssocList();
4842 if ($similar) {
4843 $valid = false;
4844 foreach ($similar as $sim) {
4845 $double_records[] = $sim['spname'];
4846 }
4847 }
4848 }
4849
4850 if (!$valid && !$ppromo) {
4851 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').(count($double_records) ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4852 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4853 exit;
4854 }
4855
4856 // insert new record
4857 $sea_record = new stdClass;
4858 $sea_record->type = $ptype == "1" ? 1 : 2;
4859 $sea_record->from = $sfrom;
4860 $sea_record->to = $sto;
4861 $sea_record->diffcost = $pdiffcost;
4862 $sea_record->idrooms = $roomstr;
4863 $sea_record->spname = $pspname;
4864 $sea_record->wdays = $wdaystr;
4865 $sea_record->checkinincl = $pcheckinincl;
4866 $sea_record->val_pcent = $pval_pcent;
4867 $sea_record->losoverride = $losverridestr;
4868 $sea_record->roundmode = !empty($proundmode) ? $proundmode : null;
4869 $sea_record->year = $pyeartied == 1 ? $tieyear : null;
4870 $sea_record->idprices = $pricestr;
4871 $sea_record->promo = $ppromo == 1 ? 1 : 0;
4872 $sea_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4873 $sea_record->promotxt = $ppromotxt;
4874 $sea_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4875 $sea_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4876 $sea_record->promolastmin = (int)$promolastmin;
4877 $sea_record->promofinalprice = $ppromofinalprice;
4878
4879 $dbo->insertObject('#__vikbooking_seasons', $sea_record, 'id');
4880
4881 $vbo_promo_id = $sea_record->id;
4882
4883 $app->enqueueMessage(JText::translate('VBSEASONSAVED'));
4884
4885 // update session values
4886 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4887 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4888 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4889 } else {
4890 $updforvcm['dfrom'] = $first;
4891 }
4892 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4893 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4894 } else {
4895 $updforvcm['dto'] = $second;
4896 }
4897 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4898 foreach ($roomids as $rid) {
4899 if (!in_array($rid, $updforvcm['rooms'])) {
4900 $updforvcm['rooms'][] = $rid;
4901 }
4902 }
4903 } else {
4904 $updforvcm['rooms'] = $roomids;
4905 }
4906 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4907 foreach ($roomids as $rid) {
4908 if (array_key_exists($rid, $updforvcm['rplans'])) {
4909 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4910 } else {
4911 $updforvcm['rplans'][$rid] = $priceids;
4912 }
4913 }
4914 } else {
4915 $updforvcm['rplans'] = array();
4916 foreach ($roomids as $rid) {
4917 $updforvcm['rplans'][$rid] = $priceids;
4918 }
4919 }
4920 if (!$ppromo) {
4921 $session->set('vbVcmRatesUpd', $updforvcm);
4922 }
4923
4924 /**
4925 * Create the promotion also on the selected channels
4926 *
4927 * @since 1.13.0 (J) - 1.3.0 (WP)
4928 */
4929 if ($ppromo && $pchannels) {
4930 foreach ($pchannels as $channel_key) {
4931 $promo_obj = VikBooking::getPromotionHandlers($channel_key);
4932 if (!is_object($promo_obj)) {
4933 continue;
4934 }
4935 /**
4936 * We inject for VCM the ID of the newly created promotion in VBO.
4937 *
4938 * @since 1.15.0 (J) - 1.5.0 (WP)
4939 */
4940 $ch_result = $promo_obj->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'new');
4941 if (!$ch_result) {
4942 VikError::raiseWarning('', $promo_obj->getName() . ': ' . $promo_obj->getError());
4943 } else {
4944 $resp = $promo_obj->getResponse();
4945 $app->enqueueMessage($promo_obj->getName() . ': ' . JText::translate('VBOCHPROMOSUCCESS') . (!empty($resp) ? ' (' . str_replace('e4j.ok.', '', $resp) . ')' : ''));
4946 // in case of success, unset the current session values in VCM
4947 $session->set('vcmBPromo', '');
4948 }
4949 }
4950 }
4951
4952 $app->redirect("index.php?option=com_vikbooking&task=".($andnew ? 'newseason' : 'seasons'));
4953 $app->close();
4954 }
4955
4956 public function removeseasons()
4957 {
4958 if (!JSession::checkToken()) {
4959 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4960 }
4961 $app = JFactory::getApplication();
4962 $dbo = JFactory::getDbo();
4963
4964 $ids = VikRequest::getVar('cid', array(0));
4965 $pidroom = VikRequest::getInt('idroom', '', 'request');
4966 $pwhere = VikRequest::getInt('where', '', 'request');
4967 if (!empty($pwhere)) {
4968 $ids[] = $pwhere;
4969 }
4970 $tot_removed = array();
4971 $prev_promos = array();
4972 foreach ($ids as $d) {
4973 if (empty($d)) {
4974 continue;
4975 }
4976 // check if it was a promotion
4977 $q = "SELECT `id` FROM `#__vikbooking_seasons` WHERE `id`=" . (int)$d . " AND `promo`=1;";
4978 $dbo->setQuery($q);
4979 $dbo->execute();
4980 if ($dbo->getNumRows()) {
4981 // push it as a previous promo
4982 array_push($prev_promos, $d);
4983 }
4984
4985 // delete the record
4986 $q = "DELETE FROM `#__vikbooking_seasons` WHERE `id`=".$dbo->quote($d).";";
4987 $dbo->setQuery($q);
4988 $dbo->execute();
4989 $tot_removed[] = $d;
4990 }
4991
4992 /**
4993 * Query promotion handlers, if any, to trigger the delete promotion event.
4994 *
4995 * @since 1.15.0 (J) - 1.5.0 (WP)
4996 */
4997 $promo_handlers = VikBooking::getPromotionHandlers();
4998 foreach ($prev_promos as $vbo_promo_id) {
4999 try {
5000 if (is_array($promo_handlers)) {
5001 foreach ($promo_handlers as $promo_handler) {
5002 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, 'triggerDelete')) {
5003 // outdated handler object
5004 continue;
5005 }
5006 if (!is_callable(array($promo_handler->instance, 'triggerDelete')) || !$promo_handler->instance->triggerDelete()) {
5007 // promotion handler does not support delete promotion event
5008 continue;
5009 }
5010 // invoke the delete promotion event for this handler
5011 $ch_result = $promo_handler->instance->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'delete');
5012 if (!$ch_result) {
5013 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
5014 }
5015 }
5016 }
5017 } catch (Exception $e) {
5018 // do nothing
5019 }
5020 }
5021
5022 $app->enqueueMessage(JText::sprintf('VBRECORDSREMOVED', count($tot_removed)));
5023 $app->redirect("index.php?option=com_vikbooking&task=seasons".(!empty($pidroom) ? '&idroom='.$pidroom : ''));
5024 $app->close();
5025 }
5026
5027 public function updatecustomer() {
5028 if (!JSession::checkToken()) {
5029 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5030 }
5031 $this->do_updatecustomer();
5032 }
5033
5034 public function updatecustomerstay() {
5035 if (!JSession::checkToken()) {
5036 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5037 }
5038 $this->do_updatecustomer(true);
5039 }
5040
5041 private function do_updatecustomer($stay = false) {
5042 $dbo = JFactory::getDbo();
5043 $mainframe = JFactory::getApplication();
5044 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5045 $plast_name = VikRequest::getString('last_name', '', 'request');
5046 $pcompany = VikRequest::getString('company', '', 'request');
5047 $pvat = VikRequest::getString('vat', '', 'request');
5048 $pemail = VikRequest::getString('email', '', 'request');
5049 $pphone = VikRequest::getString('phone', '', 'request');
5050 $pcountry = VikRequest::getString('country', '', 'request');
5051 $pstate = VikRequest::getString('state', '', 'request');
5052 $ppin = VikRequest::getString('pin', '', 'request');
5053 $pujid = VikRequest::getInt('ujid', '', 'request');
5054 $paddress = VikRequest::getString('address', '', 'request');
5055 $pcity = VikRequest::getString('city', '', 'request');
5056 $pzip = VikRequest::getString('zip', '', 'request');
5057 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5058 $ppec = VikRequest::getString('pec', '', 'request');
5059 $precipcode = VikRequest::getString('recipcode', '', 'request');
5060 $pgender = VikRequest::getString('gender', '', 'request');
5061 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5062 $pbdate = VikRequest::getString('bdate', '', 'request');
5063 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5064 $pdoctype = VikRequest::getString('doctype', '', 'request');
5065 $pdocnum = VikRequest::getString('docnum', '', 'request');
5066 $pnotes = VikRequest::getString('notes', '', 'request');
5067 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5068 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5069 $pcommission = VikRequest::getFloat('commission', '', 'request');
5070 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5071 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5072 $pchname = VikRequest::getString('chname', '', 'request');
5073 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5074 $pwhere = VikRequest::getInt('where', '', 'request');
5075 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5076 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5077 $pbid = VikRequest::getInt('bid', '', 'request');
5078 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5079 if (!empty($pwhere) && !empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5080 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `id`=".(int)$pwhere." LIMIT 1;";
5081 $dbo->setQuery($q);
5082 $dbo->execute();
5083 if ($dbo->getNumRows() == 1) {
5084 $customer = $dbo->loadAssoc();
5085 } else {
5086 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5087 exit;
5088 }
5089 /**
5090 * Existing customers are recognized by equal first name, last name and email address.
5091 *
5092 * @since 1.3.0
5093 */
5094 $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;";
5095 $dbo->setQuery($q);
5096 $dbo->execute();
5097 if ($dbo->getNumRows() == 0) {
5098 $cpin = VikBooking::getCPinIstance();
5099 if (empty($ppin)) {
5100 $ppin = $customer['pin'];
5101 } elseif ($cpin->pinExists($ppin, $customer['pin'])) {
5102 $ppin = $cpin->generateUniquePin();
5103 }
5104 //file upload
5105 jimport('joomla.filesystem.file');
5106 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5107 $gimg = "";
5108 if (isset($pimg) && strlen(trim($pimg['name']))) {
5109 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5110 $src = $pimg['tmp_name'];
5111 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5112 $j = "";
5113 if (file_exists($dest.$filename)) {
5114 $j = rand(171, 1717);
5115 while (file_exists($dest.$j.$filename)) {
5116 $j++;
5117 }
5118 }
5119 $finaldest = $dest.$j.$filename;
5120 $check = getimagesize($pimg['tmp_name']);
5121 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5122 if (VikBooking::uploadFile($src, $finaldest)) {
5123 $gimg = $j.$filename;
5124 } else {
5125 VikError::raiseWarning('', 'Error while uploading image');
5126 }
5127 } else {
5128 VikError::raiseWarning('', 'Uploaded file is not an Image');
5129 }
5130 } elseif (!empty($pscandocimg)) {
5131 $gimg = $pscandocimg;
5132 }
5133 //
5134 $pischannel = $pischannel > 0 ? 1 : 0;
5135 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5136 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5137 $pchname = str_replace(' ', '', trim($pchname));
5138 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5139 $chparams = array(
5140 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5141 'calccmmon' => $pcalccmmon,
5142 'applycmmon' => $papplycmmon,
5143 'chcolor' => $pchcolor,
5144 'chname' => $pchname
5145 );
5146
5147 /**
5148 * Customer profile picture (URL or uploaded file).
5149 *
5150 * @since 1.15.3 (J) - 1.5.5 (WP)
5151 */
5152 $customer_pic = VikRequest::getString('pic', '', 'request');
5153 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5154 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5155 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5156 $src = $customer_pic_img['tmp_name'];
5157 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5158 $j = "";
5159 if (is_file($dest.$filename)) {
5160 $j = rand(1, 99999);
5161 while (is_file($dest . $j .$filename)) {
5162 $j++;
5163 }
5164 }
5165 $finaldest = $dest . $j . $filename;
5166 $check = getimagesize($customer_pic_img['tmp_name']);
5167 if (($check[2] & imagetypes())) {
5168 if (VikBooking::uploadFile($src, $finaldest)) {
5169 $customer_pic = $j . $filename;
5170 } else {
5171 VikError::raiseWarning('', 'Error while uploading image');
5172 }
5173 } else {
5174 VikError::raiseWarning('', 'Uploaded file is not an Image');
5175 }
5176 }
5177
5178 // update customer object
5179 $new_customer = new stdClass;
5180 $new_customer->id = (int)$pwhere;
5181 $new_customer->first_name = $pfirst_name;
5182 $new_customer->last_name = $plast_name;
5183 $new_customer->email = $pemail;
5184 $new_customer->phone = $pphone;
5185 $new_customer->country = $pcountry;
5186 $new_customer->pin = $ppin;
5187 $new_customer->ujid = $pujid;
5188 $new_customer->address = $paddress;
5189 $new_customer->city = $pcity;
5190 $new_customer->zip = $pzip;
5191 $new_customer->state = $pstate;
5192 $new_customer->doctype = $pdoctype;
5193 $new_customer->docnum = $pdocnum;
5194 if (!empty($gimg)) {
5195 $new_customer->docimg = $gimg;
5196 }
5197 $new_customer->notes = $pnotes;
5198 $new_customer->ischannel = $pischannel;
5199 $new_customer->chdata = json_encode($chparams);
5200 $new_customer->company = $pcompany;
5201 $new_customer->vat = $pvat;
5202 $new_customer->gender = $pgender;
5203 $new_customer->bdate = $pbdate;
5204 $new_customer->pbirth = $ppbirth;
5205 $new_customer->fisccode = $pfisccode;
5206 $new_customer->pec = $ppec;
5207 $new_customer->recipcode = $precipcode;
5208 $new_customer->pic = $customer_pic;
5209 /**
5210 * We need to update the previous information stored through
5211 * the custom fields when making a reservation for/by this client.
5212 *
5213 * @since 1.13
5214 */
5215 $skip_prev_fields = array(
5216 'id',
5217 'ujid',
5218 'docimg',
5219 'ischannel',
5220 'chdata',
5221 'notes',
5222 );
5223 if (!empty($customer['cfields'])) {
5224 $custf_info = json_decode($customer['cfields'], true);
5225 foreach ($new_customer as $fname => $fnewval) {
5226 if (!isset($customer[$fname]) || in_array($fname, $skip_prev_fields)) {
5227 continue;
5228 }
5229 // seek for old value in custom fields submitted
5230 foreach ($custf_info as $k => $v) {
5231 if (!empty($customer[$fname]) && $v == $customer[$fname]) {
5232 // field found, replace it with the new value
5233 $custf_info[$k] = $fnewval;
5234 }
5235 }
5236 }
5237 // update record on db
5238 $new_customer->cfields = json_encode($custf_info);
5239 }
5240 //
5241
5242 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5243
5244 $cpin->pluginCustomerSync($pwhere, 'update');
5245 //Update all the bookings affected by this Customer ID as a sales channel
5246 $source_name = 'customer'.$pwhere.'_'.$pchname;
5247 if ($pischannel > 0) {
5248 $oid_clause = '';
5249 if ($customer['ischannel'] < 1) {
5250 //Was not a sales channel but now it is, so update all his bookings
5251 $q = "SELECT `idorder` FROM `#__vikbooking_customers_orders` WHERE `idcustomer`=".$customer['id'].";";
5252 $dbo->setQuery($q);
5253 $dbo->execute();
5254 if ($dbo->getNumRows() > 0) {
5255 $all_bids = $dbo->loadAssocList();
5256 $bids = array();
5257 foreach ($all_bids as $bid) {
5258 if (!in_array($bid['idorder'], $bids)) {
5259 $bids[] = $bid['idorder'];
5260 }
5261 }
5262 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5263 }
5264 }
5265 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5266 } else {
5267 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5268 }
5269 $dbo->setQuery($q);
5270 $dbo->execute();
5271 //
5272 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5273 } else {
5274 //email already exists
5275 $ex_customer = $dbo->loadAssoc();
5276 //check if coming from the Check-in view or not
5277 if (!empty($pcheckin) && !empty($pbid)) {
5278 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5279 /**
5280 * @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
5281 */
5282 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5283 //
5284 exit;
5285 } elseif (!empty($pgoto)) {
5286 // check if coming from a specific task
5287 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5288 $mainframe->redirect(base64_decode($pgoto));
5289 exit;
5290 } else {
5291 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>');
5292 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5293 exit;
5294 }
5295 }
5296 }
5297
5298 //check if coming from the Check-in view
5299 if (!empty($pcheckin) && !empty($pbid)) {
5300 /**
5301 * @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
5302 */
5303 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5304 exit;
5305 }
5306
5307 if ($stay) {
5308 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5309 exit;
5310 }
5311
5312 // check if coming from a specific task
5313 if (!empty($pgoto)) {
5314 $mainframe->redirect(base64_decode($pgoto));
5315 exit;
5316 }
5317
5318 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5319 }
5320
5321 public function savecustomer() {
5322 if (!JSession::checkToken()) {
5323 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5324 }
5325 $dbo = JFactory::getDbo();
5326 $mainframe = JFactory::getApplication();
5327 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5328 $plast_name = VikRequest::getString('last_name', '', 'request');
5329 $pcompany = VikRequest::getString('company', '', 'request');
5330 $pvat = VikRequest::getString('vat', '', 'request');
5331 $pemail = VikRequest::getString('email', '', 'request');
5332 $pphone = VikRequest::getString('phone', '', 'request');
5333 $pcountry = VikRequest::getString('country', '', 'request');
5334 $pstate = VikRequest::getString('state', '', 'request');
5335 $ppin = VikRequest::getString('pin', '', 'request');
5336 $pujid = VikRequest::getInt('ujid', '', 'request');
5337 $paddress = VikRequest::getString('address', '', 'request');
5338 $pcity = VikRequest::getString('city', '', 'request');
5339 $pzip = VikRequest::getString('zip', '', 'request');
5340 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5341 $ppec = VikRequest::getString('pec', '', 'request');
5342 $precipcode = VikRequest::getString('recipcode', '', 'request');
5343 $pgender = VikRequest::getString('gender', '', 'request');
5344 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5345 $pbdate = VikRequest::getString('bdate', '', 'request');
5346 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5347 $pdoctype = VikRequest::getString('doctype', '', 'request');
5348 $pdocnum = VikRequest::getString('docnum', '', 'request');
5349 $pnotes = VikRequest::getString('notes', '', 'request');
5350 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5351 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5352 $pcommission = VikRequest::getFloat('commission', '', 'request');
5353 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5354 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5355 $pchname = VikRequest::getString('chname', '', 'request');
5356 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5357 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5358 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5359 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5360 $pbid = VikRequest::getInt('bid', '', 'request');
5361 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5362 $cpin = VikBooking::getCPinIstance();
5363 /**
5364 * Existing customers are recognized by equal first name, last name and email address.
5365 *
5366 * @since 1.3.0
5367 */
5368 $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;";
5369 $dbo->setQuery($q);
5370 $dbo->execute();
5371 if ($dbo->getNumRows() == 0) {
5372 if (empty($ppin)) {
5373 $ppin = $cpin->generateUniquePin();
5374 } elseif ($cpin->pinExists($ppin)) {
5375 $ppin = $cpin->generateUniquePin();
5376 }
5377 //file upload
5378 jimport('joomla.filesystem.file');
5379 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5380 $gimg = "";
5381 if (isset($pimg) && strlen(trim($pimg['name']))) {
5382 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5383 $src = $pimg['tmp_name'];
5384 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5385 $j = "";
5386 if (file_exists($dest.$filename)) {
5387 $j = rand(171, 1717);
5388 while (file_exists($dest.$j.$filename)) {
5389 $j++;
5390 }
5391 }
5392 $finaldest = $dest.$j.$filename;
5393 $check = getimagesize($pimg['tmp_name']);
5394 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5395 if (VikBooking::uploadFile($src, $finaldest)) {
5396 $gimg = $j.$filename;
5397 } else {
5398 VikError::raiseWarning('', 'Error while uploading image');
5399 }
5400 } else {
5401 VikError::raiseWarning('', 'Uploaded file is not an Image');
5402 }
5403 } elseif (!empty($pscandocimg)) {
5404 $gimg = $pscandocimg;
5405 }
5406 //
5407 $pischannel = $pischannel > 0 ? 1 : 0;
5408 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5409 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5410 $pchname = str_replace(' ', '', trim($pchname));
5411 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5412 $chparams = array(
5413 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5414 'calccmmon' => $pcalccmmon,
5415 'applycmmon' => $papplycmmon,
5416 'chcolor' => $pchcolor,
5417 'chname' => $pchname
5418 );
5419
5420 /**
5421 * Customer profile picture (URL or uploaded file).
5422 *
5423 * @since 1.15.3 (J) - 1.5.5 (WP)
5424 */
5425 $customer_pic = VikRequest::getString('pic', '', 'request');
5426 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5427 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5428 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5429 $src = $customer_pic_img['tmp_name'];
5430 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5431 $j = "";
5432 if (is_file($dest.$filename)) {
5433 $j = rand(1, 99999);
5434 while (is_file($dest . $j .$filename)) {
5435 $j++;
5436 }
5437 }
5438 $finaldest = $dest . $j . $filename;
5439 $check = getimagesize($customer_pic_img['tmp_name']);
5440 if (($check[2] & imagetypes())) {
5441 if (VikBooking::uploadFile($src, $finaldest)) {
5442 $customer_pic = $j . $filename;
5443 } else {
5444 VikError::raiseWarning('', 'Error while uploading image');
5445 }
5446 } else {
5447 VikError::raiseWarning('', 'Uploaded file is not an Image');
5448 }
5449 }
5450
5451 $q = "INSERT INTO `#__vikbooking_customers` (`first_name`,`last_name`,`email`,`phone`,`country`,`pin`,`ujid`,`address`,`city`,`zip`,`state`,`doctype`,`docnum`,`docimg`,`notes`,`ischannel`,`chdata`,`company`,`vat`,`gender`,`bdate`,`pbirth`,`fisccode`,`pec`,`recipcode`,`pic`) VALUES(".$dbo->quote($pfirst_name).", ".$dbo->quote($plast_name).", ".$dbo->quote($pemail).", ".$dbo->quote($pphone).", ".$dbo->quote($pcountry).", ".$dbo->quote($ppin).", ".$dbo->quote($pujid).", ".$dbo->quote($paddress).", ".$dbo->quote($pcity).", ".$dbo->quote($pzip).", ".$dbo->quote($pstate).", ".$dbo->quote($pdoctype).", ".$dbo->quote($pdocnum).", ".$dbo->quote($gimg).", ".$dbo->quote($pnotes).", ".$pischannel.", ".$dbo->quote(json_encode($chparams)).", ".$dbo->quote($pcompany).", ".$dbo->quote($pvat).", ".$dbo->quote($pgender).", ".$dbo->quote($pbdate).", ".$dbo->quote($ppbirth).", ".$dbo->quote($pfisccode).", ".$dbo->quote($ppec).", ".$dbo->quote($precipcode).", " . (!empty($customer_pic) ? $dbo->quote($customer_pic) : 'NULL') . ");";
5452 $dbo->setQuery($q);
5453 $dbo->execute();
5454 $lid = $dbo->insertid();
5455 $cpin->pluginCustomerSync($lid, 'insert');
5456 if (!empty($lid)) {
5457 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5458 //check if coming from the Check-in view
5459 if (!empty($pcheckin) && !empty($pbid)) {
5460 $cpin->setNewPin($ppin);
5461 $cpin->setNewCustomerId($lid);
5462 $cpin->saveCustomerBooking($pbid);
5463 /**
5464 * @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
5465 */
5466 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5467 //
5468 exit;
5469 }
5470 // check if coming from a specific task
5471 if (!empty($pgoto) && !empty($pbid)) {
5472 $cpin->setNewPin($ppin);
5473 $cpin->setNewCustomerId($lid);
5474 $cpin->saveCustomerBooking($pbid);
5475 $mainframe->redirect(base64_decode($pgoto));
5476 exit;
5477 }
5478 }
5479 } else {
5480 //email already exists
5481 $ex_customer = $dbo->loadAssoc();
5482 //check if coming from the Check-in view or not
5483 if (!empty($pcheckin) && !empty($pbid)) {
5484 $cpin->setNewPin($ex_customer['pin']);
5485 $cpin->setNewCustomerId($ex_customer['id']);
5486 $cpin->saveCustomerBooking($pbid);
5487 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5488 /**
5489 * @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
5490 */
5491 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5492 //
5493 exit;
5494 } elseif (!empty($pgoto) && !empty($pbid)) {
5495 // check if coming from a specific task
5496 $cpin->setNewPin($ex_customer['pin']);
5497 $cpin->setNewCustomerId($ex_customer['id']);
5498 $cpin->saveCustomerBooking($pbid);
5499 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5500 $mainframe->redirect(base64_decode($pgoto));
5501 exit;
5502 } else {
5503 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>');
5504 }
5505 }
5506 }
5507 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5508 }
5509
5510 public function customers() {
5511 VikBookingHelper::printHeader("22");
5512
5513 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5514
5515 parent::display();
5516
5517 if (VikBooking::showFooter()) {
5518 VikBookingHelper::printFooter();
5519 }
5520 }
5521
5522 public function newcustomer() {
5523 VikBookingHelper::printHeader("22");
5524
5525 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5526
5527 parent::display();
5528
5529 if (VikBooking::showFooter()) {
5530 VikBookingHelper::printFooter();
5531 }
5532 }
5533
5534 public function editcustomer() {
5535 VikBookingHelper::printHeader("22");
5536
5537 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5538
5539 parent::display();
5540
5541 if (VikBooking::showFooter()) {
5542 VikBookingHelper::printFooter();
5543 }
5544 }
5545
5546 public function removecustomers() {
5547 if (!JSession::checkToken()) {
5548 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5549 }
5550 $ids = VikRequest::getVar('cid', array(0));
5551 if (@count($ids)) {
5552 $dbo = JFactory::getDBO();
5553 $cpin = VikBooking::getCPinIstance();
5554 foreach ($ids as $d) {
5555 $cpin->pluginCustomerSync($d, 'delete');
5556 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5557 $dbo->setQuery($q);
5558 $dbo->execute();
5559 }
5560 }
5561 $mainframe = JFactory::getApplication();
5562 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5563 }
5564
5565 public function restrictions() {
5566 VikBookingHelper::printHeader("restrictions");
5567
5568 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5569
5570 parent::display();
5571
5572 if (VikBooking::showFooter()) {
5573 VikBookingHelper::printFooter();
5574 }
5575 }
5576
5577 public function newrestriction() {
5578 VikBookingHelper::printHeader("restrictions");
5579
5580 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5581
5582 parent::display();
5583
5584 if (VikBooking::showFooter()) {
5585 VikBookingHelper::printFooter();
5586 }
5587 }
5588
5589 public function editrestriction() {
5590 VikBookingHelper::printHeader("restrictions");
5591
5592 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5593
5594 parent::display();
5595
5596 if (VikBooking::showFooter()) {
5597 VikBookingHelper::printFooter();
5598 }
5599 }
5600
5601 public function createrestriction() {
5602 if (!JSession::checkToken()) {
5603 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5604 }
5605 $dbo = JFactory::getDBO();
5606 $session = JFactory::getSession();
5607 $mainframe = JFactory::getApplication();
5608 $updforvcm = $session->get('vbVcmRatesUpd', '');
5609 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5610 $pname = VikRequest::getString('name', '', 'request');
5611 $pmonth = VikRequest::getInt('month', '', 'request');
5612 $pmonth = empty($pmonth) ? 0 : $pmonth;
5613 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5614 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5615 $pdto = VikRequest::getString('dto', '', 'request');
5616 $pwday = VikRequest::getString('wday', '', 'request');
5617 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5618 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5619 $pcomboa = VikRequest::getString('comboa', '', 'request');
5620 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5621 $pcombob = VikRequest::getString('combob', '', 'request');
5622 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5623 $pcomboc = VikRequest::getString('comboc', '', 'request');
5624 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5625 $pcombod = VikRequest::getString('combod', '', 'request');
5626 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5627 $combostr = '';
5628 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5629 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5630 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5631 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5632 $pminlos = VikRequest::getInt('minlos', '', 'request');
5633 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5634 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5635 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5636 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5637 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5638 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5639 $pallrooms = $pallrooms == "1" ? 1 : 0;
5640 $pidrooms = VikRequest::getVar('idrooms', array(0));
5641 $ridr = '';
5642 $roomidsforsess = array();
5643 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5644 foreach ($pidrooms as $idr) {
5645 if (empty($idr)) {
5646 continue;
5647 }
5648 $ridr .= '-'.$idr.'-;';
5649 $roomidsforsess[] = (int)$idr;
5650 }
5651 } elseif ($pallrooms > 0) {
5652 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5653 $dbo->setQuery($q);
5654 $dbo->execute();
5655 if ($dbo->getNumRows() > 0) {
5656 $fetchids = $dbo->loadAssocList();
5657 foreach ($fetchids as $fetchid) {
5658 $roomidsforsess[] = (int)$fetchid['id'];
5659 }
5660 }
5661 }
5662 $pcta = VikRequest::getInt('cta', '', 'request');
5663 $pctd = VikRequest::getInt('ctd', '', 'request');
5664 $pctad = VikRequest::getVar('ctad', array());
5665 $pctdd = VikRequest::getVar('ctdd', array());
5666 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5667 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5668 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5669 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5670 // exit;
5671 }
5672
5673 //check if there are restrictions for this month
5674 if ($pmonth > 0) {
5675 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5676 $dbo->setQuery($q);
5677 $dbo->execute();
5678 if ($dbo->getNumRows() > 0) {
5679 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5680 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5681 exit;
5682 }
5683 $pdfrom = 0;
5684 $pdto = 0;
5685 } else {
5686 //dates range
5687 if (empty($pdfrom) || empty($pdto)) {
5688 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5689 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5690 exit;
5691 } else {
5692 $housto = $pdfrom == $pdto ? 23 : 0;
5693 $minsto = $pdfrom == $pdto ? 59 : 0;
5694 $secsto = $pdfrom == $pdto ? 59 : 0;
5695 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5696 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5697 }
5698 if ($pdfrom > $pdto) {
5699 // invalid dates in the past
5700 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5701 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5702 exit;
5703 }
5704 }
5705 //CTA and CTD
5706 $setcta = array();
5707 $setctd = array();
5708 if ($pcta > 0 && count($pctad) > 0) {
5709 foreach ($pctad as $ctwd) {
5710 if (strlen($ctwd)) {
5711 $setcta[] = '-'.(int)$ctwd.'-';
5712 }
5713 }
5714 }
5715 if ($pctd > 0 && count($pctdd) > 0) {
5716 foreach ($pctdd as $ctwd) {
5717 if (strlen($ctwd)) {
5718 $setctd[] = '-'.(int)$ctwd.'-';
5719 }
5720 }
5721 }
5722 //
5723 //update session values
5724 if (!($pdfrom > 0)) {
5725 $attemptyear = (int)date('Y');
5726 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5727 if ($attemptfrom < time()) {
5728 $attemptyear++;
5729 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5730 }
5731 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5732 } else {
5733 $attemptfrom = $pdfrom;
5734 $attemptto = $pdto;
5735 }
5736 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5737 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5738 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5739 } else {
5740 $updforvcm['dfrom'] = $attemptfrom;
5741 }
5742 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5743 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5744 } else {
5745 $updforvcm['dto'] = $attemptto;
5746 }
5747 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5748 foreach ($roomidsforsess as $rid) {
5749 if (!in_array($rid, $updforvcm['rooms'])) {
5750 $updforvcm['rooms'][] = $rid;
5751 }
5752 }
5753 } else {
5754 $updforvcm['rooms'] = $roomidsforsess;
5755 }
5756 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5757 $updforvcm['rplans'] = array();
5758 }
5759 $session->set('vbVcmRatesUpd', $updforvcm);
5760 //
5761 $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").");";
5762 $dbo->setQuery($q);
5763 $dbo->execute();
5764 $lid = $dbo->insertid();
5765 if (!empty($lid)) {
5766 /**
5767 * Repeat restriction on the selected week days until the limit
5768 *
5769 * @since 1.13
5770 */
5771 $prepeat = VikRequest::getInt('repeat', 0, 'request');
5772 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
5773 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
5774 $repeat_intervals = array();
5775 $start = getdate($pdfrom);
5776 $end = getdate($pdto);
5777 $wdays = array();
5778 while ($start[0] <= $end[0]) {
5779 // push requested week day
5780 array_push($wdays, $start['wday']);
5781 // next day
5782 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
5783 }
5784 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
5785 if (count($wdays) < 7 && $dtuntil > $pdto) {
5786 // increment end date for the repeat
5787 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5788 //
5789 $until_info = getdate($dtuntil);
5790 $interval = array();
5791 while ($end[0] <= $until_info[0]) {
5792 if (in_array($end['wday'], $wdays)) {
5793 if (!isset($interval['from'])) {
5794 $interval['from'] = $end[0];
5795 }
5796 $interval['to'] = $end[0];
5797 } else {
5798 if (isset($interval['from'])) {
5799 // append interval
5800 array_push($repeat_intervals, $interval);
5801 // reset interval
5802 $interval = array();
5803 }
5804 }
5805 // next day
5806 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5807 }
5808 if (isset($interval['from'])) {
5809 // append last hanging interval
5810 array_push($repeat_intervals, $interval);
5811 }
5812 if (count($repeat_intervals)) {
5813 // create the repeated records for the calculated intervals
5814 $repeat_count = 2;
5815 foreach ($repeat_intervals as $rp) {
5816 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
5817 // adjust time in case of equal dates (1 single day restriction)
5818 $rpfrom = getdate($rp['from']);
5819 $rpto = getdate($rp['to']);
5820 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
5821 /**
5822 * The end date of the restriction must cover the whole day until 23:59:59.
5823 *
5824 * @since 1.15.4 (J) - 1.5.4 (WP)
5825 */
5826 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
5827 }
5828 // adjust name
5829 $restr_rp_name = $pname . " #{$repeat_count}";
5830 //
5831 $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").");";
5832 $dbo->setQuery($q);
5833 $dbo->execute();
5834 $lid = $dbo->insertid();
5835 if (!empty($lid)) {
5836 $repeat_count++;
5837 }
5838 }
5839 }
5840 }
5841 }
5842 //
5843 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5844 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5845 } else {
5846 VikError::raiseWarning('', 'Error while saving');
5847 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5848 }
5849 }
5850
5851 public function updaterestriction() {
5852 if (!JSession::checkToken()) {
5853 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5854 }
5855 $dbo = JFactory::getDBO();
5856 $session = JFactory::getSession();
5857 $mainframe = JFactory::getApplication();
5858 $updforvcm = $session->get('vbVcmRatesUpd', '');
5859 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5860 $pwhere = VikRequest::getInt('where', '', 'request');
5861 $pname = VikRequest::getString('name', '', 'request');
5862 $pmonth = VikRequest::getInt('month', '', 'request');
5863 $pmonth = empty($pmonth) ? 0 : $pmonth;
5864 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5865 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5866 $pdto = VikRequest::getString('dto', '', 'request');
5867 $pwday = VikRequest::getString('wday', '', 'request');
5868 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5869 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5870 $pcomboa = VikRequest::getString('comboa', '', 'request');
5871 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5872 $pcombob = VikRequest::getString('combob', '', 'request');
5873 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5874 $pcomboc = VikRequest::getString('comboc', '', 'request');
5875 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5876 $pcombod = VikRequest::getString('combod', '', 'request');
5877 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5878 $combostr = '';
5879 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5880 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5881 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5882 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5883 $pminlos = VikRequest::getInt('minlos', '', 'request');
5884 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5885 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5886 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5887 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5888 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5889 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5890 $pallrooms = $pallrooms == "1" ? 1 : 0;
5891 $pidrooms = VikRequest::getVar('idrooms', array(0));
5892 $ridr = '';
5893 $roomidsforsess = array();
5894 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5895 foreach ($pidrooms as $idr) {
5896 if (empty($idr)) {
5897 continue;
5898 }
5899 $ridr .= '-'.$idr.'-;';
5900 $roomidsforsess[] = (int)$idr;
5901 }
5902 } elseif ($pallrooms > 0) {
5903 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5904 $dbo->setQuery($q);
5905 $dbo->execute();
5906 if ($dbo->getNumRows() > 0) {
5907 $fetchids = $dbo->loadAssocList();
5908 foreach ($fetchids as $fetchid) {
5909 $roomidsforsess[] = (int)$fetchid['id'];
5910 }
5911 }
5912 }
5913 $pcta = VikRequest::getInt('cta', '', 'request');
5914 $pctd = VikRequest::getInt('ctd', '', 'request');
5915 $pctad = VikRequest::getVar('ctad', array());
5916 $pctdd = VikRequest::getVar('ctdd', array());
5917 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5918 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5919 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5920 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5921 // exit;
5922 }
5923 //check if there are restrictions for this month
5924 if ($pmonth > 0) {
5925 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
5926 $dbo->setQuery($q);
5927 $dbo->execute();
5928 if ($dbo->getNumRows() > 0) {
5929 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5930 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5931 exit;
5932 }
5933 $pdfrom = 0;
5934 $pdto = 0;
5935 } else {
5936 //dates range
5937 if (empty($pdfrom) || empty($pdto)) {
5938 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5939 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5940 exit;
5941 } else {
5942 $housto = $pdfrom == $pdto ? 23 : 0;
5943 $minsto = $pdfrom == $pdto ? 59 : 0;
5944 $secsto = $pdfrom == $pdto ? 59 : 0;
5945 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5946 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5947 }
5948 if ($pdfrom > $pdto) {
5949 // invalid dates in the past
5950 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5951 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5952 exit;
5953 }
5954 }
5955 //CTA and CTD
5956 $setcta = array();
5957 $setctd = array();
5958 if ($pcta > 0 && count($pctad) > 0) {
5959 foreach ($pctad as $ctwd) {
5960 if (strlen($ctwd)) {
5961 $setcta[] = '-'.(int)$ctwd.'-';
5962 }
5963 }
5964 }
5965 if ($pctd > 0 && count($pctdd) > 0) {
5966 foreach ($pctdd as $ctwd) {
5967 if (strlen($ctwd)) {
5968 $setctd[] = '-'.(int)$ctwd.'-';
5969 }
5970 }
5971 }
5972 //
5973 //update session values
5974 if (!($pdfrom > 0)) {
5975 $attemptyear = (int)date('Y');
5976 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5977 if ($attemptfrom < time()) {
5978 $attemptyear++;
5979 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5980 }
5981 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5982 } else {
5983 $attemptfrom = $pdfrom;
5984 $attemptto = $pdto;
5985 }
5986 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5987 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5988 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5989 } else {
5990 $updforvcm['dfrom'] = $attemptfrom;
5991 }
5992 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5993 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5994 } else {
5995 $updforvcm['dto'] = $attemptto;
5996 }
5997 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5998 foreach ($roomidsforsess as $rid) {
5999 if (!in_array($rid, $updforvcm['rooms'])) {
6000 $updforvcm['rooms'][] = $rid;
6001 }
6002 }
6003 } else {
6004 $updforvcm['rooms'] = $roomidsforsess;
6005 }
6006 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6007 $updforvcm['rplans'] = array();
6008 }
6009 $session->set('vbVcmRatesUpd', $updforvcm);
6010 //
6011 $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."';";
6012 $dbo->setQuery($q);
6013 $dbo->execute();
6014 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6015 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6016 }
6017
6018 public function removerestrictions() {
6019 if (!JSession::checkToken()) {
6020 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6021 }
6022 $ids = VikRequest::getVar('cid', array(0));
6023 if (@count($ids)) {
6024 $dbo = JFactory::getDBO();
6025 foreach ($ids as $d) {
6026 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6027 $dbo->setQuery($q);
6028 $dbo->execute();
6029 }
6030 }
6031 $mainframe = JFactory::getApplication();
6032 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6033 }
6034
6035 public function prices() {
6036 VikBookingHelper::printHeader("1");
6037
6038 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6039
6040 parent::display();
6041
6042 if (VikBooking::showFooter()) {
6043 VikBookingHelper::printFooter();
6044 }
6045 }
6046
6047 public function newprice() {
6048 VikBookingHelper::printHeader("1");
6049
6050 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6051
6052 parent::display();
6053
6054 if (VikBooking::showFooter()) {
6055 VikBookingHelper::printFooter();
6056 }
6057 }
6058
6059 public function editprice() {
6060 VikBookingHelper::printHeader("1");
6061
6062 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6063
6064 parent::display();
6065
6066 if (VikBooking::showFooter()) {
6067 VikBookingHelper::printFooter();
6068 }
6069 }
6070
6071 public function createprice() {
6072 if (!JSession::checkToken()) {
6073 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6074 }
6075 $this->do_createprice();
6076 }
6077
6078 public function createprice_new() {
6079 if (!JSession::checkToken()) {
6080 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6081 }
6082 $this->do_createprice(true);
6083 }
6084
6085 private function do_createprice($new = false)
6086 {
6087 $pprice = VikRequest::getString('price', '', 'request');
6088 $pattr = VikRequest::getString('attr', '', 'request');
6089 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6090 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6091 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6092 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6093 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6094 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6095 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6096 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6097 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6098 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6099 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6100 if (!empty($pprice)) {
6101 $dbo = JFactory::getDbo();
6102 $q = "INSERT INTO `#__vikbooking_prices` (`name`,`attr`,`idiva`,`breakfast_included`,`free_cancellation`,`canc_deadline`,`canc_policy`,`minlos`,`minhadv`,`meal_plans`) 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)) . ");";
6103 $dbo->setQuery($q);
6104 $dbo->execute();
6105 }
6106
6107 $app = JFactory::getApplication();
6108 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6109 $app->close();
6110 }
6111
6112 public function updateprice()
6113 {
6114 if (!JSession::checkToken()) {
6115 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6116 }
6117 $this->do_updateprice();
6118 }
6119
6120 public function updatepricestay()
6121 {
6122 if (!JSession::checkToken()) {
6123 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6124 }
6125 $this->do_updateprice(true);
6126 }
6127
6128 private function do_updateprice($stay = false)
6129 {
6130 $pprice = VikRequest::getString('price', '', 'request');
6131 $pattr = VikRequest::getString('attr', '', 'request');
6132 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6133 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6134 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6135 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6136 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6137 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6138 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6139 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6140 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6141 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6142 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6143 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6144 if (!empty($pprice) && $pwhereup) {
6145 $dbo = JFactory::getDbo();
6146 $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)) . " WHERE `id`=" . $dbo->q($pwhereup) . ";";
6147 $dbo->setQuery($q);
6148 $dbo->execute();
6149 }
6150
6151 $app = JFactory::getApplication();
6152 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6153 $app->close();
6154 }
6155
6156 public function removeprice() {
6157 if (!JSession::checkToken()) {
6158 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6159 }
6160 $ids = VikRequest::getVar('cid', array(0));
6161 if (@count($ids)) {
6162 $dbo = JFactory::getDBO();
6163 foreach ($ids as $d) {
6164 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6165 $dbo->setQuery($q);
6166 $dbo->execute();
6167 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6168 $dbo->setQuery($q);
6169 $dbo->execute();
6170 }
6171 }
6172 $mainframe = JFactory::getApplication();
6173 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6174 }
6175
6176 public function iva() {
6177 VikBookingHelper::printHeader("2");
6178
6179 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6180
6181 parent::display();
6182
6183 if (VikBooking::showFooter()) {
6184 VikBookingHelper::printFooter();
6185 }
6186 }
6187
6188 public function newiva() {
6189 VikBookingHelper::printHeader("2");
6190
6191 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6192
6193 parent::display();
6194
6195 if (VikBooking::showFooter()) {
6196 VikBookingHelper::printFooter();
6197 }
6198 }
6199
6200 public function editiva() {
6201 VikBookingHelper::printHeader("2");
6202
6203 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6204
6205 parent::display();
6206
6207 if (VikBooking::showFooter()) {
6208 VikBookingHelper::printFooter();
6209 }
6210 }
6211
6212 public function createiva() {
6213 if (!JSession::checkToken()) {
6214 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6215 }
6216 $paliqname = VikRequest::getString('aliqname', '', 'request');
6217 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6218 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6219 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6220 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6221 if (!empty($paliqperc)) {
6222 $dbo = JFactory::getDBO();
6223 $breakdown_str = '';
6224 if (count($pbreakdown_name) > 0) {
6225 $breakdown_values = array();
6226 $bkcount = 0;
6227 $tot_sub_aliq = 0;
6228 foreach ($pbreakdown_name as $key => $subtax) {
6229 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6230 $breakdown_values[$bkcount]['name'] = $subtax;
6231 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6232 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6233 $bkcount++;
6234 }
6235 }
6236 if (count($breakdown_values) > 0) {
6237 $breakdown_str = json_encode($breakdown_values);
6238 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6239 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6240 }
6241 }
6242 }
6243 $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').");";
6244 $dbo->setQuery($q);
6245 $dbo->execute();
6246 }
6247 $mainframe = JFactory::getApplication();
6248 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6249 }
6250
6251 public function updateiva() {
6252 if (!JSession::checkToken()) {
6253 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6254 }
6255 $paliqname = VikRequest::getString('aliqname', '', 'request');
6256 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6257 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6258 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6259 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6260 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6261 if (!empty($paliqperc)) {
6262 $dbo = JFactory::getDBO();
6263 $breakdown_str = '';
6264 if (count($pbreakdown_name) > 0) {
6265 $breakdown_values = array();
6266 $bkcount = 0;
6267 $tot_sub_aliq = 0;
6268 foreach ($pbreakdown_name as $key => $subtax) {
6269 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6270 $breakdown_values[$bkcount]['name'] = $subtax;
6271 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6272 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6273 $bkcount++;
6274 }
6275 }
6276 if (count($breakdown_values) > 0) {
6277 $breakdown_str = json_encode($breakdown_values);
6278 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6279 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6280 }
6281 }
6282 }
6283 $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).";";
6284 $dbo->setQuery($q);
6285 $dbo->execute();
6286 }
6287 $mainframe = JFactory::getApplication();
6288 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6289 }
6290
6291 public function removeiva() {
6292 if (!JSession::checkToken()) {
6293 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6294 }
6295 $ids = VikRequest::getVar('cid', array(0));
6296 if (@count($ids)) {
6297 $dbo = JFactory::getDBO();
6298 foreach ($ids as $d) {
6299 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6300 $dbo->setQuery($q);
6301 $dbo->execute();
6302 }
6303 }
6304 $mainframe = JFactory::getApplication();
6305 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6306 }
6307
6308 public function categories() {
6309 VikBookingHelper::printHeader("4");
6310
6311 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6312
6313 parent::display();
6314
6315 if (VikBooking::showFooter()) {
6316 VikBookingHelper::printFooter();
6317 }
6318 }
6319
6320 public function newcat() {
6321 VikBookingHelper::printHeader("4");
6322
6323 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6324
6325 parent::display();
6326
6327 if (VikBooking::showFooter()) {
6328 VikBookingHelper::printFooter();
6329 }
6330 }
6331
6332 public function editcat() {
6333 VikBookingHelper::printHeader("4");
6334
6335 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6336
6337 parent::display();
6338
6339 if (VikBooking::showFooter()) {
6340 VikBookingHelper::printFooter();
6341 }
6342 }
6343
6344 public function createcat() {
6345 if (!JSession::checkToken()) {
6346 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6347 }
6348 $pcatname = VikRequest::getString('catname', '', 'request');
6349 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6350 if (!empty($pcatname)) {
6351 $dbo = JFactory::getDBO();
6352 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6353 $dbo->setQuery($q);
6354 $dbo->execute();
6355 }
6356 $mainframe = JFactory::getApplication();
6357 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6358 }
6359
6360 public function updatecat() {
6361 if (!JSession::checkToken()) {
6362 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6363 }
6364 $pcatname = VikRequest::getString('catname', '', 'request');
6365 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6366 $pwhereup = VikRequest::getString('whereup', '', 'request');
6367 if (!empty($pcatname)) {
6368 $dbo = JFactory::getDBO();
6369 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6370 $dbo->setQuery($q);
6371 $dbo->execute();
6372 }
6373 $mainframe = JFactory::getApplication();
6374 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6375 }
6376
6377 public function removecat() {
6378 $ids = VikRequest::getVar('cid', array(0));
6379 if (@count($ids)) {
6380 $dbo = JFactory::getDBO();
6381 foreach ($ids as $d) {
6382 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6383 $dbo->setQuery($q);
6384 $dbo->execute();
6385 }
6386 }
6387 $mainframe = JFactory::getApplication();
6388 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6389 }
6390
6391 public function carat() {
6392 VikBookingHelper::printHeader("5");
6393
6394 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6395
6396 parent::display();
6397
6398 if (VikBooking::showFooter()) {
6399 VikBookingHelper::printFooter();
6400 }
6401 }
6402
6403 public function newcarat() {
6404 VikBookingHelper::printHeader("5");
6405
6406 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6407
6408 parent::display();
6409
6410 if (VikBooking::showFooter()) {
6411 VikBookingHelper::printFooter();
6412 }
6413 }
6414
6415 public function editcarat() {
6416 VikBookingHelper::printHeader("5");
6417
6418 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6419
6420 parent::display();
6421
6422 if (VikBooking::showFooter()) {
6423 VikBookingHelper::printFooter();
6424 }
6425 }
6426
6427 public function createcarat() {
6428 if (!JSession::checkToken()) {
6429 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6430 }
6431 $pcaratname = VikRequest::getString('caratname', '', 'request');
6432 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6433 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6434 $presizeto = VikRequest::getString('resizeto', '', 'request');
6435 $pidrooms = VikRequest::getVar('idrooms', array());
6436 if (!empty($pcaratname)) {
6437 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6438 jimport('joomla.filesystem.file');
6439 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6440 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6441 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6442 if (file_exists($updpath.$safename)) {
6443 $j=1;
6444 while (file_exists($updpath.$j.$safename)) {
6445 $j++;
6446 }
6447 $pwhere=$updpath.$j.$safename;
6448 } else {
6449 $j="";
6450 $pwhere=$updpath.$safename;
6451 }
6452 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6453 @unlink($pwhere);
6454 $picon="";
6455 } else {
6456 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6457 @chmod($pwhere, 0644);
6458 $picon=$j.$safename;
6459 if ($pautoresize=="1" && !empty($presizeto)) {
6460 $eforj = new vikResizer();
6461 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6462 if ($origmod) {
6463 @unlink($pwhere);
6464 $picon='r_'.$j.$safename;
6465 }
6466 }
6467 }
6468 } else {
6469 $picon="";
6470 }
6471 } else {
6472 $picon="";
6473 }
6474 $dbo = JFactory::getDbo();
6475 // get new ordering
6476 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6477 $dbo->setQuery($q);
6478 $dbo->execute();
6479 if ($dbo->getNumRows()) {
6480 $newsortnum = $dbo->loadResult() + 1;
6481 } else {
6482 $newsortnum = 1;
6483 }
6484 $pordering = VikRequest::getInt('ordering', 0, 'request');
6485 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6486 //
6487 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6488 $dbo->setQuery($q);
6489 $dbo->execute();
6490
6491 $new_carat_id = $dbo->insertid();
6492 if (!empty($new_carat_id)) {
6493 // assign/unset carat-rooms relations
6494 $rooms_with_carat = array();
6495 if (count($pidrooms)) {
6496 // assign this new carat to the requested rooms
6497 foreach ($pidrooms as $idroom) {
6498 if (empty($idroom)) {
6499 continue;
6500 }
6501 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6502 $dbo->setQuery($q);
6503 $dbo->execute();
6504 if (!$dbo->getNumRows()) {
6505 continue;
6506 }
6507 $room_data = $dbo->loadAssoc();
6508 array_push($rooms_with_carat, $room_data['id']);
6509 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6510 if (in_array((string)$new_carat_id, $current_carats)) {
6511 continue;
6512 }
6513 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6514 // make sure we do not concatenate a real ID to 0
6515 $current_carats = array();
6516 }
6517 array_push($current_carats, $new_carat_id);
6518 $new_opts = implode(';', $current_carats) . ';';
6519 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6520 $dbo->setQuery($q);
6521 $dbo->execute();
6522 }
6523 }
6524 if (!count($rooms_with_carat)) {
6525 // get all rooms to unset this carat (if previously set)
6526 array_push($rooms_with_carat, '0');
6527 }
6528 // unset the carat from the other rooms that may have it
6529 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6530 $dbo->setQuery($q);
6531 $dbo->execute();
6532 if ($dbo->getNumRows()) {
6533 $unset_rooms_carat = $dbo->loadAssocList();
6534 foreach ($unset_rooms_carat as $room_data) {
6535 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6536 if (!in_array((string)$new_carat_id, $current_carats)) {
6537 // this room is not using this carat
6538 continue;
6539 }
6540 $caratkey = array_search((string)$new_carat_id, $current_carats);
6541 if ($caratkey === false) {
6542 // key not found
6543 continue;
6544 }
6545 // unset this carat ID from the string
6546 unset($current_carats[$caratkey]);
6547 if (!count($current_carats)) {
6548 // a room with no carats assigned will be listed as "0;"
6549 $current_carats = array(0);
6550 }
6551 $new_opts = implode(';', $current_carats) . ';';
6552 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6553 $dbo->setQuery($q);
6554 $dbo->execute();
6555 }
6556 }
6557 //
6558 }
6559 }
6560 $mainframe = JFactory::getApplication();
6561 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6562 }
6563
6564 public function updatecarat() {
6565 if (!JSession::checkToken()) {
6566 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6567 }
6568 $pcaratname = VikRequest::getString('caratname', '', 'request');
6569 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6570 $pwhereup = VikRequest::getString('whereup', '', 'request');
6571 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6572 $presizeto = VikRequest::getString('resizeto', '', 'request');
6573 $pidrooms = VikRequest::getVar('idrooms', array());
6574 $pordering = VikRequest::getInt('ordering', 1, 'request');
6575 if (!empty($pcaratname)) {
6576 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6577 jimport('joomla.filesystem.file');
6578 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6579 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6580 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6581 if (file_exists($updpath.$safename)) {
6582 $j=1;
6583 while (file_exists($updpath.$j.$safename)) {
6584 $j++;
6585 }
6586 $pwhere=$updpath.$j.$safename;
6587 } else {
6588 $j="";
6589 $pwhere=$updpath.$safename;
6590 }
6591 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6592 @unlink($pwhere);
6593 $picon="";
6594 } else {
6595 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6596 @chmod($pwhere, 0644);
6597 $picon=$j.$safename;
6598 if ($pautoresize=="1" && !empty($presizeto)) {
6599 $eforj = new vikResizer();
6600 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6601 if ($origmod) {
6602 @unlink($pwhere);
6603 $picon='r_'.$j.$safename;
6604 }
6605 }
6606 }
6607 } else {
6608 $picon="";
6609 }
6610 } else {
6611 $picon="";
6612 }
6613 $dbo = JFactory::getDbo();
6614 $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).";";
6615 $dbo->setQuery($q);
6616 $dbo->execute();
6617
6618 // assign/unset carat-rooms relations
6619 $rooms_with_carat = array();
6620 if (count($pidrooms)) {
6621 // assign this new carat to the requested rooms
6622 foreach ($pidrooms as $idroom) {
6623 if (empty($idroom)) {
6624 continue;
6625 }
6626 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6627 $dbo->setQuery($q);
6628 $dbo->execute();
6629 if (!$dbo->getNumRows()) {
6630 continue;
6631 }
6632 $room_data = $dbo->loadAssoc();
6633 array_push($rooms_with_carat, $room_data['id']);
6634 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6635 if (in_array((string)$pwhereup, $current_carats)) {
6636 continue;
6637 }
6638 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6639 // make sure we do not concatenate a real ID to 0
6640 $current_carats = array();
6641 }
6642 array_push($current_carats, $pwhereup);
6643 $new_carats = implode(';', $current_carats) . ';';
6644 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6645 $dbo->setQuery($q);
6646 $dbo->execute();
6647 }
6648 }
6649 if (!count($rooms_with_carat)) {
6650 // get all rooms to unset this carat (if previously set)
6651 array_push($rooms_with_carat, '0');
6652 }
6653 // unset the carat from the other rooms that may have it
6654 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6655 $dbo->setQuery($q);
6656 $dbo->execute();
6657 if ($dbo->getNumRows()) {
6658 $unset_rooms_carat = $dbo->loadAssocList();
6659 foreach ($unset_rooms_carat as $room_data) {
6660 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6661 if (!in_array((string)$pwhereup, $current_carats)) {
6662 // this room is not using this carat
6663 continue;
6664 }
6665 $caratkey = array_search((string)$pwhereup, $current_carats);
6666 if ($caratkey === false) {
6667 // key not found
6668 continue;
6669 }
6670 // unset this carat ID from the string
6671 unset($current_carats[$caratkey]);
6672 if (!count($current_carats)) {
6673 // a room with no carats assigned will be listed as "0;"
6674 $current_carats = array(0);
6675 }
6676 $new_carats = implode(';', $current_carats) . ';';
6677 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6678 $dbo->setQuery($q);
6679 $dbo->execute();
6680 }
6681 }
6682 //
6683 }
6684 $mainframe = JFactory::getApplication();
6685 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6686 }
6687
6688 public function removecarat() {
6689 if (!JSession::checkToken()) {
6690 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6691 }
6692 $ids = VikRequest::getVar('cid', array(0));
6693 if (@count($ids)) {
6694 $dbo = JFactory::getDBO();
6695 foreach ($ids as $d) {
6696 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6697 $dbo->setQuery($q);
6698 $dbo->execute();
6699 if ($dbo->getNumRows() == 1) {
6700 $rows = $dbo->loadAssocList();
6701 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
6702 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
6703 }
6704 }
6705 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6706 $dbo->setQuery($q);
6707 $dbo->execute();
6708 }
6709 }
6710 $mainframe = JFactory::getApplication();
6711 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6712 }
6713
6714 public function coupons() {
6715 VikBookingHelper::printHeader("17");
6716
6717 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
6718
6719 parent::display();
6720
6721 if (VikBooking::showFooter()) {
6722 VikBookingHelper::printFooter();
6723 }
6724 }
6725
6726 public function newcoupon() {
6727 VikBookingHelper::printHeader("17");
6728
6729 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6730
6731 parent::display();
6732
6733 if (VikBooking::showFooter()) {
6734 VikBookingHelper::printFooter();
6735 }
6736 }
6737
6738 public function editcoupon() {
6739 VikBookingHelper::printHeader("17");
6740
6741 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6742
6743 parent::display();
6744
6745 if (VikBooking::showFooter()) {
6746 VikBookingHelper::printFooter();
6747 }
6748 }
6749
6750 public function createcoupon()
6751 {
6752 if (!JSession::checkToken()) {
6753 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6754 }
6755 $pcode = VikRequest::getString('code', '', 'request');
6756 $pvalue = VikRequest::getString('value', '', 'request');
6757 $pfrom = VikRequest::getString('from', '', 'request');
6758 $pto = VikRequest::getString('to', '', 'request');
6759 $pidrooms = VikRequest::getVar('idrooms', array(0));
6760 $ptype = VikRequest::getString('type', '', 'request');
6761 $ptype = $ptype == "1" ? 1 : 2;
6762 $ppercentot = VikRequest::getString('percentot', '', 'request');
6763 $ppercentot = $ppercentot == "1" ? 1 : 2;
6764 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6765 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6766 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6767 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6768 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6769 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6770 $pcustomers = VikRequest::getVar('customers', array());
6771 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6772 $stridrooms = "";
6773 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6774 foreach ($pidrooms as $ch) {
6775 if (!empty($ch)) {
6776 $stridrooms .= ";".$ch.";";
6777 }
6778 }
6779 }
6780 $strdatevalid = "";
6781 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6782 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6783 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6784 if ($first < $second) {
6785 $strdatevalid .= $first."-".$second;
6786 }
6787 }
6788
6789 $dbo = JFactory::getDbo();
6790 $app = JFactory::getApplication();
6791
6792 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
6793 $dbo->setQuery($q);
6794 $dbo->execute();
6795 if ($dbo->getNumRows() > 0) {
6796 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6797 } else {
6798 $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) . ");";
6799 $dbo->setQuery($q);
6800 $dbo->execute();
6801
6802 $id_coupon = $dbo->insertid();
6803
6804 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6805
6806 // check if this coupon should be assigned to specific customers
6807 foreach ($pcustomers as $id_customer) {
6808 $customer_coupon = new stdClass;
6809 $customer_coupon->idcustomer = (int)$id_customer;
6810 $customer_coupon->idcoupon = (int)$id_coupon;
6811 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6812
6813 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6814 }
6815 }
6816 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6817 }
6818
6819 public function updatecoupon()
6820 {
6821 if (!JSession::checkToken()) {
6822 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6823 }
6824
6825 $this->do_updatecoupon($stay = false);
6826 }
6827
6828 public function updatecoupon_stay()
6829 {
6830 if (!JSession::checkToken()) {
6831 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6832 }
6833
6834 $this->do_updatecoupon($stay = true);
6835 }
6836
6837 protected function do_updatecoupon($stay = false)
6838 {
6839 if (!JSession::checkToken()) {
6840 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6841 }
6842 $pcode = VikRequest::getString('code', '', 'request');
6843 $pvalue = VikRequest::getString('value', '', 'request');
6844 $pfrom = VikRequest::getString('from', '', 'request');
6845 $pto = VikRequest::getString('to', '', 'request');
6846 $pidrooms = VikRequest::getVar('idrooms', array(0));
6847 $pwhere = VikRequest::getInt('where', 0, 'request');
6848 $ptype = VikRequest::getString('type', '', 'request');
6849 $ptype = $ptype == "1" ? 1 : 2;
6850 $ppercentot = VikRequest::getString('percentot', '', 'request');
6851 $ppercentot = $ppercentot == "1" ? 1 : 2;
6852 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6853 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6854 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6855 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6856 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6857 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6858 $pcustomers = VikRequest::getVar('customers', array());
6859 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6860 $stridrooms = "";
6861 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6862 foreach ($pidrooms as $ch) {
6863 if (!empty($ch)) {
6864 $stridrooms .= ";".$ch.";";
6865 }
6866 }
6867 }
6868 $strdatevalid = "";
6869 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6870 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6871 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6872 if ($first < $second) {
6873 $strdatevalid .= $first."-".$second;
6874 }
6875 }
6876
6877 $dbo = JFactory::getDbo();
6878 $app = JFactory::getApplication();
6879
6880 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
6881 $dbo->setQuery($q);
6882 $dbo->execute();
6883 if ($dbo->getNumRows() > 0) {
6884 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6885 } else {
6886 $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 . ";";
6887 $dbo->setQuery($q);
6888 $dbo->execute();
6889
6890 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6891
6892 // clean up any previously created record with customers
6893 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
6894 $dbo->setQuery($q);
6895 $dbo->execute();
6896
6897 // check if this coupon should be assigned to specific customers
6898 foreach ($pcustomers as $id_customer) {
6899 $customer_coupon = new stdClass;
6900 $customer_coupon->idcustomer = (int)$id_customer;
6901 $customer_coupon->idcoupon = (int)$pwhere;
6902 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6903
6904 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6905 }
6906 }
6907
6908 if ($stay) {
6909 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
6910 } else {
6911 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6912 }
6913 }
6914
6915 public function removecoupons()
6916 {
6917 if (!JSession::checkToken()) {
6918 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6919 }
6920
6921 $dbo = JFactory::getDbo();
6922
6923 $ids = VikRequest::getVar('cid', array(0));
6924
6925 if (count($ids)) {
6926 foreach ($ids as $d) {
6927 // delete coupon record
6928 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
6929 $dbo->setQuery($q);
6930 $dbo->execute();
6931
6932 // clean up any previously created record with customers
6933 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
6934 $dbo->setQuery($q);
6935 $dbo->execute();
6936 }
6937 }
6938
6939 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
6940 }
6941
6942 public function removemoreimgs() {
6943 $mainframe = JFactory::getApplication();
6944 $proomid = VikRequest::getInt('roomid', '', 'request');
6945 $pimgind = VikRequest::getInt('imgind', '', 'request');
6946 if (!strlen($pimgind)) {
6947 $mainframe->redirect("index.php?option=com_vikbooking");
6948 exit;
6949 }
6950 $dbo = JFactory::getDBO();
6951 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
6952 $dbo->setQuery($q);
6953 $dbo->execute();
6954 $row = $dbo->loadAssoc();
6955 $actmore = $row['moreimgs'];
6956 if (!empty($actmore)) {
6957 $actsplit = explode(';;', $actmore);
6958 $captions = json_decode($row['imgcaptions'], true);
6959 $captions = !is_array($captions) ? array() : $captions;
6960 if ($pimgind < 0) {
6961 foreach ($actsplit as $img) {
6962 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
6963 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
6964 }
6965 // reset images and captions
6966 $actsplit = array();
6967 $captions = array();
6968 } else {
6969 if (array_key_exists($pimgind, $actsplit)) {
6970 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
6971 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
6972 // unset current image
6973 unset($actsplit[$pimgind]);
6974 // unset caption if exists
6975 if (isset($captions[$pimgind])) {
6976 unset($captions[$pimgind]);
6977 $captions = array_values($captions);
6978 }
6979 }
6980 }
6981 $newstr = "";
6982 foreach ($actsplit as $oi) {
6983 if (!empty($oi)) {
6984 $newstr .= $oi.';;';
6985 }
6986 }
6987 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
6988 $dbo->setQuery($q);
6989 $dbo->execute();
6990 }
6991 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
6992 }
6993
6994 public function sortfield() {
6995 if (!JSession::checkToken('get')) {
6996 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6997 }
6998 $mainframe = JFactory::getApplication();
6999 $sortid = VikRequest::getVar('cid', array(0));
7000 $pmode = VikRequest::getString('mode', '', 'request');
7001 $dbo = JFactory::getDBO();
7002 if (!empty($pmode)) {
7003 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7004 $dbo->setQuery($q);
7005 $dbo->execute();
7006 $totr=$dbo->getNumRows();
7007 if ($totr > 1) {
7008 $data = $dbo->loadAssocList();
7009 if ($pmode == "up") {
7010 foreach ($data as $v) {
7011 if ($v['id'] == $sortid[0]) {
7012 $y = $v['ordering'];
7013 }
7014 }
7015 if ($y && $y > 1) {
7016 $vik = $y - 1;
7017 $found = false;
7018 foreach ($data as $v) {
7019 if (intval($v['ordering']) == intval($vik)) {
7020 $found=true;
7021 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7022 $dbo->setQuery($q);
7023 $dbo->execute();
7024 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7025 $dbo->setQuery($q);
7026 $dbo->execute();
7027 break;
7028 }
7029 }
7030 if (!$found) {
7031 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7032 $dbo->setQuery($q);
7033 $dbo->execute();
7034 }
7035 }
7036 } elseif ($pmode == "down") {
7037 foreach ($data as $v) {
7038 if ($v['id'] == $sortid[0]) {
7039 $y = $v['ordering'];
7040 }
7041 }
7042 if ($y) {
7043 $vik = $y + 1;
7044 $found = false;
7045 foreach ($data as $v) {
7046 if (intval($v['ordering']) == intval($vik)) {
7047 $found=true;
7048 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7049 $dbo->setQuery($q);
7050 $dbo->execute();
7051 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7052 $dbo->setQuery($q);
7053 $dbo->execute();
7054 break;
7055 }
7056 }
7057 if (!$found) {
7058 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7059 $dbo->setQuery($q);
7060 $dbo->execute();
7061 }
7062 }
7063 }
7064 }
7065 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7066 } else {
7067 $mainframe->redirect("index.php?option=com_vikbooking");
7068 }
7069 }
7070
7071 public function customf() {
7072 VikBookingHelper::printHeader("16");
7073
7074 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7075
7076 parent::display();
7077
7078 if (VikBooking::showFooter()) {
7079 VikBookingHelper::printFooter();
7080 }
7081 }
7082
7083 public function newcustomf() {
7084 VikBookingHelper::printHeader("16");
7085
7086 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7087
7088 parent::display();
7089
7090 if (VikBooking::showFooter()) {
7091 VikBookingHelper::printFooter();
7092 }
7093 }
7094
7095 public function editcustomf() {
7096 VikBookingHelper::printHeader("16");
7097
7098 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7099
7100 parent::display();
7101
7102 if (VikBooking::showFooter()) {
7103 VikBookingHelper::printFooter();
7104 }
7105 }
7106
7107 public function createcustomf() {
7108 if (!JSession::checkToken()) {
7109 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7110 }
7111 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7112 $ptype = VikRequest::getString('type', '', 'request');
7113 $pchoose = VikRequest::getVar('choose', array(0));
7114 $prequired = VikRequest::getString('required', '', 'request');
7115 $prequired = $prequired == "1" ? 1 : 0;
7116 $pflag = VikRequest::getString('flag', '', 'request');
7117 $pisemail = $pflag == 'isemail' ? 1 : 0;
7118 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7119 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7120 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7121 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7122 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7123 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7124 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7125 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7126 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7127 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7128 $fieldflag = '';
7129 if ($pisaddress == 1) {
7130 $fieldflag = 'address';
7131 } elseif ($piscity == 1) {
7132 $fieldflag = 'city';
7133 } elseif ($piszip == 1) {
7134 $fieldflag = 'zip';
7135 } elseif ($piscompany == 1) {
7136 $fieldflag = 'company';
7137 } elseif ($pisvat == 1) {
7138 $fieldflag = 'vat';
7139 } elseif ($pisfisccode == 1) {
7140 $fieldflag = 'fisccode';
7141 } elseif ($pispec == 1) {
7142 $fieldflag = 'pec';
7143 } elseif ($pisrecipcode == 1) {
7144 $fieldflag = 'recipcode';
7145 }
7146 $ppoplink = VikRequest::getString('poplink', '', 'request');
7147 $choosestr = "";
7148 if (is_array($pchoose)) {
7149 foreach ($pchoose as $ch) {
7150 if (!empty($ch)) {
7151 $choosestr .= $ch.";;__;;";
7152 }
7153 }
7154 }
7155 $defvalue = VikRequest::getString('defvalue', '', 'request');
7156
7157 $dbo = JFactory::getDbo();
7158
7159 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7160 $dbo->setQuery($q);
7161 $dbo->execute();
7162 if ($dbo->getNumRows() == 1) {
7163 $getlast = $dbo->loadResult();
7164 $newsortnum = $getlast + 1;
7165 } else {
7166 $newsortnum = 1;
7167 }
7168 $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).");";
7169 $dbo->setQuery($q);
7170 $dbo->execute();
7171 $mainframe = JFactory::getApplication();
7172 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7173 }
7174
7175 public function updatecustomf() {
7176 if (!JSession::checkToken()) {
7177 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7178 }
7179 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7180 $ptype = VikRequest::getString('type', '', 'request');
7181 $pchoose = VikRequest::getVar('choose', array(0));
7182 $prequired = VikRequest::getString('required', '', 'request');
7183 $prequired = $prequired == "1" ? 1 : 0;
7184 $pflag = VikRequest::getString('flag', '', 'request');
7185 $pisemail = $pflag == 'isemail' ? 1 : 0;
7186 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7187 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7188 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7189 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7190 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7191 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7192 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7193 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7194 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7195 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7196 $fieldflag = '';
7197 if ($pisaddress == 1) {
7198 $fieldflag = 'address';
7199 } elseif ($piscity == 1) {
7200 $fieldflag = 'city';
7201 } elseif ($piszip == 1) {
7202 $fieldflag = 'zip';
7203 } elseif ($piscompany == 1) {
7204 $fieldflag = 'company';
7205 } elseif ($pisvat == 1) {
7206 $fieldflag = 'vat';
7207 } elseif ($pisfisccode == 1) {
7208 $fieldflag = 'fisccode';
7209 } elseif ($pispec == 1) {
7210 $fieldflag = 'pec';
7211 } elseif ($pisrecipcode == 1) {
7212 $fieldflag = 'recipcode';
7213 }
7214 $ppoplink = VikRequest::getString('poplink', '', 'request');
7215 $pwhere = VikRequest::getInt('where', '', 'request');
7216 $choosestr = "";
7217 if (is_array($pchoose)) {
7218 foreach ($pchoose as $ch) {
7219 if (!empty($ch)) {
7220 $choosestr .= $ch.";;__;;";
7221 }
7222 }
7223 }
7224 $defvalue = VikRequest::getString('defvalue', '', 'request');
7225
7226 $dbo = JFactory::getDbo();
7227
7228 $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).";";
7229 $dbo->setQuery($q);
7230 $dbo->execute();
7231 $mainframe = JFactory::getApplication();
7232 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7233 }
7234
7235 public function removecustomf() {
7236 if (!JSession::checkToken()) {
7237 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7238 }
7239 $ids = VikRequest::getVar('cid', array(0));
7240 if (@count($ids)) {
7241 $dbo = JFactory::getDBO();
7242 foreach ($ids as $d) {
7243 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7244 $dbo->setQuery($q);
7245 $dbo->execute();
7246 }
7247 }
7248 $mainframe = JFactory::getApplication();
7249 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7250 }
7251
7252 public function overv() {
7253 VikBookingHelper::printHeader("15");
7254
7255 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7256
7257 parent::display();
7258
7259 if (VikBooking::showFooter()) {
7260 VikBookingHelper::printFooter();
7261 }
7262 }
7263
7264 public function translations() {
7265 VikBookingHelper::printHeader("21");
7266
7267 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7268
7269 parent::display();
7270
7271 if (VikBooking::showFooter()) {
7272 VikBookingHelper::printFooter();
7273 }
7274 }
7275
7276 public function savetranslation() {
7277 if (!JSession::checkToken()) {
7278 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7279 }
7280 $this->do_savetranslation();
7281 }
7282
7283 public function savetranslationstay() {
7284 if (!JSession::checkToken()) {
7285 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7286 }
7287 $this->do_savetranslation(true);
7288 }
7289
7290 private function do_savetranslation($stay = false) {
7291 $dbo = JFactory::getDBO();
7292 $mainframe = JFactory::getApplication();
7293 $vbo_tn = VikBooking::getTranslator();
7294 $table = VikRequest::getString('vbo_table', '', 'request');
7295 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7296 $langs = $vbo_tn->getLanguagesList();
7297 $xml_tables = $vbo_tn->getTranslationTables();
7298 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7299 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7300 $tn_saved = 0;
7301 $table_cols = $vbo_tn->getTableColumns($table);
7302 foreach ($langs as $ltag => $lang) {
7303 if ($ltag == $vbo_tn->default_lang) {
7304 continue;
7305 }
7306 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7307 foreach ($tn[$ltag] as $reference_id => $translation) {
7308 $lang_translation = array();
7309 foreach ($table_cols as $field => $fdetails) {
7310 if (!array_key_exists($field, $translation)) {
7311 continue;
7312 }
7313 $ftype = $fdetails['type'];
7314 if ($ftype == 'skip') {
7315 continue;
7316 }
7317
7318 if (is_array($translation[$field])) {
7319 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7320 if (!is_string($tn_field_v)) {
7321 continue;
7322 }
7323 // replace any possible placeholder for special tags
7324 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7325 return $match[2];
7326 }, $translation[$field][$tn_field_k]);
7327 }
7328 } elseif (!empty($translation[$field])) {
7329 // replace any possible placeholder for special tags
7330 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7331 return $match[2];
7332 }, $translation[$field]);
7333 }
7334
7335 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7336 $translation[$field] = json_encode($translation[$field]);
7337 }
7338 $lang_translation[$field] = $translation[$field];
7339 }
7340 if (count($lang_translation) > 0) {
7341 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7342 $dbo->setQuery($q);
7343 $dbo->execute();
7344 if ($dbo->getNumRows() > 0) {
7345 $last_id = $dbo->loadResult();
7346 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7347 } else {
7348 $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)).");";
7349 }
7350 $dbo->setQuery($q);
7351 $dbo->execute();
7352 $tn_saved++;
7353 }
7354 }
7355 }
7356 }
7357 if ($tn_saved > 0) {
7358 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7359 }
7360 } else {
7361 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7362 }
7363 $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);
7364 }
7365
7366 public function choosebusy() {
7367 VikBookingHelper::printHeader("8");
7368
7369 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7370
7371 parent::display();
7372
7373 if (VikBooking::showFooter()) {
7374 VikBookingHelper::printFooter();
7375 }
7376 }
7377
7378 public function orders() {
7379 VikBookingHelper::printHeader("8");
7380
7381 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7382
7383 parent::display();
7384
7385 if (VikBooking::showFooter()) {
7386 VikBookingHelper::printFooter();
7387 }
7388 }
7389
7390 public function vieworders() {
7391 //alias method of orders() for backward compatibility with VCM
7392 $this->orders();
7393 }
7394
7395 public function editorder() {
7396 VikBookingHelper::printHeader("8");
7397
7398 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7399
7400 parent::display();
7401
7402 if (VikBooking::showFooter()) {
7403 VikBookingHelper::printFooter();
7404 }
7405 }
7406
7407 public function removeorders()
7408 {
7409 $dbo = JFactory::getDbo();
7410 $app = JFactory::getApplication();
7411
7412 $ids = VikRequest::getVar('cid', array(0));
7413 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7414
7415 $user = JFactory::getUser();
7416 $config = VBOFactory::getConfig();
7417
7418 $prev_conf_ids = [];
7419 $purged = false;
7420
7421 $tot_cancs = 0;
7422
7423 if (is_array($ids) && count($ids)) {
7424 foreach ($ids as $d) {
7425 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7426 $dbo->setQuery($q, 0, 1);
7427 $row = $dbo->loadAssoc();
7428
7429 // check for any cancellation constraints
7430 $canc_denied = false;
7431 if ($row && class_exists('VCMFeesCancellation')) {
7432 // let VCM detect if there are any constraints for the cancellation
7433 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7434 if ($canc_denied) {
7435 // set error message
7436 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7437 if ($canc_deny_error) {
7438 $app->enqueueMessage($canc_deny_error, 'error');
7439 }
7440 }
7441 }
7442
7443 if ($row && !$canc_denied) {
7444 // increase counter
7445 $tot_cancs++;
7446
7447 // set status to cancelled
7448 if ($row['status'] != 'cancelled') {
7449 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7450 $dbo->setQuery($q);
7451 $dbo->execute();
7452 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7453 $dbo->setQuery($q);
7454 $dbo->execute();
7455 if ($row['status'] == 'confirmed') {
7456 $prev_conf_ids[] = $row['id'];
7457 }
7458 // Booking History
7459 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7460 }
7461
7462 // free records up
7463 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7464 $dbo->setQuery($q);
7465 $ordbusy = $dbo->loadAssocList();
7466 if ($ordbusy) {
7467 foreach ($ordbusy as $ob) {
7468 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7469 $dbo->setQuery($q);
7470 $dbo->execute();
7471 }
7472 }
7473
7474 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7475 $dbo->setQuery($q);
7476 $dbo->execute();
7477
7478 // check for purge removal
7479 if ($row['status'] == 'cancelled') {
7480 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7481 $dbo->setQuery($q);
7482 $dbo->execute();
7483 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7484 $dbo->setQuery($q);
7485 $dbo->execute();
7486 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7487 $dbo->setQuery($q);
7488 $dbo->execute();
7489 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7490 $dbo->setQuery($q);
7491 $dbo->execute();
7492 // in case of split stay booking, remove the transient
7493 if ($row['split_stay']) {
7494 $config->remove('split_stay_' . $row['id']);
7495 }
7496 // turn flag on
7497 $purged = true;
7498 }
7499 }
7500 }
7501
7502 if ($tot_cancs) {
7503 // enqueue system message
7504 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7505 }
7506 }
7507
7508 if ($prev_conf_ids) {
7509 $prev_conf_ids_str = '';
7510 foreach ($prev_conf_ids as $prev_id) {
7511 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7512 }
7513 //Invoke Channel Manager
7514 $vcm_autosync = VikBooking::vcmAutoUpdate();
7515 if ($vcm_autosync > 0) {
7516 $vcm_obj = VikBooking::getVcmInvoker();
7517 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7518 $sync_result = $vcm_obj->doSync();
7519 if ($sync_result === false) {
7520 $vcm_err = $vcm_obj->getError();
7521 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7522 }
7523 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7524 $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');
7525 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7526 }
7527 //
7528 }
7529
7530 if (!empty($pgoto)) {
7531 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7532 if ($purged) {
7533 // go back to the bookings list page
7534 $app->redirect("index.php?option=com_vikbooking&task=orders");
7535 } else {
7536 // go back to the booking details page
7537 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7538 }
7539 exit;
7540 }
7541 // we expect the goto URL to be base64 encoded
7542 $app->redirect(base64_decode($pgoto));
7543 exit;
7544 }
7545
7546 // go back to the bookings list page
7547 $app->redirect("index.php?option=com_vikbooking&task=orders");
7548 }
7549
7550 public function config() {
7551 VikBookingHelper::printHeader("11");
7552
7553 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7554
7555 parent::display();
7556
7557 if (VikBooking::showFooter()) {
7558 VikBookingHelper::printFooter();
7559 }
7560 }
7561
7562 public function saveconfig()
7563 {
7564 if (!JSession::checkToken()) {
7565 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7566 }
7567
7568 $dbo = JFactory::getDbo();
7569 $app = JFactory::getApplication();
7570
7571 $config = VBOFactory::getConfig();
7572
7573 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7574 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7575 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
7576 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
7577 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
7578 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
7579 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
7580 $pdateformat = VikRequest::getString('dateformat', '', 'request');
7581 $pdatesep = VikRequest::getString('datesep', '', 'request');
7582 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
7583 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
7584 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
7585 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
7586 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
7587 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
7588 $ptokenform = VikRequest::getString('tokenform', '', 'request');
7589 $padminemail = VikRequest::getString('adminemail', '', 'request');
7590 $psenderemail = VikRequest::getString('senderemail', '', 'request');
7591 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
7592 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
7593 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
7594 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
7595 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
7596 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
7597 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
7598 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
7599 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
7600 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
7601 $pusefa = VikRequest::getInt('usefa', '', 'request');
7602 $pusefa = $pusefa > 0 ? 1 : 0;
7603 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
7604 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
7605 $pcalendar = VikRequest::getString('calendar', '', 'request');
7606 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
7607 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
7608 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
7609 $penablepin = VikRequest::getString('enablepin', '', 'request');
7610 $penablepin = $penablepin == "1" ? 1 : 0;
7611 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
7612 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
7613 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
7614 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
7615 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
7616 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
7617 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
7618 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
7619 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
7620 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
7621 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
7622 $pnumadultsfrom = '1';
7623 $pnumadultsto = '10';
7624 }
7625 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
7626 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
7627 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
7628 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
7629 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
7630 $pnumadultsfrom = '1';
7631 $pnumadultsto = '4';
7632 }
7633 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
7634 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
7635 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
7636 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
7637 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
7638 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
7639 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
7640 $pcronkey = VikRequest::getString('cronkey', '', 'request');
7641 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
7642 $pcdsto = VikRequest::getVar('cdsto', array());
7643 $closing_dates = array();
7644 if (count($pcdsfrom)) {
7645 foreach ($pcdsfrom as $kcd => $vcdfrom) {
7646 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
7647 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
7648 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
7649 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
7650 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
7651 if (!in_array($cdval, $closing_dates)) {
7652 $closing_dates[] = $cdval;
7653 }
7654 }
7655 }
7656 }
7657 }
7658 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
7659 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
7660 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
7661 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7662 if ($pvbosef === 1) {
7663 if (!$vbosef) {
7664 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7665 }
7666 } else {
7667 if ($vbosef) {
7668 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
7669 }
7670 }
7671 $pmultilang = VikRequest::getString('multilang', '', 'request');
7672 $pmultilang = $pmultilang == "1" ? 1 : 0;
7673 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
7674 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
7675 /**
7676 * Chat params and configuration settings
7677 *
7678 * @since 1.12
7679 */
7680 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
7681 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
7682 $config->set('chatenabled', $pchatenabled);
7683
7684 // chat params
7685 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
7686 $chat_res_status = array();
7687 foreach ($pchat_res_status as $chatrs) {
7688 if (!empty($chatrs)) {
7689 array_push($chat_res_status, $chatrs);
7690 }
7691 }
7692 $chatparams = new stdClass;
7693 $chatparams->res_status = $chat_res_status;
7694 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
7695 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
7696
7697 $config->set('chatparams', $chatparams);
7698 }
7699
7700 /**
7701 * Pre check-in configuration settings
7702 *
7703 * @since 1.12
7704 */
7705 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
7706 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
7707
7708 $config->set('precheckinenabled', $pprecheckinenabled);
7709 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
7710
7711 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
7712 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
7713 $config->set('upselling', $pupsellingenabled);
7714
7715 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
7716 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
7717 $config->set('orphanscalculation', $porphanscal);
7718
7719 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
7720 $config->set('searchrestmpl', $psrcrtpl);
7721
7722 /**
7723 * Guest Reviews settings
7724 *
7725 * @since 1.13
7726 */
7727 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
7728 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
7729 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
7730 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
7731 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
7732 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
7733 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
7734 $config->set('grenabled', $pgrenabled);
7735 $config->set('grminchars', $pgrminchars);
7736 $config->set('grappr', $pgrappr);
7737 $config->set('grtype', $pgrtype);
7738 try {
7739 // always truncate service names (this query may require special permissions)
7740 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
7741 $dbo->setQuery($q);
7742 $dbo->execute();
7743 } catch (Exception $e) {
7744 // do nothing
7745 }
7746 foreach ($pgrsrv as $srvname) {
7747 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
7748 $dbo->setQuery($q);
7749 $dbo->execute();
7750 }
7751
7752 /**
7753 * Preferred countries ordering, or custom countries.
7754 *
7755 * @since 1.14 (J) - 1.3.11 (WP)
7756 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
7757 */
7758 $pref_countries = VikRequest::getVar('pref_countries', array());
7759 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
7760 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
7761 if (!empty($cust_pref_countries)) {
7762 $all_custom_prefcountries = array();
7763 $cust_pref_countries = explode(',', $cust_pref_countries);
7764 foreach ($cust_pref_countries as $cust_pref_country) {
7765 $cust_pref_country = trim(strtolower($cust_pref_country));
7766 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
7767 continue;
7768 }
7769 array_push($all_custom_prefcountries, $cust_pref_country);
7770 }
7771 if (count($all_custom_prefcountries)) {
7772 $pref_countries = $all_custom_prefcountries;
7773 }
7774 }
7775 $config->set('preferred_countries', $pref_countries);
7776 //
7777
7778 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
7779 $config->set('gmapskey', $gmapskey);
7780
7781 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
7782 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
7783 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
7784 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
7785 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
7786 $pref_colors = array(
7787 'textcolor' => $pref_textcolor,
7788 'bgcolor' => $pref_bgcolor,
7789 'fontcolor' => $pref_fontcolor,
7790 'bgcolorhov' => $pref_bgcolorhov,
7791 'fontcolorhov' => $pref_fontcolorhov,
7792 );
7793 $config->set('pref_colors', $pref_colors);
7794
7795 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
7796 $config->set('interactive_map', $interactive_map);
7797
7798 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
7799 $config->set('noemptydecimals', $noemptydecimals);
7800
7801 /**
7802 * Appearance preferences (light, auto, dark mode).
7803 *
7804 * @since 1.15.0 (J) - 1.5.0 (WP)
7805 */
7806 $appearance_pref = VikRequest::getString('appearance_pref', '');
7807 $config->set('appearance_pref', $appearance_pref);
7808
7809 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
7810 $picon = "";
7811 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
7812 jimport('joomla.filesystem.file');
7813 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
7814 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
7815 if (file_exists($res_backend_path.$safename)) {
7816 $j = 1;
7817 while (file_exists($res_backend_path.$j.$safename)) {
7818 $j++;
7819 }
7820 $pwhere = $res_backend_path.$j.$safename;
7821 } else {
7822 $j = "";
7823 $pwhere = $res_backend_path.$safename;
7824 }
7825 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7826 @unlink($pwhere);
7827 $picon = "";
7828 } else {
7829 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
7830 @chmod($pwhere, 0644);
7831 $picon = $j.$safename;
7832 }
7833 }
7834 if (!empty($picon)) {
7835 $config->set('sitelogo', $picon);
7836 }
7837 }
7838 $pbackicon = "";
7839 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
7840 jimport('joomla.filesystem.file');
7841 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
7842 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
7843 if (file_exists($res_backend_path.$safename)) {
7844 $j = 1;
7845 while (file_exists($res_backend_path.$j.$safename)) {
7846 $j++;
7847 }
7848 $pwhere = $res_backend_path.$j.$safename;
7849 } else {
7850 $j = "";
7851 $pwhere = $res_backend_path.$safename;
7852 }
7853 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7854 @unlink($pwhere);
7855 $pbackicon = "";
7856 } else {
7857 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
7858 @chmod($pwhere, 0644);
7859 $pbackicon = $j.$safename;
7860 }
7861 }
7862 if (!empty($pbackicon)) {
7863 $config->set('backlogo', $pbackicon);
7864 }
7865 }
7866 $config->set('vcmautoupd', $pvcmautoupd);
7867 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
7868 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
7869 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
7870 $config->set('searchsuggestions', $psearchsuggestions);
7871 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
7872 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
7873
7874 // translatable text
7875 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
7876 $dbo->setQuery($q);
7877 $dbo->execute();
7878
7879 // translatable text
7880 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
7881 $dbo->setQuery($q);
7882 $dbo->execute();
7883
7884 // translatable text
7885 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
7886 $dbo->setQuery($q);
7887 $dbo->execute();
7888
7889 // terms and conditions
7890 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
7891 $dbo->setQuery($q);
7892 $dbo->execute();
7893 if ($dbo->getNumRows() > 0) {
7894 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
7895 $dbo->setQuery($q);
7896 $dbo->execute();
7897 } else {
7898 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
7899 $dbo->setQuery($q);
7900 $dbo->execute();
7901 }
7902
7903 $config->set('adminemail', $padminemail);
7904 $config->set('senderemail', $psenderemail);
7905 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
7906 $config->set('datesep', $pdatesep);
7907 $config->set('resmodcanc', $presmodcanc);
7908 $config->set('resmodcancmin', $presmodcancmin);
7909 $config->set('minuteslock', $pminuteslock);
7910 $config->set('minautoremove', $pminautoremove);
7911
7912 $openingh = $ptimeopenstorefh * 3600;
7913 $openingm = $ptimeopenstorefm * 60;
7914 $openingts = $openingh + $openingm;
7915 $closingh = $ptimeopenstoreth * 3600;
7916 $closingm = $ptimeopenstoretm * 60;
7917 $closingts = $closingh + $closingm;
7918 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
7919 $prevtimes = $config->get('timeopenstore', '');
7920 if ($prevtimes != $openingts . "-" . $closingts) {
7921 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
7922 $dbo->setQuery($q);
7923 $dbo->execute();
7924 if ($dbo->getNumRows() > 0) {
7925 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
7926 /**
7927 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
7928 * for all reservations to avoid issues with the availability.
7929 *
7930 * @since August 29th 2018
7931 */
7932 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>');
7933 //
7934 }
7935 }
7936 $config->set('timeopenstore', $openingts . "-" . $closingts);
7937
7938 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
7939 $phoursmorebookingback = "0";
7940 if ($closingts > $openingts) {
7941 $diffcheck = ($closingts - $openingts) / 3600;
7942 $phoursmorebookingback = ceil($diffcheck);
7943 }
7944 $config->set('hoursmorebookingback', $phoursmorebookingback);
7945 $config->set('hoursmoreroomavail', '0');
7946 $config->set('multilang', $pmultilang);
7947 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
7948 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
7949 $config->set('todaybookings', $ptodaybookings);
7950 $config->set('bootstrap', $ploadbootstrap);
7951 $config->set('usefa', $pusefa);
7952 $config->set('loadjquery', $ploadjquery);
7953 $config->set('calendar', $pcalendar);
7954 $config->set('enablecoupons', $penablecoupons);
7955 $config->set('enablepin', $penablepin);
7956 $config->set('mindaysadvance', $pmindaysadvance);
7957 $config->set('autodefcalnights', $pautodefcalnights);
7958 $config->set('numrooms', $pnumrooms);
7959 $config->set('numadults', $confnumadults);
7960 $config->set('numchildren', $confnumchildren);
7961 $config->set('closingdates', $closing_dates);
7962 $config->set('smartsearch', $psmartsearch);
7963 $config->set('maxdate', $maxdate_str);
7964 $config->set('cronkey', $pcronkey);
7965
7966 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
7967 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
7968 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
7969 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
7970 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
7971 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
7972 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
7973 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
7974 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
7975 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
7976 $pnumdecimals = intval($pnumdecimals);
7977 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
7978 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
7979 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
7980 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
7981 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
7982 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
7983 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
7984 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
7985 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
7986 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
7987 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
7988 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
7989 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
7990 $pbctagname = VikRequest::getVar('bctagname', array());
7991 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
7992 $pbctagrule = VikRequest::getVar('bctagrule', array());
7993 $bctags_arr = array();
7994 $bctags_rules = array();
7995 if (count($pbctagname) > 0) {
7996 foreach ($pbctagname as $bctk => $bctv) {
7997 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
7998 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
7999 $bctags_rules[] = $pbctagrule[$bctk];
8000 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8001 }
8002 }
8003 }
8004 }
8005 //theme
8006 $ptheme = VikRequest::getString('theme', '', 'request');
8007 if (empty($ptheme) || $ptheme == 'default') {
8008 $ptheme = 'default';
8009 } else {
8010 $validtheme = false;
8011 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8012 if (count($themes) > 0) {
8013 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8014 foreach ($themes as $th) {
8015 if (is_dir($th)) {
8016 $tname = str_replace($strip, '', $th);
8017 if ($tname == $ptheme) {
8018 $validtheme = true;
8019 break;
8020 }
8021 }
8022 }
8023 }
8024 if ($validtheme == false) {
8025 $ptheme = 'default';
8026 }
8027 }
8028 $config->set('theme', $ptheme);
8029 //
8030 $config->set('showpartlyreserved', $pshowpartlyreserved);
8031 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8032 $config->set('numcalendars', $pnumcalendars);
8033
8034 // record may not be set
8035 $config->set('thumbsize', $pthumbsize);
8036
8037 $config->set('firstwday', $pfirstwday);
8038
8039 // translatable text
8040 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8041 $dbo->setQuery($q);
8042 $dbo->execute();
8043
8044 $config->set('fronttitletag', $pfronttitletag);
8045 $config->set('fronttitletagclass', $pfronttitletagclass);
8046 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8047
8048 // translatable texts
8049 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8050 $dbo->setQuery($q);
8051 $dbo->execute();
8052 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8053 $dbo->setQuery($q);
8054 $dbo->execute();
8055
8056 $config->set('currencyname', $pcurrencyname);
8057 $config->set('currencysymb', $pcurrencysymb);
8058 $config->set('currencycodepp', $pcurrencycodepp);
8059 $config->set('numberformat', $numberformatstr);
8060 // bookings color tags
8061 $config->set('bookingsctags', $bctags_arr);
8062
8063 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8064 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8065 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8066 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8067 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8068 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8069 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8070 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8071 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8072 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8073 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8074 $pmultipay = VikRequest::getString('multipay', '', 'request');
8075 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8076 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8077 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8078 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8079 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8080
8081 // translatable text
8082 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8083 $dbo->setQuery($q);
8084 $dbo->execute();
8085 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8086 $dbo->setQuery($q);
8087 $dbo->execute();
8088
8089 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8090 $config->set('taxsummary', $ptaxsummary);
8091 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8092
8093 $config->set('ccpaypal', $pccpaypal);
8094 $config->set('payaccpercent', $ppayaccpercent);
8095 $config->set('typedeposit', $ptypedeposit);
8096 $config->set('depoverrides', $pdepoverrides);
8097 $config->set('multipay', $pmultipay);
8098 $config->set('depifdaysadv', $pdepifdaysadv);
8099 $config->set('nodepnonrefund', $pnodepnonrefund);
8100 $config->set('depcustchoice', $pdepcustchoice);
8101
8102 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8103 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8104 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8105 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8106 $config->set('emailsendwhen', $psendemailwhen);
8107 $config->set('attachical', $pattachical);
8108
8109 // SMS APIs
8110 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8111 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8112 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8113 $psmssendto = VikRequest::getVar('smssendto', array());
8114 $sms_sendto = array();
8115 foreach ($psmssendto as $sto) {
8116 if (in_array($sto, array('admin', 'customer'))) {
8117 $sms_sendto[] = $sto;
8118 }
8119 }
8120 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8121 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8122 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8123 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8124 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8125 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8126 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8127 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8128 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8129 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8130 $smsparamarr = array();
8131 if (count($viksmsparams) > 0) {
8132 foreach ($viksmsparams as $setting => $cont) {
8133 if (strlen($setting) > 0) {
8134 $smsparamarr[$setting] = $cont;
8135 }
8136 }
8137 }
8138 $config->set('smsapi', $psmsapi);
8139 $config->set('smsautosend', $psmsautosend);
8140 $config->set('smssendto', $sms_sendto);
8141 $config->set('smssendwhen', $psmssendwhen);
8142 $config->set('smsadminphone', $psmsadminphone);
8143 $config->set('smsparams', $smsparamarr);
8144
8145 // translatable texts
8146 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8147 $dbo->setQuery($q);
8148 $dbo->execute();
8149 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8150 $dbo->setQuery($q);
8151 $dbo->execute();
8152 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8153 $dbo->setQuery($q);
8154 $dbo->execute();
8155 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8156 $dbo->setQuery($q);
8157 $dbo->execute();
8158 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8159 $dbo->setQuery($q);
8160 $dbo->execute();
8161 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8162 $dbo->setQuery($q);
8163 $dbo->execute();
8164
8165 /**
8166 * Backup settings
8167 *
8168 * @since 1.15.0 (J) - 1.5.0 (WP)
8169 */
8170 $backup_type = $app->input->getString('backuptype', 'full');
8171 $backup_folder = $app->input->getString('backupfolder', '');
8172
8173 $tmp = $app->get('tmp_path');
8174
8175 if (!$backup_folder)
8176 {
8177 // path not specified, use temporary folder
8178 $backup_folder = $tmp;
8179 }
8180
8181 $current = $config->get('backupfolder');
8182
8183 if (!$current)
8184 {
8185 // path was missing, use temporary folder
8186 $current = $tmp;
8187 }
8188
8189 // check whether the backup folder has been moved
8190 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8191 {
8192 $backupModel = new VBOModelBackup();
8193
8194 // backup folder moved, try to copy all the existing overrides
8195 if (!$backupModel->moveArchives($backup_folder))
8196 {
8197 // iterate all errors and display them
8198 foreach ($backupModel->getErrors() as $error)
8199 {
8200 $app->enqueueMessage($error, 'warning');
8201 }
8202 }
8203 }
8204
8205 // save configuration
8206 $config->set('backuptype', $backup_type);
8207 $config->set('backupfolder', $backup_folder);
8208
8209 /**
8210 * Check-in data collection type.
8211 *
8212 * @since 1.15.0 (J) - 1.5.0 (WP)
8213 */
8214 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8215
8216 /**
8217 * Front-end appearance.
8218 *
8219 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8220 */
8221 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8222
8223 /**
8224 * Split stays.
8225 *
8226 * @since 1.16.0 (J) - 1.6.0 (WP)
8227 */
8228 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8229 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8230 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8231 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8232
8233 /**
8234 * Re-build Web App manifest file to let the event trigger.
8235 *
8236 * @since 1.16.5 (J) - 1.6.5 (WP)
8237 */
8238 try {
8239 VBOWebappManifest::build();
8240 } catch (Exception $e) {
8241 // do nothing
8242 }
8243
8244 // redirect
8245 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8246 $app->redirect('index.php?option=com_vikbooking&task=config');
8247 $app->close();
8248 }
8249
8250 /**
8251 * Task to unify the check-in and check-out times for all reservations.
8252 */
8253 public function unifycheckinout()
8254 {
8255 $dbo = JFactory::getDbo();
8256 $app = JFactory::getApplication();
8257 $user = JFactory::getUser();
8258
8259 $fh = VikRequest::getInt('fh', 12, 'request');
8260 $fm = VikRequest::getInt('fm', 0, 'request');
8261 $th = VikRequest::getInt('th', 10, 'request');
8262 $tm = VikRequest::getInt('tm', 0, 'request');
8263
8264 $now = time();
8265 $totmod = 0;
8266 $totbookmod = 0;
8267
8268 // query all busy records
8269 $q = $dbo->getQuery(true)
8270 ->select('*')
8271 ->from($dbo->qn('#__vikbooking_busy'));
8272
8273 $dbo->setQuery($q);
8274 $records = $dbo->loadAssocList();
8275
8276 foreach ($records as $v) {
8277 $info_start = getdate($v['checkin']);
8278 $info_end = getdate($v['checkout']);
8279 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8280 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8281
8282 $q = $dbo->getQuery(true)
8283 ->update($dbo->qn('#__vikbooking_busy'))
8284 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8285 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8286 ->set($dbo->qn('realback') . ' = ' . $new_end)
8287 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8288
8289 $dbo->setQuery($q, 0, 1);
8290 $dbo->execute();
8291
8292 $totmod++;
8293 }
8294
8295 // query all bookings
8296 $q = $dbo->getQuery(true)
8297 ->select($dbo->qn([
8298 'id',
8299 'days',
8300 'checkin',
8301 'checkout',
8302 'total',
8303 ]))
8304 ->from($dbo->qn('#__vikbooking_orders'))
8305 ->order($dbo->qn('checkin') . ' DESC');
8306
8307 $dbo->setQuery($q);
8308 $records = $dbo->loadAssocList();
8309
8310 foreach ($records as $v) {
8311 $info_start = getdate($v['checkin']);
8312 $info_end = getdate($v['checkout']);
8313 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8314 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8315
8316 $q = $dbo->getQuery(true)
8317 ->update($dbo->qn('#__vikbooking_orders'))
8318 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8319 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8320 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8321
8322 $dbo->setQuery($q, 0, 1);
8323 $dbo->execute();
8324
8325 /**
8326 * In case the operation changed the check-in/check-out time for this booking,
8327 * store a new history record for a booking modification.
8328 *
8329 * @since 1.16.6 (J) - 1.6.6 (WP)
8330 */
8331 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8332 // Booking History
8333 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8334 }
8335
8336 $totbookmod++;
8337 }
8338
8339 $app->enqueueMessage('OK: ' . $totbookmod);
8340 $app->redirect("index.php?option=com_vikbooking&task=config");
8341 $app->close();
8342 }
8343
8344 public function savetmplfile() {
8345 if (!JSession::checkToken()) {
8346 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8347 }
8348 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8349 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8350 $mainframe = JFactory::getApplication();
8351 $exists = file_exists($fpath) ? true : false;
8352 if (!$exists) {
8353 $fpath = urldecode($fpath);
8354 }
8355 $fpath = file_exists($fpath) ? $fpath : '';
8356 if (!empty($fpath)) {
8357 $fp = fopen($fpath, 'wb');
8358 $byt = (int)fwrite($fp, $pcont);
8359 fclose($fp);
8360 if ($byt > 0) {
8361 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8362
8363 if (VBOPlatformDetection::isWordPress()) {
8364 /**
8365 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8366 */
8367 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8368 }
8369 } else {
8370 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8371 }
8372 } else {
8373 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8374 }
8375 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8376
8377 exit;
8378 }
8379
8380 public function edittmplfile() {
8381 //modal box, so we do not set menu or footer
8382
8383 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8384
8385 parent::display();
8386 }
8387
8388 public function tmplfileprew() {
8389 //modal box, so we do not set menu or footer
8390
8391 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8392
8393 parent::display();
8394 }
8395
8396 public function invoices() {
8397 VikBookingHelper::printHeader("invoices");
8398
8399 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8400
8401 parent::display();
8402
8403 if (VikBooking::showFooter()) {
8404 VikBookingHelper::printFooter();
8405 }
8406 }
8407
8408 public function newmaninvoice() {
8409 VikBookingHelper::printHeader("invoices");
8410
8411 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8412
8413 parent::display();
8414
8415 if (VikBooking::showFooter()) {
8416 VikBookingHelper::printFooter();
8417 }
8418 }
8419
8420 public function editmaninvoice() {
8421 VikBookingHelper::printHeader("invoices");
8422
8423 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8424
8425 parent::display();
8426
8427 if (VikBooking::showFooter()) {
8428 VikBookingHelper::printFooter();
8429 }
8430 }
8431
8432 public function savemaninvoice() {
8433 if (!JSession::checkToken()) {
8434 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8435 }
8436 $this->do_storemaninvoice('save');
8437 $mainframe = JFactory::getApplication();
8438 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8439 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8440 if (!empty($pgoto)) {
8441 $mainframe->redirect(base64_decode($pgoto));
8442 exit;
8443 }
8444 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8445 }
8446
8447 public function updatemaninvoice() {
8448 if (!JSession::checkToken()) {
8449 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8450 }
8451 $invid = VikRequest::getInt('whereup', 0, 'request');
8452 $this->do_storemaninvoice('update', $invid);
8453 $mainframe = JFactory::getApplication();
8454 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8455 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8456 if (!empty($pgoto)) {
8457 $mainframe->redirect(base64_decode($pgoto));
8458 exit;
8459 }
8460 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8461 }
8462
8463 public function updatemaninvoicestay() {
8464 $invid = VikRequest::getInt('whereup', 0, 'request');
8465 $this->do_storemaninvoice('updatestay', $invid);
8466 $mainframe = JFactory::getApplication();
8467 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8468 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8469 if (!empty($pgoto)) {
8470 $mainframe->redirect(base64_decode($pgoto));
8471 exit;
8472 }
8473 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8474 }
8475
8476 private function do_storemaninvoice($action, $invid = 0) {
8477 $dbo = JFactory::getDBO();
8478 $mainframe = JFactory::getApplication();
8479 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8480 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8481 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8482 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8483 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8484 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8485 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8486 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8487 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8488 if (empty($pidcustomer)) {
8489 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8490 $mainframe->redirect($error_uri);
8491 exit;
8492 }
8493 $services = VikRequest::getVar('service', array());
8494 $nets = VikRequest::getVar('net', array());
8495 $aliqs = VikRequest::getVar('aliq', array());
8496 $taxs = VikRequest::getVar('tax', array());
8497 $tots = VikRequest::getVar('tot', array());
8498 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8499 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8500 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8501 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8502 VikError::raiseWarning('', 'Missing data.');
8503 $mainframe->redirect($error_uri);
8504 exit;
8505 }
8506 $rawcont = array(
8507 'rows' => array(),
8508 'totalnet' => $ptotalnet,
8509 'totaltax' => $ptotaltax,
8510 'totaltot' => $ptotaltot,
8511 'notes' => $pinvoice_notes,
8512 );
8513 foreach ($services as $k => $service) {
8514 if (empty($service)) {
8515 continue;
8516 }
8517 array_push($rawcont['rows'], array(
8518 'service' => $service,
8519 'net' => (float)$nets[$k],
8520 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8521 'tax' => (float)$taxs[$k],
8522 'tot' => (float)$tots[$k],
8523 ));
8524 }
8525 // store/update manual invoice
8526 $nowts = time();
8527 $retval = 0;
8528 if (strpos($action, 'save') !== false) {
8529 $pdffname = $nowts . '_' . rand() . '.pdf';
8530 $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)).");";
8531 $dbo->setQuery($q);
8532 $dbo->execute();
8533 $retval = $dbo->insertid();
8534 } else {
8535 // fetch old record
8536 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8537 $dbo->setQuery($q);
8538 $dbo->execute();
8539 if (!$dbo->getNumRows()) {
8540 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8541 $mainframe->redirect($error_uri);
8542 exit;
8543 }
8544 $previnvoice = $dbo->loadAssoc();
8545 //
8546 $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'].";";
8547 $dbo->setQuery($q);
8548 $dbo->execute();
8549 $retval = $previnvoice['id'];
8550 }
8551 // update config values for the invoice
8552 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8553 $dbo->setQuery($q);
8554 $dbo->execute();
8555 // generate the custom invoice
8556 $result = VikBooking::generateCustomInvoice($retval);
8557 //
8558 $nextinv = VikBooking::getNextInvoiceNumber();
8559 $updatenum = ($pinvoice_num >= $nextinv);
8560 if ($updatenum) {
8561 /**
8562 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
8563 * to avoid conflicts with the drivers for the e-invoices generation.
8564 */
8565 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8566 $dbo->setQuery($q);
8567 $dbo->execute();
8568 }
8569
8570 return $retval;
8571 }
8572
8573 public function downloadinvoices() {
8574 $ids = VikRequest::getVar('cid', array(0));
8575 if (@count($ids) > 0) {
8576 $dbo = JFactory::getDBO();
8577 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
8578 $dbo->setQuery($q);
8579 $dbo->execute();
8580 if ($dbo->getNumRows() > 0) {
8581 $invoices = $dbo->loadAssocList();
8582 if (!(count($invoices) > 1)) {
8583 //Single Invoice Download
8584 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
8585 header("Content-type:application/pdf");
8586 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
8587 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
8588 exit;
8589 }
8590 } else {
8591 //Multiple Invoices Download
8592 $to_zip = array();
8593 foreach ($invoices as $k => $invoice) {
8594 $to_zip[$k]['name'] = $invoice['file_name'];
8595 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
8596 }
8597 if (class_exists('ZipArchive')) {
8598 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
8599 $zip = new ZipArchive;
8600 $zip->open($zip_path, ZipArchive::CREATE);
8601 foreach ($to_zip as $k => $zipv) {
8602 $zip->addFile($zipv['path'], $zipv['name']);
8603 }
8604 $zip->close();
8605 header("Content-type:application/zip");
8606 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
8607 header("Content-Length:".filesize($zip_path));
8608 readfile($zip_path);
8609 unlink($zip_path);
8610 exit;
8611 } else {
8612 //Class ZipArchive does not exist
8613 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
8614 }
8615 }
8616 }
8617 }
8618 $mainframe = JFactory::getApplication();
8619 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8620 }
8621
8622 public function resendinvoices() {
8623 $ids = VikRequest::getVar('cid', array(0));
8624 $mainframe = JFactory::getApplication();
8625 if (!(count($ids) > 0)) {
8626 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8627 exit;
8628 }
8629 $dbo = JFactory::getDBO();
8630 $invoices = array();
8631 $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` ".
8632 "FROM `#__vikbooking_invoices` AS `i` " .
8633 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
8634 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
8635 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
8636 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
8637 $dbo->setQuery($q);
8638 $dbo->execute();
8639 if ($dbo->getNumRows() > 0) {
8640 $invoices = $dbo->loadAssocList();
8641 }
8642 if (!(count($invoices) > 0)) {
8643 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8644 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8645 exit;
8646 }
8647 $tot_generated = 0;
8648 $tot_sent = 0;
8649 foreach ($invoices as $bkey => $invoice) {
8650 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
8651 $invoices[$bkey] = $invoice;
8652 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
8653 if ($send_res !== false) {
8654 $tot_sent++;
8655 }
8656 }
8657 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8658 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8659 }
8660
8661 public function removeinvoices() {
8662 $ids = VikRequest::getVar('cid', array());
8663 $tot_removed = 0;
8664 $dbo = JFactory::getDbo();
8665
8666 foreach ($ids as $d) {
8667 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8668 $dbo->setQuery($q);
8669 $dbo->execute();
8670 if ($dbo->getNumRows() == 1) {
8671 $cur_invoice = $dbo->loadAssoc();
8672 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
8673 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
8674 }
8675 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8676 $dbo->setQuery($q);
8677 $dbo->execute();
8678 $tot_removed++;
8679 }
8680 }
8681
8682 $mainframe = JFactory::getApplication();
8683 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
8684 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8685 }
8686
8687 public function geninvoices() {
8688 $ids = VikRequest::getVar('cid', array(0));
8689 $mainframe = JFactory::getApplication();
8690 if (!count($ids)) {
8691 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8692 exit;
8693 }
8694 $dbo = JFactory::getDBO();
8695 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8696 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8697 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8698 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
8699 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8700 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8701 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
8702 $pinvoice_send = $pinvoice_send > 0 ? true : false;
8703 $increment_inv = true;
8704 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
8705 //if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
8706 if (count($ids) == 1) {
8707 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
8708 $dbo->setQuery($q);
8709 $dbo->execute();
8710 if ($dbo->getNumRows() == 1) {
8711 $increment_inv = false;
8712 }
8713 }
8714 //
8715 $bookings = array();
8716 $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` 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` IN (".implode(', ', $ids).") AND `o`.`status`='confirmed' AND `o`.`total` > 0 ORDER BY `o`.`id` ASC;";
8717 $dbo->setQuery($q);
8718 $dbo->execute();
8719 if ($dbo->getNumRows() > 0) {
8720 $bookings = $dbo->loadAssocList();
8721 }
8722 if (!count($bookings)) {
8723 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8724 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8725 exit;
8726 }
8727 $tot_generated = 0;
8728 $tot_sent = 0;
8729 foreach ($bookings as $bkey => $booking) {
8730 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
8731 if ($gen_res !== false && $gen_res > 0) {
8732 $tot_generated++;
8733 $pinvoice_num++;
8734 if ($pinvoice_send) {
8735 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
8736 if ($send_res !== false) {
8737 $tot_sent++;
8738 }
8739 }
8740 } else {
8741 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
8742 }
8743 }
8744 if ($tot_generated > 0 && $increment_inv === true) {
8745 /**
8746 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
8747 * to avoid conflicts with the drivers for the e-invoices generation.
8748 */
8749 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8750 $dbo->setQuery($q);
8751 $dbo->execute();
8752 }
8753 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
8754 $dbo->setQuery($q);
8755 $dbo->execute();
8756 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8757 $dbo->setQuery($q);
8758 $dbo->execute();
8759 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8760 if ($pconfirmgen > 0) {
8761 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
8762 } elseif (count($bookings) === 1) {
8763 // go to the back-end booking details page
8764 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
8765 } else {
8766 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8767 }
8768 }
8769
8770 public function optionals() {
8771 VikBookingHelper::printHeader("6");
8772
8773 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
8774
8775 parent::display();
8776
8777 if (VikBooking::showFooter()) {
8778 VikBookingHelper::printFooter();
8779 }
8780 }
8781
8782 public function newoptionals() {
8783 VikBookingHelper::printHeader("6");
8784
8785 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8786
8787 parent::display();
8788
8789 if (VikBooking::showFooter()) {
8790 VikBookingHelper::printFooter();
8791 }
8792 }
8793
8794 public function editoptional() {
8795 VikBookingHelper::printHeader("6");
8796
8797 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8798
8799 parent::display();
8800
8801 if (VikBooking::showFooter()) {
8802 VikBookingHelper::printFooter();
8803 }
8804 }
8805
8806 public function updateoptional() {
8807 if (!JSession::checkToken()) {
8808 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8809 }
8810 $this->do_updateoptional();
8811 }
8812
8813 public function updateoptionalstay() {
8814 if (!JSession::checkToken()) {
8815 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8816 }
8817 $this->do_updateoptional(true);
8818 }
8819
8820 private function do_updateoptional($stay = false) {
8821 $dbo = JFactory::getDbo();
8822 $app = JFactory::getApplication();
8823 $poptname = VikRequest::getString('optname', '', 'request');
8824 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
8825 $poptcost = VikRequest::getFloat('optcost', '', 'request');
8826 $poptperday = VikRequest::getString('optperday', '', 'request');
8827 $poptperperson = VikRequest::getString('optperperson', '', 'request');
8828 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
8829 $popthmany = VikRequest::getString('opthmany', '', 'request');
8830 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
8831 $pwhereup = VikRequest::getString('whereup', '', 'request');
8832 $pautoresize = VikRequest::getString('autoresize', '', 'request');
8833 $presizeto = VikRequest::getString('resizeto', '', 'request');
8834 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
8835 $pifchildren = $pifchildren == "1" ? 1 : 0;
8836 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
8837 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
8838 $pforcesel = VikRequest::getString('forcesel', '', 'request');
8839 $pforceval = VikRequest::getString('forceval', '', 'request');
8840 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
8841 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
8842 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
8843 $pforcesel = $pforcesel == "1" ? 1 : 0;
8844 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
8845 $pis_fee = VikRequest::getString('is_fee', '', 'request');
8846 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
8847 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
8848 $pagefrom = VikRequest::getVar('agefrom', array());
8849 $pageto = VikRequest::getVar('ageto', array());
8850 $pagecost = VikRequest::getVar('agecost', array());
8851 $pagectype = VikRequest::getVar('agectype', array());
8852 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
8853 $pavfrom = VikRequest::getString('avfrom', '', 'request');
8854 $pavto = VikRequest::getString('avto', '', 'request');
8855 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
8856 $pidrooms = VikRequest::getVar('idrooms', array());
8857 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
8858 if ($pforcesel == 1) {
8859 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
8860 } else {
8861 $strforceval = "";
8862 }
8863 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
8864 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
8865 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
8866 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
8867 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
8868 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
8869 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
8870 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
8871 $minguests = VikRequest::getInt('minguests', 0, 'request');
8872 $minguests_conflict = false;
8873 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
8874 if ($minguestsnum >= $maxguestsnum) {
8875 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
8876 } elseif (($maxguestsnum - $minguestsnum) < 2) {
8877 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
8878 }
8879 }
8880 if (!$minguests || $minguests_conflict !== false) {
8881 $minguestsnum = 0;
8882 $maxguestsnum = 0;
8883 if ($minguests_conflict !== false) {
8884 // raise warning, but do not stop the process
8885 VikError::raiseWarning('', $minguests_conflict);
8886 }
8887 }
8888 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
8889 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
8890 $oparams = array(
8891 'minguestsnum' => $minguestsnum,
8892 'mingueststype' => $mingueststype,
8893 'maxguestsnum' => $maxguestsnum,
8894 'maxgueststype' => $maxgueststype,
8895 'damagedep' => $damagedep,
8896 'pet_fee' => $pet_fee,
8897 );
8898 /**
8899 * We fetch the previous params to merge them with the new ones
8900 * in case some properties have been set somewhere else.
8901 * For example, the damage deposit transmission to Booking.com.
8902 */
8903 $cur_oparams = array();
8904 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
8905 $dbo->setQuery($q);
8906 $dbo->execute();
8907 if ($dbo->getNumRows()) {
8908 $cur_oparams = $dbo->loadResult();
8909 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
8910 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
8911 // merge previous params with the new ones to get the new values
8912 $oparams = array_merge($cur_oparams, $oparams);
8913 }
8914 //
8915 if (!empty($poptname)) {
8916 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
8917 jimport('joomla.filesystem.file');
8918 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
8919 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
8920 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
8921 if (file_exists($updpath.$safename)) {
8922 $j=1;
8923 while (file_exists($updpath.$j.$safename)) {
8924 $j++;
8925 }
8926 $pwhere=$updpath.$j.$safename;
8927 } else {
8928 $j="";
8929 $pwhere=$updpath.$safename;
8930 }
8931 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8932 @unlink($pwhere);
8933 $picon="";
8934 } else {
8935 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
8936 @chmod($pwhere, 0644);
8937 $picon=$j.$safename;
8938 if ($pautoresize=="1" && !empty($presizeto)) {
8939 $eforj = new vikResizer();
8940 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
8941 if ($origmod) {
8942 @unlink($pwhere);
8943 $picon='r_'.$j.$safename;
8944 }
8945 }
8946 }
8947 } else {
8948 $picon="";
8949 }
8950 } else {
8951 $picon="";
8952 }
8953 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
8954 $poptperperson=($poptperperson=="each" ? "1" : "0");
8955 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
8956 $ageintervalstr = '';
8957 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
8958 foreach ($pagefrom as $kage => $vage) {
8959 $afrom = intval($vage);
8960 $ato = intval($pageto[$kage]);
8961 $acost = floatval($pagecost[$kage]);
8962 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
8963 if ($ato < $afrom) $ato = $afrom;
8964 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
8965 }
8966 }
8967 $ageintervalstr = rtrim($ageintervalstr, ';;');
8968 if (!empty($ageintervalstr)) {
8969 $pforcesel = 1;
8970 }
8971 }
8972 $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).";";
8973 $dbo->setQuery($q);
8974 $dbo->execute();
8975 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
8976
8977 // assign/unset option-rooms relations
8978 $rooms_with_opt = array();
8979 if (count($pidrooms)) {
8980 // assign this new option to the requested rooms
8981 foreach ($pidrooms as $idroom) {
8982 if (empty($idroom)) {
8983 continue;
8984 }
8985 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
8986 $dbo->setQuery($q);
8987 $dbo->execute();
8988 if (!$dbo->getNumRows()) {
8989 continue;
8990 }
8991 $room_data = $dbo->loadAssoc();
8992 array_push($rooms_with_opt, $room_data['id']);
8993 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
8994 if (in_array((string)$pwhereup, $current_opts)) {
8995 continue;
8996 }
8997 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
8998 // make sure we do not concatenate a real ID to 0
8999 $current_opts = array();
9000 }
9001 array_push($current_opts, $pwhereup);
9002 $new_opts = implode(';', $current_opts) . ';';
9003 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9004 $dbo->setQuery($q);
9005 $dbo->execute();
9006 }
9007 }
9008 if (!count($rooms_with_opt)) {
9009 // get all rooms to unset this option (if previously set)
9010 array_push($rooms_with_opt, '0');
9011 }
9012 // unset the option from the other rooms that may have it
9013 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9014 $dbo->setQuery($q);
9015 $dbo->execute();
9016 if ($dbo->getNumRows()) {
9017 $unset_rooms_opt = $dbo->loadAssocList();
9018 foreach ($unset_rooms_opt as $room_data) {
9019 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9020 if (!in_array((string)$pwhereup, $current_opts)) {
9021 // this room is not using this option
9022 continue;
9023 }
9024 $optkey = array_search((string)$pwhereup, $current_opts);
9025 if ($optkey === false) {
9026 // key not found
9027 continue;
9028 }
9029 // unset this option ID from the string
9030 unset($current_opts[$optkey]);
9031 if (!count($current_opts)) {
9032 // a room with no options assigned will be listed as "0;"
9033 $current_opts = array(0);
9034 }
9035 $new_opts = implode(';', $current_opts) . ';';
9036 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9037 $dbo->setQuery($q);
9038 $dbo->execute();
9039 }
9040 }
9041 //
9042
9043 }
9044 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9045 }
9046
9047 public function createoptionals() {
9048 if (!JSession::checkToken()) {
9049 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9050 }
9051 $this->do_createoptionals();
9052 }
9053
9054 public function createoptionalsstay() {
9055 if (!JSession::checkToken()) {
9056 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9057 }
9058 $this->do_createoptionals(true);
9059 }
9060
9061 private function do_createoptionals($stay = false) {
9062 $dbo = JFactory::getDbo();
9063 $poptname = VikRequest::getString('optname', '', 'request');
9064 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9065 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9066 $poptperday = VikRequest::getString('optperday', '', 'request');
9067 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9068 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9069 $popthmany = VikRequest::getString('opthmany', '', 'request');
9070 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9071 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9072 $presizeto = VikRequest::getString('resizeto', '', 'request');
9073 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9074 $pifchildren = $pifchildren == "1" ? 1 : 0;
9075 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9076 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9077 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9078 $pforceval = VikRequest::getString('forceval', '', 'request');
9079 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9080 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9081 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9082 $pforcesel = $pforcesel == "1" ? 1 : 0;
9083 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9084 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9085 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9086 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9087 $pagefrom = VikRequest::getVar('agefrom', array());
9088 $pageto = VikRequest::getVar('ageto', array());
9089 $pagecost = VikRequest::getVar('agecost', array());
9090 $pagectype = VikRequest::getVar('agectype', array());
9091 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9092 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9093 $pavto = VikRequest::getString('avto', '', 'request');
9094 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9095 $pidrooms = VikRequest::getVar('idrooms', array());
9096 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9097 if ($pforcesel == 1) {
9098 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9099 } else {
9100 $strforceval = "";
9101 }
9102 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9103 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9104 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9105 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9106 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9107 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9108 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9109 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9110 $minguests = VikRequest::getInt('minguests', 0, 'request');
9111 $minguests_conflict = false;
9112 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9113 if ($minguestsnum >= $maxguestsnum) {
9114 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9115 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9116 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9117 }
9118 }
9119 if (!$minguests || $minguests_conflict !== false) {
9120 $minguestsnum = 0;
9121 $maxguestsnum = 0;
9122 if ($minguests_conflict !== false) {
9123 // raise warning, but do not stop the process
9124 VikError::raiseWarning('', $minguests_conflict);
9125 }
9126 }
9127 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9128 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9129 $oparams = array(
9130 'minguestsnum' => $minguestsnum,
9131 'mingueststype' => $mingueststype,
9132 'maxguestsnum' => $maxguestsnum,
9133 'maxgueststype' => $maxgueststype,
9134 'damagedep' => $damagedep,
9135 'pet_fee' => $pet_fee,
9136 );
9137 if (!empty($poptname)) {
9138 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9139 jimport('joomla.filesystem.file');
9140 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9141 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9142 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9143 if (file_exists($updpath.$safename)) {
9144 $j = 1;
9145 while (file_exists($updpath.$j.$safename)) {
9146 $j++;
9147 }
9148 $pwhere = $updpath.$j.$safename;
9149 } else {
9150 $j = "";
9151 $pwhere = $updpath.$safename;
9152 }
9153 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9154 @unlink($pwhere);
9155 $picon = "";
9156 } else {
9157 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9158 @chmod($pwhere, 0644);
9159 $picon = $j.$safename;
9160 if ($pautoresize == "1" && !empty($presizeto)) {
9161 $eforj = new vikResizer();
9162 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9163 if ($origmod) {
9164 @unlink($pwhere);
9165 $picon = 'r_'.$j.$safename;
9166 }
9167 }
9168 }
9169 } else {
9170 $picon = "";
9171 }
9172 } else {
9173 $picon = "";
9174 }
9175 $poptperday = ($poptperday == "each" ? "1" : "0");
9176 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9177 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9178 $ageintervalstr = '';
9179 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9180 foreach ($pagefrom as $kage => $vage) {
9181 $afrom = intval($vage);
9182 $ato = intval($pageto[$kage]);
9183 $acost = floatval($pagecost[$kage]);
9184 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9185 if ($ato < $afrom) $ato = $afrom;
9186 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9187 }
9188 }
9189 $ageintervalstr = rtrim($ageintervalstr, ';;');
9190 if (!empty($ageintervalstr)) {
9191 $pforcesel = 1;
9192 }
9193 }
9194 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9195 $dbo->setQuery($q);
9196 $dbo->execute();
9197 if ($dbo->getNumRows() == 1) {
9198 $getlast = $dbo->loadResult();
9199 $newsortnum = $getlast + 1;
9200 } else {
9201 $newsortnum = 1;
9202 }
9203 $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)) . ");";
9204 $dbo->setQuery($q);
9205 $dbo->execute();
9206 $newoptid = $dbo->insertid();
9207
9208 if (!empty($newoptid)) {
9209 // assign/unset option-rooms relations
9210 $rooms_with_opt = array();
9211 if (count($pidrooms)) {
9212 // assign this new option to the requested rooms
9213 foreach ($pidrooms as $idroom) {
9214 if (empty($idroom)) {
9215 continue;
9216 }
9217 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9218 $dbo->setQuery($q);
9219 $dbo->execute();
9220 if (!$dbo->getNumRows()) {
9221 continue;
9222 }
9223 $room_data = $dbo->loadAssoc();
9224 array_push($rooms_with_opt, $room_data['id']);
9225 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9226 if (in_array((string)$newoptid, $current_opts)) {
9227 continue;
9228 }
9229 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9230 // make sure we do not concatenate a real ID to 0
9231 $current_opts = array();
9232 }
9233 array_push($current_opts, $newoptid);
9234 $new_opts = implode(';', $current_opts) . ';';
9235 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9236 $dbo->setQuery($q);
9237 $dbo->execute();
9238 }
9239 }
9240 if (!count($rooms_with_opt)) {
9241 // get all rooms to unset this option (if previously set)
9242 array_push($rooms_with_opt, '0');
9243 }
9244 // unset the option from the other rooms that may have it
9245 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9246 $dbo->setQuery($q);
9247 $dbo->execute();
9248 if ($dbo->getNumRows()) {
9249 $unset_rooms_opt = $dbo->loadAssocList();
9250 foreach ($unset_rooms_opt as $room_data) {
9251 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9252 if (!in_array((string)$newoptid, $current_opts)) {
9253 // this room is not using this option
9254 continue;
9255 }
9256 $optkey = array_search((string)$newoptid, $current_opts);
9257 if ($optkey === false) {
9258 // key not found
9259 continue;
9260 }
9261 // unset this option ID from the string
9262 unset($current_opts[$optkey]);
9263 if (!count($current_opts)) {
9264 // a room with no options assigned will be listed as "0;"
9265 $current_opts = array(0);
9266 }
9267 $new_opts = implode(';', $current_opts) . ';';
9268 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9269 $dbo->setQuery($q);
9270 $dbo->execute();
9271 }
9272 }
9273 //
9274 }
9275
9276 }
9277 $mainframe = JFactory::getApplication();
9278 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9279 }
9280
9281 public function removeoptionals() {
9282 if (!JSession::checkToken()) {
9283 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9284 }
9285 $ids = VikRequest::getVar('cid', array(0));
9286 if (@count($ids)) {
9287 $dbo = JFactory::getDbo();
9288 foreach ($ids as $d) {
9289 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9290 $dbo->setQuery($q);
9291 $dbo->execute();
9292 if ($dbo->getNumRows() == 1) {
9293 $rows = $dbo->loadAssocList();
9294 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9295 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9296 }
9297 }
9298 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9299 $dbo->setQuery($q);
9300 $dbo->execute();
9301 }
9302 }
9303 $mainframe = JFactory::getApplication();
9304 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9305 }
9306
9307 public function sendcustomsms() {
9308 $mainframe = JFactory::getApplication();
9309 $pphone = VikRequest::getString('phone', '', 'request');
9310 $psmscont = VikRequest::getString('smscont', '', 'request');
9311 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9312 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9313 if (!empty($pphone) && !empty($psmscont)) {
9314 $sms_api = VikBooking::getSMSAPIClass();
9315 $sms_api_params = VikBooking::getSMSParams();
9316 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9317 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9318 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9319 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9320 if ( !$sms_obj->validateResponse($response_obj) ) {
9321 VikError::raiseWarning('', $sms_obj->getLog());
9322 } else {
9323 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9324 }
9325 } else {
9326 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9327 }
9328 } else {
9329 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9330 }
9331 $mainframe->redirect($pgoto);
9332 }
9333
9334 public function sendcustomemail() {
9335 $dbo = JFactory::getDbo();
9336 $mainframe = JFactory::getApplication();
9337 $vbo_tn = VikBooking::getTranslator();
9338 $pbid = VikRequest::getInt('bid', '', 'request');
9339 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9340 $pemail = VikRequest::getString('email', '', 'request');
9341 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9342 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9343 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9344 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9345 if (!empty($pemail) && !empty($pemailcont)) {
9346 $email_attach = null;
9347 jimport('joomla.filesystem.file');
9348 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9349 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9350 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9351 $src = $pemailattch['tmp_name'];
9352 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9353 $j = "";
9354 if (file_exists($dest.$filename)) {
9355 $j = rand(171, 1717);
9356 while (file_exists($dest.$j.$filename)) {
9357 $j++;
9358 }
9359 }
9360 $finaldest = $dest.$j.$filename;
9361 if (VikBooking::uploadFile($src, $finaldest)) {
9362 $email_attach = $finaldest;
9363 } else {
9364 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9365 $mainframe->redirect($pgoto);
9366 exit;
9367 }
9368 }
9369 //VBO 1.10 - special tags for the custom email template files and messages
9370 $orig_mail_cont = $pemailcont;
9371 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9372 // replace any possible placeholder for special tags
9373 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9374 return $match[2];
9375 }, $pemailcont);
9376
9377 $booking = array();
9378 $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.";";
9379 $dbo->setQuery($q);
9380 $dbo->execute();
9381 if ($dbo->getNumRows() > 0) {
9382 $booking = $dbo->loadAssoc();
9383 }
9384 $booking_rooms = array();
9385 $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.";";
9386 $dbo->setQuery($q);
9387 $dbo->execute();
9388 if ($dbo->getNumRows() > 0) {
9389 $booking_rooms = $dbo->loadAssocList();
9390 if (!empty($booking['lang'])) {
9391 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9392 }
9393 }
9394 //we use the same parsing function as the one for the Customer SMS Template
9395 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9396 }
9397 //
9398 // allow the use of token {booking_id} in subject
9399 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9400 //
9401 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9402 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9403 $vbo_app = VikBooking::getVboApplication();
9404 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9405 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9406 if ($email_attach !== null) {
9407 @unlink($email_attach);
9408 }
9409 //Booking History
9410 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9411 //
9412 //Save email template for future sending
9413 $config_rec_exists = false;
9414 $emtpl = array(
9415 'emailsubj' => $pemailsubj,
9416 'emailcont' => $orig_mail_cont,
9417 'emailfrom' => $pemailfrom
9418 );
9419 $cur_emtpl = array();
9420 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9421 $dbo->setQuery($q);
9422 $dbo->execute();
9423 if ($dbo->getNumRows() > 0) {
9424 $config_rec_exists = true;
9425 $cur_emtpl = $dbo->loadResult();
9426 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9427 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9428 }
9429 if (count($cur_emtpl) > 0) {
9430 $existing_subj = false;
9431 foreach ($cur_emtpl as $emk => $emv) {
9432 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9433 $cur_emtpl[$emk] = $emtpl;
9434 $existing_subj = true;
9435 break;
9436 }
9437 }
9438 if ($existing_subj === false) {
9439 $cur_emtpl[] = $emtpl;
9440 }
9441 } else {
9442 $cur_emtpl[] = $emtpl;
9443 }
9444 if (count($cur_emtpl) > 10) {
9445 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9446 $exceed = count($cur_emtpl) - 10;
9447 for ($tl=0; $tl < $exceed; $tl++) {
9448 unset($cur_emtpl[$tl]);
9449 }
9450 $cur_emtpl = array_values($cur_emtpl);
9451 }
9452 if ($config_rec_exists === true) {
9453 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9454 $dbo->setQuery($q);
9455 $dbo->execute();
9456 } else {
9457 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9458 $dbo->setQuery($q);
9459 $dbo->execute();
9460 }
9461 //
9462 } else {
9463 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9464 }
9465 $mainframe->redirect($pgoto);
9466 }
9467
9468 public function rmcustomemailtpl() {
9469 $cid = VikRequest::getVar('cid', array(0));
9470 $oid = $cid[0];
9471 $dbo = JFactory::getDBO();
9472 $mainframe = JFactory::getApplication();
9473 $tplind = VikRequest::getInt('tplind', '', 'request');
9474 if (empty($oid) || !(strlen($tplind) > 0)) {
9475 VikError::raiseWarning('', 'Missing Data.');
9476 $mainframe->redirect('index.php?option=com_vikbooking');
9477 exit;
9478 }
9479 $cur_emtpl = array();
9480 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9481 $dbo->setQuery($q);
9482 $dbo->execute();
9483 if ($dbo->getNumRows() > 0) {
9484 $cur_emtpl = $dbo->loadResult();
9485 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9486 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9487 } else {
9488 VikError::raiseWarning('', 'Missing Templates Record.');
9489 $mainframe->redirect('index.php?option=com_vikbooking');
9490 exit;
9491 }
9492 if (array_key_exists($tplind, $cur_emtpl)) {
9493 unset($cur_emtpl[$tplind]);
9494 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9495 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9496 $dbo->setQuery($q);
9497 $dbo->execute();
9498 }
9499 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
9500 exit;
9501 }
9502
9503 public function exportcustomers() {
9504 //we do not set the menu for this view
9505
9506 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
9507
9508 parent::display();
9509
9510 if (VikBooking::showFooter()) {
9511 VikBookingHelper::printFooter();
9512 }
9513 }
9514
9515 public function csvexportprepare() {
9516 //modal box, so we do not set menu or footer
9517
9518 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
9519
9520 parent::display();
9521 }
9522
9523 public function icsexportprepare() {
9524 //modal box, so we do not set menu or footer
9525
9526 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
9527
9528 parent::display();
9529 }
9530
9531 public function bookingcheckin() {
9532 //modal box, so we do not set menu or footer
9533
9534 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
9535
9536 parent::display();
9537 }
9538
9539 public function gencheckindoc() {
9540 //modal box, so we do not set menu or footer
9541
9542 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
9543
9544 parent::display();
9545 }
9546
9547 public function checkversion() {
9548 //to be called via ajax
9549 $params = new stdClass;
9550 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9551 $params->alias = 'com_vikbooking';
9552
9553 $result = array();
9554
9555 if (!count($result)) {
9556 $result = new stdClass;
9557 $result->status = 0;
9558 } else {
9559 $result = $result[0];
9560 }
9561
9562 echo json_encode($result);
9563 exit;
9564 }
9565
9566 public function updateprogram() {
9567 $params = new stdClass;
9568 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9569 $params->alias = 'com_vikbooking';
9570
9571 $result = array();
9572
9573 if (!count($result) || !$result[0]) {
9574 if (class_exists('JEventDispatcher')) {
9575 $dispatcher = JEventDispatcher::getInstance();
9576 $result = $dispatcher->trigger('checkVersion', array(&$params));
9577 } else {
9578 $app = JFactory::getApplication();
9579 if (method_exists($app, 'triggerEvent')) {
9580 $result = $app->triggerEvent('checkVersion', array(&$params));
9581 }
9582 }
9583 }
9584
9585 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
9586 exit('Error, plugin disabled');
9587 }
9588
9589 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
9590
9591 VikBookingHelper::pUpdateProgram($result[0]->response);
9592 }
9593
9594 public function updateprogramlaunch() {
9595 $params = new stdClass;
9596 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9597 $params->alias = 'com_vikbooking';
9598
9599 $json = new stdClass;
9600 $json->status = false;
9601
9602 echo json_encode($json);
9603 exit;
9604 }
9605
9606 public function invoke_vcm()
9607 {
9608 $app = JFactory::getApplication();
9609
9610 $oids = VikRequest::getVar('cid', []);
9611 $sync_type = VikRequest::getString('stype', 'new', 'request');
9612 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
9613 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
9614 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
9615 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
9616
9617 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
9618 $app->redirect("index.php?option=com_vikbooking&task=orders");
9619 $app->close();
9620 }
9621
9622 $result = VikBooking::getVcmInvoker()
9623 ->setOids($oids)
9624 ->setSyncType($sync_type)
9625 ->setOriginalBooking($original_booking_js, true)
9626 ->doSync();
9627
9628 if ($result === true) {
9629 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
9630 } else {
9631 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
9632 }
9633
9634 if (!empty($return_url)) {
9635 $app->redirect($return_url);
9636 } else {
9637 $app->redirect("index.php?option=com_vikbooking&task=orders");
9638 }
9639
9640 $app->close();
9641 }
9642
9643 public function multiphotosupload() {
9644 jimport('joomla.filesystem.file');
9645
9646 $dbo = JFactory::getDBO();
9647 $proomid = VikRequest::getInt('roomid', '', 'request');
9648
9649 $resp = array('files' => array());
9650 $error_messages = array(
9651 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
9652 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
9653 3 => 'The uploaded file was only partially uploaded',
9654 4 => 'No file was uploaded',
9655 6 => 'Missing a temporary folder',
9656 7 => 'Failed to write file to disk',
9657 8 => 'A PHP extension stopped the file upload',
9658 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
9659 'max_file_size' => 'File is too big',
9660 'min_file_size' => 'File is too small',
9661 'accept_file_types' => 'Filetype not allowed',
9662 'max_number_of_files' => 'Maximum number of files exceeded',
9663 'max_width' => 'Image exceeds maximum width',
9664 'min_width' => 'Image requires a minimum width',
9665 'max_height' => 'Image exceeds maximum height',
9666 'min_height' => 'Image requires a minimum height',
9667 'abort' => 'File upload aborted',
9668 'image_resize' => 'Failed to resize image',
9669 'vbo_type' => 'The file type cannot be accepted',
9670 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
9671 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
9672 );
9673
9674 $creativik = new vikResizer();
9675 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9676 $bigsdest = $updpath;
9677 $thumbsdest = $updpath;
9678 $dest = $updpath;
9679 $moreimagestr = '';
9680 $cur_captions = json_encode(array());
9681
9682 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
9683 $dbo->setQuery($q);
9684 $dbo->execute();
9685 if ($dbo->getNumRows() == 1) {
9686 $photo_data = $dbo->loadAssocList();
9687 $cur_captions = $photo_data[0]['imgcaptions'];
9688 $cur_photos = $photo_data[0]['moreimgs'];
9689 if (!empty($cur_photos)) {
9690 $moreimagestr .= $cur_photos;
9691 }
9692 }
9693
9694 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
9695
9696 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
9697 foreach ($bulkphotos['name'] as $updk => $photoname) {
9698 $uploaded_image = array();
9699 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
9700 $src = $bulkphotos['tmp_name'][$updk];
9701 $j = "";
9702 if (file_exists($dest.$filename)) {
9703 $j = rand(171, 1717);
9704 while (file_exists($dest.$j.$filename)) {
9705 $j++;
9706 }
9707 }
9708 $finaldest=$dest.$j.$filename;
9709 $is_error = false;
9710 $err_key = '';
9711 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
9712 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
9713 $is_error = true;
9714 $err_key = $bulkphotos['error'][$updk];
9715 }
9716 }
9717 if (!$is_error) {
9718 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
9719 if ($check[2] & imagetypes()) {
9720 if (VikBooking::uploadFile($src, $finaldest)) {
9721 $gimg = $j.$filename;
9722 //orig img
9723 $origmod = true;
9724 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
9725 //thumb
9726 $thumbsize = VikBooking::getThumbSize();
9727 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
9728 if (!$thumb || !$origmod) {
9729 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
9730 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
9731 $is_error = true;
9732 $err_key = 'vbo_perm';
9733 } else {
9734 $moreimagestr.=$j.$filename.";;";
9735 }
9736 @unlink($finaldest);
9737 } else {
9738 $is_error = true;
9739 $err_key = 'vbo_jupload';
9740 }
9741 } else {
9742 $is_error = true;
9743 $err_key = 'vbo_type';
9744 }
9745 }
9746 $img = new stdClass();
9747 if ($is_error) {
9748 $img->name = '';
9749 $img->size = '';
9750 $img->type = '';
9751 $img->url = '';
9752 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
9753 } else {
9754 $img->name = $photoname;
9755 $img->size = $bulkphotos['size'][$updk];
9756 $img->type = $bulkphotos['type'][$updk];
9757 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
9758 }
9759 $resp['files'][] = $img;
9760 }
9761 } else {
9762 $res = new stdClass();
9763 $res->name = '';
9764 $res->size = '';
9765 $res->type = '';
9766 $res->url = '';
9767 $res->error = 'No images received for upload';
9768 $resp['files'][] = $res;
9769 }
9770 //Update current extra images string
9771 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
9772 $dbo->setQuery($q);
9773 $dbo->execute();
9774 $resp['actmoreimgs'] = $moreimagestr;
9775 //Update current extra images uploaded
9776 $cur_thumbs = '';
9777 $morei=explode(';;', $moreimagestr);
9778 if (@count($morei) > 0) {
9779 $imgcaptions = json_decode($cur_captions, true);
9780 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
9781 $cur_thumbs .= '<ul class="vbo-sortable">';
9782 foreach ($morei as $ki => $mi) {
9783 if (!empty($mi)) {
9784 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
9785 $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>';
9786 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
9787 $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>';
9788 $cur_thumbs .= '</li>';
9789 }
9790 }
9791 $cur_thumbs .= '</ul>';
9792 $cur_thumbs .= '<br clear="all"/>';
9793 }
9794 $resp['currentthumbs'] = $cur_thumbs;
9795
9796 echo json_encode($resp);
9797 exit;
9798 }
9799
9800 public function loadsmsbalance() {
9801 //to be called via ajax
9802 $html = 'Error1 [N/A]';
9803 $sms_api = VikBooking::getSMSAPIClass();
9804 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
9805 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9806 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
9807 if (method_exists('VikSmsApi', 'estimate')) {
9808 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
9809 if ( $array_result->errorCode != 0 ) {
9810 $html = 'Error3 ['.$array_result->errorMsg.']';
9811 } else {
9812 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
9813 }
9814 } else {
9815 $html = 'Error2 [N/A]';
9816 }
9817 }
9818 echo $html;
9819 exit;
9820 }
9821
9822 public function loadsmsparams() {
9823 //to be called via ajax
9824 $html = '---------';
9825 $phpfile = VikRequest::getString('phpfile', '', 'request');
9826 if (!empty($phpfile)) {
9827 $sms_api = VikBooking::getSMSAPIClass();
9828 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
9829 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
9830 }
9831 echo $html;
9832 exit;
9833 }
9834
9835 public function loadcronparams() {
9836 //to be called via ajax
9837 $html = '---------';
9838 $phpfile = VikRequest::getString('phpfile', '', 'request');
9839 if (!empty($phpfile)) {
9840 $html = VikBooking::displayCronParameters($phpfile);
9841 }
9842 echo $html;
9843 exit;
9844 }
9845
9846 public function loadpaymentparams() {
9847 //to be called via ajax
9848 $html = '<p>---------</p>';
9849 $phpfile = VikRequest::getString('phpfile', '', 'request');
9850 if (!empty($phpfile)) {
9851 $html = VikBooking::displayPaymentParameters($phpfile);
9852 }
9853 echo $html;
9854 exit;
9855 }
9856
9857 public function setbookingtag() {
9858 //to be called via ajax
9859 $dbo = JFactory::getDBO();
9860 $pidorder = VikRequest::getInt('idorder', '', 'request');
9861 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
9862 if (!empty($pidorder) && $ptagkey >= 0) {
9863 $all_tags = VikBooking::loadBookingsColorTags();
9864 if (array_key_exists($ptagkey, $all_tags)) {
9865 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
9866 $dbo->setQuery($q);
9867 $dbo->execute();
9868 if ($dbo->getNumRows() > 0) {
9869 $newcolortag = json_encode($all_tags[$ptagkey]);
9870 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
9871 $dbo->setQuery($q);
9872 $dbo->execute();
9873 $newcolortag = $all_tags[$ptagkey];
9874 $newcolortag['name'] = JText::translate($newcolortag['name']);
9875 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
9876 echo json_encode($newcolortag);
9877 } else {
9878 echo 'e4j.error.Booking ('.$pidorder.') not found';
9879 }
9880 } else {
9881 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
9882 }
9883 } else {
9884 echo 'e4j.error.Missing Data';
9885 }
9886 exit;
9887 }
9888
9889 public function updatereceiptnum() {
9890 //to be called via ajax
9891 $pnewnum = VikRequest::getInt('newnum', '', 'request');
9892 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
9893 $poid = VikRequest::getInt('oid', '', 'request');
9894 if ($pnewnum > 0) {
9895 VikBooking::getNextReceiptNumber($poid, $pnewnum);
9896 VikBooking::getReceiptNotes($pnewnotes);
9897 //Booking History
9898 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
9899 //
9900 echo 'e4j.ok';
9901 exit;
9902 }
9903 echo 'e4j.error';
9904 exit;
9905 }
9906
9907 public function isroombookable() {
9908 //to be called via ajax
9909 $dbo = JFactory::getDBO();
9910 $res = array(
9911 'status' => 0,
9912 'err' => ''
9913 );
9914 $prid = VikRequest::getInt('rid', '', 'request');
9915 $pfdate = VikRequest::getString('fdate', '', 'request');
9916 $ptdate = VikRequest::getString('tdate', '', 'request');
9917 $room_info = array();
9918 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
9919 $dbo->setQuery($q);
9920 $dbo->execute();
9921 if ($dbo->getNumRows() > 0) {
9922 $room_info = $dbo->loadAssoc();
9923 }
9924 $pcheckinh = 0;
9925 $pcheckinm = 0;
9926 $pcheckouth = 0;
9927 $pcheckoutm = 0;
9928 $timeopst = VikBooking::getTimeOpenStore();
9929 if (is_array($timeopst)) {
9930 $opent = VikBooking::getHoursMinutes($timeopst[0]);
9931 $closet = VikBooking::getHoursMinutes($timeopst[1]);
9932 $pcheckinh = $opent[0];
9933 $pcheckinm = $opent[1];
9934 $pcheckouth = $closet[0];
9935 $pcheckoutm = $closet[1];
9936 }
9937 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
9938 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
9939 if (
9940 count($room_info) > 0 &&
9941 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
9942 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
9943 {
9944 $res['status'] = 1;
9945 } else {
9946 if (!(count($room_info) > 0)) {
9947 $res['err'] = 'Room not found';
9948 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
9949 $res['err'] = 'Invalid dates';
9950 } else {
9951 //not available
9952 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
9953 }
9954 }
9955
9956 echo json_encode($res);
9957 exit;
9958 }
9959
9960 public function uploadsnapshot() {
9961 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
9962 /**
9963 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
9964 * The old snapshot collection script with Flash no longer works in 2021.
9965 *
9966 * @since 1.14 (J) - 1.4.0 (WP)
9967 */
9968 $result = null;
9969 try {
9970 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
9971 } catch (RuntimeException $e) {
9972 echo "e4j.error.Error " . $e->getMessage();
9973 exit;
9974 }
9975
9976 if (!is_object($result)) {
9977 echo "e4j.error.Invalid upload response";
9978 exit;
9979 }
9980
9981 echo $result->filename;
9982 exit;
9983 }
9984
9985 public function checkvcmrateschanges() {
9986 //to be called via ajax
9987 $session = JFactory::getSession();
9988 $ret = array('changesCount' => 0, 'changesData' => '');
9989 $updforvcm = $session->get('vbVcmRatesUpd', '');
9990 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
9991 $ret['changesCount'] = $updforvcm['count'];
9992 $ret['changesData'] = $updforvcm;
9993 }
9994
9995 echo json_encode($ret);
9996 exit;
9997 }
9998
9999 /**
10000 * AJAX endpoint to load the details of one or more bookings.
10001 *
10002 * @return void
10003 *
10004 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10005 */
10006 public function getbookingsinfo()
10007 {
10008 //to be called via ajax
10009 $dbo = JFactory::getDbo();
10010
10011 $booking_infos = [];
10012 $bookings = [];
10013
10014 $pidorders = VikRequest::getString('idorders', '', 'request');
10015 $psubroom = VikRequest::getString('subroom', '', 'request');
10016 $pstatus = VikRequest::getString('status', '', 'request');
10017 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10018 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10019 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10020
10021 if (!empty($pidorders)) {
10022 $bookings = explode(',', $pidorders);
10023 foreach ($bookings as $k => $v) {
10024 $v = intval(str_replace('-', '', $v));
10025 if (empty($v)) {
10026 unset($bookings[$k]);
10027 continue;
10028 }
10029 $bookings[$k] = $v;
10030 }
10031 }
10032 $bookings = array_values($bookings);
10033
10034 if (!$bookings) {
10035 /**
10036 * AJAX requests made by the page availability overview may contain empty booking IDs
10037 * due to SQL errors that only occupied the room, but could not save the booking record.
10038 * Clean up busy records where the busy relations contain empty booking IDs.
10039 *
10040 * @since 1.14 (J) - 1.4.0 (WP)
10041 */
10042 $hanging_busy_ids = [];
10043
10044 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10045 $dbo->setQuery($q);
10046 $removelist = $dbo->loadAssocList();
10047 if ($removelist) {
10048 foreach ($removelist as $hanging_busy) {
10049 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10050 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10051 array_push($hanging_busy_ids, $hanging_busy_id);
10052 }
10053 }
10054 }
10055
10056 // let's check also for ghost records that only occupy the room
10057 $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);";
10058 $dbo->setQuery($q);
10059 $removelist = $dbo->loadAssocList();
10060 if ($removelist) {
10061 foreach ($removelist as $hanging_busy) {
10062 $hanging_busy_id = (int)$hanging_busy['id'];
10063 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10064 array_push($hanging_busy_ids, $hanging_busy_id);
10065 }
10066 }
10067 }
10068
10069 if ($hanging_busy_ids) {
10070 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10071 $dbo->setQuery($q);
10072 $dbo->execute();
10073 }
10074 //
10075
10076 // output the error
10077 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10078 }
10079
10080 $nowdf = VikBooking::getDateFormat(true);
10081 if ($nowdf == "%d/%m/%Y") {
10082 $df = 'd/m/Y';
10083 } elseif ($nowdf == "%m/%d/%Y") {
10084 $df = 'm/d/Y';
10085 } else {
10086 $df = 'Y/m/d';
10087 }
10088 $datesep = VikBooking::getDateSeparator(true);
10089 $currencysymb = VikBooking::getCurrencySymb();
10090 $current_y = date('Y');
10091 $current_ts = time();
10092 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10093
10094 $query = $dbo->getQuery(true);
10095 $query->select('o.*');
10096 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10097 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10098 // include the requested booking IDs and the cancelled reservations for this stay date
10099 $stay_date_info = getdate(strtotime($pstay_date));
10100 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10101 $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) . '))');
10102 // exclude the pending reservations
10103 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10104 } else {
10105 // include only the requested booking IDs
10106 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10107 }
10108 if ($pstatus != 'any') {
10109 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10110 }
10111 if (!empty($pstay_date) && $pstatus == 'any') {
10112 // sort by confirmed status before cancelled status
10113 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10114 $query->order($dbo->qn('o.id') . ' ASC');
10115 }
10116 $dbo->setQuery($query);
10117 $booking_infos = $dbo->loadAssocList();
10118
10119 foreach ($booking_infos as $k => $row) {
10120 // rooms, amounts and guests information
10121 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10122 $rids_involved = [];
10123 $room_names = [];
10124 $totadults = 0;
10125 $totchildren = 0;
10126 foreach ($rooms as $rr) {
10127 $rids_involved[] = $rr['idroom'];
10128 $totadults += $rr['adults'];
10129 $totchildren += $rr['children'];
10130 $room_names[] = $rr['room_name'];
10131 if ($row['split_stay']) {
10132 // do not sum guests in case of split stay booking
10133 $totadults = $rr['adults'];
10134 $totchildren = $rr['children'];
10135 }
10136 }
10137
10138 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10139 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10140 if (!in_array($pidroom, $rids_involved)) {
10141 $is_out_of_scope = true;
10142 if ($psharedcal && count($bookings) === 1) {
10143 $is_out_of_scope = ($row['id'] != $bookings[0]);
10144 }
10145 if ($is_out_of_scope) {
10146 // out of scope reservation, unset it and go to the next one
10147 unset($booking_infos[$k]);
10148 continue;
10149 }
10150 }
10151 }
10152
10153 // included meal plans to be displayed in case of single-room booking
10154 $included_meals = [];
10155 $rplan_name = '';
10156 if (count($rooms) === 1) {
10157 // rate plan name and ID, if any
10158 $active_rplan_id = 0;
10159 if (!empty($rooms[0]['otarplan'])) {
10160 $rplan_name = $rooms[0]['otarplan'];
10161 } else {
10162 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10163 }
10164
10165 // find the included meals
10166 if (!empty($rooms[0]['meals'])) {
10167 // display included meals defined at room-reservation record
10168 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10169 } else {
10170 // fetch default included meals in the selected rate plan
10171 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10172 }
10173 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10174 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10175 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10176 }
10177 }
10178
10179 if ($included_meals) {
10180 $short_incl_meals = [];
10181 foreach ($included_meals as $meal_enum => $meal_name) {
10182 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10183 }
10184 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10185 }
10186
10187 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10188 $booking_infos[$k]['currency_symb'] = $currencysymb;
10189 if ($row['status'] == 'confirmed') {
10190 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10191 if ($row['checkout'] < $current_ts) {
10192 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10193 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10194 if ($row['checked'] == 1) {
10195 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10196 } elseif ($row['checked'] == -1) {
10197 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10198 }
10199 }
10200 } elseif ($row['status'] == 'standby') {
10201 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10202 } elseif ($row['status'] == 'cancelled') {
10203 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10204 } else {
10205 $booking_infos[$k]['status_lbl'] = $row['status'];
10206 }
10207 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10208 if ($booking_infos[$k]['colortag']) {
10209 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10210 }
10211 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10212 $booking_infos[$k]['tot_adults'] = $totadults;
10213 $booking_infos[$k]['tot_children'] = $totchildren;
10214 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10215 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10216
10217 // room indexes
10218 $rindexes = [];
10219 $av_room_indexes = [];
10220 $used_indexes_map = [];
10221 $sub_units_data = [];
10222 $optindexes = [];
10223 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10224 $missing_index = false;
10225 foreach ($rooms as $kor => $or) {
10226 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10227 // cannot build room indexes data
10228 continue;
10229 }
10230
10231 $room_params = json_decode($or['params'], true);
10232 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10233 // no distinctive features information
10234 continue;
10235 }
10236
10237 if (!strlen($or['roomindex'])) {
10238 // turn flag on for missing index when room does support them
10239 $missing_index = true;
10240 // build array with available room indexes
10241 $av_indexes = [];
10242 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10243 foreach ($room_params['features'] as $rind => $rfeatures) {
10244 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10245 continue;
10246 }
10247 foreach ($rfeatures as $fname => $fval) {
10248 if ($fval) {
10249 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10250 break;
10251 }
10252 }
10253 }
10254 if ($av_indexes) {
10255 // push available indexes for this room
10256 $av_room_indexes[$kor] = [
10257 'rid' => $or['idroom'],
10258 'name' => $or['room_name'],
10259 'list' => $av_indexes,
10260 ];
10261 }
10262 // do not proceed any further
10263 continue;
10264 }
10265
10266 // parse distinctive features
10267 foreach ($room_params['features'] as $rind => $rfeatures) {
10268 if ($rind != $or['roomindex']) {
10269 continue;
10270 }
10271 $ind_str = '';
10272 $ind_str_short = '';
10273 foreach ($rfeatures as $fname => $fval) {
10274 if (strlen($fval)) {
10275 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10276 $ind_str_short = $fval;
10277 break;
10278 }
10279 }
10280 if (!isset($rindexes[$or['room_name']])) {
10281 $rindexes[$or['room_name']] = $ind_str;
10282 $sub_units_data[$or['room_name']] = $ind_str_short;
10283 } else {
10284 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10285 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10286 }
10287 break;
10288 }
10289
10290 // build options to switch sub-unit index
10291 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10292 // build the options for switching the room index for this room
10293 foreach ($room_params['features'] as $rind => $rfeatures) {
10294 foreach ($rfeatures as $fname => $fval) {
10295 if (strlen((string)$fval)) {
10296 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10297 break;
10298 }
10299 }
10300 }
10301 }
10302 }
10303
10304 if ($rindexes) {
10305 $booking_infos[$k]['rindexes'] = $rindexes;
10306 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10307 }
10308
10309 if ($optindexes) {
10310 $booking_infos[$k]['optindexes'] = $optindexes;
10311 }
10312
10313 if ($missing_index && $av_room_indexes) {
10314 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10315 }
10316
10317 // include flag for missing room index
10318 $booking_infos[$k]['missing_index'] = $missing_index;
10319
10320 // channel provenience and small logo URL
10321 $ota_logo_img = JText::translate('VBORDFROMSITE');
10322 $booking_avatar_src = null;
10323 $booking_avatar_alt = null;
10324 if (!empty($row['channel'])) {
10325 $channelparts = explode('_', $row['channel']);
10326 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10327 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10328 if ($ota_logo_img === false) {
10329 $ota_logo_img = $otachannel;
10330 } else {
10331 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10332 }
10333 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10334 if ($logo_helper !== false) {
10335 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10336 $booking_avatar_alt = $logo_helper->provenience;
10337 }
10338 }
10339 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10340 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10341 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10342
10343 // Customer Details
10344 $custdata = $row['custdata'];
10345 $custdata_parts = explode("\n", $row['custdata']);
10346 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10347 //get the first two fields
10348 $custvalues = [];
10349 foreach ($custdata_parts as $custdet) {
10350 if (strlen($custdet) < 1) {
10351 continue;
10352 }
10353 $custdet_parts = explode(':', $custdet);
10354 if (count($custdet_parts) >= 2) {
10355 unset($custdet_parts[0]);
10356 array_push($custvalues, trim(implode(':', $custdet_parts)));
10357 }
10358 if (count($custvalues) > 1) {
10359 break;
10360 }
10361 }
10362 if (count($custvalues) > 1) {
10363 $custdata = implode(' ', $custvalues);
10364 }
10365 }
10366 if (strlen($custdata) > 45) {
10367 $custdata = substr($custdata, 0, 45)." ...";
10368 }
10369
10370 // customer record details
10371 $customer = [];
10372 $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'];
10373 $dbo->setQuery($q, 0, 1);
10374 $dbo->execute();
10375 if ($dbo->getNumRows()) {
10376 $customer = $dbo->loadAssoc();
10377 if (!empty($customer['first_name'])) {
10378 $custdata = $customer['first_name'].' '.$customer['last_name'];
10379 if (!empty($customer['country'])) {
10380 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10381 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10382 }
10383 }
10384 }
10385 }
10386 $booking_infos[$k]['customer'] = $customer;
10387
10388 // check if a profile picture is available for the customer
10389 if (!empty($customer['pic'])) {
10390 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10391 $booking_avatar_alt = basename($booking_avatar_src);
10392 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10393 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10394 }
10395
10396 // whether this is a closure
10397 $booking_infos[$k]['closure'] = (int)$row['closure'];
10398 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10399
10400 // short customer information
10401 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10402 $booking_infos[$k]['cinfo'] = $custdata;
10403
10404 // formatted dates
10405 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10406 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10407 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10408
10409 // short booking date, check-in, check-out date format
10410 $stay_info_in = getdate($row['checkin']);
10411 $stay_info_out = getdate($row['checkout']);
10412 $str_checkin = date('d', $row['checkin']);
10413 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10414 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10415 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10416 $str_checkout .= ' ' . $stay_info_out['year'];
10417 }
10418 $booking_infos[$k]['checkin_short'] = $str_checkin;
10419 $booking_infos[$k]['checkout_short'] = $str_checkout;
10420 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10421 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10422 }
10423
10424 if (!$booking_infos) {
10425 // output the error
10426 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10427 }
10428
10429 // output the JSON encoded response and exit
10430 VBOHttpDocument::getInstance()->json($booking_infos);
10431 }
10432
10433 public function switchRoomIndex() {
10434 //to be called via ajax
10435 $dbo = JFactory::getDBO();
10436 $bid = VikRequest::getInt('bid', '', 'request');
10437 $rid = VikRequest::getInt('rid', '', 'request');
10438 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10439 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10440 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10441 echo 'e4j.error.#1 Missing Data';
10442 exit;
10443 }
10444 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10445 $dbo->setQuery($q);
10446 $dbo->execute();
10447 if ($dbo->getNumRows() < 1) {
10448 echo 'e4j.error.#2 Record not found';
10449 exit;
10450 }
10451 $rows = $dbo->loadAssocList();
10452 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10453 $dbo->setQuery($q);
10454 $dbo->execute();
10455 echo 'e4j.ok';
10456 exit;
10457 }
10458
10459 public function searchcustomer()
10460 {
10461 // to be called via ajax
10462 $dbo = JFactory::getDbo();
10463
10464 $kw = VikRequest::getString('kw', '', 'request');
10465 $nopin = VikRequest::getInt('nopin', '', 'request');
10466 $email = VikRequest::getInt('email', 0, 'request');
10467 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10468 $no_script = VikRequest::getInt('no_script', 0, 'request');
10469
10470 if (!strlen($kw)) {
10471 VBOHttpDocument::getInstance()->close(200, '');
10472 }
10473
10474 if ($nopin > 0) {
10475 //page all bookings
10476 $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;";
10477 } elseif ($email > 0) {
10478 // page calendar for checking if an email exists
10479 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10480 } else {
10481 //page calendar
10482 $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;";
10483 }
10484 $dbo->setQuery($q);
10485 $customers = $dbo->loadAssocList();
10486
10487 if (!$customers) {
10488 VBOHttpDocument::getInstance()->close(200, '');
10489 }
10490
10491 if ($email > 0) {
10492 VBOHttpDocument::getInstance()->json($customers[0]);
10493 }
10494
10495 $cust_old_fields = array();
10496 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10497 foreach ($customers as $k => $v) {
10498 $cstring_search .= '<div class="' . $selector . '" data-custid="'.$v['id'].'" data-email="'.$v['email'].'" data-phone="'.htmlspecialchars($v['phone']).'" data-country="'.$v['country'].'" data-pin="'.$v['pin'].'" data-firstname="'.htmlspecialchars($v['first_name']).'" data-lastname="'.htmlspecialchars($v['last_name']).'">'."\n";
10499 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
10500 if (!empty($v['pic'])) {
10501 $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";
10502 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
10503 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
10504 } else {
10505 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
10506 }
10507 $cstring_search .= '</span>';
10508 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
10509 if (!($nopin > 0)) {
10510 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
10511 }
10512 $cstring_search .= '</div>'."\n";
10513 if (!empty($v['cfields'])) {
10514 $oldfields = json_decode($v['cfields'], true);
10515 if (is_array($oldfields) && count($oldfields)) {
10516 $cust_old_fields[$v['id']] = $oldfields;
10517 }
10518 }
10519 }
10520 $cstring_search .= '</div>'."\n";
10521
10522 /**
10523 * Add the necessary JS code for the arrow navigation.
10524 */
10525 $cstring_search_js = '<script type="text/javascript">';
10526 $cstring_search_js .= '
10527 var vboCust = jQuery(".' . $selector . '");
10528 var vboCustSelected = null;
10529 jQuery(window).keydown(function(e) {
10530 if (e.which === 40) {
10531 if (vboCustSelected) {
10532 vboCustSelected.removeClass("' . $selector . '-highligthed");
10533 next = vboCustSelected.next();
10534 if (next.length > 0) {
10535 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10536 } else {
10537 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10538 }
10539 } else {
10540 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10541 }
10542 } else if (e.which === 38) {
10543 if (vboCustSelected) {
10544 vboCustSelected.removeClass("' . $selector . '-highligthed");
10545 next = vboCustSelected.prev();
10546 if (next.length > 0) {
10547 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10548 } else {
10549 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10550 }
10551 } else {
10552 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10553 }
10554 } else if (e.which === 13) {
10555 if (vboCustSelected) {
10556 vboCustSelected.trigger("click");
10557 }
10558 }
10559 });
10560 jQuery(".' . $selector . '").off("hover");
10561 jQuery(".' . $selector . '").hover(function() {
10562 if (vboCustSelected) {
10563 vboCustSelected.removeClass("' . $selector . '-highligthed");
10564 vboCustSelected = null;
10565 }
10566 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
10567 }, function() {
10568 if (vboCustSelected) {
10569 vboCustSelected.removeClass("' . $selector . '-highligthed");
10570 vboCustSelected = null;
10571 }
10572 jQuery(this).removeClass("' . $selector . '-highligthed");
10573 });';
10574 $cstring_search_js .= '</script>';
10575
10576 if (!$no_script) {
10577 // append JS
10578 $cstring_search .= $cstring_search_js;
10579 }
10580
10581 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
10582 }
10583
10584 public function sharesignaturelink() {
10585 //to be called via ajax
10586 $dbo = JFactory::getDBO();
10587 $response = array(
10588 'status' => 0,
10589 'error' => 'Generic Error'
10590 );
10591 $pbid = VikRequest::getInt('bid', '', 'request');
10592 $phow = VikRequest::getString('how', '', 'request');
10593 $pto = VikRequest::getString('to', '', 'request');
10594 $pcustomer = VikRequest::getInt('customer', '', 'request');
10595 $cpin = VikBooking::getCPinIstance();
10596 $customer_info = $cpin->getCustomerByID($pcustomer);
10597 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
10598 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
10599 $dbo->setQuery($q);
10600 $dbo->execute();
10601 if ($dbo->getNumRows() > 0) {
10602 $row = $dbo->loadAssoc();
10603
10604 $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'];
10605 if (VBOPlatformDetection::isWordPress()) {
10606 /**
10607 * @wponly Rewrite URI for front-end signature
10608 */
10609 $share_link = str_replace(JUri::root(), '', $share_link);
10610 $model = JModel::getInstance('vikbooking', 'shortcodes');
10611 $itemid = $model->all('post_id', $full = true);
10612 if (count($itemid)) {
10613 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
10614 }
10615 } else {
10616 /**
10617 * @joomlaonly
10618 */
10619 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
10620 if ($best_menuitem_id) {
10621 $share_base = str_replace(JUri::root(), '', $share_link);
10622 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
10623 }
10624 }
10625
10626 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10627 if ($phow == 'email') {
10628 $sender = VikBooking::getSenderMail();
10629 $vbo_app = VikBooking::getVboApplication();
10630 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
10631 $response['status'] = 1;
10632 } elseif ($phow == 'sms') {
10633 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10634 $sms_api = VikBooking::getSMSAPIClass();
10635 $sms_api_params = VikBooking::getSMSParams();
10636 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
10637 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10638 $sms_obj = new VikSmsApi(array(), $sms_api_params);
10639 $response_obj = $sms_obj->sendMessage($pto, $share_message);
10640 if ($sms_obj->validateResponse($response_obj)) {
10641 $response['status'] = 1;
10642 } else {
10643 $response['error'] = $sms_obj->getLog();
10644 }
10645 } else {
10646 $response['error'] = 'No SMS Provider Configured';
10647 }
10648 } else {
10649 $response['error'] = 'Invalid Sending Method';
10650 }
10651 } else {
10652 $response['error'] = 'Invalid Booking ID';
10653 }
10654 } else {
10655 $response['error'] = 'Empty values';
10656 }
10657
10658 echo json_encode($response);
10659 exit;
10660 }
10661
10662 public function dayselectioncount() {
10663 //to be called via ajax
10664 $tsinit = VikRequest::getString('dinit', '', 'request');
10665 $tsend = VikRequest::getString('dend', '', 'request');
10666 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
10667 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
10668 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
10669 $diff = $ptsend - $ptsinit;
10670 if ($diff >= 172800) {
10671 $datef = VikBooking::getDateFormat(true);
10672 if ($datef=="%d/%m/%Y") {
10673 $df = 'd-m-Y';
10674 } else {
10675 $df = 'Y-m-d';
10676 }
10677 //minimum 2 days for excluding some days
10678 $daysdiff = floor($diff / 86400);
10679 $infoinit = getdate($ptsinit);
10680 $select = '';
10681 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
10682 for($i = 0; $i <= $daysdiff; $i++) {
10683 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
10684 $infots = getdate($ts);
10685 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
10686 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
10687 }
10688 $select .= '</select></div>';
10689 //excluded days of the week
10690 if ($daysdiff >= 14) {
10691 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
10692 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
10693 $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>';
10694 $select .= '</optgroup>';
10695 $select .= '</select></div>';
10696 }
10697 //
10698 echo $select;
10699 } else {
10700 echo '';
10701 }
10702 } else {
10703 echo '';
10704 }
10705 exit;
10706 }
10707
10708 public function createcheckindoc() {
10709 $cid = VikRequest::getVar('cid', array(0));
10710 $id = $cid[0];
10711
10712 $dbo = JFactory::getDBO();
10713 $mainframe = JFactory::getApplication();
10714 $vbo_tn = VikBooking::getTranslator();
10715 $lang = JFactory::getLanguage();
10716 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10717 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
10718 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
10719 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
10720 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
10721 $dbo->setQuery($q);
10722 $dbo->execute();
10723 if ($dbo->getNumRows() < 1) {
10724 $mainframe->redirect('index.php');
10725 exit;
10726 }
10727 $row = $dbo->loadAssoc();
10728 if (!empty($row['lang'])) {
10729 if ($lang->getTag() != $row['lang']) {
10730 if (VBOPlatformDetection::isWordPress()) {
10731 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
10732 } else {
10733 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
10734 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
10735 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
10736 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
10737 }
10738 }
10739 if ($vbo_tn->getDefaultLang() != $row['lang']) {
10740 // force the translation to start because contents should be translated
10741 $vbo_tn::$force_tolang = $row['lang'];
10742 }
10743 }
10744 $customer = array();
10745 $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'].";";
10746 $dbo->setQuery($q);
10747 $dbo->execute();
10748 if ($dbo->getNumRows() > 0) {
10749 $customer = $dbo->loadAssoc();
10750 if (!empty($customer['country'])) {
10751 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10752 $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"/>';
10753 }
10754 }
10755 }
10756 if (!(count($customer) > 0)) {
10757 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10758 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10759 exit;
10760 }
10761 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
10762 //check if the signature has been submitted
10763 $signature_data = '';
10764 $cont_type = '';
10765 if (!empty($psignature)) {
10766 //check whether the format is accepted
10767 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
10768 $parts = explode(';base64,', $psignature);
10769 $cont_type_parts = explode('image/', $parts[0]);
10770 $cont_type = $cont_type_parts[1];
10771 if (!empty($parts[1])) {
10772 $signature_data = base64_decode($parts[1]);
10773 }
10774 }
10775 }
10776 if (!empty($signature_data)) {
10777 //write file
10778 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
10779 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
10780 $fp = fopen($filepath, 'w+');
10781 $bytes = fwrite($fp, $signature_data);
10782 fclose($fp);
10783 if ($bytes !== false && $bytes > 0) {
10784 //update the signature in the DB
10785 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
10786 $dbo->setQuery($q);
10787 $dbo->execute();
10788 $customer['signature'] = $sign_fname;
10789 //resize image for screens with high resolution
10790 if ($ppad_ratio > 1) {
10791 $new_width = floor(($ppad_width / 2));
10792 $creativik = new vikResizer();
10793 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
10794 } else {
10795 /**
10796 * @wponly - trigger files mirroring
10797 */
10798 VikBookingLoader::import('update.manager');
10799 VikBookingUpdateManager::triggerUploadBackup($filepath);
10800 //
10801 }
10802 //
10803 } else {
10804 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
10805 }
10806 }
10807 //
10808 //generate PDF for check-in document by parsing the apposite template file
10809 $booking_rooms = array();
10810 $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'].";";
10811 $dbo->setQuery($q);
10812 $dbo->execute();
10813 if ($dbo->getNumRows() > 0) {
10814 $booking_rooms = $dbo->loadAssocList();
10815 if (!empty($row['lang'])) {
10816 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
10817 }
10818 }
10819 if (!class_exists('TCPDF')) {
10820 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
10821 }
10822 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
10823
10824 /**
10825 * Trigger event to allow third party plugins to return a specific font name.
10826 *
10827 * @since 1.16.0 (J) - 1.6.0 (WP)
10828 */
10829 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
10830 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
10831 $usepdffont = $custom_pdf_font[0];
10832 }
10833
10834 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
10835 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
10836 $pdffname = $row['id'] . '_' . $row['sid'] . '.pdf';
10837 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
10838 if (file_exists($pathpdf)) @unlink($pathpdf);
10839 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
10840 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
10841 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
10842 //Header for each page of the pdf
10843 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
10844 $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]);
10845 }
10846 //header and footer fonts
10847 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
10848 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
10849 //margins
10850 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
10851 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
10852 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
10853 //
10854 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
10855 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
10856 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
10857 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
10858 $pdf->SetPrintHeader(false);
10859 }
10860 if ($pdfparams['show_footer'] == 0) {
10861 $pdf->SetPrintFooter(false);
10862 }
10863 $pdf->AddPage();
10864 $pdf->writeHTML($checkin_body, true, false, true, false, '');
10865 $pdf->lastPage();
10866 $pdf->Output($pathpdf, 'F');
10867 if (!file_exists($pathpdf)) {
10868 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
10869 } else {
10870 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
10871 $dbo->setQuery($q);
10872 $dbo->execute();
10873 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
10874 /**
10875 * @wponly - trigger files mirroring
10876 */
10877 VikBookingLoader::import('update.manager');
10878 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
10879 //
10880 }
10881 //
10882 /**
10883 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
10884 */
10885 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
10886 exit;
10887 }
10888
10889 public function updatebookingcheckin() {
10890 $cid = VikRequest::getVar('cid', array(0));
10891 $id = $cid[0];
10892
10893 $dbo = JFactory::getDbo();
10894 $app = JFactory::getApplication();
10895
10896 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10897 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
10898 $pguests = VikRequest::getVar('guests', array());
10899 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
10900 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
10901 $valid_actions = array(-1, 0, 1, 2);
10902 if (!in_array($pcheckin_action, $valid_actions)) {
10903 $app->redirect('index.php');
10904 exit;
10905 }
10906 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
10907 $dbo->setQuery($q);
10908 $dbo->execute();
10909 if ($dbo->getNumRows() < 1) {
10910 $app->redirect('index.php');
10911 exit;
10912 }
10913 $row = $dbo->loadAssoc();
10914 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
10915 $dbo->setQuery($q);
10916 $dbo->execute();
10917 if ($dbo->getNumRows() < 1) {
10918 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10919 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10920 exit;
10921 }
10922 $custorder = $dbo->loadAssoc();
10923 //update checked status and new total paid
10924 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
10925 $dbo->setQuery($q);
10926 $dbo->execute();
10927 // Booking History log for new amount paid (payment update)
10928 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
10929 $extra_data = new stdClass;
10930 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
10931 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
10932 }
10933 //
10934 //Booking History
10935 $hist_type = 'A';
10936 if ($pcheckin_action < 0) {
10937 $hist_type = 'Z';
10938 } elseif ($pcheckin_action == 1) {
10939 $hist_type = 'B';
10940 } elseif ($pcheckin_action == 2) {
10941 $hist_type = 'C';
10942 }
10943 $user = JFactory::getUser();
10944 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
10945 //
10946 //Guests Details
10947 $guests_details = array();
10948 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
10949 // grab also the fields for front-end pre check-in
10950 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
10951 //
10952 foreach ($pguests as $ind => $adults) {
10953 foreach ($adults as $aduind => $details) {
10954 foreach ($pax_fields as $key => $v) {
10955 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
10956 if (!isset($guests_details[$ind])) {
10957 $guests_details[$ind] = array();
10958 }
10959 if (!isset($guests_details[$ind][$aduind])) {
10960 $guests_details[$ind][$aduind] = array();
10961 }
10962 $guests_details[$ind][$aduind][$key] = $details[$key];
10963 }
10964 }
10965 foreach ($pre_pax_fields as $key => $v) {
10966 if (isset($pax_fields[$key])) {
10967 // we must have parsed this back-end field already
10968 continue;
10969 }
10970 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
10971 if (!isset($guests_details[$ind])) {
10972 $guests_details[$ind] = array();
10973 }
10974 if (!isset($guests_details[$ind][$aduind])) {
10975 $guests_details[$ind][$aduind] = array();
10976 }
10977 if (!isset($guests_details[$ind][$aduind][$key])) {
10978 $guests_details[$ind][$aduind][$key] = $details[$key];
10979 }
10980 }
10981 }
10982 }
10983 }
10984 if (count($guests_details)) {
10985 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
10986 $curpaxdata = json_decode($custorder['pax_data'], true);
10987 if (is_array($curpaxdata) && count($curpaxdata)) {
10988 foreach ($guests_details as $ind => $groom) {
10989 foreach ($groom as $aduind => $aduinfo) {
10990 if (isset($curpaxdata[$ind][$aduind])) {
10991 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
10992 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
10993 foreach ($guests_details[$ind][$aduind] as $key => $det) {
10994 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
10995 // this default pax field was specified as empty now, so we cannot merge it
10996 unset($guests_details[$ind][$aduind][$key]);
10997 }
10998 }
10999 }
11000 }
11001 }
11002 }
11003 //
11004 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=".$dbo->quote(json_encode($guests_details))." WHERE `id`=".$custorder['id'].";";
11005 $dbo->setQuery($q);
11006 $dbo->execute();
11007 }
11008
11009 //'checked' status comments
11010 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11011 $dbo->setQuery($q);
11012 $dbo->execute();
11013
11014 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11015 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11016 exit;
11017 }
11018
11019 public function alterbooking()
11020 {
11021 $dbo = JFactory::getDbo();
11022 $app = JFactory::getApplication();
11023 $user = JFactory::getUser();
11024
11025 $response = array(
11026 'esit' => 1,
11027 'message' => '',
11028 'vcm' => '',
11029 );
11030
11031 // must be a string as it may contain a dash
11032 $pidorder = VikRequest::getString('idorder', '', 'request');
11033 $pidorder = intval(str_replace('-', '', $pidorder));
11034
11035 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11036 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11037 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11038 $ptodate = VikRequest::getString('todate', '', 'request');
11039 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11040 if ($pdebug == 1) {
11041 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11042 exit;
11043 }
11044
11045 $nowdf = VikBooking::getDateFormat(true);
11046 if ($nowdf == "%d/%m/%Y") {
11047 $df = 'd/m/Y';
11048 } elseif ($nowdf == "%m/%d/%Y") {
11049 $df = 'm/d/Y';
11050 } else {
11051 $df = 'Y/m/d';
11052 }
11053 $pcheckinh = 0;
11054 $pcheckinm = 0;
11055 $pcheckouth = 0;
11056 $pcheckoutm = 0;
11057 $timeopst = VikBooking::getTimeOpenStore();
11058 if (is_array($timeopst)) {
11059 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11060 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11061 $pcheckinh = $opent[0];
11062 $pcheckinm = $opent[1];
11063 $pcheckouth = $closet[0];
11064 $pcheckoutm = $closet[1];
11065 }
11066 $info_tsto = getdate(strtotime($ptodate));
11067 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11068 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11069 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11070 $ptodate = date('Y-m-d', $second);
11071 if (!($second > $first)) {
11072 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11073 exit;
11074 }
11075 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11076 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11077 exit;
11078 }
11079
11080 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11081 $dbo->setQuery($q, 0, 1);
11082 $dbo->execute();
11083 if (!$dbo->getNumRows()) {
11084 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11085 exit;
11086 }
11087 $ord = $dbo->loadAssoc();
11088
11089 $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;";
11090 $dbo->setQuery($q);
11091 $dbo->execute();
11092 $ordersrooms = $dbo->loadAssocList();
11093
11094 // store for VCM the current rooms before the modification
11095 $ord['rooms_info'] = $ordersrooms;
11096
11097 // package or custom rate
11098 $is_package = !empty($ord['pkg']) ? true : false;
11099 $is_cust_cost = false;
11100 foreach ($ordersrooms as $kor => $or) {
11101 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11102 $is_cust_cost = true;
11103 break;
11104 }
11105 }
11106
11107 // availability helper
11108 $av_helper = VikBooking::getAvailabilityInstance();
11109
11110 // room stay dates in case of split stay
11111 $room_stay_dates = [];
11112 if ($ord['split_stay']) {
11113 // no need to get the transient based on booking status, as the booking must be confirmed
11114 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11115 // immediately count the number of nights of stay for each split room
11116 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11117 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11118 }
11119 }
11120
11121 // determine if dates have changed
11122 $dates_changed = false;
11123 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11124 $dates_changed = true;
11125 }
11126
11127 $toswitch = array();
11128 $idbooked = array();
11129 $rooms_units = array();
11130 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11131 $dbo->setQuery($q);
11132 $dbo->execute();
11133 $all_rooms = $dbo->loadAssocList();
11134 foreach ($all_rooms as $rr) {
11135 $rooms_units[$rr['id']]['name'] = $rr['name'];
11136 $rooms_units[$rr['id']]['units'] = $rr['units'];
11137 }
11138
11139 // switch room
11140 if ($poldidroom != $pidroom) {
11141 foreach ($ordersrooms as $ind => $or) {
11142 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11143 if (!isset($idbooked[$or['idroom']])) {
11144 $idbooked[$or['idroom']] = 0;
11145 }
11146 // $idbooked is not really needed as switch is never made for the same room id
11147 $idbooked[$or['idroom']]++;
11148 //
11149 $orkey = count($toswitch);
11150 $toswitch[$orkey]['from'] = $or['idroom'];
11151 $toswitch[$orkey]['to'] = $pidroom;
11152 $toswitch[$orkey]['record'] = $or;
11153 $toswitch[$orkey]['record_ind'] = $ind;
11154 break;
11155 }
11156 }
11157 }
11158 if (count($toswitch)) {
11159 foreach ($toswitch as $ksw => $rsw) {
11160 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11161 $room_checkin = $ord['checkin'];
11162 $room_checkout = $ord['checkout'];
11163 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11164 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11165 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11166 }
11167 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11168 // the room is not available
11169 unset($toswitch[$ksw]);
11170 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11171 exit;
11172 }
11173 }
11174 if (count($toswitch)) {
11175 //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)
11176 reset($ordersrooms);
11177 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11178 $dbo->setQuery($q);
11179 $dbo->execute();
11180 //
11181 foreach ($toswitch as $ksw => $rsw) {
11182 // update room reservation record
11183 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11184 $dbo->setQuery($q);
11185 $dbo->execute();
11186 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11187
11188 // update Notes field for this booking to keep track of the previous room that was assigned
11189 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11190 if (!empty($prev_room_name)) {
11191 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11192 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11193 $dbo->setQuery($q);
11194 $dbo->execute();
11195 }
11196
11197 if ($ord['status'] == 'confirmed') {
11198 // update room record in _busy
11199 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'])) {
11200 // in case of a split stay it is fundamental to update the exact busy record ID
11201 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11202 $dbo->setQuery($q);
11203 $dbo->execute();
11204 } else {
11205 // regular processing of a room ID for a reservation, no matter which one, we switch it
11206 $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;";
11207 $dbo->setQuery($q);
11208 $dbo->execute();
11209 if ($dbo->getNumRows() == 1) {
11210 $cur_busy = $dbo->loadAssocList();
11211 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11212 $dbo->setQuery($q);
11213 $dbo->execute();
11214 }
11215 }
11216
11217 // if automated updates enabled, keep $response['vcm'] empty
11218 // Invoke Channel Manager
11219 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11220 $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>';
11221 }
11222 } elseif ($ord['status'] == 'standby') {
11223 // remove record in _tmplock
11224 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11225 $dbo->setQuery($q);
11226 $dbo->execute();
11227 }
11228 }
11229
11230 // check if sub-units should be assigned again when switching room
11231 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11232 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11233 $room_indexes_usemap = [];
11234 foreach ($new_order_rooms as $kor => $or) {
11235 $num = $kor + 1;
11236 // assign room specific unit
11237 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11238 $use_ind_key = 0;
11239 if ($room_indexes) {
11240 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11241 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11242 } else {
11243 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11244 }
11245 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11246 $dbo->setQuery($q);
11247 $dbo->execute();
11248 $room_indexes_usemap[$or['idroom']]++;
11249 }
11250 }
11251 }
11252
11253 // do not terminate the process when there is a switch, proceed to check the dates.
11254 }
11255 }
11256
11257 // change dates
11258 if ($dates_changed) {
11259 if ($ord['split_stay']) {
11260 // we do not allow to drag and change dates for rooms in a split stay reservation
11261 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11262 exit;
11263 }
11264
11265 // total nights of stay
11266 $daysdiff = $ord['days'];
11267
11268 // re-read ordersrooms (as rooms may have been switched)
11269 $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;";
11270 $dbo->setQuery($q);
11271 $dbo->execute();
11272 $ordersrooms = $dbo->loadAssocList();
11273
11274 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11275 $opertwounits = true;
11276 $units_counter = array();
11277 foreach ($ordersrooms as $ind => $or) {
11278 if (!isset($units_counter[$or['idroom']])) {
11279 $units_counter[$or['idroom']] = -1;
11280 }
11281 $units_counter[$or['idroom']]++;
11282 }
11283
11284 foreach ($ordersrooms as $ind => $or) {
11285 $num = $ind + 1;
11286 $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'] . ";";
11287 $dbo->setQuery($check);
11288 $dbo->execute();
11289 if ($dbo->getNumRows() > 0) {
11290 $busy = $dbo->loadAssocList();
11291 foreach ($groupdays as $gday) {
11292 $bfound = 0;
11293 foreach ($busy as $bu) {
11294 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11295 $bfound++;
11296 }
11297 }
11298 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11299 $opertwounits = false;
11300 break 2;
11301 }
11302 }
11303 }
11304 }
11305 if ($opertwounits !== true) {
11306 $response['esit'] = 0;
11307 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11308 echo json_encode($response);
11309 exit;
11310 }
11311
11312 // update dates and busy records
11313 $realback = VikBooking::getHoursRoomAvail() * 3600;
11314 $realback += $second;
11315 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11316 $dbo->setQuery($q);
11317 $dbo->execute();
11318 if ($ord['status'] == 'confirmed') {
11319 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11320 $dbo->setQuery($q);
11321 $dbo->execute();
11322 $allbusy = $dbo->loadAssocList();
11323 foreach ($allbusy as $bb) {
11324 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11325 $dbo->setQuery($q);
11326 $dbo->execute();
11327 }
11328 // if automated updates enabled, keep $response['vcm'] empty
11329 // Invoke Channel Manager
11330 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11331 $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>';
11332 }
11333 }
11334 $response['message'] .= JText::translate('RESUPDATED')."\n";
11335 }
11336
11337 if (count($toswitch)) {
11338 /**
11339 * Rooms have changed so the new rates must be re-calculated.
11340 * Maybe they should be calculated in any case, even if just
11341 * the dates have changed. For the moment the rates are reset.
11342 */
11343 }
11344
11345 // unset any previously booked room due to calendar sharing
11346 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11347 // check if some of the rooms booked have shared calendars
11348 VikBooking::updateSharedCalendars($ord['id']);
11349 //
11350
11351 //Booking History
11352 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11353 //
11354
11355 $vcm_autosync = VikBooking::vcmAutoUpdate();
11356 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11357 //unset the vcm property as no buttons should be displayed when in auto-sync
11358 $response['vcm'] = '';
11359 $vcm_obj = VikBooking::getVcmInvoker();
11360 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11361 $sync_result = $vcm_obj->doSync();
11362 if ($sync_result === false) {
11363 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11364 }
11365 }
11366
11367 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11368 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11369 VikError::raiseNotice('', $response['vcm']);
11370 }
11371
11372 $response['message'] = nl2br($response['message']);
11373 echo json_encode($response);
11374 exit;
11375 }
11376
11377 public function modroomrateplans() {
11378 $dbo = JFactory::getDBO();
11379 $session = JFactory::getSession();
11380 $updforvcm = $session->get('vbVcmRatesUpd', '');
11381 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11382 $pid_room = VikRequest::getInt('id_room', '', 'request');
11383 $pid_price = VikRequest::getInt('id_price', '', 'request');
11384 $ptype = VikRequest::getString('type', '', 'request');
11385 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11386 $ptodate = VikRequest::getString('todate', '', 'request');
11387 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11388 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11389 exit;
11390 }
11391 $price_record = array();
11392 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11393 $dbo->setQuery($q);
11394 $dbo->execute();
11395 if ($dbo->getNumRows() > 0) {
11396 $price_record = $dbo->loadAssoc();
11397 }
11398 if (!count($price_record) > 0) {
11399 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11400 exit;
11401 }
11402 $current_closed = array();
11403 if (!empty($price_record['closingd'])) {
11404 $current_closed = json_decode($price_record['closingd'], true);
11405 }
11406 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11407 $start_ts = strtotime($pfromdate);
11408 $end_ts = strtotime($ptodate);
11409 $infostart = getdate($start_ts);
11410 $all_days = array();
11411 $output = array();
11412 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11413 $all_days[] = date('Y-m-d', $infostart[0]);
11414 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11415 $output[$indkey] = array();
11416 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11417 }
11418 if ($ptype == 'close') {
11419 if (!array_key_exists($pid_room, $current_closed)) {
11420 $current_closed[$pid_room] = array();
11421 }
11422 foreach ($all_days as $daymod) {
11423 if (!in_array($daymod, $current_closed[$pid_room])) {
11424 $current_closed[$pid_room][] = $daymod;
11425 }
11426 }
11427 } else {
11428 //open
11429 if (array_key_exists($pid_room, $current_closed)) {
11430 foreach ($all_days as $daymod) {
11431 if (in_array($daymod, $current_closed[$pid_room])) {
11432 foreach ($current_closed[$pid_room] as $ck => $cv) {
11433 if ($daymod == $cv) {
11434 unset($current_closed[$pid_room][$ck]);
11435 }
11436 }
11437 }
11438 }
11439 } else {
11440 $current_closed[$pid_room] = array();
11441 }
11442 }
11443 if (!count($current_closed[$pid_room]) > 0) {
11444 unset($current_closed[$pid_room]);
11445 }
11446 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11447 $dbo->setQuery($q);
11448 $dbo->execute();
11449 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
11450 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
11451 foreach ($output as $ok => $ov) {
11452 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
11453 }
11454 //update session values
11455 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
11456 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
11457 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
11458 } else {
11459 $updforvcm['dfrom'] = $start_ts;
11460 }
11461 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
11462 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
11463 } else {
11464 $updforvcm['dto'] = $end_ts;
11465 }
11466 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
11467 if (!in_array($pid_room, $updforvcm['rooms'])) {
11468 $updforvcm['rooms'][] = $pid_room;
11469 }
11470 } else {
11471 $updforvcm['rooms'] = array($pid_room);
11472 }
11473 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
11474 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
11475 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
11476 $updforvcm['rplans'][$pid_room][] = $pid_price;
11477 }
11478 } else {
11479 $updforvcm['rplans'][$pid_room] = array($pid_price);
11480 }
11481 } else {
11482 $updforvcm['rplans'] = array($pid_room => array($pid_price));
11483 }
11484 $session->set('vbVcmRatesUpd', $updforvcm);
11485 //
11486 $pdebug = VikRequest::getInt('e4j_debug', '', 'request');
11487 if ($pdebug == 1) {
11488 echo "e4j.error.\n".print_r($current_closed, true)."\n";
11489 echo print_r($output, true)."\n\n";
11490 echo print_r($all_days, true)."\n";
11491 }
11492 echo json_encode($output);
11493 exit;
11494 }
11495
11496 public function icsexportlaunch() {
11497 $dbo = JFactory::getDBO();
11498 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11499 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11500 $pstatus = VikRequest::getString('status', '', 'request');
11501 $validstatus = array('confirmed', 'standby', 'cancelled');
11502 $filterstatus = '';
11503 $filterfirst = 0;
11504 $filtersecond = 0;
11505 $nowdf = VikBooking::getDateFormat(true);
11506 if ($nowdf == "%d/%m/%Y") {
11507 $df = 'd/m/Y';
11508 } elseif ($nowdf == "%m/%d/%Y") {
11509 $df = 'm/d/Y';
11510 } else {
11511 $df = 'Y/m/d';
11512 }
11513 $currencyname = VikBooking::getCurrencyName();
11514 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11515 $filterstatus = $pstatus;
11516 }
11517 if (!empty($pcheckindate)) {
11518 if (VikBooking::dateIsValid($pcheckindate)) {
11519 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11520 $filterfirst = $first;
11521 }
11522 }
11523 if (!empty($pcheckoutdate)) {
11524 if (VikBooking::dateIsValid($pcheckoutdate)) {
11525 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11526 if ($second > $first) {
11527 $filtersecond = $second;
11528 }
11529 }
11530 }
11531 $clause = array();
11532 if ($filterfirst > 0) {
11533 $clause[] = "`o`.`checkin` >= ".$filterfirst;
11534 }
11535 if ($filtersecond > 0) {
11536 $clause[] = "`o`.`checkout` <= ".$filtersecond;
11537 }
11538 if (!empty($filterstatus)) {
11539 $clause[] = "`o`.`status` = '".$filterstatus."'";
11540 }
11541 $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;";
11542 $dbo->setQuery($q);
11543 $dbo->execute();
11544 if ($dbo->getNumRows() > 0) {
11545 $orders = $dbo->loadAssocList();
11546 $icscontent = "BEGIN:VCALENDAR\n";
11547 $icscontent .= "VERSION:2.0\n";
11548 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
11549 $icscontent .= "CALSCALE:GREGORIAN\n";
11550 $str = "";
11551 foreach ($orders as $kord => $ord) {
11552 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11553 continue;
11554 }
11555 $usecurrencyname = $currencyname;
11556 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11557 $statusstr = '';
11558 if ($ord['status'] == 'confirmed') {
11559 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11560 } elseif ($ord['status'] == 'standby') {
11561 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11562 } elseif ($ord['status'] == 'cancelled') {
11563 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11564 }
11565 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
11566 /**
11567 * @wponly Rewrite URI for front-end
11568 */
11569 $uri = str_replace(JUri::root(), '', $uri);
11570 $model = JModel::getInstance('vikbooking', 'shortcodes');
11571 $itemid = $model->best('booking');
11572 if ($itemid) {
11573 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
11574 }
11575 //
11576 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
11577 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11578 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
11579 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
11580 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
11581 $str .= "BEGIN:VEVENT\n";
11582 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11583 $str .= "UID:" . uniqid() . "\n";
11584 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11585 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
11586 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
11587 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
11588 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11589 $str .= "END:VEVENT\n";
11590 }
11591 $icscontent .= $str;
11592 $icscontent .= "END:VCALENDAR\n";
11593 //download file from buffer
11594 header("Content-Type: application/octet-stream; ");
11595 header("Cache-Control: no-store, no-cache");
11596 header('Content-Disposition: attachment; filename="bookings_export.ics"');
11597 $f = fopen('php://output', "w");
11598 fwrite($f, $icscontent);
11599 fclose($f);
11600 exit;
11601 } else {
11602 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
11603 $mainframe = JFactory::getApplication();
11604 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11605 }
11606 }
11607
11608 public function csvexportlaunch()
11609 {
11610 $dbo = JFactory::getDbo();
11611 $app = JFactory::getApplication();
11612
11613 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
11614 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
11615 $pchfilt = VikRequest::getString('chfilt', '', 'request');
11616 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
11617 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11618 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11619 $pstatus = VikRequest::getString('status', '', 'request');
11620 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
11621 $pformat = VikRequest::getString('format', 'csv', 'request');
11622
11623 // let the report class (a generic one) generate the CSV file in the proper format
11624 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
11625
11626 $validstatus = array('confirmed', 'standby', 'cancelled');
11627 $validdates = array('ts', 'checkin', 'checkout');
11628
11629 $filterdate = '';
11630 $filterstatus = '';
11631 $first = 0;
11632 $filterfirst = 0;
11633 $filtersecond = 0;
11634 $nowdf = VikBooking::getDateFormat(true);
11635 if ($nowdf == "%d/%m/%Y") {
11636 $df = 'd/m/Y';
11637 } elseif ($nowdf == "%m/%d/%Y") {
11638 $df = 'm/d/Y';
11639 } else {
11640 $df = 'Y/m/d';
11641 }
11642 $datesep = VikBooking::getDateSeparator(true);
11643 $currencyname = VikBooking::getCurrencyName();
11644
11645 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11646 $filterstatus = $pstatus;
11647 }
11648 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
11649 $filterdate = $pdatefilt;
11650 }
11651 if (!empty($pcheckindate) && !empty($filterdate)) {
11652 if (VikBooking::dateIsValid($pcheckindate)) {
11653 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11654 $filterfirst = $first;
11655 }
11656 }
11657 if (!empty($pcheckoutdate) && !empty($filterdate)) {
11658 if (VikBooking::dateIsValid($pcheckoutdate)) {
11659 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11660 if ($second > $first) {
11661 $filtersecond = $second;
11662 }
11663 }
11664 }
11665 $clause = array();
11666 if ($filterfirst > 0) {
11667 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
11668 }
11669 if ($filtersecond > 0) {
11670 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
11671 }
11672 if (!empty($filterstatus)) {
11673 $clause[] = "`o`.`status` = '".$filterstatus."'";
11674 }
11675 if (!empty($pchfilt)) {
11676 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
11677 }
11678 if (!empty($ppayfilt)) {
11679 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
11680 }
11681 if (!empty($proomfilt)) {
11682 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
11683 }
11684
11685 if (!empty($pcatfilt)) {
11686 $room_cat_ids = array();
11687 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
11688 $dbo->setQuery($q);
11689 $dbo->execute();
11690 if ($dbo->getNumRows()) {
11691 $records = $dbo->loadAssocList();
11692 foreach ($records as $rcat) {
11693 $parts = explode(';', $rcat['idcat']);
11694 if (in_array($pcatfilt, $parts)) {
11695 $room_cat_ids[] = $rcat['id'];
11696 }
11697 }
11698 }
11699 if (count($room_cat_ids)) {
11700 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
11701 }
11702 }
11703
11704 $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;";
11705 $dbo->setQuery($q);
11706 $orders = $dbo->loadAssocList();
11707 if (!$orders) {
11708 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
11709 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11710 $app->close();
11711 }
11712
11713 // options
11714 $all_options = array();
11715 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
11716 $dbo->setQuery($q);
11717 $options = $dbo->loadAssocList();
11718 if ($options) {
11719 foreach ($options as $ok => $ov) {
11720 $all_options[$ov['id']] = $ov;
11721 }
11722 }
11723
11724 // set CSV columns
11725 $report_obj->setReportCols([
11726 [
11727 'label' => JText::translate('VBDASHBOOKINGID'),
11728 ],
11729 [
11730 'label' => JText::translate('VBPVIEWORDERSONE'),
11731 ],
11732 [
11733 'label' => JText::translate('VBCSVCHECKIN'),
11734 ],
11735 [
11736 'label' => JText::translate('VBCSVCHECKOUT'),
11737 ],
11738 [
11739 'label' => JText::translate('VBCSVNIGHTS'),
11740 ],
11741 [
11742 'label' => JText::translate('VBCSVROOM'),
11743 ],
11744 [
11745 'label' => JText::translate('VBCSVPEOPLE'),
11746 ],
11747 [
11748 'label' => JText::translate('VBCSVCUSTINFO'),
11749 ],
11750 [
11751 'label' => JText::translate('ORDER_SPREQUESTS'),
11752 ],
11753 [
11754 'label' => JText::translate('ORDER_NOTES'),
11755 ],
11756 [
11757 'label' => JText::translate('VBCSVCREATEDBY'),
11758 ],
11759 [
11760 'label' => JText::translate('VBCSVCUSTMAIL'),
11761 ],
11762 [
11763 'label' => JText::translate('ORDER_PHONE'),
11764 ],
11765 [
11766 'label' => JText::translate('VBCSVOPTIONS'),
11767 ],
11768 [
11769 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
11770 ],
11771 [
11772 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
11773 ],
11774 [
11775 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
11776 ],
11777 [
11778 'label' => JText::translate('VBCSVTOTAL'),
11779 ],
11780 [
11781 'label' => JText::translate('VBCSVTOTPAID'),
11782 ],
11783 [
11784 'label' => JText::translate('VBCSVTOTTAXES'),
11785 ],
11786 ]);
11787
11788 // prepare the container for the CSV rows
11789 $orderscsv = [];
11790
11791 // availability helper
11792 $av_helper = VikBooking::getAvailabilityInstance();
11793
11794 $room_inds = [];
11795 $room_stay_dates = [];
11796 foreach ($orders as $kord => $ord) {
11797 // room index in this booking
11798 if (!isset($room_inds[$ord['id']])) {
11799 $room_inds[$ord['id']] = -1;
11800 }
11801 $room_inds[$ord['id']]++;
11802
11803 /**
11804 * Split stay reservation.
11805 *
11806 * @since 1.16.0 (J) - 1.6.0 (WP)
11807 */
11808 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
11809 if ($ord['split_stay']) {
11810 if ($ord['status'] == 'confirmed') {
11811 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11812 } else {
11813 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
11814 }
11815 // immediately count the number of nights of stay for each split room
11816 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11817 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
11818 // overwrite values for compatibility with non-confirmed bookings
11819 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
11820 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
11821 }
11822 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11823 // overwrite the whole array
11824 $room_stay_dates[$sps_r_k] = $sps_r_v;
11825 }
11826 }
11827
11828 // determine nights and dates for this room booking
11829 $booking_nights = $ord['days'];
11830 $booking_checkin = $ord['checkin'];
11831 $booking_checkout = $ord['checkout'];
11832 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']) {
11833 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
11834 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
11835 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
11836 }
11837
11838 $usecurrencyname = $currencyname;
11839 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11840 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11841 $custinfostr = str_replace(",", " ", $ord['custdata']);
11842 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
11843 if (count($customer)) {
11844 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
11845 }
11846 $special_requests = '';
11847 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11848 $special_requests = $match[1];
11849 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11850 $special_requests = $match[1];
11851 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
11852 $special_requests = $match[1];
11853 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
11854 $special_requests = $match[1];
11855 }
11856 $paystr = '';
11857 if (!empty($ord['idpayment'])) {
11858 $payparts = explode('=', $ord['idpayment']);
11859 $paystr = $payparts[1];
11860 }
11861 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
11862 $statusstr = '';
11863 if ($ord['status'] == 'confirmed') {
11864 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11865 } elseif ($ord['status'] == 'standby') {
11866 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11867 } elseif ($ord['status'] == 'cancelled') {
11868 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11869 }
11870 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
11871 if ($ord['roomsnum'] > 1) {
11872 // take the cost for the individual room
11873 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
11874 }
11875 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
11876 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11877 // total paid will be printed only for the last room booked
11878 $totalpaidstring = '';
11879 }
11880 $options_str = '';
11881 if (!empty($ord['optionals'])) {
11882 $stepo = explode(";", $ord['optionals']);
11883 foreach ($stepo as $roptkey => $oo) {
11884 if (!empty($oo)) {
11885 $stept = explode(":", $oo);
11886 if (array_key_exists($stept[0], $all_options)) {
11887 $actopt = $all_options[$stept[0]];
11888 $optpcent = false;
11889 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
11890 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
11891 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
11892 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
11893 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
11894 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
11895 $agestept = explode('-', $stept[1]);
11896 $stept[1] = $agestept[0];
11897 $chvar = $agestept[1];
11898 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
11899 $optpcent = true;
11900 }
11901 $actopt['chageintv'] = $chvar;
11902 if (isset($optagenames[($chvar - 1)])) {
11903 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
11904 }
11905 if (isset($optagecosts[($chvar - 1)])) {
11906 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
11907 } else {
11908 $realcost = 0;
11909 }
11910 } else {
11911 // VBO 1.11 - options percentage cost of the room total fee
11912 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
11913 //
11914 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
11915 }
11916 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
11917 $realcost=$actopt['maxprice'];
11918 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
11919 $realcost = $actopt['maxprice'] * $stept[1];
11920 }
11921 }
11922 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
11923 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
11924 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
11925 }
11926 }
11927 }
11928 }
11929
11930 // custom extra costs
11931 if (!empty($ord['extracosts'])) {
11932 $cur_extra_costs = json_decode($ord['extracosts'], true);
11933 foreach ($cur_extra_costs as $eck => $ecv) {
11934 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
11935 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
11936 }
11937 }
11938
11939 // taxes
11940 $taxes_str = '';
11941 if ($ord['tot_taxes'] > 0.00) {
11942 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
11943 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
11944 $tax_breakdown = json_decode($ord['breakdown'], true);
11945 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
11946 if (count($tax_breakdown)) {
11947 foreach ($tax_breakdown as $tbkk => $tbkv) {
11948 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
11949 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
11950 }
11951 }
11952 }
11953 }
11954 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11955 // total taxes will be printed only for the last room booked
11956 $taxes_str = '';
11957 }
11958
11959 // created by
11960 $created_by = '';
11961 if (!empty($ord['ujid'])) {
11962 $creator = new JUser($ord['ujid']);
11963 if (property_exists($creator, 'name')) {
11964 $created_by = $creator->name.' ('.$creator->username.')';
11965 }
11966 }
11967 if (empty($created_by) && !empty($ord['t_first_name'])) {
11968 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
11969 }
11970
11971 // push line for export
11972 $orderscsv[] = [
11973 [
11974 'value' => $ord['id'],
11975 ],
11976 [
11977 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
11978 ],
11979 [
11980 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
11981 ],
11982 [
11983 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
11984 ],
11985 [
11986 'value' => $booking_nights,
11987 ],
11988 [
11989 'value' => $ord['name'],
11990 ],
11991 [
11992 'value' => $peoplestr,
11993 ],
11994 [
11995 'value' => $custinfostr,
11996 ],
11997 [
11998 'value' => $special_requests,
11999 ],
12000 [
12001 'value' => $ord['adminnotes'],
12002 ],
12003 [
12004 'value' => $created_by,
12005 ],
12006 [
12007 'value' => $ord['custmail'],
12008 ],
12009 [
12010 'value' => $ord['phone'],
12011 ],
12012 [
12013 'value' => $options_str,
12014 ],
12015 [
12016 'value' => $paystr,
12017 ],
12018 [
12019 'value' => $ordnumbstr,
12020 ],
12021 [
12022 'value' => $statusstr,
12023 ],
12024 [
12025 'value' => $totalstring,
12026 ],
12027 [
12028 'value' => $totalpaidstring,
12029 ],
12030 [
12031 'value' => $taxes_str,
12032 ],
12033 ];
12034 }
12035
12036 // set CSV rows
12037 $report_obj->setReportRows($orderscsv);
12038
12039 // build lines to export
12040 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12041
12042 // set export file name
12043 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12044
12045 // force the download of the CSV file
12046 $report_obj->outputHeaders();
12047
12048 // send lines to output
12049 $report_obj->outputCSV($csvlines);
12050
12051 exit;
12052 }
12053
12054 public function exportcustomerslaunch() {
12055 $cid = VikRequest::getVar('cid', array(0));
12056 $dbo = JFactory::getDBO();
12057 $pnotes = VikRequest::getInt('notes', '', 'request');
12058 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12059 $ppin = VikRequest::getInt('pin', '', 'request');
12060 $pcountry = VikRequest::getString('country', '', 'request');
12061 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12062 $ptodate = VikRequest::getString('todate', '', 'request');
12063 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12064 $clauses = array();
12065 if (count($cid) > 0 && !empty($cid[0])) {
12066 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12067 }
12068 if (!empty($pcountry)) {
12069 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12070 }
12071 $datescol = '`bk`.`ts`';
12072 if ($pdatefilt > 0) {
12073 if ($pdatefilt == 1) {
12074 $datescol = '`bk`.`ts`';
12075 } elseif ($pdatefilt == 2) {
12076 $datescol = '`bk`.`checkin`';
12077 } elseif ($pdatefilt == 3) {
12078 $datescol = '`bk`.`checkout`';
12079 }
12080 }
12081 if (!empty($pfromdate)) {
12082 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12083 $clauses[] = $datescol.">=".$from_ts;
12084 }
12085 if (!empty($ptodate)) {
12086 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12087 $clauses[] = $datescol."<=".$to_ts;
12088 }
12089 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12090 $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`,".
12091 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12092 "`cy`.`country_3_code`,`cy`.`country_name` ".
12093 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12094 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12095 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12096 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12097 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` ".
12098 "ORDER BY `c`.`last_name` ASC;";
12099 $dbo->setQuery($q);
12100 $dbo->execute();
12101 if (!($dbo->getNumRows() > 0)) {
12102 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12103 $mainframe = JFactory::getApplication();
12104 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12105 exit;
12106 }
12107 $customers = $dbo->loadAssocList();
12108 $csvlines = array();
12109 $csvheadline = array('ID', JText::translate('VBCUSTOMERLASTNAME'), JText::translate('VBCUSTOMERFIRSTNAME'), JText::translate('VBCUSTOMEREMAIL'), JText::translate('VBCUSTOMERPHONE'), JText::translate('VBCUSTOMERADDRESS'), JText::translate('VBCUSTOMERCITY'), JText::translate('VBCUSTOMERZIP'), JText::translate('VBCUSTOMERCOUNTRY'), JText::translate('VBCUSTOMERTOTBOOKINGS'));
12110 if ($ppin > 0) {
12111 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12112 }
12113 if ($pscanimg > 0) {
12114 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12115 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12116 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12117 }
12118 if ($pnotes > 0) {
12119 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12120 }
12121 $csvlines[] = $csvheadline;
12122 foreach ($customers as $customer) {
12123 $csvcustomerline = array($customer['id'], $customer['last_name'], $customer['first_name'], $customer['email'], $customer['phone'], $customer['address'], $customer['city'], $customer['zip'], $customer['country_name'], $customer['tot_bookings']);
12124 if ($ppin > 0) {
12125 $csvcustomerline[] = $customer['pin'];
12126 }
12127 if ($pscanimg > 0) {
12128 $csvcustomerline[] = $customer['doctype'];
12129 $csvcustomerline[] = $customer['docnum'];
12130 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12131 }
12132 if ($pnotes > 0) {
12133 $csvcustomerline[] = $customer['notes'];
12134 }
12135 $csvlines[] = $csvcustomerline;
12136 }
12137 header("Content-type: text/csv");
12138 header("Cache-Control: no-store, no-cache");
12139 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12140 $outstream = fopen("php://output", 'w');
12141 foreach ($csvlines as $csvline) {
12142 fputcsv($outstream, $csvline);
12143 }
12144 fclose($outstream);
12145 exit;
12146 }
12147
12148 public function renewsession() {
12149 /*
12150 * @wponly
12151 * We just destroy the session
12152 */
12153 JSessionHandler::destroy();
12154 $mainframe = JFactory::getApplication();
12155 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12156 }
12157
12158 public function trackings() {
12159 VikBookingHelper::printHeader("trackings");
12160
12161 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12162
12163 parent::display();
12164
12165 if (VikBooking::showFooter()) {
12166 VikBookingHelper::printFooter();
12167 }
12168 }
12169
12170 public function trkconfig() {
12171 VikBookingHelper::printHeader("trackings");
12172
12173 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12174
12175 parent::display();
12176
12177 if (VikBooking::showFooter()) {
12178 VikBookingHelper::printFooter();
12179 }
12180 }
12181
12182 public function savetrkconfigstay() {
12183 if (!JSession::checkToken()) {
12184 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12185 }
12186 $this->do_savetrkconfig(true);
12187 }
12188
12189 public function savetrkconfig() {
12190 if (!JSession::checkToken()) {
12191 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12192 }
12193 $this->do_savetrkconfig();
12194 }
12195
12196 private function do_savetrkconfig($stay = false) {
12197 $dbo = JFactory::getDBO();
12198 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12199 $trkenabled = $trkenabled == 1 ? 1 : 0;
12200 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12201 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12202 $trkcampname = VikRequest::getVar('trkcampname', array());
12203 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12204 $trkcampval = VikRequest::getVar('trkcampval', array());
12205 $trkcampaigns = array();
12206 foreach ($trkcampname as $k => $v) {
12207 if (empty($trkcampkey[$k])) {
12208 continue;
12209 }
12210 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12211 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12212 $trkcampaigns[$trkcampkey[$k]] = array(
12213 'key' => $trkcampkey[$k],
12214 'value' => $trkcampval[$k],
12215 'name' => $name,
12216 );
12217 }
12218
12219 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12220 $dbo->setQuery($q);
12221 $dbo->execute();
12222 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12223 $dbo->setQuery($q);
12224 $dbo->execute();
12225 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12226 $dbo->setQuery($q);
12227 $dbo->execute();
12228
12229 $mainframe = JFactory::getApplication();
12230 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12231 }
12232
12233 public function modtracking() {
12234 $dbo = JFactory::getDbo();
12235 $cid = VikRequest::getVar('cid', array());
12236 foreach ($cid as $id) {
12237 if (!empty($id)) {
12238 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12239 $dbo->setQuery($q);
12240 $dbo->execute();
12241 if ($dbo->getNumRows()) {
12242 $data = $dbo->loadAssoc();
12243 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12244 $dbo->setQuery($q);
12245 $dbo->execute();
12246 }
12247 }
12248 }
12249 $mainframe = JFactory::getApplication();
12250 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12251 }
12252
12253 public function removetrackings() {
12254 $ids = VikRequest::getVar('cid', array());
12255 $dbo = JFactory::getDbo();
12256
12257 foreach ($ids as $d) {
12258 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12259 $dbo->setQuery($q);
12260 $dbo->execute();
12261 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12262 $dbo->setQuery($q);
12263 $dbo->execute();
12264 }
12265
12266 $mainframe = JFactory::getApplication();
12267 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12268 }
12269
12270 /**
12271 * Invokes the Tracker class to obtain
12272 * geo information about the IP addresses.
12273 * This task is called via ajax.
12274 *
12275 * @since 1.11
12276 */
12277 public function getgeoinfo() {
12278 $ips = VikRequest::getVar('ips', array());
12279 if (!count($ips)) {
12280 echo 'e4j.error.empty IPs';
12281 exit;
12282 }
12283
12284 // require the Tracker class without instantiating the object
12285 VikBooking::getTracker(true);
12286 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12287
12288 if ($geo_info === false) {
12289 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12290 exit;
12291 }
12292
12293 // update db values and compose response
12294 $dbo = JFactory::getDbo();
12295 $resp = array();
12296 foreach ($geo_info as $id => $geo) {
12297 if (is_null($geo) || $geo === false) {
12298 continue;
12299 }
12300 // compose geo info string
12301 $geovals = array();
12302 if (!empty($geo['city'])) {
12303 array_push($geovals, $geo['city']);
12304 }
12305 if (!empty($geo['region'])) {
12306 array_push($geovals, $geo['region']);
12307 }
12308 $threecode = '';
12309 $cname = '';
12310 if (!empty($geo['country'])) {
12311 // returned country is a 2-char code, get the 3-char country code
12312 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12313 $dbo->setQuery($q);
12314 $dbo->execute();
12315 if ($dbo->getNumRows()) {
12316 $cinfo = $dbo->loadAssoc();
12317 $threecode = $cinfo['country_3_code'];
12318 $cname = $cinfo['country_name'];
12319 }
12320 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12321 }
12322
12323 // full geo information string
12324 $geoinfostr = implode(', ', $geovals);
12325
12326 // push data to the response pool
12327 $resp[$id] = array();
12328 $resp[$id]['geo'] = $geoinfostr;
12329 if (!empty($cname)) {
12330 $resp[$id]['country'] = $cname;
12331 }
12332 if (!empty($threecode)) {
12333 $resp[$id]['country3'] = $threecode;
12334 }
12335
12336 // update main tracking record
12337 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12338 $dbo->setQuery($q);
12339 $dbo->execute();
12340 }
12341
12342 // output the JSON response
12343 echo json_encode($resp);
12344 exit;
12345 }
12346
12347 /**
12348 * Counts the orphan dates for all published rooms
12349 * depending on their restrictions and booked dates.
12350 * By default, the task takes up to 3 months ahead.
12351 * It is possible to filter the request by rooms and months.
12352 * This task should be called via ajax.
12353 *
12354 * @since 1.11
12355 */
12356 public function orphanscount()
12357 {
12358 $dbo = JFactory::getDbo();
12359 $orphans = array();
12360
12361 $nowdf = VikBooking::getDateFormat();
12362 if ($nowdf == "%d/%m/%Y") {
12363 $df = 'd/m/Y';
12364 } elseif ($nowdf == "%m/%d/%Y") {
12365 $df = 'm/d/Y';
12366 } else {
12367 $df = 'Y/m/d';
12368 }
12369
12370 // global min los
12371 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12372 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12373
12374 // rooms and dates
12375 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12376 $months = VikRequest::getInt('months', 3, 'request');
12377 $from = VikRequest::getString('from', '', 'request');
12378 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12379 if (!empty($from)) {
12380 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12381 if (!empty($fromts)) {
12382 // custom starting date
12383 $today = $fromts;
12384 }
12385 }
12386 $until = strtotime("+{$months} months", $today);
12387
12388 // load all rooms
12389 $rooms = array();
12390 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12391 $dbo->setQuery($q);
12392 $dbo->execute();
12393 if ($dbo->getNumRows()) {
12394 $allrooms = $dbo->loadAssocList();
12395 foreach ($allrooms as $r) {
12396 $rooms[$r['id']] = $r;
12397 }
12398 }
12399 if (!count($rooms)) {
12400 // no rooms found, exit
12401 echo json_encode($orphans);
12402 exit;
12403 }
12404
12405 // load availabilities
12406 $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.");";
12407 $dbo->setQuery($q);
12408 $dbo->execute();
12409 if (!$dbo->getNumRows()) {
12410 // no booked dates found, exit
12411 echo json_encode($orphans);
12412 exit;
12413 }
12414 $busy = $dbo->loadAssocList();
12415
12416 // sort booked dates by room id
12417 $rooms_busy = array();
12418 foreach ($busy as $b) {
12419 if (!isset($rooms_busy[$b['idroom']])) {
12420 $rooms_busy[$b['idroom']] = array();
12421 }
12422 array_push($rooms_busy[$b['idroom']], $b);
12423 }
12424
12425 // load restrictions
12426 $rooms_restr = array();
12427 foreach ($rooms as $rid => $r) {
12428 $restrictions = VikBooking::loadRestrictions(true, array($rid));
12429 if (count($restrictions)) {
12430 $rooms_restr[$rid] = $restrictions;
12431 }
12432 }
12433 if (!count($rooms_restr) && $glob_minlos < 2) {
12434 // no restrictions found and minlos=1, exit
12435 echo json_encode($orphans);
12436 exit;
12437 }
12438
12439 // count availability and minlos per day
12440 $rooms_data = array();
12441 foreach ($rooms as $rid => $r) {
12442 $rooms_data[$rid] = array(
12443 'avail' => array(),
12444 'restr' => array()
12445 );
12446 $nowts = getdate($today);
12447 while ($nowts[0] <= $until) {
12448 $dateind = date('Y-m-d', $nowts[0]);
12449
12450 // remaining availability
12451 if (!isset($rooms_busy[$rid])) {
12452 // no bookings for this room, set full availability for this day
12453 $rooms_data[$rid]['avail'][] = array(
12454 'dt' => $dateind,
12455 'units' => $r['units']
12456 );
12457 } else {
12458 // check remaining availability for this day
12459 $totfound = 0;
12460 foreach ($rooms_busy[$rid] as $b) {
12461 $tmpone = getdate($b['checkin']);
12462 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
12463 $ritts = strtotime($rit);
12464 $tmptwo = getdate($b['checkout']);
12465 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
12466 $conts = strtotime($con);
12467 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
12468 $totfound++;
12469 }
12470 }
12471 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
12472 $rooms_data[$rid]['avail'][] = array(
12473 'dt' => $dateind,
12474 'units' => ($r['units'] - $totfound)
12475 );
12476 }
12477
12478 // restrictions
12479 if (!isset($rooms_restr[$rid])) {
12480 // no restrictions for this room, set global minlos for this day
12481 $rooms_data[$rid]['restr'][] = array(
12482 'dt' => $dateind,
12483 'minlos' => $glob_minlos
12484 );
12485 } else {
12486 // get restriction for this day
12487 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
12488 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12489
12490 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
12491 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
12492
12493 $rooms_data[$rid]['restr'][] = array(
12494 'dt' => $dateind,
12495 'minlos' => $minlos
12496 );
12497 }
12498
12499 // next loop
12500 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12501 $nowts = getdate($dayts);
12502 }
12503 }
12504
12505 // week days and months labels
12506 $days_labels = array(
12507 JText::translate('VBSUNDAY'),
12508 JText::translate('VBMONDAY'),
12509 JText::translate('VBTUESDAY'),
12510 JText::translate('VBWEDNESDAY'),
12511 JText::translate('VBTHURSDAY'),
12512 JText::translate('VBFRIDAY'),
12513 JText::translate('VBSATURDAY')
12514 );
12515 $months_labels = array(
12516 JText::translate('VBMONTHONE'),
12517 JText::translate('VBMONTHTWO'),
12518 JText::translate('VBMONTHTHREE'),
12519 JText::translate('VBMONTHFOUR'),
12520 JText::translate('VBMONTHFIVE'),
12521 JText::translate('VBMONTHSIX'),
12522 JText::translate('VBMONTHSEVEN'),
12523 JText::translate('VBMONTHEIGHT'),
12524 JText::translate('VBMONTHNINE'),
12525 JText::translate('VBMONTHTEN'),
12526 JText::translate('VBMONTHELEVEN'),
12527 JText::translate('VBMONTHTWELVE')
12528 );
12529
12530 // orphan dates calculation method
12531 $calc_method = VikBooking::orphansCalculation();
12532
12533 // parse data and build orphans if any
12534 foreach ($rooms_data as $rid => $data) {
12535 foreach ($data['avail'] as $ind => $av) {
12536 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
12537 // continue, no restriction set or no availability for this day
12538 continue;
12539 }
12540 if ($data['restr'][$ind]['minlos'] < 2) {
12541 // continue, no min los > 1 set for this day
12542 continue;
12543 }
12544 // check if any night after today, until min los, is fully booked
12545 $hasorphans = false;
12546 $forward_count = 0;
12547 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
12548 if (!isset($data['avail'][($ind + $i)])) {
12549 // break loop, no info for this day after
12550 break;
12551 }
12552 if ($data['avail'][($ind + $i)]['units'] > 0) {
12553 // continue, availability found for tomorrow, we need a non available next-day
12554 continue;
12555 }
12556 // orphan found
12557 $hasorphans = true;
12558 $forward_count = $i;
12559 break;
12560 }
12561
12562 /**
12563 * Backward calculation method only if "prevnext".
12564 *
12565 * @since 1.3.0
12566 */
12567 $backward_count = 0;
12568 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
12569 if (!isset($data['avail'][($ind - $i)])) {
12570 // break loop, no info for this prev day
12571 break;
12572 }
12573 if ($data['avail'][($ind - $i)]['units'] > 0) {
12574 // increase free nights going backward
12575 $backward_count++;
12576 }
12577 }
12578 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
12579 // this should not be an orphan date because of enough free days back, or enough free days in between
12580 $hasorphans = false;
12581 }
12582 //
12583
12584 if ($hasorphans) {
12585 // 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
12586 if (!isset($orphans[$rid])) {
12587 $orphans[$rid] = array(
12588 'name' => $rooms[$rid]['name'],
12589 'dates' => array(),
12590 'rdates' => array(),
12591 'linkd' => date($df, strtotime($av['dt']))
12592 );
12593 }
12594 array_push($orphans[$rid]['dates'], $av['dt']);
12595 // build the value for the readable date
12596 $dtinfo = getdate(strtotime($av['dt']));
12597 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
12598 array_push($orphans[$rid]['rdates'], $rdate);
12599 }
12600 }
12601 }
12602
12603 // output response
12604 echo json_encode($orphans);
12605 exit;
12606 }
12607
12608 public function tableaux() {
12609 VikBookingHelper::printHeader("tableaux");
12610
12611 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
12612
12613 parent::display();
12614
12615 if (VikBooking::showFooter()) {
12616 VikBookingHelper::printFooter();
12617 }
12618 }
12619
12620 public function operators() {
12621 VikBookingHelper::printHeader("operators");
12622
12623 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
12624
12625 parent::display();
12626
12627 if (VikBooking::showFooter()) {
12628 VikBookingHelper::printFooter();
12629 }
12630 }
12631
12632 public function newoperator() {
12633 VikBookingHelper::printHeader("operators");
12634
12635 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12636
12637 parent::display();
12638
12639 if (VikBooking::showFooter()) {
12640 VikBookingHelper::printFooter();
12641 }
12642 }
12643
12644 public function editoperator() {
12645 VikBookingHelper::printHeader("operators");
12646
12647 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12648
12649 parent::display();
12650
12651 if (VikBooking::showFooter()) {
12652 VikBookingHelper::printFooter();
12653 }
12654 }
12655
12656 public function updateoperator() {
12657 if (!JSession::checkToken()) {
12658 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12659 }
12660 $this->do_updateoperator();
12661 }
12662
12663 public function updateoperatorstay() {
12664 if (!JSession::checkToken()) {
12665 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12666 }
12667 $this->do_updateoperator(true);
12668 }
12669
12670 private function do_updateoperator($stay = false) {
12671 $dbo = JFactory::getDBO();
12672 $mainframe = JFactory::getApplication();
12673 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12674 $plast_name = VikRequest::getString('last_name', '', 'request');
12675 $pemail = VikRequest::getString('email', '', 'request');
12676 $pphone = VikRequest::getString('phone', '', 'request');
12677 $pcode = VikRequest::getString('code', '', 'request');
12678 $pujid = VikRequest::getInt('ujid', '', 'request');
12679 $pwhere = VikRequest::getInt('where', '', 'request');
12680 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12681 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
12682 $dbo->setQuery($q);
12683 $dbo->execute();
12684 if ($dbo->getNumRows() == 1) {
12685 $customer = $dbo->loadAssoc();
12686 } else {
12687 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12688 exit;
12689 }
12690 $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;";
12691 $dbo->setQuery($q);
12692 $dbo->execute();
12693 if ($dbo->getNumRows() == 0) {
12694 // update fingerprint for the operator
12695 $fingpt = md5($pwhere.$pemail);
12696 //
12697 $q = "UPDATE `#__vikbooking_operators` SET `first_name`=".$dbo->quote($pfirst_name).",`last_name`=".$dbo->quote($plast_name).",`email`=".$dbo->quote($pemail).",`phone`=".$dbo->quote($pphone).",`code`=".$dbo->quote($pcode).",`ujid`=".$dbo->quote($pujid).",`fingpt`=".$dbo->quote($fingpt)." WHERE `id`=".(int)$pwhere.";";
12698 $dbo->setQuery($q);
12699 $dbo->execute();
12700 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12701 } else {
12702 //email already exists
12703 $ex_operator = $dbo->loadAssoc();
12704 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>');
12705 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12706 exit;
12707 }
12708 } else {
12709 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12710 }
12711 if ($stay) {
12712 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12713 } else {
12714 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12715 }
12716 }
12717
12718 public function saveoperator() {
12719 if (!JSession::checkToken()) {
12720 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12721 }
12722 $dbo = JFactory::getDbo();
12723 $mainframe = JFactory::getApplication();
12724 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12725 $plast_name = VikRequest::getString('last_name', '', 'request');
12726 $pemail = VikRequest::getString('email', '', 'request');
12727 $pphone = VikRequest::getString('phone', '', 'request');
12728 $pcode = VikRequest::getString('code', '', 'request');
12729 $pujid = VikRequest::getInt('ujid', '', 'request');
12730 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12731 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
12732 $dbo->setQuery($q);
12733 $dbo->execute();
12734 if ($dbo->getNumRows() == 0) {
12735 $q = "INSERT INTO `#__vikbooking_operators` (`first_name`,`last_name`,`email`,`phone`,`code`,`ujid`) VALUES(".$dbo->quote($pfirst_name).", ".$dbo->quote($plast_name).", ".$dbo->quote($pemail).", ".$dbo->quote($pphone).", ".$dbo->quote($pcode).", ".$dbo->quote($pujid).");";
12736 $dbo->setQuery($q);
12737 $dbo->execute();
12738 $lid = $dbo->insertid();
12739 if (!empty($lid)) {
12740 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12741 // generate fingerprint for the operator
12742 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->quote(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
12743 $dbo->setQuery($q);
12744 $dbo->execute();
12745 //
12746 }
12747 } else {
12748 //email already exists
12749 $ex_operator = $dbo->loadAssoc();
12750 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>');
12751 }
12752 } else {
12753 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12754 }
12755 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12756 }
12757
12758 public function removeoperators() {
12759 if (!JSession::checkToken()) {
12760 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12761 }
12762 $ids = VikRequest::getVar('cid', array(0));
12763 if (@count($ids)) {
12764 $dbo = JFactory::getDBO();
12765 foreach ($ids as $d) {
12766 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
12767 $dbo->setQuery($q);
12768 $dbo->execute();
12769 }
12770 }
12771 $mainframe = JFactory::getApplication();
12772 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12773 }
12774
12775 public function operatorperms() {
12776 $dbo = JFactory::getDbo();
12777 $permtype = VikRequest::getString('permtype', 'tableaux', 'request');
12778 $permschanged = 0;
12779
12780 if ($permtype == 'tableaux') {
12781 $oper_id = VikRequest::getVar('oper_id', array());
12782 $oper_days = VikRequest::getVar('oper_days', array());
12783 $oper_rooms = VikRequest::getVar('oper_rooms', array());
12784 $oper_guestname = VikRequest::getVar('oper_guestname', array());
12785 $oper_roomextras = VikRequest::getVar('oper_roomextras', array());
12786 $oper_rm = VikRequest::getVar('oper_rm', array());
12787 if (count($oper_rm)) {
12788 // remove permissions first
12789 foreach ($oper_rm as $operatorid) {
12790 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$operatorid.";";
12791 $dbo->setQuery($q);
12792 $dbo->execute();
12793 if ($dbo->getNumRows()) {
12794 $current = $dbo->loadAssoc();
12795 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12796 $perms = !is_array($perms) ? array() : $perms;
12797 foreach ($perms as $kp => $perm) {
12798 if (isset($perm['type']) && $perm['type'] == $permtype) {
12799 unset($perms[$kp]);
12800 break;
12801 }
12802 }
12803 // update permissions for this operator
12804 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12805 $dbo->setQuery($q);
12806 $dbo->execute();
12807 $permschanged++;
12808 }
12809 }
12810 }
12811 foreach ($oper_id as $k => $v) {
12812 if (empty($v) || !isset($oper_days[$k])) {
12813 // missing data
12814 continue;
12815 }
12816 // get operator
12817 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$v.";";
12818 $dbo->setQuery($q);
12819 $dbo->execute();
12820 if (!$dbo->getNumRows()) {
12821 continue;
12822 }
12823 $current = $dbo->loadAssoc();
12824 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12825 $perms = !is_array($perms) ? array() : $perms;
12826 foreach ($perms as $kp => $perm) {
12827 if (isset($perm['type']) && $perm['type'] == $permtype) {
12828 unset($perms[$kp]);
12829 break;
12830 }
12831 }
12832 // push new permission
12833 array_push($perms, array(
12834 'type' => $permtype,
12835 'perms' => array(
12836 'days' => (int)$oper_days[$k],
12837 'rooms' => (isset($oper_rooms[$k]) && is_array($oper_rooms[$k]) ? $oper_rooms[$k] : array()),
12838 'guestname' => (isset($oper_guestname[$k]) && (int)$oper_guestname[$k] > 0 ? 1 : 0),
12839 'roomextras' => (isset($oper_roomextras[$k]) && (int)$oper_roomextras[$k] > 0 ? 1 : 0),
12840 )
12841 ));
12842 // update permissions for this operator
12843 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12844 $dbo->setQuery($q);
12845 $dbo->execute();
12846 $permschanged++;
12847 }
12848 }
12849
12850 $mainframe = JFactory::getApplication();
12851 if ($permschanged > 0) {
12852 $mainframe->enqueueMessage(JText::translate('VBOPERMSUPDOPEROK'));
12853 }
12854 $mainframe->redirect("index.php?option=com_vikbooking&task=".$permtype);
12855 }
12856
12857 public function canceloperator() {
12858 $mainframe = JFactory::getApplication();
12859 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12860 }
12861
12862 public function cancelcrons() {
12863 $mainframe = JFactory::getApplication();
12864 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
12865 }
12866
12867 public function cancelpackages() {
12868 $mainframe = JFactory::getApplication();
12869 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
12870 }
12871
12872 public function cancelcustomer() {
12873 $mainframe = JFactory::getApplication();
12874 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
12875 if (!empty($pgoto)) {
12876 $mainframe->redirect(base64_decode($pgoto));
12877 exit;
12878 }
12879 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12880 }
12881
12882 public function cancelbusyvcm() {
12883 $mainframe = JFactory::getApplication();
12884 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
12885 }
12886
12887 public function cancelrestriction() {
12888 $mainframe = JFactory::getApplication();
12889 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
12890 }
12891
12892 public function cancelcoupon() {
12893 $mainframe = JFactory::getApplication();
12894 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
12895 }
12896
12897 public function cancelcustomf() {
12898 $mainframe = JFactory::getApplication();
12899 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
12900 }
12901
12902 public function cancelpayment() {
12903 $mainframe = JFactory::getApplication();
12904 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
12905 }
12906
12907 public function cancelseason() {
12908 $mainframe = JFactory::getApplication();
12909 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
12910 }
12911
12912 public function goconfig() {
12913 $mainframe = JFactory::getApplication();
12914 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12915 }
12916
12917 public function canceledorder() {
12918 $pgoto = VikRequest::getString('goto', 'orders', 'request');
12919 $mainframe = JFactory::getApplication();
12920 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
12921 }
12922
12923 public function cancelbusy() {
12924 $pidorder = VikRequest::getString('idorder', '', 'request');
12925 $pgoto = VikRequest::getString('goto', '', 'request');
12926 $mainframe = JFactory::getApplication();
12927 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
12928 }
12929
12930 public function canceloverv() {
12931 $mainframe = JFactory::getApplication();
12932 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
12933 }
12934
12935 public function canceltableaux() {
12936 $mainframe = JFactory::getApplication();
12937 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
12938 }
12939
12940 public function cancelcalendar() {
12941 $pidroom = VikRequest::getString('idroom', '', 'request');
12942 $mainframe = JFactory::getApplication();
12943 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
12944 }
12945
12946 public function canceloptionals() {
12947 $mainframe = JFactory::getApplication();
12948 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
12949 }
12950
12951 public function cancel() {
12952 $mainframe = JFactory::getApplication();
12953 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
12954 }
12955
12956 public function cancelcarat() {
12957 $mainframe = JFactory::getApplication();
12958 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
12959 }
12960
12961 public function cancelcat() {
12962 $mainframe = JFactory::getApplication();
12963 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
12964 }
12965
12966 public function cancelprice() {
12967 $mainframe = JFactory::getApplication();
12968 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
12969 }
12970
12971 public function canceliva() {
12972 $mainframe = JFactory::getApplication();
12973 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
12974 }
12975
12976 public function canceltrk() {
12977 $mainframe = JFactory::getApplication();
12978 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12979 }
12980
12981 public function canceldash() {
12982 $mainframe = JFactory::getApplication();
12983 $mainframe->redirect("index.php?option=com_vikbooking");
12984 }
12985
12986 public function cancelinvoice() {
12987 $mainframe = JFactory::getApplication();
12988 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
12989 if (!empty($pgoto)) {
12990 $mainframe->redirect(base64_decode($pgoto));
12991 exit;
12992 }
12993 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
12994 }
12995
12996 /**
12997 * AJAX upload the customer documents.
12998 *
12999 * @return void
13000 *
13001 * @throws Exception
13002 */
13003 public function upload_customer_document()
13004 {
13005 $input = JFactory::getApplication()->input;
13006 $dbo = JFactory::getDbo();
13007
13008 $customer_id = $input->getUint('customer', 0);
13009
13010 $result = new stdClass;
13011 $result->status = 0;
13012
13013 try
13014 {
13015 $q = $dbo->getQuery(true)
13016 ->select($dbo->qn(array(
13017 'id',
13018 'first_name',
13019 'last_name',
13020 'email',
13021 'docsfolder',
13022 )))
13023 ->from($dbo->qn('#__vikbooking_customers'))
13024 ->where($dbo->qn('id') . ' = ' . $customer_id);
13025
13026 $dbo->setQuery($q, 0, 1);
13027 $dbo->execute();
13028
13029 if (!$dbo->getNumRows())
13030 {
13031 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13032 }
13033
13034 $customer = $dbo->loadObject();
13035
13036 // fetch documents folder path
13037 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13038
13039 // check if we have a valid directory
13040 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
13041 {
13042 // randomize string
13043 $customer->seed = uniqid();
13044
13045 // create blocks for hashed folder
13046 $parts = [
13047 $customer->first_name,
13048 $customer->last_name,
13049 md5(serialize($customer)),
13050 ];
13051
13052 // join fetched parts
13053 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13054
13055 if (strlen($customer->docsfolder) < 16)
13056 {
13057 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13058 }
13059
13060 jimport('joomla.filesystem.folder');
13061
13062 // create a folder for this customer
13063 $created = JFolder::create($dirpath . $customer->docsfolder);
13064
13065 if (!$created)
13066 {
13067 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13068 }
13069
13070 unset($customer->seed);
13071
13072 // update docs folder
13073 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13074 }
13075
13076 // get file from request
13077 $file = $input->files->get('file', array(), 'array');
13078
13079 // try to upload the file
13080 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13081 $result->status = 1;
13082
13083 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13084 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13085 }
13086 catch (Exception $e)
13087 {
13088 $result->error = $e->getMessage();
13089 $result->code = $e->getCode();
13090 }
13091
13092 echo json_encode($result);
13093 exit;
13094 }
13095
13096 /**
13097 * AJAX delete the customer documents.
13098 *
13099 * @return void
13100 *
13101 * @throws Exception
13102 */
13103 public function delete_customer_document()
13104 {
13105 $input = JFactory::getApplication()->input;
13106 $dbo = JFactory::getDbo();
13107
13108 $customer_id = $input->getUint('customer', 0);
13109
13110 $result = new stdClass;
13111 $result->status = 0;
13112
13113 $q = $dbo->getQuery(true)
13114 ->select($dbo->qn('docsfolder'))
13115 ->from($dbo->qn('#__vikbooking_customers'))
13116 ->where($dbo->qn('id') . ' = ' . $customer_id);
13117
13118 $dbo->setQuery($q, 0, 1);
13119 $dbo->execute();
13120
13121 if (!$dbo->getNumRows())
13122 {
13123 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13124 }
13125
13126 $folder = $dbo->loadResult();
13127
13128 if (!$folder)
13129 {
13130 throw new Exception('The customer does not have any documents', 500);
13131 }
13132
13133 $file = $input->getString('file');
13134
13135 if (!$file)
13136 {
13137 throw new Exception('File to remove not specified', 400);
13138 }
13139
13140 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13141
13142 if (!is_file($path))
13143 {
13144 throw new Exception(sprintf('File [%s] not found', $path), 404);
13145 }
13146
13147 jimport('joomla.filesystem.file');
13148
13149 $removed = JFile::delete($path);
13150
13151 echo json_encode(array('status' => (int) $removed));
13152 exit;
13153 }
13154
13155 /**
13156 * AJAX task to invoke a specific report and obtain information.
13157 *
13158 * @since 1.3.0
13159 */
13160 public function get_report_data()
13161 {
13162 $report_name = VikRequest::getString('report_name', '', 'request');
13163 $current_fest = VikRequest::getString('current_fest', '', 'request');
13164 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13165 $current_todate = VikRequest::getString('current_todate', '', 'request');
13166 $step = VikRequest::getString('step', 'weekend', 'request');
13167 $direction = VikRequest::getString('direction', 'load', 'request');
13168 $period = VikRequest::getString('period', 'full', 'request');
13169 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13170 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13171 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13172 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13173 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13174 // idroom can be an array of IDs or just one ID as int/string
13175 $idroom = VikRequest::getVar('idroom', null, 'request');
13176 //
13177
13178 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13179 throw new Exception("Missing request data", 400);
13180 }
13181
13182 // get requested report instance
13183 $report = VikBooking::getReportInstance($report_name);
13184 if (!$report) {
13185 throw new Exception("Report not found", 404);
13186 }
13187
13188 // chart data
13189 if (empty($chart_datatype)) {
13190 $chart_datatype = array(
13191 'type' => 'doughnut',
13192 'depth' => 1,
13193 'keys' => array($krsort),
13194 );
13195 }
13196
13197 // website date format
13198 $df = $report->getDateFormat();
13199
13200 // prepare request params for the report
13201 $rparams = array(
13202 'fromdate' => $current_fromdate,
13203 'todate' => $current_todate,
13204 'period' => $period,
13205 'krsort' => $krsort,
13206 'krorder' => $krorder,
13207 'idroom' => $idroom,
13208 );
13209
13210 // starting dates info and timestamps
13211 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13212 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13213 $from_info = getdate($from_ts);
13214 $to_info = getdate($to_ts);
13215
13216 // the name of the period requested and whether it's a fest
13217 $period_name = '';
13218 $is_fest = null;
13219
13220 if ($direction == 'prev' || $direction == 'next') {
13221 // calculate prev or next dates
13222 if ($step == 'weekend') {
13223 $period_name = JText::translate('VBOWEEKND');
13224 if ($direction == 'next') {
13225 // next weekend from current end date
13226 $next_ts = strtotime("next friday", $to_ts);
13227 } else {
13228 // prev weekend from current start date
13229 $next_ts = strtotime("previous friday", $from_ts);
13230 }
13231 $next_info = getdate($next_ts);
13232 $new_from_ts = $next_ts;
13233 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13234 $rparams['fromdate'] = date($df, $new_from_ts);
13235 $rparams['todate'] = date($df, $new_to_ts);
13236 } elseif ($step == 'week') {
13237 $period_name = JText::translate('VBOWEEK');
13238 if ($direction == 'next') {
13239 // start next week from the current end date
13240 $new_from_ts = $to_ts;
13241 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13242 $rparams['fromdate'] = $rparams['todate'];
13243 $rparams['todate'] = date($df, $new_to_ts);
13244 } else {
13245 // end prev week from the current from date
13246 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13247 $new_to_ts = $from_ts;
13248 $rparams['todate'] = $rparams['fromdate'];
13249 $rparams['fromdate'] = date($df, $new_from_ts);
13250 }
13251 } else {
13252 // month
13253 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13254 if ($direction == 'next') {
13255 // next month from the current from date
13256 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13257 $new_from_ts = $nextmonts;
13258 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13259 $rparams['fromdate'] = date($df, $new_from_ts);
13260 $rparams['todate'] = date($df, $new_to_ts);
13261 } else {
13262 // prev month from the current from date
13263 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13264 $new_from_ts = $nextmonts;
13265 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13266 $rparams['fromdate'] = date($df, $new_from_ts);
13267 $rparams['todate'] = date($df, $new_to_ts);
13268 }
13269 }
13270
13271 // get the next festivities
13272 $fests = VikBooking::getFestivitiesInstance();
13273 $next_fests = $fests->loadFestDates();
13274 if (count($next_fests)) {
13275 // check whether a festivity should be displayed rather than the calculated period of dates
13276 foreach ($next_fests as $fest) {
13277 $fest_found = false;
13278 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13279 $fest_found = true;
13280 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13281 $fest_found = true;
13282 }
13283 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13284 // festivity found before next calculated period
13285 $is_fest = $fest['festinfo'][0]->next_ts;
13286 $period_name = $fest['festinfo'][0]->trans_name;
13287 $new_from_ts = $fest['festinfo'][0]->from_ts;
13288 $new_to_ts = $fest['festinfo'][0]->to_ts;
13289 $rparams['fromdate'] = date($df, $new_from_ts);
13290 $rparams['todate'] = date($df, $new_to_ts);
13291 break;
13292 }
13293 }
13294 }
13295 } else {
13296 // load requested dates by skipping the festivities
13297 $new_from_ts = $from_ts;
13298 $new_to_ts = $to_ts;
13299 }
13300
13301 // invoke report
13302 $report->injectParams($rparams);
13303 $report_values = $report->getReportValues(1);
13304 $report_cols = $report->getColumnsValues();
13305 $report_chart = null;
13306 $report_chart_metas = array();
13307 $chart_meta_data = array(
13308 'keys' => array(
13309 'occupancy',
13310 'tot_bookings',
13311 'nights_booked',
13312 ),
13313 );
13314 $error = null;
13315
13316 if (!count($report_values)) {
13317 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13318 } else {
13319 // get doughnut Chart for the requested key
13320 $report_chart = $report->getChart($chart_datatype);
13321
13322 // get Chart meta data
13323 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13324 if (count($all_chart_metas)) {
13325 // merge all positions into one array
13326 foreach ($all_chart_metas as $pos_metas) {
13327 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13328 }
13329 }
13330
13331 if (empty($period_name)) {
13332 $period_name = $report->getProperty('chartTitle');
13333 }
13334 }
13335
13336 // build response
13337 $response = new stdClass;
13338 $response->error = $error;
13339 $response->fromdate = $rparams['fromdate'];
13340 $response->todate = $rparams['todate'];
13341 $response->in_days = $report->countDaysTo($new_from_ts);
13342 $response->in_days_to = $report->countDaysTo($new_to_ts);
13343 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13344 $response->period_name = $period_name;
13345 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13346 $response->is_fest = $is_fest;
13347 $response->report_chart = $report_chart;
13348 $response->report_cols = $report_cols;
13349 $response->report_values = $report_values;
13350 $response->report_script = $report->getScript();
13351 $response->chart_labels = $report->getProperty('chartJsLabels');
13352 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13353 $response->chart_colors = $report->getProperty('chartJsColors');
13354 $response->chart_data = $report->getProperty('chartJsData');
13355 $response->report_chart_metas = $report_chart_metas;
13356
13357 echo json_encode($response);
13358 exit;
13359 }
13360
13361 /**
13362 * Go to the previous booking.
13363 *
13364 * @uses navigateToBooking()
13365 *
13366 * @since 1.3.0
13367 */
13368 public function prev_booking()
13369 {
13370 $this->navigateToBooking('prev');
13371 }
13372
13373 /**
13374 * Go to the next booking.
13375 *
13376 * @uses navigateToBooking()
13377 *
13378 * @since 1.3.0
13379 */
13380 public function next_booking()
13381 {
13382 $this->navigateToBooking('next');
13383 }
13384
13385 /**
13386 * Given the current booking ID in the request, we navigate
13387 * either to the next or to the previous reservation (if any).
13388 *
13389 * @param string $direction either next or prev.
13390 *
13391 * @return void
13392 *
13393 * @since 1.3.0
13394 */
13395 private function navigateToBooking($direction = 'next')
13396 {
13397 $bid = VikRequest::getInt('whereup', 0, 'request');
13398 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13399 throw new Exception("Invalid request", 400);
13400 }
13401
13402 $dbo = JFactory::getDbo();
13403 $app = JFactory::getApplication();
13404
13405 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13406 $dbo->setQuery($q, 0, 1);
13407 $dbo->execute();
13408 if (!$dbo->getNumRows()) {
13409 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13410 $app->redirect("index.php?option=com_vikbooking&task=orders");
13411 exit;
13412 }
13413
13414 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
13415 exit;
13416 }
13417
13418 /**
13419 * AJAX request: from a list of reservation IDs, we return the ones
13420 * that have a review with the related review ID on VCM.
13421 *
13422 * @since 1.13
13423 */
13424 public function bookings_have_reviews()
13425 {
13426 $dbo = JFactory::getDbo();
13427 $bids = VikRequest::getVar('bids', array(), 'request', 'array');
13428 $vcm_installed = is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php');
13429 $withreviews = array();
13430
13431 if ($vcm_installed && is_array($bids) && count($bids)) {
13432 try {
13433 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
13434 $dbo->setQuery($q);
13435 $dbo->execute();
13436 if ($dbo->getNumRows()) {
13437 $reviews = $dbo->loadAssocList();
13438 foreach ($reviews as $r) {
13439 $withreviews[$r['idorder']] = $r['id'];
13440 }
13441 }
13442 } catch (Exception $e) {
13443 // do nothing, outdated version
13444 }
13445 }
13446
13447 echo json_encode($withreviews);
13448 exit;
13449 }
13450
13451 /**
13452 * AJAX request for adding a new room-day note.
13453 *
13454 * @return void
13455 *
13456 * @since 1.13.5
13457 */
13458 public function add_roomdaynote()
13459 {
13460 $dt = VikRequest::getString('dt', '', 'request');
13461 $idroom = VikRequest::getInt('idroom', 0, 'request');
13462 $subunit = VikRequest::getInt('subunit', 0, 'request');
13463 $type = VikRequest::getString('type', '', 'request');
13464 $type = empty($type) ? 'custom' : $type;
13465 $name = VikRequest::getString('name', '', 'request');
13466 $descr = VikRequest::getString('descr', '', 'request');
13467 $cdays = VikRequest::getInt('cdays', 0, 'request');
13468 $cdays = $cdays < 0 ? 0 : $cdays;
13469 $cdays = $cdays > 365 ? 365 : $cdays;
13470 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
13471 echo 'e4j.error.1';
13472 exit;
13473 }
13474
13475 // reload end date
13476 $end_date = $dt;
13477
13478 // build critical date object
13479 $new_note = array(
13480 'name' => $name,
13481 'type' => $type,
13482 'descr' => $descr,
13483 );
13484
13485 // get object
13486 $notes = VikBooking::getCriticalDatesInstance();
13487
13488 // store the notes for all consecutive dates
13489 for ($i = 0; $i <= $cdays; $i++) {
13490 $store_dt = $dt;
13491 if ($i > 0) {
13492 $dt_info = getdate(strtotime($store_dt));
13493 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
13494 $end_date = $store_dt;
13495 }
13496 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
13497 if (!$result) {
13498 echo 'e4j.error.2';
13499 exit;
13500 }
13501 }
13502
13503 // reload all room day notes for this day for the AJAX response
13504 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
13505
13506 if (!$all_notes || !count($all_notes)) {
13507 // no notes found even after storing it
13508 echo 'e4j.error.3';
13509 exit;
13510 }
13511
13512 echo json_encode($all_notes);
13513 exit;
13514 }
13515
13516 /**
13517 * AJAX request for removing a room day note.
13518 *
13519 * @return void
13520 *
13521 * @since 1.13.5
13522 */
13523 public function remove_roomdaynote()
13524 {
13525 $dt = VikRequest::getString('dt', '', 'request');
13526 $idroom = VikRequest::getInt('idroom', 0, 'request');
13527 $subunit = VikRequest::getInt('subunit', 0, 'request');
13528 $type = VikRequest::getString('type', '', 'request');
13529 $type = empty($type) ? 'custom' : $type;
13530 $ind = VikRequest::getInt('ind', 0, 'request');
13531 if (empty($dt) || !strtotime($dt)) {
13532 echo 'e4j.error.1';
13533 exit;
13534 }
13535
13536 $notes = VikBooking::getCriticalDatesInstance();
13537 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
13538 if (!$result) {
13539 echo 'e4j.error.2';
13540 exit;
13541 }
13542
13543 echo 'e4j.ok';
13544 exit;
13545 }
13546
13547 /**
13548 * AJAX request for storing an event for a booking.
13549 * Firstly developed for the VCM Reporting API - Guest Misconduct,
13550 * but it can be used for any other purpose.
13551 *
13552 * @return void
13553 *
13554 * @since 1.13.5
13555 */
13556 public function store_booking_history_event()
13557 {
13558 $bid = VikRequest::getInt('bid', 0, 'request');
13559 $event = VikRequest::getString('event', '', 'request');
13560 $descr = VikRequest::getString('descr', '', 'request');
13561
13562 if (empty($bid) || empty($event)) {
13563 throw new Exception("Missing required information", 500);
13564 }
13565
13566 // Booking History
13567 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
13568 //
13569
13570 echo 'e4j.ok';
13571 exit;
13572 }
13573
13574 /**
13575 * AJAX request for updating an option/extra service.
13576 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
13577 * but it can be used for any other purpose.
13578 *
13579 * @return void
13580 *
13581 * @since 1.13.5
13582 */
13583 public function update_option_params()
13584 {
13585 $optid = VikRequest::getInt('optid', 0, 'request');
13586 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
13587
13588 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
13589 throw new Exception("Missing required information", 500);
13590 }
13591
13592 $dbo = JFactory::getDbo();
13593 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
13594 $dbo->setQuery($q);
13595 $dbo->execute();
13596 if (!$dbo->getNumRows()) {
13597 throw new Exception("Option not found", 404);
13598 }
13599 $cur_params = $dbo->loadResult();
13600 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
13601 $cur_params = !is_array($cur_params) ? array() : $cur_params;
13602
13603 foreach ($oparams as $k => $v) {
13604 if (empty($k)) {
13605 continue;
13606 }
13607 $cur_params[$k] = $v;
13608 }
13609
13610 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
13611 $dbo->setQuery($q);
13612 $dbo->execute();
13613
13614 echo 'e4j.ok';
13615 exit;
13616 }
13617
13618 /**
13619 * Hidden task to clean up duplicate records in certain database tables
13620 * due to a double execution of the installation queries. Ghost records,
13621 * if any, are also removed to clean up issues with hanging records.
13622 *
13623 * @since November 4th 2020
13624 * @since 1.16.3 (J) - 1.6.3 (WP)
13625 */
13626 public function clean_duplicate_records()
13627 {
13628 $dbo = JFactory::getDbo();
13629
13630 $tables_with_duplicates = [
13631 '#__vikbooking_config' => [
13632 'id_key' => 'id',
13633 'compare_key' => 'param',
13634 ],
13635 '#__vikbooking_countries' => [
13636 'id_key' => 'id',
13637 'compare_key' => 'country_3_code',
13638 ],
13639 '#__vikbooking_custfields' => [
13640 'id_key' => 'id',
13641 'compare_key' => 'name',
13642 ],
13643 '#__vikbooking_texts' => [
13644 'id_key' => 'id',
13645 'compare_key' => 'param',
13646 ],
13647 ];
13648
13649 foreach ($tables_with_duplicates as $tblname => $data) {
13650 $doubles = [];
13651 $storage = [];
13652 $rmlist = [];
13653
13654 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
13655 $dbo->setQuery($q);
13656 $rows = $dbo->loadAssocList();
13657 if (!$rows) {
13658 echo "<p>No records found in table {$tblname}</p>";
13659 continue;
13660 }
13661
13662 foreach ($rows as $row) {
13663 if (!isset($doubles[$row[$data['compare_key']]])) {
13664 $doubles[$row[$data['compare_key']]] = 0;
13665 }
13666 $doubles[$row[$data['compare_key']]]++;
13667 if (!isset($storage[$row[$data['compare_key']]])) {
13668 $storage[$row[$data['compare_key']]] = [];
13669 }
13670 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
13671 }
13672
13673 foreach ($doubles as $paramkey => $paramcount) {
13674 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
13675 continue;
13676 }
13677 $exceeding = $paramcount - 1;
13678 for ($x = 0; $x < $exceeding; $x++) {
13679 array_push($rmlist, $storage[$paramkey][$x]);
13680 }
13681 }
13682
13683 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
13684 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
13685 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
13686
13687 if (count($rmlist)) {
13688 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
13689 $dbo->setQuery($q);
13690 $dbo->execute();
13691 }
13692 }
13693
13694 /**
13695 * Clean up busy records where the busy relations contain empty booking IDs.
13696 */
13697 $hanging_busy_ids = [];
13698
13699 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
13700 $dbo->setQuery($q);
13701 $removelist = $dbo->loadAssocList();
13702 if ($removelist) {
13703 foreach ($removelist as $hanging_busy) {
13704 $hanging_busy_id = (int)$hanging_busy['idbusy'];
13705 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13706 array_push($hanging_busy_ids, $hanging_busy_id);
13707 }
13708 }
13709 }
13710
13711 // let's check also for ghost records that only occupy the room
13712 $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);";
13713 $dbo->setQuery($q);
13714 $removelist = $dbo->loadAssocList();
13715 if ($removelist) {
13716 foreach ($removelist as $hanging_busy) {
13717 $hanging_busy_id = (int)$hanging_busy['id'];
13718 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13719 array_push($hanging_busy_ids, $hanging_busy_id);
13720 }
13721 }
13722 }
13723
13724 if ($hanging_busy_ids) {
13725 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
13726 $dbo->setQuery($q);
13727 $dbo->execute();
13728 }
13729
13730 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
13731
13732 return;
13733 }
13734
13735 /**
13736 * Loads a specific admin widget ID and executes the requested method.
13737 * Useful for loading a newly added widget, or to execute custom methods.
13738 *
13739 * @see this is an AJAX endpoint.
13740 *
13741 * @since 1.14 (J) - 1.4.0 (WP)
13742 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
13743 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
13744 */
13745 public function exec_admin_widget()
13746 {
13747 if (!JSession::checkToken()) {
13748 // missing CSRF-proof token
13749 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13750 }
13751
13752 $widget_id = VikRequest::getString('widget_id', '', 'request');
13753 $call = VikRequest::getString('call', '', 'request');
13754 $return = VikRequest::getInt('return', 0, 'request');
13755 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
13756 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
13757 $multitask = VikRequest::getInt('multitask', 0, 'request');
13758
13759 if (empty($widget_id)) {
13760 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
13761 }
13762
13763 if (empty($call) || !is_string($call)) {
13764 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
13765 }
13766
13767 // invoke admin widgets helper
13768 $widgets_helper = VikBooking::getAdminWidgetsInstance();
13769 $widget = $widgets_helper->getWidget($widget_id);
13770
13771 if ($widget === false) {
13772 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
13773 }
13774
13775 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
13776 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
13777 }
13778
13779 // get the multitask parser object
13780 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
13781
13782 // check if arguments should be passed
13783 $call_args = [];
13784 if ($multitask && $call === 'render') {
13785 // build the multitask data object and inject it to the args as the first index
13786 $call_args[] = $parser->getData();
13787
13788 // bind options within the widget, if any
13789 $widget->bindOptions($call_args[0]);
13790 } else {
13791 // always bind multitask options, if any
13792 $widget->bindOptions($parser->getOptions());
13793 }
13794
13795 try {
13796 if ($return) {
13797 // invoke the widget's method and get the value returned
13798 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
13799 } else {
13800 // invoke the widget's method within a buffer
13801 ob_start();
13802 if ($call_args) {
13803 $res = call_user_func_array([$widget, $call], $call_args);
13804 } else {
13805 $widget->{$call}();
13806 }
13807 $widget_response = ob_get_contents();
13808 ob_end_clean();
13809 }
13810 } catch (Throwable $e) {
13811 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
13812 } catch (Exception $e) {
13813 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
13814 }
13815
13816 // prepare response object with a property equal to the called method
13817 $response = new stdClass;
13818 $response->{$call} = $widget_response;
13819
13820 // output the JSON encoded response and exit
13821 VBOHttpDocument::getInstance()->json($response);
13822 }
13823
13824 /**
13825 * Updates the map of admin widgets.
13826 *
13827 * @throws Exception this is an AJAX endpoint.
13828 *
13829 * @since 1.4.0
13830 */
13831 public function save_admin_widgets()
13832 {
13833 if (!JSession::checkToken()) {
13834 // missing CSRF-proof token
13835 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13836 }
13837
13838 // make sure permissions are sufficient
13839 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
13840 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
13841 }
13842
13843 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
13844 if (!is_array($psections) || !count($psections)) {
13845 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
13846 }
13847
13848 // request values are all converted to arrays, so restore the object styling
13849 $psections = json_decode(json_encode($psections));
13850
13851 // update map
13852 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
13853
13854 $response = new stdClass;
13855 $response->status = (int)$result;
13856
13857 // output the JSON encoded response and exit
13858 VBOHttpDocument::getInstance()->json($response);
13859 }
13860
13861 /**
13862 * Restores the default admin widgets map.
13863 *
13864 * @since 1.4.0
13865 */
13866 public function reset_admin_widgets()
13867 {
13868 // reset map and redirect to dashboard
13869 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
13870
13871 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
13872 exit;
13873 }
13874
13875 /**
13876 * Updates the welcome message status for the widget's customizer via AJAX.
13877 *
13878 * @since 1.4.0
13879 */
13880 public function admin_widgets_welcome()
13881 {
13882 if (!JSession::checkToken()) {
13883 // missing CSRF-proof token
13884 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13885 }
13886
13887 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
13888 // update configuration value
13889 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
13890
13891 $response = new stdClass;
13892 $response->status = $hide_welcome;
13893
13894 // output the JSON encoded response and exit
13895 VBOHttpDocument::getInstance()->json($response);
13896 }
13897
13898 public function newcondtext()
13899 {
13900 VikBookingHelper::printHeader("11");
13901
13902 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13903
13904 parent::display();
13905
13906 if (VikBooking::showFooter()) {
13907 VikBookingHelper::printFooter();
13908 }
13909 }
13910
13911 public function editcondtext()
13912 {
13913 VikBookingHelper::printHeader("11");
13914
13915 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13916
13917 parent::display();
13918
13919 if (VikBooking::showFooter()) {
13920 VikBookingHelper::printFooter();
13921 }
13922 }
13923
13924 public function cancelcondtext()
13925 {
13926 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
13927 }
13928
13929 public function createcondtext()
13930 {
13931 if (!JSession::checkToken()) {
13932 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13933 }
13934 $this->_doCreateCondText();
13935 }
13936
13937 public function createcondtextstay()
13938 {
13939 if (!JSession::checkToken()) {
13940 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13941 }
13942 $this->_doCreateCondText(true);
13943 }
13944
13945 private function _doCreateCondText($stay = false)
13946 {
13947 $dbo = JFactory::getDbo();
13948 $app = JFactory::getApplication();
13949 $rules_helper = VikBooking::getConditionalRulesInstance();
13950 $rules_list = $rules_helper->composeRulesParamsFromRequest();
13951
13952 $condtextname = VikRequest::getString('condtextname', '', 'request');
13953 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
13954 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
13955 $debug = VikRequest::getInt('debug', 0, 'request');
13956 if (empty($condtextname)) {
13957 $condtextname = date('Y-m-dHis');
13958 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
13959 }
13960
13961 $existing_tokens = $rules_helper->getSpecialTags();
13962 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
13963 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
13964 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
13965 exit;
13966 }
13967
13968 $data = new stdClass;
13969 $data->name = $condtextname;
13970 $data->token = $condtexttkn;
13971 $data->rules = json_encode($rules_list);
13972 $data->msg = $msg;
13973 $data->lastupd = JDate::getInstance()->toSql();
13974 $data->debug = $debug;
13975
13976 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
13977
13978 if (isset($data->id)) {
13979 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
13980 }
13981
13982 if (!$stay || !isset($data->id)) {
13983 $this->cancelcondtext();
13984 exit;
13985 }
13986
13987 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
13988 }
13989
13990 public function updatecondtext()
13991 {
13992 if (!JSession::checkToken()) {
13993 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13994 }
13995 $this->_doUpdateCondText();
13996 }
13997
13998 public function updatecondtextstay()
13999 {
14000 if (!JSession::checkToken()) {
14001 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14002 }
14003 $this->_doUpdateCondText(true);
14004 }
14005
14006 private function _doUpdateCondText($stay = false)
14007 {
14008 $dbo = JFactory::getDbo();
14009 $app = JFactory::getApplication();
14010 $rules_helper = VikBooking::getConditionalRulesInstance();
14011 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14012
14013 $pwhere = VikRequest::getInt('where', '', 'request');
14014 $condtextname = VikRequest::getString('condtextname', '', 'request');
14015 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14016 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14017 $debug = VikRequest::getInt('debug', 0, 'request');
14018 if (empty($condtextname)) {
14019 $condtextname = date('Y-m-dHis');
14020 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14021 }
14022
14023 $existing_tokens = $rules_helper->getSpecialTags();
14024 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
14025 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
14026 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
14027 exit;
14028 }
14029
14030 $data = new stdClass;
14031 $data->id = $pwhere;
14032 $data->name = $condtextname;
14033 $data->token = $condtexttkn;
14034 $data->rules = json_encode($rules_list);
14035 $data->msg = $msg;
14036 $data->lastupd = JDate::getInstance()->toSql();
14037 $data->debug = $debug;
14038
14039 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
14040
14041 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14042
14043 if (!$stay) {
14044 $this->cancelcondtext();
14045 exit;
14046 }
14047
14048 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14049 }
14050
14051 public function removecondtext()
14052 {
14053 $dbo = JFactory::getDbo();
14054 $ids = VikRequest::getVar('cid', array());
14055
14056 VikBooking::getConditionalRulesInstance(true);
14057 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14058
14059 foreach ($ids as $d) {
14060 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14061 $dbo->setQuery($q);
14062 $dbo->execute();
14063 if (!$dbo->getNumRows()) {
14064 continue;
14065 }
14066 $special_tag = $dbo->loadResult();
14067
14068 // remove the token from each template file if it was used before
14069 if (!empty($special_tag)) {
14070 // remove token from all template files
14071 foreach ($templates as $tkey => $tpath) {
14072 // get requested file content
14073 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14074 if (empty($fcontent) || !is_string($fcontent)) {
14075 break;
14076 }
14077 // remove tag from code content
14078 $fcontent = str_replace($special_tag, '', $fcontent);
14079 // update the file code
14080 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14081 }
14082 }
14083
14084 // delete the record
14085 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14086 $dbo->setQuery($q);
14087 $dbo->execute();
14088 }
14089
14090 $this->cancelcondtext();
14091 }
14092
14093 /**
14094 * AJAX endpoint to update one template file with the given tag or styles.
14095 * A JSON response will be echoed by exiting the process.
14096 */
14097 public function condtext_update_tmpl()
14098 {
14099 VikBooking::getConditionalRulesInstance(true);
14100
14101 $tagaction = VikRequest::getString('tagaction', '', 'request');
14102 $tag = VikRequest::getString('tag', '', 'request');
14103 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14104 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14105 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14106
14107 $allowed_actions = array(
14108 'add',
14109 'remove',
14110 'styles',
14111 'restore',
14112 );
14113
14114 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14115 throw new Exception("Invalid request submitted", 500);
14116 }
14117
14118 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14119 throw new Exception("Invalid request submitted - missing tag", 500);
14120 }
14121
14122 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14123 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14124 }
14125
14126 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14127 throw new Exception("No custom CSS classes to parse", 500);
14128 }
14129
14130 if ($tagaction == 'restore') {
14131 // immediately restore the requested file to avoid script interruptions
14132 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14133 }
14134
14135 // get requested file content
14136 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14137 if (empty($fcontent) || !is_string($fcontent)) {
14138 throw new Exception("File not found or its code is unreadable", 404);
14139 }
14140
14141 if ($tagaction == 'remove') {
14142 // remove tag from code content
14143 $fcontent = str_replace($tag, '', $fcontent);
14144 } elseif ($tagaction == 'add') {
14145 // add tag to code content in the same exact position
14146 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14147 } elseif ($tagaction == 'styles') {
14148 // apply the same styling rules
14149 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14150 }
14151
14152 // update the file code
14153 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14154
14155 if (!$res) {
14156 throw new Exception("Could not update the source code of the template file", 500);
14157 }
14158
14159 // parse new HTML content
14160 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14161 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14162 throw new Exception("Could not parse new template file content", 404);
14163 }
14164
14165 // trigger backup/mirroring, if available
14166 if (VBOPlatformDetection::isWordPress()) {
14167 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14168 }
14169
14170 // build output
14171 $output = new stdClass;
14172 $output->newhtml = $newhtmls[$file];
14173 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14174
14175 echo json_encode($output);
14176 exit;
14177 }
14178
14179 /**
14180 * AJAX endpoint to invoke methods of the geocoding helper.
14181 */
14182 public function geocoding_endpoint()
14183 {
14184 $geo = VikBooking::getGeocodingInstance();
14185 $callback = VikRequest::getString('callback', '', 'request');
14186
14187 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14188 throw new Exception("Callback not available", 403);
14189 }
14190
14191 // invoke requested method
14192 $res = $geo->{$callback}();
14193
14194 // prepare response
14195 $response = new stdClass;
14196 $response->{$callback} = $res;
14197
14198 echo json_encode($response);
14199 exit;
14200 }
14201
14202 public function refundtn()
14203 {
14204 //modal box, so we do not set menu or footer
14205
14206 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14207
14208 parent::display();
14209 }
14210
14211 public function do_refundtn()
14212 {
14213 $dbo = JFactory::getDbo();
14214 $app = JFactory::getApplication();
14215
14216 $bid = VikRequest::getInt('bid', 0, 'request');
14217 $amount = VikRequest::getFloat('amount', 0, 'request');
14218 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14219 $tmpl = VikRequest::getString('tmpl', '', 'request');
14220 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14221
14222 $currencysymb = VikBooking::getCurrencySymb();
14223
14224 if (empty($bid) || $amount <= 0) {
14225 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14226 $app->redirect('index.php?option=com_vikbooking');
14227 exit;
14228 }
14229
14230 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14231 $dbo->setQuery($q);
14232 $dbo->execute();
14233 if ($dbo->getNumRows() < 1) {
14234 VikError::raiseWarning('', 'Booking not found');
14235 $app->redirect('index.php?option=com_vikbooking');
14236 exit;
14237 }
14238 $row = $dbo->loadAssoc();
14239
14240 // get booking history instance
14241 $history_obj = VikBooking::getBookingHistoryInstance();
14242 $history_obj->setBid($row['id']);
14243
14244 // get payment information
14245 $payment = VikBooking::getPayment($row['idpayment']);
14246 $tn_driver = is_array($payment) ? $payment['file'] : null;
14247
14248 // transaction data validation callback
14249 $tn_data_callback = function($data) use ($tn_driver) {
14250 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14251 };
14252 // get previous transactions
14253 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14254
14255 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14256 // no previous transactions found
14257 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14258 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14259 exit;
14260 }
14261
14262 // push refund information for the payment gateway
14263 $row['total_to_refund'] = $amount;
14264 $row['transaction'] = $prev_tn_data;
14265 $row['refund_reason'] = $refund_reason;
14266
14267 // push the transaction currency information
14268 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14269
14270 /**
14271 * @wponly The payment gateway is loaded
14272 * through the apposite dispatcher.
14273 */
14274 JLoader::import('adapter.payment.dispatcher');
14275 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14276
14277 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14278 // refund not supported
14279 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14280 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14281 exit;
14282 }
14283
14284 // perform the refund transaction
14285 $array_result = $obj->refund();
14286
14287 if ($array_result['verified'] != 1) {
14288 // raise warning by getting the message
14289 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14290 VikError::raiseWarning('', $array_result['log']);
14291 } else {
14292 VikError::raiseWarning('', 'Operation failed');
14293 }
14294 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14295 exit;
14296 }
14297
14298 /**
14299 * New payment plugins can return the total amount refunded ('tot_paid').
14300 *
14301 * @since 1.15.4 (J) - 1.5.10 (WP)
14302 */
14303 if (!empty($array_result['tot_paid'])) {
14304 // overwrite the requested amount with the returned one
14305 $amount = (float)$array_result['tot_paid'];
14306 }
14307
14308 // update total paid, total and refund columns for the booking
14309 $booking = new stdClass;
14310 $booking->id = $row['id'];
14311 if ($row['totpaid'] > 0) {
14312 $booking->totpaid = $row['totpaid'] - $amount;
14313 }
14314 if ($row['total'] > 0) {
14315 $booking->total = $row['total'] - $amount;
14316 }
14317 $booking->refund = (float)$row['refund'] + $amount;
14318 // update record in db
14319 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
14320
14321 // store the refund event
14322 $event_descr = array(
14323 '(' . $payment['name'] . ')',
14324 $refund_reason,
14325 $currencysymb . ' ' . VikBooking::numberFormat($amount),
14326 );
14327 $history_obj->store('RF', implode("\n", $event_descr));
14328
14329 // display success message and redirect
14330 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
14331 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
14332 exit;
14333 }
14334
14335 /**
14336 * AJAX upload endpoint for media files.
14337 *
14338 * @return void
14339 *
14340 * @throws Exception
14341 *
14342 * @since 1.15.0 (J) - 1.5.0 (WP)
14343 */
14344 public function upload_media_file()
14345 {
14346 $input = JFactory::getApplication()->input;
14347
14348 // allowed types
14349 $type = $input->getString('type', '');
14350 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
14351 if ($type == 'image') {
14352 $mask = "/(image\/.+)$/i";
14353 }
14354
14355 // response object
14356 $result = new stdClass;
14357 $result->status = 0;
14358
14359 try
14360 {
14361 // get file from request
14362 $file = $input->files->get('file', array(), 'array');
14363
14364 // try to upload the file
14365 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
14366 $result->status = 1;
14367
14368 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
14369 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
14370 }
14371 catch (Exception $e)
14372 {
14373 $result->error = $e->getMessage();
14374 $result->code = $e->getCode();
14375 }
14376
14377 echo json_encode($result);
14378 exit;
14379 }
14380
14381 /**
14382 * AJAX endpoint to invoke a report object's method.
14383 *
14384 * @return void
14385 *
14386 * @throws Exception
14387 *
14388 * @since 1.15.0 (J) - 1.5.0 (WP)
14389 */
14390 public function invoke_report()
14391 {
14392 $report_name = VikRequest::getString('report', '', 'request');
14393 $report_call = VikRequest::getString('call', '', 'request');
14394 $params = VikRequest::getVar('params', array(), 'request', 'array');
14395
14396 if (empty($report_name)) {
14397 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
14398 }
14399
14400 if (empty($report_call)) {
14401 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
14402 }
14403
14404 // get requested report instance
14405 $report = VikBooking::getReportInstance($report_name);
14406 if (!$report) {
14407 VBOHttpDocument::getInstance()->close(404, 'Report not found');
14408 }
14409
14410 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
14411 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
14412 }
14413
14414 // call on report's method
14415 $result = $report->{$report_call}($params);
14416
14417 if (is_null($result)) {
14418 VBOHttpDocument::getInstance()->close(400, 'Null response');
14419 }
14420
14421 if (is_scalar($result)) {
14422 // wrap result within an array for a JSON encoded response
14423 VBOHttpDocument::getInstance()->json([$result]);
14424 }
14425
14426 // output the JSON encoded array/object returned
14427 VBOHttpDocument::getInstance()->json($result);
14428 }
14429
14430 /**
14431 * Handles requests for the multitask widgets panel.
14432 *
14433 * @see this is an AJAX endpoint.
14434 *
14435 * @since 1.15.0 (J) - 1.5.0 (WP)
14436 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14437 */
14438 public function exec_multitask_widgets()
14439 {
14440 if (!JSession::checkToken()) {
14441 // missing CSRF-proof token
14442 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14443 }
14444
14445 $call = VikRequest::getString('call', '', 'request');
14446 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
14447
14448 if (empty($call)) {
14449 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14450 }
14451
14452 // invoke admin widgets helper
14453 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14454
14455 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
14456 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
14457 }
14458
14459 try {
14460 // invoke the helper's method and get the value returned
14461 if (is_array($call_args) && count($call_args)) {
14462 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
14463 } else {
14464 $result = $widgets_helper->{$call}();
14465 }
14466 } catch (Throwable $e) {
14467 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14468 } catch (Exception $e) {
14469 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14470 }
14471
14472 // prepare response object with a property equal to the called method
14473 $response = new stdClass;
14474 $response->result = $result;
14475
14476 // output the JSON response and exit
14477 VBOHttpDocument::getInstance()->json($response);
14478 }
14479
14480 /**
14481 * Handles requests for displaying a browser notification being dispatched.
14482 *
14483 * @see this is an AJAX endpoint.
14484 *
14485 * @since 1.15.0 (J) - 1.5.0 (WP)
14486 */
14487 public function notification_displayer()
14488 {
14489 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
14490
14491 if (empty($payload_str)) {
14492 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
14493 }
14494
14495 // attempt to decode the notification payload
14496 $payload = json_decode($payload_str);
14497
14498 if (!is_object($payload)) {
14499 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
14500 }
14501
14502 // get notification displayer for this type of notification
14503 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
14504 if (!$displayer) {
14505 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
14506 }
14507
14508 // compose the notification display data object
14509 try {
14510 $notif_data = $displayer->getData();
14511 if (!$notif_data) {
14512 throw new Exception('Error building the notification display data', 500);
14513 }
14514 } catch (Exception $e) {
14515 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14516 }
14517
14518 // output the JSON response and exit
14519 VBOHttpDocument::getInstance()->json($notif_data);
14520 }
14521
14522 /**
14523 * Handles requests for watching widgets data and getting
14524 * new events to trigger browser notifications.
14525 *
14526 * @see this is an AJAX endpoint.
14527 *
14528 * @since 1.15.0 (J) - 1.5.0 (WP)
14529 */
14530 public function widgets_watch_data()
14531 {
14532 if (!JSession::checkToken()) {
14533 // missing CSRF-proof token
14534 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14535 }
14536
14537 $app = JFactory::getApplication();
14538
14539 $watch_data_str = $app->input->get('watch_data', '', 'raw');
14540 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
14541
14542 if (empty($watch_data_str)) {
14543 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
14544 }
14545
14546 // attempt to decode the watch-data payload
14547 $watch_data = json_decode($watch_data_str, true);
14548
14549 if (!$watch_data) {
14550 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
14551 }
14552
14553 // check if any pushed data was set
14554 $pushed_data = (array)json_decode($pushed_data_str, true);
14555
14556 // container for new notifications
14557 $notifs_pool = [];
14558
14559 // get admin widgets helper
14560 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14561
14562 foreach ($watch_data as $widget_id => $data) {
14563 // invoke admin widget (with no pre-loading)
14564 $widget_instance = $widgets_helper->getWidget($widget_id);
14565 if (!$widget_instance) {
14566 continue;
14567 }
14568
14569 // build the widget watch data object
14570 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
14571
14572 // check if the widget needs to emit browser notifications
14573 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
14574
14575 if ($watch_next) {
14576 // update next watch-data object for this widget
14577 $watch_data[$widget_id] = $watch_next;
14578 }
14579
14580 if (is_array($notifications) && $notifications) {
14581 $notifs_pool = array_merge($notifs_pool, $notifications);
14582 }
14583 }
14584
14585 // build the response object
14586 $response = new stdClass;
14587 $response->watch_data = $watch_data;
14588 $response->notifications = $notifs_pool;
14589
14590 // output the JSON response and exit
14591 VBOHttpDocument::getInstance()->json($response);
14592 }
14593
14594 /**
14595 * Outputs a list of CSS assets required to render the admin widgets
14596 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
14597 *
14598 * @see this is an AJAX endpoint.
14599 *
14600 * @since 1.16.0 (J) - 1.6.0 (WP)
14601 */
14602 public function widgets_get_assets()
14603 {
14604 // list of needed CSS asset details
14605 $assets_pool = [];
14606
14607 // appearance preference assets (one or none)
14608 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
14609
14610 if (VBOPlatformDetection::isWordPress()) {
14611 // WordPress (main CSS)
14612 $assets_pool[] = [
14613 'rel' => 'stylesheet',
14614 'id' => 'vbo-style-css',
14615 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14616 'media' => 'all',
14617 ];
14618
14619 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14620 // appearance preference CSS
14621 $assets_pool[] = [
14622 'rel' => 'stylesheet',
14623 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14624 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14625 'media' => 'all',
14626 ];
14627 }
14628 } else {
14629 // Joomla (main CSS)
14630 $assets_pool[] = [
14631 'rel' => 'stylesheet',
14632 'id' => 'vbo-style-css',
14633 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
14634 'media' => 'all',
14635 ];
14636
14637 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14638 // appearance preference CSS
14639 $assets_pool[] = [
14640 'rel' => 'stylesheet',
14641 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14642 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
14643 'media' => 'all',
14644 ];
14645 }
14646 }
14647
14648 // output the JSON response and exit
14649 VBOHttpDocument::getInstance()->json($assets_pool);
14650 }
14651 }
14652