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

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

14,717 lines 560.4 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 value on db
5238 $new_customer->cfields = json_encode($custf_info);
5239 }
5240
5241 // trigger the customer before-update event
5242 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = true);
5243
5244 // update customer record
5245 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5246
5247 // trigger the customer after-save event
5248 $cpin->pluginCustomerSync($new_customer->id, 'update', (array)$new_customer, $before = false);
5249
5250 // update all the bookings affected by this Customer ID as a sales channel
5251 $source_name = 'customer'.$pwhere.'_'.$pchname;
5252 if ($pischannel > 0) {
5253 $oid_clause = '';
5254 if ($customer['ischannel'] < 1) {
5255 //Was not a sales channel but now it is, so update all his bookings
5256 $q = "SELECT `idorder` FROM `#__vikbooking_customers_orders` WHERE `idcustomer`=".$customer['id'].";";
5257 $dbo->setQuery($q);
5258 $dbo->execute();
5259 if ($dbo->getNumRows() > 0) {
5260 $all_bids = $dbo->loadAssocList();
5261 $bids = array();
5262 foreach ($all_bids as $bid) {
5263 if (!in_array($bid['idorder'], $bids)) {
5264 $bids[] = $bid['idorder'];
5265 }
5266 }
5267 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5268 }
5269 }
5270 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5271 } else {
5272 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5273 }
5274 $dbo->setQuery($q);
5275 $dbo->execute();
5276 //
5277 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5278 } else {
5279 //email already exists
5280 $ex_customer = $dbo->loadAssoc();
5281 //check if coming from the Check-in view or not
5282 if (!empty($pcheckin) && !empty($pbid)) {
5283 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5284 /**
5285 * @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
5286 */
5287 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5288 //
5289 exit;
5290 } elseif (!empty($pgoto)) {
5291 // check if coming from a specific task
5292 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5293 $mainframe->redirect(base64_decode($pgoto));
5294 exit;
5295 } else {
5296 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>');
5297 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5298 exit;
5299 }
5300 }
5301 }
5302
5303 //check if coming from the Check-in view
5304 if (!empty($pcheckin) && !empty($pbid)) {
5305 /**
5306 * @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
5307 */
5308 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5309 exit;
5310 }
5311
5312 if ($stay) {
5313 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5314 exit;
5315 }
5316
5317 // check if coming from a specific task
5318 if (!empty($pgoto)) {
5319 $mainframe->redirect(base64_decode($pgoto));
5320 exit;
5321 }
5322
5323 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5324 }
5325
5326 public function savecustomer() {
5327 if (!JSession::checkToken()) {
5328 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5329 }
5330 $dbo = JFactory::getDbo();
5331 $mainframe = JFactory::getApplication();
5332 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5333 $plast_name = VikRequest::getString('last_name', '', 'request');
5334 $pcompany = VikRequest::getString('company', '', 'request');
5335 $pvat = VikRequest::getString('vat', '', 'request');
5336 $pemail = VikRequest::getString('email', '', 'request');
5337 $pphone = VikRequest::getString('phone', '', 'request');
5338 $pcountry = VikRequest::getString('country', '', 'request');
5339 $pstate = VikRequest::getString('state', '', 'request');
5340 $ppin = VikRequest::getString('pin', '', 'request');
5341 $pujid = VikRequest::getInt('ujid', '', 'request');
5342 $paddress = VikRequest::getString('address', '', 'request');
5343 $pcity = VikRequest::getString('city', '', 'request');
5344 $pzip = VikRequest::getString('zip', '', 'request');
5345 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5346 $ppec = VikRequest::getString('pec', '', 'request');
5347 $precipcode = VikRequest::getString('recipcode', '', 'request');
5348 $pgender = VikRequest::getString('gender', '', 'request');
5349 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5350 $pbdate = VikRequest::getString('bdate', '', 'request');
5351 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5352 $pdoctype = VikRequest::getString('doctype', '', 'request');
5353 $pdocnum = VikRequest::getString('docnum', '', 'request');
5354 $pnotes = VikRequest::getString('notes', '', 'request');
5355 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5356 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5357 $pcommission = VikRequest::getFloat('commission', '', 'request');
5358 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5359 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5360 $pchname = VikRequest::getString('chname', '', 'request');
5361 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5362 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5363 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5364 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5365 $pbid = VikRequest::getInt('bid', '', 'request');
5366 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5367 $cpin = VikBooking::getCPinIstance();
5368 /**
5369 * Existing customers are recognized by equal first name, last name and email address.
5370 *
5371 * @since 1.3.0
5372 */
5373 $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;";
5374 $dbo->setQuery($q);
5375 $dbo->execute();
5376 if ($dbo->getNumRows() == 0) {
5377 if (empty($ppin)) {
5378 $ppin = $cpin->generateUniquePin();
5379 } elseif ($cpin->pinExists($ppin)) {
5380 $ppin = $cpin->generateUniquePin();
5381 }
5382 //file upload
5383 jimport('joomla.filesystem.file');
5384 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5385 $gimg = "";
5386 if (isset($pimg) && strlen(trim($pimg['name']))) {
5387 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5388 $src = $pimg['tmp_name'];
5389 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5390 $j = "";
5391 if (file_exists($dest.$filename)) {
5392 $j = rand(171, 1717);
5393 while (file_exists($dest.$j.$filename)) {
5394 $j++;
5395 }
5396 }
5397 $finaldest = $dest.$j.$filename;
5398 $check = getimagesize($pimg['tmp_name']);
5399 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5400 if (VikBooking::uploadFile($src, $finaldest)) {
5401 $gimg = $j.$filename;
5402 } else {
5403 VikError::raiseWarning('', 'Error while uploading image');
5404 }
5405 } else {
5406 VikError::raiseWarning('', 'Uploaded file is not an Image');
5407 }
5408 } elseif (!empty($pscandocimg)) {
5409 $gimg = $pscandocimg;
5410 }
5411 //
5412 $pischannel = $pischannel > 0 ? 1 : 0;
5413 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5414 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5415 $pchname = str_replace(' ', '', trim($pchname));
5416 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5417 $chparams = array(
5418 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5419 'calccmmon' => $pcalccmmon,
5420 'applycmmon' => $papplycmmon,
5421 'chcolor' => $pchcolor,
5422 'chname' => $pchname
5423 );
5424
5425 /**
5426 * Customer profile picture (URL or uploaded file).
5427 *
5428 * @since 1.15.3 (J) - 1.5.5 (WP)
5429 */
5430 $customer_pic = VikRequest::getString('pic', '', 'request');
5431 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5432 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5433 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5434 $src = $customer_pic_img['tmp_name'];
5435 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5436 $j = "";
5437 if (is_file($dest.$filename)) {
5438 $j = rand(1, 99999);
5439 while (is_file($dest . $j .$filename)) {
5440 $j++;
5441 }
5442 }
5443 $finaldest = $dest . $j . $filename;
5444 $check = getimagesize($customer_pic_img['tmp_name']);
5445 if (($check[2] & imagetypes())) {
5446 if (VikBooking::uploadFile($src, $finaldest)) {
5447 $customer_pic = $j . $filename;
5448 } else {
5449 VikError::raiseWarning('', 'Error while uploading image');
5450 }
5451 } else {
5452 VikError::raiseWarning('', 'Uploaded file is not an Image');
5453 }
5454 }
5455
5456 // build customer record
5457 $customer_obj = new stdClass;
5458 $customer_obj->first_name = $pfirst_name;
5459 $customer_obj->last_name = $plast_name;
5460 $customer_obj->email = $pemail;
5461 $customer_obj->phone = $pphone;
5462 $customer_obj->country = $pcountry;
5463 $customer_obj->pin = $ppin;
5464 $customer_obj->ujid = $pujid;
5465 $customer_obj->address = $paddress;
5466 $customer_obj->city = $pcity;
5467 $customer_obj->zip = $pzip;
5468 $customer_obj->state = $pstate;
5469 $customer_obj->doctype = $pdoctype;
5470 $customer_obj->docnum = $pdocnum;
5471 $customer_obj->docimg = $gimg;
5472 $customer_obj->notes = $pnotes;
5473 $customer_obj->ischannel = $pischannel;
5474 $customer_obj->chdata = json_encode($chparams);
5475 $customer_obj->company = $pcompany;
5476 $customer_obj->vat = $pvat;
5477 $customer_obj->gender = $pgender;
5478 $customer_obj->bdate = $pbdate;
5479 $customer_obj->pbirth = $ppbirth;
5480 $customer_obj->fisccode = $pfisccode;
5481 $customer_obj->pec = $ppec;
5482 $customer_obj->recipcode = $precipcode;
5483 $customer_obj->pic = !empty($customer_pic) ? $customer_pic : null;
5484
5485 // trigger the customer before-insert event
5486 $cpin->pluginCustomerSync(0, 'insert', (array)$customer_obj, $before = true);
5487
5488 // insert the new customer record
5489 $dbo->insertObject('#__vikbooking_customers', $customer_obj, 'id');
5490 $lid = isset($customer_obj->id) ? $customer_obj->id : null;
5491
5492 // trigger the customer after-save event
5493 $cpin->pluginCustomerSync($lid, 'insert', (array)$customer_obj, $before = false);
5494
5495 if (!empty($lid)) {
5496 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5497 //check if coming from the Check-in view
5498 if (!empty($pcheckin) && !empty($pbid)) {
5499 $cpin->setNewPin($ppin);
5500 $cpin->setNewCustomerId($lid);
5501 $cpin->saveCustomerBooking($pbid);
5502 /**
5503 * @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
5504 */
5505 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5506 //
5507 exit;
5508 }
5509 // check if coming from a specific task
5510 if (!empty($pgoto) && !empty($pbid)) {
5511 $cpin->setNewPin($ppin);
5512 $cpin->setNewCustomerId($lid);
5513 $cpin->saveCustomerBooking($pbid);
5514 $mainframe->redirect(base64_decode($pgoto));
5515 exit;
5516 }
5517 }
5518 } else {
5519 //email already exists
5520 $ex_customer = $dbo->loadAssoc();
5521 //check if coming from the Check-in view or not
5522 if (!empty($pcheckin) && !empty($pbid)) {
5523 $cpin->setNewPin($ex_customer['pin']);
5524 $cpin->setNewCustomerId($ex_customer['id']);
5525 $cpin->saveCustomerBooking($pbid);
5526 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5527 /**
5528 * @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
5529 */
5530 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5531 //
5532 exit;
5533 } elseif (!empty($pgoto) && !empty($pbid)) {
5534 // check if coming from a specific task
5535 $cpin->setNewPin($ex_customer['pin']);
5536 $cpin->setNewCustomerId($ex_customer['id']);
5537 $cpin->saveCustomerBooking($pbid);
5538 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5539 $mainframe->redirect(base64_decode($pgoto));
5540 exit;
5541 } else {
5542 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>');
5543 }
5544 }
5545 }
5546 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5547 }
5548
5549 public function customers() {
5550 VikBookingHelper::printHeader("22");
5551
5552 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5553
5554 parent::display();
5555
5556 if (VikBooking::showFooter()) {
5557 VikBookingHelper::printFooter();
5558 }
5559 }
5560
5561 public function newcustomer() {
5562 VikBookingHelper::printHeader("22");
5563
5564 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5565
5566 parent::display();
5567
5568 if (VikBooking::showFooter()) {
5569 VikBookingHelper::printFooter();
5570 }
5571 }
5572
5573 public function editcustomer() {
5574 VikBookingHelper::printHeader("22");
5575
5576 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5577
5578 parent::display();
5579
5580 if (VikBooking::showFooter()) {
5581 VikBookingHelper::printFooter();
5582 }
5583 }
5584
5585 public function removecustomers() {
5586 if (!JSession::checkToken()) {
5587 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5588 }
5589 $ids = VikRequest::getVar('cid', array(0));
5590 if (@count($ids)) {
5591 $dbo = JFactory::getDBO();
5592 $cpin = VikBooking::getCPinIstance();
5593 foreach ($ids as $d) {
5594 $cpin->pluginCustomerSync($d, 'delete');
5595 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5596 $dbo->setQuery($q);
5597 $dbo->execute();
5598 }
5599 }
5600 $mainframe = JFactory::getApplication();
5601 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5602 }
5603
5604 public function restrictions() {
5605 VikBookingHelper::printHeader("restrictions");
5606
5607 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5608
5609 parent::display();
5610
5611 if (VikBooking::showFooter()) {
5612 VikBookingHelper::printFooter();
5613 }
5614 }
5615
5616 public function newrestriction() {
5617 VikBookingHelper::printHeader("restrictions");
5618
5619 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5620
5621 parent::display();
5622
5623 if (VikBooking::showFooter()) {
5624 VikBookingHelper::printFooter();
5625 }
5626 }
5627
5628 public function editrestriction() {
5629 VikBookingHelper::printHeader("restrictions");
5630
5631 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5632
5633 parent::display();
5634
5635 if (VikBooking::showFooter()) {
5636 VikBookingHelper::printFooter();
5637 }
5638 }
5639
5640 public function createrestriction() {
5641 if (!JSession::checkToken()) {
5642 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5643 }
5644 $dbo = JFactory::getDBO();
5645 $session = JFactory::getSession();
5646 $mainframe = JFactory::getApplication();
5647 $updforvcm = $session->get('vbVcmRatesUpd', '');
5648 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5649 $pname = VikRequest::getString('name', '', 'request');
5650 $pmonth = VikRequest::getInt('month', '', 'request');
5651 $pmonth = empty($pmonth) ? 0 : $pmonth;
5652 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5653 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5654 $pdto = VikRequest::getString('dto', '', 'request');
5655 $pwday = VikRequest::getString('wday', '', 'request');
5656 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5657 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5658 $pcomboa = VikRequest::getString('comboa', '', 'request');
5659 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5660 $pcombob = VikRequest::getString('combob', '', 'request');
5661 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5662 $pcomboc = VikRequest::getString('comboc', '', 'request');
5663 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5664 $pcombod = VikRequest::getString('combod', '', 'request');
5665 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5666 $combostr = '';
5667 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5668 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5669 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5670 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5671 $pminlos = VikRequest::getInt('minlos', '', 'request');
5672 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5673 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5674 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5675 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5676 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5677 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5678 $pallrooms = $pallrooms == "1" ? 1 : 0;
5679 $pidrooms = VikRequest::getVar('idrooms', array(0));
5680 $ridr = '';
5681 $roomidsforsess = array();
5682 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5683 foreach ($pidrooms as $idr) {
5684 if (empty($idr)) {
5685 continue;
5686 }
5687 $ridr .= '-'.$idr.'-;';
5688 $roomidsforsess[] = (int)$idr;
5689 }
5690 } elseif ($pallrooms > 0) {
5691 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5692 $dbo->setQuery($q);
5693 $dbo->execute();
5694 if ($dbo->getNumRows() > 0) {
5695 $fetchids = $dbo->loadAssocList();
5696 foreach ($fetchids as $fetchid) {
5697 $roomidsforsess[] = (int)$fetchid['id'];
5698 }
5699 }
5700 }
5701 $pcta = VikRequest::getInt('cta', '', 'request');
5702 $pctd = VikRequest::getInt('ctd', '', 'request');
5703 $pctad = VikRequest::getVar('ctad', array());
5704 $pctdd = VikRequest::getVar('ctdd', array());
5705 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5706 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5707 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5708 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5709 // exit;
5710 }
5711
5712 //check if there are restrictions for this month
5713 if ($pmonth > 0) {
5714 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5715 $dbo->setQuery($q);
5716 $dbo->execute();
5717 if ($dbo->getNumRows() > 0) {
5718 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5719 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5720 exit;
5721 }
5722 $pdfrom = 0;
5723 $pdto = 0;
5724 } else {
5725 //dates range
5726 if (empty($pdfrom) || empty($pdto)) {
5727 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5728 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5729 exit;
5730 } else {
5731 $housto = $pdfrom == $pdto ? 23 : 0;
5732 $minsto = $pdfrom == $pdto ? 59 : 0;
5733 $secsto = $pdfrom == $pdto ? 59 : 0;
5734 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5735 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5736 }
5737 if ($pdfrom > $pdto) {
5738 // invalid dates in the past
5739 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5740 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5741 exit;
5742 }
5743 }
5744 //CTA and CTD
5745 $setcta = array();
5746 $setctd = array();
5747 if ($pcta > 0 && count($pctad) > 0) {
5748 foreach ($pctad as $ctwd) {
5749 if (strlen($ctwd)) {
5750 $setcta[] = '-'.(int)$ctwd.'-';
5751 }
5752 }
5753 }
5754 if ($pctd > 0 && count($pctdd) > 0) {
5755 foreach ($pctdd as $ctwd) {
5756 if (strlen($ctwd)) {
5757 $setctd[] = '-'.(int)$ctwd.'-';
5758 }
5759 }
5760 }
5761 //
5762 //update session values
5763 if (!($pdfrom > 0)) {
5764 $attemptyear = (int)date('Y');
5765 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5766 if ($attemptfrom < time()) {
5767 $attemptyear++;
5768 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5769 }
5770 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5771 } else {
5772 $attemptfrom = $pdfrom;
5773 $attemptto = $pdto;
5774 }
5775 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5776 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5777 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5778 } else {
5779 $updforvcm['dfrom'] = $attemptfrom;
5780 }
5781 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5782 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5783 } else {
5784 $updforvcm['dto'] = $attemptto;
5785 }
5786 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5787 foreach ($roomidsforsess as $rid) {
5788 if (!in_array($rid, $updforvcm['rooms'])) {
5789 $updforvcm['rooms'][] = $rid;
5790 }
5791 }
5792 } else {
5793 $updforvcm['rooms'] = $roomidsforsess;
5794 }
5795 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5796 $updforvcm['rplans'] = array();
5797 }
5798 $session->set('vbVcmRatesUpd', $updforvcm);
5799 //
5800 $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").");";
5801 $dbo->setQuery($q);
5802 $dbo->execute();
5803 $lid = $dbo->insertid();
5804 if (!empty($lid)) {
5805 /**
5806 * Repeat restriction on the selected week days until the limit
5807 *
5808 * @since 1.13
5809 */
5810 $prepeat = VikRequest::getInt('repeat', 0, 'request');
5811 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
5812 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
5813 $repeat_intervals = array();
5814 $start = getdate($pdfrom);
5815 $end = getdate($pdto);
5816 $wdays = array();
5817 while ($start[0] <= $end[0]) {
5818 // push requested week day
5819 array_push($wdays, $start['wday']);
5820 // next day
5821 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
5822 }
5823 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
5824 if (count($wdays) < 7 && $dtuntil > $pdto) {
5825 // increment end date for the repeat
5826 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5827 //
5828 $until_info = getdate($dtuntil);
5829 $interval = array();
5830 while ($end[0] <= $until_info[0]) {
5831 if (in_array($end['wday'], $wdays)) {
5832 if (!isset($interval['from'])) {
5833 $interval['from'] = $end[0];
5834 }
5835 $interval['to'] = $end[0];
5836 } else {
5837 if (isset($interval['from'])) {
5838 // append interval
5839 array_push($repeat_intervals, $interval);
5840 // reset interval
5841 $interval = array();
5842 }
5843 }
5844 // next day
5845 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5846 }
5847 if (isset($interval['from'])) {
5848 // append last hanging interval
5849 array_push($repeat_intervals, $interval);
5850 }
5851 if (count($repeat_intervals)) {
5852 // create the repeated records for the calculated intervals
5853 $repeat_count = 2;
5854 foreach ($repeat_intervals as $rp) {
5855 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
5856 // adjust time in case of equal dates (1 single day restriction)
5857 $rpfrom = getdate($rp['from']);
5858 $rpto = getdate($rp['to']);
5859 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
5860 /**
5861 * The end date of the restriction must cover the whole day until 23:59:59.
5862 *
5863 * @since 1.15.4 (J) - 1.5.4 (WP)
5864 */
5865 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
5866 }
5867 // adjust name
5868 $restr_rp_name = $pname . " #{$repeat_count}";
5869 //
5870 $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").");";
5871 $dbo->setQuery($q);
5872 $dbo->execute();
5873 $lid = $dbo->insertid();
5874 if (!empty($lid)) {
5875 $repeat_count++;
5876 }
5877 }
5878 }
5879 }
5880 }
5881 //
5882 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5883 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5884 } else {
5885 VikError::raiseWarning('', 'Error while saving');
5886 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5887 }
5888 }
5889
5890 public function updaterestriction() {
5891 if (!JSession::checkToken()) {
5892 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5893 }
5894 $dbo = JFactory::getDBO();
5895 $session = JFactory::getSession();
5896 $mainframe = JFactory::getApplication();
5897 $updforvcm = $session->get('vbVcmRatesUpd', '');
5898 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5899 $pwhere = VikRequest::getInt('where', '', 'request');
5900 $pname = VikRequest::getString('name', '', 'request');
5901 $pmonth = VikRequest::getInt('month', '', 'request');
5902 $pmonth = empty($pmonth) ? 0 : $pmonth;
5903 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5904 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5905 $pdto = VikRequest::getString('dto', '', 'request');
5906 $pwday = VikRequest::getString('wday', '', 'request');
5907 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5908 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5909 $pcomboa = VikRequest::getString('comboa', '', 'request');
5910 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5911 $pcombob = VikRequest::getString('combob', '', 'request');
5912 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5913 $pcomboc = VikRequest::getString('comboc', '', 'request');
5914 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5915 $pcombod = VikRequest::getString('combod', '', 'request');
5916 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5917 $combostr = '';
5918 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5919 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5920 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5921 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5922 $pminlos = VikRequest::getInt('minlos', '', 'request');
5923 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5924 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5925 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5926 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5927 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5928 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5929 $pallrooms = $pallrooms == "1" ? 1 : 0;
5930 $pidrooms = VikRequest::getVar('idrooms', array(0));
5931 $ridr = '';
5932 $roomidsforsess = array();
5933 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5934 foreach ($pidrooms as $idr) {
5935 if (empty($idr)) {
5936 continue;
5937 }
5938 $ridr .= '-'.$idr.'-;';
5939 $roomidsforsess[] = (int)$idr;
5940 }
5941 } elseif ($pallrooms > 0) {
5942 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5943 $dbo->setQuery($q);
5944 $dbo->execute();
5945 if ($dbo->getNumRows() > 0) {
5946 $fetchids = $dbo->loadAssocList();
5947 foreach ($fetchids as $fetchid) {
5948 $roomidsforsess[] = (int)$fetchid['id'];
5949 }
5950 }
5951 }
5952 $pcta = VikRequest::getInt('cta', '', 'request');
5953 $pctd = VikRequest::getInt('ctd', '', 'request');
5954 $pctad = VikRequest::getVar('ctad', array());
5955 $pctdd = VikRequest::getVar('ctdd', array());
5956 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5957 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5958 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5959 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5960 // exit;
5961 }
5962 //check if there are restrictions for this month
5963 if ($pmonth > 0) {
5964 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
5965 $dbo->setQuery($q);
5966 $dbo->execute();
5967 if ($dbo->getNumRows() > 0) {
5968 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5969 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5970 exit;
5971 }
5972 $pdfrom = 0;
5973 $pdto = 0;
5974 } else {
5975 //dates range
5976 if (empty($pdfrom) || empty($pdto)) {
5977 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5978 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5979 exit;
5980 } else {
5981 $housto = $pdfrom == $pdto ? 23 : 0;
5982 $minsto = $pdfrom == $pdto ? 59 : 0;
5983 $secsto = $pdfrom == $pdto ? 59 : 0;
5984 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5985 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5986 }
5987 if ($pdfrom > $pdto) {
5988 // invalid dates in the past
5989 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5990 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5991 exit;
5992 }
5993 }
5994 //CTA and CTD
5995 $setcta = array();
5996 $setctd = array();
5997 if ($pcta > 0 && count($pctad) > 0) {
5998 foreach ($pctad as $ctwd) {
5999 if (strlen($ctwd)) {
6000 $setcta[] = '-'.(int)$ctwd.'-';
6001 }
6002 }
6003 }
6004 if ($pctd > 0 && count($pctdd) > 0) {
6005 foreach ($pctdd as $ctwd) {
6006 if (strlen($ctwd)) {
6007 $setctd[] = '-'.(int)$ctwd.'-';
6008 }
6009 }
6010 }
6011 //
6012 //update session values
6013 if (!($pdfrom > 0)) {
6014 $attemptyear = (int)date('Y');
6015 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6016 if ($attemptfrom < time()) {
6017 $attemptyear++;
6018 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
6019 }
6020 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
6021 } else {
6022 $attemptfrom = $pdfrom;
6023 $attemptto = $pdto;
6024 }
6025 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
6026 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
6027 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
6028 } else {
6029 $updforvcm['dfrom'] = $attemptfrom;
6030 }
6031 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
6032 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
6033 } else {
6034 $updforvcm['dto'] = $attemptto;
6035 }
6036 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
6037 foreach ($roomidsforsess as $rid) {
6038 if (!in_array($rid, $updforvcm['rooms'])) {
6039 $updforvcm['rooms'][] = $rid;
6040 }
6041 }
6042 } else {
6043 $updforvcm['rooms'] = $roomidsforsess;
6044 }
6045 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6046 $updforvcm['rplans'] = array();
6047 }
6048 $session->set('vbVcmRatesUpd', $updforvcm);
6049 //
6050 $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."';";
6051 $dbo->setQuery($q);
6052 $dbo->execute();
6053 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6054 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6055 }
6056
6057 public function removerestrictions() {
6058 if (!JSession::checkToken()) {
6059 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6060 }
6061 $ids = VikRequest::getVar('cid', array(0));
6062 if (@count($ids)) {
6063 $dbo = JFactory::getDBO();
6064 foreach ($ids as $d) {
6065 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6066 $dbo->setQuery($q);
6067 $dbo->execute();
6068 }
6069 }
6070 $mainframe = JFactory::getApplication();
6071 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6072 }
6073
6074 public function prices() {
6075 VikBookingHelper::printHeader("1");
6076
6077 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6078
6079 parent::display();
6080
6081 if (VikBooking::showFooter()) {
6082 VikBookingHelper::printFooter();
6083 }
6084 }
6085
6086 public function newprice() {
6087 VikBookingHelper::printHeader("1");
6088
6089 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6090
6091 parent::display();
6092
6093 if (VikBooking::showFooter()) {
6094 VikBookingHelper::printFooter();
6095 }
6096 }
6097
6098 public function editprice() {
6099 VikBookingHelper::printHeader("1");
6100
6101 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6102
6103 parent::display();
6104
6105 if (VikBooking::showFooter()) {
6106 VikBookingHelper::printFooter();
6107 }
6108 }
6109
6110 public function createprice() {
6111 if (!JSession::checkToken()) {
6112 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6113 }
6114 $this->do_createprice();
6115 }
6116
6117 public function createprice_new() {
6118 if (!JSession::checkToken()) {
6119 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6120 }
6121 $this->do_createprice(true);
6122 }
6123
6124 private function do_createprice($new = false)
6125 {
6126 $pprice = VikRequest::getString('price', '', 'request');
6127 $pattr = VikRequest::getString('attr', '', 'request');
6128 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6129 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6130 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6131 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6132 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6133 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6134 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6135 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6136 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6137 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6138 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6139 if (!empty($pprice)) {
6140 $dbo = JFactory::getDbo();
6141 $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)) . ");";
6142 $dbo->setQuery($q);
6143 $dbo->execute();
6144 }
6145
6146 $app = JFactory::getApplication();
6147 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6148 $app->close();
6149 }
6150
6151 public function updateprice()
6152 {
6153 if (!JSession::checkToken()) {
6154 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6155 }
6156 $this->do_updateprice();
6157 }
6158
6159 public function updatepricestay()
6160 {
6161 if (!JSession::checkToken()) {
6162 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6163 }
6164 $this->do_updateprice(true);
6165 }
6166
6167 private function do_updateprice($stay = false)
6168 {
6169 $pprice = VikRequest::getString('price', '', 'request');
6170 $pattr = VikRequest::getString('attr', '', 'request');
6171 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6172 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6173 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6174 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6175 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6176 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6177 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6178 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6179 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6180 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6181 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6182 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6183 if (!empty($pprice) && $pwhereup) {
6184 $dbo = JFactory::getDbo();
6185 $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) . ";";
6186 $dbo->setQuery($q);
6187 $dbo->execute();
6188 }
6189
6190 $app = JFactory::getApplication();
6191 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6192 $app->close();
6193 }
6194
6195 public function removeprice() {
6196 if (!JSession::checkToken()) {
6197 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6198 }
6199 $ids = VikRequest::getVar('cid', array(0));
6200 if (@count($ids)) {
6201 $dbo = JFactory::getDBO();
6202 foreach ($ids as $d) {
6203 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6204 $dbo->setQuery($q);
6205 $dbo->execute();
6206 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6207 $dbo->setQuery($q);
6208 $dbo->execute();
6209 }
6210 }
6211 $mainframe = JFactory::getApplication();
6212 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6213 }
6214
6215 public function iva() {
6216 VikBookingHelper::printHeader("2");
6217
6218 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6219
6220 parent::display();
6221
6222 if (VikBooking::showFooter()) {
6223 VikBookingHelper::printFooter();
6224 }
6225 }
6226
6227 public function newiva() {
6228 VikBookingHelper::printHeader("2");
6229
6230 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6231
6232 parent::display();
6233
6234 if (VikBooking::showFooter()) {
6235 VikBookingHelper::printFooter();
6236 }
6237 }
6238
6239 public function editiva() {
6240 VikBookingHelper::printHeader("2");
6241
6242 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6243
6244 parent::display();
6245
6246 if (VikBooking::showFooter()) {
6247 VikBookingHelper::printFooter();
6248 }
6249 }
6250
6251 public function createiva() {
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 if (!empty($paliqperc)) {
6261 $dbo = JFactory::getDBO();
6262 $breakdown_str = '';
6263 if (count($pbreakdown_name) > 0) {
6264 $breakdown_values = array();
6265 $bkcount = 0;
6266 $tot_sub_aliq = 0;
6267 foreach ($pbreakdown_name as $key => $subtax) {
6268 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6269 $breakdown_values[$bkcount]['name'] = $subtax;
6270 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6271 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6272 $bkcount++;
6273 }
6274 }
6275 if (count($breakdown_values) > 0) {
6276 $breakdown_str = json_encode($breakdown_values);
6277 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6278 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6279 }
6280 }
6281 }
6282 $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').");";
6283 $dbo->setQuery($q);
6284 $dbo->execute();
6285 }
6286 $mainframe = JFactory::getApplication();
6287 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6288 }
6289
6290 public function updateiva() {
6291 if (!JSession::checkToken()) {
6292 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6293 }
6294 $paliqname = VikRequest::getString('aliqname', '', 'request');
6295 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6296 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6297 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6298 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6299 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6300 if (!empty($paliqperc)) {
6301 $dbo = JFactory::getDBO();
6302 $breakdown_str = '';
6303 if (count($pbreakdown_name) > 0) {
6304 $breakdown_values = array();
6305 $bkcount = 0;
6306 $tot_sub_aliq = 0;
6307 foreach ($pbreakdown_name as $key => $subtax) {
6308 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6309 $breakdown_values[$bkcount]['name'] = $subtax;
6310 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6311 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6312 $bkcount++;
6313 }
6314 }
6315 if (count($breakdown_values) > 0) {
6316 $breakdown_str = json_encode($breakdown_values);
6317 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6318 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6319 }
6320 }
6321 }
6322 $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).";";
6323 $dbo->setQuery($q);
6324 $dbo->execute();
6325 }
6326 $mainframe = JFactory::getApplication();
6327 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6328 }
6329
6330 public function removeiva() {
6331 if (!JSession::checkToken()) {
6332 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6333 }
6334 $ids = VikRequest::getVar('cid', array(0));
6335 if (@count($ids)) {
6336 $dbo = JFactory::getDBO();
6337 foreach ($ids as $d) {
6338 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6339 $dbo->setQuery($q);
6340 $dbo->execute();
6341 }
6342 }
6343 $mainframe = JFactory::getApplication();
6344 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6345 }
6346
6347 public function categories() {
6348 VikBookingHelper::printHeader("4");
6349
6350 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6351
6352 parent::display();
6353
6354 if (VikBooking::showFooter()) {
6355 VikBookingHelper::printFooter();
6356 }
6357 }
6358
6359 public function newcat() {
6360 VikBookingHelper::printHeader("4");
6361
6362 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6363
6364 parent::display();
6365
6366 if (VikBooking::showFooter()) {
6367 VikBookingHelper::printFooter();
6368 }
6369 }
6370
6371 public function editcat() {
6372 VikBookingHelper::printHeader("4");
6373
6374 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6375
6376 parent::display();
6377
6378 if (VikBooking::showFooter()) {
6379 VikBookingHelper::printFooter();
6380 }
6381 }
6382
6383 public function createcat() {
6384 if (!JSession::checkToken()) {
6385 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6386 }
6387 $pcatname = VikRequest::getString('catname', '', 'request');
6388 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6389 if (!empty($pcatname)) {
6390 $dbo = JFactory::getDBO();
6391 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6392 $dbo->setQuery($q);
6393 $dbo->execute();
6394 }
6395 $mainframe = JFactory::getApplication();
6396 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6397 }
6398
6399 public function updatecat() {
6400 if (!JSession::checkToken()) {
6401 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6402 }
6403 $pcatname = VikRequest::getString('catname', '', 'request');
6404 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6405 $pwhereup = VikRequest::getString('whereup', '', 'request');
6406 if (!empty($pcatname)) {
6407 $dbo = JFactory::getDBO();
6408 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6409 $dbo->setQuery($q);
6410 $dbo->execute();
6411 }
6412 $mainframe = JFactory::getApplication();
6413 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6414 }
6415
6416 public function removecat() {
6417 $ids = VikRequest::getVar('cid', array(0));
6418 if (@count($ids)) {
6419 $dbo = JFactory::getDBO();
6420 foreach ($ids as $d) {
6421 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6422 $dbo->setQuery($q);
6423 $dbo->execute();
6424 }
6425 }
6426 $mainframe = JFactory::getApplication();
6427 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6428 }
6429
6430 public function carat() {
6431 VikBookingHelper::printHeader("5");
6432
6433 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6434
6435 parent::display();
6436
6437 if (VikBooking::showFooter()) {
6438 VikBookingHelper::printFooter();
6439 }
6440 }
6441
6442 public function newcarat() {
6443 VikBookingHelper::printHeader("5");
6444
6445 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6446
6447 parent::display();
6448
6449 if (VikBooking::showFooter()) {
6450 VikBookingHelper::printFooter();
6451 }
6452 }
6453
6454 public function editcarat() {
6455 VikBookingHelper::printHeader("5");
6456
6457 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6458
6459 parent::display();
6460
6461 if (VikBooking::showFooter()) {
6462 VikBookingHelper::printFooter();
6463 }
6464 }
6465
6466 public function createcarat() {
6467 if (!JSession::checkToken()) {
6468 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6469 }
6470 $pcaratname = VikRequest::getString('caratname', '', 'request');
6471 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6472 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6473 $presizeto = VikRequest::getString('resizeto', '', 'request');
6474 $pidrooms = VikRequest::getVar('idrooms', array());
6475 if (!empty($pcaratname)) {
6476 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6477 jimport('joomla.filesystem.file');
6478 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6479 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6480 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6481 if (file_exists($updpath.$safename)) {
6482 $j=1;
6483 while (file_exists($updpath.$j.$safename)) {
6484 $j++;
6485 }
6486 $pwhere=$updpath.$j.$safename;
6487 } else {
6488 $j="";
6489 $pwhere=$updpath.$safename;
6490 }
6491 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6492 @unlink($pwhere);
6493 $picon="";
6494 } else {
6495 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6496 @chmod($pwhere, 0644);
6497 $picon=$j.$safename;
6498 if ($pautoresize=="1" && !empty($presizeto)) {
6499 $eforj = new vikResizer();
6500 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6501 if ($origmod) {
6502 @unlink($pwhere);
6503 $picon='r_'.$j.$safename;
6504 }
6505 }
6506 }
6507 } else {
6508 $picon="";
6509 }
6510 } else {
6511 $picon="";
6512 }
6513 $dbo = JFactory::getDbo();
6514 // get new ordering
6515 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6516 $dbo->setQuery($q);
6517 $dbo->execute();
6518 if ($dbo->getNumRows()) {
6519 $newsortnum = $dbo->loadResult() + 1;
6520 } else {
6521 $newsortnum = 1;
6522 }
6523 $pordering = VikRequest::getInt('ordering', 0, 'request');
6524 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6525 //
6526 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6527 $dbo->setQuery($q);
6528 $dbo->execute();
6529
6530 $new_carat_id = $dbo->insertid();
6531 if (!empty($new_carat_id)) {
6532 // assign/unset carat-rooms relations
6533 $rooms_with_carat = array();
6534 if (count($pidrooms)) {
6535 // assign this new carat to the requested rooms
6536 foreach ($pidrooms as $idroom) {
6537 if (empty($idroom)) {
6538 continue;
6539 }
6540 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6541 $dbo->setQuery($q);
6542 $dbo->execute();
6543 if (!$dbo->getNumRows()) {
6544 continue;
6545 }
6546 $room_data = $dbo->loadAssoc();
6547 array_push($rooms_with_carat, $room_data['id']);
6548 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6549 if (in_array((string)$new_carat_id, $current_carats)) {
6550 continue;
6551 }
6552 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6553 // make sure we do not concatenate a real ID to 0
6554 $current_carats = array();
6555 }
6556 array_push($current_carats, $new_carat_id);
6557 $new_opts = implode(';', $current_carats) . ';';
6558 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6559 $dbo->setQuery($q);
6560 $dbo->execute();
6561 }
6562 }
6563 if (!count($rooms_with_carat)) {
6564 // get all rooms to unset this carat (if previously set)
6565 array_push($rooms_with_carat, '0');
6566 }
6567 // unset the carat from the other rooms that may have it
6568 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6569 $dbo->setQuery($q);
6570 $dbo->execute();
6571 if ($dbo->getNumRows()) {
6572 $unset_rooms_carat = $dbo->loadAssocList();
6573 foreach ($unset_rooms_carat as $room_data) {
6574 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6575 if (!in_array((string)$new_carat_id, $current_carats)) {
6576 // this room is not using this carat
6577 continue;
6578 }
6579 $caratkey = array_search((string)$new_carat_id, $current_carats);
6580 if ($caratkey === false) {
6581 // key not found
6582 continue;
6583 }
6584 // unset this carat ID from the string
6585 unset($current_carats[$caratkey]);
6586 if (!count($current_carats)) {
6587 // a room with no carats assigned will be listed as "0;"
6588 $current_carats = array(0);
6589 }
6590 $new_opts = implode(';', $current_carats) . ';';
6591 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6592 $dbo->setQuery($q);
6593 $dbo->execute();
6594 }
6595 }
6596 //
6597 }
6598 }
6599 $mainframe = JFactory::getApplication();
6600 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6601 }
6602
6603 public function updatecarat() {
6604 if (!JSession::checkToken()) {
6605 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6606 }
6607 $pcaratname = VikRequest::getString('caratname', '', 'request');
6608 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6609 $pwhereup = VikRequest::getString('whereup', '', 'request');
6610 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6611 $presizeto = VikRequest::getString('resizeto', '', 'request');
6612 $pidrooms = VikRequest::getVar('idrooms', array());
6613 $pordering = VikRequest::getInt('ordering', 1, 'request');
6614 if (!empty($pcaratname)) {
6615 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6616 jimport('joomla.filesystem.file');
6617 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6618 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6619 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6620 if (file_exists($updpath.$safename)) {
6621 $j=1;
6622 while (file_exists($updpath.$j.$safename)) {
6623 $j++;
6624 }
6625 $pwhere=$updpath.$j.$safename;
6626 } else {
6627 $j="";
6628 $pwhere=$updpath.$safename;
6629 }
6630 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6631 @unlink($pwhere);
6632 $picon="";
6633 } else {
6634 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6635 @chmod($pwhere, 0644);
6636 $picon=$j.$safename;
6637 if ($pautoresize=="1" && !empty($presizeto)) {
6638 $eforj = new vikResizer();
6639 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6640 if ($origmod) {
6641 @unlink($pwhere);
6642 $picon='r_'.$j.$safename;
6643 }
6644 }
6645 }
6646 } else {
6647 $picon="";
6648 }
6649 } else {
6650 $picon="";
6651 }
6652 $dbo = JFactory::getDbo();
6653 $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).";";
6654 $dbo->setQuery($q);
6655 $dbo->execute();
6656
6657 // assign/unset carat-rooms relations
6658 $rooms_with_carat = array();
6659 if (count($pidrooms)) {
6660 // assign this new carat to the requested rooms
6661 foreach ($pidrooms as $idroom) {
6662 if (empty($idroom)) {
6663 continue;
6664 }
6665 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6666 $dbo->setQuery($q);
6667 $dbo->execute();
6668 if (!$dbo->getNumRows()) {
6669 continue;
6670 }
6671 $room_data = $dbo->loadAssoc();
6672 array_push($rooms_with_carat, $room_data['id']);
6673 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6674 if (in_array((string)$pwhereup, $current_carats)) {
6675 continue;
6676 }
6677 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6678 // make sure we do not concatenate a real ID to 0
6679 $current_carats = array();
6680 }
6681 array_push($current_carats, $pwhereup);
6682 $new_carats = implode(';', $current_carats) . ';';
6683 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6684 $dbo->setQuery($q);
6685 $dbo->execute();
6686 }
6687 }
6688 if (!count($rooms_with_carat)) {
6689 // get all rooms to unset this carat (if previously set)
6690 array_push($rooms_with_carat, '0');
6691 }
6692 // unset the carat from the other rooms that may have it
6693 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6694 $dbo->setQuery($q);
6695 $dbo->execute();
6696 if ($dbo->getNumRows()) {
6697 $unset_rooms_carat = $dbo->loadAssocList();
6698 foreach ($unset_rooms_carat as $room_data) {
6699 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6700 if (!in_array((string)$pwhereup, $current_carats)) {
6701 // this room is not using this carat
6702 continue;
6703 }
6704 $caratkey = array_search((string)$pwhereup, $current_carats);
6705 if ($caratkey === false) {
6706 // key not found
6707 continue;
6708 }
6709 // unset this carat ID from the string
6710 unset($current_carats[$caratkey]);
6711 if (!count($current_carats)) {
6712 // a room with no carats assigned will be listed as "0;"
6713 $current_carats = array(0);
6714 }
6715 $new_carats = implode(';', $current_carats) . ';';
6716 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6717 $dbo->setQuery($q);
6718 $dbo->execute();
6719 }
6720 }
6721 //
6722 }
6723 $mainframe = JFactory::getApplication();
6724 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6725 }
6726
6727 public function removecarat() {
6728 if (!JSession::checkToken()) {
6729 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6730 }
6731 $ids = VikRequest::getVar('cid', array(0));
6732 if (@count($ids)) {
6733 $dbo = JFactory::getDBO();
6734 foreach ($ids as $d) {
6735 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6736 $dbo->setQuery($q);
6737 $dbo->execute();
6738 if ($dbo->getNumRows() == 1) {
6739 $rows = $dbo->loadAssocList();
6740 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
6741 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
6742 }
6743 }
6744 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6745 $dbo->setQuery($q);
6746 $dbo->execute();
6747 }
6748 }
6749 $mainframe = JFactory::getApplication();
6750 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6751 }
6752
6753 public function coupons() {
6754 VikBookingHelper::printHeader("17");
6755
6756 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
6757
6758 parent::display();
6759
6760 if (VikBooking::showFooter()) {
6761 VikBookingHelper::printFooter();
6762 }
6763 }
6764
6765 public function newcoupon() {
6766 VikBookingHelper::printHeader("17");
6767
6768 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6769
6770 parent::display();
6771
6772 if (VikBooking::showFooter()) {
6773 VikBookingHelper::printFooter();
6774 }
6775 }
6776
6777 public function editcoupon() {
6778 VikBookingHelper::printHeader("17");
6779
6780 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6781
6782 parent::display();
6783
6784 if (VikBooking::showFooter()) {
6785 VikBookingHelper::printFooter();
6786 }
6787 }
6788
6789 public function createcoupon()
6790 {
6791 if (!JSession::checkToken()) {
6792 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6793 }
6794 $pcode = VikRequest::getString('code', '', 'request');
6795 $pvalue = VikRequest::getString('value', '', 'request');
6796 $pfrom = VikRequest::getString('from', '', 'request');
6797 $pto = VikRequest::getString('to', '', 'request');
6798 $pidrooms = VikRequest::getVar('idrooms', array(0));
6799 $ptype = VikRequest::getString('type', '', 'request');
6800 $ptype = $ptype == "1" ? 1 : 2;
6801 $ppercentot = VikRequest::getString('percentot', '', 'request');
6802 $ppercentot = $ppercentot == "1" ? 1 : 2;
6803 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6804 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6805 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6806 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6807 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6808 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6809 $pcustomers = VikRequest::getVar('customers', array());
6810 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6811 $stridrooms = "";
6812 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6813 foreach ($pidrooms as $ch) {
6814 if (!empty($ch)) {
6815 $stridrooms .= ";".$ch.";";
6816 }
6817 }
6818 }
6819 $strdatevalid = "";
6820 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6821 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6822 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6823 if ($first < $second) {
6824 $strdatevalid .= $first."-".$second;
6825 }
6826 }
6827
6828 $dbo = JFactory::getDbo();
6829 $app = JFactory::getApplication();
6830
6831 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
6832 $dbo->setQuery($q);
6833 $dbo->execute();
6834 if ($dbo->getNumRows() > 0) {
6835 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6836 } else {
6837 $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) . ");";
6838 $dbo->setQuery($q);
6839 $dbo->execute();
6840
6841 $id_coupon = $dbo->insertid();
6842
6843 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6844
6845 // check if this coupon should be assigned to specific customers
6846 foreach ($pcustomers as $id_customer) {
6847 $customer_coupon = new stdClass;
6848 $customer_coupon->idcustomer = (int)$id_customer;
6849 $customer_coupon->idcoupon = (int)$id_coupon;
6850 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6851
6852 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6853 }
6854 }
6855 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6856 }
6857
6858 public function updatecoupon()
6859 {
6860 if (!JSession::checkToken()) {
6861 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6862 }
6863
6864 $this->do_updatecoupon($stay = false);
6865 }
6866
6867 public function updatecoupon_stay()
6868 {
6869 if (!JSession::checkToken()) {
6870 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6871 }
6872
6873 $this->do_updatecoupon($stay = true);
6874 }
6875
6876 protected function do_updatecoupon($stay = false)
6877 {
6878 if (!JSession::checkToken()) {
6879 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6880 }
6881 $pcode = VikRequest::getString('code', '', 'request');
6882 $pvalue = VikRequest::getString('value', '', 'request');
6883 $pfrom = VikRequest::getString('from', '', 'request');
6884 $pto = VikRequest::getString('to', '', 'request');
6885 $pidrooms = VikRequest::getVar('idrooms', array(0));
6886 $pwhere = VikRequest::getInt('where', 0, 'request');
6887 $ptype = VikRequest::getString('type', '', 'request');
6888 $ptype = $ptype == "1" ? 1 : 2;
6889 $ppercentot = VikRequest::getString('percentot', '', 'request');
6890 $ppercentot = $ppercentot == "1" ? 1 : 2;
6891 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6892 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6893 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6894 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6895 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6896 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6897 $pcustomers = VikRequest::getVar('customers', array());
6898 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6899 $stridrooms = "";
6900 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6901 foreach ($pidrooms as $ch) {
6902 if (!empty($ch)) {
6903 $stridrooms .= ";".$ch.";";
6904 }
6905 }
6906 }
6907 $strdatevalid = "";
6908 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6909 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6910 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6911 if ($first < $second) {
6912 $strdatevalid .= $first."-".$second;
6913 }
6914 }
6915
6916 $dbo = JFactory::getDbo();
6917 $app = JFactory::getApplication();
6918
6919 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
6920 $dbo->setQuery($q);
6921 $dbo->execute();
6922 if ($dbo->getNumRows() > 0) {
6923 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6924 } else {
6925 $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 . ";";
6926 $dbo->setQuery($q);
6927 $dbo->execute();
6928
6929 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6930
6931 // clean up any previously created record with customers
6932 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
6933 $dbo->setQuery($q);
6934 $dbo->execute();
6935
6936 // check if this coupon should be assigned to specific customers
6937 foreach ($pcustomers as $id_customer) {
6938 $customer_coupon = new stdClass;
6939 $customer_coupon->idcustomer = (int)$id_customer;
6940 $customer_coupon->idcoupon = (int)$pwhere;
6941 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6942
6943 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6944 }
6945 }
6946
6947 if ($stay) {
6948 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
6949 } else {
6950 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6951 }
6952 }
6953
6954 public function removecoupons()
6955 {
6956 if (!JSession::checkToken()) {
6957 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6958 }
6959
6960 $dbo = JFactory::getDbo();
6961
6962 $ids = VikRequest::getVar('cid', array(0));
6963
6964 if (count($ids)) {
6965 foreach ($ids as $d) {
6966 // delete coupon record
6967 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
6968 $dbo->setQuery($q);
6969 $dbo->execute();
6970
6971 // clean up any previously created record with customers
6972 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
6973 $dbo->setQuery($q);
6974 $dbo->execute();
6975 }
6976 }
6977
6978 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
6979 }
6980
6981 public function removemoreimgs() {
6982 $mainframe = JFactory::getApplication();
6983 $proomid = VikRequest::getInt('roomid', '', 'request');
6984 $pimgind = VikRequest::getInt('imgind', '', 'request');
6985 if (!strlen($pimgind)) {
6986 $mainframe->redirect("index.php?option=com_vikbooking");
6987 exit;
6988 }
6989 $dbo = JFactory::getDBO();
6990 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
6991 $dbo->setQuery($q);
6992 $dbo->execute();
6993 $row = $dbo->loadAssoc();
6994 $actmore = $row['moreimgs'];
6995 if (!empty($actmore)) {
6996 $actsplit = explode(';;', $actmore);
6997 $captions = json_decode($row['imgcaptions'], true);
6998 $captions = !is_array($captions) ? array() : $captions;
6999 if ($pimgind < 0) {
7000 foreach ($actsplit as $img) {
7001 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
7002 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
7003 }
7004 // reset images and captions
7005 $actsplit = array();
7006 $captions = array();
7007 } else {
7008 if (array_key_exists($pimgind, $actsplit)) {
7009 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
7010 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
7011 // unset current image
7012 unset($actsplit[$pimgind]);
7013 // unset caption if exists
7014 if (isset($captions[$pimgind])) {
7015 unset($captions[$pimgind]);
7016 $captions = array_values($captions);
7017 }
7018 }
7019 }
7020 $newstr = "";
7021 foreach ($actsplit as $oi) {
7022 if (!empty($oi)) {
7023 $newstr .= $oi.';;';
7024 }
7025 }
7026 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
7027 $dbo->setQuery($q);
7028 $dbo->execute();
7029 }
7030 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
7031 }
7032
7033 public function sortfield() {
7034 if (!JSession::checkToken('get')) {
7035 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7036 }
7037 $mainframe = JFactory::getApplication();
7038 $sortid = VikRequest::getVar('cid', array(0));
7039 $pmode = VikRequest::getString('mode', '', 'request');
7040 $dbo = JFactory::getDBO();
7041 if (!empty($pmode)) {
7042 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7043 $dbo->setQuery($q);
7044 $dbo->execute();
7045 $totr=$dbo->getNumRows();
7046 if ($totr > 1) {
7047 $data = $dbo->loadAssocList();
7048 if ($pmode == "up") {
7049 foreach ($data as $v) {
7050 if ($v['id'] == $sortid[0]) {
7051 $y = $v['ordering'];
7052 }
7053 }
7054 if ($y && $y > 1) {
7055 $vik = $y - 1;
7056 $found = false;
7057 foreach ($data as $v) {
7058 if (intval($v['ordering']) == intval($vik)) {
7059 $found=true;
7060 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7061 $dbo->setQuery($q);
7062 $dbo->execute();
7063 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7064 $dbo->setQuery($q);
7065 $dbo->execute();
7066 break;
7067 }
7068 }
7069 if (!$found) {
7070 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7071 $dbo->setQuery($q);
7072 $dbo->execute();
7073 }
7074 }
7075 } elseif ($pmode == "down") {
7076 foreach ($data as $v) {
7077 if ($v['id'] == $sortid[0]) {
7078 $y = $v['ordering'];
7079 }
7080 }
7081 if ($y) {
7082 $vik = $y + 1;
7083 $found = false;
7084 foreach ($data as $v) {
7085 if (intval($v['ordering']) == intval($vik)) {
7086 $found=true;
7087 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7088 $dbo->setQuery($q);
7089 $dbo->execute();
7090 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7091 $dbo->setQuery($q);
7092 $dbo->execute();
7093 break;
7094 }
7095 }
7096 if (!$found) {
7097 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7098 $dbo->setQuery($q);
7099 $dbo->execute();
7100 }
7101 }
7102 }
7103 }
7104 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7105 } else {
7106 $mainframe->redirect("index.php?option=com_vikbooking");
7107 }
7108 }
7109
7110 public function customf() {
7111 VikBookingHelper::printHeader("16");
7112
7113 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7114
7115 parent::display();
7116
7117 if (VikBooking::showFooter()) {
7118 VikBookingHelper::printFooter();
7119 }
7120 }
7121
7122 public function newcustomf() {
7123 VikBookingHelper::printHeader("16");
7124
7125 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7126
7127 parent::display();
7128
7129 if (VikBooking::showFooter()) {
7130 VikBookingHelper::printFooter();
7131 }
7132 }
7133
7134 public function editcustomf() {
7135 VikBookingHelper::printHeader("16");
7136
7137 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7138
7139 parent::display();
7140
7141 if (VikBooking::showFooter()) {
7142 VikBookingHelper::printFooter();
7143 }
7144 }
7145
7146 public function createcustomf() {
7147 if (!JSession::checkToken()) {
7148 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7149 }
7150 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7151 $ptype = VikRequest::getString('type', '', 'request');
7152 $pchoose = VikRequest::getVar('choose', array(0));
7153 $prequired = VikRequest::getString('required', '', 'request');
7154 $prequired = $prequired == "1" ? 1 : 0;
7155 $pflag = VikRequest::getString('flag', '', 'request');
7156 $pisemail = $pflag == 'isemail' ? 1 : 0;
7157 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7158 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7159 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7160 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7161 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7162 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7163 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7164 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7165 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7166 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7167 $fieldflag = '';
7168 if ($pisaddress == 1) {
7169 $fieldflag = 'address';
7170 } elseif ($piscity == 1) {
7171 $fieldflag = 'city';
7172 } elseif ($piszip == 1) {
7173 $fieldflag = 'zip';
7174 } elseif ($piscompany == 1) {
7175 $fieldflag = 'company';
7176 } elseif ($pisvat == 1) {
7177 $fieldflag = 'vat';
7178 } elseif ($pisfisccode == 1) {
7179 $fieldflag = 'fisccode';
7180 } elseif ($pispec == 1) {
7181 $fieldflag = 'pec';
7182 } elseif ($pisrecipcode == 1) {
7183 $fieldflag = 'recipcode';
7184 }
7185 $ppoplink = VikRequest::getString('poplink', '', 'request');
7186 $choosestr = "";
7187 if (is_array($pchoose)) {
7188 foreach ($pchoose as $ch) {
7189 if (!empty($ch)) {
7190 $choosestr .= $ch.";;__;;";
7191 }
7192 }
7193 }
7194 $defvalue = VikRequest::getString('defvalue', '', 'request');
7195
7196 $dbo = JFactory::getDbo();
7197
7198 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7199 $dbo->setQuery($q);
7200 $dbo->execute();
7201 if ($dbo->getNumRows() == 1) {
7202 $getlast = $dbo->loadResult();
7203 $newsortnum = $getlast + 1;
7204 } else {
7205 $newsortnum = 1;
7206 }
7207 $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).");";
7208 $dbo->setQuery($q);
7209 $dbo->execute();
7210 $mainframe = JFactory::getApplication();
7211 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7212 }
7213
7214 public function updatecustomf() {
7215 if (!JSession::checkToken()) {
7216 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7217 }
7218 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7219 $ptype = VikRequest::getString('type', '', 'request');
7220 $pchoose = VikRequest::getVar('choose', array(0));
7221 $prequired = VikRequest::getString('required', '', 'request');
7222 $prequired = $prequired == "1" ? 1 : 0;
7223 $pflag = VikRequest::getString('flag', '', 'request');
7224 $pisemail = $pflag == 'isemail' ? 1 : 0;
7225 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7226 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7227 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7228 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7229 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7230 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7231 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7232 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7233 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7234 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7235 $fieldflag = '';
7236 if ($pisaddress == 1) {
7237 $fieldflag = 'address';
7238 } elseif ($piscity == 1) {
7239 $fieldflag = 'city';
7240 } elseif ($piszip == 1) {
7241 $fieldflag = 'zip';
7242 } elseif ($piscompany == 1) {
7243 $fieldflag = 'company';
7244 } elseif ($pisvat == 1) {
7245 $fieldflag = 'vat';
7246 } elseif ($pisfisccode == 1) {
7247 $fieldflag = 'fisccode';
7248 } elseif ($pispec == 1) {
7249 $fieldflag = 'pec';
7250 } elseif ($pisrecipcode == 1) {
7251 $fieldflag = 'recipcode';
7252 }
7253 $ppoplink = VikRequest::getString('poplink', '', 'request');
7254 $pwhere = VikRequest::getInt('where', '', 'request');
7255 $choosestr = "";
7256 if (is_array($pchoose)) {
7257 foreach ($pchoose as $ch) {
7258 if (!empty($ch)) {
7259 $choosestr .= $ch.";;__;;";
7260 }
7261 }
7262 }
7263 $defvalue = VikRequest::getString('defvalue', '', 'request');
7264
7265 $dbo = JFactory::getDbo();
7266
7267 $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).";";
7268 $dbo->setQuery($q);
7269 $dbo->execute();
7270 $mainframe = JFactory::getApplication();
7271 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7272 }
7273
7274 public function removecustomf() {
7275 if (!JSession::checkToken()) {
7276 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7277 }
7278 $ids = VikRequest::getVar('cid', array(0));
7279 if (@count($ids)) {
7280 $dbo = JFactory::getDBO();
7281 foreach ($ids as $d) {
7282 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7283 $dbo->setQuery($q);
7284 $dbo->execute();
7285 }
7286 }
7287 $mainframe = JFactory::getApplication();
7288 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7289 }
7290
7291 public function overv() {
7292 VikBookingHelper::printHeader("15");
7293
7294 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7295
7296 parent::display();
7297
7298 if (VikBooking::showFooter()) {
7299 VikBookingHelper::printFooter();
7300 }
7301 }
7302
7303 public function translations() {
7304 VikBookingHelper::printHeader("21");
7305
7306 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7307
7308 parent::display();
7309
7310 if (VikBooking::showFooter()) {
7311 VikBookingHelper::printFooter();
7312 }
7313 }
7314
7315 public function savetranslation() {
7316 if (!JSession::checkToken()) {
7317 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7318 }
7319 $this->do_savetranslation();
7320 }
7321
7322 public function savetranslationstay() {
7323 if (!JSession::checkToken()) {
7324 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7325 }
7326 $this->do_savetranslation(true);
7327 }
7328
7329 private function do_savetranslation($stay = false) {
7330 $dbo = JFactory::getDBO();
7331 $mainframe = JFactory::getApplication();
7332 $vbo_tn = VikBooking::getTranslator();
7333 $table = VikRequest::getString('vbo_table', '', 'request');
7334 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7335 $langs = $vbo_tn->getLanguagesList();
7336 $xml_tables = $vbo_tn->getTranslationTables();
7337 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7338 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7339 $tn_saved = 0;
7340 $table_cols = $vbo_tn->getTableColumns($table);
7341 foreach ($langs as $ltag => $lang) {
7342 if ($ltag == $vbo_tn->default_lang) {
7343 continue;
7344 }
7345 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7346 foreach ($tn[$ltag] as $reference_id => $translation) {
7347 $lang_translation = array();
7348 foreach ($table_cols as $field => $fdetails) {
7349 if (!array_key_exists($field, $translation)) {
7350 continue;
7351 }
7352 $ftype = $fdetails['type'];
7353 if ($ftype == 'skip') {
7354 continue;
7355 }
7356
7357 if (is_array($translation[$field])) {
7358 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7359 if (!is_string($tn_field_v)) {
7360 continue;
7361 }
7362 // replace any possible placeholder for special tags
7363 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7364 return $match[2];
7365 }, $translation[$field][$tn_field_k]);
7366 }
7367 } elseif (!empty($translation[$field])) {
7368 // replace any possible placeholder for special tags
7369 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7370 return $match[2];
7371 }, $translation[$field]);
7372 }
7373
7374 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7375 $translation[$field] = json_encode($translation[$field]);
7376 }
7377 $lang_translation[$field] = $translation[$field];
7378 }
7379 if (count($lang_translation) > 0) {
7380 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7381 $dbo->setQuery($q);
7382 $dbo->execute();
7383 if ($dbo->getNumRows() > 0) {
7384 $last_id = $dbo->loadResult();
7385 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7386 } else {
7387 $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)).");";
7388 }
7389 $dbo->setQuery($q);
7390 $dbo->execute();
7391 $tn_saved++;
7392 }
7393 }
7394 }
7395 }
7396 if ($tn_saved > 0) {
7397 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7398 }
7399 } else {
7400 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7401 }
7402 $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);
7403 }
7404
7405 public function choosebusy() {
7406 VikBookingHelper::printHeader("8");
7407
7408 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7409
7410 parent::display();
7411
7412 if (VikBooking::showFooter()) {
7413 VikBookingHelper::printFooter();
7414 }
7415 }
7416
7417 public function orders() {
7418 VikBookingHelper::printHeader("8");
7419
7420 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7421
7422 parent::display();
7423
7424 if (VikBooking::showFooter()) {
7425 VikBookingHelper::printFooter();
7426 }
7427 }
7428
7429 public function vieworders() {
7430 //alias method of orders() for backward compatibility with VCM
7431 $this->orders();
7432 }
7433
7434 public function editorder() {
7435 VikBookingHelper::printHeader("8");
7436
7437 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7438
7439 parent::display();
7440
7441 if (VikBooking::showFooter()) {
7442 VikBookingHelper::printFooter();
7443 }
7444 }
7445
7446 public function removeorders()
7447 {
7448 $dbo = JFactory::getDbo();
7449 $app = JFactory::getApplication();
7450
7451 $ids = VikRequest::getVar('cid', array(0));
7452 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7453
7454 $user = JFactory::getUser();
7455 $config = VBOFactory::getConfig();
7456
7457 $prev_conf_ids = [];
7458 $purged = false;
7459
7460 $tot_cancs = 0;
7461
7462 if (is_array($ids) && count($ids)) {
7463 foreach ($ids as $d) {
7464 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7465 $dbo->setQuery($q, 0, 1);
7466 $row = $dbo->loadAssoc();
7467
7468 // check for any cancellation constraints
7469 $canc_denied = false;
7470 if ($row && class_exists('VCMFeesCancellation')) {
7471 // let VCM detect if there are any constraints for the cancellation
7472 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7473 if ($canc_denied) {
7474 // set error message
7475 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7476 if ($canc_deny_error) {
7477 $app->enqueueMessage($canc_deny_error, 'error');
7478 }
7479 }
7480 }
7481
7482 if ($row && !$canc_denied) {
7483 // increase counter
7484 $tot_cancs++;
7485
7486 // set status to cancelled
7487 if ($row['status'] != 'cancelled') {
7488 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7489 $dbo->setQuery($q);
7490 $dbo->execute();
7491 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7492 $dbo->setQuery($q);
7493 $dbo->execute();
7494 if ($row['status'] == 'confirmed') {
7495 $prev_conf_ids[] = $row['id'];
7496 }
7497 // Booking History
7498 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7499 }
7500
7501 // free records up
7502 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7503 $dbo->setQuery($q);
7504 $ordbusy = $dbo->loadAssocList();
7505 if ($ordbusy) {
7506 foreach ($ordbusy as $ob) {
7507 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7508 $dbo->setQuery($q);
7509 $dbo->execute();
7510 }
7511 }
7512
7513 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7514 $dbo->setQuery($q);
7515 $dbo->execute();
7516
7517 // check for purge removal
7518 if ($row['status'] == 'cancelled') {
7519 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7520 $dbo->setQuery($q);
7521 $dbo->execute();
7522 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7523 $dbo->setQuery($q);
7524 $dbo->execute();
7525 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7526 $dbo->setQuery($q);
7527 $dbo->execute();
7528 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7529 $dbo->setQuery($q);
7530 $dbo->execute();
7531 // in case of split stay booking, remove the transient
7532 if ($row['split_stay']) {
7533 $config->remove('split_stay_' . $row['id']);
7534 }
7535 // turn flag on
7536 $purged = true;
7537 }
7538 }
7539 }
7540
7541 if ($tot_cancs) {
7542 // enqueue system message
7543 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7544 }
7545 }
7546
7547 if ($prev_conf_ids) {
7548 $prev_conf_ids_str = '';
7549 foreach ($prev_conf_ids as $prev_id) {
7550 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7551 }
7552 //Invoke Channel Manager
7553 $vcm_autosync = VikBooking::vcmAutoUpdate();
7554 if ($vcm_autosync > 0) {
7555 $vcm_obj = VikBooking::getVcmInvoker();
7556 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7557 $sync_result = $vcm_obj->doSync();
7558 if ($sync_result === false) {
7559 $vcm_err = $vcm_obj->getError();
7560 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7561 }
7562 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7563 $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');
7564 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7565 }
7566 //
7567 }
7568
7569 if (!empty($pgoto)) {
7570 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7571 if ($purged) {
7572 // go back to the bookings list page
7573 $app->redirect("index.php?option=com_vikbooking&task=orders");
7574 } else {
7575 // go back to the booking details page
7576 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7577 }
7578 exit;
7579 }
7580 // we expect the goto URL to be base64 encoded
7581 $app->redirect(base64_decode($pgoto));
7582 exit;
7583 }
7584
7585 // go back to the bookings list page
7586 $app->redirect("index.php?option=com_vikbooking&task=orders");
7587 }
7588
7589 public function config() {
7590 VikBookingHelper::printHeader("11");
7591
7592 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7593
7594 parent::display();
7595
7596 if (VikBooking::showFooter()) {
7597 VikBookingHelper::printFooter();
7598 }
7599 }
7600
7601 public function saveconfig()
7602 {
7603 if (!JSession::checkToken()) {
7604 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7605 }
7606
7607 $dbo = JFactory::getDbo();
7608 $app = JFactory::getApplication();
7609
7610 $config = VBOFactory::getConfig();
7611
7612 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7613 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7614 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
7615 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
7616 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
7617 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
7618 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
7619 $pdateformat = VikRequest::getString('dateformat', '', 'request');
7620 $pdatesep = VikRequest::getString('datesep', '', 'request');
7621 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
7622 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
7623 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
7624 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
7625 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
7626 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
7627 $ptokenform = VikRequest::getString('tokenform', '', 'request');
7628 $padminemail = VikRequest::getString('adminemail', '', 'request');
7629 $psenderemail = VikRequest::getString('senderemail', '', 'request');
7630 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
7631 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
7632 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
7633 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
7634 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
7635 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
7636 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
7637 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
7638 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
7639 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
7640 $pusefa = VikRequest::getInt('usefa', '', 'request');
7641 $pusefa = $pusefa > 0 ? 1 : 0;
7642 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
7643 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
7644 $pcalendar = VikRequest::getString('calendar', '', 'request');
7645 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
7646 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
7647 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
7648 $penablepin = VikRequest::getString('enablepin', '', 'request');
7649 $penablepin = $penablepin == "1" ? 1 : 0;
7650 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
7651 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
7652 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
7653 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
7654 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
7655 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
7656 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
7657 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
7658 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
7659 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
7660 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
7661 $pnumadultsfrom = '1';
7662 $pnumadultsto = '10';
7663 }
7664 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
7665 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
7666 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
7667 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
7668 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
7669 $pnumadultsfrom = '1';
7670 $pnumadultsto = '4';
7671 }
7672 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
7673 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
7674 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
7675 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
7676 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
7677 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
7678 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
7679 $pcronkey = VikRequest::getString('cronkey', '', 'request');
7680 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
7681 $pcdsto = VikRequest::getVar('cdsto', array());
7682 $closing_dates = array();
7683 if (count($pcdsfrom)) {
7684 foreach ($pcdsfrom as $kcd => $vcdfrom) {
7685 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
7686 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
7687 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
7688 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
7689 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
7690 if (!in_array($cdval, $closing_dates)) {
7691 $closing_dates[] = $cdval;
7692 }
7693 }
7694 }
7695 }
7696 }
7697 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
7698 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
7699 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
7700 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7701 if ($pvbosef === 1) {
7702 if (!$vbosef) {
7703 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7704 }
7705 } else {
7706 if ($vbosef) {
7707 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
7708 }
7709 }
7710 $pmultilang = VikRequest::getString('multilang', '', 'request');
7711 $pmultilang = $pmultilang == "1" ? 1 : 0;
7712 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
7713 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
7714 /**
7715 * Chat params and configuration settings
7716 *
7717 * @since 1.12
7718 */
7719 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
7720 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
7721 $config->set('chatenabled', $pchatenabled);
7722
7723 // chat params
7724 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
7725 $chat_res_status = array();
7726 foreach ($pchat_res_status as $chatrs) {
7727 if (!empty($chatrs)) {
7728 array_push($chat_res_status, $chatrs);
7729 }
7730 }
7731 $chatparams = new stdClass;
7732 $chatparams->res_status = $chat_res_status;
7733 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
7734 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
7735
7736 $config->set('chatparams', $chatparams);
7737 }
7738
7739 /**
7740 * Pre check-in configuration settings
7741 *
7742 * @since 1.12
7743 */
7744 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
7745 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
7746
7747 $config->set('precheckinenabled', $pprecheckinenabled);
7748 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
7749
7750 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
7751 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
7752 $config->set('upselling', $pupsellingenabled);
7753
7754 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
7755 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
7756 $config->set('orphanscalculation', $porphanscal);
7757
7758 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
7759 $config->set('searchrestmpl', $psrcrtpl);
7760
7761 /**
7762 * Guest Reviews settings
7763 *
7764 * @since 1.13
7765 */
7766 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
7767 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
7768 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
7769 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
7770 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
7771 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
7772 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
7773 $config->set('grenabled', $pgrenabled);
7774 $config->set('grminchars', $pgrminchars);
7775 $config->set('grappr', $pgrappr);
7776 $config->set('grtype', $pgrtype);
7777 try {
7778 // always truncate service names (this query may require special permissions)
7779 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
7780 $dbo->setQuery($q);
7781 $dbo->execute();
7782 } catch (Exception $e) {
7783 // do nothing
7784 }
7785 foreach ($pgrsrv as $srvname) {
7786 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
7787 $dbo->setQuery($q);
7788 $dbo->execute();
7789 }
7790
7791 /**
7792 * Preferred countries ordering, or custom countries.
7793 *
7794 * @since 1.14 (J) - 1.3.11 (WP)
7795 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
7796 */
7797 $pref_countries = VikRequest::getVar('pref_countries', array());
7798 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
7799 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
7800 if (!empty($cust_pref_countries)) {
7801 $all_custom_prefcountries = array();
7802 $cust_pref_countries = explode(',', $cust_pref_countries);
7803 foreach ($cust_pref_countries as $cust_pref_country) {
7804 $cust_pref_country = trim(strtolower($cust_pref_country));
7805 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
7806 continue;
7807 }
7808 array_push($all_custom_prefcountries, $cust_pref_country);
7809 }
7810 if (count($all_custom_prefcountries)) {
7811 $pref_countries = $all_custom_prefcountries;
7812 }
7813 }
7814 $config->set('preferred_countries', $pref_countries);
7815 //
7816
7817 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
7818 $config->set('gmapskey', $gmapskey);
7819
7820 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
7821 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
7822 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
7823 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
7824 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
7825 $pref_colors = array(
7826 'textcolor' => $pref_textcolor,
7827 'bgcolor' => $pref_bgcolor,
7828 'fontcolor' => $pref_fontcolor,
7829 'bgcolorhov' => $pref_bgcolorhov,
7830 'fontcolorhov' => $pref_fontcolorhov,
7831 );
7832 $config->set('pref_colors', $pref_colors);
7833
7834 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
7835 $config->set('interactive_map', $interactive_map);
7836
7837 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
7838 $config->set('noemptydecimals', $noemptydecimals);
7839
7840 /**
7841 * Appearance preferences (light, auto, dark mode).
7842 *
7843 * @since 1.15.0 (J) - 1.5.0 (WP)
7844 */
7845 $appearance_pref = VikRequest::getString('appearance_pref', '');
7846 $config->set('appearance_pref', $appearance_pref);
7847
7848 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
7849 $picon = "";
7850 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
7851 jimport('joomla.filesystem.file');
7852 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
7853 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
7854 if (file_exists($res_backend_path.$safename)) {
7855 $j = 1;
7856 while (file_exists($res_backend_path.$j.$safename)) {
7857 $j++;
7858 }
7859 $pwhere = $res_backend_path.$j.$safename;
7860 } else {
7861 $j = "";
7862 $pwhere = $res_backend_path.$safename;
7863 }
7864 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7865 @unlink($pwhere);
7866 $picon = "";
7867 } else {
7868 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
7869 @chmod($pwhere, 0644);
7870 $picon = $j.$safename;
7871 }
7872 }
7873 if (!empty($picon)) {
7874 $config->set('sitelogo', $picon);
7875 }
7876 }
7877 $pbackicon = "";
7878 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
7879 jimport('joomla.filesystem.file');
7880 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
7881 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
7882 if (file_exists($res_backend_path.$safename)) {
7883 $j = 1;
7884 while (file_exists($res_backend_path.$j.$safename)) {
7885 $j++;
7886 }
7887 $pwhere = $res_backend_path.$j.$safename;
7888 } else {
7889 $j = "";
7890 $pwhere = $res_backend_path.$safename;
7891 }
7892 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7893 @unlink($pwhere);
7894 $pbackicon = "";
7895 } else {
7896 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
7897 @chmod($pwhere, 0644);
7898 $pbackicon = $j.$safename;
7899 }
7900 }
7901 if (!empty($pbackicon)) {
7902 $config->set('backlogo', $pbackicon);
7903 }
7904 }
7905 $config->set('vcmautoupd', $pvcmautoupd);
7906 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
7907 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
7908 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
7909 $config->set('searchsuggestions', $psearchsuggestions);
7910 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
7911 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
7912
7913 // translatable text
7914 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
7915 $dbo->setQuery($q);
7916 $dbo->execute();
7917
7918 // translatable text
7919 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
7920 $dbo->setQuery($q);
7921 $dbo->execute();
7922
7923 // translatable text
7924 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
7925 $dbo->setQuery($q);
7926 $dbo->execute();
7927
7928 // terms and conditions
7929 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
7930 $dbo->setQuery($q);
7931 $dbo->execute();
7932 if ($dbo->getNumRows() > 0) {
7933 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
7934 $dbo->setQuery($q);
7935 $dbo->execute();
7936 } else {
7937 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
7938 $dbo->setQuery($q);
7939 $dbo->execute();
7940 }
7941
7942 $config->set('adminemail', $padminemail);
7943 $config->set('senderemail', $psenderemail);
7944 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
7945 $config->set('datesep', $pdatesep);
7946 $config->set('resmodcanc', $presmodcanc);
7947 $config->set('resmodcancmin', $presmodcancmin);
7948 $config->set('minuteslock', $pminuteslock);
7949 $config->set('minautoremove', $pminautoremove);
7950
7951 $openingh = $ptimeopenstorefh * 3600;
7952 $openingm = $ptimeopenstorefm * 60;
7953 $openingts = $openingh + $openingm;
7954 $closingh = $ptimeopenstoreth * 3600;
7955 $closingm = $ptimeopenstoretm * 60;
7956 $closingts = $closingh + $closingm;
7957 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
7958 $prevtimes = $config->get('timeopenstore', '');
7959 if ($prevtimes != $openingts . "-" . $closingts) {
7960 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
7961 $dbo->setQuery($q);
7962 $dbo->execute();
7963 if ($dbo->getNumRows() > 0) {
7964 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
7965 /**
7966 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
7967 * for all reservations to avoid issues with the availability.
7968 *
7969 * @since August 29th 2018
7970 */
7971 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>');
7972 //
7973 }
7974 }
7975 $config->set('timeopenstore', $openingts . "-" . $closingts);
7976
7977 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
7978 $phoursmorebookingback = "0";
7979 if ($closingts > $openingts) {
7980 $diffcheck = ($closingts - $openingts) / 3600;
7981 $phoursmorebookingback = ceil($diffcheck);
7982 }
7983 $config->set('hoursmorebookingback', $phoursmorebookingback);
7984 $config->set('hoursmoreroomavail', '0');
7985 $config->set('multilang', $pmultilang);
7986 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
7987 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
7988 $config->set('todaybookings', $ptodaybookings);
7989 $config->set('bootstrap', $ploadbootstrap);
7990 $config->set('usefa', $pusefa);
7991 $config->set('loadjquery', $ploadjquery);
7992 $config->set('calendar', $pcalendar);
7993 $config->set('enablecoupons', $penablecoupons);
7994 $config->set('enablepin', $penablepin);
7995 $config->set('mindaysadvance', $pmindaysadvance);
7996 $config->set('autodefcalnights', $pautodefcalnights);
7997 $config->set('numrooms', $pnumrooms);
7998 $config->set('numadults', $confnumadults);
7999 $config->set('numchildren', $confnumchildren);
8000 $config->set('closingdates', $closing_dates);
8001 $config->set('smartsearch', $psmartsearch);
8002 $config->set('maxdate', $maxdate_str);
8003 $config->set('cronkey', $pcronkey);
8004
8005 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
8006 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
8007 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
8008 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
8009 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
8010 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
8011 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
8012 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
8013 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
8014 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
8015 $pnumdecimals = intval($pnumdecimals);
8016 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
8017 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
8018 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
8019 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
8020 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
8021 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
8022 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
8023 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
8024 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
8025 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
8026 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
8027 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
8028 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
8029 $pbctagname = VikRequest::getVar('bctagname', array());
8030 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
8031 $pbctagrule = VikRequest::getVar('bctagrule', array());
8032 $bctags_arr = array();
8033 $bctags_rules = array();
8034 if (count($pbctagname) > 0) {
8035 foreach ($pbctagname as $bctk => $bctv) {
8036 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
8037 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
8038 $bctags_rules[] = $pbctagrule[$bctk];
8039 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8040 }
8041 }
8042 }
8043 }
8044 //theme
8045 $ptheme = VikRequest::getString('theme', '', 'request');
8046 if (empty($ptheme) || $ptheme == 'default') {
8047 $ptheme = 'default';
8048 } else {
8049 $validtheme = false;
8050 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8051 if (count($themes) > 0) {
8052 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8053 foreach ($themes as $th) {
8054 if (is_dir($th)) {
8055 $tname = str_replace($strip, '', $th);
8056 if ($tname == $ptheme) {
8057 $validtheme = true;
8058 break;
8059 }
8060 }
8061 }
8062 }
8063 if ($validtheme == false) {
8064 $ptheme = 'default';
8065 }
8066 }
8067 $config->set('theme', $ptheme);
8068 //
8069 $config->set('showpartlyreserved', $pshowpartlyreserved);
8070 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8071 $config->set('numcalendars', $pnumcalendars);
8072
8073 // record may not be set
8074 $config->set('thumbsize', $pthumbsize);
8075
8076 $config->set('firstwday', $pfirstwday);
8077
8078 // translatable text
8079 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8080 $dbo->setQuery($q);
8081 $dbo->execute();
8082
8083 $config->set('fronttitletag', $pfronttitletag);
8084 $config->set('fronttitletagclass', $pfronttitletagclass);
8085 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8086
8087 // translatable texts
8088 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8089 $dbo->setQuery($q);
8090 $dbo->execute();
8091 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8092 $dbo->setQuery($q);
8093 $dbo->execute();
8094
8095 $config->set('currencyname', $pcurrencyname);
8096 $config->set('currencysymb', $pcurrencysymb);
8097 $config->set('currencycodepp', $pcurrencycodepp);
8098 $config->set('numberformat', $numberformatstr);
8099 // bookings color tags
8100 $config->set('bookingsctags', $bctags_arr);
8101
8102 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8103 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8104 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8105 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8106 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8107 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8108 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8109 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8110 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8111 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8112 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8113 $pmultipay = VikRequest::getString('multipay', '', 'request');
8114 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8115 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8116 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8117 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8118 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8119
8120 // translatable text
8121 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8122 $dbo->setQuery($q);
8123 $dbo->execute();
8124 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8125 $dbo->setQuery($q);
8126 $dbo->execute();
8127
8128 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8129 $config->set('taxsummary', $ptaxsummary);
8130 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8131
8132 $config->set('ccpaypal', $pccpaypal);
8133 $config->set('payaccpercent', $ppayaccpercent);
8134 $config->set('typedeposit', $ptypedeposit);
8135 $config->set('depoverrides', $pdepoverrides);
8136 $config->set('multipay', $pmultipay);
8137 $config->set('depifdaysadv', $pdepifdaysadv);
8138 $config->set('nodepnonrefund', $pnodepnonrefund);
8139 $config->set('depcustchoice', $pdepcustchoice);
8140
8141 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8142 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8143 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8144 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8145 $config->set('emailsendwhen', $psendemailwhen);
8146 $config->set('attachical', $pattachical);
8147
8148 // SMS APIs
8149 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8150 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8151 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8152 $psmssendto = VikRequest::getVar('smssendto', array());
8153 $sms_sendto = array();
8154 foreach ($psmssendto as $sto) {
8155 if (in_array($sto, array('admin', 'customer'))) {
8156 $sms_sendto[] = $sto;
8157 }
8158 }
8159 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8160 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8161 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8162 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8163 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8164 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8165 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8166 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8167 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8168 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8169 $smsparamarr = array();
8170 if (count($viksmsparams) > 0) {
8171 foreach ($viksmsparams as $setting => $cont) {
8172 if (strlen($setting) > 0) {
8173 $smsparamarr[$setting] = $cont;
8174 }
8175 }
8176 }
8177 $config->set('smsapi', $psmsapi);
8178 $config->set('smsautosend', $psmsautosend);
8179 $config->set('smssendto', $sms_sendto);
8180 $config->set('smssendwhen', $psmssendwhen);
8181 $config->set('smsadminphone', $psmsadminphone);
8182 $config->set('smsparams', $smsparamarr);
8183
8184 // translatable texts
8185 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8186 $dbo->setQuery($q);
8187 $dbo->execute();
8188 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8189 $dbo->setQuery($q);
8190 $dbo->execute();
8191 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8192 $dbo->setQuery($q);
8193 $dbo->execute();
8194 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8195 $dbo->setQuery($q);
8196 $dbo->execute();
8197 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8198 $dbo->setQuery($q);
8199 $dbo->execute();
8200 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8201 $dbo->setQuery($q);
8202 $dbo->execute();
8203
8204 /**
8205 * Backup settings
8206 *
8207 * @since 1.15.0 (J) - 1.5.0 (WP)
8208 */
8209 $backup_type = $app->input->getString('backuptype', 'full');
8210 $backup_folder = $app->input->getString('backupfolder', '');
8211
8212 $tmp = $app->get('tmp_path');
8213
8214 if (!$backup_folder)
8215 {
8216 // path not specified, use temporary folder
8217 $backup_folder = $tmp;
8218 }
8219
8220 $current = $config->get('backupfolder');
8221
8222 if (!$current)
8223 {
8224 // path was missing, use temporary folder
8225 $current = $tmp;
8226 }
8227
8228 // check whether the backup folder has been moved
8229 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8230 {
8231 $backupModel = new VBOModelBackup();
8232
8233 // backup folder moved, try to copy all the existing overrides
8234 if (!$backupModel->moveArchives($backup_folder))
8235 {
8236 // iterate all errors and display them
8237 foreach ($backupModel->getErrors() as $error)
8238 {
8239 $app->enqueueMessage($error, 'warning');
8240 }
8241 }
8242 }
8243
8244 // save configuration
8245 $config->set('backuptype', $backup_type);
8246 $config->set('backupfolder', $backup_folder);
8247
8248 /**
8249 * Check-in data collection type.
8250 *
8251 * @since 1.15.0 (J) - 1.5.0 (WP)
8252 */
8253 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8254
8255 /**
8256 * Front-end appearance.
8257 *
8258 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8259 */
8260 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8261
8262 /**
8263 * Split stays.
8264 *
8265 * @since 1.16.0 (J) - 1.6.0 (WP)
8266 */
8267 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8268 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8269 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8270 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8271
8272 /**
8273 * Re-build Web App manifest file to let the event trigger.
8274 *
8275 * @since 1.16.5 (J) - 1.6.5 (WP)
8276 */
8277 try {
8278 VBOWebappManifest::build();
8279 } catch (Exception $e) {
8280 // do nothing
8281 }
8282
8283 // redirect
8284 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8285 $app->redirect('index.php?option=com_vikbooking&task=config');
8286 $app->close();
8287 }
8288
8289 /**
8290 * Task to unify the check-in and check-out times for all reservations.
8291 */
8292 public function unifycheckinout()
8293 {
8294 $dbo = JFactory::getDbo();
8295 $app = JFactory::getApplication();
8296 $user = JFactory::getUser();
8297
8298 $fh = VikRequest::getInt('fh', 12, 'request');
8299 $fm = VikRequest::getInt('fm', 0, 'request');
8300 $th = VikRequest::getInt('th', 10, 'request');
8301 $tm = VikRequest::getInt('tm', 0, 'request');
8302
8303 $now = time();
8304 $totmod = 0;
8305 $totbookmod = 0;
8306
8307 // query all busy records
8308 $q = $dbo->getQuery(true)
8309 ->select('*')
8310 ->from($dbo->qn('#__vikbooking_busy'));
8311
8312 $dbo->setQuery($q);
8313 $records = $dbo->loadAssocList();
8314
8315 foreach ($records as $v) {
8316 $info_start = getdate($v['checkin']);
8317 $info_end = getdate($v['checkout']);
8318 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8319 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8320
8321 $q = $dbo->getQuery(true)
8322 ->update($dbo->qn('#__vikbooking_busy'))
8323 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8324 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8325 ->set($dbo->qn('realback') . ' = ' . $new_end)
8326 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8327
8328 $dbo->setQuery($q, 0, 1);
8329 $dbo->execute();
8330
8331 $totmod++;
8332 }
8333
8334 // query all bookings
8335 $q = $dbo->getQuery(true)
8336 ->select($dbo->qn([
8337 'id',
8338 'days',
8339 'checkin',
8340 'checkout',
8341 'total',
8342 ]))
8343 ->from($dbo->qn('#__vikbooking_orders'))
8344 ->order($dbo->qn('checkin') . ' DESC');
8345
8346 $dbo->setQuery($q);
8347 $records = $dbo->loadAssocList();
8348
8349 foreach ($records as $v) {
8350 $info_start = getdate($v['checkin']);
8351 $info_end = getdate($v['checkout']);
8352 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8353 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8354
8355 $q = $dbo->getQuery(true)
8356 ->update($dbo->qn('#__vikbooking_orders'))
8357 ->set($dbo->qn('checkin') . ' = ' . $new_start)
8358 ->set($dbo->qn('checkout') . ' = ' . $new_end)
8359 ->where($dbo->qn('id') . ' = ' . (int)$v['id']);
8360
8361 $dbo->setQuery($q, 0, 1);
8362 $dbo->execute();
8363
8364 /**
8365 * In case the operation changed the check-in/check-out time for this booking,
8366 * store a new history record for a booking modification.
8367 *
8368 * @since 1.16.6 (J) - 1.6.6 (WP)
8369 */
8370 if ($v['checkout'] > $now && ($info_start['hours'] != $fh || $info_end['hours'] != $th)) {
8371 // Booking History
8372 VikBooking::getBookingHistoryInstance($v['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($v));
8373 }
8374
8375 $totbookmod++;
8376 }
8377
8378 $app->enqueueMessage('OK: ' . $totbookmod);
8379 $app->redirect("index.php?option=com_vikbooking&task=config");
8380 $app->close();
8381 }
8382
8383 public function savetmplfile() {
8384 if (!JSession::checkToken()) {
8385 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8386 }
8387 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8388 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8389 $mainframe = JFactory::getApplication();
8390 $exists = file_exists($fpath) ? true : false;
8391 if (!$exists) {
8392 $fpath = urldecode($fpath);
8393 }
8394 $fpath = file_exists($fpath) ? $fpath : '';
8395 if (!empty($fpath)) {
8396 $fp = fopen($fpath, 'wb');
8397 $byt = (int)fwrite($fp, $pcont);
8398 fclose($fp);
8399 if ($byt > 0) {
8400 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8401
8402 if (VBOPlatformDetection::isWordPress()) {
8403 /**
8404 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8405 */
8406 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8407 }
8408 } else {
8409 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8410 }
8411 } else {
8412 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8413 }
8414 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8415
8416 exit;
8417 }
8418
8419 public function edittmplfile() {
8420 //modal box, so we do not set menu or footer
8421
8422 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8423
8424 parent::display();
8425 }
8426
8427 public function tmplfileprew() {
8428 //modal box, so we do not set menu or footer
8429
8430 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8431
8432 parent::display();
8433 }
8434
8435 public function invoices() {
8436 VikBookingHelper::printHeader("invoices");
8437
8438 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8439
8440 parent::display();
8441
8442 if (VikBooking::showFooter()) {
8443 VikBookingHelper::printFooter();
8444 }
8445 }
8446
8447 public function newmaninvoice() {
8448 VikBookingHelper::printHeader("invoices");
8449
8450 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8451
8452 parent::display();
8453
8454 if (VikBooking::showFooter()) {
8455 VikBookingHelper::printFooter();
8456 }
8457 }
8458
8459 public function editmaninvoice() {
8460 VikBookingHelper::printHeader("invoices");
8461
8462 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8463
8464 parent::display();
8465
8466 if (VikBooking::showFooter()) {
8467 VikBookingHelper::printFooter();
8468 }
8469 }
8470
8471 public function savemaninvoice() {
8472 if (!JSession::checkToken()) {
8473 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8474 }
8475 $this->do_storemaninvoice('save');
8476 $mainframe = JFactory::getApplication();
8477 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8478 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8479 if (!empty($pgoto)) {
8480 $mainframe->redirect(base64_decode($pgoto));
8481 exit;
8482 }
8483 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8484 }
8485
8486 public function updatemaninvoice() {
8487 if (!JSession::checkToken()) {
8488 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8489 }
8490 $invid = VikRequest::getInt('whereup', 0, 'request');
8491 $this->do_storemaninvoice('update', $invid);
8492 $mainframe = JFactory::getApplication();
8493 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8494 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8495 if (!empty($pgoto)) {
8496 $mainframe->redirect(base64_decode($pgoto));
8497 exit;
8498 }
8499 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8500 }
8501
8502 public function updatemaninvoicestay() {
8503 $invid = VikRequest::getInt('whereup', 0, 'request');
8504 $this->do_storemaninvoice('updatestay', $invid);
8505 $mainframe = JFactory::getApplication();
8506 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8507 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8508 if (!empty($pgoto)) {
8509 $mainframe->redirect(base64_decode($pgoto));
8510 exit;
8511 }
8512 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8513 }
8514
8515 private function do_storemaninvoice($action, $invid = 0) {
8516 $dbo = JFactory::getDBO();
8517 $mainframe = JFactory::getApplication();
8518 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8519 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8520 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8521 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8522 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8523 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8524 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8525 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8526 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8527 if (empty($pidcustomer)) {
8528 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8529 $mainframe->redirect($error_uri);
8530 exit;
8531 }
8532 $services = VikRequest::getVar('service', array());
8533 $nets = VikRequest::getVar('net', array());
8534 $aliqs = VikRequest::getVar('aliq', array());
8535 $taxs = VikRequest::getVar('tax', array());
8536 $tots = VikRequest::getVar('tot', array());
8537 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8538 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8539 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8540 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8541 VikError::raiseWarning('', 'Missing data.');
8542 $mainframe->redirect($error_uri);
8543 exit;
8544 }
8545 $rawcont = array(
8546 'rows' => array(),
8547 'totalnet' => $ptotalnet,
8548 'totaltax' => $ptotaltax,
8549 'totaltot' => $ptotaltot,
8550 'notes' => $pinvoice_notes,
8551 );
8552 foreach ($services as $k => $service) {
8553 if (empty($service)) {
8554 continue;
8555 }
8556 array_push($rawcont['rows'], array(
8557 'service' => $service,
8558 'net' => (float)$nets[$k],
8559 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8560 'tax' => (float)$taxs[$k],
8561 'tot' => (float)$tots[$k],
8562 ));
8563 }
8564 // store/update manual invoice
8565 $nowts = time();
8566 $retval = 0;
8567 if (strpos($action, 'save') !== false) {
8568 $pdffname = $nowts . '_' . rand() . '.pdf';
8569 $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)).");";
8570 $dbo->setQuery($q);
8571 $dbo->execute();
8572 $retval = $dbo->insertid();
8573 } else {
8574 // fetch old record
8575 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8576 $dbo->setQuery($q);
8577 $dbo->execute();
8578 if (!$dbo->getNumRows()) {
8579 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8580 $mainframe->redirect($error_uri);
8581 exit;
8582 }
8583 $previnvoice = $dbo->loadAssoc();
8584 //
8585 $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'].";";
8586 $dbo->setQuery($q);
8587 $dbo->execute();
8588 $retval = $previnvoice['id'];
8589 }
8590 // update config values for the invoice
8591 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8592 $dbo->setQuery($q);
8593 $dbo->execute();
8594 // generate the custom invoice
8595 $result = VikBooking::generateCustomInvoice($retval);
8596 //
8597 $nextinv = VikBooking::getNextInvoiceNumber();
8598 $updatenum = ($pinvoice_num >= $nextinv);
8599 if ($updatenum) {
8600 /**
8601 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
8602 * to avoid conflicts with the drivers for the e-invoices generation.
8603 */
8604 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8605 $dbo->setQuery($q);
8606 $dbo->execute();
8607 }
8608
8609 return $retval;
8610 }
8611
8612 public function downloadinvoices() {
8613 $ids = VikRequest::getVar('cid', array(0));
8614 if (@count($ids) > 0) {
8615 $dbo = JFactory::getDBO();
8616 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
8617 $dbo->setQuery($q);
8618 $dbo->execute();
8619 if ($dbo->getNumRows() > 0) {
8620 $invoices = $dbo->loadAssocList();
8621 if (!(count($invoices) > 1)) {
8622 //Single Invoice Download
8623 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
8624 header("Content-type:application/pdf");
8625 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
8626 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
8627 exit;
8628 }
8629 } else {
8630 //Multiple Invoices Download
8631 $to_zip = array();
8632 foreach ($invoices as $k => $invoice) {
8633 $to_zip[$k]['name'] = $invoice['file_name'];
8634 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
8635 }
8636 if (class_exists('ZipArchive')) {
8637 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
8638 $zip = new ZipArchive;
8639 $zip->open($zip_path, ZipArchive::CREATE);
8640 foreach ($to_zip as $k => $zipv) {
8641 $zip->addFile($zipv['path'], $zipv['name']);
8642 }
8643 $zip->close();
8644 header("Content-type:application/zip");
8645 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
8646 header("Content-Length:".filesize($zip_path));
8647 readfile($zip_path);
8648 unlink($zip_path);
8649 exit;
8650 } else {
8651 //Class ZipArchive does not exist
8652 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
8653 }
8654 }
8655 }
8656 }
8657 $mainframe = JFactory::getApplication();
8658 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8659 }
8660
8661 public function resendinvoices() {
8662 $ids = VikRequest::getVar('cid', array(0));
8663 $mainframe = JFactory::getApplication();
8664 if (!(count($ids) > 0)) {
8665 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8666 exit;
8667 }
8668 $dbo = JFactory::getDBO();
8669 $invoices = array();
8670 $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` ".
8671 "FROM `#__vikbooking_invoices` AS `i` " .
8672 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
8673 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
8674 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
8675 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
8676 $dbo->setQuery($q);
8677 $dbo->execute();
8678 if ($dbo->getNumRows() > 0) {
8679 $invoices = $dbo->loadAssocList();
8680 }
8681 if (!(count($invoices) > 0)) {
8682 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8683 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8684 exit;
8685 }
8686 $tot_generated = 0;
8687 $tot_sent = 0;
8688 foreach ($invoices as $bkey => $invoice) {
8689 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
8690 $invoices[$bkey] = $invoice;
8691 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
8692 if ($send_res !== false) {
8693 $tot_sent++;
8694 }
8695 }
8696 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8697 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8698 }
8699
8700 public function removeinvoices() {
8701 $ids = VikRequest::getVar('cid', array());
8702 $tot_removed = 0;
8703 $dbo = JFactory::getDbo();
8704
8705 foreach ($ids as $d) {
8706 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8707 $dbo->setQuery($q);
8708 $dbo->execute();
8709 if ($dbo->getNumRows() == 1) {
8710 $cur_invoice = $dbo->loadAssoc();
8711 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
8712 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
8713 }
8714 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8715 $dbo->setQuery($q);
8716 $dbo->execute();
8717 $tot_removed++;
8718 }
8719 }
8720
8721 $mainframe = JFactory::getApplication();
8722 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
8723 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8724 }
8725
8726 public function geninvoices()
8727 {
8728 $dbo = JFactory::getDbo();
8729 $app = JFactory::getApplication();
8730
8731 $ids = VikRequest::getVar('cid', array());
8732
8733 if (!$ids) {
8734 $app->redirect("index.php?option=com_vikbooking&task=orders");
8735 exit;
8736 }
8737
8738 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8739 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8740 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8741 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
8742 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8743 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8744 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
8745 $pinvoice_send = $pinvoice_send > 0 ? true : false;
8746 $increment_inv = true;
8747 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
8748
8749 // if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
8750 if (count($ids) === 1) {
8751 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
8752 $dbo->setQuery($q);
8753 $dbo->execute();
8754 if ($dbo->getNumRows() == 1) {
8755 $increment_inv = false;
8756 }
8757 }
8758
8759 // get bookings
8760 $dbo->setQuery(
8761 $dbo->getQuery(true)
8762 ->select($dbo->qn('o') . '.*')
8763 ->select($dbo->qn('co.idcustomer'))
8764 ->select('CONCAT_WS(\' \', ' . $dbo->qn('c.first_name') . ', ' . $dbo->qn('c.last_name') . ') AS ' . $dbo->qn('customer_name'))
8765 ->select([
8766 $dbo->qn('c.pin', 'customer_pin'),
8767 $dbo->qn('nat.country_name'),
8768 ])
8769 ->from($dbo->qn('#__vikbooking_orders', 'o'))
8770 ->leftJoin($dbo->qn('#__vikbooking_customers_orders', 'co') . ' ON ' . $dbo->qn('co.idorder') . ' = ' . $dbo->qn('o.id'))
8771 ->leftJoin($dbo->qn('#__vikbooking_customers', 'c') . ' ON ' . $dbo->qn('c.id') . ' = ' . $dbo->qn('co.idcustomer'))
8772 ->leftJoin($dbo->qn('#__vikbooking_countries', 'nat') . ' ON ' . $dbo->qn('nat.country_3_code') . ' = ' . $dbo->qn('o.country'))
8773 ->where($dbo->qn('o.id') . ' IN (' . implode(', ', array_map('intval', $ids)) . ')')
8774 ->where($dbo->qn('o.status') . ' = ' . $dbo->q('confirmed'))
8775 ->where($dbo->qn('o.total') . ' > 0')
8776 ->order($dbo->qn('o.id') . ' ASC')
8777 );
8778
8779 $bookings = $dbo->loadAssocList();
8780
8781 if (!$bookings) {
8782 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8783 $app->redirect("index.php?option=com_vikbooking&task=orders");
8784 exit;
8785 }
8786
8787 $tot_generated = 0;
8788 $tot_sent = 0;
8789 foreach ($bookings as $bkey => $booking) {
8790 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
8791 if ($gen_res !== false && $gen_res > 0) {
8792 $tot_generated++;
8793 $pinvoice_num++;
8794 if ($pinvoice_send) {
8795 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
8796 if ($send_res !== false) {
8797 $tot_sent++;
8798 }
8799 }
8800 } else {
8801 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
8802 }
8803 }
8804
8805 if ($tot_generated > 0 && $increment_inv === true) {
8806 /**
8807 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
8808 * to avoid conflicts with the drivers for the e-invoices generation.
8809 */
8810 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8811 $dbo->setQuery($q);
8812 $dbo->execute();
8813 }
8814
8815 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
8816 $dbo->setQuery($q);
8817 $dbo->execute();
8818
8819 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8820 $dbo->setQuery($q);
8821 $dbo->execute();
8822
8823 $app->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8824
8825 if ($pconfirmgen > 0) {
8826 $app->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
8827 } elseif (count($bookings) === 1) {
8828 // go to the back-end booking details page
8829 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
8830 } else {
8831 $app->redirect("index.php?option=com_vikbooking&task=orders");
8832 }
8833 }
8834
8835 public function optionals() {
8836 VikBookingHelper::printHeader("6");
8837
8838 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
8839
8840 parent::display();
8841
8842 if (VikBooking::showFooter()) {
8843 VikBookingHelper::printFooter();
8844 }
8845 }
8846
8847 public function newoptionals() {
8848 VikBookingHelper::printHeader("6");
8849
8850 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8851
8852 parent::display();
8853
8854 if (VikBooking::showFooter()) {
8855 VikBookingHelper::printFooter();
8856 }
8857 }
8858
8859 public function editoptional() {
8860 VikBookingHelper::printHeader("6");
8861
8862 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8863
8864 parent::display();
8865
8866 if (VikBooking::showFooter()) {
8867 VikBookingHelper::printFooter();
8868 }
8869 }
8870
8871 public function updateoptional() {
8872 if (!JSession::checkToken()) {
8873 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8874 }
8875 $this->do_updateoptional();
8876 }
8877
8878 public function updateoptionalstay() {
8879 if (!JSession::checkToken()) {
8880 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8881 }
8882 $this->do_updateoptional(true);
8883 }
8884
8885 private function do_updateoptional($stay = false) {
8886 $dbo = JFactory::getDbo();
8887 $app = JFactory::getApplication();
8888 $poptname = VikRequest::getString('optname', '', 'request');
8889 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
8890 $poptcost = VikRequest::getFloat('optcost', '', 'request');
8891 $poptperday = VikRequest::getString('optperday', '', 'request');
8892 $poptperperson = VikRequest::getString('optperperson', '', 'request');
8893 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
8894 $popthmany = VikRequest::getString('opthmany', '', 'request');
8895 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
8896 $pwhereup = VikRequest::getString('whereup', '', 'request');
8897 $pautoresize = VikRequest::getString('autoresize', '', 'request');
8898 $presizeto = VikRequest::getString('resizeto', '', 'request');
8899 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
8900 $pifchildren = $pifchildren == "1" ? 1 : 0;
8901 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
8902 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
8903 $pforcesel = VikRequest::getString('forcesel', '', 'request');
8904 $pforceval = VikRequest::getString('forceval', '', 'request');
8905 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
8906 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
8907 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
8908 $pforcesel = $pforcesel == "1" ? 1 : 0;
8909 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
8910 $pis_fee = VikRequest::getString('is_fee', '', 'request');
8911 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
8912 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
8913 $pagefrom = VikRequest::getVar('agefrom', array());
8914 $pageto = VikRequest::getVar('ageto', array());
8915 $pagecost = VikRequest::getVar('agecost', array());
8916 $pagectype = VikRequest::getVar('agectype', array());
8917 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
8918 $pavfrom = VikRequest::getString('avfrom', '', 'request');
8919 $pavto = VikRequest::getString('avto', '', 'request');
8920 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
8921 $pidrooms = VikRequest::getVar('idrooms', array());
8922 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
8923 if ($pforcesel == 1) {
8924 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
8925 } else {
8926 $strforceval = "";
8927 }
8928 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
8929 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
8930 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
8931 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
8932 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
8933 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
8934 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
8935 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
8936 $minguests = VikRequest::getInt('minguests', 0, 'request');
8937 $minguests_conflict = false;
8938 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
8939 if ($minguestsnum >= $maxguestsnum) {
8940 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
8941 } elseif (($maxguestsnum - $minguestsnum) < 2) {
8942 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
8943 }
8944 }
8945 if (!$minguests || $minguests_conflict !== false) {
8946 $minguestsnum = 0;
8947 $maxguestsnum = 0;
8948 if ($minguests_conflict !== false) {
8949 // raise warning, but do not stop the process
8950 VikError::raiseWarning('', $minguests_conflict);
8951 }
8952 }
8953 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
8954 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
8955 $oparams = array(
8956 'minguestsnum' => $minguestsnum,
8957 'mingueststype' => $mingueststype,
8958 'maxguestsnum' => $maxguestsnum,
8959 'maxgueststype' => $maxgueststype,
8960 'damagedep' => $damagedep,
8961 'pet_fee' => $pet_fee,
8962 );
8963 /**
8964 * We fetch the previous params to merge them with the new ones
8965 * in case some properties have been set somewhere else.
8966 * For example, the damage deposit transmission to Booking.com.
8967 */
8968 $cur_oparams = array();
8969 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
8970 $dbo->setQuery($q);
8971 $dbo->execute();
8972 if ($dbo->getNumRows()) {
8973 $cur_oparams = $dbo->loadResult();
8974 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
8975 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
8976 // merge previous params with the new ones to get the new values
8977 $oparams = array_merge($cur_oparams, $oparams);
8978 }
8979 //
8980 if (!empty($poptname)) {
8981 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
8982 jimport('joomla.filesystem.file');
8983 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
8984 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
8985 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
8986 if (file_exists($updpath.$safename)) {
8987 $j=1;
8988 while (file_exists($updpath.$j.$safename)) {
8989 $j++;
8990 }
8991 $pwhere=$updpath.$j.$safename;
8992 } else {
8993 $j="";
8994 $pwhere=$updpath.$safename;
8995 }
8996 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8997 @unlink($pwhere);
8998 $picon="";
8999 } else {
9000 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9001 @chmod($pwhere, 0644);
9002 $picon=$j.$safename;
9003 if ($pautoresize=="1" && !empty($presizeto)) {
9004 $eforj = new vikResizer();
9005 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9006 if ($origmod) {
9007 @unlink($pwhere);
9008 $picon='r_'.$j.$safename;
9009 }
9010 }
9011 }
9012 } else {
9013 $picon="";
9014 }
9015 } else {
9016 $picon="";
9017 }
9018 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
9019 $poptperperson=($poptperperson=="each" ? "1" : "0");
9020 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
9021 $ageintervalstr = '';
9022 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9023 foreach ($pagefrom as $kage => $vage) {
9024 $afrom = intval($vage);
9025 $ato = intval($pageto[$kage]);
9026 $acost = floatval($pagecost[$kage]);
9027 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9028 if ($ato < $afrom) $ato = $afrom;
9029 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9030 }
9031 }
9032 $ageintervalstr = rtrim($ageintervalstr, ';;');
9033 if (!empty($ageintervalstr)) {
9034 $pforcesel = 1;
9035 }
9036 }
9037 $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).";";
9038 $dbo->setQuery($q);
9039 $dbo->execute();
9040 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
9041
9042 // assign/unset option-rooms relations
9043 $rooms_with_opt = array();
9044 if (count($pidrooms)) {
9045 // assign this new option to the requested rooms
9046 foreach ($pidrooms as $idroom) {
9047 if (empty($idroom)) {
9048 continue;
9049 }
9050 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9051 $dbo->setQuery($q);
9052 $dbo->execute();
9053 if (!$dbo->getNumRows()) {
9054 continue;
9055 }
9056 $room_data = $dbo->loadAssoc();
9057 array_push($rooms_with_opt, $room_data['id']);
9058 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9059 if (in_array((string)$pwhereup, $current_opts)) {
9060 continue;
9061 }
9062 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9063 // make sure we do not concatenate a real ID to 0
9064 $current_opts = array();
9065 }
9066 array_push($current_opts, $pwhereup);
9067 $new_opts = implode(';', $current_opts) . ';';
9068 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9069 $dbo->setQuery($q);
9070 $dbo->execute();
9071 }
9072 }
9073 if (!count($rooms_with_opt)) {
9074 // get all rooms to unset this option (if previously set)
9075 array_push($rooms_with_opt, '0');
9076 }
9077 // unset the option from the other rooms that may have it
9078 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9079 $dbo->setQuery($q);
9080 $dbo->execute();
9081 if ($dbo->getNumRows()) {
9082 $unset_rooms_opt = $dbo->loadAssocList();
9083 foreach ($unset_rooms_opt as $room_data) {
9084 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9085 if (!in_array((string)$pwhereup, $current_opts)) {
9086 // this room is not using this option
9087 continue;
9088 }
9089 $optkey = array_search((string)$pwhereup, $current_opts);
9090 if ($optkey === false) {
9091 // key not found
9092 continue;
9093 }
9094 // unset this option ID from the string
9095 unset($current_opts[$optkey]);
9096 if (!count($current_opts)) {
9097 // a room with no options assigned will be listed as "0;"
9098 $current_opts = array(0);
9099 }
9100 $new_opts = implode(';', $current_opts) . ';';
9101 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9102 $dbo->setQuery($q);
9103 $dbo->execute();
9104 }
9105 }
9106 //
9107
9108 }
9109 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
9110 }
9111
9112 public function createoptionals() {
9113 if (!JSession::checkToken()) {
9114 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9115 }
9116 $this->do_createoptionals();
9117 }
9118
9119 public function createoptionalsstay() {
9120 if (!JSession::checkToken()) {
9121 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9122 }
9123 $this->do_createoptionals(true);
9124 }
9125
9126 private function do_createoptionals($stay = false) {
9127 $dbo = JFactory::getDbo();
9128 $poptname = VikRequest::getString('optname', '', 'request');
9129 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9130 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9131 $poptperday = VikRequest::getString('optperday', '', 'request');
9132 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9133 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9134 $popthmany = VikRequest::getString('opthmany', '', 'request');
9135 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9136 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9137 $presizeto = VikRequest::getString('resizeto', '', 'request');
9138 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9139 $pifchildren = $pifchildren == "1" ? 1 : 0;
9140 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9141 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9142 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9143 $pforceval = VikRequest::getString('forceval', '', 'request');
9144 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9145 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9146 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9147 $pforcesel = $pforcesel == "1" ? 1 : 0;
9148 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9149 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9150 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9151 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9152 $pagefrom = VikRequest::getVar('agefrom', array());
9153 $pageto = VikRequest::getVar('ageto', array());
9154 $pagecost = VikRequest::getVar('agecost', array());
9155 $pagectype = VikRequest::getVar('agectype', array());
9156 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9157 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9158 $pavto = VikRequest::getString('avto', '', 'request');
9159 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9160 $pidrooms = VikRequest::getVar('idrooms', array());
9161 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9162 if ($pforcesel == 1) {
9163 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9164 } else {
9165 $strforceval = "";
9166 }
9167 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9168 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9169 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9170 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9171 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9172 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9173 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9174 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9175 $minguests = VikRequest::getInt('minguests', 0, 'request');
9176 $minguests_conflict = false;
9177 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9178 if ($minguestsnum >= $maxguestsnum) {
9179 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9180 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9181 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9182 }
9183 }
9184 if (!$minguests || $minguests_conflict !== false) {
9185 $minguestsnum = 0;
9186 $maxguestsnum = 0;
9187 if ($minguests_conflict !== false) {
9188 // raise warning, but do not stop the process
9189 VikError::raiseWarning('', $minguests_conflict);
9190 }
9191 }
9192 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9193 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9194 $oparams = array(
9195 'minguestsnum' => $minguestsnum,
9196 'mingueststype' => $mingueststype,
9197 'maxguestsnum' => $maxguestsnum,
9198 'maxgueststype' => $maxgueststype,
9199 'damagedep' => $damagedep,
9200 'pet_fee' => $pet_fee,
9201 );
9202 if (!empty($poptname)) {
9203 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9204 jimport('joomla.filesystem.file');
9205 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9206 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9207 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9208 if (file_exists($updpath.$safename)) {
9209 $j = 1;
9210 while (file_exists($updpath.$j.$safename)) {
9211 $j++;
9212 }
9213 $pwhere = $updpath.$j.$safename;
9214 } else {
9215 $j = "";
9216 $pwhere = $updpath.$safename;
9217 }
9218 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9219 @unlink($pwhere);
9220 $picon = "";
9221 } else {
9222 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9223 @chmod($pwhere, 0644);
9224 $picon = $j.$safename;
9225 if ($pautoresize == "1" && !empty($presizeto)) {
9226 $eforj = new vikResizer();
9227 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9228 if ($origmod) {
9229 @unlink($pwhere);
9230 $picon = 'r_'.$j.$safename;
9231 }
9232 }
9233 }
9234 } else {
9235 $picon = "";
9236 }
9237 } else {
9238 $picon = "";
9239 }
9240 $poptperday = ($poptperday == "each" ? "1" : "0");
9241 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9242 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9243 $ageintervalstr = '';
9244 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9245 foreach ($pagefrom as $kage => $vage) {
9246 $afrom = intval($vage);
9247 $ato = intval($pageto[$kage]);
9248 $acost = floatval($pagecost[$kage]);
9249 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9250 if ($ato < $afrom) $ato = $afrom;
9251 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9252 }
9253 }
9254 $ageintervalstr = rtrim($ageintervalstr, ';;');
9255 if (!empty($ageintervalstr)) {
9256 $pforcesel = 1;
9257 }
9258 }
9259 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9260 $dbo->setQuery($q);
9261 $dbo->execute();
9262 if ($dbo->getNumRows() == 1) {
9263 $getlast = $dbo->loadResult();
9264 $newsortnum = $getlast + 1;
9265 } else {
9266 $newsortnum = 1;
9267 }
9268 $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)) . ");";
9269 $dbo->setQuery($q);
9270 $dbo->execute();
9271 $newoptid = $dbo->insertid();
9272
9273 if (!empty($newoptid)) {
9274 // assign/unset option-rooms relations
9275 $rooms_with_opt = array();
9276 if (count($pidrooms)) {
9277 // assign this new option to the requested rooms
9278 foreach ($pidrooms as $idroom) {
9279 if (empty($idroom)) {
9280 continue;
9281 }
9282 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9283 $dbo->setQuery($q);
9284 $dbo->execute();
9285 if (!$dbo->getNumRows()) {
9286 continue;
9287 }
9288 $room_data = $dbo->loadAssoc();
9289 array_push($rooms_with_opt, $room_data['id']);
9290 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9291 if (in_array((string)$newoptid, $current_opts)) {
9292 continue;
9293 }
9294 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9295 // make sure we do not concatenate a real ID to 0
9296 $current_opts = array();
9297 }
9298 array_push($current_opts, $newoptid);
9299 $new_opts = implode(';', $current_opts) . ';';
9300 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9301 $dbo->setQuery($q);
9302 $dbo->execute();
9303 }
9304 }
9305 if (!count($rooms_with_opt)) {
9306 // get all rooms to unset this option (if previously set)
9307 array_push($rooms_with_opt, '0');
9308 }
9309 // unset the option from the other rooms that may have it
9310 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9311 $dbo->setQuery($q);
9312 $dbo->execute();
9313 if ($dbo->getNumRows()) {
9314 $unset_rooms_opt = $dbo->loadAssocList();
9315 foreach ($unset_rooms_opt as $room_data) {
9316 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9317 if (!in_array((string)$newoptid, $current_opts)) {
9318 // this room is not using this option
9319 continue;
9320 }
9321 $optkey = array_search((string)$newoptid, $current_opts);
9322 if ($optkey === false) {
9323 // key not found
9324 continue;
9325 }
9326 // unset this option ID from the string
9327 unset($current_opts[$optkey]);
9328 if (!count($current_opts)) {
9329 // a room with no options assigned will be listed as "0;"
9330 $current_opts = array(0);
9331 }
9332 $new_opts = implode(';', $current_opts) . ';';
9333 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9334 $dbo->setQuery($q);
9335 $dbo->execute();
9336 }
9337 }
9338 //
9339 }
9340
9341 }
9342 $mainframe = JFactory::getApplication();
9343 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9344 }
9345
9346 public function removeoptionals() {
9347 if (!JSession::checkToken()) {
9348 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9349 }
9350 $ids = VikRequest::getVar('cid', array(0));
9351 if (@count($ids)) {
9352 $dbo = JFactory::getDbo();
9353 foreach ($ids as $d) {
9354 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9355 $dbo->setQuery($q);
9356 $dbo->execute();
9357 if ($dbo->getNumRows() == 1) {
9358 $rows = $dbo->loadAssocList();
9359 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9360 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9361 }
9362 }
9363 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9364 $dbo->setQuery($q);
9365 $dbo->execute();
9366 }
9367 }
9368 $mainframe = JFactory::getApplication();
9369 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9370 }
9371
9372 public function sendcustomsms() {
9373 $mainframe = JFactory::getApplication();
9374 $pphone = VikRequest::getString('phone', '', 'request');
9375 $psmscont = VikRequest::getString('smscont', '', 'request');
9376 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9377 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9378 if (!empty($pphone) && !empty($psmscont)) {
9379 $sms_api = VikBooking::getSMSAPIClass();
9380 $sms_api_params = VikBooking::getSMSParams();
9381 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9382 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9383 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9384 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9385 if ( !$sms_obj->validateResponse($response_obj) ) {
9386 VikError::raiseWarning('', $sms_obj->getLog());
9387 } else {
9388 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9389 }
9390 } else {
9391 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9392 }
9393 } else {
9394 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9395 }
9396 $mainframe->redirect($pgoto);
9397 }
9398
9399 public function sendcustomemail() {
9400 $dbo = JFactory::getDbo();
9401 $mainframe = JFactory::getApplication();
9402 $vbo_tn = VikBooking::getTranslator();
9403 $pbid = VikRequest::getInt('bid', '', 'request');
9404 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9405 $pemail = VikRequest::getString('email', '', 'request');
9406 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9407 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9408 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9409 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9410 if (!empty($pemail) && !empty($pemailcont)) {
9411 $email_attach = null;
9412 jimport('joomla.filesystem.file');
9413 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9414 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9415 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9416 $src = $pemailattch['tmp_name'];
9417 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9418 $j = "";
9419 if (file_exists($dest.$filename)) {
9420 $j = rand(171, 1717);
9421 while (file_exists($dest.$j.$filename)) {
9422 $j++;
9423 }
9424 }
9425 $finaldest = $dest.$j.$filename;
9426 if (VikBooking::uploadFile($src, $finaldest)) {
9427 $email_attach = $finaldest;
9428 } else {
9429 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9430 $mainframe->redirect($pgoto);
9431 exit;
9432 }
9433 }
9434 //VBO 1.10 - special tags for the custom email template files and messages
9435 $orig_mail_cont = $pemailcont;
9436 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9437 // replace any possible placeholder for special tags
9438 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9439 return $match[2];
9440 }, $pemailcont);
9441
9442 $booking = array();
9443 $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.";";
9444 $dbo->setQuery($q);
9445 $dbo->execute();
9446 if ($dbo->getNumRows() > 0) {
9447 $booking = $dbo->loadAssoc();
9448 }
9449 $booking_rooms = array();
9450 $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.";";
9451 $dbo->setQuery($q);
9452 $dbo->execute();
9453 if ($dbo->getNumRows() > 0) {
9454 $booking_rooms = $dbo->loadAssocList();
9455 if (!empty($booking['lang'])) {
9456 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9457 }
9458 }
9459 //we use the same parsing function as the one for the Customer SMS Template
9460 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9461 }
9462 //
9463 // allow the use of token {booking_id} in subject
9464 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9465 //
9466 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9467 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9468 $vbo_app = VikBooking::getVboApplication();
9469 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9470 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9471 if ($email_attach !== null) {
9472 @unlink($email_attach);
9473 }
9474 //Booking History
9475 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9476 //
9477 //Save email template for future sending
9478 $config_rec_exists = false;
9479 $emtpl = array(
9480 'emailsubj' => $pemailsubj,
9481 'emailcont' => $orig_mail_cont,
9482 'emailfrom' => $pemailfrom
9483 );
9484 $cur_emtpl = array();
9485 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9486 $dbo->setQuery($q);
9487 $dbo->execute();
9488 if ($dbo->getNumRows() > 0) {
9489 $config_rec_exists = true;
9490 $cur_emtpl = $dbo->loadResult();
9491 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9492 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9493 }
9494 if (count($cur_emtpl) > 0) {
9495 $existing_subj = false;
9496 foreach ($cur_emtpl as $emk => $emv) {
9497 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9498 $cur_emtpl[$emk] = $emtpl;
9499 $existing_subj = true;
9500 break;
9501 }
9502 }
9503 if ($existing_subj === false) {
9504 $cur_emtpl[] = $emtpl;
9505 }
9506 } else {
9507 $cur_emtpl[] = $emtpl;
9508 }
9509 if (count($cur_emtpl) > 10) {
9510 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9511 $exceed = count($cur_emtpl) - 10;
9512 for ($tl=0; $tl < $exceed; $tl++) {
9513 unset($cur_emtpl[$tl]);
9514 }
9515 $cur_emtpl = array_values($cur_emtpl);
9516 }
9517 if ($config_rec_exists === true) {
9518 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9519 $dbo->setQuery($q);
9520 $dbo->execute();
9521 } else {
9522 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9523 $dbo->setQuery($q);
9524 $dbo->execute();
9525 }
9526 //
9527 } else {
9528 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9529 }
9530 $mainframe->redirect($pgoto);
9531 }
9532
9533 public function rmcustomemailtpl() {
9534 $cid = VikRequest::getVar('cid', array(0));
9535 $oid = $cid[0];
9536 $dbo = JFactory::getDBO();
9537 $mainframe = JFactory::getApplication();
9538 $tplind = VikRequest::getInt('tplind', '', 'request');
9539 if (empty($oid) || !(strlen($tplind) > 0)) {
9540 VikError::raiseWarning('', 'Missing Data.');
9541 $mainframe->redirect('index.php?option=com_vikbooking');
9542 exit;
9543 }
9544 $cur_emtpl = array();
9545 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9546 $dbo->setQuery($q);
9547 $dbo->execute();
9548 if ($dbo->getNumRows() > 0) {
9549 $cur_emtpl = $dbo->loadResult();
9550 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9551 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9552 } else {
9553 VikError::raiseWarning('', 'Missing Templates Record.');
9554 $mainframe->redirect('index.php?option=com_vikbooking');
9555 exit;
9556 }
9557 if (array_key_exists($tplind, $cur_emtpl)) {
9558 unset($cur_emtpl[$tplind]);
9559 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9560 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9561 $dbo->setQuery($q);
9562 $dbo->execute();
9563 }
9564 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
9565 exit;
9566 }
9567
9568 public function exportcustomers() {
9569 //we do not set the menu for this view
9570
9571 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
9572
9573 parent::display();
9574
9575 if (VikBooking::showFooter()) {
9576 VikBookingHelper::printFooter();
9577 }
9578 }
9579
9580 public function csvexportprepare() {
9581 //modal box, so we do not set menu or footer
9582
9583 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
9584
9585 parent::display();
9586 }
9587
9588 public function icsexportprepare() {
9589 //modal box, so we do not set menu or footer
9590
9591 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
9592
9593 parent::display();
9594 }
9595
9596 public function bookingcheckin() {
9597 //modal box, so we do not set menu or footer
9598
9599 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
9600
9601 parent::display();
9602 }
9603
9604 public function gencheckindoc() {
9605 //modal box, so we do not set menu or footer
9606
9607 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
9608
9609 parent::display();
9610 }
9611
9612 public function checkversion() {
9613 //to be called via ajax
9614 $params = new stdClass;
9615 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9616 $params->alias = 'com_vikbooking';
9617
9618 $result = array();
9619
9620 if (!count($result)) {
9621 $result = new stdClass;
9622 $result->status = 0;
9623 } else {
9624 $result = $result[0];
9625 }
9626
9627 echo json_encode($result);
9628 exit;
9629 }
9630
9631 public function updateprogram() {
9632 $params = new stdClass;
9633 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9634 $params->alias = 'com_vikbooking';
9635
9636 $result = array();
9637
9638 if (!count($result) || !$result[0]) {
9639 if (class_exists('JEventDispatcher')) {
9640 $dispatcher = JEventDispatcher::getInstance();
9641 $result = $dispatcher->trigger('checkVersion', array(&$params));
9642 } else {
9643 $app = JFactory::getApplication();
9644 if (method_exists($app, 'triggerEvent')) {
9645 $result = $app->triggerEvent('checkVersion', array(&$params));
9646 }
9647 }
9648 }
9649
9650 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
9651 exit('Error, plugin disabled');
9652 }
9653
9654 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
9655
9656 VikBookingHelper::pUpdateProgram($result[0]->response);
9657 }
9658
9659 public function updateprogramlaunch() {
9660 $params = new stdClass;
9661 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9662 $params->alias = 'com_vikbooking';
9663
9664 $json = new stdClass;
9665 $json->status = false;
9666
9667 echo json_encode($json);
9668 exit;
9669 }
9670
9671 public function invoke_vcm()
9672 {
9673 $app = JFactory::getApplication();
9674
9675 $oids = VikRequest::getVar('cid', []);
9676 $sync_type = VikRequest::getString('stype', 'new', 'request');
9677 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
9678 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
9679 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
9680 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
9681
9682 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
9683 $app->redirect("index.php?option=com_vikbooking&task=orders");
9684 $app->close();
9685 }
9686
9687 $result = VikBooking::getVcmInvoker()
9688 ->setOids($oids)
9689 ->setSyncType($sync_type)
9690 ->setOriginalBooking($original_booking_js, true)
9691 ->doSync();
9692
9693 if ($result === true) {
9694 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
9695 } else {
9696 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
9697 }
9698
9699 if (!empty($return_url)) {
9700 $app->redirect($return_url);
9701 } else {
9702 $app->redirect("index.php?option=com_vikbooking&task=orders");
9703 }
9704
9705 $app->close();
9706 }
9707
9708 public function multiphotosupload() {
9709 jimport('joomla.filesystem.file');
9710
9711 $dbo = JFactory::getDBO();
9712 $proomid = VikRequest::getInt('roomid', '', 'request');
9713
9714 $resp = array('files' => array());
9715 $error_messages = array(
9716 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
9717 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
9718 3 => 'The uploaded file was only partially uploaded',
9719 4 => 'No file was uploaded',
9720 6 => 'Missing a temporary folder',
9721 7 => 'Failed to write file to disk',
9722 8 => 'A PHP extension stopped the file upload',
9723 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
9724 'max_file_size' => 'File is too big',
9725 'min_file_size' => 'File is too small',
9726 'accept_file_types' => 'Filetype not allowed',
9727 'max_number_of_files' => 'Maximum number of files exceeded',
9728 'max_width' => 'Image exceeds maximum width',
9729 'min_width' => 'Image requires a minimum width',
9730 'max_height' => 'Image exceeds maximum height',
9731 'min_height' => 'Image requires a minimum height',
9732 'abort' => 'File upload aborted',
9733 'image_resize' => 'Failed to resize image',
9734 'vbo_type' => 'The file type cannot be accepted',
9735 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
9736 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
9737 );
9738
9739 $creativik = new vikResizer();
9740 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9741 $bigsdest = $updpath;
9742 $thumbsdest = $updpath;
9743 $dest = $updpath;
9744 $moreimagestr = '';
9745 $cur_captions = json_encode(array());
9746
9747 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
9748 $dbo->setQuery($q);
9749 $dbo->execute();
9750 if ($dbo->getNumRows() == 1) {
9751 $photo_data = $dbo->loadAssocList();
9752 $cur_captions = $photo_data[0]['imgcaptions'];
9753 $cur_photos = $photo_data[0]['moreimgs'];
9754 if (!empty($cur_photos)) {
9755 $moreimagestr .= $cur_photos;
9756 }
9757 }
9758
9759 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
9760
9761 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
9762 foreach ($bulkphotos['name'] as $updk => $photoname) {
9763 $uploaded_image = array();
9764 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
9765 $src = $bulkphotos['tmp_name'][$updk];
9766 $j = "";
9767 if (file_exists($dest.$filename)) {
9768 $j = rand(171, 1717);
9769 while (file_exists($dest.$j.$filename)) {
9770 $j++;
9771 }
9772 }
9773 $finaldest=$dest.$j.$filename;
9774 $is_error = false;
9775 $err_key = '';
9776 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
9777 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
9778 $is_error = true;
9779 $err_key = $bulkphotos['error'][$updk];
9780 }
9781 }
9782 if (!$is_error) {
9783 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
9784 if ($check[2] & imagetypes()) {
9785 if (VikBooking::uploadFile($src, $finaldest)) {
9786 $gimg = $j.$filename;
9787 //orig img
9788 $origmod = true;
9789 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
9790 //thumb
9791 $thumbsize = VikBooking::getThumbSize();
9792 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
9793 if (!$thumb || !$origmod) {
9794 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
9795 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
9796 $is_error = true;
9797 $err_key = 'vbo_perm';
9798 } else {
9799 $moreimagestr.=$j.$filename.";;";
9800 }
9801 @unlink($finaldest);
9802 } else {
9803 $is_error = true;
9804 $err_key = 'vbo_jupload';
9805 }
9806 } else {
9807 $is_error = true;
9808 $err_key = 'vbo_type';
9809 }
9810 }
9811 $img = new stdClass();
9812 if ($is_error) {
9813 $img->name = '';
9814 $img->size = '';
9815 $img->type = '';
9816 $img->url = '';
9817 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
9818 } else {
9819 $img->name = $photoname;
9820 $img->size = $bulkphotos['size'][$updk];
9821 $img->type = $bulkphotos['type'][$updk];
9822 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
9823 }
9824 $resp['files'][] = $img;
9825 }
9826 } else {
9827 $res = new stdClass();
9828 $res->name = '';
9829 $res->size = '';
9830 $res->type = '';
9831 $res->url = '';
9832 $res->error = 'No images received for upload';
9833 $resp['files'][] = $res;
9834 }
9835 //Update current extra images string
9836 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
9837 $dbo->setQuery($q);
9838 $dbo->execute();
9839 $resp['actmoreimgs'] = $moreimagestr;
9840 //Update current extra images uploaded
9841 $cur_thumbs = '';
9842 $morei=explode(';;', $moreimagestr);
9843 if (@count($morei) > 0) {
9844 $imgcaptions = json_decode($cur_captions, true);
9845 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
9846 $cur_thumbs .= '<ul class="vbo-sortable">';
9847 foreach ($morei as $ki => $mi) {
9848 if (!empty($mi)) {
9849 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
9850 $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>';
9851 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
9852 $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>';
9853 $cur_thumbs .= '</li>';
9854 }
9855 }
9856 $cur_thumbs .= '</ul>';
9857 $cur_thumbs .= '<br clear="all"/>';
9858 }
9859 $resp['currentthumbs'] = $cur_thumbs;
9860
9861 echo json_encode($resp);
9862 exit;
9863 }
9864
9865 public function loadsmsbalance() {
9866 //to be called via ajax
9867 $html = 'Error1 [N/A]';
9868 $sms_api = VikBooking::getSMSAPIClass();
9869 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
9870 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9871 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
9872 if (method_exists('VikSmsApi', 'estimate')) {
9873 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
9874 if ( $array_result->errorCode != 0 ) {
9875 $html = 'Error3 ['.$array_result->errorMsg.']';
9876 } else {
9877 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
9878 }
9879 } else {
9880 $html = 'Error2 [N/A]';
9881 }
9882 }
9883 echo $html;
9884 exit;
9885 }
9886
9887 public function loadsmsparams() {
9888 //to be called via ajax
9889 $html = '---------';
9890 $phpfile = VikRequest::getString('phpfile', '', 'request');
9891 if (!empty($phpfile)) {
9892 $sms_api = VikBooking::getSMSAPIClass();
9893 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
9894 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
9895 }
9896 echo $html;
9897 exit;
9898 }
9899
9900 public function loadcronparams() {
9901 //to be called via ajax
9902 $html = '---------';
9903 $phpfile = VikRequest::getString('phpfile', '', 'request');
9904 if (!empty($phpfile)) {
9905 $html = VikBooking::displayCronParameters($phpfile);
9906 }
9907 echo $html;
9908 exit;
9909 }
9910
9911 public function loadpaymentparams() {
9912 //to be called via ajax
9913 $html = '<p>---------</p>';
9914 $phpfile = VikRequest::getString('phpfile', '', 'request');
9915 if (!empty($phpfile)) {
9916 $html = VikBooking::displayPaymentParameters($phpfile);
9917 }
9918 echo $html;
9919 exit;
9920 }
9921
9922 public function setbookingtag() {
9923 //to be called via ajax
9924 $dbo = JFactory::getDBO();
9925 $pidorder = VikRequest::getInt('idorder', '', 'request');
9926 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
9927 if (!empty($pidorder) && $ptagkey >= 0) {
9928 $all_tags = VikBooking::loadBookingsColorTags();
9929 if (array_key_exists($ptagkey, $all_tags)) {
9930 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
9931 $dbo->setQuery($q);
9932 $dbo->execute();
9933 if ($dbo->getNumRows() > 0) {
9934 $newcolortag = json_encode($all_tags[$ptagkey]);
9935 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
9936 $dbo->setQuery($q);
9937 $dbo->execute();
9938 $newcolortag = $all_tags[$ptagkey];
9939 $newcolortag['name'] = JText::translate($newcolortag['name']);
9940 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
9941 echo json_encode($newcolortag);
9942 } else {
9943 echo 'e4j.error.Booking ('.$pidorder.') not found';
9944 }
9945 } else {
9946 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
9947 }
9948 } else {
9949 echo 'e4j.error.Missing Data';
9950 }
9951 exit;
9952 }
9953
9954 public function updatereceiptnum() {
9955 //to be called via ajax
9956 $pnewnum = VikRequest::getInt('newnum', '', 'request');
9957 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
9958 $poid = VikRequest::getInt('oid', '', 'request');
9959 if ($pnewnum > 0) {
9960 VikBooking::getNextReceiptNumber($poid, $pnewnum);
9961 VikBooking::getReceiptNotes($pnewnotes);
9962 //Booking History
9963 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
9964 //
9965 echo 'e4j.ok';
9966 exit;
9967 }
9968 echo 'e4j.error';
9969 exit;
9970 }
9971
9972 public function isroombookable() {
9973 //to be called via ajax
9974 $dbo = JFactory::getDBO();
9975 $res = array(
9976 'status' => 0,
9977 'err' => ''
9978 );
9979 $prid = VikRequest::getInt('rid', '', 'request');
9980 $pfdate = VikRequest::getString('fdate', '', 'request');
9981 $ptdate = VikRequest::getString('tdate', '', 'request');
9982 $room_info = array();
9983 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
9984 $dbo->setQuery($q);
9985 $dbo->execute();
9986 if ($dbo->getNumRows() > 0) {
9987 $room_info = $dbo->loadAssoc();
9988 }
9989 $pcheckinh = 0;
9990 $pcheckinm = 0;
9991 $pcheckouth = 0;
9992 $pcheckoutm = 0;
9993 $timeopst = VikBooking::getTimeOpenStore();
9994 if (is_array($timeopst)) {
9995 $opent = VikBooking::getHoursMinutes($timeopst[0]);
9996 $closet = VikBooking::getHoursMinutes($timeopst[1]);
9997 $pcheckinh = $opent[0];
9998 $pcheckinm = $opent[1];
9999 $pcheckouth = $closet[0];
10000 $pcheckoutm = $closet[1];
10001 }
10002 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
10003 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
10004 if (
10005 count($room_info) > 0 &&
10006 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
10007 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
10008 {
10009 $res['status'] = 1;
10010 } else {
10011 if (!(count($room_info) > 0)) {
10012 $res['err'] = 'Room not found';
10013 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
10014 $res['err'] = 'Invalid dates';
10015 } else {
10016 //not available
10017 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
10018 }
10019 }
10020
10021 echo json_encode($res);
10022 exit;
10023 }
10024
10025 public function uploadsnapshot() {
10026 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
10027 /**
10028 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
10029 * The old snapshot collection script with Flash no longer works in 2021.
10030 *
10031 * @since 1.14 (J) - 1.4.0 (WP)
10032 */
10033 $result = null;
10034 try {
10035 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
10036 } catch (RuntimeException $e) {
10037 echo "e4j.error.Error " . $e->getMessage();
10038 exit;
10039 }
10040
10041 if (!is_object($result)) {
10042 echo "e4j.error.Invalid upload response";
10043 exit;
10044 }
10045
10046 echo $result->filename;
10047 exit;
10048 }
10049
10050 public function checkvcmrateschanges() {
10051 //to be called via ajax
10052 $session = JFactory::getSession();
10053 $ret = array('changesCount' => 0, 'changesData' => '');
10054 $updforvcm = $session->get('vbVcmRatesUpd', '');
10055 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
10056 $ret['changesCount'] = $updforvcm['count'];
10057 $ret['changesData'] = $updforvcm;
10058 }
10059
10060 echo json_encode($ret);
10061 exit;
10062 }
10063
10064 /**
10065 * AJAX endpoint to load the details of one or more bookings.
10066 *
10067 * @return void
10068 *
10069 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
10070 */
10071 public function getbookingsinfo()
10072 {
10073 //to be called via ajax
10074 $dbo = JFactory::getDbo();
10075
10076 $booking_infos = [];
10077 $bookings = [];
10078
10079 $pidorders = VikRequest::getString('idorders', '', 'request');
10080 $psubroom = VikRequest::getString('subroom', '', 'request');
10081 $pstatus = VikRequest::getString('status', '', 'request');
10082 $pstay_date = VikRequest::getString('stay_date', '', 'request');
10083 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10084 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
10085
10086 if (!empty($pidorders)) {
10087 $bookings = explode(',', $pidorders);
10088 foreach ($bookings as $k => $v) {
10089 $v = intval(str_replace('-', '', $v));
10090 if (empty($v)) {
10091 unset($bookings[$k]);
10092 continue;
10093 }
10094 $bookings[$k] = $v;
10095 }
10096 }
10097 $bookings = array_values($bookings);
10098
10099 if (!$bookings) {
10100 /**
10101 * AJAX requests made by the page availability overview may contain empty booking IDs
10102 * due to SQL errors that only occupied the room, but could not save the booking record.
10103 * Clean up busy records where the busy relations contain empty booking IDs.
10104 *
10105 * @since 1.14 (J) - 1.4.0 (WP)
10106 */
10107 $hanging_busy_ids = [];
10108
10109 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
10110 $dbo->setQuery($q);
10111 $removelist = $dbo->loadAssocList();
10112 if ($removelist) {
10113 foreach ($removelist as $hanging_busy) {
10114 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10115 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10116 array_push($hanging_busy_ids, $hanging_busy_id);
10117 }
10118 }
10119 }
10120
10121 // let's check also for ghost records that only occupy the room
10122 $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);";
10123 $dbo->setQuery($q);
10124 $removelist = $dbo->loadAssocList();
10125 if ($removelist) {
10126 foreach ($removelist as $hanging_busy) {
10127 $hanging_busy_id = (int)$hanging_busy['id'];
10128 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10129 array_push($hanging_busy_ids, $hanging_busy_id);
10130 }
10131 }
10132 }
10133
10134 if ($hanging_busy_ids) {
10135 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10136 $dbo->setQuery($q);
10137 $dbo->execute();
10138 }
10139 //
10140
10141 // output the error
10142 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10143 }
10144
10145 $nowdf = VikBooking::getDateFormat(true);
10146 if ($nowdf == "%d/%m/%Y") {
10147 $df = 'd/m/Y';
10148 } elseif ($nowdf == "%m/%d/%Y") {
10149 $df = 'm/d/Y';
10150 } else {
10151 $df = 'Y/m/d';
10152 }
10153 $datesep = VikBooking::getDateSeparator(true);
10154 $currencysymb = VikBooking::getCurrencySymb();
10155 $current_y = date('Y');
10156 $current_ts = time();
10157 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10158
10159 $query = $dbo->getQuery(true);
10160 $query->select('o.*');
10161 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10162 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10163 // include the requested booking IDs and the cancelled reservations for this stay date
10164 $stay_date_info = getdate(strtotime($pstay_date));
10165 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10166 $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) . '))');
10167 // exclude the pending reservations
10168 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10169 } else {
10170 // include only the requested booking IDs
10171 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10172 }
10173 if ($pstatus != 'any') {
10174 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10175 }
10176 if (!empty($pstay_date) && $pstatus == 'any') {
10177 // sort by confirmed status before cancelled status
10178 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10179 $query->order($dbo->qn('o.id') . ' ASC');
10180 }
10181 $dbo->setQuery($query);
10182 $booking_infos = $dbo->loadAssocList();
10183
10184 foreach ($booking_infos as $k => $row) {
10185 // rooms, amounts and guests information
10186 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10187 $rids_involved = [];
10188 $room_names = [];
10189 $totadults = 0;
10190 $totchildren = 0;
10191 foreach ($rooms as $rr) {
10192 $rids_involved[] = $rr['idroom'];
10193 $totadults += $rr['adults'];
10194 $totchildren += $rr['children'];
10195 $room_names[] = $rr['room_name'];
10196 if ($row['split_stay']) {
10197 // do not sum guests in case of split stay booking
10198 $totadults = $rr['adults'];
10199 $totchildren = $rr['children'];
10200 }
10201 }
10202
10203 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10204 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10205 if (!in_array($pidroom, $rids_involved)) {
10206 $is_out_of_scope = true;
10207 if ($psharedcal && count($bookings) === 1) {
10208 $is_out_of_scope = ($row['id'] != $bookings[0]);
10209 }
10210 if ($is_out_of_scope) {
10211 // out of scope reservation, unset it and go to the next one
10212 unset($booking_infos[$k]);
10213 continue;
10214 }
10215 }
10216 }
10217
10218 // included meal plans to be displayed in case of single-room booking
10219 $included_meals = [];
10220 $rplan_name = '';
10221 if (count($rooms) === 1) {
10222 // rate plan name and ID, if any
10223 $active_rplan_id = 0;
10224 if (!empty($rooms[0]['otarplan'])) {
10225 $rplan_name = $rooms[0]['otarplan'];
10226 } else {
10227 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10228 }
10229
10230 // find the included meals
10231 if (!empty($rooms[0]['meals'])) {
10232 // display included meals defined at room-reservation record
10233 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10234 } else {
10235 // fetch default included meals in the selected rate plan
10236 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10237 }
10238 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10239 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10240 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10241 }
10242 }
10243
10244 if ($included_meals) {
10245 $short_incl_meals = [];
10246 foreach ($included_meals as $meal_enum => $meal_name) {
10247 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10248 }
10249 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10250 }
10251
10252 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10253 $booking_infos[$k]['currency_symb'] = $currencysymb;
10254 if ($row['status'] == 'confirmed') {
10255 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10256 if ($row['checkout'] < $current_ts) {
10257 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10258 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10259 if ($row['checked'] == 1) {
10260 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10261 } elseif ($row['checked'] == -1) {
10262 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10263 }
10264 }
10265 } elseif ($row['status'] == 'standby') {
10266 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10267 } elseif ($row['status'] == 'cancelled') {
10268 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10269 } else {
10270 $booking_infos[$k]['status_lbl'] = $row['status'];
10271 }
10272 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10273 if ($booking_infos[$k]['colortag']) {
10274 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10275 }
10276 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10277 $booking_infos[$k]['tot_adults'] = $totadults;
10278 $booking_infos[$k]['tot_children'] = $totchildren;
10279 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10280 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10281
10282 // room indexes
10283 $rindexes = [];
10284 $av_room_indexes = [];
10285 $used_indexes_map = [];
10286 $sub_units_data = [];
10287 $optindexes = [];
10288 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10289 $missing_index = false;
10290 foreach ($rooms as $kor => $or) {
10291 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10292 // cannot build room indexes data
10293 continue;
10294 }
10295
10296 $room_params = json_decode($or['params'], true);
10297 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10298 // no distinctive features information
10299 continue;
10300 }
10301
10302 if (!strlen($or['roomindex'])) {
10303 // turn flag on for missing index when room does support them
10304 $missing_index = true;
10305 // build array with available room indexes
10306 $av_indexes = [];
10307 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10308 foreach ($room_params['features'] as $rind => $rfeatures) {
10309 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10310 continue;
10311 }
10312 foreach ($rfeatures as $fname => $fval) {
10313 if ($fval) {
10314 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10315 break;
10316 }
10317 }
10318 }
10319 if ($av_indexes) {
10320 // push available indexes for this room
10321 $av_room_indexes[$kor] = [
10322 'rid' => $or['idroom'],
10323 'name' => $or['room_name'],
10324 'list' => $av_indexes,
10325 ];
10326 }
10327 // do not proceed any further
10328 continue;
10329 }
10330
10331 // parse distinctive features
10332 foreach ($room_params['features'] as $rind => $rfeatures) {
10333 if ($rind != $or['roomindex']) {
10334 continue;
10335 }
10336 $ind_str = '';
10337 $ind_str_short = '';
10338 foreach ($rfeatures as $fname => $fval) {
10339 if (strlen($fval)) {
10340 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10341 $ind_str_short = $fval;
10342 break;
10343 }
10344 }
10345 if (!isset($rindexes[$or['room_name']])) {
10346 $rindexes[$or['room_name']] = $ind_str;
10347 $sub_units_data[$or['room_name']] = $ind_str_short;
10348 } else {
10349 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10350 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10351 }
10352 break;
10353 }
10354
10355 // build options to switch sub-unit index
10356 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10357 // build the options for switching the room index for this room
10358 foreach ($room_params['features'] as $rind => $rfeatures) {
10359 foreach ($rfeatures as $fname => $fval) {
10360 if (strlen((string)$fval)) {
10361 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10362 break;
10363 }
10364 }
10365 }
10366 }
10367 }
10368
10369 if ($rindexes) {
10370 $booking_infos[$k]['rindexes'] = $rindexes;
10371 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10372 }
10373
10374 if ($optindexes) {
10375 $booking_infos[$k]['optindexes'] = $optindexes;
10376 }
10377
10378 if ($missing_index && $av_room_indexes) {
10379 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10380 }
10381
10382 // include flag for missing room index
10383 $booking_infos[$k]['missing_index'] = $missing_index;
10384
10385 // channel provenience and small logo URL
10386 $ota_logo_img = JText::translate('VBORDFROMSITE');
10387 $booking_avatar_src = null;
10388 $booking_avatar_alt = null;
10389 if (!empty($row['channel'])) {
10390 $channelparts = explode('_', $row['channel']);
10391 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10392 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10393 if ($ota_logo_img === false) {
10394 $ota_logo_img = $otachannel;
10395 } else {
10396 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10397 }
10398 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10399 if ($logo_helper !== false) {
10400 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10401 $booking_avatar_alt = $logo_helper->provenience;
10402 }
10403 }
10404 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10405 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10406 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10407
10408 // Customer Details
10409 $custdata = $row['custdata'];
10410 $custdata_parts = explode("\n", $row['custdata']);
10411 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10412 //get the first two fields
10413 $custvalues = [];
10414 foreach ($custdata_parts as $custdet) {
10415 if (strlen($custdet) < 1) {
10416 continue;
10417 }
10418 $custdet_parts = explode(':', $custdet);
10419 if (count($custdet_parts) >= 2) {
10420 unset($custdet_parts[0]);
10421 array_push($custvalues, trim(implode(':', $custdet_parts)));
10422 }
10423 if (count($custvalues) > 1) {
10424 break;
10425 }
10426 }
10427 if (count($custvalues) > 1) {
10428 $custdata = implode(' ', $custvalues);
10429 }
10430 }
10431 if (strlen($custdata) > 45) {
10432 $custdata = (function_exists('mb_substr') ? mb_substr($custdata, 0, 45, 'UTF-8') : substr($custdata, 0, 45)) . " ...";
10433 }
10434
10435 // customer record details
10436 $customer = [];
10437 $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'];
10438 $dbo->setQuery($q, 0, 1);
10439 $dbo->execute();
10440 if ($dbo->getNumRows()) {
10441 $customer = $dbo->loadAssoc();
10442 if (!empty($customer['first_name'])) {
10443 $custdata = $customer['first_name'].' '.$customer['last_name'];
10444 if (!empty($customer['country'])) {
10445 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10446 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10447 }
10448 }
10449 }
10450 }
10451 $booking_infos[$k]['customer'] = $customer;
10452
10453 // check if a profile picture is available for the customer
10454 if (!empty($customer['pic'])) {
10455 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10456 $booking_avatar_alt = basename($booking_avatar_src);
10457 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10458 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10459 }
10460
10461 // whether this is a closure
10462 $booking_infos[$k]['closure'] = (int)$row['closure'];
10463 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10464
10465 // short customer information
10466 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10467 $booking_infos[$k]['cinfo'] = $custdata;
10468
10469 // formatted dates
10470 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10471 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10472 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10473
10474 // short booking date, check-in, check-out date format
10475 $stay_info_in = getdate($row['checkin']);
10476 $stay_info_out = getdate($row['checkout']);
10477 $str_checkin = date('d', $row['checkin']);
10478 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10479 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10480 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10481 $str_checkout .= ' ' . $stay_info_out['year'];
10482 }
10483 $booking_infos[$k]['checkin_short'] = $str_checkin;
10484 $booking_infos[$k]['checkout_short'] = $str_checkout;
10485 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10486 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10487 }
10488
10489 if (!$booking_infos) {
10490 // output the error
10491 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10492 }
10493
10494 // output the JSON encoded response and exit
10495 VBOHttpDocument::getInstance()->json($booking_infos);
10496 }
10497
10498 public function switchRoomIndex() {
10499 //to be called via ajax
10500 $dbo = JFactory::getDBO();
10501 $bid = VikRequest::getInt('bid', '', 'request');
10502 $rid = VikRequest::getInt('rid', '', 'request');
10503 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10504 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10505 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10506 echo 'e4j.error.#1 Missing Data';
10507 exit;
10508 }
10509 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10510 $dbo->setQuery($q);
10511 $dbo->execute();
10512 if ($dbo->getNumRows() < 1) {
10513 echo 'e4j.error.#2 Record not found';
10514 exit;
10515 }
10516 $rows = $dbo->loadAssocList();
10517 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10518 $dbo->setQuery($q);
10519 $dbo->execute();
10520 echo 'e4j.ok';
10521 exit;
10522 }
10523
10524 public function searchcustomer()
10525 {
10526 // to be called via ajax
10527 $dbo = JFactory::getDbo();
10528
10529 $kw = VikRequest::getString('kw', '', 'request');
10530 $nopin = VikRequest::getInt('nopin', '', 'request');
10531 $email = VikRequest::getInt('email', 0, 'request');
10532 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10533 $no_script = VikRequest::getInt('no_script', 0, 'request');
10534
10535 if (!strlen($kw)) {
10536 VBOHttpDocument::getInstance()->close(200, '');
10537 }
10538
10539 if ($nopin > 0) {
10540 //page all bookings
10541 $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;";
10542 } elseif ($email > 0) {
10543 // page calendar for checking if an email exists
10544 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10545 } else {
10546 //page calendar
10547 $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;";
10548 }
10549 $dbo->setQuery($q);
10550 $customers = $dbo->loadAssocList();
10551
10552 if (!$customers) {
10553 VBOHttpDocument::getInstance()->close(200, '');
10554 }
10555
10556 if ($email > 0) {
10557 VBOHttpDocument::getInstance()->json($customers[0]);
10558 }
10559
10560 $cust_old_fields = array();
10561 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10562 foreach ($customers as $k => $v) {
10563 $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";
10564 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
10565 if (!empty($v['pic'])) {
10566 $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";
10567 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
10568 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
10569 } else {
10570 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
10571 }
10572 $cstring_search .= '</span>';
10573 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
10574 if (!($nopin > 0)) {
10575 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
10576 }
10577 $cstring_search .= '</div>'."\n";
10578 if (!empty($v['cfields'])) {
10579 $oldfields = json_decode($v['cfields'], true);
10580 if (is_array($oldfields) && count($oldfields)) {
10581 $cust_old_fields[$v['id']] = $oldfields;
10582 }
10583 }
10584 }
10585 $cstring_search .= '</div>'."\n";
10586
10587 /**
10588 * Add the necessary JS code for the arrow navigation.
10589 */
10590 $cstring_search_js = '<script type="text/javascript">';
10591 $cstring_search_js .= '
10592 var vboCust = jQuery(".' . $selector . '");
10593 var vboCustSelected = null;
10594 jQuery(window).keydown(function(e) {
10595 if (e.which === 40) {
10596 if (vboCustSelected) {
10597 vboCustSelected.removeClass("' . $selector . '-highligthed");
10598 next = vboCustSelected.next();
10599 if (next.length > 0) {
10600 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10601 } else {
10602 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10603 }
10604 } else {
10605 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10606 }
10607 } else if (e.which === 38) {
10608 if (vboCustSelected) {
10609 vboCustSelected.removeClass("' . $selector . '-highligthed");
10610 next = vboCustSelected.prev();
10611 if (next.length > 0) {
10612 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10613 } else {
10614 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10615 }
10616 } else {
10617 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10618 }
10619 } else if (e.which === 13) {
10620 if (vboCustSelected) {
10621 vboCustSelected.trigger("click");
10622 }
10623 }
10624 });
10625 jQuery(".' . $selector . '").off("hover");
10626 jQuery(".' . $selector . '").hover(function() {
10627 if (vboCustSelected) {
10628 vboCustSelected.removeClass("' . $selector . '-highligthed");
10629 vboCustSelected = null;
10630 }
10631 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
10632 }, function() {
10633 if (vboCustSelected) {
10634 vboCustSelected.removeClass("' . $selector . '-highligthed");
10635 vboCustSelected = null;
10636 }
10637 jQuery(this).removeClass("' . $selector . '-highligthed");
10638 });';
10639 $cstring_search_js .= '</script>';
10640
10641 if (!$no_script) {
10642 // append JS
10643 $cstring_search .= $cstring_search_js;
10644 }
10645
10646 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
10647 }
10648
10649 public function sharesignaturelink() {
10650 //to be called via ajax
10651 $dbo = JFactory::getDBO();
10652 $response = array(
10653 'status' => 0,
10654 'error' => 'Generic Error'
10655 );
10656 $pbid = VikRequest::getInt('bid', '', 'request');
10657 $phow = VikRequest::getString('how', '', 'request');
10658 $pto = VikRequest::getString('to', '', 'request');
10659 $pcustomer = VikRequest::getInt('customer', '', 'request');
10660 $cpin = VikBooking::getCPinIstance();
10661 $customer_info = $cpin->getCustomerByID($pcustomer);
10662 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
10663 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
10664 $dbo->setQuery($q);
10665 $dbo->execute();
10666 if ($dbo->getNumRows() > 0) {
10667 $row = $dbo->loadAssoc();
10668
10669 $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'];
10670 if (VBOPlatformDetection::isWordPress()) {
10671 /**
10672 * @wponly Rewrite URI for front-end signature
10673 */
10674 $share_link = str_replace(JUri::root(), '', $share_link);
10675 $model = JModel::getInstance('vikbooking', 'shortcodes');
10676 $itemid = $model->all('post_id', $full = true);
10677 if (count($itemid)) {
10678 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
10679 }
10680 } else {
10681 /**
10682 * @joomlaonly
10683 */
10684 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
10685 if ($best_menuitem_id) {
10686 $share_base = str_replace(JUri::root(), '', $share_link);
10687 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
10688 }
10689 }
10690
10691 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10692 if ($phow == 'email') {
10693 $sender = VikBooking::getSenderMail();
10694 $vbo_app = VikBooking::getVboApplication();
10695 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
10696 $response['status'] = 1;
10697 } elseif ($phow == 'sms') {
10698 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10699 $sms_api = VikBooking::getSMSAPIClass();
10700 $sms_api_params = VikBooking::getSMSParams();
10701 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
10702 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10703 $sms_obj = new VikSmsApi(array(), $sms_api_params);
10704 $response_obj = $sms_obj->sendMessage($pto, $share_message);
10705 if ($sms_obj->validateResponse($response_obj)) {
10706 $response['status'] = 1;
10707 } else {
10708 $response['error'] = $sms_obj->getLog();
10709 }
10710 } else {
10711 $response['error'] = 'No SMS Provider Configured';
10712 }
10713 } else {
10714 $response['error'] = 'Invalid Sending Method';
10715 }
10716 } else {
10717 $response['error'] = 'Invalid Booking ID';
10718 }
10719 } else {
10720 $response['error'] = 'Empty values';
10721 }
10722
10723 echo json_encode($response);
10724 exit;
10725 }
10726
10727 public function dayselectioncount() {
10728 //to be called via ajax
10729 $tsinit = VikRequest::getString('dinit', '', 'request');
10730 $tsend = VikRequest::getString('dend', '', 'request');
10731 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
10732 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
10733 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
10734 $diff = $ptsend - $ptsinit;
10735 if ($diff >= 172800) {
10736 $datef = VikBooking::getDateFormat(true);
10737 if ($datef=="%d/%m/%Y") {
10738 $df = 'd-m-Y';
10739 } else {
10740 $df = 'Y-m-d';
10741 }
10742 //minimum 2 days for excluding some days
10743 $daysdiff = floor($diff / 86400);
10744 $infoinit = getdate($ptsinit);
10745 $select = '';
10746 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
10747 for($i = 0; $i <= $daysdiff; $i++) {
10748 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
10749 $infots = getdate($ts);
10750 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
10751 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
10752 }
10753 $select .= '</select></div>';
10754 //excluded days of the week
10755 if ($daysdiff >= 14) {
10756 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
10757 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
10758 $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>';
10759 $select .= '</optgroup>';
10760 $select .= '</select></div>';
10761 }
10762 //
10763 echo $select;
10764 } else {
10765 echo '';
10766 }
10767 } else {
10768 echo '';
10769 }
10770 exit;
10771 }
10772
10773 public function createcheckindoc() {
10774 $cid = VikRequest::getVar('cid', array(0));
10775 $id = $cid[0];
10776
10777 $dbo = JFactory::getDBO();
10778 $mainframe = JFactory::getApplication();
10779 $vbo_tn = VikBooking::getTranslator();
10780 $lang = JFactory::getLanguage();
10781 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10782 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
10783 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
10784 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
10785 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
10786 $dbo->setQuery($q);
10787 $dbo->execute();
10788 if ($dbo->getNumRows() < 1) {
10789 $mainframe->redirect('index.php');
10790 exit;
10791 }
10792 $row = $dbo->loadAssoc();
10793 if (!empty($row['lang'])) {
10794 if ($lang->getTag() != $row['lang']) {
10795 if (VBOPlatformDetection::isWordPress()) {
10796 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
10797 } else {
10798 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
10799 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
10800 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
10801 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
10802 }
10803 }
10804 if ($vbo_tn->getDefaultLang() != $row['lang']) {
10805 // force the translation to start because contents should be translated
10806 $vbo_tn::$force_tolang = $row['lang'];
10807 }
10808 }
10809 $customer = array();
10810 $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'].";";
10811 $dbo->setQuery($q);
10812 $dbo->execute();
10813 if ($dbo->getNumRows() > 0) {
10814 $customer = $dbo->loadAssoc();
10815 if (!empty($customer['country'])) {
10816 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10817 $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"/>';
10818 }
10819 }
10820 }
10821 if (!(count($customer) > 0)) {
10822 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10823 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10824 exit;
10825 }
10826 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
10827 //check if the signature has been submitted
10828 $signature_data = '';
10829 $cont_type = '';
10830 if (!empty($psignature)) {
10831 //check whether the format is accepted
10832 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
10833 $parts = explode(';base64,', $psignature);
10834 $cont_type_parts = explode('image/', $parts[0]);
10835 $cont_type = $cont_type_parts[1];
10836 if (!empty($parts[1])) {
10837 $signature_data = base64_decode($parts[1]);
10838 }
10839 }
10840 }
10841 if (!empty($signature_data)) {
10842 //write file
10843 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
10844 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
10845 $fp = fopen($filepath, 'w+');
10846 $bytes = fwrite($fp, $signature_data);
10847 fclose($fp);
10848 if ($bytes !== false && $bytes > 0) {
10849 //update the signature in the DB
10850 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
10851 $dbo->setQuery($q);
10852 $dbo->execute();
10853 $customer['signature'] = $sign_fname;
10854 //resize image for screens with high resolution
10855 if ($ppad_ratio > 1) {
10856 $new_width = floor(($ppad_width / 2));
10857 $creativik = new vikResizer();
10858 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
10859 } else {
10860 /**
10861 * @wponly - trigger files mirroring
10862 */
10863 VikBookingLoader::import('update.manager');
10864 VikBookingUpdateManager::triggerUploadBackup($filepath);
10865 //
10866 }
10867 //
10868 } else {
10869 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
10870 }
10871 }
10872 //
10873 //generate PDF for check-in document by parsing the apposite template file
10874 $booking_rooms = array();
10875 $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'].";";
10876 $dbo->setQuery($q);
10877 $dbo->execute();
10878 if ($dbo->getNumRows() > 0) {
10879 $booking_rooms = $dbo->loadAssocList();
10880 if (!empty($row['lang'])) {
10881 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
10882 }
10883 }
10884 if (!class_exists('TCPDF')) {
10885 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
10886 }
10887 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
10888
10889 /**
10890 * Trigger event to allow third party plugins to return a specific font name.
10891 *
10892 * @since 1.16.0 (J) - 1.6.0 (WP)
10893 */
10894 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
10895 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
10896 $usepdffont = $custom_pdf_font[0];
10897 }
10898
10899 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
10900 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
10901 $pdffname = $row['id'] . '_' . $row['sid'] . '.pdf';
10902 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
10903 if (file_exists($pathpdf)) @unlink($pathpdf);
10904 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
10905 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
10906 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
10907 //Header for each page of the pdf
10908 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
10909 $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]);
10910 }
10911 //header and footer fonts
10912 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
10913 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
10914 //margins
10915 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
10916 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
10917 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
10918 //
10919 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
10920 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
10921 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
10922 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
10923 $pdf->SetPrintHeader(false);
10924 }
10925 if ($pdfparams['show_footer'] == 0) {
10926 $pdf->SetPrintFooter(false);
10927 }
10928 $pdf->AddPage();
10929 $pdf->writeHTML($checkin_body, true, false, true, false, '');
10930 $pdf->lastPage();
10931 $pdf->Output($pathpdf, 'F');
10932 if (!file_exists($pathpdf)) {
10933 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
10934 } else {
10935 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
10936 $dbo->setQuery($q);
10937 $dbo->execute();
10938 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
10939 /**
10940 * @wponly - trigger files mirroring
10941 */
10942 VikBookingLoader::import('update.manager');
10943 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
10944 //
10945 }
10946 //
10947 /**
10948 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
10949 */
10950 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
10951 exit;
10952 }
10953
10954 public function updatebookingcheckin() {
10955 $cid = VikRequest::getVar('cid', array(0));
10956 $id = $cid[0];
10957
10958 $dbo = JFactory::getDbo();
10959 $app = JFactory::getApplication();
10960
10961 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10962 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
10963 $pguests = VikRequest::getVar('guests', array());
10964 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
10965 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
10966 $valid_actions = array(-1, 0, 1, 2);
10967 if (!in_array($pcheckin_action, $valid_actions)) {
10968 $app->redirect('index.php');
10969 exit;
10970 }
10971 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
10972 $dbo->setQuery($q);
10973 $dbo->execute();
10974 if ($dbo->getNumRows() < 1) {
10975 $app->redirect('index.php');
10976 exit;
10977 }
10978 $row = $dbo->loadAssoc();
10979 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
10980 $dbo->setQuery($q);
10981 $dbo->execute();
10982 if ($dbo->getNumRows() < 1) {
10983 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10984 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10985 exit;
10986 }
10987 $custorder = $dbo->loadAssoc();
10988 //update checked status and new total paid
10989 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
10990 $dbo->setQuery($q);
10991 $dbo->execute();
10992 // Booking History log for new amount paid (payment update)
10993 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
10994 $extra_data = new stdClass;
10995 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
10996 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
10997 }
10998 //
10999 //Booking History
11000 $hist_type = 'A';
11001 if ($pcheckin_action < 0) {
11002 $hist_type = 'Z';
11003 } elseif ($pcheckin_action == 1) {
11004 $hist_type = 'B';
11005 } elseif ($pcheckin_action == 2) {
11006 $hist_type = 'C';
11007 }
11008 $user = JFactory::getUser();
11009 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
11010 //
11011 //Guests Details
11012 $guests_details = array();
11013 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
11014 // grab also the fields for front-end pre check-in
11015 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
11016 //
11017 foreach ($pguests as $ind => $adults) {
11018 foreach ($adults as $aduind => $details) {
11019 foreach ($pax_fields as $key => $v) {
11020 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11021 if (!isset($guests_details[$ind])) {
11022 $guests_details[$ind] = array();
11023 }
11024 if (!isset($guests_details[$ind][$aduind])) {
11025 $guests_details[$ind][$aduind] = array();
11026 }
11027 $guests_details[$ind][$aduind][$key] = $details[$key];
11028 }
11029 }
11030 foreach ($pre_pax_fields as $key => $v) {
11031 if (isset($pax_fields[$key])) {
11032 // we must have parsed this back-end field already
11033 continue;
11034 }
11035 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
11036 if (!isset($guests_details[$ind])) {
11037 $guests_details[$ind] = array();
11038 }
11039 if (!isset($guests_details[$ind][$aduind])) {
11040 $guests_details[$ind][$aduind] = array();
11041 }
11042 if (!isset($guests_details[$ind][$aduind][$key])) {
11043 $guests_details[$ind][$aduind][$key] = $details[$key];
11044 }
11045 }
11046 }
11047 }
11048 }
11049 if (count($guests_details)) {
11050 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
11051 $curpaxdata = json_decode($custorder['pax_data'], true);
11052 if (is_array($curpaxdata) && count($curpaxdata)) {
11053 foreach ($guests_details as $ind => $groom) {
11054 foreach ($groom as $aduind => $aduinfo) {
11055 if (isset($curpaxdata[$ind][$aduind])) {
11056 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
11057 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
11058 foreach ($guests_details[$ind][$aduind] as $key => $det) {
11059 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
11060 // this default pax field was specified as empty now, so we cannot merge it
11061 unset($guests_details[$ind][$aduind][$key]);
11062 }
11063 }
11064 }
11065 }
11066 }
11067 }
11068 //
11069 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=".$dbo->quote(json_encode($guests_details))." WHERE `id`=".$custorder['id'].";";
11070 $dbo->setQuery($q);
11071 $dbo->execute();
11072 }
11073
11074 //'checked' status comments
11075 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
11076 $dbo->setQuery($q);
11077 $dbo->execute();
11078
11079 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
11080 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
11081 exit;
11082 }
11083
11084 public function alterbooking()
11085 {
11086 $dbo = JFactory::getDbo();
11087 $app = JFactory::getApplication();
11088 $user = JFactory::getUser();
11089
11090 $response = array(
11091 'esit' => 1,
11092 'message' => '',
11093 'vcm' => '',
11094 );
11095
11096 // must be a string as it may contain a dash
11097 $pidorder = VikRequest::getString('idorder', '', 'request');
11098 $pidorder = intval(str_replace('-', '', $pidorder));
11099
11100 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
11101 $pidroom = VikRequest::getInt('idroom', 0, 'request');
11102 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11103 $ptodate = VikRequest::getString('todate', '', 'request');
11104 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
11105 if ($pdebug == 1) {
11106 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
11107 exit;
11108 }
11109
11110 $nowdf = VikBooking::getDateFormat(true);
11111 if ($nowdf == "%d/%m/%Y") {
11112 $df = 'd/m/Y';
11113 } elseif ($nowdf == "%m/%d/%Y") {
11114 $df = 'm/d/Y';
11115 } else {
11116 $df = 'Y/m/d';
11117 }
11118 $pcheckinh = 0;
11119 $pcheckinm = 0;
11120 $pcheckouth = 0;
11121 $pcheckoutm = 0;
11122 $timeopst = VikBooking::getTimeOpenStore();
11123 if (is_array($timeopst)) {
11124 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11125 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11126 $pcheckinh = $opent[0];
11127 $pcheckinm = $opent[1];
11128 $pcheckouth = $closet[0];
11129 $pcheckoutm = $closet[1];
11130 }
11131 $info_tsto = getdate(strtotime($ptodate));
11132 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11133 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11134 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11135 $ptodate = date('Y-m-d', $second);
11136 if (!($second > $first)) {
11137 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11138 exit;
11139 }
11140 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11141 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11142 exit;
11143 }
11144
11145 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11146 $dbo->setQuery($q, 0, 1);
11147 $dbo->execute();
11148 if (!$dbo->getNumRows()) {
11149 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11150 exit;
11151 }
11152 $ord = $dbo->loadAssoc();
11153
11154 $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;";
11155 $dbo->setQuery($q);
11156 $dbo->execute();
11157 $ordersrooms = $dbo->loadAssocList();
11158
11159 // store for VCM the current rooms before the modification
11160 $ord['rooms_info'] = $ordersrooms;
11161
11162 // package or custom rate
11163 $is_package = !empty($ord['pkg']) ? true : false;
11164 $is_cust_cost = false;
11165 foreach ($ordersrooms as $kor => $or) {
11166 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11167 $is_cust_cost = true;
11168 break;
11169 }
11170 }
11171
11172 // availability helper
11173 $av_helper = VikBooking::getAvailabilityInstance();
11174
11175 // room stay dates in case of split stay
11176 $room_stay_dates = [];
11177 if ($ord['split_stay']) {
11178 // no need to get the transient based on booking status, as the booking must be confirmed
11179 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11180 // immediately count the number of nights of stay for each split room
11181 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11182 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11183 }
11184 }
11185
11186 // determine if dates have changed
11187 $dates_changed = false;
11188 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11189 $dates_changed = true;
11190 }
11191
11192 $toswitch = array();
11193 $idbooked = array();
11194 $rooms_units = array();
11195 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11196 $dbo->setQuery($q);
11197 $dbo->execute();
11198 $all_rooms = $dbo->loadAssocList();
11199 foreach ($all_rooms as $rr) {
11200 $rooms_units[$rr['id']]['name'] = $rr['name'];
11201 $rooms_units[$rr['id']]['units'] = $rr['units'];
11202 }
11203
11204 // switch room
11205 if ($poldidroom != $pidroom) {
11206 foreach ($ordersrooms as $ind => $or) {
11207 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11208 if (!isset($idbooked[$or['idroom']])) {
11209 $idbooked[$or['idroom']] = 0;
11210 }
11211 // $idbooked is not really needed as switch is never made for the same room id
11212 $idbooked[$or['idroom']]++;
11213 //
11214 $orkey = count($toswitch);
11215 $toswitch[$orkey]['from'] = $or['idroom'];
11216 $toswitch[$orkey]['to'] = $pidroom;
11217 $toswitch[$orkey]['record'] = $or;
11218 $toswitch[$orkey]['record_ind'] = $ind;
11219 break;
11220 }
11221 }
11222 }
11223 if (count($toswitch)) {
11224 foreach ($toswitch as $ksw => $rsw) {
11225 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11226 $room_checkin = $ord['checkin'];
11227 $room_checkout = $ord['checkout'];
11228 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11229 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11230 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11231 }
11232 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11233 // the room is not available
11234 unset($toswitch[$ksw]);
11235 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11236 exit;
11237 }
11238 }
11239 if (count($toswitch)) {
11240 //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)
11241 reset($ordersrooms);
11242 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11243 $dbo->setQuery($q);
11244 $dbo->execute();
11245 //
11246 foreach ($toswitch as $ksw => $rsw) {
11247 // update room reservation record
11248 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11249 $dbo->setQuery($q);
11250 $dbo->execute();
11251 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11252
11253 // update Notes field for this booking to keep track of the previous room that was assigned
11254 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11255 if (!empty($prev_room_name)) {
11256 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11257 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11258 $dbo->setQuery($q);
11259 $dbo->execute();
11260 }
11261
11262 if ($ord['status'] == 'confirmed') {
11263 // update room record in _busy
11264 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'])) {
11265 // in case of a split stay it is fundamental to update the exact busy record ID
11266 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11267 $dbo->setQuery($q);
11268 $dbo->execute();
11269 } else {
11270 // regular processing of a room ID for a reservation, no matter which one, we switch it
11271 $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;";
11272 $dbo->setQuery($q);
11273 $dbo->execute();
11274 if ($dbo->getNumRows() == 1) {
11275 $cur_busy = $dbo->loadAssocList();
11276 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11277 $dbo->setQuery($q);
11278 $dbo->execute();
11279 }
11280 }
11281
11282 // if automated updates enabled, keep $response['vcm'] empty
11283 // Invoke Channel Manager
11284 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11285 $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>';
11286 }
11287 } elseif ($ord['status'] == 'standby') {
11288 // remove record in _tmplock
11289 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11290 $dbo->setQuery($q);
11291 $dbo->execute();
11292 }
11293 }
11294
11295 // check if sub-units should be assigned again when switching room
11296 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11297 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11298 $room_indexes_usemap = [];
11299 foreach ($new_order_rooms as $kor => $or) {
11300 $num = $kor + 1;
11301 // assign room specific unit
11302 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11303 $use_ind_key = 0;
11304 if ($room_indexes) {
11305 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11306 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11307 } else {
11308 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11309 }
11310 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11311 $dbo->setQuery($q);
11312 $dbo->execute();
11313 $room_indexes_usemap[$or['idroom']]++;
11314 }
11315 }
11316 }
11317
11318 // do not terminate the process when there is a switch, proceed to check the dates.
11319 }
11320 }
11321
11322 // change dates
11323 if ($dates_changed) {
11324 if ($ord['split_stay']) {
11325 // we do not allow to drag and change dates for rooms in a split stay reservation
11326 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11327 exit;
11328 }
11329
11330 // total nights of stay
11331 $daysdiff = $ord['days'];
11332
11333 // re-read ordersrooms (as rooms may have been switched)
11334 $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;";
11335 $dbo->setQuery($q);
11336 $dbo->execute();
11337 $ordersrooms = $dbo->loadAssocList();
11338
11339 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11340 $opertwounits = true;
11341 $units_counter = array();
11342 foreach ($ordersrooms as $ind => $or) {
11343 if (!isset($units_counter[$or['idroom']])) {
11344 $units_counter[$or['idroom']] = -1;
11345 }
11346 $units_counter[$or['idroom']]++;
11347 }
11348
11349 foreach ($ordersrooms as $ind => $or) {
11350 $num = $ind + 1;
11351 $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'] . ";";
11352 $dbo->setQuery($check);
11353 $dbo->execute();
11354 if ($dbo->getNumRows() > 0) {
11355 $busy = $dbo->loadAssocList();
11356 foreach ($groupdays as $gday) {
11357 $bfound = 0;
11358 foreach ($busy as $bu) {
11359 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11360 $bfound++;
11361 }
11362 }
11363 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11364 $opertwounits = false;
11365 break 2;
11366 }
11367 }
11368 }
11369 }
11370 if ($opertwounits !== true) {
11371 $response['esit'] = 0;
11372 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11373 echo json_encode($response);
11374 exit;
11375 }
11376
11377 // update dates and busy records
11378 $realback = VikBooking::getHoursRoomAvail() * 3600;
11379 $realback += $second;
11380 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11381 $dbo->setQuery($q);
11382 $dbo->execute();
11383 if ($ord['status'] == 'confirmed') {
11384 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11385 $dbo->setQuery($q);
11386 $dbo->execute();
11387 $allbusy = $dbo->loadAssocList();
11388 foreach ($allbusy as $bb) {
11389 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11390 $dbo->setQuery($q);
11391 $dbo->execute();
11392 }
11393 // if automated updates enabled, keep $response['vcm'] empty
11394 // Invoke Channel Manager
11395 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11396 $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>';
11397 }
11398 }
11399 $response['message'] .= JText::translate('RESUPDATED')."\n";
11400 }
11401
11402 if (count($toswitch)) {
11403 /**
11404 * Rooms have changed so the new rates must be re-calculated.
11405 * Maybe they should be calculated in any case, even if just
11406 * the dates have changed. For the moment the rates are reset.
11407 */
11408 }
11409
11410 // unset any previously booked room due to calendar sharing
11411 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11412 // check if some of the rooms booked have shared calendars
11413 VikBooking::updateSharedCalendars($ord['id']);
11414 //
11415
11416 //Booking History
11417 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11418 //
11419
11420 $vcm_autosync = VikBooking::vcmAutoUpdate();
11421 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11422 //unset the vcm property as no buttons should be displayed when in auto-sync
11423 $response['vcm'] = '';
11424 $vcm_obj = VikBooking::getVcmInvoker();
11425 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11426 $sync_result = $vcm_obj->doSync();
11427 if ($sync_result === false) {
11428 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11429 }
11430 }
11431
11432 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11433 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11434 VikError::raiseNotice('', $response['vcm']);
11435 }
11436
11437 $response['message'] = nl2br($response['message']);
11438 echo json_encode($response);
11439 exit;
11440 }
11441
11442 public function modroomrateplans() {
11443 $dbo = JFactory::getDBO();
11444 $session = JFactory::getSession();
11445 $updforvcm = $session->get('vbVcmRatesUpd', '');
11446 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11447 $pid_room = VikRequest::getInt('id_room', '', 'request');
11448 $pid_price = VikRequest::getInt('id_price', '', 'request');
11449 $ptype = VikRequest::getString('type', '', 'request');
11450 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11451 $ptodate = VikRequest::getString('todate', '', 'request');
11452 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11453 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11454 exit;
11455 }
11456 $price_record = array();
11457 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11458 $dbo->setQuery($q);
11459 $dbo->execute();
11460 if ($dbo->getNumRows() > 0) {
11461 $price_record = $dbo->loadAssoc();
11462 }
11463 if (!count($price_record) > 0) {
11464 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11465 exit;
11466 }
11467 $current_closed = array();
11468 if (!empty($price_record['closingd'])) {
11469 $current_closed = json_decode($price_record['closingd'], true);
11470 }
11471 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11472 $start_ts = strtotime($pfromdate);
11473 $end_ts = strtotime($ptodate);
11474 $infostart = getdate($start_ts);
11475 $all_days = array();
11476 $output = array();
11477 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11478 $all_days[] = date('Y-m-d', $infostart[0]);
11479 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11480 $output[$indkey] = array();
11481 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11482 }
11483 if ($ptype == 'close') {
11484 if (!array_key_exists($pid_room, $current_closed)) {
11485 $current_closed[$pid_room] = array();
11486 }
11487 foreach ($all_days as $daymod) {
11488 if (!in_array($daymod, $current_closed[$pid_room])) {
11489 $current_closed[$pid_room][] = $daymod;
11490 }
11491 }
11492 } else {
11493 //open
11494 if (array_key_exists($pid_room, $current_closed)) {
11495 foreach ($all_days as $daymod) {
11496 if (in_array($daymod, $current_closed[$pid_room])) {
11497 foreach ($current_closed[$pid_room] as $ck => $cv) {
11498 if ($daymod == $cv) {
11499 unset($current_closed[$pid_room][$ck]);
11500 }
11501 }
11502 }
11503 }
11504 } else {
11505 $current_closed[$pid_room] = array();
11506 }
11507 }
11508 if (!count($current_closed[$pid_room]) > 0) {
11509 unset($current_closed[$pid_room]);
11510 }
11511 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11512 $dbo->setQuery($q);
11513 $dbo->execute();
11514 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
11515 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
11516 foreach ($output as $ok => $ov) {
11517 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
11518 }
11519 //update session values
11520 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
11521 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
11522 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
11523 } else {
11524 $updforvcm['dfrom'] = $start_ts;
11525 }
11526 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
11527 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
11528 } else {
11529 $updforvcm['dto'] = $end_ts;
11530 }
11531 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
11532 if (!in_array($pid_room, $updforvcm['rooms'])) {
11533 $updforvcm['rooms'][] = $pid_room;
11534 }
11535 } else {
11536 $updforvcm['rooms'] = array($pid_room);
11537 }
11538 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
11539 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
11540 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
11541 $updforvcm['rplans'][$pid_room][] = $pid_price;
11542 }
11543 } else {
11544 $updforvcm['rplans'][$pid_room] = array($pid_price);
11545 }
11546 } else {
11547 $updforvcm['rplans'] = array($pid_room => array($pid_price));
11548 }
11549 $session->set('vbVcmRatesUpd', $updforvcm);
11550 //
11551 $pdebug = VikRequest::getInt('e4j_debug', '', 'request');
11552 if ($pdebug == 1) {
11553 echo "e4j.error.\n".print_r($current_closed, true)."\n";
11554 echo print_r($output, true)."\n\n";
11555 echo print_r($all_days, true)."\n";
11556 }
11557 echo json_encode($output);
11558 exit;
11559 }
11560
11561 public function icsexportlaunch() {
11562 $dbo = JFactory::getDBO();
11563 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11564 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11565 $pstatus = VikRequest::getString('status', '', 'request');
11566 $validstatus = array('confirmed', 'standby', 'cancelled');
11567 $filterstatus = '';
11568 $filterfirst = 0;
11569 $filtersecond = 0;
11570 $nowdf = VikBooking::getDateFormat(true);
11571 if ($nowdf == "%d/%m/%Y") {
11572 $df = 'd/m/Y';
11573 } elseif ($nowdf == "%m/%d/%Y") {
11574 $df = 'm/d/Y';
11575 } else {
11576 $df = 'Y/m/d';
11577 }
11578 $currencyname = VikBooking::getCurrencyName();
11579 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11580 $filterstatus = $pstatus;
11581 }
11582 if (!empty($pcheckindate)) {
11583 if (VikBooking::dateIsValid($pcheckindate)) {
11584 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11585 $filterfirst = $first;
11586 }
11587 }
11588 if (!empty($pcheckoutdate)) {
11589 if (VikBooking::dateIsValid($pcheckoutdate)) {
11590 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11591 if ($second > $first) {
11592 $filtersecond = $second;
11593 }
11594 }
11595 }
11596 $clause = array();
11597 if ($filterfirst > 0) {
11598 $clause[] = "`o`.`checkin` >= ".$filterfirst;
11599 }
11600 if ($filtersecond > 0) {
11601 $clause[] = "`o`.`checkout` <= ".$filtersecond;
11602 }
11603 if (!empty($filterstatus)) {
11604 $clause[] = "`o`.`status` = '".$filterstatus."'";
11605 }
11606 $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;";
11607 $dbo->setQuery($q);
11608 $dbo->execute();
11609 if ($dbo->getNumRows() > 0) {
11610 $orders = $dbo->loadAssocList();
11611 $icscontent = "BEGIN:VCALENDAR\n";
11612 $icscontent .= "VERSION:2.0\n";
11613 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
11614 $icscontent .= "CALSCALE:GREGORIAN\n";
11615 $str = "";
11616 foreach ($orders as $kord => $ord) {
11617 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11618 continue;
11619 }
11620 $usecurrencyname = $currencyname;
11621 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11622 $statusstr = '';
11623 if ($ord['status'] == 'confirmed') {
11624 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11625 } elseif ($ord['status'] == 'standby') {
11626 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11627 } elseif ($ord['status'] == 'cancelled') {
11628 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11629 }
11630 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
11631 /**
11632 * @wponly Rewrite URI for front-end
11633 */
11634 $uri = str_replace(JUri::root(), '', $uri);
11635 $model = JModel::getInstance('vikbooking', 'shortcodes');
11636 $itemid = $model->best('booking');
11637 if ($itemid) {
11638 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
11639 }
11640 //
11641 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
11642 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11643 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
11644 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
11645 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
11646 $str .= "BEGIN:VEVENT\n";
11647 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11648 $str .= "UID:" . uniqid() . "\n";
11649 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11650 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
11651 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
11652 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
11653 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11654 $str .= "END:VEVENT\n";
11655 }
11656 $icscontent .= $str;
11657 $icscontent .= "END:VCALENDAR\n";
11658 //download file from buffer
11659 header("Content-Type: application/octet-stream; ");
11660 header("Cache-Control: no-store, no-cache");
11661 header('Content-Disposition: attachment; filename="bookings_export.ics"');
11662 $f = fopen('php://output', "w");
11663 fwrite($f, $icscontent);
11664 fclose($f);
11665 exit;
11666 } else {
11667 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
11668 $mainframe = JFactory::getApplication();
11669 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11670 }
11671 }
11672
11673 public function csvexportlaunch()
11674 {
11675 $dbo = JFactory::getDbo();
11676 $app = JFactory::getApplication();
11677
11678 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
11679 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
11680 $pchfilt = VikRequest::getString('chfilt', '', 'request');
11681 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
11682 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11683 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11684 $pstatus = VikRequest::getString('status', '', 'request');
11685 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
11686 $pformat = VikRequest::getString('format', 'csv', 'request');
11687
11688 // let the report class (a generic one) generate the CSV file in the proper format
11689 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
11690
11691 $validstatus = array('confirmed', 'standby', 'cancelled');
11692 $validdates = array('ts', 'checkin', 'checkout');
11693
11694 $filterdate = '';
11695 $filterstatus = '';
11696 $first = 0;
11697 $filterfirst = 0;
11698 $filtersecond = 0;
11699 $nowdf = VikBooking::getDateFormat(true);
11700 if ($nowdf == "%d/%m/%Y") {
11701 $df = 'd/m/Y';
11702 } elseif ($nowdf == "%m/%d/%Y") {
11703 $df = 'm/d/Y';
11704 } else {
11705 $df = 'Y/m/d';
11706 }
11707 $datesep = VikBooking::getDateSeparator(true);
11708 $currencyname = VikBooking::getCurrencyName();
11709
11710 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11711 $filterstatus = $pstatus;
11712 }
11713 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
11714 $filterdate = $pdatefilt;
11715 }
11716 if (!empty($pcheckindate) && !empty($filterdate)) {
11717 if (VikBooking::dateIsValid($pcheckindate)) {
11718 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11719 $filterfirst = $first;
11720 }
11721 }
11722 if (!empty($pcheckoutdate) && !empty($filterdate)) {
11723 if (VikBooking::dateIsValid($pcheckoutdate)) {
11724 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11725 if ($second > $first) {
11726 $filtersecond = $second;
11727 }
11728 }
11729 }
11730 $clause = array();
11731 if ($filterfirst > 0) {
11732 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
11733 }
11734 if ($filtersecond > 0) {
11735 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
11736 }
11737 if (!empty($filterstatus)) {
11738 $clause[] = "`o`.`status` = '".$filterstatus."'";
11739 }
11740 if (!empty($pchfilt)) {
11741 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
11742 }
11743 if (!empty($ppayfilt)) {
11744 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
11745 }
11746 if (!empty($proomfilt)) {
11747 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
11748 }
11749
11750 if (!empty($pcatfilt)) {
11751 $room_cat_ids = array();
11752 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
11753 $dbo->setQuery($q);
11754 $dbo->execute();
11755 if ($dbo->getNumRows()) {
11756 $records = $dbo->loadAssocList();
11757 foreach ($records as $rcat) {
11758 $parts = explode(';', $rcat['idcat']);
11759 if (in_array($pcatfilt, $parts)) {
11760 $room_cat_ids[] = $rcat['id'];
11761 }
11762 }
11763 }
11764 if (count($room_cat_ids)) {
11765 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
11766 }
11767 }
11768
11769 $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;";
11770 $dbo->setQuery($q);
11771 $orders = $dbo->loadAssocList();
11772 if (!$orders) {
11773 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
11774 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11775 $app->close();
11776 }
11777
11778 // options
11779 $all_options = array();
11780 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
11781 $dbo->setQuery($q);
11782 $options = $dbo->loadAssocList();
11783 if ($options) {
11784 foreach ($options as $ok => $ov) {
11785 $all_options[$ov['id']] = $ov;
11786 }
11787 }
11788
11789 // set CSV columns
11790 $report_obj->setReportCols([
11791 [
11792 'label' => JText::translate('VBDASHBOOKINGID'),
11793 ],
11794 [
11795 'label' => JText::translate('VBPVIEWORDERSONE'),
11796 ],
11797 [
11798 'label' => JText::translate('VBCSVCHECKIN'),
11799 ],
11800 [
11801 'label' => JText::translate('VBCSVCHECKOUT'),
11802 ],
11803 [
11804 'label' => JText::translate('VBCSVNIGHTS'),
11805 ],
11806 [
11807 'label' => JText::translate('VBCSVROOM'),
11808 ],
11809 [
11810 'label' => JText::translate('VBCSVPEOPLE'),
11811 ],
11812 [
11813 'label' => JText::translate('VBCSVCUSTINFO'),
11814 ],
11815 [
11816 'label' => JText::translate('ORDER_SPREQUESTS'),
11817 ],
11818 [
11819 'label' => JText::translate('ORDER_NOTES'),
11820 ],
11821 [
11822 'label' => JText::translate('VBCSVCREATEDBY'),
11823 ],
11824 [
11825 'label' => JText::translate('VBCSVCUSTMAIL'),
11826 ],
11827 [
11828 'label' => JText::translate('ORDER_PHONE'),
11829 ],
11830 [
11831 'label' => JText::translate('VBCSVOPTIONS'),
11832 ],
11833 [
11834 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
11835 ],
11836 [
11837 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
11838 ],
11839 [
11840 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
11841 ],
11842 [
11843 'label' => JText::translate('VBCSVTOTAL'),
11844 ],
11845 [
11846 'label' => JText::translate('VBCSVTOTPAID'),
11847 ],
11848 [
11849 'label' => JText::translate('VBCSVTOTTAXES'),
11850 ],
11851 ]);
11852
11853 // prepare the container for the CSV rows
11854 $orderscsv = [];
11855
11856 // availability helper
11857 $av_helper = VikBooking::getAvailabilityInstance();
11858
11859 $room_inds = [];
11860 $room_stay_dates = [];
11861 foreach ($orders as $kord => $ord) {
11862 // room index in this booking
11863 if (!isset($room_inds[$ord['id']])) {
11864 $room_inds[$ord['id']] = -1;
11865 }
11866 $room_inds[$ord['id']]++;
11867
11868 /**
11869 * Split stay reservation.
11870 *
11871 * @since 1.16.0 (J) - 1.6.0 (WP)
11872 */
11873 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
11874 if ($ord['split_stay']) {
11875 if ($ord['status'] == 'confirmed') {
11876 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11877 } else {
11878 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
11879 }
11880 // immediately count the number of nights of stay for each split room
11881 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11882 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
11883 // overwrite values for compatibility with non-confirmed bookings
11884 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
11885 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
11886 }
11887 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11888 // overwrite the whole array
11889 $room_stay_dates[$sps_r_k] = $sps_r_v;
11890 }
11891 }
11892
11893 // determine nights and dates for this room booking
11894 $booking_nights = $ord['days'];
11895 $booking_checkin = $ord['checkin'];
11896 $booking_checkout = $ord['checkout'];
11897 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']) {
11898 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
11899 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
11900 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
11901 }
11902
11903 $usecurrencyname = $currencyname;
11904 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11905 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11906 $custinfostr = str_replace(",", " ", $ord['custdata']);
11907 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
11908 if (count($customer)) {
11909 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
11910 }
11911 $special_requests = '';
11912 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11913 $special_requests = $match[1];
11914 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11915 $special_requests = $match[1];
11916 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
11917 $special_requests = $match[1];
11918 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
11919 $special_requests = $match[1];
11920 }
11921 $paystr = '';
11922 if (!empty($ord['idpayment'])) {
11923 $payparts = explode('=', $ord['idpayment']);
11924 $paystr = $payparts[1];
11925 }
11926 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
11927 $statusstr = '';
11928 if ($ord['status'] == 'confirmed') {
11929 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11930 } elseif ($ord['status'] == 'standby') {
11931 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11932 } elseif ($ord['status'] == 'cancelled') {
11933 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11934 }
11935 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
11936 if ($ord['roomsnum'] > 1) {
11937 // take the cost for the individual room
11938 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
11939 }
11940 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
11941 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11942 // total paid will be printed only for the last room booked
11943 $totalpaidstring = '';
11944 }
11945 $options_str = '';
11946 if (!empty($ord['optionals'])) {
11947 $stepo = explode(";", $ord['optionals']);
11948 foreach ($stepo as $roptkey => $oo) {
11949 if (!empty($oo)) {
11950 $stept = explode(":", $oo);
11951 if (array_key_exists($stept[0], $all_options)) {
11952 $actopt = $all_options[$stept[0]];
11953 $optpcent = false;
11954 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
11955 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
11956 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
11957 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
11958 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
11959 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
11960 $agestept = explode('-', $stept[1]);
11961 $stept[1] = $agestept[0];
11962 $chvar = $agestept[1];
11963 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
11964 $optpcent = true;
11965 }
11966 $actopt['chageintv'] = $chvar;
11967 if (isset($optagenames[($chvar - 1)])) {
11968 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
11969 }
11970 if (isset($optagecosts[($chvar - 1)])) {
11971 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
11972 } else {
11973 $realcost = 0;
11974 }
11975 } else {
11976 // VBO 1.11 - options percentage cost of the room total fee
11977 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
11978 //
11979 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
11980 }
11981 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
11982 $realcost=$actopt['maxprice'];
11983 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
11984 $realcost = $actopt['maxprice'] * $stept[1];
11985 }
11986 }
11987 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
11988 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
11989 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
11990 }
11991 }
11992 }
11993 }
11994
11995 // custom extra costs
11996 if (!empty($ord['extracosts'])) {
11997 $cur_extra_costs = json_decode($ord['extracosts'], true);
11998 foreach ($cur_extra_costs as $eck => $ecv) {
11999 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
12000 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
12001 }
12002 }
12003
12004 // taxes
12005 $taxes_str = '';
12006 if ($ord['tot_taxes'] > 0.00) {
12007 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
12008 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
12009 $tax_breakdown = json_decode($ord['breakdown'], true);
12010 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
12011 if (count($tax_breakdown)) {
12012 foreach ($tax_breakdown as $tbkk => $tbkv) {
12013 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
12014 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
12015 }
12016 }
12017 }
12018 }
12019 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
12020 // total taxes will be printed only for the last room booked
12021 $taxes_str = '';
12022 }
12023
12024 // created by
12025 $created_by = '';
12026 if (!empty($ord['ujid'])) {
12027 $creator = new JUser($ord['ujid']);
12028 if (property_exists($creator, 'name')) {
12029 $created_by = $creator->name.' ('.$creator->username.')';
12030 }
12031 }
12032 if (empty($created_by) && !empty($ord['t_first_name'])) {
12033 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
12034 }
12035
12036 // push line for export
12037 $orderscsv[] = [
12038 [
12039 'value' => $ord['id'],
12040 ],
12041 [
12042 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
12043 ],
12044 [
12045 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
12046 ],
12047 [
12048 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
12049 ],
12050 [
12051 'value' => $booking_nights,
12052 ],
12053 [
12054 'value' => $ord['name'],
12055 ],
12056 [
12057 'value' => $peoplestr,
12058 ],
12059 [
12060 'value' => $custinfostr,
12061 ],
12062 [
12063 'value' => $special_requests,
12064 ],
12065 [
12066 'value' => $ord['adminnotes'],
12067 ],
12068 [
12069 'value' => $created_by,
12070 ],
12071 [
12072 'value' => $ord['custmail'],
12073 ],
12074 [
12075 'value' => $ord['phone'],
12076 ],
12077 [
12078 'value' => $options_str,
12079 ],
12080 [
12081 'value' => $paystr,
12082 ],
12083 [
12084 'value' => $ordnumbstr,
12085 ],
12086 [
12087 'value' => $statusstr,
12088 ],
12089 [
12090 'value' => $totalstring,
12091 ],
12092 [
12093 'value' => $totalpaidstring,
12094 ],
12095 [
12096 'value' => $taxes_str,
12097 ],
12098 ];
12099 }
12100
12101 // set CSV rows
12102 $report_obj->setReportRows($orderscsv);
12103
12104 // build lines to export
12105 $csvlines = $report_obj->getExportCSVLines($no_data = true);
12106
12107 // set export file name
12108 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
12109
12110 // force the download of the CSV file
12111 $report_obj->outputHeaders();
12112
12113 // send lines to output
12114 $report_obj->outputCSV($csvlines);
12115
12116 exit;
12117 }
12118
12119 public function exportcustomerslaunch() {
12120 $cid = VikRequest::getVar('cid', array(0));
12121 $dbo = JFactory::getDBO();
12122 $pnotes = VikRequest::getInt('notes', '', 'request');
12123 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12124 $ppin = VikRequest::getInt('pin', '', 'request');
12125 $pcountry = VikRequest::getString('country', '', 'request');
12126 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12127 $ptodate = VikRequest::getString('todate', '', 'request');
12128 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12129 $clauses = array();
12130 if (count($cid) > 0 && !empty($cid[0])) {
12131 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12132 }
12133 if (!empty($pcountry)) {
12134 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12135 }
12136 $datescol = '`bk`.`ts`';
12137 if ($pdatefilt > 0) {
12138 if ($pdatefilt == 1) {
12139 $datescol = '`bk`.`ts`';
12140 } elseif ($pdatefilt == 2) {
12141 $datescol = '`bk`.`checkin`';
12142 } elseif ($pdatefilt == 3) {
12143 $datescol = '`bk`.`checkout`';
12144 }
12145 }
12146 if (!empty($pfromdate)) {
12147 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12148 $clauses[] = $datescol.">=".$from_ts;
12149 }
12150 if (!empty($ptodate)) {
12151 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12152 $clauses[] = $datescol."<=".$to_ts;
12153 }
12154 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12155 $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`,".
12156 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12157 "`cy`.`country_3_code`,`cy`.`country_name` ".
12158 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12159 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12160 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12161 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12162 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` ".
12163 "ORDER BY `c`.`last_name` ASC;";
12164 $dbo->setQuery($q);
12165 $dbo->execute();
12166 if (!($dbo->getNumRows() > 0)) {
12167 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12168 $mainframe = JFactory::getApplication();
12169 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12170 exit;
12171 }
12172 $customers = $dbo->loadAssocList();
12173 $csvlines = array();
12174 $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'));
12175 if ($ppin > 0) {
12176 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12177 }
12178 if ($pscanimg > 0) {
12179 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12180 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12181 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12182 }
12183 if ($pnotes > 0) {
12184 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12185 }
12186 $csvlines[] = $csvheadline;
12187 foreach ($customers as $customer) {
12188 $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']);
12189 if ($ppin > 0) {
12190 $csvcustomerline[] = $customer['pin'];
12191 }
12192 if ($pscanimg > 0) {
12193 $csvcustomerline[] = $customer['doctype'];
12194 $csvcustomerline[] = $customer['docnum'];
12195 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12196 }
12197 if ($pnotes > 0) {
12198 $csvcustomerline[] = $customer['notes'];
12199 }
12200 $csvlines[] = $csvcustomerline;
12201 }
12202 header("Content-type: text/csv");
12203 header("Cache-Control: no-store, no-cache");
12204 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12205 $outstream = fopen("php://output", 'w');
12206 foreach ($csvlines as $csvline) {
12207 fputcsv($outstream, $csvline);
12208 }
12209 fclose($outstream);
12210 exit;
12211 }
12212
12213 public function renewsession() {
12214 /*
12215 * @wponly
12216 * We just destroy the session
12217 */
12218 JSessionHandler::destroy();
12219 $mainframe = JFactory::getApplication();
12220 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12221 }
12222
12223 public function trackings() {
12224 VikBookingHelper::printHeader("trackings");
12225
12226 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12227
12228 parent::display();
12229
12230 if (VikBooking::showFooter()) {
12231 VikBookingHelper::printFooter();
12232 }
12233 }
12234
12235 public function trkconfig() {
12236 VikBookingHelper::printHeader("trackings");
12237
12238 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12239
12240 parent::display();
12241
12242 if (VikBooking::showFooter()) {
12243 VikBookingHelper::printFooter();
12244 }
12245 }
12246
12247 public function savetrkconfigstay() {
12248 if (!JSession::checkToken()) {
12249 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12250 }
12251 $this->do_savetrkconfig(true);
12252 }
12253
12254 public function savetrkconfig() {
12255 if (!JSession::checkToken()) {
12256 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12257 }
12258 $this->do_savetrkconfig();
12259 }
12260
12261 private function do_savetrkconfig($stay = false) {
12262 $dbo = JFactory::getDBO();
12263 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12264 $trkenabled = $trkenabled == 1 ? 1 : 0;
12265 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12266 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12267 $trkcampname = VikRequest::getVar('trkcampname', array());
12268 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12269 $trkcampval = VikRequest::getVar('trkcampval', array());
12270 $trkcampaigns = array();
12271 foreach ($trkcampname as $k => $v) {
12272 if (empty($trkcampkey[$k])) {
12273 continue;
12274 }
12275 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12276 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12277 $trkcampaigns[$trkcampkey[$k]] = array(
12278 'key' => $trkcampkey[$k],
12279 'value' => $trkcampval[$k],
12280 'name' => $name,
12281 );
12282 }
12283
12284 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12285 $dbo->setQuery($q);
12286 $dbo->execute();
12287 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12288 $dbo->setQuery($q);
12289 $dbo->execute();
12290 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12291 $dbo->setQuery($q);
12292 $dbo->execute();
12293
12294 $mainframe = JFactory::getApplication();
12295 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12296 }
12297
12298 public function modtracking() {
12299 $dbo = JFactory::getDbo();
12300 $cid = VikRequest::getVar('cid', array());
12301 foreach ($cid as $id) {
12302 if (!empty($id)) {
12303 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12304 $dbo->setQuery($q);
12305 $dbo->execute();
12306 if ($dbo->getNumRows()) {
12307 $data = $dbo->loadAssoc();
12308 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12309 $dbo->setQuery($q);
12310 $dbo->execute();
12311 }
12312 }
12313 }
12314 $mainframe = JFactory::getApplication();
12315 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12316 }
12317
12318 public function removetrackings() {
12319 $ids = VikRequest::getVar('cid', array());
12320 $dbo = JFactory::getDbo();
12321
12322 foreach ($ids as $d) {
12323 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12324 $dbo->setQuery($q);
12325 $dbo->execute();
12326 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12327 $dbo->setQuery($q);
12328 $dbo->execute();
12329 }
12330
12331 $mainframe = JFactory::getApplication();
12332 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12333 }
12334
12335 /**
12336 * Invokes the Tracker class to obtain
12337 * geo information about the IP addresses.
12338 * This task is called via ajax.
12339 *
12340 * @since 1.11
12341 */
12342 public function getgeoinfo() {
12343 $ips = VikRequest::getVar('ips', array());
12344 if (!count($ips)) {
12345 echo 'e4j.error.empty IPs';
12346 exit;
12347 }
12348
12349 // require the Tracker class without instantiating the object
12350 VikBooking::getTracker(true);
12351 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12352
12353 if ($geo_info === false) {
12354 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12355 exit;
12356 }
12357
12358 // update db values and compose response
12359 $dbo = JFactory::getDbo();
12360 $resp = array();
12361 foreach ($geo_info as $id => $geo) {
12362 if (is_null($geo) || $geo === false) {
12363 continue;
12364 }
12365 // compose geo info string
12366 $geovals = array();
12367 if (!empty($geo['city'])) {
12368 array_push($geovals, $geo['city']);
12369 }
12370 if (!empty($geo['region'])) {
12371 array_push($geovals, $geo['region']);
12372 }
12373 $threecode = '';
12374 $cname = '';
12375 if (!empty($geo['country'])) {
12376 // returned country is a 2-char code, get the 3-char country code
12377 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12378 $dbo->setQuery($q);
12379 $dbo->execute();
12380 if ($dbo->getNumRows()) {
12381 $cinfo = $dbo->loadAssoc();
12382 $threecode = $cinfo['country_3_code'];
12383 $cname = $cinfo['country_name'];
12384 }
12385 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12386 }
12387
12388 // full geo information string
12389 $geoinfostr = implode(', ', $geovals);
12390
12391 // push data to the response pool
12392 $resp[$id] = array();
12393 $resp[$id]['geo'] = $geoinfostr;
12394 if (!empty($cname)) {
12395 $resp[$id]['country'] = $cname;
12396 }
12397 if (!empty($threecode)) {
12398 $resp[$id]['country3'] = $threecode;
12399 }
12400
12401 // update main tracking record
12402 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12403 $dbo->setQuery($q);
12404 $dbo->execute();
12405 }
12406
12407 // output the JSON response
12408 echo json_encode($resp);
12409 exit;
12410 }
12411
12412 /**
12413 * Counts the orphan dates for all published rooms
12414 * depending on their restrictions and booked dates.
12415 * By default, the task takes up to 3 months ahead.
12416 * It is possible to filter the request by rooms and months.
12417 * This task should be called via ajax.
12418 *
12419 * @since 1.11
12420 */
12421 public function orphanscount()
12422 {
12423 $dbo = JFactory::getDbo();
12424 $orphans = array();
12425
12426 $nowdf = VikBooking::getDateFormat();
12427 if ($nowdf == "%d/%m/%Y") {
12428 $df = 'd/m/Y';
12429 } elseif ($nowdf == "%m/%d/%Y") {
12430 $df = 'm/d/Y';
12431 } else {
12432 $df = 'Y/m/d';
12433 }
12434
12435 // global min los
12436 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12437 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12438
12439 // rooms and dates
12440 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12441 $months = VikRequest::getInt('months', 3, 'request');
12442 $from = VikRequest::getString('from', '', 'request');
12443 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12444 if (!empty($from)) {
12445 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12446 if (!empty($fromts)) {
12447 // custom starting date
12448 $today = $fromts;
12449 }
12450 }
12451 $until = strtotime("+{$months} months", $today);
12452
12453 // load all rooms
12454 $rooms = array();
12455 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12456 $dbo->setQuery($q);
12457 $dbo->execute();
12458 if ($dbo->getNumRows()) {
12459 $allrooms = $dbo->loadAssocList();
12460 foreach ($allrooms as $r) {
12461 $rooms[$r['id']] = $r;
12462 }
12463 }
12464 if (!count($rooms)) {
12465 // no rooms found, exit
12466 echo json_encode($orphans);
12467 exit;
12468 }
12469
12470 // load availabilities
12471 $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.");";
12472 $dbo->setQuery($q);
12473 $dbo->execute();
12474 if (!$dbo->getNumRows()) {
12475 // no booked dates found, exit
12476 echo json_encode($orphans);
12477 exit;
12478 }
12479 $busy = $dbo->loadAssocList();
12480
12481 // sort booked dates by room id
12482 $rooms_busy = array();
12483 foreach ($busy as $b) {
12484 if (!isset($rooms_busy[$b['idroom']])) {
12485 $rooms_busy[$b['idroom']] = array();
12486 }
12487 array_push($rooms_busy[$b['idroom']], $b);
12488 }
12489
12490 // load restrictions
12491 $rooms_restr = array();
12492 foreach ($rooms as $rid => $r) {
12493 $restrictions = VikBooking::loadRestrictions(true, array($rid));
12494 if (count($restrictions)) {
12495 $rooms_restr[$rid] = $restrictions;
12496 }
12497 }
12498 if (!count($rooms_restr) && $glob_minlos < 2) {
12499 // no restrictions found and minlos=1, exit
12500 echo json_encode($orphans);
12501 exit;
12502 }
12503
12504 // count availability and minlos per day
12505 $rooms_data = array();
12506 foreach ($rooms as $rid => $r) {
12507 $rooms_data[$rid] = array(
12508 'avail' => array(),
12509 'restr' => array()
12510 );
12511 $nowts = getdate($today);
12512 while ($nowts[0] <= $until) {
12513 $dateind = date('Y-m-d', $nowts[0]);
12514
12515 // remaining availability
12516 if (!isset($rooms_busy[$rid])) {
12517 // no bookings for this room, set full availability for this day
12518 $rooms_data[$rid]['avail'][] = array(
12519 'dt' => $dateind,
12520 'units' => $r['units']
12521 );
12522 } else {
12523 // check remaining availability for this day
12524 $totfound = 0;
12525 foreach ($rooms_busy[$rid] as $b) {
12526 $tmpone = getdate($b['checkin']);
12527 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
12528 $ritts = strtotime($rit);
12529 $tmptwo = getdate($b['checkout']);
12530 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
12531 $conts = strtotime($con);
12532 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
12533 $totfound++;
12534 }
12535 }
12536 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
12537 $rooms_data[$rid]['avail'][] = array(
12538 'dt' => $dateind,
12539 'units' => ($r['units'] - $totfound)
12540 );
12541 }
12542
12543 // restrictions
12544 if (!isset($rooms_restr[$rid])) {
12545 // no restrictions for this room, set global minlos for this day
12546 $rooms_data[$rid]['restr'][] = array(
12547 'dt' => $dateind,
12548 'minlos' => $glob_minlos
12549 );
12550 } else {
12551 // get restriction for this day
12552 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
12553 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12554
12555 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
12556 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
12557
12558 $rooms_data[$rid]['restr'][] = array(
12559 'dt' => $dateind,
12560 'minlos' => $minlos
12561 );
12562 }
12563
12564 // next loop
12565 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12566 $nowts = getdate($dayts);
12567 }
12568 }
12569
12570 // week days and months labels
12571 $days_labels = array(
12572 JText::translate('VBSUNDAY'),
12573 JText::translate('VBMONDAY'),
12574 JText::translate('VBTUESDAY'),
12575 JText::translate('VBWEDNESDAY'),
12576 JText::translate('VBTHURSDAY'),
12577 JText::translate('VBFRIDAY'),
12578 JText::translate('VBSATURDAY')
12579 );
12580 $months_labels = array(
12581 JText::translate('VBMONTHONE'),
12582 JText::translate('VBMONTHTWO'),
12583 JText::translate('VBMONTHTHREE'),
12584 JText::translate('VBMONTHFOUR'),
12585 JText::translate('VBMONTHFIVE'),
12586 JText::translate('VBMONTHSIX'),
12587 JText::translate('VBMONTHSEVEN'),
12588 JText::translate('VBMONTHEIGHT'),
12589 JText::translate('VBMONTHNINE'),
12590 JText::translate('VBMONTHTEN'),
12591 JText::translate('VBMONTHELEVEN'),
12592 JText::translate('VBMONTHTWELVE')
12593 );
12594
12595 // orphan dates calculation method
12596 $calc_method = VikBooking::orphansCalculation();
12597
12598 // parse data and build orphans if any
12599 foreach ($rooms_data as $rid => $data) {
12600 foreach ($data['avail'] as $ind => $av) {
12601 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
12602 // continue, no restriction set or no availability for this day
12603 continue;
12604 }
12605 if ($data['restr'][$ind]['minlos'] < 2) {
12606 // continue, no min los > 1 set for this day
12607 continue;
12608 }
12609 // check if any night after today, until min los, is fully booked
12610 $hasorphans = false;
12611 $forward_count = 0;
12612 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
12613 if (!isset($data['avail'][($ind + $i)])) {
12614 // break loop, no info for this day after
12615 break;
12616 }
12617 if ($data['avail'][($ind + $i)]['units'] > 0) {
12618 // continue, availability found for tomorrow, we need a non available next-day
12619 continue;
12620 }
12621 // orphan found
12622 $hasorphans = true;
12623 $forward_count = $i;
12624 break;
12625 }
12626
12627 /**
12628 * Backward calculation method only if "prevnext".
12629 *
12630 * @since 1.3.0
12631 */
12632 $backward_count = 0;
12633 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
12634 if (!isset($data['avail'][($ind - $i)])) {
12635 // break loop, no info for this prev day
12636 break;
12637 }
12638 if ($data['avail'][($ind - $i)]['units'] > 0) {
12639 // increase free nights going backward
12640 $backward_count++;
12641 }
12642 }
12643 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
12644 // this should not be an orphan date because of enough free days back, or enough free days in between
12645 $hasorphans = false;
12646 }
12647 //
12648
12649 if ($hasorphans) {
12650 // 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
12651 if (!isset($orphans[$rid])) {
12652 $orphans[$rid] = array(
12653 'name' => $rooms[$rid]['name'],
12654 'dates' => array(),
12655 'rdates' => array(),
12656 'linkd' => date($df, strtotime($av['dt']))
12657 );
12658 }
12659 array_push($orphans[$rid]['dates'], $av['dt']);
12660 // build the value for the readable date
12661 $dtinfo = getdate(strtotime($av['dt']));
12662 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
12663 array_push($orphans[$rid]['rdates'], $rdate);
12664 }
12665 }
12666 }
12667
12668 // output response
12669 echo json_encode($orphans);
12670 exit;
12671 }
12672
12673 public function tableaux() {
12674 VikBookingHelper::printHeader("tableaux");
12675
12676 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
12677
12678 parent::display();
12679
12680 if (VikBooking::showFooter()) {
12681 VikBookingHelper::printFooter();
12682 }
12683 }
12684
12685 public function operators() {
12686 VikBookingHelper::printHeader("operators");
12687
12688 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
12689
12690 parent::display();
12691
12692 if (VikBooking::showFooter()) {
12693 VikBookingHelper::printFooter();
12694 }
12695 }
12696
12697 public function newoperator() {
12698 VikBookingHelper::printHeader("operators");
12699
12700 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12701
12702 parent::display();
12703
12704 if (VikBooking::showFooter()) {
12705 VikBookingHelper::printFooter();
12706 }
12707 }
12708
12709 public function editoperator() {
12710 VikBookingHelper::printHeader("operators");
12711
12712 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12713
12714 parent::display();
12715
12716 if (VikBooking::showFooter()) {
12717 VikBookingHelper::printFooter();
12718 }
12719 }
12720
12721 public function updateoperator() {
12722 if (!JSession::checkToken()) {
12723 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12724 }
12725 $this->do_updateoperator();
12726 }
12727
12728 public function updateoperatorstay() {
12729 if (!JSession::checkToken()) {
12730 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12731 }
12732 $this->do_updateoperator(true);
12733 }
12734
12735 private function do_updateoperator($stay = false) {
12736 $dbo = JFactory::getDBO();
12737 $mainframe = JFactory::getApplication();
12738 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12739 $plast_name = VikRequest::getString('last_name', '', 'request');
12740 $pemail = VikRequest::getString('email', '', 'request');
12741 $pphone = VikRequest::getString('phone', '', 'request');
12742 $pcode = VikRequest::getString('code', '', 'request');
12743 $pujid = VikRequest::getInt('ujid', '', 'request');
12744 $pwhere = VikRequest::getInt('where', '', 'request');
12745 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12746 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
12747 $dbo->setQuery($q);
12748 $dbo->execute();
12749 if ($dbo->getNumRows() == 1) {
12750 $customer = $dbo->loadAssoc();
12751 } else {
12752 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12753 exit;
12754 }
12755 $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;";
12756 $dbo->setQuery($q);
12757 $dbo->execute();
12758 if ($dbo->getNumRows() == 0) {
12759 // update fingerprint for the operator
12760 $fingpt = md5($pwhere.$pemail);
12761 //
12762 $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.";";
12763 $dbo->setQuery($q);
12764 $dbo->execute();
12765 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12766 } else {
12767 //email already exists
12768 $ex_operator = $dbo->loadAssoc();
12769 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>');
12770 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12771 exit;
12772 }
12773 } else {
12774 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12775 }
12776 if ($stay) {
12777 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12778 } else {
12779 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12780 }
12781 }
12782
12783 public function saveoperator() {
12784 if (!JSession::checkToken()) {
12785 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12786 }
12787 $dbo = JFactory::getDbo();
12788 $mainframe = JFactory::getApplication();
12789 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12790 $plast_name = VikRequest::getString('last_name', '', 'request');
12791 $pemail = VikRequest::getString('email', '', 'request');
12792 $pphone = VikRequest::getString('phone', '', 'request');
12793 $pcode = VikRequest::getString('code', '', 'request');
12794 $pujid = VikRequest::getInt('ujid', '', 'request');
12795 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12796 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
12797 $dbo->setQuery($q);
12798 $dbo->execute();
12799 if ($dbo->getNumRows() == 0) {
12800 $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).");";
12801 $dbo->setQuery($q);
12802 $dbo->execute();
12803 $lid = $dbo->insertid();
12804 if (!empty($lid)) {
12805 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12806 // generate fingerprint for the operator
12807 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->quote(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
12808 $dbo->setQuery($q);
12809 $dbo->execute();
12810 //
12811 }
12812 } else {
12813 //email already exists
12814 $ex_operator = $dbo->loadAssoc();
12815 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>');
12816 }
12817 } else {
12818 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12819 }
12820 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12821 }
12822
12823 public function removeoperators() {
12824 if (!JSession::checkToken()) {
12825 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12826 }
12827 $ids = VikRequest::getVar('cid', array(0));
12828 if (@count($ids)) {
12829 $dbo = JFactory::getDBO();
12830 foreach ($ids as $d) {
12831 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
12832 $dbo->setQuery($q);
12833 $dbo->execute();
12834 }
12835 }
12836 $mainframe = JFactory::getApplication();
12837 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12838 }
12839
12840 public function operatorperms() {
12841 $dbo = JFactory::getDbo();
12842 $permtype = VikRequest::getString('permtype', 'tableaux', 'request');
12843 $permschanged = 0;
12844
12845 if ($permtype == 'tableaux') {
12846 $oper_id = VikRequest::getVar('oper_id', array());
12847 $oper_days = VikRequest::getVar('oper_days', array());
12848 $oper_rooms = VikRequest::getVar('oper_rooms', array());
12849 $oper_guestname = VikRequest::getVar('oper_guestname', array());
12850 $oper_roomextras = VikRequest::getVar('oper_roomextras', array());
12851 $oper_rm = VikRequest::getVar('oper_rm', array());
12852 if (count($oper_rm)) {
12853 // remove permissions first
12854 foreach ($oper_rm as $operatorid) {
12855 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$operatorid.";";
12856 $dbo->setQuery($q);
12857 $dbo->execute();
12858 if ($dbo->getNumRows()) {
12859 $current = $dbo->loadAssoc();
12860 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12861 $perms = !is_array($perms) ? array() : $perms;
12862 foreach ($perms as $kp => $perm) {
12863 if (isset($perm['type']) && $perm['type'] == $permtype) {
12864 unset($perms[$kp]);
12865 break;
12866 }
12867 }
12868 // update permissions for this operator
12869 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12870 $dbo->setQuery($q);
12871 $dbo->execute();
12872 $permschanged++;
12873 }
12874 }
12875 }
12876 foreach ($oper_id as $k => $v) {
12877 if (empty($v) || !isset($oper_days[$k])) {
12878 // missing data
12879 continue;
12880 }
12881 // get operator
12882 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$v.";";
12883 $dbo->setQuery($q);
12884 $dbo->execute();
12885 if (!$dbo->getNumRows()) {
12886 continue;
12887 }
12888 $current = $dbo->loadAssoc();
12889 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12890 $perms = !is_array($perms) ? array() : $perms;
12891 foreach ($perms as $kp => $perm) {
12892 if (isset($perm['type']) && $perm['type'] == $permtype) {
12893 unset($perms[$kp]);
12894 break;
12895 }
12896 }
12897 // push new permission
12898 array_push($perms, array(
12899 'type' => $permtype,
12900 'perms' => array(
12901 'days' => (int)$oper_days[$k],
12902 'rooms' => (isset($oper_rooms[$k]) && is_array($oper_rooms[$k]) ? $oper_rooms[$k] : array()),
12903 'guestname' => (isset($oper_guestname[$k]) && (int)$oper_guestname[$k] > 0 ? 1 : 0),
12904 'roomextras' => (isset($oper_roomextras[$k]) && (int)$oper_roomextras[$k] > 0 ? 1 : 0),
12905 )
12906 ));
12907 // update permissions for this operator
12908 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12909 $dbo->setQuery($q);
12910 $dbo->execute();
12911 $permschanged++;
12912 }
12913 }
12914
12915 $mainframe = JFactory::getApplication();
12916 if ($permschanged > 0) {
12917 $mainframe->enqueueMessage(JText::translate('VBOPERMSUPDOPEROK'));
12918 }
12919 $mainframe->redirect("index.php?option=com_vikbooking&task=".$permtype);
12920 }
12921
12922 public function canceloperator() {
12923 $mainframe = JFactory::getApplication();
12924 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12925 }
12926
12927 public function cancelcrons() {
12928 $mainframe = JFactory::getApplication();
12929 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
12930 }
12931
12932 public function cancelpackages() {
12933 $mainframe = JFactory::getApplication();
12934 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
12935 }
12936
12937 public function cancelcustomer() {
12938 $mainframe = JFactory::getApplication();
12939 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
12940 if (!empty($pgoto)) {
12941 $mainframe->redirect(base64_decode($pgoto));
12942 exit;
12943 }
12944 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12945 }
12946
12947 public function cancelbusyvcm() {
12948 $mainframe = JFactory::getApplication();
12949 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
12950 }
12951
12952 public function cancelrestriction() {
12953 $mainframe = JFactory::getApplication();
12954 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
12955 }
12956
12957 public function cancelcoupon() {
12958 $mainframe = JFactory::getApplication();
12959 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
12960 }
12961
12962 public function cancelcustomf() {
12963 $mainframe = JFactory::getApplication();
12964 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
12965 }
12966
12967 public function cancelpayment() {
12968 $mainframe = JFactory::getApplication();
12969 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
12970 }
12971
12972 public function cancelseason() {
12973 $mainframe = JFactory::getApplication();
12974 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
12975 }
12976
12977 public function goconfig() {
12978 $mainframe = JFactory::getApplication();
12979 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12980 }
12981
12982 public function canceledorder() {
12983 $pgoto = VikRequest::getString('goto', 'orders', 'request');
12984 $mainframe = JFactory::getApplication();
12985 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
12986 }
12987
12988 public function cancelbusy() {
12989 $pidorder = VikRequest::getString('idorder', '', 'request');
12990 $pgoto = VikRequest::getString('goto', '', 'request');
12991 $mainframe = JFactory::getApplication();
12992 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
12993 }
12994
12995 public function canceloverv() {
12996 $mainframe = JFactory::getApplication();
12997 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
12998 }
12999
13000 public function canceltableaux() {
13001 $mainframe = JFactory::getApplication();
13002 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
13003 }
13004
13005 public function cancelcalendar() {
13006 $pidroom = VikRequest::getString('idroom', '', 'request');
13007 $mainframe = JFactory::getApplication();
13008 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
13009 }
13010
13011 public function canceloptionals() {
13012 $mainframe = JFactory::getApplication();
13013 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
13014 }
13015
13016 public function cancel() {
13017 $mainframe = JFactory::getApplication();
13018 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
13019 }
13020
13021 public function cancelcarat() {
13022 $mainframe = JFactory::getApplication();
13023 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
13024 }
13025
13026 public function cancelcat() {
13027 $mainframe = JFactory::getApplication();
13028 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
13029 }
13030
13031 public function cancelprice() {
13032 $mainframe = JFactory::getApplication();
13033 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
13034 }
13035
13036 public function canceliva() {
13037 $mainframe = JFactory::getApplication();
13038 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
13039 }
13040
13041 public function canceltrk() {
13042 $mainframe = JFactory::getApplication();
13043 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
13044 }
13045
13046 public function canceldash() {
13047 $mainframe = JFactory::getApplication();
13048 $mainframe->redirect("index.php?option=com_vikbooking");
13049 }
13050
13051 public function cancelinvoice() {
13052 $mainframe = JFactory::getApplication();
13053 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
13054 if (!empty($pgoto)) {
13055 $mainframe->redirect(base64_decode($pgoto));
13056 exit;
13057 }
13058 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
13059 }
13060
13061 /**
13062 * AJAX upload the customer documents.
13063 *
13064 * @return void
13065 *
13066 * @throws Exception
13067 */
13068 public function upload_customer_document()
13069 {
13070 $input = JFactory::getApplication()->input;
13071 $dbo = JFactory::getDbo();
13072
13073 $customer_id = $input->getUint('customer', 0);
13074
13075 $result = new stdClass;
13076 $result->status = 0;
13077
13078 try
13079 {
13080 $q = $dbo->getQuery(true)
13081 ->select($dbo->qn(array(
13082 'id',
13083 'first_name',
13084 'last_name',
13085 'email',
13086 'docsfolder',
13087 )))
13088 ->from($dbo->qn('#__vikbooking_customers'))
13089 ->where($dbo->qn('id') . ' = ' . $customer_id);
13090
13091 $dbo->setQuery($q, 0, 1);
13092 $dbo->execute();
13093
13094 if (!$dbo->getNumRows())
13095 {
13096 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13097 }
13098
13099 $customer = $dbo->loadObject();
13100
13101 // fetch documents folder path
13102 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
13103
13104 // check if we have a valid directory
13105 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
13106 {
13107 // randomize string
13108 $customer->seed = uniqid();
13109
13110 // create blocks for hashed folder
13111 $parts = [
13112 $customer->first_name,
13113 $customer->last_name,
13114 md5(serialize($customer)),
13115 ];
13116
13117 // join fetched parts
13118 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13119
13120 if (strlen($customer->docsfolder) < 16)
13121 {
13122 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13123 }
13124
13125 jimport('joomla.filesystem.folder');
13126
13127 // create a folder for this customer
13128 $created = JFolder::create($dirpath . $customer->docsfolder);
13129
13130 if (!$created)
13131 {
13132 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13133 }
13134
13135 unset($customer->seed);
13136
13137 // update docs folder
13138 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13139 }
13140
13141 // get file from request
13142 $file = $input->files->get('file', array(), 'array');
13143
13144 // try to upload the file
13145 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13146 $result->status = 1;
13147
13148 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13149 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13150 }
13151 catch (Exception $e)
13152 {
13153 $result->error = $e->getMessage();
13154 $result->code = $e->getCode();
13155 }
13156
13157 echo json_encode($result);
13158 exit;
13159 }
13160
13161 /**
13162 * AJAX delete the customer documents.
13163 *
13164 * @return void
13165 *
13166 * @throws Exception
13167 */
13168 public function delete_customer_document()
13169 {
13170 $input = JFactory::getApplication()->input;
13171 $dbo = JFactory::getDbo();
13172
13173 $customer_id = $input->getUint('customer', 0);
13174
13175 $result = new stdClass;
13176 $result->status = 0;
13177
13178 $q = $dbo->getQuery(true)
13179 ->select($dbo->qn('docsfolder'))
13180 ->from($dbo->qn('#__vikbooking_customers'))
13181 ->where($dbo->qn('id') . ' = ' . $customer_id);
13182
13183 $dbo->setQuery($q, 0, 1);
13184 $dbo->execute();
13185
13186 if (!$dbo->getNumRows())
13187 {
13188 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13189 }
13190
13191 $folder = $dbo->loadResult();
13192
13193 if (!$folder)
13194 {
13195 throw new Exception('The customer does not have any documents', 500);
13196 }
13197
13198 $file = $input->getString('file');
13199
13200 if (!$file)
13201 {
13202 throw new Exception('File to remove not specified', 400);
13203 }
13204
13205 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13206
13207 if (!is_file($path))
13208 {
13209 throw new Exception(sprintf('File [%s] not found', $path), 404);
13210 }
13211
13212 jimport('joomla.filesystem.file');
13213
13214 $removed = JFile::delete($path);
13215
13216 echo json_encode(array('status' => (int) $removed));
13217 exit;
13218 }
13219
13220 /**
13221 * AJAX task to invoke a specific report and obtain information.
13222 *
13223 * @since 1.3.0
13224 */
13225 public function get_report_data()
13226 {
13227 $report_name = VikRequest::getString('report_name', '', 'request');
13228 $current_fest = VikRequest::getString('current_fest', '', 'request');
13229 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13230 $current_todate = VikRequest::getString('current_todate', '', 'request');
13231 $step = VikRequest::getString('step', 'weekend', 'request');
13232 $direction = VikRequest::getString('direction', 'load', 'request');
13233 $period = VikRequest::getString('period', 'full', 'request');
13234 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13235 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13236 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13237 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13238 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13239 // idroom can be an array of IDs or just one ID as int/string
13240 $idroom = VikRequest::getVar('idroom', null, 'request');
13241 //
13242
13243 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13244 throw new Exception("Missing request data", 400);
13245 }
13246
13247 // get requested report instance
13248 $report = VikBooking::getReportInstance($report_name);
13249 if (!$report) {
13250 throw new Exception("Report not found", 404);
13251 }
13252
13253 // chart data
13254 if (empty($chart_datatype)) {
13255 $chart_datatype = array(
13256 'type' => 'doughnut',
13257 'depth' => 1,
13258 'keys' => array($krsort),
13259 );
13260 }
13261
13262 // website date format
13263 $df = $report->getDateFormat();
13264
13265 // prepare request params for the report
13266 $rparams = array(
13267 'fromdate' => $current_fromdate,
13268 'todate' => $current_todate,
13269 'period' => $period,
13270 'krsort' => $krsort,
13271 'krorder' => $krorder,
13272 'idroom' => $idroom,
13273 );
13274
13275 // starting dates info and timestamps
13276 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13277 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13278 $from_info = getdate($from_ts);
13279 $to_info = getdate($to_ts);
13280
13281 // the name of the period requested and whether it's a fest
13282 $period_name = '';
13283 $is_fest = null;
13284
13285 if ($direction == 'prev' || $direction == 'next') {
13286 // calculate prev or next dates
13287 if ($step == 'weekend') {
13288 $period_name = JText::translate('VBOWEEKND');
13289 if ($direction == 'next') {
13290 // next weekend from current end date
13291 $next_ts = strtotime("next friday", $to_ts);
13292 } else {
13293 // prev weekend from current start date
13294 $next_ts = strtotime("previous friday", $from_ts);
13295 }
13296 $next_info = getdate($next_ts);
13297 $new_from_ts = $next_ts;
13298 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13299 $rparams['fromdate'] = date($df, $new_from_ts);
13300 $rparams['todate'] = date($df, $new_to_ts);
13301 } elseif ($step == 'week') {
13302 $period_name = JText::translate('VBOWEEK');
13303 if ($direction == 'next') {
13304 // start next week from the current end date
13305 $new_from_ts = $to_ts;
13306 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13307 $rparams['fromdate'] = $rparams['todate'];
13308 $rparams['todate'] = date($df, $new_to_ts);
13309 } else {
13310 // end prev week from the current from date
13311 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13312 $new_to_ts = $from_ts;
13313 $rparams['todate'] = $rparams['fromdate'];
13314 $rparams['fromdate'] = date($df, $new_from_ts);
13315 }
13316 } else {
13317 // month
13318 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13319 if ($direction == 'next') {
13320 // next month from the current from date
13321 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13322 $new_from_ts = $nextmonts;
13323 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13324 $rparams['fromdate'] = date($df, $new_from_ts);
13325 $rparams['todate'] = date($df, $new_to_ts);
13326 } else {
13327 // prev month from the current from date
13328 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13329 $new_from_ts = $nextmonts;
13330 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13331 $rparams['fromdate'] = date($df, $new_from_ts);
13332 $rparams['todate'] = date($df, $new_to_ts);
13333 }
13334 }
13335
13336 // get the next festivities
13337 $fests = VikBooking::getFestivitiesInstance();
13338 $next_fests = $fests->loadFestDates();
13339 if (count($next_fests)) {
13340 // check whether a festivity should be displayed rather than the calculated period of dates
13341 foreach ($next_fests as $fest) {
13342 $fest_found = false;
13343 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13344 $fest_found = true;
13345 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13346 $fest_found = true;
13347 }
13348 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13349 // festivity found before next calculated period
13350 $is_fest = $fest['festinfo'][0]->next_ts;
13351 $period_name = $fest['festinfo'][0]->trans_name;
13352 $new_from_ts = $fest['festinfo'][0]->from_ts;
13353 $new_to_ts = $fest['festinfo'][0]->to_ts;
13354 $rparams['fromdate'] = date($df, $new_from_ts);
13355 $rparams['todate'] = date($df, $new_to_ts);
13356 break;
13357 }
13358 }
13359 }
13360 } else {
13361 // load requested dates by skipping the festivities
13362 $new_from_ts = $from_ts;
13363 $new_to_ts = $to_ts;
13364 }
13365
13366 // invoke report
13367 $report->injectParams($rparams);
13368 $report_values = $report->getReportValues(1);
13369 $report_cols = $report->getColumnsValues();
13370 $report_chart = null;
13371 $report_chart_metas = array();
13372 $chart_meta_data = array(
13373 'keys' => array(
13374 'occupancy',
13375 'tot_bookings',
13376 'nights_booked',
13377 ),
13378 );
13379 $error = null;
13380
13381 if (!count($report_values)) {
13382 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13383 } else {
13384 // get doughnut Chart for the requested key
13385 $report_chart = $report->getChart($chart_datatype);
13386
13387 // get Chart meta data
13388 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13389 if (count($all_chart_metas)) {
13390 // merge all positions into one array
13391 foreach ($all_chart_metas as $pos_metas) {
13392 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13393 }
13394 }
13395
13396 if (empty($period_name)) {
13397 $period_name = $report->getProperty('chartTitle');
13398 }
13399 }
13400
13401 // build response
13402 $response = new stdClass;
13403 $response->error = $error;
13404 $response->fromdate = $rparams['fromdate'];
13405 $response->todate = $rparams['todate'];
13406 $response->in_days = $report->countDaysTo($new_from_ts);
13407 $response->in_days_to = $report->countDaysTo($new_to_ts);
13408 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13409 $response->period_name = $period_name;
13410 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13411 $response->is_fest = $is_fest;
13412 $response->report_chart = $report_chart;
13413 $response->report_cols = $report_cols;
13414 $response->report_values = $report_values;
13415 $response->report_script = $report->getScript();
13416 $response->chart_labels = $report->getProperty('chartJsLabels');
13417 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13418 $response->chart_colors = $report->getProperty('chartJsColors');
13419 $response->chart_data = $report->getProperty('chartJsData');
13420 $response->report_chart_metas = $report_chart_metas;
13421
13422 echo json_encode($response);
13423 exit;
13424 }
13425
13426 /**
13427 * Go to the previous booking.
13428 *
13429 * @uses navigateToBooking()
13430 *
13431 * @since 1.3.0
13432 */
13433 public function prev_booking()
13434 {
13435 $this->navigateToBooking('prev');
13436 }
13437
13438 /**
13439 * Go to the next booking.
13440 *
13441 * @uses navigateToBooking()
13442 *
13443 * @since 1.3.0
13444 */
13445 public function next_booking()
13446 {
13447 $this->navigateToBooking('next');
13448 }
13449
13450 /**
13451 * Given the current booking ID in the request, we navigate
13452 * either to the next or to the previous reservation (if any).
13453 *
13454 * @param string $direction either next or prev.
13455 *
13456 * @return void
13457 *
13458 * @since 1.3.0
13459 */
13460 private function navigateToBooking($direction = 'next')
13461 {
13462 $bid = VikRequest::getInt('whereup', 0, 'request');
13463 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13464 throw new Exception("Invalid request", 400);
13465 }
13466
13467 $dbo = JFactory::getDbo();
13468 $app = JFactory::getApplication();
13469
13470 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13471 $dbo->setQuery($q, 0, 1);
13472 $dbo->execute();
13473 if (!$dbo->getNumRows()) {
13474 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13475 $app->redirect("index.php?option=com_vikbooking&task=orders");
13476 exit;
13477 }
13478
13479 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
13480 exit;
13481 }
13482
13483 /**
13484 * AJAX request: from a list of reservation IDs, we return the ones
13485 * that have a review with the related review ID on VCM.
13486 *
13487 * @since 1.13
13488 */
13489 public function bookings_have_reviews()
13490 {
13491 $dbo = JFactory::getDbo();
13492 $bids = VikRequest::getVar('bids', array(), 'request', 'array');
13493 $vcm_installed = is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php');
13494 $withreviews = array();
13495
13496 if ($vcm_installed && is_array($bids) && count($bids)) {
13497 try {
13498 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
13499 $dbo->setQuery($q);
13500 $dbo->execute();
13501 if ($dbo->getNumRows()) {
13502 $reviews = $dbo->loadAssocList();
13503 foreach ($reviews as $r) {
13504 $withreviews[$r['idorder']] = $r['id'];
13505 }
13506 }
13507 } catch (Exception $e) {
13508 // do nothing, outdated version
13509 }
13510 }
13511
13512 echo json_encode($withreviews);
13513 exit;
13514 }
13515
13516 /**
13517 * AJAX request for adding a new room-day note.
13518 *
13519 * @return void
13520 *
13521 * @since 1.13.5
13522 */
13523 public function add_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 $name = VikRequest::getString('name', '', 'request');
13531 $descr = VikRequest::getString('descr', '', 'request');
13532 $cdays = VikRequest::getInt('cdays', 0, 'request');
13533 $cdays = $cdays < 0 ? 0 : $cdays;
13534 $cdays = $cdays > 365 ? 365 : $cdays;
13535 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
13536 echo 'e4j.error.1';
13537 exit;
13538 }
13539
13540 // reload end date
13541 $end_date = $dt;
13542
13543 // build critical date object
13544 $new_note = array(
13545 'name' => $name,
13546 'type' => $type,
13547 'descr' => $descr,
13548 );
13549
13550 // get object
13551 $notes = VikBooking::getCriticalDatesInstance();
13552
13553 // store the notes for all consecutive dates
13554 for ($i = 0; $i <= $cdays; $i++) {
13555 $store_dt = $dt;
13556 if ($i > 0) {
13557 $dt_info = getdate(strtotime($store_dt));
13558 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
13559 $end_date = $store_dt;
13560 }
13561 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
13562 if (!$result) {
13563 echo 'e4j.error.2';
13564 exit;
13565 }
13566 }
13567
13568 // reload all room day notes for this day for the AJAX response
13569 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
13570
13571 if (!$all_notes || !count($all_notes)) {
13572 // no notes found even after storing it
13573 echo 'e4j.error.3';
13574 exit;
13575 }
13576
13577 echo json_encode($all_notes);
13578 exit;
13579 }
13580
13581 /**
13582 * AJAX request for removing a room day note.
13583 *
13584 * @return void
13585 *
13586 * @since 1.13.5
13587 */
13588 public function remove_roomdaynote()
13589 {
13590 $dt = VikRequest::getString('dt', '', 'request');
13591 $idroom = VikRequest::getInt('idroom', 0, 'request');
13592 $subunit = VikRequest::getInt('subunit', 0, 'request');
13593 $type = VikRequest::getString('type', '', 'request');
13594 $type = empty($type) ? 'custom' : $type;
13595 $ind = VikRequest::getInt('ind', 0, 'request');
13596 if (empty($dt) || !strtotime($dt)) {
13597 echo 'e4j.error.1';
13598 exit;
13599 }
13600
13601 $notes = VikBooking::getCriticalDatesInstance();
13602 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
13603 if (!$result) {
13604 echo 'e4j.error.2';
13605 exit;
13606 }
13607
13608 echo 'e4j.ok';
13609 exit;
13610 }
13611
13612 /**
13613 * AJAX request for storing an event for a booking.
13614 * Firstly developed for the VCM Reporting API - Guest Misconduct,
13615 * but it can be used for any other purpose.
13616 *
13617 * @return void
13618 *
13619 * @since 1.13.5
13620 */
13621 public function store_booking_history_event()
13622 {
13623 $bid = VikRequest::getInt('bid', 0, 'request');
13624 $event = VikRequest::getString('event', '', 'request');
13625 $descr = VikRequest::getString('descr', '', 'request');
13626
13627 if (empty($bid) || empty($event)) {
13628 throw new Exception("Missing required information", 500);
13629 }
13630
13631 // Booking History
13632 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
13633 //
13634
13635 echo 'e4j.ok';
13636 exit;
13637 }
13638
13639 /**
13640 * AJAX request for updating an option/extra service.
13641 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
13642 * but it can be used for any other purpose.
13643 *
13644 * @return void
13645 *
13646 * @since 1.13.5
13647 */
13648 public function update_option_params()
13649 {
13650 $optid = VikRequest::getInt('optid', 0, 'request');
13651 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
13652
13653 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
13654 throw new Exception("Missing required information", 500);
13655 }
13656
13657 $dbo = JFactory::getDbo();
13658 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
13659 $dbo->setQuery($q);
13660 $dbo->execute();
13661 if (!$dbo->getNumRows()) {
13662 throw new Exception("Option not found", 404);
13663 }
13664 $cur_params = $dbo->loadResult();
13665 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
13666 $cur_params = !is_array($cur_params) ? array() : $cur_params;
13667
13668 foreach ($oparams as $k => $v) {
13669 if (empty($k)) {
13670 continue;
13671 }
13672 $cur_params[$k] = $v;
13673 }
13674
13675 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
13676 $dbo->setQuery($q);
13677 $dbo->execute();
13678
13679 echo 'e4j.ok';
13680 exit;
13681 }
13682
13683 /**
13684 * Hidden task to clean up duplicate records in certain database tables
13685 * due to a double execution of the installation queries. Ghost records,
13686 * if any, are also removed to clean up issues with hanging records.
13687 *
13688 * @since November 4th 2020
13689 * @since 1.16.3 (J) - 1.6.3 (WP)
13690 */
13691 public function clean_duplicate_records()
13692 {
13693 $dbo = JFactory::getDbo();
13694
13695 $tables_with_duplicates = [
13696 '#__vikbooking_config' => [
13697 'id_key' => 'id',
13698 'compare_key' => 'param',
13699 ],
13700 '#__vikbooking_countries' => [
13701 'id_key' => 'id',
13702 'compare_key' => 'country_3_code',
13703 ],
13704 '#__vikbooking_custfields' => [
13705 'id_key' => 'id',
13706 'compare_key' => 'name',
13707 ],
13708 '#__vikbooking_texts' => [
13709 'id_key' => 'id',
13710 'compare_key' => 'param',
13711 ],
13712 ];
13713
13714 foreach ($tables_with_duplicates as $tblname => $data) {
13715 $doubles = [];
13716 $storage = [];
13717 $rmlist = [];
13718
13719 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
13720 $dbo->setQuery($q);
13721 $rows = $dbo->loadAssocList();
13722 if (!$rows) {
13723 echo "<p>No records found in table {$tblname}</p>";
13724 continue;
13725 }
13726
13727 foreach ($rows as $row) {
13728 if (!isset($doubles[$row[$data['compare_key']]])) {
13729 $doubles[$row[$data['compare_key']]] = 0;
13730 }
13731 $doubles[$row[$data['compare_key']]]++;
13732 if (!isset($storage[$row[$data['compare_key']]])) {
13733 $storage[$row[$data['compare_key']]] = [];
13734 }
13735 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
13736 }
13737
13738 foreach ($doubles as $paramkey => $paramcount) {
13739 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
13740 continue;
13741 }
13742 $exceeding = $paramcount - 1;
13743 for ($x = 0; $x < $exceeding; $x++) {
13744 array_push($rmlist, $storage[$paramkey][$x]);
13745 }
13746 }
13747
13748 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
13749 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
13750 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
13751
13752 if (count($rmlist)) {
13753 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
13754 $dbo->setQuery($q);
13755 $dbo->execute();
13756 }
13757 }
13758
13759 /**
13760 * Clean up busy records where the busy relations contain empty booking IDs.
13761 */
13762 $hanging_busy_ids = [];
13763
13764 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
13765 $dbo->setQuery($q);
13766 $removelist = $dbo->loadAssocList();
13767 if ($removelist) {
13768 foreach ($removelist as $hanging_busy) {
13769 $hanging_busy_id = (int)$hanging_busy['idbusy'];
13770 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13771 array_push($hanging_busy_ids, $hanging_busy_id);
13772 }
13773 }
13774 }
13775
13776 // let's check also for ghost records that only occupy the room
13777 $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);";
13778 $dbo->setQuery($q);
13779 $removelist = $dbo->loadAssocList();
13780 if ($removelist) {
13781 foreach ($removelist as $hanging_busy) {
13782 $hanging_busy_id = (int)$hanging_busy['id'];
13783 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13784 array_push($hanging_busy_ids, $hanging_busy_id);
13785 }
13786 }
13787 }
13788
13789 if ($hanging_busy_ids) {
13790 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
13791 $dbo->setQuery($q);
13792 $dbo->execute();
13793 }
13794
13795 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
13796
13797 return;
13798 }
13799
13800 /**
13801 * Loads a specific admin widget ID and executes the requested method.
13802 * Useful for loading a newly added widget, or to execute custom methods.
13803 *
13804 * @see this is an AJAX endpoint.
13805 *
13806 * @since 1.14 (J) - 1.4.0 (WP)
13807 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
13808 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
13809 */
13810 public function exec_admin_widget()
13811 {
13812 if (!JSession::checkToken()) {
13813 // missing CSRF-proof token
13814 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13815 }
13816
13817 $widget_id = VikRequest::getString('widget_id', '', 'request');
13818 $call = VikRequest::getString('call', '', 'request');
13819 $return = VikRequest::getInt('return', 0, 'request');
13820 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
13821 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
13822 $multitask = VikRequest::getInt('multitask', 0, 'request');
13823
13824 if (empty($widget_id)) {
13825 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
13826 }
13827
13828 if (empty($call) || !is_string($call)) {
13829 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
13830 }
13831
13832 // invoke admin widgets helper
13833 $widgets_helper = VikBooking::getAdminWidgetsInstance();
13834 $widget = $widgets_helper->getWidget($widget_id);
13835
13836 if ($widget === false) {
13837 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
13838 }
13839
13840 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
13841 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
13842 }
13843
13844 // get the multitask parser object
13845 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
13846
13847 // check if arguments should be passed
13848 $call_args = [];
13849 if ($multitask && $call === 'render') {
13850 // build the multitask data object and inject it to the args as the first index
13851 $call_args[] = $parser->getData();
13852
13853 // bind options within the widget, if any
13854 $widget->bindOptions($call_args[0]);
13855 } else {
13856 // always bind multitask options, if any
13857 $widget->bindOptions($parser->getOptions());
13858 }
13859
13860 try {
13861 if ($return) {
13862 // invoke the widget's method and get the value returned
13863 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
13864 } else {
13865 // invoke the widget's method within a buffer
13866 ob_start();
13867 if ($call_args) {
13868 $res = call_user_func_array([$widget, $call], $call_args);
13869 } else {
13870 $widget->{$call}();
13871 }
13872 $widget_response = ob_get_contents();
13873 ob_end_clean();
13874 }
13875 } catch (Throwable $e) {
13876 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
13877 } catch (Exception $e) {
13878 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
13879 }
13880
13881 // prepare response object with a property equal to the called method
13882 $response = new stdClass;
13883 $response->{$call} = $widget_response;
13884
13885 // output the JSON encoded response and exit
13886 VBOHttpDocument::getInstance()->json($response);
13887 }
13888
13889 /**
13890 * Updates the map of admin widgets.
13891 *
13892 * @throws Exception this is an AJAX endpoint.
13893 *
13894 * @since 1.4.0
13895 */
13896 public function save_admin_widgets()
13897 {
13898 if (!JSession::checkToken()) {
13899 // missing CSRF-proof token
13900 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13901 }
13902
13903 // make sure permissions are sufficient
13904 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
13905 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
13906 }
13907
13908 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
13909 if (!is_array($psections) || !count($psections)) {
13910 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
13911 }
13912
13913 // request values are all converted to arrays, so restore the object styling
13914 $psections = json_decode(json_encode($psections));
13915
13916 // update map
13917 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
13918
13919 $response = new stdClass;
13920 $response->status = (int)$result;
13921
13922 // output the JSON encoded response and exit
13923 VBOHttpDocument::getInstance()->json($response);
13924 }
13925
13926 /**
13927 * Restores the default admin widgets map.
13928 *
13929 * @since 1.4.0
13930 */
13931 public function reset_admin_widgets()
13932 {
13933 // reset map and redirect to dashboard
13934 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
13935
13936 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
13937 exit;
13938 }
13939
13940 /**
13941 * Updates the welcome message status for the widget's customizer via AJAX.
13942 *
13943 * @since 1.4.0
13944 */
13945 public function admin_widgets_welcome()
13946 {
13947 if (!JSession::checkToken()) {
13948 // missing CSRF-proof token
13949 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13950 }
13951
13952 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
13953 // update configuration value
13954 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
13955
13956 $response = new stdClass;
13957 $response->status = $hide_welcome;
13958
13959 // output the JSON encoded response and exit
13960 VBOHttpDocument::getInstance()->json($response);
13961 }
13962
13963 public function newcondtext()
13964 {
13965 VikBookingHelper::printHeader("11");
13966
13967 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13968
13969 parent::display();
13970
13971 if (VikBooking::showFooter()) {
13972 VikBookingHelper::printFooter();
13973 }
13974 }
13975
13976 public function editcondtext()
13977 {
13978 VikBookingHelper::printHeader("11");
13979
13980 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13981
13982 parent::display();
13983
13984 if (VikBooking::showFooter()) {
13985 VikBookingHelper::printFooter();
13986 }
13987 }
13988
13989 public function cancelcondtext()
13990 {
13991 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
13992 }
13993
13994 public function createcondtext()
13995 {
13996 if (!JSession::checkToken()) {
13997 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13998 }
13999 $this->_doCreateCondText();
14000 }
14001
14002 public function createcondtextstay()
14003 {
14004 if (!JSession::checkToken()) {
14005 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14006 }
14007 $this->_doCreateCondText(true);
14008 }
14009
14010 private function _doCreateCondText($stay = false)
14011 {
14012 $dbo = JFactory::getDbo();
14013 $app = JFactory::getApplication();
14014 $rules_helper = VikBooking::getConditionalRulesInstance();
14015 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14016
14017 $condtextname = VikRequest::getString('condtextname', '', 'request');
14018 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14019 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14020 $debug = VikRequest::getInt('debug', 0, 'request');
14021 if (empty($condtextname)) {
14022 $condtextname = date('Y-m-dHis');
14023 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14024 }
14025
14026 $existing_tokens = $rules_helper->getSpecialTags();
14027 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
14028 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
14029 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
14030 exit;
14031 }
14032
14033 $data = new stdClass;
14034 $data->name = $condtextname;
14035 $data->token = $condtexttkn;
14036 $data->rules = json_encode($rules_list);
14037 $data->msg = $msg;
14038 $data->lastupd = JDate::getInstance()->toSql();
14039 $data->debug = $debug;
14040
14041 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
14042
14043 if (isset($data->id)) {
14044 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14045 }
14046
14047 if (!$stay || !isset($data->id)) {
14048 $this->cancelcondtext();
14049 exit;
14050 }
14051
14052 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14053 }
14054
14055 public function updatecondtext()
14056 {
14057 if (!JSession::checkToken()) {
14058 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14059 }
14060 $this->_doUpdateCondText();
14061 }
14062
14063 public function updatecondtextstay()
14064 {
14065 if (!JSession::checkToken()) {
14066 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
14067 }
14068 $this->_doUpdateCondText(true);
14069 }
14070
14071 private function _doUpdateCondText($stay = false)
14072 {
14073 $dbo = JFactory::getDbo();
14074 $app = JFactory::getApplication();
14075 $rules_helper = VikBooking::getConditionalRulesInstance();
14076 $rules_list = $rules_helper->composeRulesParamsFromRequest();
14077
14078 $pwhere = VikRequest::getInt('where', '', 'request');
14079 $condtextname = VikRequest::getString('condtextname', '', 'request');
14080 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
14081 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
14082 $debug = VikRequest::getInt('debug', 0, 'request');
14083 if (empty($condtextname)) {
14084 $condtextname = date('Y-m-dHis');
14085 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
14086 }
14087
14088 $existing_tokens = $rules_helper->getSpecialTags();
14089 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
14090 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
14091 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
14092 exit;
14093 }
14094
14095 $data = new stdClass;
14096 $data->id = $pwhere;
14097 $data->name = $condtextname;
14098 $data->token = $condtexttkn;
14099 $data->rules = json_encode($rules_list);
14100 $data->msg = $msg;
14101 $data->lastupd = JDate::getInstance()->toSql();
14102 $data->debug = $debug;
14103
14104 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
14105
14106 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
14107
14108 if (!$stay) {
14109 $this->cancelcondtext();
14110 exit;
14111 }
14112
14113 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14114 }
14115
14116 public function removecondtext()
14117 {
14118 $dbo = JFactory::getDbo();
14119 $ids = VikRequest::getVar('cid', array());
14120
14121 VikBooking::getConditionalRulesInstance(true);
14122 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14123
14124 foreach ($ids as $d) {
14125 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14126 $dbo->setQuery($q);
14127 $dbo->execute();
14128 if (!$dbo->getNumRows()) {
14129 continue;
14130 }
14131 $special_tag = $dbo->loadResult();
14132
14133 // remove the token from each template file if it was used before
14134 if (!empty($special_tag)) {
14135 // remove token from all template files
14136 foreach ($templates as $tkey => $tpath) {
14137 // get requested file content
14138 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14139 if (empty($fcontent) || !is_string($fcontent)) {
14140 break;
14141 }
14142 // remove tag from code content
14143 $fcontent = str_replace($special_tag, '', $fcontent);
14144 // update the file code
14145 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14146 }
14147 }
14148
14149 // delete the record
14150 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14151 $dbo->setQuery($q);
14152 $dbo->execute();
14153 }
14154
14155 $this->cancelcondtext();
14156 }
14157
14158 /**
14159 * AJAX endpoint to update one template file with the given tag or styles.
14160 * A JSON response will be echoed by exiting the process.
14161 */
14162 public function condtext_update_tmpl()
14163 {
14164 VikBooking::getConditionalRulesInstance(true);
14165
14166 $tagaction = VikRequest::getString('tagaction', '', 'request');
14167 $tag = VikRequest::getString('tag', '', 'request');
14168 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14169 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14170 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14171
14172 $allowed_actions = array(
14173 'add',
14174 'remove',
14175 'styles',
14176 'restore',
14177 );
14178
14179 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14180 throw new Exception("Invalid request submitted", 500);
14181 }
14182
14183 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14184 throw new Exception("Invalid request submitted - missing tag", 500);
14185 }
14186
14187 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14188 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14189 }
14190
14191 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14192 throw new Exception("No custom CSS classes to parse", 500);
14193 }
14194
14195 if ($tagaction == 'restore') {
14196 // immediately restore the requested file to avoid script interruptions
14197 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14198 }
14199
14200 // get requested file content
14201 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14202 if (empty($fcontent) || !is_string($fcontent)) {
14203 throw new Exception("File not found or its code is unreadable", 404);
14204 }
14205
14206 if ($tagaction == 'remove') {
14207 // remove tag from code content
14208 $fcontent = str_replace($tag, '', $fcontent);
14209 } elseif ($tagaction == 'add') {
14210 // add tag to code content in the same exact position
14211 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14212 } elseif ($tagaction == 'styles') {
14213 // apply the same styling rules
14214 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14215 }
14216
14217 // update the file code
14218 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14219
14220 if (!$res) {
14221 throw new Exception("Could not update the source code of the template file", 500);
14222 }
14223
14224 // parse new HTML content
14225 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14226 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14227 throw new Exception("Could not parse new template file content", 404);
14228 }
14229
14230 // trigger backup/mirroring, if available
14231 if (VBOPlatformDetection::isWordPress()) {
14232 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14233 }
14234
14235 // build output
14236 $output = new stdClass;
14237 $output->newhtml = $newhtmls[$file];
14238 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14239
14240 echo json_encode($output);
14241 exit;
14242 }
14243
14244 /**
14245 * AJAX endpoint to invoke methods of the geocoding helper.
14246 */
14247 public function geocoding_endpoint()
14248 {
14249 $geo = VikBooking::getGeocodingInstance();
14250 $callback = VikRequest::getString('callback', '', 'request');
14251
14252 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14253 throw new Exception("Callback not available", 403);
14254 }
14255
14256 // invoke requested method
14257 $res = $geo->{$callback}();
14258
14259 // prepare response
14260 $response = new stdClass;
14261 $response->{$callback} = $res;
14262
14263 echo json_encode($response);
14264 exit;
14265 }
14266
14267 public function refundtn()
14268 {
14269 //modal box, so we do not set menu or footer
14270
14271 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14272
14273 parent::display();
14274 }
14275
14276 public function do_refundtn()
14277 {
14278 $dbo = JFactory::getDbo();
14279 $app = JFactory::getApplication();
14280
14281 $bid = VikRequest::getInt('bid', 0, 'request');
14282 $amount = VikRequest::getFloat('amount', 0, 'request');
14283 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14284 $tmpl = VikRequest::getString('tmpl', '', 'request');
14285 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14286
14287 $currencysymb = VikBooking::getCurrencySymb();
14288
14289 if (empty($bid) || $amount <= 0) {
14290 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14291 $app->redirect('index.php?option=com_vikbooking');
14292 exit;
14293 }
14294
14295 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14296 $dbo->setQuery($q);
14297 $dbo->execute();
14298 if ($dbo->getNumRows() < 1) {
14299 VikError::raiseWarning('', 'Booking not found');
14300 $app->redirect('index.php?option=com_vikbooking');
14301 exit;
14302 }
14303 $row = $dbo->loadAssoc();
14304
14305 // get booking history instance
14306 $history_obj = VikBooking::getBookingHistoryInstance();
14307 $history_obj->setBid($row['id']);
14308
14309 // get payment information
14310 $payment = VikBooking::getPayment($row['idpayment']);
14311 $tn_driver = is_array($payment) ? $payment['file'] : null;
14312
14313 // transaction data validation callback
14314 $tn_data_callback = function($data) use ($tn_driver) {
14315 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14316 };
14317 // get previous transactions
14318 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14319
14320 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14321 // no previous transactions found
14322 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14323 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14324 exit;
14325 }
14326
14327 // push refund information for the payment gateway
14328 $row['total_to_refund'] = $amount;
14329 $row['transaction'] = $prev_tn_data;
14330 $row['refund_reason'] = $refund_reason;
14331
14332 // push the transaction currency information
14333 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14334
14335 /**
14336 * @wponly The payment gateway is loaded
14337 * through the apposite dispatcher.
14338 */
14339 JLoader::import('adapter.payment.dispatcher');
14340 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14341
14342 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14343 // refund not supported
14344 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14345 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14346 exit;
14347 }
14348
14349 // perform the refund transaction
14350 $array_result = $obj->refund();
14351
14352 if ($array_result['verified'] != 1) {
14353 // raise warning by getting the message
14354 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14355 VikError::raiseWarning('', $array_result['log']);
14356 } else {
14357 VikError::raiseWarning('', 'Operation failed');
14358 }
14359 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14360 exit;
14361 }
14362
14363 /**
14364 * New payment plugins can return the total amount refunded ('tot_paid').
14365 *
14366 * @since 1.15.4 (J) - 1.5.10 (WP)
14367 */
14368 if (!empty($array_result['tot_paid'])) {
14369 // overwrite the requested amount with the returned one
14370 $amount = (float)$array_result['tot_paid'];
14371 }
14372
14373 // update total paid, total and refund columns for the booking
14374 $booking = new stdClass;
14375 $booking->id = $row['id'];
14376 if ($row['totpaid'] > 0) {
14377 $booking->totpaid = $row['totpaid'] - $amount;
14378 }
14379 if ($row['total'] > 0) {
14380 $booking->total = $row['total'] - $amount;
14381 }
14382 $booking->refund = (float)$row['refund'] + $amount;
14383 // update record in db
14384 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
14385
14386 // store the refund event
14387 $event_descr = array(
14388 '(' . $payment['name'] . ')',
14389 $refund_reason,
14390 $currencysymb . ' ' . VikBooking::numberFormat($amount),
14391 );
14392 $history_obj->store('RF', implode("\n", $event_descr));
14393
14394 // display success message and redirect
14395 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
14396 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
14397 exit;
14398 }
14399
14400 /**
14401 * AJAX upload endpoint for media files.
14402 *
14403 * @return void
14404 *
14405 * @throws Exception
14406 *
14407 * @since 1.15.0 (J) - 1.5.0 (WP)
14408 */
14409 public function upload_media_file()
14410 {
14411 $input = JFactory::getApplication()->input;
14412
14413 // allowed types
14414 $type = $input->getString('type', '');
14415 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
14416 if ($type == 'image') {
14417 $mask = "/(image\/.+)$/i";
14418 }
14419
14420 // response object
14421 $result = new stdClass;
14422 $result->status = 0;
14423
14424 try
14425 {
14426 // get file from request
14427 $file = $input->files->get('file', array(), 'array');
14428
14429 // try to upload the file
14430 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
14431 $result->status = 1;
14432
14433 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
14434 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
14435 }
14436 catch (Exception $e)
14437 {
14438 $result->error = $e->getMessage();
14439 $result->code = $e->getCode();
14440 }
14441
14442 echo json_encode($result);
14443 exit;
14444 }
14445
14446 /**
14447 * AJAX endpoint to invoke a report object's method.
14448 *
14449 * @return void
14450 *
14451 * @throws Exception
14452 *
14453 * @since 1.15.0 (J) - 1.5.0 (WP)
14454 */
14455 public function invoke_report()
14456 {
14457 $report_name = VikRequest::getString('report', '', 'request');
14458 $report_call = VikRequest::getString('call', '', 'request');
14459 $params = VikRequest::getVar('params', array(), 'request', 'array');
14460
14461 if (empty($report_name)) {
14462 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
14463 }
14464
14465 if (empty($report_call)) {
14466 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
14467 }
14468
14469 // get requested report instance
14470 $report = VikBooking::getReportInstance($report_name);
14471 if (!$report) {
14472 VBOHttpDocument::getInstance()->close(404, 'Report not found');
14473 }
14474
14475 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
14476 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
14477 }
14478
14479 // call on report's method
14480 $result = $report->{$report_call}($params);
14481
14482 if (is_null($result)) {
14483 VBOHttpDocument::getInstance()->close(400, 'Null response');
14484 }
14485
14486 if (is_scalar($result)) {
14487 // wrap result within an array for a JSON encoded response
14488 VBOHttpDocument::getInstance()->json([$result]);
14489 }
14490
14491 // output the JSON encoded array/object returned
14492 VBOHttpDocument::getInstance()->json($result);
14493 }
14494
14495 /**
14496 * Handles requests for the multitask widgets panel.
14497 *
14498 * @see this is an AJAX endpoint.
14499 *
14500 * @since 1.15.0 (J) - 1.5.0 (WP)
14501 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14502 */
14503 public function exec_multitask_widgets()
14504 {
14505 if (!JSession::checkToken()) {
14506 // missing CSRF-proof token
14507 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14508 }
14509
14510 $call = VikRequest::getString('call', '', 'request');
14511 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
14512
14513 if (empty($call)) {
14514 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14515 }
14516
14517 // invoke admin widgets helper
14518 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14519
14520 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
14521 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
14522 }
14523
14524 try {
14525 // invoke the helper's method and get the value returned
14526 if (is_array($call_args) && count($call_args)) {
14527 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
14528 } else {
14529 $result = $widgets_helper->{$call}();
14530 }
14531 } catch (Throwable $e) {
14532 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14533 } catch (Exception $e) {
14534 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14535 }
14536
14537 // prepare response object with a property equal to the called method
14538 $response = new stdClass;
14539 $response->result = $result;
14540
14541 // output the JSON response and exit
14542 VBOHttpDocument::getInstance()->json($response);
14543 }
14544
14545 /**
14546 * Handles requests for displaying a browser notification being dispatched.
14547 *
14548 * @see this is an AJAX endpoint.
14549 *
14550 * @since 1.15.0 (J) - 1.5.0 (WP)
14551 */
14552 public function notification_displayer()
14553 {
14554 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
14555
14556 if (empty($payload_str)) {
14557 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
14558 }
14559
14560 // attempt to decode the notification payload
14561 $payload = json_decode($payload_str);
14562
14563 if (!is_object($payload)) {
14564 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
14565 }
14566
14567 // get notification displayer for this type of notification
14568 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
14569 if (!$displayer) {
14570 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
14571 }
14572
14573 // compose the notification display data object
14574 try {
14575 $notif_data = $displayer->getData();
14576 if (!$notif_data) {
14577 throw new Exception('Error building the notification display data', 500);
14578 }
14579 } catch (Exception $e) {
14580 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14581 }
14582
14583 // output the JSON response and exit
14584 VBOHttpDocument::getInstance()->json($notif_data);
14585 }
14586
14587 /**
14588 * Handles requests for watching widgets data and getting
14589 * new events to trigger browser notifications.
14590 *
14591 * @see this is an AJAX endpoint.
14592 *
14593 * @since 1.15.0 (J) - 1.5.0 (WP)
14594 */
14595 public function widgets_watch_data()
14596 {
14597 if (!JSession::checkToken()) {
14598 // missing CSRF-proof token
14599 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14600 }
14601
14602 $app = JFactory::getApplication();
14603
14604 $watch_data_str = $app->input->get('watch_data', '', 'raw');
14605 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
14606
14607 if (empty($watch_data_str)) {
14608 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
14609 }
14610
14611 // attempt to decode the watch-data payload
14612 $watch_data = json_decode($watch_data_str, true);
14613
14614 if (!$watch_data) {
14615 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
14616 }
14617
14618 // check if any pushed data was set
14619 $pushed_data = (array)json_decode($pushed_data_str, true);
14620
14621 // container for new notifications
14622 $notifs_pool = [];
14623
14624 // get admin widgets helper
14625 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14626
14627 foreach ($watch_data as $widget_id => $data) {
14628 // invoke admin widget (with no pre-loading)
14629 $widget_instance = $widgets_helper->getWidget($widget_id);
14630 if (!$widget_instance) {
14631 continue;
14632 }
14633
14634 // build the widget watch data object
14635 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
14636
14637 // check if the widget needs to emit browser notifications
14638 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
14639
14640 if ($watch_next) {
14641 // update next watch-data object for this widget
14642 $watch_data[$widget_id] = $watch_next;
14643 }
14644
14645 if (is_array($notifications) && $notifications) {
14646 $notifs_pool = array_merge($notifs_pool, $notifications);
14647 }
14648 }
14649
14650 // build the response object
14651 $response = new stdClass;
14652 $response->watch_data = $watch_data;
14653 $response->notifications = $notifs_pool;
14654
14655 // output the JSON response and exit
14656 VBOHttpDocument::getInstance()->json($response);
14657 }
14658
14659 /**
14660 * Outputs a list of CSS assets required to render the admin widgets
14661 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
14662 *
14663 * @see this is an AJAX endpoint.
14664 *
14665 * @since 1.16.0 (J) - 1.6.0 (WP)
14666 */
14667 public function widgets_get_assets()
14668 {
14669 // list of needed CSS asset details
14670 $assets_pool = [];
14671
14672 // appearance preference assets (one or none)
14673 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
14674
14675 if (VBOPlatformDetection::isWordPress()) {
14676 // WordPress (main CSS)
14677 $assets_pool[] = [
14678 'rel' => 'stylesheet',
14679 'id' => 'vbo-style-css',
14680 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14681 'media' => 'all',
14682 ];
14683
14684 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14685 // appearance preference CSS
14686 $assets_pool[] = [
14687 'rel' => 'stylesheet',
14688 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14689 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14690 'media' => 'all',
14691 ];
14692 }
14693 } else {
14694 // Joomla (main CSS)
14695 $assets_pool[] = [
14696 'rel' => 'stylesheet',
14697 'id' => 'vbo-style-css',
14698 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
14699 'media' => 'all',
14700 ];
14701
14702 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14703 // appearance preference CSS
14704 $assets_pool[] = [
14705 'rel' => 'stylesheet',
14706 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14707 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
14708 'media' => 'all',
14709 ];
14710 }
14711 }
14712
14713 // output the JSON response and exit
14714 VBOHttpDocument::getInstance()->json($assets_pool);
14715 }
14716 }
14717