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

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

14,605 lines 558.3 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::getString('yeartied', '', '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');
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::getString('yeartied', '', 'request');
4664 $pyeartied = $pyeartied == "1" ? 1 : 0;
4665 $tieyear = 0;
4666 $pval_pcent = VikRequest::getString('val_pcent', '', 'request');
4667 $pval_pcent = $pval_pcent == "1" ? 1 : 2;
4668 $proundmode = VikRequest::getString('roundmode', '', 'request');
4669 $proundmode = (!empty($proundmode) && in_array($proundmode, array('PHP_ROUND_HALF_UP', 'PHP_ROUND_HALF_DOWN')) ? $proundmode : '');
4670 $ppromo = VikRequest::getInt('promo', 0, 'request');
4671 $ppromodaysadv = VikRequest::getInt('promodaysadv', '', 'request');
4672 $ppromominlos = VikRequest::getInt('promominlos', '', 'request');
4673 $ppromotxt = VikRequest::getString('promotxt', '', 'request', VIKREQUEST_ALLOWHTML);
4674 $pnightsoverrides = VikRequest::getVar('nightsoverrides', array());
4675 $pvaluesoverrides = VikRequest::getVar('valuesoverrides', array());
4676 $pandmoreoverride = VikRequest::getVar('andmoreoverride', array());
4677 $padultsdiffchdisc = VikRequest::getVar('adultsdiffchdisc', array());
4678 $padultsdiffval = VikRequest::getVar('adultsdiffval', array());
4679 $padultsdiffvalpcent = VikRequest::getVar('adultsdiffvalpcent', array());
4680 $padultsdiffpernight = VikRequest::getVar('adultsdiffpernight', array());
4681 $ppromolastmind = VikRequest::getInt('promolastmind', 0, 'request');
4682 $ppromolastminh = VikRequest::getInt('promolastminh', 0, 'request');
4683 $promolastmin = ($ppromolastmind * 86400) + ($ppromolastminh * 3600);
4684 $ppromofinalprice = VikRequest::getInt('promofinalprice', 0, 'request');
4685 $ppromofinalprice = $ppromo ? $ppromofinalprice : 0;
4686 $pchannels = VikRequest::getVar('channels', array());
4687 $occupancy_ovr = array();
4688 $losverridestr = "";
4689
4690 $updforvcm = $session->get('vbVcmRatesUpd', '');
4691 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
4692
4693 // check null dates
4694 if ($dbo->getNullDate() == $pfrom) {
4695 $pfrom = '';
4696 }
4697 if ($dbo->getNullDate() == $pto) {
4698 $pto = '';
4699 }
4700
4701 if ((empty($pfrom) || empty($pto)) && !$pwdays) {
4702 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4703 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4704 exit;
4705 }
4706
4707 $skipseason = false;
4708 if (empty($pfrom) || empty($pto)) {
4709 $skipseason = true;
4710 }
4711 $skipdays = false;
4712 $wdaystr = null;
4713 if (!$pwdays) {
4714 $skipdays = true;
4715 } else {
4716 $wdaystr = "";
4717 foreach ($pwdays as $wd) {
4718 $wdaystr .= $wd.';';
4719 }
4720 }
4721 $roomstr = "";
4722 $roomids = array();
4723 foreach ($pidrooms as $room) {
4724 if (empty($room)) {
4725 continue;
4726 }
4727 $roomstr .= "-".$room."-,";
4728 $roomids[] = (int)$room;
4729 }
4730 $pricestr = "";
4731 $priceids = array();
4732 foreach ($pidprices as $price) {
4733 if (empty($price)) {
4734 continue;
4735 }
4736 $pricestr .= "-".$price."-,";
4737 $priceids[] = (int)$price;
4738 }
4739 $valid = true;
4740 $double_records = array();
4741 $sfrom = null;
4742 $sto = null;
4743
4744 // value overrides
4745 if ($pnightsoverrides && $pvaluesoverrides) {
4746 foreach ($pnightsoverrides as $ko => $no) {
4747 if (!empty($no) && strlen(trim($pvaluesoverrides[$ko])) > 0) {
4748 $infiniteclause = intval($pandmoreoverride[$ko]) == 1 ? '-i' : '';
4749 $losverridestr .= intval($no).$infiniteclause.':'.trim($pvaluesoverrides[$ko]).'_';
4750 }
4751 }
4752 }
4753
4754 if (!$skipseason) {
4755 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
4756 $second = VikBooking::getDateTimestamp($pto, 0, 0);
4757
4758 if ($second > 0 && $second == $first) {
4759 $second += 86399;
4760 }
4761
4762 if (!($second > $first)) {
4763 VikError::raiseWarning('', JText::translate('ERRINVDATESEASON'));
4764 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4765 exit;
4766 }
4767
4768 $baseone = getdate($first);
4769 $basets = mktime(0, 0, 0, 1, 1, $baseone['year']);
4770 $sfrom = $baseone[0] - $basets;
4771 $basetwo = getdate($second);
4772 $basets = mktime(0, 0, 0, 1, 1, $basetwo['year']);
4773 $sto = $basetwo[0] - $basets;
4774
4775 // check leap year
4776 if ($baseone['year'] % 4 == 0 && ($baseone['year'] % 100 != 0 || $baseone['year'] % 400 == 0)) {
4777 $leapts = mktime(0, 0, 0, 2, 29, $baseone['year']);
4778 if ($baseone[0] > $leapts) {
4779 $sfrom -= 86400;
4780 /**
4781 * To avoid issue with leap years and dates near Feb 29th, we only reduce the seconds if these were reduced
4782 * for the from-date of the seasons. Doing it just for the to-date in 2019 for 2020 (leap) produced invalid results.
4783 *
4784 * @since July 2nd 2019
4785 */
4786 if ($basetwo['year'] % 4 == 0 && ($basetwo['year'] % 100 != 0 || $basetwo['year'] % 400 == 0)) {
4787 $leapts = mktime(0, 0, 0, 2, 29, $basetwo['year']);
4788 if ($basetwo[0] > $leapts) {
4789 $sto -= 86400;
4790 }
4791 }
4792 }
4793 }
4794
4795 // tied to the year
4796 if ($pyeartied == 1) {
4797 $tieyear = $baseone['year'];
4798 }
4799
4800 // Occupancy Override
4801 if ($padultsdiffval) {
4802 foreach ($padultsdiffval as $rid => $valovr_arr) {
4803 if (!is_array($valovr_arr) || !is_array($padultsdiffchdisc[$rid]) || !is_array($padultsdiffvalpcent[$rid]) || !is_array($padultsdiffpernight[$rid])) {
4804 continue;
4805 }
4806 foreach ($valovr_arr as $occ => $valovr) {
4807 if (!(strlen($valovr) > 0) || !(strlen($padultsdiffchdisc[$rid][$occ]) > 0) || !(strlen($padultsdiffvalpcent[$rid][$occ]) > 0) || !(strlen($padultsdiffpernight[$rid][$occ]) > 0)) {
4808 continue;
4809 }
4810 if (!array_key_exists($rid, $occupancy_ovr)) {
4811 $occupancy_ovr[$rid] = array();
4812 }
4813 $occupancy_ovr[$rid][$occ] = array('chdisc' => (int)$padultsdiffchdisc[$rid][$occ], 'valpcent' => (int)$padultsdiffvalpcent[$rid][$occ], 'pernight' => (int)$padultsdiffpernight[$rid][$occ], 'value' => (float)$valovr);
4814 }
4815 }
4816 }
4817
4818 // check if seasons dates are valid
4819 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sfrom)." AND `to`>".$dbo->quote($sfrom)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4820 $dbo->setQuery($q);
4821 $similar = $dbo->loadAssocList();
4822 if ($similar) {
4823 $valid = false;
4824 foreach ($similar as $sim) {
4825 $double_records[] = $sim['spname'];
4826 }
4827 }
4828
4829 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sto)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4830 $dbo->setQuery($q);
4831 $similar = $dbo->loadAssocList();
4832 if ($similar) {
4833 $valid = false;
4834 foreach ($similar as $sim) {
4835 $double_records[] = $sim['spname'];
4836 }
4837 }
4838
4839 $q = "SELECT `id`,`spname` FROM `#__vikbooking_seasons` WHERE `from`>=".$dbo->quote($sfrom)." AND `from`<=".$dbo->quote($sto)." AND `to`>=".$dbo->quote($sfrom)." AND `to`<=".$dbo->quote($sto)." AND `idrooms`=".$dbo->quote($roomstr)."".(!$skipdays ? " AND `wdays`='".$wdaystr."'" : "").($skipdays ? " AND (`from` > 0 OR `to` > 0) AND `wdays`=''" : "").($pyeartied == 1 ? " AND `year`=".$tieyear : " AND `year` IS NULL")." AND `idprices`=".$dbo->quote($pricestr)." AND `promo`=".$ppromo." AND `promodaysadv`=" . $dbo->quote($ppromodaysadv) . " AND `promominlos`=" . $dbo->quote($ppromominlos) . " AND `promolastmin`=" . $dbo->quote($promolastmin) . " AND `losoverride`=".$dbo->quote($losverridestr)." AND `occupancy_ovr`".(count($occupancy_ovr) > 0 ? "=".$dbo->quote(json_encode($occupancy_ovr)) : " IS NULL").";";
4840 $dbo->setQuery($q);
4841 $similar = $dbo->loadAssocList();
4842 if ($similar) {
4843 $valid = false;
4844 foreach ($similar as $sim) {
4845 $double_records[] = $sim['spname'];
4846 }
4847 }
4848 }
4849
4850 if (!$valid && !$ppromo) {
4851 VikError::raiseWarning('', JText::translate('ERRINVDATEROOMSLOCSEASON').(count($double_records) ? ' ('.implode(', ', array_unique($double_records)).')' : ''));
4852 $app->redirect("index.php?option=com_vikbooking&task=newseason");
4853 exit;
4854 }
4855
4856 // insert new record
4857 $sea_record = new stdClass;
4858 $sea_record->type = $ptype == "1" ? 1 : 2;
4859 $sea_record->from = $sfrom;
4860 $sea_record->to = $sto;
4861 $sea_record->diffcost = $pdiffcost;
4862 $sea_record->idrooms = $roomstr;
4863 $sea_record->spname = $pspname;
4864 $sea_record->wdays = $wdaystr;
4865 $sea_record->checkinincl = $pcheckinincl;
4866 $sea_record->val_pcent = $pval_pcent;
4867 $sea_record->losoverride = $losverridestr;
4868 $sea_record->roundmode = !empty($proundmode) ? $proundmode : null;
4869 $sea_record->year = $pyeartied == 1 ? $tieyear : null;
4870 $sea_record->idprices = $pricestr;
4871 $sea_record->promo = $ppromo == 1 ? 1 : 0;
4872 $sea_record->promodaysadv = !empty($ppromodaysadv) ? $ppromodaysadv : null;
4873 $sea_record->promotxt = $ppromotxt;
4874 $sea_record->promominlos = !empty($ppromominlos) ? $ppromominlos : 0;
4875 $sea_record->occupancy_ovr = $occupancy_ovr ? json_encode($occupancy_ovr) : null;
4876 $sea_record->promolastmin = (int)$promolastmin;
4877 $sea_record->promofinalprice = $ppromofinalprice;
4878
4879 $dbo->insertObject('#__vikbooking_seasons', $sea_record, 'id');
4880
4881 $vbo_promo_id = $sea_record->id;
4882
4883 $app->enqueueMessage(JText::translate('VBSEASONSAVED'));
4884
4885 // update session values
4886 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
4887 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
4888 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $first ? $first : $updforvcm['dfrom'];
4889 } else {
4890 $updforvcm['dfrom'] = $first;
4891 }
4892 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
4893 $updforvcm['dto'] = $updforvcm['dto'] < $second ? $second : $updforvcm['dto'];
4894 } else {
4895 $updforvcm['dto'] = $second;
4896 }
4897 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
4898 foreach ($roomids as $rid) {
4899 if (!in_array($rid, $updforvcm['rooms'])) {
4900 $updforvcm['rooms'][] = $rid;
4901 }
4902 }
4903 } else {
4904 $updforvcm['rooms'] = $roomids;
4905 }
4906 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
4907 foreach ($roomids as $rid) {
4908 if (array_key_exists($rid, $updforvcm['rplans'])) {
4909 $updforvcm['rplans'][$rid] = $updforvcm['rplans'][$rid] + $priceids;
4910 } else {
4911 $updforvcm['rplans'][$rid] = $priceids;
4912 }
4913 }
4914 } else {
4915 $updforvcm['rplans'] = array();
4916 foreach ($roomids as $rid) {
4917 $updforvcm['rplans'][$rid] = $priceids;
4918 }
4919 }
4920 if (!$ppromo) {
4921 $session->set('vbVcmRatesUpd', $updforvcm);
4922 }
4923
4924 /**
4925 * Create the promotion also on the selected channels
4926 *
4927 * @since 1.13.0 (J) - 1.3.0 (WP)
4928 */
4929 if ($ppromo && $pchannels) {
4930 foreach ($pchannels as $channel_key) {
4931 $promo_obj = VikBooking::getPromotionHandlers($channel_key);
4932 if (!is_object($promo_obj)) {
4933 continue;
4934 }
4935 /**
4936 * We inject for VCM the ID of the newly created promotion in VBO.
4937 *
4938 * @since 1.15.0 (J) - 1.5.0 (WP)
4939 */
4940 $ch_result = $promo_obj->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'new');
4941 if (!$ch_result) {
4942 VikError::raiseWarning('', $promo_obj->getName() . ': ' . $promo_obj->getError());
4943 } else {
4944 $resp = $promo_obj->getResponse();
4945 $app->enqueueMessage($promo_obj->getName() . ': ' . JText::translate('VBOCHPROMOSUCCESS') . (!empty($resp) ? ' (' . str_replace('e4j.ok.', '', $resp) . ')' : ''));
4946 // in case of success, unset the current session values in VCM
4947 $session->set('vcmBPromo', '');
4948 }
4949 }
4950 }
4951
4952 $app->redirect("index.php?option=com_vikbooking&task=".($andnew ? 'newseason' : 'seasons'));
4953 $app->close();
4954 }
4955
4956 public function removeseasons()
4957 {
4958 if (!JSession::checkToken()) {
4959 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
4960 }
4961 $app = JFactory::getApplication();
4962 $dbo = JFactory::getDbo();
4963
4964 $ids = VikRequest::getVar('cid', array(0));
4965 $pidroom = VikRequest::getInt('idroom', '', 'request');
4966 $pwhere = VikRequest::getInt('where', '', 'request');
4967 if (!empty($pwhere)) {
4968 $ids[] = $pwhere;
4969 }
4970 $tot_removed = array();
4971 $prev_promos = array();
4972 foreach ($ids as $d) {
4973 if (empty($d)) {
4974 continue;
4975 }
4976 // check if it was a promotion
4977 $q = "SELECT `id` FROM `#__vikbooking_seasons` WHERE `id`=" . (int)$d . " AND `promo`=1;";
4978 $dbo->setQuery($q);
4979 $dbo->execute();
4980 if ($dbo->getNumRows()) {
4981 // push it as a previous promo
4982 array_push($prev_promos, $d);
4983 }
4984
4985 // delete the record
4986 $q = "DELETE FROM `#__vikbooking_seasons` WHERE `id`=".$dbo->quote($d).";";
4987 $dbo->setQuery($q);
4988 $dbo->execute();
4989 $tot_removed[] = $d;
4990 }
4991
4992 /**
4993 * Query promotion handlers, if any, to trigger the delete promotion event.
4994 *
4995 * @since 1.15.0 (J) - 1.5.0 (WP)
4996 */
4997 $promo_handlers = VikBooking::getPromotionHandlers();
4998 foreach ($prev_promos as $vbo_promo_id) {
4999 try {
5000 if (is_array($promo_handlers)) {
5001 foreach ($promo_handlers as $promo_handler) {
5002 if (!isset($promo_handler->instance) || !is_object($promo_handler->instance) || !method_exists($promo_handler->instance, 'triggerDelete')) {
5003 // outdated handler object
5004 continue;
5005 }
5006 if (!is_callable(array($promo_handler->instance, 'triggerDelete')) || !$promo_handler->instance->triggerDelete()) {
5007 // promotion handler does not support delete promotion event
5008 continue;
5009 }
5010 // invoke the delete promotion event for this handler
5011 $ch_result = $promo_handler->instance->createPromotion(array('vbo_promo_id' => $vbo_promo_id), 'delete');
5012 if (!$ch_result) {
5013 VikError::raiseWarning('', $promo_handler->instance->getName() . ': ' . $promo_handler->instance->getError());
5014 }
5015 }
5016 }
5017 } catch (Exception $e) {
5018 // do nothing
5019 }
5020 }
5021
5022 $app->enqueueMessage(JText::sprintf('VBRECORDSREMOVED', count($tot_removed)));
5023 $app->redirect("index.php?option=com_vikbooking&task=seasons".(!empty($pidroom) ? '&idroom='.$pidroom : ''));
5024 $app->close();
5025 }
5026
5027 public function updatecustomer() {
5028 if (!JSession::checkToken()) {
5029 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5030 }
5031 $this->do_updatecustomer();
5032 }
5033
5034 public function updatecustomerstay() {
5035 if (!JSession::checkToken()) {
5036 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5037 }
5038 $this->do_updatecustomer(true);
5039 }
5040
5041 private function do_updatecustomer($stay = false) {
5042 $dbo = JFactory::getDbo();
5043 $mainframe = JFactory::getApplication();
5044 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5045 $plast_name = VikRequest::getString('last_name', '', 'request');
5046 $pcompany = VikRequest::getString('company', '', 'request');
5047 $pvat = VikRequest::getString('vat', '', 'request');
5048 $pemail = VikRequest::getString('email', '', 'request');
5049 $pphone = VikRequest::getString('phone', '', 'request');
5050 $pcountry = VikRequest::getString('country', '', 'request');
5051 $pstate = VikRequest::getString('state', '', 'request');
5052 $ppin = VikRequest::getString('pin', '', 'request');
5053 $pujid = VikRequest::getInt('ujid', '', 'request');
5054 $paddress = VikRequest::getString('address', '', 'request');
5055 $pcity = VikRequest::getString('city', '', 'request');
5056 $pzip = VikRequest::getString('zip', '', 'request');
5057 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5058 $ppec = VikRequest::getString('pec', '', 'request');
5059 $precipcode = VikRequest::getString('recipcode', '', 'request');
5060 $pgender = VikRequest::getString('gender', '', 'request');
5061 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5062 $pbdate = VikRequest::getString('bdate', '', 'request');
5063 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5064 $pdoctype = VikRequest::getString('doctype', '', 'request');
5065 $pdocnum = VikRequest::getString('docnum', '', 'request');
5066 $pnotes = VikRequest::getString('notes', '', 'request');
5067 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5068 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5069 $pcommission = VikRequest::getFloat('commission', '', 'request');
5070 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5071 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5072 $pchname = VikRequest::getString('chname', '', 'request');
5073 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5074 $pwhere = VikRequest::getInt('where', '', 'request');
5075 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5076 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5077 $pbid = VikRequest::getInt('bid', '', 'request');
5078 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5079 if (!empty($pwhere) && !empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5080 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `id`=".(int)$pwhere." LIMIT 1;";
5081 $dbo->setQuery($q);
5082 $dbo->execute();
5083 if ($dbo->getNumRows() == 1) {
5084 $customer = $dbo->loadAssoc();
5085 } else {
5086 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5087 exit;
5088 }
5089 /**
5090 * Existing customers are recognized by equal first name, last name and email address.
5091 *
5092 * @since 1.3.0
5093 */
5094 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `first_name`=".$dbo->quote($pfirst_name)." AND `last_name`=".$dbo->quote($plast_name)." AND `email`=".$dbo->quote($pemail)." AND `id`!=".(int)$pwhere." LIMIT 1;";
5095 $dbo->setQuery($q);
5096 $dbo->execute();
5097 if ($dbo->getNumRows() == 0) {
5098 $cpin = VikBooking::getCPinIstance();
5099 if (empty($ppin)) {
5100 $ppin = $customer['pin'];
5101 } elseif ($cpin->pinExists($ppin, $customer['pin'])) {
5102 $ppin = $cpin->generateUniquePin();
5103 }
5104 //file upload
5105 jimport('joomla.filesystem.file');
5106 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5107 $gimg = "";
5108 if (isset($pimg) && strlen(trim($pimg['name']))) {
5109 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5110 $src = $pimg['tmp_name'];
5111 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5112 $j = "";
5113 if (file_exists($dest.$filename)) {
5114 $j = rand(171, 1717);
5115 while (file_exists($dest.$j.$filename)) {
5116 $j++;
5117 }
5118 }
5119 $finaldest = $dest.$j.$filename;
5120 $check = getimagesize($pimg['tmp_name']);
5121 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5122 if (VikBooking::uploadFile($src, $finaldest)) {
5123 $gimg = $j.$filename;
5124 } else {
5125 VikError::raiseWarning('', 'Error while uploading image');
5126 }
5127 } else {
5128 VikError::raiseWarning('', 'Uploaded file is not an Image');
5129 }
5130 } elseif (!empty($pscandocimg)) {
5131 $gimg = $pscandocimg;
5132 }
5133 //
5134 $pischannel = $pischannel > 0 ? 1 : 0;
5135 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5136 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5137 $pchname = str_replace(' ', '', trim($pchname));
5138 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5139 $chparams = array(
5140 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5141 'calccmmon' => $pcalccmmon,
5142 'applycmmon' => $papplycmmon,
5143 'chcolor' => $pchcolor,
5144 'chname' => $pchname
5145 );
5146
5147 /**
5148 * Customer profile picture (URL or uploaded file).
5149 *
5150 * @since 1.15.3 (J) - 1.5.5 (WP)
5151 */
5152 $customer_pic = VikRequest::getString('pic', '', 'request');
5153 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5154 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5155 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5156 $src = $customer_pic_img['tmp_name'];
5157 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5158 $j = "";
5159 if (is_file($dest.$filename)) {
5160 $j = rand(1, 99999);
5161 while (is_file($dest . $j .$filename)) {
5162 $j++;
5163 }
5164 }
5165 $finaldest = $dest . $j . $filename;
5166 $check = getimagesize($customer_pic_img['tmp_name']);
5167 if (($check[2] & imagetypes())) {
5168 if (VikBooking::uploadFile($src, $finaldest)) {
5169 $customer_pic = $j . $filename;
5170 } else {
5171 VikError::raiseWarning('', 'Error while uploading image');
5172 }
5173 } else {
5174 VikError::raiseWarning('', 'Uploaded file is not an Image');
5175 }
5176 }
5177
5178 // update customer object
5179 $new_customer = new stdClass;
5180 $new_customer->id = (int)$pwhere;
5181 $new_customer->first_name = $pfirst_name;
5182 $new_customer->last_name = $plast_name;
5183 $new_customer->email = $pemail;
5184 $new_customer->phone = $pphone;
5185 $new_customer->country = $pcountry;
5186 $new_customer->pin = $ppin;
5187 $new_customer->ujid = $pujid;
5188 $new_customer->address = $paddress;
5189 $new_customer->city = $pcity;
5190 $new_customer->zip = $pzip;
5191 $new_customer->state = $pstate;
5192 $new_customer->doctype = $pdoctype;
5193 $new_customer->docnum = $pdocnum;
5194 if (!empty($gimg)) {
5195 $new_customer->docimg = $gimg;
5196 }
5197 $new_customer->notes = $pnotes;
5198 $new_customer->ischannel = $pischannel;
5199 $new_customer->chdata = json_encode($chparams);
5200 $new_customer->company = $pcompany;
5201 $new_customer->vat = $pvat;
5202 $new_customer->gender = $pgender;
5203 $new_customer->bdate = $pbdate;
5204 $new_customer->pbirth = $ppbirth;
5205 $new_customer->fisccode = $pfisccode;
5206 $new_customer->pec = $ppec;
5207 $new_customer->recipcode = $precipcode;
5208 $new_customer->pic = $customer_pic;
5209 /**
5210 * We need to update the previous information stored through
5211 * the custom fields when making a reservation for/by this client.
5212 *
5213 * @since 1.13
5214 */
5215 $skip_prev_fields = array(
5216 'id',
5217 'ujid',
5218 'docimg',
5219 'ischannel',
5220 'chdata',
5221 'notes',
5222 );
5223 if (!empty($customer['cfields'])) {
5224 $custf_info = json_decode($customer['cfields'], true);
5225 foreach ($new_customer as $fname => $fnewval) {
5226 if (!isset($customer[$fname]) || in_array($fname, $skip_prev_fields)) {
5227 continue;
5228 }
5229 // seek for old value in custom fields submitted
5230 foreach ($custf_info as $k => $v) {
5231 if (!empty($customer[$fname]) && $v == $customer[$fname]) {
5232 // field found, replace it with the new value
5233 $custf_info[$k] = $fnewval;
5234 }
5235 }
5236 }
5237 // update record on db
5238 $new_customer->cfields = json_encode($custf_info);
5239 }
5240 //
5241
5242 $dbo->updateObject('#__vikbooking_customers', $new_customer, 'id');
5243
5244 $cpin->pluginCustomerSync($pwhere, 'update');
5245 //Update all the bookings affected by this Customer ID as a sales channel
5246 $source_name = 'customer'.$pwhere.'_'.$pchname;
5247 if ($pischannel > 0) {
5248 $oid_clause = '';
5249 if ($customer['ischannel'] < 1) {
5250 //Was not a sales channel but now it is, so update all his bookings
5251 $q = "SELECT `idorder` FROM `#__vikbooking_customers_orders` WHERE `idcustomer`=".$customer['id'].";";
5252 $dbo->setQuery($q);
5253 $dbo->execute();
5254 if ($dbo->getNumRows() > 0) {
5255 $all_bids = $dbo->loadAssocList();
5256 $bids = array();
5257 foreach ($all_bids as $bid) {
5258 if (!in_array($bid['idorder'], $bids)) {
5259 $bids[] = $bid['idorder'];
5260 }
5261 }
5262 $oid_clause = " OR `id` IN (".implode(',', $bids).")";
5263 }
5264 }
5265 $q = "UPDATE `#__vikbooking_orders` SET `channel`=".$dbo->quote($source_name)." WHERE `channel` LIKE 'customer".$pwhere."%'".$oid_clause.";";
5266 } else {
5267 $q = "UPDATE `#__vikbooking_orders` SET `channel`=NULL,`cmms`=NULL WHERE `channel` LIKE 'customer".$pwhere."%';";
5268 }
5269 $dbo->setQuery($q);
5270 $dbo->execute();
5271 //
5272 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5273 } else {
5274 //email already exists
5275 $ex_customer = $dbo->loadAssoc();
5276 //check if coming from the Check-in view or not
5277 if (!empty($pcheckin) && !empty($pbid)) {
5278 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5279 /**
5280 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5281 */
5282 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5283 //
5284 exit;
5285 } elseif (!empty($pgoto)) {
5286 // check if coming from a specific task
5287 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5288 $mainframe->redirect(base64_decode($pgoto));
5289 exit;
5290 } else {
5291 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editcustomer&cid[]='.$ex_customer['id'].'" target="_blank">'.$ex_customer['first_name'].' '.$ex_customer['last_name'].'</a>');
5292 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=".$pwhere);
5293 exit;
5294 }
5295 }
5296 }
5297
5298 //check if coming from the Check-in view
5299 if (!empty($pcheckin) && !empty($pbid)) {
5300 /**
5301 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5302 */
5303 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $pbid);
5304 exit;
5305 }
5306
5307 if ($stay) {
5308 $mainframe->redirect("index.php?option=com_vikbooking&task=editcustomer&cid[]=" . $pwhere . (!empty($pgoto) ? '&goto=' . $pgoto : ''));
5309 exit;
5310 }
5311
5312 // check if coming from a specific task
5313 if (!empty($pgoto)) {
5314 $mainframe->redirect(base64_decode($pgoto));
5315 exit;
5316 }
5317
5318 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5319 }
5320
5321 public function savecustomer() {
5322 if (!JSession::checkToken()) {
5323 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5324 }
5325 $dbo = JFactory::getDbo();
5326 $mainframe = JFactory::getApplication();
5327 $pfirst_name = VikRequest::getString('first_name', '', 'request');
5328 $plast_name = VikRequest::getString('last_name', '', 'request');
5329 $pcompany = VikRequest::getString('company', '', 'request');
5330 $pvat = VikRequest::getString('vat', '', 'request');
5331 $pemail = VikRequest::getString('email', '', 'request');
5332 $pphone = VikRequest::getString('phone', '', 'request');
5333 $pcountry = VikRequest::getString('country', '', 'request');
5334 $pstate = VikRequest::getString('state', '', 'request');
5335 $ppin = VikRequest::getString('pin', '', 'request');
5336 $pujid = VikRequest::getInt('ujid', '', 'request');
5337 $paddress = VikRequest::getString('address', '', 'request');
5338 $pcity = VikRequest::getString('city', '', 'request');
5339 $pzip = VikRequest::getString('zip', '', 'request');
5340 $pfisccode = VikRequest::getString('fisccode', '', 'request');
5341 $ppec = VikRequest::getString('pec', '', 'request');
5342 $precipcode = VikRequest::getString('recipcode', '', 'request');
5343 $pgender = VikRequest::getString('gender', '', 'request');
5344 $pgender = in_array($pgender, array('F', 'M')) ? $pgender : '';
5345 $pbdate = VikRequest::getString('bdate', '', 'request');
5346 $ppbirth = VikRequest::getString('pbirth', '', 'request');
5347 $pdoctype = VikRequest::getString('doctype', '', 'request');
5348 $pdocnum = VikRequest::getString('docnum', '', 'request');
5349 $pnotes = VikRequest::getString('notes', '', 'request');
5350 $pscandocimg = VikRequest::getString('scandocimg', '', 'request');
5351 $pischannel = VikRequest::getInt('ischannel', '', 'request');
5352 $pcommission = VikRequest::getFloat('commission', '', 'request');
5353 $pcalccmmon = VikRequest::getInt('calccmmon', '', 'request');
5354 $papplycmmon = VikRequest::getInt('applycmmon', '', 'request');
5355 $pchname = VikRequest::getString('chname', '', 'request');
5356 $pchcolor = VikRequest::getString('chcolor', '', 'request');
5357 $ptmpl = VikRequest::getString('tmpl', '', 'request');
5358 $pcheckin = VikRequest::getInt('checkin', '', 'request');
5359 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
5360 $pbid = VikRequest::getInt('bid', '', 'request');
5361 if (!empty($pfirst_name) && !empty($plast_name) && !empty($pemail)) {
5362 $cpin = VikBooking::getCPinIstance();
5363 /**
5364 * Existing customers are recognized by equal first name, last name and email address.
5365 *
5366 * @since 1.3.0
5367 */
5368 $q = "SELECT * FROM `#__vikbooking_customers` WHERE `first_name`=".$dbo->quote($pfirst_name)." AND `last_name`=".$dbo->quote($plast_name)." AND `email`=".$dbo->quote($pemail)." LIMIT 1;";
5369 $dbo->setQuery($q);
5370 $dbo->execute();
5371 if ($dbo->getNumRows() == 0) {
5372 if (empty($ppin)) {
5373 $ppin = $cpin->generateUniquePin();
5374 } elseif ($cpin->pinExists($ppin)) {
5375 $ppin = $cpin->generateUniquePin();
5376 }
5377 //file upload
5378 jimport('joomla.filesystem.file');
5379 $pimg = VikRequest::getVar('docimg', null, 'files', 'array');
5380 $gimg = "";
5381 if (isset($pimg) && strlen(trim($pimg['name']))) {
5382 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($pimg['name'])));
5383 $src = $pimg['tmp_name'];
5384 $dest = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans'.DIRECTORY_SEPARATOR;
5385 $j = "";
5386 if (file_exists($dest.$filename)) {
5387 $j = rand(171, 1717);
5388 while (file_exists($dest.$j.$filename)) {
5389 $j++;
5390 }
5391 }
5392 $finaldest = $dest.$j.$filename;
5393 $check = getimagesize($pimg['tmp_name']);
5394 if (($check[2] & imagetypes()) || preg_match("/application\/(zip|pdf)$/", $pimg['type'])) {
5395 if (VikBooking::uploadFile($src, $finaldest)) {
5396 $gimg = $j.$filename;
5397 } else {
5398 VikError::raiseWarning('', 'Error while uploading image');
5399 }
5400 } else {
5401 VikError::raiseWarning('', 'Uploaded file is not an Image');
5402 }
5403 } elseif (!empty($pscandocimg)) {
5404 $gimg = $pscandocimg;
5405 }
5406 //
5407 $pischannel = $pischannel > 0 ? 1 : 0;
5408 $pcalccmmon = $pcalccmmon > 0 ? 1 : 0;
5409 $papplycmmon = $papplycmmon > 0 ? 1 : 0;
5410 $pchname = str_replace(' ', '', trim($pchname));
5411 $pchname = strlen($pchname) <= 0 && $pischannel > 0 ? str_replace(' ', '', trim($pfirst_name.' '.$plast_name)) : $pchname;
5412 $chparams = array(
5413 'commission' => ($pcommission > 0.00 ? $pcommission : 0),
5414 'calccmmon' => $pcalccmmon,
5415 'applycmmon' => $papplycmmon,
5416 'chcolor' => $pchcolor,
5417 'chname' => $pchname
5418 );
5419
5420 /**
5421 * Customer profile picture (URL or uploaded file).
5422 *
5423 * @since 1.15.3 (J) - 1.5.5 (WP)
5424 */
5425 $customer_pic = VikRequest::getString('pic', '', 'request');
5426 $customer_pic_img = VikRequest::getVar('picimg', null, 'files', 'array');
5427 if (is_array($customer_pic_img) && !empty($customer_pic_img['name'])) {
5428 $filename = JFile::makeSafe(rand(100, 9999).str_replace(" ", "_", strtolower($customer_pic_img['name'])));
5429 $src = $customer_pic_img['tmp_name'];
5430 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
5431 $j = "";
5432 if (is_file($dest.$filename)) {
5433 $j = rand(1, 99999);
5434 while (is_file($dest . $j .$filename)) {
5435 $j++;
5436 }
5437 }
5438 $finaldest = $dest . $j . $filename;
5439 $check = getimagesize($customer_pic_img['tmp_name']);
5440 if (($check[2] & imagetypes())) {
5441 if (VikBooking::uploadFile($src, $finaldest)) {
5442 $customer_pic = $j . $filename;
5443 } else {
5444 VikError::raiseWarning('', 'Error while uploading image');
5445 }
5446 } else {
5447 VikError::raiseWarning('', 'Uploaded file is not an Image');
5448 }
5449 }
5450
5451 $q = "INSERT INTO `#__vikbooking_customers` (`first_name`,`last_name`,`email`,`phone`,`country`,`pin`,`ujid`,`address`,`city`,`zip`,`state`,`doctype`,`docnum`,`docimg`,`notes`,`ischannel`,`chdata`,`company`,`vat`,`gender`,`bdate`,`pbirth`,`fisccode`,`pec`,`recipcode`,`pic`) VALUES(".$dbo->quote($pfirst_name).", ".$dbo->quote($plast_name).", ".$dbo->quote($pemail).", ".$dbo->quote($pphone).", ".$dbo->quote($pcountry).", ".$dbo->quote($ppin).", ".$dbo->quote($pujid).", ".$dbo->quote($paddress).", ".$dbo->quote($pcity).", ".$dbo->quote($pzip).", ".$dbo->quote($pstate).", ".$dbo->quote($pdoctype).", ".$dbo->quote($pdocnum).", ".$dbo->quote($gimg).", ".$dbo->quote($pnotes).", ".$pischannel.", ".$dbo->quote(json_encode($chparams)).", ".$dbo->quote($pcompany).", ".$dbo->quote($pvat).", ".$dbo->quote($pgender).", ".$dbo->quote($pbdate).", ".$dbo->quote($ppbirth).", ".$dbo->quote($pfisccode).", ".$dbo->quote($ppec).", ".$dbo->quote($precipcode).", " . (!empty($customer_pic) ? $dbo->quote($customer_pic) : 'NULL') . ");";
5452 $dbo->setQuery($q);
5453 $dbo->execute();
5454 $lid = $dbo->insertid();
5455 $cpin->pluginCustomerSync($lid, 'insert');
5456 if (!empty($lid)) {
5457 $mainframe->enqueueMessage(JText::translate('VBCUSTOMERSAVED'));
5458 //check if coming from the Check-in view
5459 if (!empty($pcheckin) && !empty($pbid)) {
5460 $cpin->setNewPin($ppin);
5461 $cpin->setNewCustomerId($lid);
5462 $cpin->saveCustomerBooking($pbid);
5463 /**
5464 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5465 */
5466 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5467 //
5468 exit;
5469 }
5470 // check if coming from a specific task
5471 if (!empty($pgoto) && !empty($pbid)) {
5472 $cpin->setNewPin($ppin);
5473 $cpin->setNewCustomerId($lid);
5474 $cpin->saveCustomerBooking($pbid);
5475 $mainframe->redirect(base64_decode($pgoto));
5476 exit;
5477 }
5478 }
5479 } else {
5480 //email already exists
5481 $ex_customer = $dbo->loadAssoc();
5482 //check if coming from the Check-in view or not
5483 if (!empty($pcheckin) && !empty($pbid)) {
5484 $cpin->setNewPin($ex_customer['pin']);
5485 $cpin->setNewCustomerId($ex_customer['id']);
5486 $cpin->saveCustomerBooking($pbid);
5487 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5488 /**
5489 * @wponly - this task is executed via Ajax for the Modal forms listener. We must redirect to the booking details page and let the user restart the procedure
5490 */
5491 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pbid);
5492 //
5493 exit;
5494 } elseif (!empty($pgoto) && !empty($pbid)) {
5495 // check if coming from a specific task
5496 $cpin->setNewPin($ex_customer['pin']);
5497 $cpin->setNewCustomerId($ex_customer['id']);
5498 $cpin->saveCustomerBooking($pbid);
5499 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').' ('.$ex_customer['first_name'].' '.$ex_customer['last_name'].')');
5500 $mainframe->redirect(base64_decode($pgoto));
5501 exit;
5502 } else {
5503 VikError::raiseWarning('', JText::translate('VBERRCUSTOMEREMAILEXISTS').'<br/><a href="index.php?option=com_vikbooking&task=editcustomer&cid[]='.$ex_customer['id'].'" target="_blank">'.$ex_customer['first_name'].' '.$ex_customer['last_name'].'</a>');
5504 }
5505 }
5506 }
5507 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5508 }
5509
5510 public function customers() {
5511 VikBookingHelper::printHeader("22");
5512
5513 VikRequest::setVar('view', VikRequest::getCmd('view', 'customers'));
5514
5515 parent::display();
5516
5517 if (VikBooking::showFooter()) {
5518 VikBookingHelper::printFooter();
5519 }
5520 }
5521
5522 public function newcustomer() {
5523 VikBookingHelper::printHeader("22");
5524
5525 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5526
5527 parent::display();
5528
5529 if (VikBooking::showFooter()) {
5530 VikBookingHelper::printFooter();
5531 }
5532 }
5533
5534 public function editcustomer() {
5535 VikBookingHelper::printHeader("22");
5536
5537 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomer'));
5538
5539 parent::display();
5540
5541 if (VikBooking::showFooter()) {
5542 VikBookingHelper::printFooter();
5543 }
5544 }
5545
5546 public function removecustomers() {
5547 if (!JSession::checkToken()) {
5548 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5549 }
5550 $ids = VikRequest::getVar('cid', array(0));
5551 if (@count($ids)) {
5552 $dbo = JFactory::getDBO();
5553 $cpin = VikBooking::getCPinIstance();
5554 foreach ($ids as $d) {
5555 $cpin->pluginCustomerSync($d, 'delete');
5556 $q = "DELETE FROM `#__vikbooking_customers` WHERE `id`=".(int)$d.";";
5557 $dbo->setQuery($q);
5558 $dbo->execute();
5559 }
5560 }
5561 $mainframe = JFactory::getApplication();
5562 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
5563 }
5564
5565 public function restrictions() {
5566 VikBookingHelper::printHeader("restrictions");
5567
5568 VikRequest::setVar('view', VikRequest::getCmd('view', 'restrictions'));
5569
5570 parent::display();
5571
5572 if (VikBooking::showFooter()) {
5573 VikBookingHelper::printFooter();
5574 }
5575 }
5576
5577 public function newrestriction() {
5578 VikBookingHelper::printHeader("restrictions");
5579
5580 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5581
5582 parent::display();
5583
5584 if (VikBooking::showFooter()) {
5585 VikBookingHelper::printFooter();
5586 }
5587 }
5588
5589 public function editrestriction() {
5590 VikBookingHelper::printHeader("restrictions");
5591
5592 VikRequest::setVar('view', VikRequest::getCmd('view', 'managerestriction'));
5593
5594 parent::display();
5595
5596 if (VikBooking::showFooter()) {
5597 VikBookingHelper::printFooter();
5598 }
5599 }
5600
5601 public function createrestriction() {
5602 if (!JSession::checkToken()) {
5603 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5604 }
5605 $dbo = JFactory::getDBO();
5606 $session = JFactory::getSession();
5607 $mainframe = JFactory::getApplication();
5608 $updforvcm = $session->get('vbVcmRatesUpd', '');
5609 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5610 $pname = VikRequest::getString('name', '', 'request');
5611 $pmonth = VikRequest::getInt('month', '', 'request');
5612 $pmonth = empty($pmonth) ? 0 : $pmonth;
5613 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5614 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5615 $pdto = VikRequest::getString('dto', '', 'request');
5616 $pwday = VikRequest::getString('wday', '', 'request');
5617 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5618 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5619 $pcomboa = VikRequest::getString('comboa', '', 'request');
5620 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5621 $pcombob = VikRequest::getString('combob', '', 'request');
5622 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5623 $pcomboc = VikRequest::getString('comboc', '', 'request');
5624 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5625 $pcombod = VikRequest::getString('combod', '', 'request');
5626 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5627 $combostr = '';
5628 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5629 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5630 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5631 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5632 $pminlos = VikRequest::getInt('minlos', '', 'request');
5633 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5634 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5635 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5636 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5637 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5638 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5639 $pallrooms = $pallrooms == "1" ? 1 : 0;
5640 $pidrooms = VikRequest::getVar('idrooms', array(0));
5641 $ridr = '';
5642 $roomidsforsess = array();
5643 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5644 foreach ($pidrooms as $idr) {
5645 if (empty($idr)) {
5646 continue;
5647 }
5648 $ridr .= '-'.$idr.'-;';
5649 $roomidsforsess[] = (int)$idr;
5650 }
5651 } elseif ($pallrooms > 0) {
5652 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5653 $dbo->setQuery($q);
5654 $dbo->execute();
5655 if ($dbo->getNumRows() > 0) {
5656 $fetchids = $dbo->loadAssocList();
5657 foreach ($fetchids as $fetchid) {
5658 $roomidsforsess[] = (int)$fetchid['id'];
5659 }
5660 }
5661 }
5662 $pcta = VikRequest::getInt('cta', '', 'request');
5663 $pctd = VikRequest::getInt('ctd', '', 'request');
5664 $pctad = VikRequest::getVar('ctad', array());
5665 $pctdd = VikRequest::getVar('ctdd', array());
5666 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5667 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5668 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5669 // $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5670 // exit;
5671 }
5672
5673 //check if there are restrictions for this month
5674 if ($pmonth > 0) {
5675 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."';";
5676 $dbo->setQuery($q);
5677 $dbo->execute();
5678 if ($dbo->getNumRows() > 0) {
5679 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5680 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5681 exit;
5682 }
5683 $pdfrom = 0;
5684 $pdto = 0;
5685 } else {
5686 //dates range
5687 if (empty($pdfrom) || empty($pdto)) {
5688 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5689 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5690 exit;
5691 } else {
5692 $housto = $pdfrom == $pdto ? 23 : 0;
5693 $minsto = $pdfrom == $pdto ? 59 : 0;
5694 $secsto = $pdfrom == $pdto ? 59 : 0;
5695 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5696 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5697 }
5698 if ($pdfrom > $pdto) {
5699 // invalid dates in the past
5700 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5701 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5702 exit;
5703 }
5704 }
5705 //CTA and CTD
5706 $setcta = array();
5707 $setctd = array();
5708 if ($pcta > 0 && count($pctad) > 0) {
5709 foreach ($pctad as $ctwd) {
5710 if (strlen($ctwd)) {
5711 $setcta[] = '-'.(int)$ctwd.'-';
5712 }
5713 }
5714 }
5715 if ($pctd > 0 && count($pctdd) > 0) {
5716 foreach ($pctdd as $ctwd) {
5717 if (strlen($ctwd)) {
5718 $setctd[] = '-'.(int)$ctwd.'-';
5719 }
5720 }
5721 }
5722 //
5723 //update session values
5724 if (!($pdfrom > 0)) {
5725 $attemptyear = (int)date('Y');
5726 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5727 if ($attemptfrom < time()) {
5728 $attemptyear++;
5729 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5730 }
5731 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5732 } else {
5733 $attemptfrom = $pdfrom;
5734 $attemptto = $pdto;
5735 }
5736 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5737 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5738 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5739 } else {
5740 $updforvcm['dfrom'] = $attemptfrom;
5741 }
5742 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5743 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5744 } else {
5745 $updforvcm['dto'] = $attemptto;
5746 }
5747 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5748 foreach ($roomidsforsess as $rid) {
5749 if (!in_array($rid, $updforvcm['rooms'])) {
5750 $updforvcm['rooms'][] = $rid;
5751 }
5752 }
5753 } else {
5754 $updforvcm['rooms'] = $roomidsforsess;
5755 }
5756 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
5757 $updforvcm['rplans'] = array();
5758 }
5759 $session->set('vbVcmRatesUpd', $updforvcm);
5760 //
5761 $q = "INSERT INTO `#__vikbooking_restrictions` (`name`,`month`,`wday`,`minlos`,`multiplyminlos`,`maxlos`,`dfrom`,`dto`,`wdaytwo`,`wdaycombo`,`allrooms`,`idrooms`,`ctad`,`ctdd`) VALUES(".$dbo->quote($pname).", '".$pmonth."', ".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").", '".$pminlos."', '".$pmultiplyminlos."', '".$pmaxlos."', ".$pdfrom.", ".$pdto.", ".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").", ".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").", ".$pallrooms.", ".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", ".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", ".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL").");";
5762 $dbo->setQuery($q);
5763 $dbo->execute();
5764 $lid = $dbo->insertid();
5765 if (!empty($lid)) {
5766 /**
5767 * Repeat restriction on the selected week days until the limit
5768 *
5769 * @since 1.13
5770 */
5771 $prepeat = VikRequest::getInt('repeat', 0, 'request');
5772 $prepeatuntil = VikRequest::getString('repeatuntil', '', 'request');
5773 if ($prepeat > 0 && !empty($prepeatuntil) && $pdfrom > 0 && $pdto > 0) {
5774 $repeat_intervals = array();
5775 $start = getdate($pdfrom);
5776 $end = getdate($pdto);
5777 $wdays = array();
5778 while ($start[0] <= $end[0]) {
5779 // push requested week day
5780 array_push($wdays, $start['wday']);
5781 // next day
5782 $start = getdate(mktime($start['hours'], $start['minutes'], $start['seconds'], $start['mon'], ($start['mday'] + 1), $start['year']));
5783 }
5784 $dtuntil = VikBooking::getDateTimestamp($prepeatuntil, 23, 59, 59);
5785 if (count($wdays) < 7 && $dtuntil > $pdto) {
5786 // increment end date for the repeat
5787 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5788 //
5789 $until_info = getdate($dtuntil);
5790 $interval = array();
5791 while ($end[0] <= $until_info[0]) {
5792 if (in_array($end['wday'], $wdays)) {
5793 if (!isset($interval['from'])) {
5794 $interval['from'] = $end[0];
5795 }
5796 $interval['to'] = $end[0];
5797 } else {
5798 if (isset($interval['from'])) {
5799 // append interval
5800 array_push($repeat_intervals, $interval);
5801 // reset interval
5802 $interval = array();
5803 }
5804 }
5805 // next day
5806 $end = getdate(mktime($end['hours'], $end['minutes'], $end['seconds'], $end['mon'], ($end['mday'] + 1), $end['year']));
5807 }
5808 if (isset($interval['from'])) {
5809 // append last hanging interval
5810 array_push($repeat_intervals, $interval);
5811 }
5812 if (count($repeat_intervals)) {
5813 // create the repeated records for the calculated intervals
5814 $repeat_count = 2;
5815 foreach ($repeat_intervals as $rp) {
5816 if (date('Y-m-d', $rp['from']) == date('Y-m-d', $rp['to'])) {
5817 // adjust time in case of equal dates (1 single day restriction)
5818 $rpfrom = getdate($rp['from']);
5819 $rpto = getdate($rp['to']);
5820 $rp['from'] = mktime(0, 0, 0, $rpfrom['mon'], $rpfrom['mday'], $rpfrom['year']);
5821 /**
5822 * The end date of the restriction must cover the whole day until 23:59:59.
5823 *
5824 * @since 1.15.4 (J) - 1.5.4 (WP)
5825 */
5826 $rp['to'] = mktime(23, 59, 59, $rpto['mon'], $rpto['mday'], $rpto['year']);
5827 }
5828 // adjust name
5829 $restr_rp_name = $pname . " #{$repeat_count}";
5830 //
5831 $q = "INSERT INTO `#__vikbooking_restrictions` (`name`,`month`,`wday`,`minlos`,`multiplyminlos`,`maxlos`,`dfrom`,`dto`,`wdaytwo`,`wdaycombo`,`allrooms`,`idrooms`,`ctad`,`ctdd`) VALUES(".$dbo->quote($restr_rp_name).", '".$pmonth."', ".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").", '".$pminlos."', '".$pmultiplyminlos."', '".$pmaxlos."', ".$rp['from'].", ".$rp['to'].", ".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").", ".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").", ".$pallrooms.", ".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", ".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", ".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL").");";
5832 $dbo->setQuery($q);
5833 $dbo->execute();
5834 $lid = $dbo->insertid();
5835 if (!empty($lid)) {
5836 $repeat_count++;
5837 }
5838 }
5839 }
5840 }
5841 }
5842 //
5843 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
5844 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
5845 } else {
5846 VikError::raiseWarning('', 'Error while saving');
5847 $mainframe->redirect("index.php?option=com_vikbooking&task=newrestriction");
5848 }
5849 }
5850
5851 public function updaterestriction() {
5852 if (!JSession::checkToken()) {
5853 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
5854 }
5855 $dbo = JFactory::getDBO();
5856 $session = JFactory::getSession();
5857 $mainframe = JFactory::getApplication();
5858 $updforvcm = $session->get('vbVcmRatesUpd', '');
5859 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
5860 $pwhere = VikRequest::getInt('where', '', 'request');
5861 $pname = VikRequest::getString('name', '', 'request');
5862 $pmonth = VikRequest::getInt('month', '', 'request');
5863 $pmonth = empty($pmonth) ? 0 : $pmonth;
5864 $pname = empty($pname) ? 'Restriction '.$pmonth : $pname;
5865 $pdfrom = VikRequest::getString('dfrom', '', 'request');
5866 $pdto = VikRequest::getString('dto', '', 'request');
5867 $pwday = VikRequest::getString('wday', '', 'request');
5868 $pwdaytwo = VikRequest::getString('wdaytwo', '', 'request');
5869 $pwdaytwo = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday == $pwdaytwo ? '' : $pwdaytwo;
5870 $pcomboa = VikRequest::getString('comboa', '', 'request');
5871 $pcomboa = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboa : '';
5872 $pcombob = VikRequest::getString('combob', '', 'request');
5873 $pcombob = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombob : '';
5874 $pcomboc = VikRequest::getString('comboc', '', 'request');
5875 $pcomboc = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcomboc : '';
5876 $pcombod = VikRequest::getString('combod', '', 'request');
5877 $pcombod = strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo ? $pcombod : '';
5878 $combostr = '';
5879 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboa) ? $pcomboa.':' : ':';
5880 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombob) ? $pcombob.':' : ':';
5881 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcomboc) ? $pcomboc.':' : ':';
5882 $combostr .= strlen($pwday) > 0 && strlen($pwdaytwo) > 0 && $pwday != $pwdaytwo && !empty($pcombod) ? $pcombod : '';
5883 $pminlos = VikRequest::getInt('minlos', '', 'request');
5884 $pminlos = $pminlos < 1 ? 1 : $pminlos;
5885 $pmaxlos = VikRequest::getInt('maxlos', '', 'request');
5886 $pmaxlos = empty($pmaxlos) ? 0 : $pmaxlos;
5887 $pmultiplyminlos = VikRequest::getString('multiplyminlos', '', 'request');
5888 $pmultiplyminlos = empty($pmultiplyminlos) ? 0 : 1;
5889 $pallrooms = VikRequest::getString('allrooms', '', 'request');
5890 $pallrooms = $pallrooms == "1" ? 1 : 0;
5891 $pidrooms = VikRequest::getVar('idrooms', array(0));
5892 $ridr = '';
5893 $roomidsforsess = array();
5894 if (!empty($pidrooms) && @count($pidrooms) && $pallrooms == 0) {
5895 foreach ($pidrooms as $idr) {
5896 if (empty($idr)) {
5897 continue;
5898 }
5899 $ridr .= '-'.$idr.'-;';
5900 $roomidsforsess[] = (int)$idr;
5901 }
5902 } elseif ($pallrooms > 0) {
5903 $q = "SELECT `id` FROM `#__vikbooking_rooms`;";
5904 $dbo->setQuery($q);
5905 $dbo->execute();
5906 if ($dbo->getNumRows() > 0) {
5907 $fetchids = $dbo->loadAssocList();
5908 foreach ($fetchids as $fetchid) {
5909 $roomidsforsess[] = (int)$fetchid['id'];
5910 }
5911 }
5912 }
5913 $pcta = VikRequest::getInt('cta', '', 'request');
5914 $pctd = VikRequest::getInt('ctd', '', 'request');
5915 $pctad = VikRequest::getVar('ctad', array());
5916 $pctdd = VikRequest::getVar('ctdd', array());
5917 if ($pminlos == 1 && strlen($pwday) == 0 && empty($pctad) && empty($pctdd) && $pmaxlos < 1) {
5918 // VBO 1.11 - we now allow restrictions with just 1 night of stay
5919 // VikError::raiseWarning('', JText::translate('VBUSELESSRESTRICTION'));
5920 // $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5921 // exit;
5922 }
5923 //check if there are restrictions for this month
5924 if ($pmonth > 0) {
5925 $q = "SELECT `id` FROM `#__vikbooking_restrictions` WHERE `month`='".$pmonth."' AND `id`!='".$pwhere."';";
5926 $dbo->setQuery($q);
5927 $dbo->execute();
5928 if ($dbo->getNumRows() > 0) {
5929 VikError::raiseWarning('', JText::translate('VBRESTRICTIONMONTHEXISTS'));
5930 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5931 exit;
5932 }
5933 $pdfrom = 0;
5934 $pdto = 0;
5935 } else {
5936 //dates range
5937 if (empty($pdfrom) || empty($pdto)) {
5938 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5939 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5940 exit;
5941 } else {
5942 $housto = $pdfrom == $pdto ? 23 : 0;
5943 $minsto = $pdfrom == $pdto ? 59 : 0;
5944 $secsto = $pdfrom == $pdto ? 59 : 0;
5945 $pdfrom = VikBooking::getDateTimestamp($pdfrom, 0, 0);
5946 $pdto = VikBooking::getDateTimestamp($pdto, $housto, $minsto, $secsto);
5947 }
5948 if ($pdfrom > $pdto) {
5949 // invalid dates in the past
5950 VikError::raiseWarning('', JText::translate('VBRESTRICTIONERRDRANGE'));
5951 $mainframe->redirect("index.php?option=com_vikbooking&task=editrestriction&cid[]=".$pwhere);
5952 exit;
5953 }
5954 }
5955 //CTA and CTD
5956 $setcta = array();
5957 $setctd = array();
5958 if ($pcta > 0 && count($pctad) > 0) {
5959 foreach ($pctad as $ctwd) {
5960 if (strlen($ctwd)) {
5961 $setcta[] = '-'.(int)$ctwd.'-';
5962 }
5963 }
5964 }
5965 if ($pctd > 0 && count($pctdd) > 0) {
5966 foreach ($pctdd as $ctwd) {
5967 if (strlen($ctwd)) {
5968 $setctd[] = '-'.(int)$ctwd.'-';
5969 }
5970 }
5971 }
5972 //
5973 //update session values
5974 if (!($pdfrom > 0)) {
5975 $attemptyear = (int)date('Y');
5976 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5977 if ($attemptfrom < time()) {
5978 $attemptyear++;
5979 $attemptfrom = mktime(0, 0, 0, $pmonth, 1, $attemptyear);
5980 }
5981 $attemptto = mktime(0, 0, 0, $pmonth, date('t', $attemptfrom), $attemptyear);
5982 } else {
5983 $attemptfrom = $pdfrom;
5984 $attemptto = $pdto;
5985 }
5986 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
5987 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
5988 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $attemptfrom ? $attemptfrom : $updforvcm['dfrom'];
5989 } else {
5990 $updforvcm['dfrom'] = $attemptfrom;
5991 }
5992 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
5993 $updforvcm['dto'] = $updforvcm['dto'] < $attemptto ? $attemptto : $updforvcm['dto'];
5994 } else {
5995 $updforvcm['dto'] = $attemptto;
5996 }
5997 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
5998 foreach ($roomidsforsess as $rid) {
5999 if (!in_array($rid, $updforvcm['rooms'])) {
6000 $updforvcm['rooms'][] = $rid;
6001 }
6002 }
6003 } else {
6004 $updforvcm['rooms'] = $roomidsforsess;
6005 }
6006 if (!array_key_exists('rplans', $updforvcm) || !is_array($updforvcm['rplans'])) {
6007 $updforvcm['rplans'] = array();
6008 }
6009 $session->set('vbVcmRatesUpd', $updforvcm);
6010 //
6011 $q = "UPDATE `#__vikbooking_restrictions` SET `name`=".$dbo->quote($pname).",`month`='".$pmonth."',`wday`=".(strlen($pwday) > 0 ? "'".$pwday."'" : "NULL").",`minlos`='".$pminlos."',`multiplyminlos`='".$pmultiplyminlos."',`maxlos`='".$pmaxlos."',`dfrom`=".$pdfrom.",`dto`=".$pdto.",`wdaytwo`=".(strlen($pwday) > 0 && strlen($pwdaytwo) > 0 ? intval($pwdaytwo) : "NULL").",`wdaycombo`=".(strlen($combostr) > 0 ? $dbo->quote($combostr) : "NULL").",`allrooms`=".$pallrooms.",`idrooms`=".(strlen($ridr) > 0 ? $dbo->quote($ridr) : "NULL").", `ctad`=".(count($setcta) > 0 ? $dbo->quote(implode(',', $setcta)) : "NULL").", `ctdd`=".(count($setctd) > 0 ? $dbo->quote(implode(',', $setctd)) : "NULL")." WHERE `id`='".$pwhere."';";
6012 $dbo->setQuery($q);
6013 $dbo->execute();
6014 $mainframe->enqueueMessage(JText::translate('VBRESTRICTIONSAVED'));
6015 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6016 }
6017
6018 public function removerestrictions() {
6019 if (!JSession::checkToken()) {
6020 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6021 }
6022 $ids = VikRequest::getVar('cid', array(0));
6023 if (@count($ids)) {
6024 $dbo = JFactory::getDBO();
6025 foreach ($ids as $d) {
6026 $q = "DELETE FROM `#__vikbooking_restrictions` WHERE `id`=".(int)$d.";";
6027 $dbo->setQuery($q);
6028 $dbo->execute();
6029 }
6030 }
6031 $mainframe = JFactory::getApplication();
6032 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
6033 }
6034
6035 public function prices() {
6036 VikBookingHelper::printHeader("1");
6037
6038 VikRequest::setVar('view', VikRequest::getCmd('view', 'prices'));
6039
6040 parent::display();
6041
6042 if (VikBooking::showFooter()) {
6043 VikBookingHelper::printFooter();
6044 }
6045 }
6046
6047 public function newprice() {
6048 VikBookingHelper::printHeader("1");
6049
6050 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6051
6052 parent::display();
6053
6054 if (VikBooking::showFooter()) {
6055 VikBookingHelper::printFooter();
6056 }
6057 }
6058
6059 public function editprice() {
6060 VikBookingHelper::printHeader("1");
6061
6062 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageprice'));
6063
6064 parent::display();
6065
6066 if (VikBooking::showFooter()) {
6067 VikBookingHelper::printFooter();
6068 }
6069 }
6070
6071 public function createprice() {
6072 if (!JSession::checkToken()) {
6073 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6074 }
6075 $this->do_createprice();
6076 }
6077
6078 public function createprice_new() {
6079 if (!JSession::checkToken()) {
6080 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6081 }
6082 $this->do_createprice(true);
6083 }
6084
6085 private function do_createprice($new = false)
6086 {
6087 $pprice = VikRequest::getString('price', '', 'request');
6088 $pattr = VikRequest::getString('attr', '', 'request');
6089 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6090 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6091 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6092 $pfree_cancellation = VikRequest::getInt('free_cancellation', 0, 'request');
6093 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6094 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6095 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6096 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6097 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6098 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6099 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6100 if (!empty($pprice)) {
6101 $dbo = JFactory::getDbo();
6102 $q = "INSERT INTO `#__vikbooking_prices` (`name`,`attr`,`idiva`,`breakfast_included`,`free_cancellation`,`canc_deadline`,`canc_policy`,`minlos`,`minhadv`,`meal_plans`) VALUES(" . $dbo->q($pprice) . ", " . $dbo->q($pattr) . ", " . $dbo->q($ppraliq) . ", " . $pbreakfast_included . ", " . $pfree_cancellation . ", " . $pcanc_deadline . ", " . $dbo->q($pcanc_policy) . ", " . $pminlos . ", " . $pminhadv . ", " . $dbo->q(json_encode($pmeal_plans)) . ");";
6103 $dbo->setQuery($q);
6104 $dbo->execute();
6105 }
6106
6107 $app = JFactory::getApplication();
6108 $app->redirect("index.php?option=com_vikbooking&task=" . ($new ? 'newprice' : 'prices'));
6109 $app->close();
6110 }
6111
6112 public function updateprice()
6113 {
6114 if (!JSession::checkToken()) {
6115 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6116 }
6117 $this->do_updateprice();
6118 }
6119
6120 public function updatepricestay()
6121 {
6122 if (!JSession::checkToken()) {
6123 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6124 }
6125 $this->do_updateprice(true);
6126 }
6127
6128 private function do_updateprice($stay = false)
6129 {
6130 $pprice = VikRequest::getString('price', '', 'request');
6131 $pattr = VikRequest::getString('attr', '', 'request');
6132 $ppraliq = VikRequest::getInt('praliq', '', 'request');
6133 $pmeal_plans = (array)VikRequest::getVar('meal_plans', []);
6134 $pbreakfast_included = in_array('breakfast', $pmeal_plans) ? 1 : 0;
6135 $pfree_cancellation = VikRequest::getInt('free_cancellation', '', 'request');
6136 $pfree_cancellation = $pfree_cancellation == 1 ? 1 : 0;
6137 $pcanc_deadline = VikRequest::getInt('canc_deadline', '', 'request');
6138 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6139 $pminlos = $pminlos < 0 ? 0 : $pminlos;
6140 $pminhadv = VikRequest::getInt('minhadv', '', 'request');
6141 $pminhadv = $pminhadv < 0 ? 0 : $pminhadv;
6142 $pcanc_policy = VikRequest::getString('canc_policy', '', 'request', VIKREQUEST_ALLOWHTML);
6143 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6144 if (!empty($pprice) && $pwhereup) {
6145 $dbo = JFactory::getDbo();
6146 $q = "UPDATE `#__vikbooking_prices` SET `name`=" . $dbo->q($pprice) . ",`attr`=" . $dbo->q($pattr) . ",`idiva`=" . $dbo->q($ppraliq) . ",`breakfast_included`=" . $pbreakfast_included . ",`free_cancellation`=" . $pfree_cancellation . ",`canc_deadline`=" . $pcanc_deadline . ",`canc_policy`=" . $dbo->q($pcanc_policy) . ",`minlos`=" . $pminlos . ",`minhadv`=" . $pminhadv . ",`meal_plans`=" . $dbo->q(json_encode($pmeal_plans)) . " WHERE `id`=" . $dbo->q($pwhereup) . ";";
6147 $dbo->setQuery($q);
6148 $dbo->execute();
6149 }
6150
6151 $app = JFactory::getApplication();
6152 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editprice&cid[]=' . $pwhereup : 'prices'));
6153 $app->close();
6154 }
6155
6156 public function removeprice() {
6157 if (!JSession::checkToken()) {
6158 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6159 }
6160 $ids = VikRequest::getVar('cid', array(0));
6161 if (@count($ids)) {
6162 $dbo = JFactory::getDBO();
6163 foreach ($ids as $d) {
6164 $q = "DELETE FROM `#__vikbooking_prices` WHERE `id`=".$dbo->quote($d).";";
6165 $dbo->setQuery($q);
6166 $dbo->execute();
6167 $q = "DELETE FROM `#__vikbooking_dispcost` WHERE `idprice`=".intval($d).";";
6168 $dbo->setQuery($q);
6169 $dbo->execute();
6170 }
6171 }
6172 $mainframe = JFactory::getApplication();
6173 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
6174 }
6175
6176 public function iva() {
6177 VikBookingHelper::printHeader("2");
6178
6179 VikRequest::setVar('view', VikRequest::getCmd('view', 'iva'));
6180
6181 parent::display();
6182
6183 if (VikBooking::showFooter()) {
6184 VikBookingHelper::printFooter();
6185 }
6186 }
6187
6188 public function newiva() {
6189 VikBookingHelper::printHeader("2");
6190
6191 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6192
6193 parent::display();
6194
6195 if (VikBooking::showFooter()) {
6196 VikBookingHelper::printFooter();
6197 }
6198 }
6199
6200 public function editiva() {
6201 VikBookingHelper::printHeader("2");
6202
6203 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageiva'));
6204
6205 parent::display();
6206
6207 if (VikBooking::showFooter()) {
6208 VikBookingHelper::printFooter();
6209 }
6210 }
6211
6212 public function createiva() {
6213 if (!JSession::checkToken()) {
6214 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6215 }
6216 $paliqname = VikRequest::getString('aliqname', '', 'request');
6217 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6218 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6219 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6220 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6221 if (!empty($paliqperc)) {
6222 $dbo = JFactory::getDBO();
6223 $breakdown_str = '';
6224 if (count($pbreakdown_name) > 0) {
6225 $breakdown_values = array();
6226 $bkcount = 0;
6227 $tot_sub_aliq = 0;
6228 foreach ($pbreakdown_name as $key => $subtax) {
6229 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6230 $breakdown_values[$bkcount]['name'] = $subtax;
6231 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6232 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6233 $bkcount++;
6234 }
6235 }
6236 if (count($breakdown_values) > 0) {
6237 $breakdown_str = json_encode($breakdown_values);
6238 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6239 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6240 }
6241 }
6242 }
6243 $q = "INSERT INTO `#__vikbooking_iva` (`name`,`aliq`,`breakdown`,`taxcap`) VALUES(".$dbo->quote($paliqname).", ".$dbo->quote($paliqperc).", ".(empty($breakdown_str) ? 'NULL' : $dbo->quote($breakdown_str)).", ".($ptaxcap > 0 ? $dbo->quote($ptaxcap) : 'NULL').");";
6244 $dbo->setQuery($q);
6245 $dbo->execute();
6246 }
6247 $mainframe = JFactory::getApplication();
6248 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6249 }
6250
6251 public function updateiva() {
6252 if (!JSession::checkToken()) {
6253 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6254 }
6255 $paliqname = VikRequest::getString('aliqname', '', 'request');
6256 $paliqperc = VikRequest::getFloat('aliqperc', '', 'request');
6257 $pbreakdown_name = VikRequest::getVar('breakdown_name', array());
6258 $pbreakdown_rate = VikRequest::getVar('breakdown_rate', array());
6259 $ptaxcap = VikRequest::getFloat('taxcap', 0, 'request');
6260 $pwhereup = VikRequest::getInt('whereup', 0, 'request');
6261 if (!empty($paliqperc)) {
6262 $dbo = JFactory::getDBO();
6263 $breakdown_str = '';
6264 if (count($pbreakdown_name) > 0) {
6265 $breakdown_values = array();
6266 $bkcount = 0;
6267 $tot_sub_aliq = 0;
6268 foreach ($pbreakdown_name as $key => $subtax) {
6269 if (!empty($subtax) && floatval($pbreakdown_rate[$key]) > 0) {
6270 $breakdown_values[$bkcount]['name'] = $subtax;
6271 $breakdown_values[$bkcount]['aliq'] = (float)$pbreakdown_rate[$key];
6272 $tot_sub_aliq += (float)$pbreakdown_rate[$key];
6273 $bkcount++;
6274 }
6275 }
6276 if (count($breakdown_values) > 0) {
6277 $breakdown_str = json_encode($breakdown_values);
6278 if ($tot_sub_aliq < (float)$paliqperc || $tot_sub_aliq > (float)$paliqperc) {
6279 VikError::raiseWarning('', JText::translate('VBOTAXBKDWNERRNOMATCH'));
6280 }
6281 }
6282 }
6283 $q = "UPDATE `#__vikbooking_iva` SET `name`=".$dbo->quote($paliqname).",`aliq`=".$dbo->quote($paliqperc).",`breakdown`=".(empty($breakdown_str) ? 'NULL' : $dbo->quote($breakdown_str)).",`taxcap`=".($ptaxcap > 0 ? $dbo->quote($ptaxcap) : 'NULL')." WHERE `id`=".$dbo->quote($pwhereup).";";
6284 $dbo->setQuery($q);
6285 $dbo->execute();
6286 }
6287 $mainframe = JFactory::getApplication();
6288 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6289 }
6290
6291 public function removeiva() {
6292 if (!JSession::checkToken()) {
6293 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6294 }
6295 $ids = VikRequest::getVar('cid', array(0));
6296 if (@count($ids)) {
6297 $dbo = JFactory::getDBO();
6298 foreach ($ids as $d) {
6299 $q = "DELETE FROM `#__vikbooking_iva` WHERE `id`=".$dbo->quote($d).";";
6300 $dbo->setQuery($q);
6301 $dbo->execute();
6302 }
6303 }
6304 $mainframe = JFactory::getApplication();
6305 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
6306 }
6307
6308 public function categories() {
6309 VikBookingHelper::printHeader("4");
6310
6311 VikRequest::setVar('view', VikRequest::getCmd('view', 'categories'));
6312
6313 parent::display();
6314
6315 if (VikBooking::showFooter()) {
6316 VikBookingHelper::printFooter();
6317 }
6318 }
6319
6320 public function newcat() {
6321 VikBookingHelper::printHeader("4");
6322
6323 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6324
6325 parent::display();
6326
6327 if (VikBooking::showFooter()) {
6328 VikBookingHelper::printFooter();
6329 }
6330 }
6331
6332 public function editcat() {
6333 VikBookingHelper::printHeader("4");
6334
6335 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecategory'));
6336
6337 parent::display();
6338
6339 if (VikBooking::showFooter()) {
6340 VikBookingHelper::printFooter();
6341 }
6342 }
6343
6344 public function createcat() {
6345 if (!JSession::checkToken()) {
6346 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6347 }
6348 $pcatname = VikRequest::getString('catname', '', 'request');
6349 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6350 if (!empty($pcatname)) {
6351 $dbo = JFactory::getDBO();
6352 $q = "INSERT INTO `#__vikbooking_categories` (`name`,`descr`) VALUES(".$dbo->quote($pcatname).", ".$dbo->quote($pdescr).");";
6353 $dbo->setQuery($q);
6354 $dbo->execute();
6355 }
6356 $mainframe = JFactory::getApplication();
6357 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6358 }
6359
6360 public function updatecat() {
6361 if (!JSession::checkToken()) {
6362 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6363 }
6364 $pcatname = VikRequest::getString('catname', '', 'request');
6365 $pdescr = VikRequest::getString('descr', '', 'request', VIKREQUEST_ALLOWHTML);
6366 $pwhereup = VikRequest::getString('whereup', '', 'request');
6367 if (!empty($pcatname)) {
6368 $dbo = JFactory::getDBO();
6369 $q = "UPDATE `#__vikbooking_categories` SET `name`=".$dbo->quote($pcatname).", `descr`=".$dbo->quote($pdescr)." WHERE `id`=".$dbo->quote($pwhereup).";";
6370 $dbo->setQuery($q);
6371 $dbo->execute();
6372 }
6373 $mainframe = JFactory::getApplication();
6374 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6375 }
6376
6377 public function removecat() {
6378 $ids = VikRequest::getVar('cid', array(0));
6379 if (@count($ids)) {
6380 $dbo = JFactory::getDBO();
6381 foreach ($ids as $d) {
6382 $q = "DELETE FROM `#__vikbooking_categories` WHERE `id`=".$dbo->quote($d).";";
6383 $dbo->setQuery($q);
6384 $dbo->execute();
6385 }
6386 }
6387 $mainframe = JFactory::getApplication();
6388 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
6389 }
6390
6391 public function carat() {
6392 VikBookingHelper::printHeader("5");
6393
6394 VikRequest::setVar('view', VikRequest::getCmd('view', 'carat'));
6395
6396 parent::display();
6397
6398 if (VikBooking::showFooter()) {
6399 VikBookingHelper::printFooter();
6400 }
6401 }
6402
6403 public function newcarat() {
6404 VikBookingHelper::printHeader("5");
6405
6406 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6407
6408 parent::display();
6409
6410 if (VikBooking::showFooter()) {
6411 VikBookingHelper::printFooter();
6412 }
6413 }
6414
6415 public function editcarat() {
6416 VikBookingHelper::printHeader("5");
6417
6418 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecarat'));
6419
6420 parent::display();
6421
6422 if (VikBooking::showFooter()) {
6423 VikBookingHelper::printFooter();
6424 }
6425 }
6426
6427 public function createcarat() {
6428 if (!JSession::checkToken()) {
6429 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6430 }
6431 $pcaratname = VikRequest::getString('caratname', '', 'request');
6432 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6433 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6434 $presizeto = VikRequest::getString('resizeto', '', 'request');
6435 $pidrooms = VikRequest::getVar('idrooms', array());
6436 if (!empty($pcaratname)) {
6437 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6438 jimport('joomla.filesystem.file');
6439 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6440 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6441 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6442 if (file_exists($updpath.$safename)) {
6443 $j=1;
6444 while (file_exists($updpath.$j.$safename)) {
6445 $j++;
6446 }
6447 $pwhere=$updpath.$j.$safename;
6448 } else {
6449 $j="";
6450 $pwhere=$updpath.$safename;
6451 }
6452 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6453 @unlink($pwhere);
6454 $picon="";
6455 } else {
6456 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6457 @chmod($pwhere, 0644);
6458 $picon=$j.$safename;
6459 if ($pautoresize=="1" && !empty($presizeto)) {
6460 $eforj = new vikResizer();
6461 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6462 if ($origmod) {
6463 @unlink($pwhere);
6464 $picon='r_'.$j.$safename;
6465 }
6466 }
6467 }
6468 } else {
6469 $picon="";
6470 }
6471 } else {
6472 $picon="";
6473 }
6474 $dbo = JFactory::getDbo();
6475 // get new ordering
6476 $q = "SELECT `ordering` FROM `#__vikbooking_characteristics` ORDER BY `#__vikbooking_characteristics`.`ordering` DESC LIMIT 1;";
6477 $dbo->setQuery($q);
6478 $dbo->execute();
6479 if ($dbo->getNumRows()) {
6480 $newsortnum = $dbo->loadResult() + 1;
6481 } else {
6482 $newsortnum = 1;
6483 }
6484 $pordering = VikRequest::getInt('ordering', 0, 'request');
6485 $newsortnum = !empty($pordering) ? $pordering : $newsortnum;
6486 //
6487 $q = "INSERT INTO `#__vikbooking_characteristics` (`name`,`icon`,`textimg`,`ordering`) VALUES(".$dbo->quote($pcaratname).", ".$dbo->quote($picon).", ".$dbo->quote($pcarattextimg).", {$newsortnum});";
6488 $dbo->setQuery($q);
6489 $dbo->execute();
6490
6491 $new_carat_id = $dbo->insertid();
6492 if (!empty($new_carat_id)) {
6493 // assign/unset carat-rooms relations
6494 $rooms_with_carat = array();
6495 if (count($pidrooms)) {
6496 // assign this new carat to the requested rooms
6497 foreach ($pidrooms as $idroom) {
6498 if (empty($idroom)) {
6499 continue;
6500 }
6501 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6502 $dbo->setQuery($q);
6503 $dbo->execute();
6504 if (!$dbo->getNumRows()) {
6505 continue;
6506 }
6507 $room_data = $dbo->loadAssoc();
6508 array_push($rooms_with_carat, $room_data['id']);
6509 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6510 if (in_array((string)$new_carat_id, $current_carats)) {
6511 continue;
6512 }
6513 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6514 // make sure we do not concatenate a real ID to 0
6515 $current_carats = array();
6516 }
6517 array_push($current_carats, $new_carat_id);
6518 $new_opts = implode(';', $current_carats) . ';';
6519 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6520 $dbo->setQuery($q);
6521 $dbo->execute();
6522 }
6523 }
6524 if (!count($rooms_with_carat)) {
6525 // get all rooms to unset this carat (if previously set)
6526 array_push($rooms_with_carat, '0');
6527 }
6528 // unset the carat from the other rooms that may have it
6529 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6530 $dbo->setQuery($q);
6531 $dbo->execute();
6532 if ($dbo->getNumRows()) {
6533 $unset_rooms_carat = $dbo->loadAssocList();
6534 foreach ($unset_rooms_carat as $room_data) {
6535 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6536 if (!in_array((string)$new_carat_id, $current_carats)) {
6537 // this room is not using this carat
6538 continue;
6539 }
6540 $caratkey = array_search((string)$new_carat_id, $current_carats);
6541 if ($caratkey === false) {
6542 // key not found
6543 continue;
6544 }
6545 // unset this carat ID from the string
6546 unset($current_carats[$caratkey]);
6547 if (!count($current_carats)) {
6548 // a room with no carats assigned will be listed as "0;"
6549 $current_carats = array(0);
6550 }
6551 $new_opts = implode(';', $current_carats) . ';';
6552 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
6553 $dbo->setQuery($q);
6554 $dbo->execute();
6555 }
6556 }
6557 //
6558 }
6559 }
6560 $mainframe = JFactory::getApplication();
6561 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6562 }
6563
6564 public function updatecarat() {
6565 if (!JSession::checkToken()) {
6566 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6567 }
6568 $pcaratname = VikRequest::getString('caratname', '', 'request');
6569 $pcarattextimg = VikRequest::getString('carattextimg', '', 'request', VIKREQUEST_ALLOWHTML);
6570 $pwhereup = VikRequest::getString('whereup', '', 'request');
6571 $pautoresize = VikRequest::getString('autoresize', '', 'request');
6572 $presizeto = VikRequest::getString('resizeto', '', 'request');
6573 $pidrooms = VikRequest::getVar('idrooms', array());
6574 $pordering = VikRequest::getInt('ordering', 1, 'request');
6575 if (!empty($pcaratname)) {
6576 if (intval($_FILES['caraticon']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['caraticon']['name'])!="") {
6577 jimport('joomla.filesystem.file');
6578 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
6579 if (@is_uploaded_file($_FILES['caraticon']['tmp_name'])) {
6580 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['caraticon']['name'])));
6581 if (file_exists($updpath.$safename)) {
6582 $j=1;
6583 while (file_exists($updpath.$j.$safename)) {
6584 $j++;
6585 }
6586 $pwhere=$updpath.$j.$safename;
6587 } else {
6588 $j="";
6589 $pwhere=$updpath.$safename;
6590 }
6591 if (!getimagesize($_FILES['caraticon']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
6592 @unlink($pwhere);
6593 $picon="";
6594 } else {
6595 VikBooking::uploadFile($_FILES['caraticon']['tmp_name'], $pwhere);
6596 @chmod($pwhere, 0644);
6597 $picon=$j.$safename;
6598 if ($pautoresize=="1" && !empty($presizeto)) {
6599 $eforj = new vikResizer();
6600 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
6601 if ($origmod) {
6602 @unlink($pwhere);
6603 $picon='r_'.$j.$safename;
6604 }
6605 }
6606 }
6607 } else {
6608 $picon="";
6609 }
6610 } else {
6611 $picon="";
6612 }
6613 $dbo = JFactory::getDbo();
6614 $q = "UPDATE `#__vikbooking_characteristics` SET `name`=".$dbo->quote($pcaratname).",".(strlen($picon) > 0 ? "`icon`='".$picon."'," : "")."`textimg`=".$dbo->quote($pcarattextimg).",`ordering`={$pordering} WHERE `id`=".$dbo->quote($pwhereup).";";
6615 $dbo->setQuery($q);
6616 $dbo->execute();
6617
6618 // assign/unset carat-rooms relations
6619 $rooms_with_carat = array();
6620 if (count($pidrooms)) {
6621 // assign this new carat to the requested rooms
6622 foreach ($pidrooms as $idroom) {
6623 if (empty($idroom)) {
6624 continue;
6625 }
6626 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
6627 $dbo->setQuery($q);
6628 $dbo->execute();
6629 if (!$dbo->getNumRows()) {
6630 continue;
6631 }
6632 $room_data = $dbo->loadAssoc();
6633 array_push($rooms_with_carat, $room_data['id']);
6634 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6635 if (in_array((string)$pwhereup, $current_carats)) {
6636 continue;
6637 }
6638 if (count($current_carats) === 1 && (string)$current_carats[0] == '0') {
6639 // make sure we do not concatenate a real ID to 0
6640 $current_carats = array();
6641 }
6642 array_push($current_carats, $pwhereup);
6643 $new_carats = implode(';', $current_carats) . ';';
6644 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6645 $dbo->setQuery($q);
6646 $dbo->execute();
6647 }
6648 }
6649 if (!count($rooms_with_carat)) {
6650 // get all rooms to unset this carat (if previously set)
6651 array_push($rooms_with_carat, '0');
6652 }
6653 // unset the carat from the other rooms that may have it
6654 $q = "SELECT `id`, `idcarat` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_carat) . ");";
6655 $dbo->setQuery($q);
6656 $dbo->execute();
6657 if ($dbo->getNumRows()) {
6658 $unset_rooms_carat = $dbo->loadAssocList();
6659 foreach ($unset_rooms_carat as $room_data) {
6660 $current_carats = empty($room_data['idcarat']) ? array() : explode(';', rtrim($room_data['idcarat'], ';'));
6661 if (!in_array((string)$pwhereup, $current_carats)) {
6662 // this room is not using this carat
6663 continue;
6664 }
6665 $caratkey = array_search((string)$pwhereup, $current_carats);
6666 if ($caratkey === false) {
6667 // key not found
6668 continue;
6669 }
6670 // unset this carat ID from the string
6671 unset($current_carats[$caratkey]);
6672 if (!count($current_carats)) {
6673 // a room with no carats assigned will be listed as "0;"
6674 $current_carats = array(0);
6675 }
6676 $new_carats = implode(';', $current_carats) . ';';
6677 $q = "UPDATE `#__vikbooking_rooms` SET `idcarat`=" . $dbo->quote($new_carats) . " WHERE `id`={$room_data['id']};";
6678 $dbo->setQuery($q);
6679 $dbo->execute();
6680 }
6681 }
6682 //
6683 }
6684 $mainframe = JFactory::getApplication();
6685 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6686 }
6687
6688 public function removecarat() {
6689 if (!JSession::checkToken()) {
6690 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6691 }
6692 $ids = VikRequest::getVar('cid', array(0));
6693 if (@count($ids)) {
6694 $dbo = JFactory::getDBO();
6695 foreach ($ids as $d) {
6696 $q = "SELECT `icon` FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6697 $dbo->setQuery($q);
6698 $dbo->execute();
6699 if ($dbo->getNumRows() == 1) {
6700 $rows = $dbo->loadAssocList();
6701 if (!empty($rows[0]['icon']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon'])) {
6702 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['icon']);
6703 }
6704 }
6705 $q = "DELETE FROM `#__vikbooking_characteristics` WHERE `id`=".$dbo->quote($d).";";
6706 $dbo->setQuery($q);
6707 $dbo->execute();
6708 }
6709 }
6710 $mainframe = JFactory::getApplication();
6711 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
6712 }
6713
6714 public function coupons() {
6715 VikBookingHelper::printHeader("17");
6716
6717 VikRequest::setVar('view', VikRequest::getCmd('view', 'coupons'));
6718
6719 parent::display();
6720
6721 if (VikBooking::showFooter()) {
6722 VikBookingHelper::printFooter();
6723 }
6724 }
6725
6726 public function newcoupon() {
6727 VikBookingHelper::printHeader("17");
6728
6729 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6730
6731 parent::display();
6732
6733 if (VikBooking::showFooter()) {
6734 VikBookingHelper::printFooter();
6735 }
6736 }
6737
6738 public function editcoupon() {
6739 VikBookingHelper::printHeader("17");
6740
6741 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecoupon'));
6742
6743 parent::display();
6744
6745 if (VikBooking::showFooter()) {
6746 VikBookingHelper::printFooter();
6747 }
6748 }
6749
6750 public function createcoupon()
6751 {
6752 if (!JSession::checkToken()) {
6753 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6754 }
6755 $pcode = VikRequest::getString('code', '', 'request');
6756 $pvalue = VikRequest::getString('value', '', 'request');
6757 $pfrom = VikRequest::getString('from', '', 'request');
6758 $pto = VikRequest::getString('to', '', 'request');
6759 $pidrooms = VikRequest::getVar('idrooms', array(0));
6760 $ptype = VikRequest::getString('type', '', 'request');
6761 $ptype = $ptype == "1" ? 1 : 2;
6762 $ppercentot = VikRequest::getString('percentot', '', 'request');
6763 $ppercentot = $ppercentot == "1" ? 1 : 2;
6764 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6765 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6766 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6767 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6768 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6769 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6770 $pcustomers = VikRequest::getVar('customers', array());
6771 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6772 $stridrooms = "";
6773 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6774 foreach ($pidrooms as $ch) {
6775 if (!empty($ch)) {
6776 $stridrooms .= ";".$ch.";";
6777 }
6778 }
6779 }
6780 $strdatevalid = "";
6781 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6782 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6783 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6784 if ($first < $second) {
6785 $strdatevalid .= $first."-".$second;
6786 }
6787 }
6788
6789 $dbo = JFactory::getDbo();
6790 $app = JFactory::getApplication();
6791
6792 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode).";";
6793 $dbo->setQuery($q);
6794 $dbo->execute();
6795 if ($dbo->getNumRows() > 0) {
6796 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6797 } else {
6798 $q = "INSERT INTO `#__vikbooking_coupons` (`code`,`type`,`percentot`,`value`,`datevalid`,`allvehicles`,`idrooms`,`mintotord`,`excludetaxes`,`minlos`,`maxtotord`) VALUES(".$dbo->quote($pcode).",'".$ptype."','".$ppercentot."',".$dbo->quote($pvalue).",'".$strdatevalid."','".$pallvehicles."','".$stridrooms."', ".$dbo->quote($pmintotord).", {$pexcludetaxes}, {$pminlos}, " . $dbo->quote($pmaxtotord) . ");";
6799 $dbo->setQuery($q);
6800 $dbo->execute();
6801
6802 $id_coupon = $dbo->insertid();
6803
6804 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6805
6806 // check if this coupon should be assigned to specific customers
6807 foreach ($pcustomers as $id_customer) {
6808 $customer_coupon = new stdClass;
6809 $customer_coupon->idcustomer = (int)$id_customer;
6810 $customer_coupon->idcoupon = (int)$id_coupon;
6811 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6812
6813 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6814 }
6815 }
6816 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6817 }
6818
6819 public function updatecoupon()
6820 {
6821 if (!JSession::checkToken()) {
6822 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6823 }
6824
6825 $this->do_updatecoupon($stay = false);
6826 }
6827
6828 public function updatecoupon_stay()
6829 {
6830 if (!JSession::checkToken()) {
6831 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6832 }
6833
6834 $this->do_updatecoupon($stay = true);
6835 }
6836
6837 protected function do_updatecoupon($stay = false)
6838 {
6839 if (!JSession::checkToken()) {
6840 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6841 }
6842 $pcode = VikRequest::getString('code', '', 'request');
6843 $pvalue = VikRequest::getString('value', '', 'request');
6844 $pfrom = VikRequest::getString('from', '', 'request');
6845 $pto = VikRequest::getString('to', '', 'request');
6846 $pidrooms = VikRequest::getVar('idrooms', array(0));
6847 $pwhere = VikRequest::getInt('where', 0, 'request');
6848 $ptype = VikRequest::getString('type', '', 'request');
6849 $ptype = $ptype == "1" ? 1 : 2;
6850 $ppercentot = VikRequest::getString('percentot', '', 'request');
6851 $ppercentot = $ppercentot == "1" ? 1 : 2;
6852 $pallvehicles = VikRequest::getString('allvehicles', '', 'request');
6853 $pallvehicles = $pallvehicles == "1" ? 1 : 0;
6854 $pmintotord = VikRequest::getFloat('mintotord', 0, 'request');
6855 $pmaxtotord = VikRequest::getFloat('maxtotord', 0, 'request');
6856 $pexcludetaxes = VikRequest::getInt('excludetaxes', 0, 'request');
6857 $pminlos = VikRequest::getInt('minlos', 0, 'request');
6858 $pcustomers = VikRequest::getVar('customers', array());
6859 $pautomatic = VikRequest::getInt('automatic', 0, 'request');
6860 $stridrooms = "";
6861 if (count($pidrooms) > 0 && $pallvehicles != 1) {
6862 foreach ($pidrooms as $ch) {
6863 if (!empty($ch)) {
6864 $stridrooms .= ";".$ch.";";
6865 }
6866 }
6867 }
6868 $strdatevalid = "";
6869 if (strlen($pfrom) > 0 && strlen($pto) > 0) {
6870 $first = VikBooking::getDateTimestamp($pfrom, 0, 0);
6871 $second = VikBooking::getDateTimestamp($pto, 0, 0);
6872 if ($first < $second) {
6873 $strdatevalid .= $first."-".$second;
6874 }
6875 }
6876
6877 $dbo = JFactory::getDbo();
6878 $app = JFactory::getApplication();
6879
6880 $q = "SELECT * FROM `#__vikbooking_coupons` WHERE `code`=".$dbo->quote($pcode)." AND `id`!='".$pwhere."';";
6881 $dbo->setQuery($q);
6882 $dbo->execute();
6883 if ($dbo->getNumRows() > 0) {
6884 VikError::raiseWarning('', JText::translate('VBCOUPONEXISTS'));
6885 } else {
6886 $q = "UPDATE `#__vikbooking_coupons` SET `code`=".$dbo->quote($pcode).",`type`='".$ptype."',`percentot`='".$ppercentot."',`value`=".$dbo->quote($pvalue).",`datevalid`='".$strdatevalid."',`allvehicles`='".$pallvehicles."',`idrooms`='".$stridrooms."',`mintotord`=".$dbo->quote($pmintotord).",`excludetaxes`={$pexcludetaxes},`minlos`={$pminlos},`maxtotord`= " . $dbo->quote($pmaxtotord) . " WHERE `id`=" . $pwhere . ";";
6887 $dbo->setQuery($q);
6888 $dbo->execute();
6889
6890 $app->enqueueMessage(JText::translate('VBCOUPONSAVEOK'));
6891
6892 // clean up any previously created record with customers
6893 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . $pwhere;
6894 $dbo->setQuery($q);
6895 $dbo->execute();
6896
6897 // check if this coupon should be assigned to specific customers
6898 foreach ($pcustomers as $id_customer) {
6899 $customer_coupon = new stdClass;
6900 $customer_coupon->idcustomer = (int)$id_customer;
6901 $customer_coupon->idcoupon = (int)$pwhere;
6902 $customer_coupon->automatic = $pautomatic ? 1 : 0;
6903
6904 $dbo->insertObject('#__vikbooking_customers_coupons', $customer_coupon, 'id');
6905 }
6906 }
6907
6908 if ($stay) {
6909 $app->redirect("index.php?option=com_vikbooking&task=editcoupon&cid[]=$pwhere");
6910 } else {
6911 $app->redirect("index.php?option=com_vikbooking&task=coupons");
6912 }
6913 }
6914
6915 public function removecoupons()
6916 {
6917 if (!JSession::checkToken()) {
6918 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6919 }
6920
6921 $dbo = JFactory::getDbo();
6922
6923 $ids = VikRequest::getVar('cid', array(0));
6924
6925 if (count($ids)) {
6926 foreach ($ids as $d) {
6927 // delete coupon record
6928 $q = "DELETE FROM `#__vikbooking_coupons` WHERE `id`=".$dbo->quote($d).";";
6929 $dbo->setQuery($q);
6930 $dbo->execute();
6931
6932 // clean up any previously created record with customers
6933 $q = "DELETE FROM `#__vikbooking_customers_coupons` WHERE `idcoupon`=" . (int)$d;
6934 $dbo->setQuery($q);
6935 $dbo->execute();
6936 }
6937 }
6938
6939 JFactory::getApplication()->redirect("index.php?option=com_vikbooking&task=coupons");
6940 }
6941
6942 public function removemoreimgs() {
6943 $mainframe = JFactory::getApplication();
6944 $proomid = VikRequest::getInt('roomid', '', 'request');
6945 $pimgind = VikRequest::getInt('imgind', '', 'request');
6946 if (!strlen($pimgind)) {
6947 $mainframe->redirect("index.php?option=com_vikbooking");
6948 exit;
6949 }
6950 $dbo = JFactory::getDBO();
6951 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`='".$proomid."';";
6952 $dbo->setQuery($q);
6953 $dbo->execute();
6954 $row = $dbo->loadAssoc();
6955 $actmore = $row['moreimgs'];
6956 if (!empty($actmore)) {
6957 $actsplit = explode(';;', $actmore);
6958 $captions = json_decode($row['imgcaptions'], true);
6959 $captions = !is_array($captions) ? array() : $captions;
6960 if ($pimgind < 0) {
6961 foreach ($actsplit as $img) {
6962 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$img);
6963 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$img);
6964 }
6965 // reset images and captions
6966 $actsplit = array();
6967 $captions = array();
6968 } else {
6969 if (array_key_exists($pimgind, $actsplit)) {
6970 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'big_'.$actsplit[$pimgind]);
6971 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.'thumb_'.$actsplit[$pimgind]);
6972 // unset current image
6973 unset($actsplit[$pimgind]);
6974 // unset caption if exists
6975 if (isset($captions[$pimgind])) {
6976 unset($captions[$pimgind]);
6977 $captions = array_values($captions);
6978 }
6979 }
6980 }
6981 $newstr = "";
6982 foreach ($actsplit as $oi) {
6983 if (!empty($oi)) {
6984 $newstr .= $oi.';;';
6985 }
6986 }
6987 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($newstr).", `imgcaptions`=".$dbo->quote(json_encode($captions))." WHERE `id`='".$proomid."';";
6988 $dbo->setQuery($q);
6989 $dbo->execute();
6990 }
6991 $mainframe->redirect("index.php?option=com_vikbooking&task=editroom&cid[]=".$proomid);
6992 }
6993
6994 public function sortfield() {
6995 if (!JSession::checkToken('get')) {
6996 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
6997 }
6998 $mainframe = JFactory::getApplication();
6999 $sortid = VikRequest::getVar('cid', array(0));
7000 $pmode = VikRequest::getString('mode', '', 'request');
7001 $dbo = JFactory::getDBO();
7002 if (!empty($pmode)) {
7003 $q = "SELECT `id`,`ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` ASC;";
7004 $dbo->setQuery($q);
7005 $dbo->execute();
7006 $totr=$dbo->getNumRows();
7007 if ($totr > 1) {
7008 $data = $dbo->loadAssocList();
7009 if ($pmode == "up") {
7010 foreach ($data as $v) {
7011 if ($v['id'] == $sortid[0]) {
7012 $y = $v['ordering'];
7013 }
7014 }
7015 if ($y && $y > 1) {
7016 $vik = $y - 1;
7017 $found = false;
7018 foreach ($data as $v) {
7019 if (intval($v['ordering']) == intval($vik)) {
7020 $found=true;
7021 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7022 $dbo->setQuery($q);
7023 $dbo->execute();
7024 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7025 $dbo->setQuery($q);
7026 $dbo->execute();
7027 break;
7028 }
7029 }
7030 if (!$found) {
7031 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7032 $dbo->setQuery($q);
7033 $dbo->execute();
7034 }
7035 }
7036 } elseif ($pmode == "down") {
7037 foreach ($data as $v) {
7038 if ($v['id'] == $sortid[0]) {
7039 $y = $v['ordering'];
7040 }
7041 }
7042 if ($y) {
7043 $vik = $y + 1;
7044 $found = false;
7045 foreach ($data as $v) {
7046 if (intval($v['ordering']) == intval($vik)) {
7047 $found=true;
7048 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$y."' WHERE `id`='".$v['id']."' LIMIT 1;";
7049 $dbo->setQuery($q);
7050 $dbo->execute();
7051 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7052 $dbo->setQuery($q);
7053 $dbo->execute();
7054 break;
7055 }
7056 }
7057 if (!$found) {
7058 $q = "UPDATE `#__vikbooking_custfields` SET `ordering`='".$vik."' WHERE `id`='".$sortid[0]."' LIMIT 1;";
7059 $dbo->setQuery($q);
7060 $dbo->execute();
7061 }
7062 }
7063 }
7064 }
7065 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7066 } else {
7067 $mainframe->redirect("index.php?option=com_vikbooking");
7068 }
7069 }
7070
7071 public function customf() {
7072 VikBookingHelper::printHeader("16");
7073
7074 VikRequest::setVar('view', VikRequest::getCmd('view', 'customf'));
7075
7076 parent::display();
7077
7078 if (VikBooking::showFooter()) {
7079 VikBookingHelper::printFooter();
7080 }
7081 }
7082
7083 public function newcustomf() {
7084 VikBookingHelper::printHeader("16");
7085
7086 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7087
7088 parent::display();
7089
7090 if (VikBooking::showFooter()) {
7091 VikBookingHelper::printFooter();
7092 }
7093 }
7094
7095 public function editcustomf() {
7096 VikBookingHelper::printHeader("16");
7097
7098 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecustomf'));
7099
7100 parent::display();
7101
7102 if (VikBooking::showFooter()) {
7103 VikBookingHelper::printFooter();
7104 }
7105 }
7106
7107 public function createcustomf() {
7108 if (!JSession::checkToken()) {
7109 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7110 }
7111 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7112 $ptype = VikRequest::getString('type', '', 'request');
7113 $pchoose = VikRequest::getVar('choose', array(0));
7114 $prequired = VikRequest::getString('required', '', 'request');
7115 $prequired = $prequired == "1" ? 1 : 0;
7116 $pflag = VikRequest::getString('flag', '', 'request');
7117 $pisemail = $pflag == 'isemail' ? 1 : 0;
7118 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7119 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7120 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7121 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7122 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7123 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7124 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7125 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7126 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7127 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7128 $fieldflag = '';
7129 if ($pisaddress == 1) {
7130 $fieldflag = 'address';
7131 } elseif ($piscity == 1) {
7132 $fieldflag = 'city';
7133 } elseif ($piszip == 1) {
7134 $fieldflag = 'zip';
7135 } elseif ($piscompany == 1) {
7136 $fieldflag = 'company';
7137 } elseif ($pisvat == 1) {
7138 $fieldflag = 'vat';
7139 } elseif ($pisfisccode == 1) {
7140 $fieldflag = 'fisccode';
7141 } elseif ($pispec == 1) {
7142 $fieldflag = 'pec';
7143 } elseif ($pisrecipcode == 1) {
7144 $fieldflag = 'recipcode';
7145 }
7146 $ppoplink = VikRequest::getString('poplink', '', 'request');
7147 $choosestr = "";
7148 if (is_array($pchoose)) {
7149 foreach ($pchoose as $ch) {
7150 if (!empty($ch)) {
7151 $choosestr .= $ch.";;__;;";
7152 }
7153 }
7154 }
7155 $defvalue = VikRequest::getString('defvalue', '', 'request');
7156
7157 $dbo = JFactory::getDbo();
7158
7159 $q = "SELECT `ordering` FROM `#__vikbooking_custfields` ORDER BY `#__vikbooking_custfields`.`ordering` DESC LIMIT 1;";
7160 $dbo->setQuery($q);
7161 $dbo->execute();
7162 if ($dbo->getNumRows() == 1) {
7163 $getlast = $dbo->loadResult();
7164 $newsortnum = $getlast + 1;
7165 } else {
7166 $newsortnum = 1;
7167 }
7168 $q = "INSERT INTO `#__vikbooking_custfields` (`name`,`type`,`choose`,`required`,`ordering`,`isemail`,`poplink`,`isnominative`,`isphone`,`flag`,`defvalue`) VALUES(".$dbo->quote($pname).", ".$dbo->quote($ptype).", ".$dbo->quote($choosestr).", ".$dbo->quote($prequired).", ".$dbo->quote($newsortnum).", ".$dbo->quote($pisemail).", ".$dbo->quote($ppoplink).", ".$pisnominative.", ".$pisphone.", ".$dbo->quote($fieldflag).", ".$dbo->quote($defvalue).");";
7169 $dbo->setQuery($q);
7170 $dbo->execute();
7171 $mainframe = JFactory::getApplication();
7172 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7173 }
7174
7175 public function updatecustomf() {
7176 if (!JSession::checkToken()) {
7177 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7178 }
7179 $pname = VikRequest::getString('name', '', 'request', VIKREQUEST_ALLOWHTML);
7180 $ptype = VikRequest::getString('type', '', 'request');
7181 $pchoose = VikRequest::getVar('choose', array(0));
7182 $prequired = VikRequest::getString('required', '', 'request');
7183 $prequired = $prequired == "1" ? 1 : 0;
7184 $pflag = VikRequest::getString('flag', '', 'request');
7185 $pisemail = $pflag == 'isemail' ? 1 : 0;
7186 $pisnominative = $pflag == 'isnominative' && $ptype == 'text' ? 1 : 0;
7187 $pisphone = $pflag == 'isphone' && $ptype == 'text' ? 1 : 0;
7188 $pisaddress = $pflag == 'isaddress' && $ptype == 'text' ? 1 : 0;
7189 $piscity = $pflag == 'iscity' && $ptype == 'text' ? 1 : 0;
7190 $piszip = $pflag == 'iszip' && $ptype == 'text' ? 1 : 0;
7191 $piscompany = $pflag == 'iscompany' && $ptype == 'text' ? 1 : 0;
7192 $pisvat = $pflag == 'isvat' && $ptype == 'text' ? 1 : 0;
7193 $pisfisccode = $pflag == 'isfisccode' && $ptype == 'text' ? 1 : 0;
7194 $pispec = $pflag == 'ispec' && $ptype == 'text' ? 1 : 0;
7195 $pisrecipcode = $pflag == 'isrecipcode' && $ptype == 'text' ? 1 : 0;
7196 $fieldflag = '';
7197 if ($pisaddress == 1) {
7198 $fieldflag = 'address';
7199 } elseif ($piscity == 1) {
7200 $fieldflag = 'city';
7201 } elseif ($piszip == 1) {
7202 $fieldflag = 'zip';
7203 } elseif ($piscompany == 1) {
7204 $fieldflag = 'company';
7205 } elseif ($pisvat == 1) {
7206 $fieldflag = 'vat';
7207 } elseif ($pisfisccode == 1) {
7208 $fieldflag = 'fisccode';
7209 } elseif ($pispec == 1) {
7210 $fieldflag = 'pec';
7211 } elseif ($pisrecipcode == 1) {
7212 $fieldflag = 'recipcode';
7213 }
7214 $ppoplink = VikRequest::getString('poplink', '', 'request');
7215 $pwhere = VikRequest::getInt('where', '', 'request');
7216 $choosestr = "";
7217 if (is_array($pchoose)) {
7218 foreach ($pchoose as $ch) {
7219 if (!empty($ch)) {
7220 $choosestr .= $ch.";;__;;";
7221 }
7222 }
7223 }
7224 $defvalue = VikRequest::getString('defvalue', '', 'request');
7225
7226 $dbo = JFactory::getDbo();
7227
7228 $q = "UPDATE `#__vikbooking_custfields` SET `name`=".$dbo->quote($pname).",`type`=".$dbo->quote($ptype).",`choose`=".$dbo->quote($choosestr).",`required`=".$dbo->quote($prequired).",`isemail`=".$dbo->quote($pisemail).",`poplink`=".$dbo->quote($ppoplink).",`isnominative`=".$pisnominative.",`isphone`=".$pisphone.",`flag`=".$dbo->quote($fieldflag).",`defvalue`=".$dbo->quote($defvalue)." WHERE `id`=".$dbo->quote($pwhere).";";
7229 $dbo->setQuery($q);
7230 $dbo->execute();
7231 $mainframe = JFactory::getApplication();
7232 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7233 }
7234
7235 public function removecustomf() {
7236 if (!JSession::checkToken()) {
7237 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7238 }
7239 $ids = VikRequest::getVar('cid', array(0));
7240 if (@count($ids)) {
7241 $dbo = JFactory::getDBO();
7242 foreach ($ids as $d) {
7243 $q = "DELETE FROM `#__vikbooking_custfields` WHERE `id`=".$dbo->quote($d).";";
7244 $dbo->setQuery($q);
7245 $dbo->execute();
7246 }
7247 }
7248 $mainframe = JFactory::getApplication();
7249 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
7250 }
7251
7252 public function overv() {
7253 VikBookingHelper::printHeader("15");
7254
7255 VikRequest::setVar('view', VikRequest::getCmd('view', 'overv'));
7256
7257 parent::display();
7258
7259 if (VikBooking::showFooter()) {
7260 VikBookingHelper::printFooter();
7261 }
7262 }
7263
7264 public function translations() {
7265 VikBookingHelper::printHeader("21");
7266
7267 VikRequest::setVar('view', VikRequest::getCmd('view', 'translations'));
7268
7269 parent::display();
7270
7271 if (VikBooking::showFooter()) {
7272 VikBookingHelper::printFooter();
7273 }
7274 }
7275
7276 public function savetranslation() {
7277 if (!JSession::checkToken()) {
7278 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7279 }
7280 $this->do_savetranslation();
7281 }
7282
7283 public function savetranslationstay() {
7284 if (!JSession::checkToken()) {
7285 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7286 }
7287 $this->do_savetranslation(true);
7288 }
7289
7290 private function do_savetranslation($stay = false) {
7291 $dbo = JFactory::getDBO();
7292 $mainframe = JFactory::getApplication();
7293 $vbo_tn = VikBooking::getTranslator();
7294 $table = VikRequest::getString('vbo_table', '', 'request');
7295 $cur_langtab = VikRequest::getString('vbo_lang', '', 'request');
7296 $langs = $vbo_tn->getLanguagesList();
7297 $xml_tables = $vbo_tn->getTranslationTables();
7298 if (!empty($table) && array_key_exists($table, $xml_tables)) {
7299 $tn = VikRequest::getVar('tn', array(), 'request', 'array', VIKREQUEST_ALLOWRAW);
7300 $tn_saved = 0;
7301 $table_cols = $vbo_tn->getTableColumns($table);
7302 foreach ($langs as $ltag => $lang) {
7303 if ($ltag == $vbo_tn->default_lang) {
7304 continue;
7305 }
7306 if (array_key_exists($ltag, $tn) && count($tn[$ltag]) > 0) {
7307 foreach ($tn[$ltag] as $reference_id => $translation) {
7308 $lang_translation = array();
7309 foreach ($table_cols as $field => $fdetails) {
7310 if (!array_key_exists($field, $translation)) {
7311 continue;
7312 }
7313 $ftype = $fdetails['type'];
7314 if ($ftype == 'skip') {
7315 continue;
7316 }
7317
7318 if (is_array($translation[$field])) {
7319 foreach ($translation[$field] as $tn_field_k => $tn_field_v) {
7320 if (!is_string($tn_field_v)) {
7321 continue;
7322 }
7323 // replace any possible placeholder for special tags
7324 $translation[$field][$tn_field_k] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7325 return $match[2];
7326 }, $translation[$field][$tn_field_k]);
7327 }
7328 } elseif (!empty($translation[$field])) {
7329 // replace any possible placeholder for special tags
7330 $translation[$field] = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
7331 return $match[2];
7332 }, $translation[$field]);
7333 }
7334
7335 if ($ftype == 'json' && !is_scalar($translation[$field])) {
7336 $translation[$field] = json_encode($translation[$field]);
7337 }
7338 $lang_translation[$field] = $translation[$field];
7339 }
7340 if (count($lang_translation) > 0) {
7341 $q = "SELECT `id` FROM `#__vikbooking_translations` WHERE `table`=".$dbo->quote($table)." AND `lang`=".$dbo->quote($ltag)." AND `reference_id`=".$dbo->quote((int)$reference_id).";";
7342 $dbo->setQuery($q);
7343 $dbo->execute();
7344 if ($dbo->getNumRows() > 0) {
7345 $last_id = $dbo->loadResult();
7346 $q = "UPDATE `#__vikbooking_translations` SET `content`=".$dbo->quote(json_encode($lang_translation))." WHERE `id`=".(int)$last_id.";";
7347 } else {
7348 $q = "INSERT INTO `#__vikbooking_translations` (`table`,`lang`,`reference_id`,`content`) VALUES (".$dbo->quote($table).", ".$dbo->quote($ltag).", ".$dbo->quote((int)$reference_id).", ".$dbo->quote(json_encode($lang_translation)).");";
7349 }
7350 $dbo->setQuery($q);
7351 $dbo->execute();
7352 $tn_saved++;
7353 }
7354 }
7355 }
7356 }
7357 if ($tn_saved > 0) {
7358 $mainframe->enqueueMessage(JText::translate('VBOTRANSLSAVEDOK'));
7359 }
7360 } else {
7361 VikError::raiseWarning('', JText::translate('VBTRANSLATIONERRINVTABLE'));
7362 }
7363 $mainframe->redirect("index.php?option=com_vikbooking".($stay ? '&task=translations&vbo_table='.$vbo_tn->replacePrefix($table).'&vbo_lang='.$cur_langtab : '').'&limitstart='.$vbo_tn->lim0.'&limit='.$vbo_tn->lim);
7364 }
7365
7366 public function choosebusy() {
7367 VikBookingHelper::printHeader("8");
7368
7369 VikRequest::setVar('view', VikRequest::getCmd('view', 'choosebusy'));
7370
7371 parent::display();
7372
7373 if (VikBooking::showFooter()) {
7374 VikBookingHelper::printFooter();
7375 }
7376 }
7377
7378 public function orders() {
7379 VikBookingHelper::printHeader("8");
7380
7381 VikRequest::setVar('view', VikRequest::getCmd('view', 'orders'));
7382
7383 parent::display();
7384
7385 if (VikBooking::showFooter()) {
7386 VikBookingHelper::printFooter();
7387 }
7388 }
7389
7390 public function vieworders() {
7391 //alias method of orders() for backward compatibility with VCM
7392 $this->orders();
7393 }
7394
7395 public function editorder() {
7396 VikBookingHelper::printHeader("8");
7397
7398 VikRequest::setVar('view', VikRequest::getCmd('view', 'editorder'));
7399
7400 parent::display();
7401
7402 if (VikBooking::showFooter()) {
7403 VikBookingHelper::printFooter();
7404 }
7405 }
7406
7407 public function removeorders()
7408 {
7409 $dbo = JFactory::getDbo();
7410 $app = JFactory::getApplication();
7411
7412 $ids = VikRequest::getVar('cid', array(0));
7413 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
7414
7415 $user = JFactory::getUser();
7416 $config = VBOFactory::getConfig();
7417
7418 $prev_conf_ids = [];
7419 $purged = false;
7420
7421 $tot_cancs = 0;
7422
7423 if (is_array($ids) && count($ids)) {
7424 foreach ($ids as $d) {
7425 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $dbo->quote($d);
7426 $dbo->setQuery($q, 0, 1);
7427 $row = $dbo->loadAssoc();
7428
7429 // check for any cancellation constraints
7430 $canc_denied = false;
7431 if ($row && class_exists('VCMFeesCancellation')) {
7432 // let VCM detect if there are any constraints for the cancellation
7433 $canc_denied = VCMFeesCancellation::getInstance($row, $anew = true)->isBookingConstrained();
7434 if ($canc_denied) {
7435 // set error message
7436 $canc_deny_error = VCMFeesCancellation::getInstance()->getError();
7437 if ($canc_deny_error) {
7438 $app->enqueueMessage($canc_deny_error, 'error');
7439 }
7440 }
7441 }
7442
7443 if ($row && !$canc_denied) {
7444 // increase counter
7445 $tot_cancs++;
7446
7447 // set status to cancelled
7448 if ($row['status'] != 'cancelled') {
7449 $q = "UPDATE `#__vikbooking_orders` SET `status`='cancelled' WHERE `id`=".(int)$row['id'].";";
7450 $dbo->setQuery($q);
7451 $dbo->execute();
7452 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";";
7453 $dbo->setQuery($q);
7454 $dbo->execute();
7455 if ($row['status'] == 'confirmed') {
7456 $prev_conf_ids[] = $row['id'];
7457 }
7458 // Booking History
7459 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('CB', "({$user->name})");
7460 }
7461
7462 // free records up
7463 $q = "SELECT * FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7464 $dbo->setQuery($q);
7465 $ordbusy = $dbo->loadAssocList();
7466 if ($ordbusy) {
7467 foreach ($ordbusy as $ob) {
7468 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id`='".$ob['idbusy']."';";
7469 $dbo->setQuery($q);
7470 $dbo->execute();
7471 }
7472 }
7473
7474 $q = "DELETE FROM `#__vikbooking_ordersbusy` WHERE `idorder`=".(int)$row['id'].";";
7475 $dbo->setQuery($q);
7476 $dbo->execute();
7477
7478 // check for purge removal
7479 if ($row['status'] == 'cancelled') {
7480 $q = "DELETE FROM `#__vikbooking_customers_orders` WHERE `idorder`=" . intval($row['id']) . ";";
7481 $dbo->setQuery($q);
7482 $dbo->execute();
7483 $q = "DELETE FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".(int)$row['id'].";";
7484 $dbo->setQuery($q);
7485 $dbo->execute();
7486 $q = "DELETE FROM `#__vikbooking_orderhistory` WHERE `idorder`=".(int)$row['id'].";";
7487 $dbo->setQuery($q);
7488 $dbo->execute();
7489 $q = "DELETE FROM `#__vikbooking_orders` WHERE `id`=".(int)$row['id'].";";
7490 $dbo->setQuery($q);
7491 $dbo->execute();
7492 // in case of split stay booking, remove the transient
7493 if ($row['split_stay']) {
7494 $config->remove('split_stay_' . $row['id']);
7495 }
7496 // turn flag on
7497 $purged = true;
7498 }
7499 }
7500 }
7501
7502 if ($tot_cancs) {
7503 // enqueue system message
7504 $app->enqueueMessage(JText::translate('VBMESSDELBUSY'));
7505 }
7506 }
7507
7508 if ($prev_conf_ids) {
7509 $prev_conf_ids_str = '';
7510 foreach ($prev_conf_ids as $prev_id) {
7511 $prev_conf_ids_str .= '&cid[]='.$prev_id;
7512 }
7513 //Invoke Channel Manager
7514 $vcm_autosync = VikBooking::vcmAutoUpdate();
7515 if ($vcm_autosync > 0) {
7516 $vcm_obj = VikBooking::getVcmInvoker();
7517 $vcm_obj->setOids($prev_conf_ids)->setSyncType('cancel');
7518 $sync_result = $vcm_obj->doSync();
7519 if ($sync_result === false) {
7520 $vcm_err = $vcm_obj->getError();
7521 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a> '.(strlen($vcm_err) > 0 ? '('.$vcm_err.')' : ''));
7522 }
7523 } elseif (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
7524 $vcm_sync_url = 'index.php?option=com_vikbooking&task=invoke_vcm&stype=cancel'.$prev_conf_ids_str.'&returl='.urlencode('index.php?option=com_vikbooking&task=orders');
7525 VikError::raiseNotice('', JText::translate('VBCHANNELMANAGERINVOKEASK').' <button type="button" class="btn btn-primary" onclick="document.location.href=\''.$vcm_sync_url.'\';">'.JText::translate('VBCHANNELMANAGERSENDRQ').'</button>');
7526 }
7527 //
7528 }
7529
7530 if (!empty($pgoto)) {
7531 if (is_numeric($pgoto) && is_array($ids) && count($ids) === 1) {
7532 if ($purged) {
7533 // go back to the bookings list page
7534 $app->redirect("index.php?option=com_vikbooking&task=orders");
7535 } else {
7536 // go back to the booking details page
7537 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . (int)$ids[0]);
7538 }
7539 exit;
7540 }
7541 // we expect the goto URL to be base64 encoded
7542 $app->redirect(base64_decode($pgoto));
7543 exit;
7544 }
7545
7546 // go back to the bookings list page
7547 $app->redirect("index.php?option=com_vikbooking&task=orders");
7548 }
7549
7550 public function config() {
7551 VikBookingHelper::printHeader("11");
7552
7553 VikRequest::setVar('view', VikRequest::getCmd('view', 'config'));
7554
7555 parent::display();
7556
7557 if (VikBooking::showFooter()) {
7558 VikBookingHelper::printFooter();
7559 }
7560 }
7561
7562 public function saveconfig()
7563 {
7564 if (!JSession::checkToken()) {
7565 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
7566 }
7567
7568 $dbo = JFactory::getDbo();
7569 $app = JFactory::getApplication();
7570
7571 $config = VBOFactory::getConfig();
7572
7573 $pallowbooking = VikRequest::getString('allowbooking', '', 'request');
7574 $pdisabledbookingmsg = VikRequest::getString('disabledbookingmsg', '', 'request', VIKREQUEST_ALLOWHTML);
7575 $ptimeopenstorefh = VikRequest::getString('timeopenstorefh', '', 'request');
7576 $ptimeopenstorefm = VikRequest::getString('timeopenstorefm', '', 'request');
7577 $ptimeopenstoreth = VikRequest::getString('timeopenstoreth', '', 'request');
7578 $ptimeopenstoretm = VikRequest::getString('timeopenstoretm', '', 'request');
7579 $phoursmorebookingback = VikRequest::getString('hoursmorebookingback', '', 'request');
7580 $pdateformat = VikRequest::getString('dateformat', '', 'request');
7581 $pdatesep = VikRequest::getString('datesep', '', 'request');
7582 $pdatesep = empty($pdatesep) ? "/" : $pdatesep;
7583 $presmodcanc = VikRequest::getInt('resmodcanc', 1, 'request');
7584 $presmodcancmin = VikRequest::getInt('resmodcancmin', 1, 'request');
7585 $pshowcategories = VikRequest::getString('showcategories', '', 'request');
7586 $pshowchildren = VikRequest::getString('showchildren', '', 'request');
7587 $psearchsuggestions = VikRequest::getInt('searchsuggestions', '', 'request');
7588 $ptokenform = VikRequest::getString('tokenform', '', 'request');
7589 $padminemail = VikRequest::getString('adminemail', '', 'request');
7590 $psenderemail = VikRequest::getString('senderemail', '', 'request');
7591 $pminuteslock = VikRequest::getString('minuteslock', '', 'request');
7592 $pminautoremove = VikRequest::getInt('minautoremove', '', 'request');
7593 $pfooterordmail = VikRequest::getString('footerordmail', '', 'request', VIKREQUEST_ALLOWHTML);
7594 $ptermsconds = VikRequest::getString('termsconds', '', 'request', VIKREQUEST_ALLOWHTML);
7595 $prequirelogin = VikRequest::getString('requirelogin', '', 'request');
7596 $pautoroomunit = VikRequest::getInt('autoroomunit', '', 'request');
7597 $ptodaybookings = VikRequest::getInt('todaybookings', '', 'request');
7598 $ptodaybookings = $ptodaybookings === 1 ? 1 : 0;
7599 $ploadbootstrap = VikRequest::getInt('loadbootstrap', '', 'request');
7600 $ploadbootstrap = $ploadbootstrap === 1 ? 1 : 0;
7601 $pusefa = VikRequest::getInt('usefa', '', 'request');
7602 $pusefa = $pusefa > 0 ? 1 : 0;
7603 $ploadjquery = VikRequest::getString('loadjquery', '', 'request');
7604 $ploadjquery = $ploadjquery == "yes" ? "1" : "0";
7605 $pcalendar = VikRequest::getString('calendar', '', 'request');
7606 $pcalendar = $pcalendar == "joomla" ? "joomla" : "jqueryui";
7607 $penablecoupons = VikRequest::getString('enablecoupons', '', 'request');
7608 $penablecoupons = $penablecoupons == "1" ? 1 : 0;
7609 $penablepin = VikRequest::getString('enablepin', '', 'request');
7610 $penablepin = $penablepin == "1" ? 1 : 0;
7611 $pmindaysadvance = VikRequest::getInt('mindaysadvance', '', 'request');
7612 $pmindaysadvance = $pmindaysadvance < 0 ? 0 : $pmindaysadvance;
7613 $pautodefcalnights = VikRequest::getInt('autodefcalnights', '', 'request');
7614 $pautodefcalnights = $pautodefcalnights >= 1 ? $pautodefcalnights : '1';
7615 $pnumrooms = VikRequest::getInt('numrooms', '', 'request');
7616 $pnumrooms = $pnumrooms > 0 ? $pnumrooms : '5';
7617 $pnumadultsfrom = VikRequest::getString('numadultsfrom', '', 'request');
7618 $pnumadultsfrom = intval($pnumadultsfrom) >= 0 ? $pnumadultsfrom : '1';
7619 $pnumadultsto = VikRequest::getString('numadultsto', '', 'request');
7620 $pnumadultsto = intval($pnumadultsto) > 0 ? $pnumadultsto : '10';
7621 if (intval($pnumadultsfrom) > intval($pnumadultsto)) {
7622 $pnumadultsfrom = '1';
7623 $pnumadultsto = '10';
7624 }
7625 $pnumchildrenfrom = VikRequest::getString('numchildrenfrom', '', 'request');
7626 $pnumchildrenfrom = intval($pnumchildrenfrom) >= 0 ? $pnumchildrenfrom : '1';
7627 $pnumchildrento = VikRequest::getString('numchildrento', '', 'request');
7628 $pnumchildrento = intval($pnumchildrento) > 0 ? $pnumchildrento : '4';
7629 if (intval($pnumchildrenfrom) > intval($pnumchildrento)) {
7630 $pnumadultsfrom = '1';
7631 $pnumadultsto = '4';
7632 }
7633 $confnumadults = $pnumadultsfrom.'-'.$pnumadultsto;
7634 $confnumchildren = $pnumchildrenfrom.'-'.$pnumchildrento;
7635 $pmaxdate = VikRequest::getString('maxdate', '', 'request');
7636 $pmaxdate = intval($pmaxdate) < 1 ? 2 : $pmaxdate;
7637 $pmaxdateinterval = VikRequest::getString('maxdateinterval', '', 'request');
7638 $pmaxdateinterval = !in_array($pmaxdateinterval, array('d', 'w', 'm', 'y')) ? 'y' : $pmaxdateinterval;
7639 $maxdate_str = '+'.$pmaxdate.$pmaxdateinterval;
7640 $pcronkey = VikRequest::getString('cronkey', '', 'request');
7641 $pcdsfrom = VikRequest::getVar('cdsfrom', array());
7642 $pcdsto = VikRequest::getVar('cdsto', array());
7643 $closing_dates = array();
7644 if (count($pcdsfrom)) {
7645 foreach ($pcdsfrom as $kcd => $vcdfrom) {
7646 if (!empty($vcdfrom) && array_key_exists($kcd, $pcdsto) && !empty($pcdsto[$kcd])) {
7647 $tscdfrom = VikBooking::getDateTimestamp($vcdfrom, '0', '0');
7648 $tscdto = VikBooking::getDateTimestamp($pcdsto[$kcd], '0', '0');
7649 if (!empty($tscdfrom) && !empty($tscdto) && $tscdto >= $tscdfrom) {
7650 $cdval = array('from' => $tscdfrom, 'to' => $tscdto);
7651 if (!in_array($cdval, $closing_dates)) {
7652 $closing_dates[] = $cdval;
7653 }
7654 }
7655 }
7656 }
7657 }
7658 $psmartsearch = VikRequest::getString('smartsearch', '', 'request');
7659 $psmartsearch = $psmartsearch == "dynamic" ? "dynamic" : "automatic";
7660 $pvbosef = VikRequest::getInt('vbosef', '', 'request');
7661 $vbosef = file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7662 if ($pvbosef === 1) {
7663 if (!$vbosef) {
7664 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php');
7665 }
7666 } else {
7667 if ($vbosef) {
7668 rename(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'router.php', VBO_SITE_PATH.DIRECTORY_SEPARATOR.'_router.php');
7669 }
7670 }
7671 $pmultilang = VikRequest::getString('multilang', '', 'request');
7672 $pmultilang = $pmultilang == "1" ? 1 : 0;
7673 $pvcmautoupd = VikRequest::getInt('vcmautoupd', '', 'request');
7674 $pvcmautoupd = $pvcmautoupd > 0 ? 1 : 0;
7675 /**
7676 * Chat params and configuration settings
7677 *
7678 * @since 1.12
7679 */
7680 $pchatenabled = VikRequest::getInt('chatenabled', 0, 'request');
7681 if (is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php')) {
7682 $config->set('chatenabled', $pchatenabled);
7683
7684 // chat params
7685 $pchat_res_status = explode(';', VikRequest::getString('chat_res_status', '', 'request'));
7686 $chat_res_status = array();
7687 foreach ($pchat_res_status as $chatrs) {
7688 if (!empty($chatrs)) {
7689 array_push($chat_res_status, $chatrs);
7690 }
7691 }
7692 $chatparams = new stdClass;
7693 $chatparams->res_status = $chat_res_status;
7694 $chatparams->av_type = VikRequest::getString('chat_av_type', '', 'request');
7695 $chatparams->av_days = VikRequest::getInt('chat_av_days', 0, 'request');
7696
7697 $config->set('chatparams', $chatparams);
7698 }
7699
7700 /**
7701 * Pre check-in configuration settings
7702 *
7703 * @since 1.12
7704 */
7705 $pprecheckinenabled = VikRequest::getInt('precheckinenabled', 0, 'request');
7706 $pprecheckinenabled = $pprecheckinenabled > 0 ? 1 : 0;
7707
7708 $config->set('precheckinenabled', $pprecheckinenabled);
7709 $config->set('precheckinminoffset', VikRequest::getInt('precheckinminoffset', 0, 'request'));
7710
7711 $pupsellingenabled = VikRequest::getInt('upsellingenabled', 0, 'request');
7712 $pupsellingenabled = $pupsellingenabled > 0 ? 1 : 0;
7713 $config->set('upselling', $pupsellingenabled);
7714
7715 $porphanscal = VikRequest::getString('orphanscal', 'next', 'request');
7716 $porphanscal = $porphanscal == 'prevnext' ? 'prevnext' : 'next';
7717 $config->set('orphanscalculation', $porphanscal);
7718
7719 $psrcrtpl = VikRequest::getString('srcrtpl', 'compact', 'request');
7720 $config->set('searchrestmpl', $psrcrtpl);
7721
7722 /**
7723 * Guest Reviews settings
7724 *
7725 * @since 1.13
7726 */
7727 $pgrenabled = VikRequest::getInt('grenabled', 0, 'request');
7728 $pgrminchars = VikRequest::getInt('grminchars', 0, 'request');
7729 $pgrappr = VikRequest::getString('grappr', 'auto', 'request');
7730 $pgrappr = $pgrappr == 'auto' ? 'auto' : 'manual';
7731 $pgrtype = VikRequest::getString('grtype', 'service', 'request');
7732 $pgrtype = $pgrtype == 'service' ? 'service' : 'global';
7733 $pgrsrv = VikRequest::getVar('grsrv', array(), 'request', 'array');
7734 $config->set('grenabled', $pgrenabled);
7735 $config->set('grminchars', $pgrminchars);
7736 $config->set('grappr', $pgrappr);
7737 $config->set('grtype', $pgrtype);
7738 try {
7739 // always truncate service names (this query may require special permissions)
7740 $q = "TRUNCATE TABLE `#__vikbooking_greview_service`;";
7741 $dbo->setQuery($q);
7742 $dbo->execute();
7743 } catch (Exception $e) {
7744 // do nothing
7745 }
7746 foreach ($pgrsrv as $srvname) {
7747 $q = "INSERT INTO `#__vikbooking_greview_service` (`service_name`) VALUES (" . $dbo->quote($srvname) . ");";
7748 $dbo->setQuery($q);
7749 $dbo->execute();
7750 }
7751
7752 /**
7753 * Preferred countries ordering, or custom countries.
7754 *
7755 * @since 1.14 (J) - 1.3.11 (WP)
7756 * @since 1.14.1 (J) - 1.4.1 (WP) we also support "cust_pref_countries"
7757 */
7758 $pref_countries = VikRequest::getVar('pref_countries', array());
7759 $cust_pref_countries = VikRequest::getString('cust_pref_countries', '', 'request');
7760 $pref_countries = !is_array($pref_countries) || empty($pref_countries[0]) ? VikBooking::preferredCountriesOrdering() : $pref_countries;
7761 if (!empty($cust_pref_countries)) {
7762 $all_custom_prefcountries = array();
7763 $cust_pref_countries = explode(',', $cust_pref_countries);
7764 foreach ($cust_pref_countries as $cust_pref_country) {
7765 $cust_pref_country = trim(strtolower($cust_pref_country));
7766 if (empty($cust_pref_country) || strlen($cust_pref_country) != 2) {
7767 continue;
7768 }
7769 array_push($all_custom_prefcountries, $cust_pref_country);
7770 }
7771 if (count($all_custom_prefcountries)) {
7772 $pref_countries = $all_custom_prefcountries;
7773 }
7774 }
7775 $config->set('preferred_countries', $pref_countries);
7776 //
7777
7778 $gmapskey = VikRequest::getString('gmapskey', '', 'request');
7779 $config->set('gmapskey', $gmapskey);
7780
7781 $pref_textcolor = VikRequest::getString('pref_textcolor', '', 'request');
7782 $pref_bgcolor = VikRequest::getString('pref_bgcolor', '', 'request');
7783 $pref_fontcolor = VikRequest::getString('pref_fontcolor', '', 'request');
7784 $pref_bgcolorhov = VikRequest::getString('pref_bgcolorhov', '', 'request');
7785 $pref_fontcolorhov = VikRequest::getString('pref_fontcolorhov', '', 'request');
7786 $pref_colors = array(
7787 'textcolor' => $pref_textcolor,
7788 'bgcolor' => $pref_bgcolor,
7789 'fontcolor' => $pref_fontcolor,
7790 'bgcolorhov' => $pref_bgcolorhov,
7791 'fontcolorhov' => $pref_fontcolorhov,
7792 );
7793 $config->set('pref_colors', $pref_colors);
7794
7795 $interactive_map = VikRequest::getInt('interactive_map', 0, 'request');
7796 $config->set('interactive_map', $interactive_map);
7797
7798 $noemptydecimals = VikRequest::getInt('noemptydecimals', 0, 'request');
7799 $config->set('noemptydecimals', $noemptydecimals);
7800
7801 /**
7802 * Appearance preferences (light, auto, dark mode).
7803 *
7804 * @since 1.15.0 (J) - 1.5.0 (WP)
7805 */
7806 $appearance_pref = VikRequest::getString('appearance_pref', '');
7807 $config->set('appearance_pref', $appearance_pref);
7808
7809 $res_backend_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
7810 $picon = "";
7811 if (intval($_FILES['sitelogo']['error']) == 0 && trim($_FILES['sitelogo']['name'])!="") {
7812 jimport('joomla.filesystem.file');
7813 if (@is_uploaded_file($_FILES['sitelogo']['tmp_name'])) {
7814 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['sitelogo']['name'])));
7815 if (file_exists($res_backend_path.$safename)) {
7816 $j = 1;
7817 while (file_exists($res_backend_path.$j.$safename)) {
7818 $j++;
7819 }
7820 $pwhere = $res_backend_path.$j.$safename;
7821 } else {
7822 $j = "";
7823 $pwhere = $res_backend_path.$safename;
7824 }
7825 if (!getimagesize($_FILES['sitelogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7826 @unlink($pwhere);
7827 $picon = "";
7828 } else {
7829 VikBooking::uploadFile($_FILES['sitelogo']['tmp_name'], $pwhere);
7830 @chmod($pwhere, 0644);
7831 $picon = $j.$safename;
7832 }
7833 }
7834 if (!empty($picon)) {
7835 $config->set('sitelogo', $picon);
7836 }
7837 }
7838 $pbackicon = "";
7839 if (intval($_FILES['backlogo']['error']) == 0 && trim($_FILES['backlogo']['name'])!="") {
7840 jimport('joomla.filesystem.file');
7841 if (@is_uploaded_file($_FILES['backlogo']['tmp_name'])) {
7842 $safename = JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['backlogo']['name'])));
7843 if (file_exists($res_backend_path.$safename)) {
7844 $j = 1;
7845 while (file_exists($res_backend_path.$j.$safename)) {
7846 $j++;
7847 }
7848 $pwhere = $res_backend_path.$j.$safename;
7849 } else {
7850 $j = "";
7851 $pwhere = $res_backend_path.$safename;
7852 }
7853 if (!getimagesize($_FILES['backlogo']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
7854 @unlink($pwhere);
7855 $pbackicon = "";
7856 } else {
7857 VikBooking::uploadFile($_FILES['backlogo']['tmp_name'], $pwhere);
7858 @chmod($pwhere, 0644);
7859 $pbackicon = $j.$safename;
7860 }
7861 }
7862 if (!empty($pbackicon)) {
7863 $config->set('backlogo', $pbackicon);
7864 }
7865 }
7866 $config->set('vcmautoupd', $pvcmautoupd);
7867 $config->set('allowbooking', empty($pallowbooking) || $pallowbooking != "1" ? 0 : 1);
7868 $config->set('showcategories', empty($pshowcategories) || $pshowcategories != "yes" ? 0 : 1);
7869 $config->set('showchildren', empty($pshowchildren) || $pshowchildren != "yes" ? 0 : 1);
7870 $config->set('searchsuggestions', $psearchsuggestions);
7871 $config->set('tokenform', empty($ptokenform) || $ptokenform != "yes" ? 0 : 1);
7872 $config->set('guests_label', $app->input->getString('guests_label', 'adults'));
7873
7874 // translatable text
7875 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfooterordmail)." WHERE `param`='footerordmail';";
7876 $dbo->setQuery($q);
7877 $dbo->execute();
7878
7879 // translatable text
7880 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pdisabledbookingmsg)." WHERE `param`='disabledbookingmsg';";
7881 $dbo->setQuery($q);
7882 $dbo->execute();
7883
7884 // translatable text
7885 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($app->input->getString('guests_allowed_policy', '', 'raw')) . " WHERE `param`='guests_allowed_policy';";
7886 $dbo->setQuery($q);
7887 $dbo->execute();
7888
7889 // terms and conditions
7890 $q = "SELECT `id`,`setting` FROM `#__vikbooking_texts` WHERE `param`='termsconds';";
7891 $dbo->setQuery($q);
7892 $dbo->execute();
7893 if ($dbo->getNumRows() > 0) {
7894 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($ptermsconds)." WHERE `param`='termsconds';";
7895 $dbo->setQuery($q);
7896 $dbo->execute();
7897 } else {
7898 $q = "INSERT INTO `#__vikbooking_texts` (`param`,`exp`,`setting`) VALUES ('termsconds','Terms and Conditions',".$dbo->quote($ptermsconds).");";
7899 $dbo->setQuery($q);
7900 $dbo->execute();
7901 }
7902
7903 $config->set('adminemail', $padminemail);
7904 $config->set('senderemail', $psenderemail);
7905 $config->set('dateformat', empty($pdateformat) ? "%d/%m/%Y" : $pdateformat);
7906 $config->set('datesep', $pdatesep);
7907 $config->set('resmodcanc', $presmodcanc);
7908 $config->set('resmodcancmin', $presmodcancmin);
7909 $config->set('minuteslock', $pminuteslock);
7910 $config->set('minautoremove', $pminautoremove);
7911
7912 $openingh = $ptimeopenstorefh * 3600;
7913 $openingm = $ptimeopenstorefm * 60;
7914 $openingts = $openingh + $openingm;
7915 $closingh = $ptimeopenstoreth * 3600;
7916 $closingm = $ptimeopenstoretm * 60;
7917 $closingts = $closingh + $closingm;
7918 // check if the check-in/out times have changed and if there are future bookings with the old time to prevent availability errors
7919 $prevtimes = $config->get('timeopenstore', '');
7920 if ($prevtimes != $openingts . "-" . $closingts) {
7921 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `checkout`>".time().";";
7922 $dbo->setQuery($q);
7923 $dbo->execute();
7924 if ($dbo->getNumRows() > 0) {
7925 VikError::raiseWarning('', JText::translate('VBOCONFIGWARNDIFFCHECKINOUT'));
7926 /**
7927 * VBO 1.10 Patch - we concatenate a button to unify the check-in/out times
7928 * for all reservations to avoid issues with the availability.
7929 *
7930 * @since August 29th 2018
7931 */
7932 VikError::raiseWarning('', '<br/><a href="index.php?option=com_vikbooking&task=unifycheckinout&fh='.$ptimeopenstorefh.'&fm='.$ptimeopenstorefm.'&th='.$ptimeopenstoreth.'&tm='.$ptimeopenstoretm.'" class="btn btn-large btn-warning">'.JText::translate('VBAPPLY').'</a>');
7933 //
7934 }
7935 }
7936 $config->set('timeopenstore', $openingts . "-" . $closingts);
7937
7938 // set the hours of extended gratuity period to the difference between checkin and checkout if checkout is later
7939 $phoursmorebookingback = "0";
7940 if ($closingts > $openingts) {
7941 $diffcheck = ($closingts - $openingts) / 3600;
7942 $phoursmorebookingback = ceil($diffcheck);
7943 }
7944 $config->set('hoursmorebookingback', $phoursmorebookingback);
7945 $config->set('hoursmoreroomavail', '0');
7946 $config->set('multilang', $pmultilang);
7947 $config->set('requirelogin', $prequirelogin == "1" ? 1 : 0);
7948 $config->set('autoroomunit', $pautoroomunit ? 1 : 0);
7949 $config->set('todaybookings', $ptodaybookings);
7950 $config->set('bootstrap', $ploadbootstrap);
7951 $config->set('usefa', $pusefa);
7952 $config->set('loadjquery', $ploadjquery);
7953 $config->set('calendar', $pcalendar);
7954 $config->set('enablecoupons', $penablecoupons);
7955 $config->set('enablepin', $penablepin);
7956 $config->set('mindaysadvance', $pmindaysadvance);
7957 $config->set('autodefcalnights', $pautodefcalnights);
7958 $config->set('numrooms', $pnumrooms);
7959 $config->set('numadults', $confnumadults);
7960 $config->set('numchildren', $confnumchildren);
7961 $config->set('closingdates', $closing_dates);
7962 $config->set('smartsearch', $psmartsearch);
7963 $config->set('maxdate', $maxdate_str);
7964 $config->set('cronkey', $pcronkey);
7965
7966 $pfronttitle = VikRequest::getString('fronttitle', '', 'request');
7967 $pfronttitletag = VikRequest::getString('fronttitletag', '', 'request');
7968 $pfronttitletagclass = VikRequest::getString('fronttitletagclass', '', 'request');
7969 $pshowfooter = VikRequest::getString('showfooter', '', 'request');
7970 $pintromain = VikRequest::getString('intromain', '', 'request', VIKREQUEST_ALLOWHTML);
7971 $pclosingmain = VikRequest::getString('closingmain', '', 'request', VIKREQUEST_ALLOWHTML);
7972 $pcurrencyname = VikRequest::getString('currencyname', '', 'request', VIKREQUEST_ALLOWHTML);
7973 $pcurrencysymb = VikRequest::getString('currencysymb', '', 'request', VIKREQUEST_ALLOWHTML);
7974 $pcurrencycodepp = VikRequest::getString('currencycodepp', '', 'request');
7975 $pnumdecimals = VikRequest::getString('numdecimals', '', 'request');
7976 $pnumdecimals = intval($pnumdecimals);
7977 $pdecseparator = VikRequest::getString('decseparator', '', 'request');
7978 $pdecseparator = empty($pdecseparator) ? '.' : $pdecseparator;
7979 $pthoseparator = VikRequest::getString('thoseparator', '', 'request');
7980 $numberformatstr = $pnumdecimals.':'.$pdecseparator.':'.$pthoseparator;
7981 $pshowpartlyreserved = VikRequest::getString('showpartlyreserved', '', 'request');
7982 $pshowpartlyreserved = $pshowpartlyreserved == "yes" ? 1 : 0;
7983 $pshowcheckinoutonly = VikRequest::getInt('showcheckinoutonly', '', 'request');
7984 $pshowcheckinoutonly = $pshowcheckinoutonly > 0 ? 1 : 0;
7985 $pnumcalendars = VikRequest::getInt('numcalendars', '', 'request');
7986 $pnumcalendars = $pnumcalendars > -1 ? $pnumcalendars : 3;
7987 $pthumbsize = VikRequest::getInt('thumbsize', 0, 'request');
7988 $pfirstwday = VikRequest::getString('firstwday', '', 'request');
7989 $pfirstwday = intval($pfirstwday) >= 0 && intval($pfirstwday) <= 6 ? $pfirstwday : '0';
7990 $pbctagname = VikRequest::getVar('bctagname', array());
7991 $pbctagcolor = VikRequest::getVar('bctagcolor', array());
7992 $pbctagrule = VikRequest::getVar('bctagrule', array());
7993 $bctags_arr = array();
7994 $bctags_rules = array();
7995 if (count($pbctagname) > 0) {
7996 foreach ($pbctagname as $bctk => $bctv) {
7997 if (!empty($bctv) && !empty($pbctagcolor[$bctk]) && strlen($pbctagrule[$bctk]) > 0) {
7998 if (intval($pbctagrule[$bctk]) == 0 || !in_array($pbctagrule[$bctk], $bctags_rules)) {
7999 $bctags_rules[] = $pbctagrule[$bctk];
8000 $bctags_arr[] = array('color' => $pbctagcolor[$bctk], 'name' => $bctv, 'rule' => $pbctagrule[$bctk]);
8001 }
8002 }
8003 }
8004 }
8005 //theme
8006 $ptheme = VikRequest::getString('theme', '', 'request');
8007 if (empty($ptheme) || $ptheme == 'default') {
8008 $ptheme = 'default';
8009 } else {
8010 $validtheme = false;
8011 $themes = glob(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'*');
8012 if (count($themes) > 0) {
8013 $strip = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR;
8014 foreach ($themes as $th) {
8015 if (is_dir($th)) {
8016 $tname = str_replace($strip, '', $th);
8017 if ($tname == $ptheme) {
8018 $validtheme = true;
8019 break;
8020 }
8021 }
8022 }
8023 }
8024 if ($validtheme == false) {
8025 $ptheme = 'default';
8026 }
8027 }
8028 $config->set('theme', $ptheme);
8029 //
8030 $config->set('showpartlyreserved', $pshowpartlyreserved);
8031 $config->set('showcheckinoutonly', $pshowcheckinoutonly);
8032 $config->set('numcalendars', $pnumcalendars);
8033
8034 // record may not be set
8035 $config->set('thumbsize', $pthumbsize);
8036
8037 $config->set('firstwday', $pfirstwday);
8038
8039 // translatable text
8040 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pfronttitle)." WHERE `param`='fronttitle';";
8041 $dbo->setQuery($q);
8042 $dbo->execute();
8043
8044 $config->set('fronttitletag', $pfronttitletag);
8045 $config->set('fronttitletagclass', $pfronttitletagclass);
8046 $config->set('showfooter', empty($pshowfooter) || $pshowfooter != "yes" ? 0 : 1);
8047
8048 // translatable texts
8049 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pintromain)." WHERE `param`='intromain';";
8050 $dbo->setQuery($q);
8051 $dbo->execute();
8052 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($pclosingmain)." WHERE `param`='closingmain';";
8053 $dbo->setQuery($q);
8054 $dbo->execute();
8055
8056 $config->set('currencyname', $pcurrencyname);
8057 $config->set('currencysymb', $pcurrencysymb);
8058 $config->set('currencycodepp', $pcurrencycodepp);
8059 $config->set('numberformat', $numberformatstr);
8060 // bookings color tags
8061 $config->set('bookingsctags', $bctags_arr);
8062
8063 $pivainclusa = VikRequest::getString('ivainclusa', '', 'request');
8064 $ptaxsummary = VikRequest::getString('taxsummary', '', 'request');
8065 $ptaxsummary = empty($ptaxsummary) || $ptaxsummary != "yes" ? "0" : "1";
8066 $pccpaypal = VikRequest::getString('ccpaypal', '', 'request');
8067 $ppaytotal = VikRequest::getString('paytotal', '', 'request');
8068 $ppayaccpercent = VikRequest::getString('payaccpercent', '', 'request');
8069 $ptypedeposit = VikRequest::getString('typedeposit', '', 'request');
8070 $ptypedeposit = $ptypedeposit == 'fixed' ? 'fixed' : 'pcent';
8071 $pdepoverrides = VikRequest::getString('depoverrides', '', 'request');
8072 $ppaymentname = VikRequest::getString('paymentname', '', 'request');
8073 $pdisclaimer = VikRequest::getString('disclaimer', '', 'request', VIKREQUEST_ALLOWHTML);
8074 $pmultipay = VikRequest::getString('multipay', '', 'request');
8075 $pmultipay = $pmultipay == "yes" ? 1 : 0;
8076 $pdepifdaysadv = VikRequest::getInt('depifdaysadv', '', 'request');
8077 $pnodepnonrefund = VikRequest::getInt('nodepnonrefund', '', 'request');
8078 $pdepcustchoice = VikRequest::getString('depcustchoice', '', 'request');
8079 $pdepcustchoice = $pdepcustchoice == "yes" ? 1 : 0;
8080
8081 // translatable text
8082 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($ppaymentname) . " WHERE `param`='paymentname';";
8083 $dbo->setQuery($q);
8084 $dbo->execute();
8085 $q = "UPDATE `#__vikbooking_texts` SET `setting`=" . $dbo->q($pdisclaimer) . " WHERE `param`='disclaimer';";
8086 $dbo->setQuery($q);
8087 $dbo->execute();
8088
8089 $config->set('ivainclusa', empty($pivainclusa) || $pivainclusa != "yes" ? 0 : 1);
8090 $config->set('taxsummary', $ptaxsummary);
8091 $config->set('paytotal', empty($ppaytotal) || $ppaytotal != "yes" ? 0 : 1);
8092
8093 $config->set('ccpaypal', $pccpaypal);
8094 $config->set('payaccpercent', $ppayaccpercent);
8095 $config->set('typedeposit', $ptypedeposit);
8096 $config->set('depoverrides', $pdepoverrides);
8097 $config->set('multipay', $pmultipay);
8098 $config->set('depifdaysadv', $pdepifdaysadv);
8099 $config->set('nodepnonrefund', $pnodepnonrefund);
8100 $config->set('depcustchoice', $pdepcustchoice);
8101
8102 $psendemailwhen = VikRequest::getInt('sendemailwhen', '', 'request');
8103 $psendemailwhen = $psendemailwhen > 1 ? 2 : 1;
8104 $pattachical = VikRequest::getInt('attachical', 0, 'request');
8105 $pattachical = $pattachical >= 0 && $pattachical <= 3 ? $pattachical : 1;
8106 $config->set('emailsendwhen', $psendemailwhen);
8107 $config->set('attachical', $pattachical);
8108
8109 // SMS APIs
8110 $psmsapi = VikRequest::getString('smsapi', '', 'request');
8111 $psmsautosend = VikRequest::getString('smsautosend', '', 'request');
8112 $psmsautosend = intval($psmsautosend) > 0 ? 1 : 0;
8113 $psmssendto = VikRequest::getVar('smssendto', array());
8114 $sms_sendto = array();
8115 foreach ($psmssendto as $sto) {
8116 if (in_array($sto, array('admin', 'customer'))) {
8117 $sms_sendto[] = $sto;
8118 }
8119 }
8120 $psmssendwhen = VikRequest::getInt('smssendwhen', '', 'request');
8121 $psmssendwhen = $psmssendwhen > 1 ? 2 : 1;
8122 $psmsadminphone = VikRequest::getString('smsadminphone', '', 'request');
8123 $psmsadmintpl = VikRequest::getString('smsadmintpl', '', 'request', VIKREQUEST_ALLOWRAW);
8124 $psmscustomertpl = VikRequest::getString('smscustomertpl', '', 'request', VIKREQUEST_ALLOWRAW);
8125 $psmsadmintplpend = VikRequest::getString('smsadmintplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8126 $psmscustomertplpend = VikRequest::getString('smscustomertplpend', '', 'request', VIKREQUEST_ALLOWRAW);
8127 $psmsadmintplcanc = VikRequest::getString('smsadmintplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8128 $psmscustomertplcanc = VikRequest::getString('smscustomertplcanc', '', 'request', VIKREQUEST_ALLOWRAW);
8129 $viksmsparams = VikRequest::getVar('viksmsparams', array());
8130 $smsparamarr = array();
8131 if (count($viksmsparams) > 0) {
8132 foreach ($viksmsparams as $setting => $cont) {
8133 if (strlen($setting) > 0) {
8134 $smsparamarr[$setting] = $cont;
8135 }
8136 }
8137 }
8138 $config->set('smsapi', $psmsapi);
8139 $config->set('smsautosend', $psmsautosend);
8140 $config->set('smssendto', $sms_sendto);
8141 $config->set('smssendwhen', $psmssendwhen);
8142 $config->set('smsadminphone', $psmsadminphone);
8143 $config->set('smsparams', $smsparamarr);
8144
8145 // translatable texts
8146 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintpl)." WHERE `param`='smsadmintpl';";
8147 $dbo->setQuery($q);
8148 $dbo->execute();
8149 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertpl)." WHERE `param`='smscustomertpl';";
8150 $dbo->setQuery($q);
8151 $dbo->execute();
8152 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplpend)." WHERE `param`='smsadmintplpend';";
8153 $dbo->setQuery($q);
8154 $dbo->execute();
8155 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplpend)." WHERE `param`='smscustomertplpend';";
8156 $dbo->setQuery($q);
8157 $dbo->execute();
8158 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmsadmintplcanc)." WHERE `param`='smsadmintplcanc';";
8159 $dbo->setQuery($q);
8160 $dbo->execute();
8161 $q = "UPDATE `#__vikbooking_texts` SET `setting`=".$dbo->quote($psmscustomertplcanc)." WHERE `param`='smscustomertplcanc';";
8162 $dbo->setQuery($q);
8163 $dbo->execute();
8164
8165 /**
8166 * Backup settings
8167 *
8168 * @since 1.15.0 (J) - 1.5.0 (WP)
8169 */
8170 $backup_type = $app->input->getString('backuptype', 'full');
8171 $backup_folder = $app->input->getString('backupfolder', '');
8172
8173 $tmp = $app->get('tmp_path');
8174
8175 if (!$backup_folder)
8176 {
8177 // path not specified, use temporary folder
8178 $backup_folder = $tmp;
8179 }
8180
8181 $current = $config->get('backupfolder');
8182
8183 if (!$current)
8184 {
8185 // path was missing, use temporary folder
8186 $current = $tmp;
8187 }
8188
8189 // check whether the backup folder has been moved
8190 if ($current && $backup_folder && rtrim($current, DIRECTORY_SEPARATOR) !== rtrim($backup_folder, DIRECTORY_SEPARATOR))
8191 {
8192 $backupModel = new VBOModelBackup();
8193
8194 // backup folder moved, try to copy all the existing overrides
8195 if (!$backupModel->moveArchives($backup_folder))
8196 {
8197 // iterate all errors and display them
8198 foreach ($backupModel->getErrors() as $error)
8199 {
8200 $app->enqueueMessage($error, 'warning');
8201 }
8202 }
8203 }
8204
8205 // save configuration
8206 $config->set('backuptype', $backup_type);
8207 $config->set('backupfolder', $backup_folder);
8208
8209 /**
8210 * Check-in data collection type.
8211 *
8212 * @since 1.15.0 (J) - 1.5.0 (WP)
8213 */
8214 $config->set('checkindata', VikRequest::getString('checkindata', 'basic', 'request'));
8215
8216 /**
8217 * Front-end appearance.
8218 *
8219 * @since 1.15.0 (J) - 1.5.0 (WP) (patch)
8220 */
8221 $config->set('appearance_front', VikRequest::getInt('appearance_front', 0, 'request'));
8222
8223 /**
8224 * Split stays.
8225 *
8226 * @since 1.16.0 (J) - 1.6.0 (WP)
8227 */
8228 $glob_split_stay = VikRequest::getInt('split_stay', 0, 'request');
8229 $split_stay_ratio = VikRequest::getFloat('split_stay_ratio', 0, 'request');
8230 $split_stay_ratio = $split_stay_ratio > 100 ? 100 : $split_stay_ratio;
8231 $config->set('split_stay_ratio', ($glob_split_stay && $split_stay_ratio > 0 ? $split_stay_ratio : 0));
8232
8233 /**
8234 * Re-build Web App manifest file to let the event trigger.
8235 *
8236 * @since 1.16.5 (J) - 1.6.5 (WP)
8237 */
8238 try {
8239 VBOWebappManifest::build();
8240 } catch (Exception $e) {
8241 // do nothing
8242 }
8243
8244 // redirect
8245 $app->enqueueMessage(JText::translate('VBSETTINGSAVED'));
8246 $app->redirect('index.php?option=com_vikbooking&task=config');
8247 $app->close();
8248 }
8249
8250 /**
8251 * Unify the check-in and check-out times for all reservations.
8252 *
8253 * @since 1.10 - Patch August 29th 2018
8254 */
8255 public function unifycheckinout() {
8256 $dbo = JFactory::getDBO();
8257 $mainframe = JFactory::getApplication();
8258 $fh = VikRequest::getInt('fh', 12, 'request');
8259 $fm = VikRequest::getInt('fm', 0, 'request');
8260 $th = VikRequest::getInt('th', 10, 'request');
8261 $tm = VikRequest::getInt('tm', 0, 'request');
8262 $totmod = 0;
8263 $totbookmod = 0;
8264 $q = "SELECT * FROM `#__vikbooking_busy`;";
8265 $dbo->setQuery($q);
8266 $dbo->execute();
8267 $records = $dbo->loadAssocList();
8268 foreach ($records as $v) {
8269 $info_start = getdate($v['checkin']);
8270 $info_end = getdate($v['checkout']);
8271 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8272 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8273 $q = "UPDATE `#__vikbooking_busy` SET `checkin`=".$new_start.",`checkout`=".$new_end.",`realback`=".$new_end." WHERE `id`=".$v['id']." LIMIT 1;";
8274 $dbo->setQuery($q);
8275 $dbo->execute();
8276 $totmod++;
8277 }
8278
8279 $q = "SELECT * FROM `#__vikbooking_orders`;";
8280 $dbo->setQuery($q);
8281 $dbo->execute();
8282 $records = $dbo->loadAssocList();
8283 foreach ($records as $v) {
8284 $info_start = getdate($v['checkin']);
8285 $info_end = getdate($v['checkout']);
8286 $new_start = mktime($fh, $fm, 0, $info_start['mon'], $info_start['mday'], $info_start['year']);
8287 $new_end = mktime($th, $tm, 0, $info_end['mon'], $info_end['mday'], $info_end['year']);
8288 $q = "UPDATE `#__vikbooking_orders` SET `checkin`=".$new_start.",`checkout`=".$new_end." WHERE `id`=".$v['id']." LIMIT 1;";
8289 $dbo->setQuery($q);
8290 $dbo->execute();
8291 $totbookmod++;
8292 }
8293 $mainframe->enqueueMessage('OK: '.$totbookmod);
8294 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
8295 }
8296
8297 public function savetmplfile() {
8298 if (!JSession::checkToken()) {
8299 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8300 }
8301 $fpath = VikRequest::getString('path', '', 'request', VIKREQUEST_ALLOWRAW);
8302 $pcont = VikRequest::getString('cont', '', 'request', VIKREQUEST_ALLOWRAW);
8303 $mainframe = JFactory::getApplication();
8304 $exists = file_exists($fpath) ? true : false;
8305 if (!$exists) {
8306 $fpath = urldecode($fpath);
8307 }
8308 $fpath = file_exists($fpath) ? $fpath : '';
8309 if (!empty($fpath)) {
8310 $fp = fopen($fpath, 'wb');
8311 $byt = (int)fwrite($fp, $pcont);
8312 fclose($fp);
8313 if ($byt > 0) {
8314 $mainframe->enqueueMessage(JText::translate('VBOUPDTMPLFILEOK'));
8315
8316 if (VBOPlatformDetection::isWordPress()) {
8317 /**
8318 * @wponly call the UpdateManager Class to temporarily store modifications made to template files
8319 */
8320 VikBookingUpdateManager::storeTemplateContent($fpath, $pcont);
8321 }
8322 } else {
8323 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILENOBYTES'));
8324 }
8325 } else {
8326 VikError::raiseWarning('', JText::translate('VBOUPDTMPLFILEERR'));
8327 }
8328 $mainframe->redirect("index.php?option=com_vikbooking&task=edittmplfile&path=".$fpath."&tmpl=component");
8329
8330 exit;
8331 }
8332
8333 public function edittmplfile() {
8334 //modal box, so we do not set menu or footer
8335
8336 VikRequest::setVar('view', VikRequest::getCmd('view', 'edittmplfile'));
8337
8338 parent::display();
8339 }
8340
8341 public function tmplfileprew() {
8342 //modal box, so we do not set menu or footer
8343
8344 VikRequest::setVar('view', VikRequest::getCmd('view', 'tmplfileprew'));
8345
8346 parent::display();
8347 }
8348
8349 public function invoices() {
8350 VikBookingHelper::printHeader("invoices");
8351
8352 VikRequest::setVar('view', VikRequest::getCmd('view', 'invoices'));
8353
8354 parent::display();
8355
8356 if (VikBooking::showFooter()) {
8357 VikBookingHelper::printFooter();
8358 }
8359 }
8360
8361 public function newmaninvoice() {
8362 VikBookingHelper::printHeader("invoices");
8363
8364 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8365
8366 parent::display();
8367
8368 if (VikBooking::showFooter()) {
8369 VikBookingHelper::printFooter();
8370 }
8371 }
8372
8373 public function editmaninvoice() {
8374 VikBookingHelper::printHeader("invoices");
8375
8376 VikRequest::setVar('view', VikRequest::getCmd('view', 'managemaninvoice'));
8377
8378 parent::display();
8379
8380 if (VikBooking::showFooter()) {
8381 VikBookingHelper::printFooter();
8382 }
8383 }
8384
8385 public function savemaninvoice() {
8386 if (!JSession::checkToken()) {
8387 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8388 }
8389 $this->do_storemaninvoice('save');
8390 $mainframe = JFactory::getApplication();
8391 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8392 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8393 if (!empty($pgoto)) {
8394 $mainframe->redirect(base64_decode($pgoto));
8395 exit;
8396 }
8397 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8398 }
8399
8400 public function updatemaninvoice() {
8401 if (!JSession::checkToken()) {
8402 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8403 }
8404 $invid = VikRequest::getInt('whereup', 0, 'request');
8405 $this->do_storemaninvoice('update', $invid);
8406 $mainframe = JFactory::getApplication();
8407 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8408 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8409 if (!empty($pgoto)) {
8410 $mainframe->redirect(base64_decode($pgoto));
8411 exit;
8412 }
8413 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8414 }
8415
8416 public function updatemaninvoicestay() {
8417 $invid = VikRequest::getInt('whereup', 0, 'request');
8418 $this->do_storemaninvoice('updatestay', $invid);
8419 $mainframe = JFactory::getApplication();
8420 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', 1, 0));
8421 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
8422 if (!empty($pgoto)) {
8423 $mainframe->redirect(base64_decode($pgoto));
8424 exit;
8425 }
8426 $mainframe->redirect("index.php?option=com_vikbooking&task=editmaninvoice&cid[]=".$invid);
8427 }
8428
8429 private function do_storemaninvoice($action, $invid = 0) {
8430 $dbo = JFactory::getDBO();
8431 $mainframe = JFactory::getApplication();
8432 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8433 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8434 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8435 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8436 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8437 $pinvoice_notes = VikRequest::getString('invoice_notes', '', 'request', VIKREQUEST_ALLOWHTML);
8438 $pinvoice_notes = strpos($pinvoice_notes, '<') !== false ? $pinvoice_notes : nl2br($pinvoice_notes);
8439 $pidcustomer = VikRequest::getInt('idcustomer', '', 'request');
8440 $error_uri = strpos($action, 'update') !== false && !empty($invid) ? 'index.php?option=com_vikbooking&task=editmaninvoice&cid[]='.$invid : 'index.php?option=com_vikbooking&task=newmaninvoice';
8441 if (empty($pidcustomer)) {
8442 VikError::raiseWarning('', JText::translate('VBNOCUSTOMERS'));
8443 $mainframe->redirect($error_uri);
8444 exit;
8445 }
8446 $services = VikRequest::getVar('service', array());
8447 $nets = VikRequest::getVar('net', array());
8448 $aliqs = VikRequest::getVar('aliq', array());
8449 $taxs = VikRequest::getVar('tax', array());
8450 $tots = VikRequest::getVar('tot', array());
8451 $ptotalnet = VikRequest::getFloat('totalnet', 0, 'request');
8452 $ptotaltax = VikRequest::getFloat('totaltax', 0, 'request');
8453 $ptotaltot = VikRequest::getFloat('totaltot', 0, 'request');
8454 if (!count($services) || count($services) != count($nets) || count($services) != count($taxs) || count($services) != count($tots)) {
8455 VikError::raiseWarning('', 'Missing data.');
8456 $mainframe->redirect($error_uri);
8457 exit;
8458 }
8459 $rawcont = array(
8460 'rows' => array(),
8461 'totalnet' => $ptotalnet,
8462 'totaltax' => $ptotaltax,
8463 'totaltot' => $ptotaltot,
8464 'notes' => $pinvoice_notes,
8465 );
8466 foreach ($services as $k => $service) {
8467 if (empty($service)) {
8468 continue;
8469 }
8470 array_push($rawcont['rows'], array(
8471 'service' => $service,
8472 'net' => (float)$nets[$k],
8473 'aliq' => (isset($aliqs[$k]) ? (float)$aliqs[$k] : 0),
8474 'tax' => (float)$taxs[$k],
8475 'tot' => (float)$tots[$k],
8476 ));
8477 }
8478 // store/update manual invoice
8479 $nowts = time();
8480 $retval = 0;
8481 if (strpos($action, 'save') !== false) {
8482 $pdffname = $nowts . '_' . rand() . '.pdf';
8483 $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)).");";
8484 $dbo->setQuery($q);
8485 $dbo->execute();
8486 $retval = $dbo->insertid();
8487 } else {
8488 // fetch old record
8489 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$invid.";";
8490 $dbo->setQuery($q);
8491 $dbo->execute();
8492 if (!$dbo->getNumRows()) {
8493 VikError::raiseWarning('', JText::translate('VBNOINVOICESFOUND'));
8494 $mainframe->redirect($error_uri);
8495 exit;
8496 }
8497 $previnvoice = $dbo->loadAssoc();
8498 //
8499 $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'].";";
8500 $dbo->setQuery($q);
8501 $dbo->execute();
8502 $retval = $previnvoice['id'];
8503 }
8504 // update config values for the invoice
8505 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8506 $dbo->setQuery($q);
8507 $dbo->execute();
8508 // generate the custom invoice
8509 $result = VikBooking::generateCustomInvoice($retval);
8510 //
8511 $nextinv = VikBooking::getNextInvoiceNumber();
8512 $updatenum = ($pinvoice_num >= $nextinv);
8513 if ($updatenum) {
8514 /**
8515 * IMPORTANT: update the next invoice number after calling the e-Invocing drivers
8516 * to avoid conflicts with the drivers for the e-invoices generation.
8517 */
8518 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8519 $dbo->setQuery($q);
8520 $dbo->execute();
8521 }
8522
8523 return $retval;
8524 }
8525
8526 public function downloadinvoices() {
8527 $ids = VikRequest::getVar('cid', array(0));
8528 if (@count($ids) > 0) {
8529 $dbo = JFactory::getDBO();
8530 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id` IN (".implode(', ', $ids).");";
8531 $dbo->setQuery($q);
8532 $dbo->execute();
8533 if ($dbo->getNumRows() > 0) {
8534 $invoices = $dbo->loadAssocList();
8535 if (!(count($invoices) > 1)) {
8536 //Single Invoice Download
8537 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name'])) {
8538 header("Content-type:application/pdf");
8539 header("Content-Disposition:attachment;filename=".$invoices[0]['file_name']);
8540 readfile(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoices[0]['file_name']);
8541 exit;
8542 }
8543 } else {
8544 //Multiple Invoices Download
8545 $to_zip = array();
8546 foreach ($invoices as $k => $invoice) {
8547 $to_zip[$k]['name'] = $invoice['file_name'];
8548 $to_zip[$k]['path'] = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$invoice['file_name'];
8549 }
8550 if (class_exists('ZipArchive')) {
8551 $zip_path = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.date('Y-m-d').'-invoices.zip';
8552 $zip = new ZipArchive;
8553 $zip->open($zip_path, ZipArchive::CREATE);
8554 foreach ($to_zip as $k => $zipv) {
8555 $zip->addFile($zipv['path'], $zipv['name']);
8556 }
8557 $zip->close();
8558 header("Content-type:application/zip");
8559 header("Content-Disposition:attachment;filename=".date('Y-m-d').'-invoices.zip');
8560 header("Content-Length:".filesize($zip_path));
8561 readfile($zip_path);
8562 unlink($zip_path);
8563 exit;
8564 } else {
8565 //Class ZipArchive does not exist
8566 VikError::raiseWarning('', 'Class ZipArchive does not exist on your server. Download the files one by one.');
8567 }
8568 }
8569 }
8570 }
8571 $mainframe = JFactory::getApplication();
8572 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8573 }
8574
8575 public function resendinvoices() {
8576 $ids = VikRequest::getVar('cid', array(0));
8577 $mainframe = JFactory::getApplication();
8578 if (!(count($ids) > 0)) {
8579 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8580 exit;
8581 }
8582 $dbo = JFactory::getDBO();
8583 $invoices = array();
8584 $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` ".
8585 "FROM `#__vikbooking_invoices` AS `i` " .
8586 "LEFT JOIN `#__vikbooking_orders` `o` ON `o`.`id`=`i`.`idorder` " .
8587 "LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`i`.`idcustomer` " .
8588 "LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`c`.`country` " .
8589 "WHERE `i`.`id` IN (".implode(', ', $ids).") AND (`i`.`idorder` < 0 OR (`o`.`status`='confirmed' AND `o`.`total` > 0)) ORDER BY `o`.`id` ASC;";
8590 $dbo->setQuery($q);
8591 $dbo->execute();
8592 if ($dbo->getNumRows() > 0) {
8593 $invoices = $dbo->loadAssocList();
8594 }
8595 if (!(count($invoices) > 0)) {
8596 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8597 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8598 exit;
8599 }
8600 $tot_generated = 0;
8601 $tot_sent = 0;
8602 foreach ($invoices as $bkey => $invoice) {
8603 $invoice['custmail'] = empty($invoice['custmail']) && !empty($invoice['customer_email']) ? $invoice['customer_email'] : $invoice['custmail'];
8604 $invoices[$bkey] = $invoice;
8605 $send_res = VikBooking::sendBookingInvoice($invoice['id'], $invoice);
8606 if ($send_res !== false) {
8607 $tot_sent++;
8608 }
8609 }
8610 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8611 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8612 }
8613
8614 public function removeinvoices() {
8615 $ids = VikRequest::getVar('cid', array());
8616 $tot_removed = 0;
8617 $dbo = JFactory::getDbo();
8618
8619 foreach ($ids as $d) {
8620 $q = "SELECT * FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8621 $dbo->setQuery($q);
8622 $dbo->execute();
8623 if ($dbo->getNumRows() == 1) {
8624 $cur_invoice = $dbo->loadAssoc();
8625 if (file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name'])) {
8626 unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'invoices'.DIRECTORY_SEPARATOR.'generated'.DIRECTORY_SEPARATOR.$cur_invoice['file_name']);
8627 }
8628 $q = "DELETE FROM `#__vikbooking_invoices` WHERE `id`=".(int)$d.";";
8629 $dbo->setQuery($q);
8630 $dbo->execute();
8631 $tot_removed++;
8632 }
8633 }
8634
8635 $mainframe = JFactory::getApplication();
8636 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESRMVD', $tot_removed));
8637 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
8638 }
8639
8640 public function geninvoices() {
8641 $ids = VikRequest::getVar('cid', array(0));
8642 $mainframe = JFactory::getApplication();
8643 if (!count($ids)) {
8644 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8645 exit;
8646 }
8647 $dbo = JFactory::getDBO();
8648 $pinvoice_num = VikRequest::getInt('invoice_num', '', 'request');
8649 $pinvoice_num = $pinvoice_num <= 0 ? 1 : $pinvoice_num;
8650 $pinvoice_suff = VikRequest::getString('invoice_suff', '', 'request');
8651 $pinvoice_date = VikRequest::getString('invoice_date', '', 'request');
8652 $pcompany_info = VikRequest::getString('company_info', '', 'request', VIKREQUEST_ALLOWHTML);
8653 $pcompany_info = strpos($pcompany_info, '<') !== false ? $pcompany_info : nl2br($pcompany_info);
8654 $pinvoice_send = VikRequest::getInt('invoice_send', '', 'request');
8655 $pinvoice_send = $pinvoice_send > 0 ? true : false;
8656 $increment_inv = true;
8657 $pconfirmgen = VikRequest::getInt('confirmgen', '', 'request');
8658 //if editing an invoice (re-creating an existing invoice for a booking), do not increment the invoice number
8659 if (count($ids) == 1) {
8660 $q = "SELECT `number` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$ids[0].";";
8661 $dbo->setQuery($q);
8662 $dbo->execute();
8663 if ($dbo->getNumRows() == 1) {
8664 $increment_inv = false;
8665 }
8666 }
8667 //
8668 $bookings = array();
8669 $q = "SELECT `o`.*,`co`.`idcustomer`,CONCAT_WS(' ',`c`.`first_name`,`c`.`last_name`) AS `customer_name`,`c`.`pin` AS `customer_pin`,`nat`.`country_name` FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idorder`=`o`.`id` LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`co`.`idcustomer` LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`o`.`country` WHERE `o`.`id` IN (".implode(', ', $ids).") AND `o`.`status`='confirmed' AND `o`.`total` > 0 ORDER BY `o`.`id` ASC;";
8670 $dbo->setQuery($q);
8671 $dbo->execute();
8672 if ($dbo->getNumRows() > 0) {
8673 $bookings = $dbo->loadAssocList();
8674 }
8675 if (!count($bookings)) {
8676 VikError::raiseWarning('', JText::translate('VBOGENINVERRNOBOOKINGS'));
8677 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8678 exit;
8679 }
8680 $tot_generated = 0;
8681 $tot_sent = 0;
8682 foreach ($bookings as $bkey => $booking) {
8683 $gen_res = VikBooking::generateBookingInvoice($booking, $pinvoice_num, $pinvoice_suff, $pinvoice_date, $pcompany_info);
8684 if ($gen_res !== false && $gen_res > 0) {
8685 $tot_generated++;
8686 $pinvoice_num++;
8687 if ($pinvoice_send) {
8688 $send_res = VikBooking::sendBookingInvoice($gen_res, $booking);
8689 if ($send_res !== false) {
8690 $tot_sent++;
8691 }
8692 }
8693 } else {
8694 VikError::raiseWarning('', JText::sprintf('VBOGENINVERRBOOKING', $booking['id']));
8695 }
8696 }
8697 if ($tot_generated > 0 && $increment_inv === true) {
8698 /**
8699 * IMPORTANT: update the next invoice number after calling generateBookingInvoice()
8700 * to avoid conflicts with the drivers for the e-invoices generation.
8701 */
8702 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(($pinvoice_num - 1))." WHERE `param`='invoiceinum';";
8703 $dbo->setQuery($q);
8704 $dbo->execute();
8705 }
8706 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pinvoice_suff)." WHERE `param`='invoicesuffix';";
8707 $dbo->setQuery($q);
8708 $dbo->execute();
8709 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($pcompany_info)." WHERE `param`='invcompanyinfo';";
8710 $dbo->setQuery($q);
8711 $dbo->execute();
8712 $mainframe->enqueueMessage(JText::sprintf('VBOTOTINVOICESGEND', $tot_generated, $tot_sent));
8713 if ($pconfirmgen > 0) {
8714 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices&show=".$pconfirmgen);
8715 } elseif (count($bookings) === 1) {
8716 // go to the back-end booking details page
8717 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $bookings[0]['id']);
8718 } else {
8719 $mainframe->redirect("index.php?option=com_vikbooking&task=orders");
8720 }
8721 }
8722
8723 public function optionals() {
8724 VikBookingHelper::printHeader("6");
8725
8726 VikRequest::setVar('view', VikRequest::getCmd('view', 'optionals'));
8727
8728 parent::display();
8729
8730 if (VikBooking::showFooter()) {
8731 VikBookingHelper::printFooter();
8732 }
8733 }
8734
8735 public function newoptionals() {
8736 VikBookingHelper::printHeader("6");
8737
8738 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8739
8740 parent::display();
8741
8742 if (VikBooking::showFooter()) {
8743 VikBookingHelper::printFooter();
8744 }
8745 }
8746
8747 public function editoptional() {
8748 VikBookingHelper::printHeader("6");
8749
8750 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoptional'));
8751
8752 parent::display();
8753
8754 if (VikBooking::showFooter()) {
8755 VikBookingHelper::printFooter();
8756 }
8757 }
8758
8759 public function updateoptional() {
8760 if (!JSession::checkToken()) {
8761 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8762 }
8763 $this->do_updateoptional();
8764 }
8765
8766 public function updateoptionalstay() {
8767 if (!JSession::checkToken()) {
8768 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
8769 }
8770 $this->do_updateoptional(true);
8771 }
8772
8773 private function do_updateoptional($stay = false) {
8774 $dbo = JFactory::getDbo();
8775 $app = JFactory::getApplication();
8776 $poptname = VikRequest::getString('optname', '', 'request');
8777 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
8778 $poptcost = VikRequest::getFloat('optcost', '', 'request');
8779 $poptperday = VikRequest::getString('optperday', '', 'request');
8780 $poptperperson = VikRequest::getString('optperperson', '', 'request');
8781 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
8782 $popthmany = VikRequest::getString('opthmany', '', 'request');
8783 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
8784 $pwhereup = VikRequest::getString('whereup', '', 'request');
8785 $pautoresize = VikRequest::getString('autoresize', '', 'request');
8786 $presizeto = VikRequest::getString('resizeto', '', 'request');
8787 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
8788 $pifchildren = $pifchildren == "1" ? 1 : 0;
8789 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
8790 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
8791 $pforcesel = VikRequest::getString('forcesel', '', 'request');
8792 $pforceval = VikRequest::getString('forceval', '', 'request');
8793 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
8794 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
8795 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
8796 $pforcesel = $pforcesel == "1" ? 1 : 0;
8797 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
8798 $pis_fee = VikRequest::getString('is_fee', '', 'request');
8799 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
8800 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
8801 $pagefrom = VikRequest::getVar('agefrom', array());
8802 $pageto = VikRequest::getVar('ageto', array());
8803 $pagecost = VikRequest::getVar('agecost', array());
8804 $pagectype = VikRequest::getVar('agectype', array());
8805 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
8806 $pavfrom = VikRequest::getString('avfrom', '', 'request');
8807 $pavto = VikRequest::getString('avto', '', 'request');
8808 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
8809 $pidrooms = VikRequest::getVar('idrooms', array());
8810 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
8811 if ($pforcesel == 1) {
8812 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
8813 } else {
8814 $strforceval = "";
8815 }
8816 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
8817 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
8818 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
8819 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
8820 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
8821 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
8822 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
8823 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
8824 $minguests = VikRequest::getInt('minguests', 0, 'request');
8825 $minguests_conflict = false;
8826 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
8827 if ($minguestsnum >= $maxguestsnum) {
8828 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
8829 } elseif (($maxguestsnum - $minguestsnum) < 2) {
8830 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
8831 }
8832 }
8833 if (!$minguests || $minguests_conflict !== false) {
8834 $minguestsnum = 0;
8835 $maxguestsnum = 0;
8836 if ($minguests_conflict !== false) {
8837 // raise warning, but do not stop the process
8838 VikError::raiseWarning('', $minguests_conflict);
8839 }
8840 }
8841 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
8842 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
8843 $oparams = array(
8844 'minguestsnum' => $minguestsnum,
8845 'mingueststype' => $mingueststype,
8846 'maxguestsnum' => $maxguestsnum,
8847 'maxgueststype' => $maxgueststype,
8848 'damagedep' => $damagedep,
8849 'pet_fee' => $pet_fee,
8850 );
8851 /**
8852 * We fetch the previous params to merge them with the new ones
8853 * in case some properties have been set somewhere else.
8854 * For example, the damage deposit transmission to Booking.com.
8855 */
8856 $cur_oparams = array();
8857 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$pwhereup . ";";
8858 $dbo->setQuery($q);
8859 $dbo->execute();
8860 if ($dbo->getNumRows()) {
8861 $cur_oparams = $dbo->loadResult();
8862 $cur_oparams = !empty($cur_oparams) ? json_decode($cur_oparams, true) : array();
8863 $cur_oparams = !is_array($cur_oparams) ? array() : $cur_oparams;
8864 // merge previous params with the new ones to get the new values
8865 $oparams = array_merge($cur_oparams, $oparams);
8866 }
8867 //
8868 if (!empty($poptname)) {
8869 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
8870 jimport('joomla.filesystem.file');
8871 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
8872 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
8873 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
8874 if (file_exists($updpath.$safename)) {
8875 $j=1;
8876 while (file_exists($updpath.$j.$safename)) {
8877 $j++;
8878 }
8879 $pwhere=$updpath.$j.$safename;
8880 } else {
8881 $j="";
8882 $pwhere=$updpath.$safename;
8883 }
8884 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
8885 @unlink($pwhere);
8886 $picon="";
8887 } else {
8888 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
8889 @chmod($pwhere, 0644);
8890 $picon=$j.$safename;
8891 if ($pautoresize=="1" && !empty($presizeto)) {
8892 $eforj = new vikResizer();
8893 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
8894 if ($origmod) {
8895 @unlink($pwhere);
8896 $picon='r_'.$j.$safename;
8897 }
8898 }
8899 }
8900 } else {
8901 $picon="";
8902 }
8903 } else {
8904 $picon="";
8905 }
8906 ($poptperday=="each" ? $poptperday="1" : $poptperday="0");
8907 $poptperperson=($poptperperson=="each" ? "1" : "0");
8908 ($popthmany=="yes" ? $popthmany="1" : $popthmany="0");
8909 $ageintervalstr = '';
8910 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
8911 foreach ($pagefrom as $kage => $vage) {
8912 $afrom = intval($vage);
8913 $ato = intval($pageto[$kage]);
8914 $acost = floatval($pagecost[$kage]);
8915 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
8916 if ($ato < $afrom) $ato = $afrom;
8917 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
8918 }
8919 }
8920 $ageintervalstr = rtrim($ageintervalstr, ';;');
8921 if (!empty($ageintervalstr)) {
8922 $pforcesel = 1;
8923 }
8924 }
8925 $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).";";
8926 $dbo->setQuery($q);
8927 $dbo->execute();
8928 $app->enqueueMessage(JText::translate('VBOSUCCUPDOPTION'));
8929
8930 // assign/unset option-rooms relations
8931 $rooms_with_opt = array();
8932 if (count($pidrooms)) {
8933 // assign this new option to the requested rooms
8934 foreach ($pidrooms as $idroom) {
8935 if (empty($idroom)) {
8936 continue;
8937 }
8938 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
8939 $dbo->setQuery($q);
8940 $dbo->execute();
8941 if (!$dbo->getNumRows()) {
8942 continue;
8943 }
8944 $room_data = $dbo->loadAssoc();
8945 array_push($rooms_with_opt, $room_data['id']);
8946 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
8947 if (in_array((string)$pwhereup, $current_opts)) {
8948 continue;
8949 }
8950 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
8951 // make sure we do not concatenate a real ID to 0
8952 $current_opts = array();
8953 }
8954 array_push($current_opts, $pwhereup);
8955 $new_opts = implode(';', $current_opts) . ';';
8956 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
8957 $dbo->setQuery($q);
8958 $dbo->execute();
8959 }
8960 }
8961 if (!count($rooms_with_opt)) {
8962 // get all rooms to unset this option (if previously set)
8963 array_push($rooms_with_opt, '0');
8964 }
8965 // unset the option from the other rooms that may have it
8966 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
8967 $dbo->setQuery($q);
8968 $dbo->execute();
8969 if ($dbo->getNumRows()) {
8970 $unset_rooms_opt = $dbo->loadAssocList();
8971 foreach ($unset_rooms_opt as $room_data) {
8972 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
8973 if (!in_array((string)$pwhereup, $current_opts)) {
8974 // this room is not using this option
8975 continue;
8976 }
8977 $optkey = array_search((string)$pwhereup, $current_opts);
8978 if ($optkey === false) {
8979 // key not found
8980 continue;
8981 }
8982 // unset this option ID from the string
8983 unset($current_opts[$optkey]);
8984 if (!count($current_opts)) {
8985 // a room with no options assigned will be listed as "0;"
8986 $current_opts = array(0);
8987 }
8988 $new_opts = implode(';', $current_opts) . ';';
8989 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
8990 $dbo->setQuery($q);
8991 $dbo->execute();
8992 }
8993 }
8994 //
8995
8996 }
8997 $app->redirect("index.php?option=com_vikbooking&task=" . ($stay ? 'editoptional&cid[]=' . $pwhereup : 'optionals'));
8998 }
8999
9000 public function createoptionals() {
9001 if (!JSession::checkToken()) {
9002 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9003 }
9004 $this->do_createoptionals();
9005 }
9006
9007 public function createoptionalsstay() {
9008 if (!JSession::checkToken()) {
9009 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9010 }
9011 $this->do_createoptionals(true);
9012 }
9013
9014 private function do_createoptionals($stay = false) {
9015 $dbo = JFactory::getDbo();
9016 $poptname = VikRequest::getString('optname', '', 'request');
9017 $poptdescr = VikRequest::getString('optdescr', '', 'request', VIKREQUEST_ALLOWHTML);
9018 $poptcost = VikRequest::getFloat('optcost', '', 'request');
9019 $poptperday = VikRequest::getString('optperday', '', 'request');
9020 $poptperperson = VikRequest::getString('optperperson', '', 'request');
9021 $pmaxprice = VikRequest::getFloat('maxprice', '', 'request');
9022 $popthmany = VikRequest::getString('opthmany', '', 'request');
9023 $poptaliq = VikRequest::getInt('optaliq', '', 'request');
9024 $pautoresize = VikRequest::getString('autoresize', '', 'request');
9025 $presizeto = VikRequest::getString('resizeto', '', 'request');
9026 $pifchildren = VikRequest::getString('ifchildren', '', 'request');
9027 $pifchildren = $pifchildren == "1" ? 1 : 0;
9028 $pmaxquant = VikRequest::getString('maxquant', '', 'request');
9029 $pmaxquant = empty($pmaxquant) ? 0 : intval($pmaxquant);
9030 $pforcesel = VikRequest::getString('forcesel', '', 'request');
9031 $pforceval = VikRequest::getString('forceval', '', 'request');
9032 $pforcevalperday = VikRequest::getString('forcevalperday', '', 'request');
9033 $pforcevalperchild = VikRequest::getString('forcevalperchild', '', 'request');
9034 $pforcesummary = VikRequest::getString('forcesummary', '', 'request');
9035 $pforcesel = $pforcesel == "1" ? 1 : 0;
9036 $pis_citytax = VikRequest::getString('is_citytax', '', 'request');
9037 $pis_fee = VikRequest::getString('is_fee', '', 'request');
9038 $pis_citytax = $pis_citytax == "1" && $pis_fee != "1" ? 1 : 0;
9039 $pis_fee = $pis_fee == "1" && $pis_citytax == 0 ? 1 : 0;
9040 $pagefrom = VikRequest::getVar('agefrom', array());
9041 $pageto = VikRequest::getVar('ageto', array());
9042 $pagecost = VikRequest::getVar('agecost', array());
9043 $pagectype = VikRequest::getVar('agectype', array());
9044 $palwaysav = VikRequest::getInt('alwaysav', 0, 'request');
9045 $pavfrom = VikRequest::getString('avfrom', '', 'request');
9046 $pavto = VikRequest::getString('avto', '', 'request');
9047 $ppcentroom = VikRequest::getInt('pcentroom', 0, 'request');
9048 $pidrooms = VikRequest::getVar('idrooms', array());
9049 $optavstr = empty($palwaysav) && !empty($pavfrom) && !empty($pavto) ? VikBooking::getDateTimestamp($pavfrom, 0, 0, 0).';'.VikBooking::getDateTimestamp($pavto, 23, 59, 59) : '';
9050 if ($pforcesel == 1) {
9051 $strforceval = intval($pforceval)."-".($pforcevalperday == "1" ? "1" : "0")."-".($pforcevalperchild == "1" ? "1" : "0")."-".($pforcesummary == "1" ? "1" : "0");
9052 } else {
9053 $strforceval = "";
9054 }
9055 $minguestsnum = VikRequest::getInt('minguestsnum', 0, 'request');
9056 $mingueststype = VikRequest::getString('mingueststype', 'guests', 'request');
9057 $minguestsnum = $minguestsnum < 0 ? 0 : $minguestsnum;
9058 $mingueststype = !empty($mingueststype) && !in_array($mingueststype, array('adults', 'guests')) ? 'guests' : $mingueststype;
9059 $maxguestsnum = VikRequest::getInt('maxguestsnum', 0, 'request');
9060 $maxgueststype = VikRequest::getString('maxgueststype', 'guests', 'request');
9061 $maxguestsnum = $maxguestsnum < 0 ? 0 : $maxguestsnum;
9062 $maxgueststype = !empty($maxgueststype) && !in_array($maxgueststype, array('adults', 'guests')) ? 'guests' : $maxgueststype;
9063 $minguests = VikRequest::getInt('minguests', 0, 'request');
9064 $minguests_conflict = false;
9065 if ($minguests > 0 && $minguestsnum > 0 && $maxguestsnum > 0) {
9066 if ($minguestsnum >= $maxguestsnum) {
9067 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL1');
9068 } elseif (($maxguestsnum - $minguestsnum) < 2) {
9069 $minguests_conflict = JText::translate('VBOMINMAXGUESTSOPTCONFL2');
9070 }
9071 }
9072 if (!$minguests || $minguests_conflict !== false) {
9073 $minguestsnum = 0;
9074 $maxguestsnum = 0;
9075 if ($minguests_conflict !== false) {
9076 // raise warning, but do not stop the process
9077 VikError::raiseWarning('', $minguests_conflict);
9078 }
9079 }
9080 $damagedep = VikRequest::getInt('damagedep', 0, 'request');
9081 $pet_fee = VikRequest::getInt('pet_fee', 0, 'request');
9082 $oparams = array(
9083 'minguestsnum' => $minguestsnum,
9084 'mingueststype' => $mingueststype,
9085 'maxguestsnum' => $maxguestsnum,
9086 'maxgueststype' => $maxgueststype,
9087 'damagedep' => $damagedep,
9088 'pet_fee' => $pet_fee,
9089 );
9090 if (!empty($poptname)) {
9091 if (intval($_FILES['optimg']['error']) == 0 && VikBooking::caniWrite(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR) && trim($_FILES['optimg']['name'])!="") {
9092 jimport('joomla.filesystem.file');
9093 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9094 if (@is_uploaded_file($_FILES['optimg']['tmp_name'])) {
9095 $safename=JFile::makeSafe(str_replace(" ", "_", strtolower($_FILES['optimg']['name'])));
9096 if (file_exists($updpath.$safename)) {
9097 $j = 1;
9098 while (file_exists($updpath.$j.$safename)) {
9099 $j++;
9100 }
9101 $pwhere = $updpath.$j.$safename;
9102 } else {
9103 $j = "";
9104 $pwhere = $updpath.$safename;
9105 }
9106 if (!getimagesize($_FILES['optimg']['tmp_name']) || !preg_match("/\.(a?png|jpe?g|bmp|gif|ico|webp)\z/i", $safename)) {
9107 @unlink($pwhere);
9108 $picon = "";
9109 } else {
9110 VikBooking::uploadFile($_FILES['optimg']['tmp_name'], $pwhere);
9111 @chmod($pwhere, 0644);
9112 $picon = $j.$safename;
9113 if ($pautoresize == "1" && !empty($presizeto)) {
9114 $eforj = new vikResizer();
9115 $origmod = $eforj->proportionalImage($pwhere, $updpath.'r_'.$j.$safename, $presizeto, $presizeto);
9116 if ($origmod) {
9117 @unlink($pwhere);
9118 $picon = 'r_'.$j.$safename;
9119 }
9120 }
9121 }
9122 } else {
9123 $picon = "";
9124 }
9125 } else {
9126 $picon = "";
9127 }
9128 $poptperday = ($poptperday == "each" ? "1" : "0");
9129 $poptperperson = ($poptperperson == "each" ? "1" : "0");
9130 ($popthmany == "yes" ? $popthmany = "1" : $popthmany = "0");
9131 $ageintervalstr = '';
9132 if ($pifchildren == 1 && count($pagefrom) > 0 && count($pagecost) > 0 && count($pagefrom) == count($pagecost)) {
9133 foreach ($pagefrom as $kage => $vage) {
9134 $afrom = intval($vage);
9135 $ato = intval($pageto[$kage]);
9136 $acost = floatval($pagecost[$kage]);
9137 if (strlen($vage) > 0 && strlen($pagecost[$kage]) > 0) {
9138 if ($ato < $afrom) $ato = $afrom;
9139 $ageintervalstr .= $afrom.'_'.$ato.'_'.$acost.(array_key_exists($kage, $pagectype) && strpos($pagectype[$kage], '%') !== false ? '_%'.(strpos($pagectype[$kage], '%b') !== false ? 'b' : '') : '').';;';
9140 }
9141 }
9142 $ageintervalstr = rtrim($ageintervalstr, ';;');
9143 if (!empty($ageintervalstr)) {
9144 $pforcesel = 1;
9145 }
9146 }
9147 $q = "SELECT `ordering` FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` DESC LIMIT 1;";
9148 $dbo->setQuery($q);
9149 $dbo->execute();
9150 if ($dbo->getNumRows() == 1) {
9151 $getlast = $dbo->loadResult();
9152 $newsortnum = $getlast + 1;
9153 } else {
9154 $newsortnum = 1;
9155 }
9156 $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)) . ");";
9157 $dbo->setQuery($q);
9158 $dbo->execute();
9159 $newoptid = $dbo->insertid();
9160
9161 if (!empty($newoptid)) {
9162 // assign/unset option-rooms relations
9163 $rooms_with_opt = array();
9164 if (count($pidrooms)) {
9165 // assign this new option to the requested rooms
9166 foreach ($pidrooms as $idroom) {
9167 if (empty($idroom)) {
9168 continue;
9169 }
9170 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id`=" . (int)$idroom . ";";
9171 $dbo->setQuery($q);
9172 $dbo->execute();
9173 if (!$dbo->getNumRows()) {
9174 continue;
9175 }
9176 $room_data = $dbo->loadAssoc();
9177 array_push($rooms_with_opt, $room_data['id']);
9178 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9179 if (in_array((string)$newoptid, $current_opts)) {
9180 continue;
9181 }
9182 if (count($current_opts) === 1 && (string)$current_opts[0] == '0') {
9183 // make sure we do not concatenate a real ID to 0
9184 $current_opts = array();
9185 }
9186 array_push($current_opts, $newoptid);
9187 $new_opts = implode(';', $current_opts) . ';';
9188 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9189 $dbo->setQuery($q);
9190 $dbo->execute();
9191 }
9192 }
9193 if (!count($rooms_with_opt)) {
9194 // get all rooms to unset this option (if previously set)
9195 array_push($rooms_with_opt, '0');
9196 }
9197 // unset the option from the other rooms that may have it
9198 $q = "SELECT `id`, `idopt` FROM `#__vikbooking_rooms` WHERE `id` NOT IN (" . implode(', ', $rooms_with_opt) . ");";
9199 $dbo->setQuery($q);
9200 $dbo->execute();
9201 if ($dbo->getNumRows()) {
9202 $unset_rooms_opt = $dbo->loadAssocList();
9203 foreach ($unset_rooms_opt as $room_data) {
9204 $current_opts = empty($room_data['idopt']) ? array() : explode(';', rtrim($room_data['idopt'], ';'));
9205 if (!in_array((string)$newoptid, $current_opts)) {
9206 // this room is not using this option
9207 continue;
9208 }
9209 $optkey = array_search((string)$newoptid, $current_opts);
9210 if ($optkey === false) {
9211 // key not found
9212 continue;
9213 }
9214 // unset this option ID from the string
9215 unset($current_opts[$optkey]);
9216 if (!count($current_opts)) {
9217 // a room with no options assigned will be listed as "0;"
9218 $current_opts = array(0);
9219 }
9220 $new_opts = implode(';', $current_opts) . ';';
9221 $q = "UPDATE `#__vikbooking_rooms` SET `idopt`=" . $dbo->quote($new_opts) . " WHERE `id`={$room_data['id']};";
9222 $dbo->setQuery($q);
9223 $dbo->execute();
9224 }
9225 }
9226 //
9227 }
9228
9229 }
9230 $mainframe = JFactory::getApplication();
9231 $mainframe->redirect("index.php?option=com_vikbooking&task=" . ($stay && isset($newoptid) && !empty($newoptid) ? 'editoptional&cid[]=' . $newoptid : 'optionals'));
9232 }
9233
9234 public function removeoptionals() {
9235 if (!JSession::checkToken()) {
9236 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
9237 }
9238 $ids = VikRequest::getVar('cid', array(0));
9239 if (@count($ids)) {
9240 $dbo = JFactory::getDbo();
9241 foreach ($ids as $d) {
9242 $q = "SELECT `img` FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9243 $dbo->setQuery($q);
9244 $dbo->execute();
9245 if ($dbo->getNumRows() == 1) {
9246 $rows = $dbo->loadAssocList();
9247 if (!empty($rows[0]['img']) && file_exists(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img'])) {
9248 @unlink(VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR.$rows[0]['img']);
9249 }
9250 }
9251 $q = "DELETE FROM `#__vikbooking_optionals` WHERE `id`=".$dbo->quote($d).";";
9252 $dbo->setQuery($q);
9253 $dbo->execute();
9254 }
9255 }
9256 $mainframe = JFactory::getApplication();
9257 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
9258 }
9259
9260 public function sendcustomsms() {
9261 $mainframe = JFactory::getApplication();
9262 $pphone = VikRequest::getString('phone', '', 'request');
9263 $psmscont = VikRequest::getString('smscont', '', 'request');
9264 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9265 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9266 if (!empty($pphone) && !empty($psmscont)) {
9267 $sms_api = VikBooking::getSMSAPIClass();
9268 $sms_api_params = VikBooking::getSMSParams();
9269 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
9270 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9271 $sms_obj = new VikSmsApi(array(), $sms_api_params);
9272 $response_obj = $sms_obj->sendMessage($pphone, $psmscont);
9273 if ( !$sms_obj->validateResponse($response_obj) ) {
9274 VikError::raiseWarning('', $sms_obj->getLog());
9275 } else {
9276 $mainframe->enqueueMessage(JText::translate('VBSENDSMSOK'));
9277 }
9278 } else {
9279 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSAPI'));
9280 }
9281 } else {
9282 VikError::raiseWarning('', JText::translate('VBSENDSMSERRMISSDATA'));
9283 }
9284 $mainframe->redirect($pgoto);
9285 }
9286
9287 public function sendcustomemail() {
9288 $dbo = JFactory::getDbo();
9289 $mainframe = JFactory::getApplication();
9290 $vbo_tn = VikBooking::getTranslator();
9291 $pbid = VikRequest::getInt('bid', '', 'request');
9292 $pemailsubj = VikRequest::getString('emailsubj', '', 'request');
9293 $pemail = VikRequest::getString('email', '', 'request');
9294 $pemailcont = VikRequest::getString('emailcont', '', 'request', VIKREQUEST_ALLOWRAW);
9295 $pemailfrom = VikRequest::getString('emailfrom', '', 'request');
9296 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
9297 $pgoto = !empty($pgoto) ? urldecode($pgoto) : 'index.php?option=com_vikbooking';
9298 if (!empty($pemail) && !empty($pemailcont)) {
9299 $email_attach = null;
9300 jimport('joomla.filesystem.file');
9301 $pemailattch = VikRequest::getVar('emailattch', null, 'files', 'array');
9302 if (isset($pemailattch) && strlen(trim($pemailattch['name']))) {
9303 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($pemailattch['name'])));
9304 $src = $pemailattch['tmp_name'];
9305 $dest = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9306 $j = "";
9307 if (file_exists($dest.$filename)) {
9308 $j = rand(171, 1717);
9309 while (file_exists($dest.$j.$filename)) {
9310 $j++;
9311 }
9312 }
9313 $finaldest = $dest.$j.$filename;
9314 if (VikBooking::uploadFile($src, $finaldest)) {
9315 $email_attach = $finaldest;
9316 } else {
9317 VikError::raiseWarning('', 'Error uploading the attachment. Email not sent.');
9318 $mainframe->redirect($pgoto);
9319 exit;
9320 }
9321 }
9322 //VBO 1.10 - special tags for the custom email template files and messages
9323 $orig_mail_cont = $pemailcont;
9324 if (strpos($pemailcont, '{') !== false && strpos($pemailcont, '}') !== false) {
9325 // replace any possible placeholder for special tags
9326 $pemailcont = preg_replace_callback("/(<strong class=\"vbo-editor-hl-specialtag\">)([^<]+)(<\/strong>)/", function($match) {
9327 return $match[2];
9328 }, $pemailcont);
9329
9330 $booking = array();
9331 $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.";";
9332 $dbo->setQuery($q);
9333 $dbo->execute();
9334 if ($dbo->getNumRows() > 0) {
9335 $booking = $dbo->loadAssoc();
9336 }
9337 $booking_rooms = array();
9338 $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.";";
9339 $dbo->setQuery($q);
9340 $dbo->execute();
9341 if ($dbo->getNumRows() > 0) {
9342 $booking_rooms = $dbo->loadAssocList();
9343 if (!empty($booking['lang'])) {
9344 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $booking['lang']);
9345 }
9346 }
9347 //we use the same parsing function as the one for the Customer SMS Template
9348 $pemailcont = VikBooking::parseCustomerSMSTemplate($booking, $booking_rooms, null, $pemailcont);
9349 }
9350 //
9351 // allow the use of token {booking_id} in subject
9352 $pemailsubj = str_replace('{booking_id}', $pbid, $pemailsubj);
9353 //
9354 $is_html = (strpos($pemailcont, '<') !== false && strpos($pemailcont, '>') !== false);
9355 $pemailcont = $is_html ? nl2br($pemailcont) : $pemailcont;
9356 $vbo_app = VikBooking::getVboApplication();
9357 $vbo_app->sendMail($pemailfrom, $pemailfrom, $pemail, $pemailfrom, $pemailsubj, $pemailcont, $is_html, 'base64', $email_attach);
9358 $mainframe->enqueueMessage(JText::translate('VBSENDEMAILOK'));
9359 if ($email_attach !== null) {
9360 @unlink($email_attach);
9361 }
9362 //Booking History
9363 VikBooking::getBookingHistoryInstance()->setBid($pbid)->store('CE', nl2br($pemailsubj . "\n\n" . $pemailcont));
9364 //
9365 //Save email template for future sending
9366 $config_rec_exists = false;
9367 $emtpl = array(
9368 'emailsubj' => $pemailsubj,
9369 'emailcont' => $orig_mail_cont,
9370 'emailfrom' => $pemailfrom
9371 );
9372 $cur_emtpl = array();
9373 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9374 $dbo->setQuery($q);
9375 $dbo->execute();
9376 if ($dbo->getNumRows() > 0) {
9377 $config_rec_exists = true;
9378 $cur_emtpl = $dbo->loadResult();
9379 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9380 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9381 }
9382 if (count($cur_emtpl) > 0) {
9383 $existing_subj = false;
9384 foreach ($cur_emtpl as $emk => $emv) {
9385 if (array_key_exists('emailsubj', $emv) && $emv['emailsubj'] == $emtpl['emailsubj']) {
9386 $cur_emtpl[$emk] = $emtpl;
9387 $existing_subj = true;
9388 break;
9389 }
9390 }
9391 if ($existing_subj === false) {
9392 $cur_emtpl[] = $emtpl;
9393 }
9394 } else {
9395 $cur_emtpl[] = $emtpl;
9396 }
9397 if (count($cur_emtpl) > 10) {
9398 //Max 10 templates to avoid problems with the size of the field and truncated json strings
9399 $exceed = count($cur_emtpl) - 10;
9400 for ($tl=0; $tl < $exceed; $tl++) {
9401 unset($cur_emtpl[$tl]);
9402 }
9403 $cur_emtpl = array_values($cur_emtpl);
9404 }
9405 if ($config_rec_exists === true) {
9406 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9407 $dbo->setQuery($q);
9408 $dbo->execute();
9409 } else {
9410 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('customemailtpls', ".$dbo->quote(json_encode($cur_emtpl)).");";
9411 $dbo->setQuery($q);
9412 $dbo->execute();
9413 }
9414 //
9415 } else {
9416 VikError::raiseWarning('', JText::translate('VBSENDEMAILERRMISSDATA'));
9417 }
9418 $mainframe->redirect($pgoto);
9419 }
9420
9421 public function rmcustomemailtpl() {
9422 $cid = VikRequest::getVar('cid', array(0));
9423 $oid = $cid[0];
9424 $dbo = JFactory::getDBO();
9425 $mainframe = JFactory::getApplication();
9426 $tplind = VikRequest::getInt('tplind', '', 'request');
9427 if (empty($oid) || !(strlen($tplind) > 0)) {
9428 VikError::raiseWarning('', 'Missing Data.');
9429 $mainframe->redirect('index.php?option=com_vikbooking');
9430 exit;
9431 }
9432 $cur_emtpl = array();
9433 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='customemailtpls';";
9434 $dbo->setQuery($q);
9435 $dbo->execute();
9436 if ($dbo->getNumRows() > 0) {
9437 $cur_emtpl = $dbo->loadResult();
9438 $cur_emtpl = empty($cur_emtpl) ? array() : json_decode($cur_emtpl, true);
9439 $cur_emtpl = is_array($cur_emtpl) ? $cur_emtpl : array();
9440 } else {
9441 VikError::raiseWarning('', 'Missing Templates Record.');
9442 $mainframe->redirect('index.php?option=com_vikbooking');
9443 exit;
9444 }
9445 if (array_key_exists($tplind, $cur_emtpl)) {
9446 unset($cur_emtpl[$tplind]);
9447 $cur_emtpl = count($cur_emtpl) > 0 ? array_values($cur_emtpl) : array();
9448 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($cur_emtpl))." WHERE `param`='customemailtpls';";
9449 $dbo->setQuery($q);
9450 $dbo->execute();
9451 }
9452 $mainframe->redirect('index.php?option=com_vikbooking&task=editorder&cid[]='.$oid.'&customemail=1');
9453 exit;
9454 }
9455
9456 public function exportcustomers() {
9457 //we do not set the menu for this view
9458
9459 VikRequest::setVar('view', VikRequest::getCmd('view', 'exportcustomers'));
9460
9461 parent::display();
9462
9463 if (VikBooking::showFooter()) {
9464 VikBookingHelper::printFooter();
9465 }
9466 }
9467
9468 public function csvexportprepare() {
9469 //modal box, so we do not set menu or footer
9470
9471 VikRequest::setVar('view', VikRequest::getCmd('view', 'csvexportprepare'));
9472
9473 parent::display();
9474 }
9475
9476 public function icsexportprepare() {
9477 //modal box, so we do not set menu or footer
9478
9479 VikRequest::setVar('view', VikRequest::getCmd('view', 'icsexportprepare'));
9480
9481 parent::display();
9482 }
9483
9484 public function bookingcheckin() {
9485 //modal box, so we do not set menu or footer
9486
9487 VikRequest::setVar('view', VikRequest::getCmd('view', 'bookingcheckin'));
9488
9489 parent::display();
9490 }
9491
9492 public function gencheckindoc() {
9493 //modal box, so we do not set menu or footer
9494
9495 VikRequest::setVar('view', VikRequest::getCmd('view', 'gencheckindoc'));
9496
9497 parent::display();
9498 }
9499
9500 public function checkversion() {
9501 //to be called via ajax
9502 $params = new stdClass;
9503 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9504 $params->alias = 'com_vikbooking';
9505
9506 $result = array();
9507
9508 if (!count($result)) {
9509 $result = new stdClass;
9510 $result->status = 0;
9511 } else {
9512 $result = $result[0];
9513 }
9514
9515 echo json_encode($result);
9516 exit;
9517 }
9518
9519 public function updateprogram() {
9520 $params = new stdClass;
9521 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9522 $params->alias = 'com_vikbooking';
9523
9524 $result = array();
9525
9526 if (!count($result) || !$result[0]) {
9527 if (class_exists('JEventDispatcher')) {
9528 $dispatcher = JEventDispatcher::getInstance();
9529 $result = $dispatcher->trigger('checkVersion', array(&$params));
9530 } else {
9531 $app = JFactory::getApplication();
9532 if (method_exists($app, 'triggerEvent')) {
9533 $result = $app->triggerEvent('checkVersion', array(&$params));
9534 }
9535 }
9536 }
9537
9538 if (!count($result) || !$result[0]->status || !$result[0]->response->status) {
9539 exit('Error, plugin disabled');
9540 }
9541
9542 JToolbarHelper::title(JText::translate('VBMAINTITLEUPDATEPROGRAM'));
9543
9544 VikBookingHelper::pUpdateProgram($result[0]->response);
9545 }
9546
9547 public function updateprogramlaunch() {
9548 $params = new stdClass;
9549 $params->version = VIKBOOKING_SOFTWARE_VERSION;
9550 $params->alias = 'com_vikbooking';
9551
9552 $json = new stdClass;
9553 $json->status = false;
9554
9555 echo json_encode($json);
9556 exit;
9557 }
9558
9559 public function invoke_vcm()
9560 {
9561 $app = JFactory::getApplication();
9562
9563 $oids = VikRequest::getVar('cid', []);
9564 $sync_type = VikRequest::getString('stype', 'new', 'request');
9565 $sync_type = !in_array($sync_type, ['new', 'modify', 'cancel']) ? 'new' : $sync_type;
9566 $original_booking_js = VikRequest::getString('origb', '', 'request', VIKREQUEST_ALLOWRAW);
9567 $return_url = VikRequest::getString('returl', '', 'request', VIKREQUEST_ALLOWRAW);
9568 $return_url = !empty($return_url) ? urldecode($return_url) : $return_url;
9569
9570 if (!$oids || !is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
9571 $app->redirect("index.php?option=com_vikbooking&task=orders");
9572 $app->close();
9573 }
9574
9575 $result = VikBooking::getVcmInvoker()
9576 ->setOids($oids)
9577 ->setSyncType($sync_type)
9578 ->setOriginalBooking($original_booking_js, true)
9579 ->doSync();
9580
9581 if ($result === true) {
9582 $app->enqueueMessage(JText::translate('VBCHANNELMANAGERRESULTOK'));
9583 } else {
9584 VikError::raiseWarning('', JText::translate('VBCHANNELMANAGERRESULTKO').' <a href="index.php?option=com_vikchannelmanager" target="_blank">'.JText::translate('VBCHANNELMANAGEROPEN').'</a>');
9585 }
9586
9587 if (!empty($return_url)) {
9588 $app->redirect($return_url);
9589 } else {
9590 $app->redirect("index.php?option=com_vikbooking&task=orders");
9591 }
9592
9593 $app->close();
9594 }
9595
9596 public function multiphotosupload() {
9597 jimport('joomla.filesystem.file');
9598
9599 $dbo = JFactory::getDBO();
9600 $proomid = VikRequest::getInt('roomid', '', 'request');
9601
9602 $resp = array('files' => array());
9603 $error_messages = array(
9604 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
9605 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
9606 3 => 'The uploaded file was only partially uploaded',
9607 4 => 'No file was uploaded',
9608 6 => 'Missing a temporary folder',
9609 7 => 'Failed to write file to disk',
9610 8 => 'A PHP extension stopped the file upload',
9611 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
9612 'max_file_size' => 'File is too big',
9613 'min_file_size' => 'File is too small',
9614 'accept_file_types' => 'Filetype not allowed',
9615 'max_number_of_files' => 'Maximum number of files exceeded',
9616 'max_width' => 'Image exceeds maximum width',
9617 'min_width' => 'Image requires a minimum width',
9618 'max_height' => 'Image exceeds maximum height',
9619 'min_height' => 'Image requires a minimum height',
9620 'abort' => 'File upload aborted',
9621 'image_resize' => 'Failed to resize image',
9622 'vbo_type' => 'The file type cannot be accepted',
9623 'vbo_jupload' => 'The upload has failed. Check the Joomla Configuration',
9624 'vbo_perm' => 'Error moving the uploaded files. Check your permissions'
9625 );
9626
9627 $creativik = new vikResizer();
9628 $updpath = VBO_SITE_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'uploads'.DIRECTORY_SEPARATOR;
9629 $bigsdest = $updpath;
9630 $thumbsdest = $updpath;
9631 $dest = $updpath;
9632 $moreimagestr = '';
9633 $cur_captions = json_encode(array());
9634
9635 $q = "SELECT `moreimgs`,`imgcaptions` FROM `#__vikbooking_rooms` WHERE `id`=".$proomid.";";
9636 $dbo->setQuery($q);
9637 $dbo->execute();
9638 if ($dbo->getNumRows() == 1) {
9639 $photo_data = $dbo->loadAssocList();
9640 $cur_captions = $photo_data[0]['imgcaptions'];
9641 $cur_photos = $photo_data[0]['moreimgs'];
9642 if (!empty($cur_photos)) {
9643 $moreimagestr .= $cur_photos;
9644 }
9645 }
9646
9647 $bulkphotos = VikRequest::getVar('bulkphotos', null, 'files', 'array');
9648
9649 if (is_array($bulkphotos) && count($bulkphotos) > 0 && array_key_exists('name', $bulkphotos) && count($bulkphotos['name']) > 0) {
9650 foreach ($bulkphotos['name'] as $updk => $photoname) {
9651 $uploaded_image = array();
9652 $filename = JFile::makeSafe(str_replace(" ", "_", strtolower($photoname)));
9653 $src = $bulkphotos['tmp_name'][$updk];
9654 $j = "";
9655 if (file_exists($dest.$filename)) {
9656 $j = rand(171, 1717);
9657 while (file_exists($dest.$j.$filename)) {
9658 $j++;
9659 }
9660 }
9661 $finaldest=$dest.$j.$filename;
9662 $is_error = false;
9663 $err_key = '';
9664 if (array_key_exists('error', $bulkphotos) && array_key_exists($updk, $bulkphotos['error']) && !empty($bulkphotos['error'][$updk])) {
9665 if (array_key_exists($bulkphotos['error'][$updk], $error_messages)) {
9666 $is_error = true;
9667 $err_key = $bulkphotos['error'][$updk];
9668 }
9669 }
9670 if (!$is_error) {
9671 $check = getimagesize($bulkphotos['tmp_name'][$updk]);
9672 if ($check[2] & imagetypes()) {
9673 if (VikBooking::uploadFile($src, $finaldest)) {
9674 $gimg = $j.$filename;
9675 //orig img
9676 $origmod = true;
9677 VikBooking::uploadFile($finaldest, $bigsdest.'big_'.$j.$filename, true);
9678 //thumb
9679 $thumbsize = VikBooking::getThumbSize();
9680 $thumb = $creativik->proportionalImage($finaldest, $thumbsdest.'thumb_'.$j.$filename, $thumbsize, $thumbsize);
9681 if (!$thumb || !$origmod) {
9682 if (file_exists($bigsdest.'big_'.$j.$filename)) @unlink($bigsdest.'big_'.$j.$filename);
9683 if (file_exists($thumbsdest.'thumb_'.$j.$filename)) @unlink($thumbsdest.'thumb_'.$j.$filename);
9684 $is_error = true;
9685 $err_key = 'vbo_perm';
9686 } else {
9687 $moreimagestr.=$j.$filename.";;";
9688 }
9689 @unlink($finaldest);
9690 } else {
9691 $is_error = true;
9692 $err_key = 'vbo_jupload';
9693 }
9694 } else {
9695 $is_error = true;
9696 $err_key = 'vbo_type';
9697 }
9698 }
9699 $img = new stdClass();
9700 if ($is_error) {
9701 $img->name = '';
9702 $img->size = '';
9703 $img->type = '';
9704 $img->url = '';
9705 $img->error = array_key_exists($err_key, $error_messages) ? $error_messages[$err_key] : 'Generic Error for Upload';
9706 } else {
9707 $img->name = $photoname;
9708 $img->size = $bulkphotos['size'][$updk];
9709 $img->type = $bulkphotos['type'][$updk];
9710 $img->url = VBO_SITE_URI.'resources/uploads/big_'.$j.$filename;
9711 }
9712 $resp['files'][] = $img;
9713 }
9714 } else {
9715 $res = new stdClass();
9716 $res->name = '';
9717 $res->size = '';
9718 $res->type = '';
9719 $res->url = '';
9720 $res->error = 'No images received for upload';
9721 $resp['files'][] = $res;
9722 }
9723 //Update current extra images string
9724 $q = "UPDATE `#__vikbooking_rooms` SET `moreimgs`=".$dbo->quote($moreimagestr)." WHERE `id`=".$proomid.";";
9725 $dbo->setQuery($q);
9726 $dbo->execute();
9727 $resp['actmoreimgs'] = $moreimagestr;
9728 //Update current extra images uploaded
9729 $cur_thumbs = '';
9730 $morei=explode(';;', $moreimagestr);
9731 if (@count($morei) > 0) {
9732 $imgcaptions = json_decode($cur_captions, true);
9733 $usecaptions = empty($imgcaptions) || is_null($imgcaptions) || !is_array($imgcaptions) || !(count($imgcaptions) > 0) ? false : true;
9734 $cur_thumbs .= '<ul class="vbo-sortable">';
9735 foreach ($morei as $ki => $mi) {
9736 if (!empty($mi)) {
9737 $cur_thumbs .= '<li class="vbo-editroom-currentphoto">';
9738 $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>';
9739 $cur_thumbs .= '<a class="vbo-toggle-imgcaption" href="javascript: void(0);" onclick="vbOpenImgDetails(\''.$ki.'\', this)"><i class="'.VikBookingIcons::i('cog').'"></i></a>';
9740 $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>';
9741 $cur_thumbs .= '</li>';
9742 }
9743 }
9744 $cur_thumbs .= '</ul>';
9745 $cur_thumbs .= '<br clear="all"/>';
9746 }
9747 $resp['currentthumbs'] = $cur_thumbs;
9748
9749 echo json_encode($resp);
9750 exit;
9751 }
9752
9753 public function loadsmsbalance() {
9754 //to be called via ajax
9755 $html = 'Error1 [N/A]';
9756 $sms_api = VikBooking::getSMSAPIClass();
9757 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api)) {
9758 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
9759 $sms_obj = new VikSmsApi(array(), VikBooking::getSMSParams());
9760 if (method_exists('VikSmsApi', 'estimate')) {
9761 $array_result = $sms_obj->estimate("+393711271611", "estimate credit");
9762 if ( $array_result->errorCode != 0 ) {
9763 $html = 'Error3 ['.$array_result->errorMsg.']';
9764 } else {
9765 $html = VikBooking::getCurrencySymb().' '.$array_result->userCredit;
9766 }
9767 } else {
9768 $html = 'Error2 [N/A]';
9769 }
9770 }
9771 echo $html;
9772 exit;
9773 }
9774
9775 public function loadsmsparams() {
9776 //to be called via ajax
9777 $html = '---------';
9778 $phpfile = VikRequest::getString('phpfile', '', 'request');
9779 if (!empty($phpfile)) {
9780 $sms_api = VikBooking::getSMSAPIClass();
9781 $sms_params = $sms_api == $phpfile ? VikBooking::getSMSParams(false) : '';
9782 $html = VikBooking::displaySMSParameters($phpfile, $sms_params);
9783 }
9784 echo $html;
9785 exit;
9786 }
9787
9788 public function loadcronparams() {
9789 //to be called via ajax
9790 $html = '---------';
9791 $phpfile = VikRequest::getString('phpfile', '', 'request');
9792 if (!empty($phpfile)) {
9793 $html = VikBooking::displayCronParameters($phpfile);
9794 }
9795 echo $html;
9796 exit;
9797 }
9798
9799 public function loadpaymentparams() {
9800 //to be called via ajax
9801 $html = '<p>---------</p>';
9802 $phpfile = VikRequest::getString('phpfile', '', 'request');
9803 if (!empty($phpfile)) {
9804 $html = VikBooking::displayPaymentParameters($phpfile);
9805 }
9806 echo $html;
9807 exit;
9808 }
9809
9810 public function setbookingtag() {
9811 //to be called via ajax
9812 $dbo = JFactory::getDBO();
9813 $pidorder = VikRequest::getInt('idorder', '', 'request');
9814 $ptagkey = VikRequest::getInt('tagkey', '', 'request');
9815 if (!empty($pidorder) && $ptagkey >= 0) {
9816 $all_tags = VikBooking::loadBookingsColorTags();
9817 if (array_key_exists($ptagkey, $all_tags)) {
9818 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`=".(int)$pidorder.";";
9819 $dbo->setQuery($q);
9820 $dbo->execute();
9821 if ($dbo->getNumRows() > 0) {
9822 $newcolortag = json_encode($all_tags[$ptagkey]);
9823 $q = "UPDATE `#__vikbooking_orders` SET `colortag`=".$dbo->quote($newcolortag)." WHERE `id`=".(int)$pidorder.";";
9824 $dbo->setQuery($q);
9825 $dbo->execute();
9826 $newcolortag = $all_tags[$ptagkey];
9827 $newcolortag['name'] = JText::translate($newcolortag['name']);
9828 $newcolortag['fontcolor'] = VikBooking::getBestColorContrast($newcolortag['color']);
9829 echo json_encode($newcolortag);
9830 } else {
9831 echo 'e4j.error.Booking ('.$pidorder.') not found';
9832 }
9833 } else {
9834 echo 'e4j.error.Color Tag ('.$ptagkey.') not found';
9835 }
9836 } else {
9837 echo 'e4j.error.Missing Data';
9838 }
9839 exit;
9840 }
9841
9842 public function updatereceiptnum() {
9843 //to be called via ajax
9844 $pnewnum = VikRequest::getInt('newnum', '', 'request');
9845 $pnewnotes = VikRequest::getString('newnotes', '', 'request', VIKREQUEST_ALLOWRAW);
9846 $poid = VikRequest::getInt('oid', '', 'request');
9847 if ($pnewnum > 0) {
9848 VikBooking::getNextReceiptNumber($poid, $pnewnum);
9849 VikBooking::getReceiptNotes($pnewnotes);
9850 //Booking History
9851 VikBooking::getBookingHistoryInstance()->setBid($poid)->store('BR', JText::translate('VBOFISCRECEIPTNUM').': '.$pnewnum);
9852 //
9853 echo 'e4j.ok';
9854 exit;
9855 }
9856 echo 'e4j.error';
9857 exit;
9858 }
9859
9860 public function isroombookable() {
9861 //to be called via ajax
9862 $dbo = JFactory::getDBO();
9863 $res = array(
9864 'status' => 0,
9865 'err' => ''
9866 );
9867 $prid = VikRequest::getInt('rid', '', 'request');
9868 $pfdate = VikRequest::getString('fdate', '', 'request');
9869 $ptdate = VikRequest::getString('tdate', '', 'request');
9870 $room_info = array();
9871 $q = "SELECT * FROM `#__vikbooking_rooms` WHERE `id`=".(int)$prid.";";
9872 $dbo->setQuery($q);
9873 $dbo->execute();
9874 if ($dbo->getNumRows() > 0) {
9875 $room_info = $dbo->loadAssoc();
9876 }
9877 $pcheckinh = 0;
9878 $pcheckinm = 0;
9879 $pcheckouth = 0;
9880 $pcheckoutm = 0;
9881 $timeopst = VikBooking::getTimeOpenStore();
9882 if (is_array($timeopst)) {
9883 $opent = VikBooking::getHoursMinutes($timeopst[0]);
9884 $closet = VikBooking::getHoursMinutes($timeopst[1]);
9885 $pcheckinh = $opent[0];
9886 $pcheckinm = $opent[1];
9887 $pcheckouth = $closet[0];
9888 $pcheckoutm = $closet[1];
9889 }
9890 $from_ts = VikBooking::getDateTimestamp($pfdate, $pcheckinh, $pcheckinm);
9891 $to_ts = VikBooking::getDateTimestamp($ptdate, $pcheckouth, $pcheckoutm);
9892 if (
9893 count($room_info) > 0 &&
9894 (!empty($pfdate) && !empty($ptdate) && !empty($from_ts) && !empty($to_ts)) &&
9895 VikBooking::roomBookable($room_info['id'], $room_info['units'], $from_ts, $to_ts))
9896 {
9897 $res['status'] = 1;
9898 } else {
9899 if (!(count($room_info) > 0)) {
9900 $res['err'] = 'Room not found';
9901 } elseif (empty($pfdate) || empty($ptdate) || empty($from_ts) || empty($to_ts)) {
9902 $res['err'] = 'Invalid dates';
9903 } else {
9904 //not available
9905 $res['err'] = JText::sprintf('VBOBOOKADDROOMERR', $room_info['name'], $pfdate, $ptdate);
9906 }
9907 }
9908
9909 echo json_encode($res);
9910 exit;
9911 }
9912
9913 public function uploadsnapshot() {
9914 $snap_base_path = VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'idscans';
9915 /**
9916 * We no longer access the uploaded file from php://input, we now retrieve it as a regular file upload.
9917 * The old snapshot collection script with Flash no longer works in 2021.
9918 *
9919 * @since 1.14 (J) - 1.4.0 (WP)
9920 */
9921 $result = null;
9922 try {
9923 $result = VikBooking::uploadFileFromRequest(VikRequest::getVar('snapshot', null, 'files', 'array'), $snap_base_path);
9924 } catch (RuntimeException $e) {
9925 echo "e4j.error.Error " . $e->getMessage();
9926 exit;
9927 }
9928
9929 if (!is_object($result)) {
9930 echo "e4j.error.Invalid upload response";
9931 exit;
9932 }
9933
9934 echo $result->filename;
9935 exit;
9936 }
9937
9938 public function checkvcmrateschanges() {
9939 //to be called via ajax
9940 $session = JFactory::getSession();
9941 $ret = array('changesCount' => 0, 'changesData' => '');
9942 $updforvcm = $session->get('vbVcmRatesUpd', '');
9943 if (!empty($updforvcm) && is_array($updforvcm) && count($updforvcm) > 0) {
9944 $ret['changesCount'] = $updforvcm['count'];
9945 $ret['changesData'] = $updforvcm;
9946 }
9947
9948 echo json_encode($ret);
9949 exit;
9950 }
9951
9952 /**
9953 * AJAX endpoint to load the details of one or more bookings.
9954 *
9955 * @return void
9956 *
9957 * @since 1.16.0 (J) - 1.6.0 (WP) the method was refactored.
9958 */
9959 public function getbookingsinfo()
9960 {
9961 //to be called via ajax
9962 $dbo = JFactory::getDbo();
9963
9964 $booking_infos = [];
9965 $bookings = [];
9966
9967 $pidorders = VikRequest::getString('idorders', '', 'request');
9968 $psubroom = VikRequest::getString('subroom', '', 'request');
9969 $pstatus = VikRequest::getString('status', '', 'request');
9970 $pstay_date = VikRequest::getString('stay_date', '', 'request');
9971 $pidroom = VikRequest::getInt('idroom', 0, 'request');
9972 $psharedcal = VikRequest::getInt('sharedcal', 0, 'request');
9973
9974 if (!empty($pidorders)) {
9975 $bookings = explode(',', $pidorders);
9976 foreach ($bookings as $k => $v) {
9977 $v = intval(str_replace('-', '', $v));
9978 if (empty($v)) {
9979 unset($bookings[$k]);
9980 continue;
9981 }
9982 $bookings[$k] = $v;
9983 }
9984 }
9985 $bookings = array_values($bookings);
9986
9987 if (!$bookings) {
9988 /**
9989 * AJAX requests made by the page availability overview may contain empty booking IDs
9990 * due to SQL errors that only occupied the room, but could not save the booking record.
9991 * Clean up busy records where the busy relations contain empty booking IDs.
9992 *
9993 * @since 1.14 (J) - 1.4.0 (WP)
9994 */
9995 $hanging_busy_ids = [];
9996
9997 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
9998 $dbo->setQuery($q);
9999 $removelist = $dbo->loadAssocList();
10000 if ($removelist) {
10001 foreach ($removelist as $hanging_busy) {
10002 $hanging_busy_id = (int)$hanging_busy['idbusy'];
10003 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10004 array_push($hanging_busy_ids, $hanging_busy_id);
10005 }
10006 }
10007 }
10008
10009 // let's check also for ghost records that only occupy the room
10010 $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);";
10011 $dbo->setQuery($q);
10012 $removelist = $dbo->loadAssocList();
10013 if ($removelist) {
10014 foreach ($removelist as $hanging_busy) {
10015 $hanging_busy_id = (int)$hanging_busy['id'];
10016 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
10017 array_push($hanging_busy_ids, $hanging_busy_id);
10018 }
10019 }
10020 }
10021
10022 if ($hanging_busy_ids) {
10023 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
10024 $dbo->setQuery($q);
10025 $dbo->execute();
10026 }
10027 //
10028
10029 // output the error
10030 VBOHttpDocument::getInstance()->close(500, '1 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10031 }
10032
10033 $nowdf = VikBooking::getDateFormat(true);
10034 if ($nowdf == "%d/%m/%Y") {
10035 $df = 'd/m/Y';
10036 } elseif ($nowdf == "%m/%d/%Y") {
10037 $df = 'm/d/Y';
10038 } else {
10039 $df = 'Y/m/d';
10040 }
10041 $datesep = VikBooking::getDateSeparator(true);
10042 $currencysymb = VikBooking::getCurrencySymb();
10043 $current_y = date('Y');
10044 $current_ts = time();
10045 $short_meal_enums = VBOMealplanManager::getInstance()->getShortMealPlans();
10046
10047 $query = $dbo->getQuery(true);
10048 $query->select('o.*');
10049 $query->from($dbo->qn('#__vikbooking_orders', 'o'));
10050 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10051 // include the requested booking IDs and the cancelled reservations for this stay date
10052 $stay_date_info = getdate(strtotime($pstay_date));
10053 $lim_ts_to = mktime(23, 59, 59, $stay_date_info['mon'], $stay_date_info['mday'], $stay_date_info['year']);
10054 $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) . '))');
10055 // exclude the pending reservations
10056 $query->where($dbo->qn('o.status') . ' IN (' . $dbo->q('confirmed') . ', ' . $dbo->q('cancelled') . ')');
10057 } else {
10058 // include only the requested booking IDs
10059 $query->where($dbo->qn('o.id') . ' IN (' . implode(', ', $bookings) . ')');
10060 }
10061 if ($pstatus != 'any') {
10062 $query->where($dbo->qn('o.status') . ' != ' . $dbo->q('cancelled'));
10063 }
10064 if (!empty($pstay_date) && $pstatus == 'any') {
10065 // sort by confirmed status before cancelled status
10066 $query->order('CASE WHEN ' . $dbo->qn('o.status') . ' = ' . $dbo->q('confirmed') . ' THEN 1 ELSE 0 END DESC');
10067 $query->order($dbo->qn('o.id') . ' ASC');
10068 }
10069 $dbo->setQuery($query);
10070 $booking_infos = $dbo->loadAssocList();
10071
10072 foreach ($booking_infos as $k => $row) {
10073 // rooms, amounts and guests information
10074 $rooms = VikBooking::loadOrdersRoomsData($row['id']);
10075 $rids_involved = [];
10076 $room_names = [];
10077 $totadults = 0;
10078 $totchildren = 0;
10079 foreach ($rooms as $rr) {
10080 $rids_involved[] = $rr['idroom'];
10081 $totadults += $rr['adults'];
10082 $totchildren += $rr['children'];
10083 $room_names[] = $rr['room_name'];
10084 if ($row['split_stay']) {
10085 // do not sum guests in case of split stay booking
10086 $totadults = $rr['adults'];
10087 $totchildren = $rr['children'];
10088 }
10089 }
10090
10091 if (!empty($pstay_date) && !empty($pidroom) && $pstatus == 'any') {
10092 // make sure we have fetched a reservation for the correct room (in case of cancellations included)
10093 if (!in_array($pidroom, $rids_involved)) {
10094 $is_out_of_scope = true;
10095 if ($psharedcal && count($bookings) === 1) {
10096 $is_out_of_scope = ($row['id'] != $bookings[0]);
10097 }
10098 if ($is_out_of_scope) {
10099 // out of scope reservation, unset it and go to the next one
10100 unset($booking_infos[$k]);
10101 continue;
10102 }
10103 }
10104 }
10105
10106 // included meal plans to be displayed in case of single-room booking
10107 $included_meals = [];
10108 $rplan_name = '';
10109 if (count($rooms) === 1) {
10110 // rate plan name and ID, if any
10111 $active_rplan_id = 0;
10112 if (!empty($rooms[0]['otarplan'])) {
10113 $rplan_name = $rooms[0]['otarplan'];
10114 } else {
10115 list($rplan_name, $active_rplan_id) = VBOMealplanManager::getInstance()->getPriceData($rooms[0]['idtar']);
10116 }
10117
10118 // find the included meals
10119 if (!empty($rooms[0]['meals'])) {
10120 // display included meals defined at room-reservation record
10121 $included_meals = VBOMealplanManager::getInstance()->roomRateIncludedMeals($rooms[0]);
10122 } else {
10123 // fetch default included meals in the selected rate plan
10124 $included_meals = $active_rplan_id ? VBOMealplanManager::getInstance()->ratePlanIncludedMeals($active_rplan_id) : [];
10125 }
10126 if (!$included_meals && empty($row['meals']) && !empty($row['idorderota']) && !empty($row['channel']) && !empty($row['custdata'])) {
10127 // attempt to fetch the included meal plans from the raw customer data or OTA reservation and room
10128 $included_meals = VBOMealplanManager::getInstance()->otaDataIncludedMeals($row, $rooms[0]);
10129 }
10130 }
10131
10132 if ($included_meals) {
10133 $short_incl_meals = [];
10134 foreach ($included_meals as $meal_enum => $meal_name) {
10135 $short_incl_meals[] = $short_meal_enums[$meal_enum];
10136 }
10137 $booking_infos[$k]['meals_included'] = $short_incl_meals;
10138 }
10139
10140 $booking_infos[$k]['rateplan_name'] = $rplan_name;
10141 $booking_infos[$k]['currency_symb'] = $currencysymb;
10142 if ($row['status'] == 'confirmed') {
10143 $booking_infos[$k]['status_lbl'] = JText::translate('VBCONFIRMED');
10144 if ($row['checkout'] < $current_ts) {
10145 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSOUT');
10146 } elseif ($row['checkin'] < $current_ts && $row['checkout'] > $current_ts) {
10147 if ($row['checked'] == 1) {
10148 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSIN');
10149 } elseif ($row['checked'] == -1) {
10150 $booking_infos[$k]['status_lbl'] = JText::translate('VBOCHECKEDSTATUSNOS');
10151 }
10152 }
10153 } elseif ($row['status'] == 'standby') {
10154 $booking_infos[$k]['status_lbl'] = JText::translate('VBSTANDBY');
10155 } elseif ($row['status'] == 'cancelled') {
10156 $booking_infos[$k]['status_lbl'] = JText::translate('VBCANCELLED');
10157 } else {
10158 $booking_infos[$k]['status_lbl'] = $row['status'];
10159 }
10160 $booking_infos[$k]['colortag'] = VikBooking::applyBookingColorTag($row);
10161 if ($booking_infos[$k]['colortag']) {
10162 $booking_infos[$k]['colortag']['name'] = JText::translate($booking_infos[$k]['colortag']['name']);
10163 }
10164 $booking_infos[$k]['room_names'] = implode(', ', $room_names);
10165 $booking_infos[$k]['tot_adults'] = $totadults;
10166 $booking_infos[$k]['tot_children'] = $totchildren;
10167 $booking_infos[$k]['format_tot'] = VikBooking::numberFormat($row['total']);
10168 $booking_infos[$k]['format_totpaid'] = VikBooking::numberFormat($row['totpaid']);
10169
10170 // room indexes
10171 $rindexes = [];
10172 $av_room_indexes = [];
10173 $used_indexes_map = [];
10174 $sub_units_data = [];
10175 $optindexes = [];
10176 $subroomdata = !empty($psubroom) ? explode('-', $psubroom) : array();
10177 $missing_index = false;
10178 foreach ($rooms as $kor => $or) {
10179 if ($row['status'] != "confirmed" || $row['closure'] || empty($or['params'])) {
10180 // cannot build room indexes data
10181 continue;
10182 }
10183
10184 $room_params = json_decode($or['params'], true);
10185 if (!is_array($room_params) || empty($room_params['features']) || !is_array($room_params['features'])) {
10186 // no distinctive features information
10187 continue;
10188 }
10189
10190 if (!strlen($or['roomindex'])) {
10191 // turn flag on for missing index when room does support them
10192 $missing_index = true;
10193 // build array with available room indexes
10194 $av_indexes = [];
10195 $unavailable_indexes = VikBooking::getRoomUnitNumsUnavailable($row, $or['idroom']);
10196 foreach ($room_params['features'] as $rind => $rfeatures) {
10197 if (in_array($rind, $unavailable_indexes) || (isset($used_indexes_map[$or['idroom']]) && in_array($rind, $used_indexes_map[$or['idroom']]))) {
10198 continue;
10199 }
10200 foreach ($rfeatures as $fname => $fval) {
10201 if ($fval) {
10202 $av_indexes[$rind] = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10203 break;
10204 }
10205 }
10206 }
10207 if ($av_indexes) {
10208 // push available indexes for this room
10209 $av_room_indexes[$kor] = [
10210 'rid' => $or['idroom'],
10211 'name' => $or['room_name'],
10212 'list' => $av_indexes,
10213 ];
10214 }
10215 // do not proceed any further
10216 continue;
10217 }
10218
10219 // parse distinctive features
10220 foreach ($room_params['features'] as $rind => $rfeatures) {
10221 if ($rind != $or['roomindex']) {
10222 continue;
10223 }
10224 $ind_str = '';
10225 $ind_str_short = '';
10226 foreach ($rfeatures as $fname => $fval) {
10227 if (strlen($fval)) {
10228 $ind_str = '#' . $rind . ' - ' . JText::translate($fname) . ': ' . $fval;
10229 $ind_str_short = $fval;
10230 break;
10231 }
10232 }
10233 if (!isset($rindexes[$or['room_name']])) {
10234 $rindexes[$or['room_name']] = $ind_str;
10235 $sub_units_data[$or['room_name']] = $ind_str_short;
10236 } else {
10237 $rindexes[$or['room_name']] .= ', ' . $ind_str;
10238 $sub_units_data[$or['room_name']] .= ', ' . $ind_str_short;
10239 }
10240 break;
10241 }
10242
10243 // build options to switch sub-unit index
10244 if (count($subroomdata) && !count($optindexes) && $or['idroom'] == (int)$subroomdata[0]) {
10245 // build the options for switching the room index for this room
10246 foreach ($room_params['features'] as $rind => $rfeatures) {
10247 foreach ($rfeatures as $fname => $fval) {
10248 if (strlen((string)$fval)) {
10249 $optindexes[] = '<option value="'.$rind.'"'.($rind == (int)$subroomdata[1] ? ' selected="selected"' : '').'>#'.$rind.' - '.JText::translate($fname).': '.$fval.'</option>';
10250 break;
10251 }
10252 }
10253 }
10254 }
10255 }
10256
10257 if ($rindexes) {
10258 $booking_infos[$k]['rindexes'] = $rindexes;
10259 $booking_infos[$k]['sub_units_data'] = $sub_units_data;
10260 }
10261
10262 if ($optindexes) {
10263 $booking_infos[$k]['optindexes'] = $optindexes;
10264 }
10265
10266 if ($missing_index && $av_room_indexes) {
10267 $booking_infos[$k]['av_room_indexes'] = $av_room_indexes;
10268 }
10269
10270 // include flag for missing room index
10271 $booking_infos[$k]['missing_index'] = $missing_index;
10272
10273 // channel provenience and small logo URL
10274 $ota_logo_img = JText::translate('VBORDFROMSITE');
10275 $booking_avatar_src = null;
10276 $booking_avatar_alt = null;
10277 if (!empty($row['channel'])) {
10278 $channelparts = explode('_', $row['channel']);
10279 $otachannel = array_key_exists(1, $channelparts) && strlen($channelparts[1]) > 0 ? $channelparts[1] : ucwords($channelparts[0]);
10280 $ota_logo_img = VikBooking::getVcmChannelsLogo($row['channel']);
10281 if ($ota_logo_img === false) {
10282 $ota_logo_img = $otachannel;
10283 } else {
10284 $ota_logo_img = '<img src="'.$ota_logo_img.'" class="vbo-channelimg-small"/>';
10285 }
10286 $logo_helper = VikBooking::getVcmChannelsLogo($row['channel'], $get_istance = true);
10287 if ($logo_helper !== false) {
10288 $booking_avatar_src = $logo_helper->getSmallLogoURL();
10289 $booking_avatar_alt = $logo_helper->provenience;
10290 }
10291 }
10292 $booking_infos[$k]['channelimg'] = $ota_logo_img;
10293 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10294 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10295
10296 // Customer Details
10297 $custdata = $row['custdata'];
10298 $custdata_parts = explode("\n", $row['custdata']);
10299 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
10300 //get the first two fields
10301 $custvalues = [];
10302 foreach ($custdata_parts as $custdet) {
10303 if (strlen($custdet) < 1) {
10304 continue;
10305 }
10306 $custdet_parts = explode(':', $custdet);
10307 if (count($custdet_parts) >= 2) {
10308 unset($custdet_parts[0]);
10309 array_push($custvalues, trim(implode(':', $custdet_parts)));
10310 }
10311 if (count($custvalues) > 1) {
10312 break;
10313 }
10314 }
10315 if (count($custvalues) > 1) {
10316 $custdata = implode(' ', $custvalues);
10317 }
10318 }
10319 if (strlen($custdata) > 45) {
10320 $custdata = substr($custdata, 0, 45)." ...";
10321 }
10322
10323 // customer record details
10324 $customer = [];
10325 $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'];
10326 $dbo->setQuery($q, 0, 1);
10327 $dbo->execute();
10328 if ($dbo->getNumRows()) {
10329 $customer = $dbo->loadAssoc();
10330 if (!empty($customer['first_name'])) {
10331 $custdata = $customer['first_name'].' '.$customer['last_name'];
10332 if (!empty($customer['country'])) {
10333 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10334 $custdata .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$customer['country'].'.png'.'" title="'.htmlspecialchars($customer['country']).'" class="vbo-country-flag vbo-country-flag-left"/>';
10335 }
10336 }
10337 }
10338 }
10339 $booking_infos[$k]['customer'] = $customer;
10340
10341 // check if a profile picture is available for the customer
10342 if (!empty($customer['pic'])) {
10343 $booking_avatar_src = strpos($customer['pic'], 'http') === 0 ? $customer['pic'] : VBO_SITE_URI . 'resources/uploads/' . $customer['pic'];
10344 $booking_avatar_alt = basename($booking_avatar_src);
10345 $booking_infos[$k]['avatar_src'] = $booking_avatar_src;
10346 $booking_infos[$k]['avatar_alt'] = $booking_avatar_alt;
10347 }
10348
10349 // whether this is a closure
10350 $booking_infos[$k]['closure'] = (int)$row['closure'];
10351 $booking_infos[$k]['closure_txt'] = $row['closure'] ? JText::translate('VBDBTEXTROOMCLOSED') : null;
10352
10353 // short customer information
10354 $custdata = JText::translate('VBDBTEXTROOMCLOSED') == $row['custdata'] ? '<span class="vbordersroomclosed">'.JText::translate('VBDBTEXTROOMCLOSED').'</span>' : $custdata;
10355 $booking_infos[$k]['cinfo'] = $custdata;
10356
10357 // formatted dates
10358 $booking_infos[$k]['ts'] = date(str_replace("/", $datesep, $df).' H:i', $row['ts']);
10359 $booking_infos[$k]['checkin'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkin']);
10360 $booking_infos[$k]['checkout'] = date(str_replace("/", $datesep, $df).' H:i', $row['checkout']);
10361
10362 // short booking date, check-in, check-out date format
10363 $stay_info_in = getdate($row['checkin']);
10364 $stay_info_out = getdate($row['checkout']);
10365 $str_checkin = date('d', $row['checkin']);
10366 $str_checkin .= $stay_info_in['mon'] != $stay_info_out['mon'] ? ' ' . VikBooking::sayMonth($stay_info_in['mon'], $short = true) : '';
10367 $str_checkout = date('d', $row['checkout']) . ' ' . VikBooking::sayMonth($stay_info_out['mon'], $short = true);
10368 if ($stay_info_in['year'] != $stay_info_out['year'] || $stay_info_in['year'] != $current_y || $stay_info_out['year'] != $current_y) {
10369 $str_checkout .= ' ' . $stay_info_out['year'];
10370 }
10371 $booking_infos[$k]['checkin_short'] = $str_checkin;
10372 $booking_infos[$k]['checkout_short'] = $str_checkout;
10373 $booking_infos[$k]['book_date'] = date(str_replace("/", $datesep, $df), $row['ts']);
10374 $booking_infos[$k]['book_time'] = date('H:i', $row['ts']);
10375 }
10376
10377 if (!$booking_infos) {
10378 // output the error
10379 VBOHttpDocument::getInstance()->close(500, '2 - ' . JText::translate('VBOVWGETBKERRMISSDATA'));
10380 }
10381
10382 // output the JSON encoded response and exit
10383 VBOHttpDocument::getInstance()->json($booking_infos);
10384 }
10385
10386 public function switchRoomIndex() {
10387 //to be called via ajax
10388 $dbo = JFactory::getDBO();
10389 $bid = VikRequest::getInt('bid', '', 'request');
10390 $rid = VikRequest::getInt('rid', '', 'request');
10391 $old_rindex = VikRequest::getInt('old_rindex', '', 'request');
10392 $new_rindex = VikRequest::getInt('new_rindex', '', 'request');
10393 if (empty($bid) || empty($rid) || empty($old_rindex) || empty($new_rindex)) {
10394 echo 'e4j.error.#1 Missing Data';
10395 exit;
10396 }
10397 $q = "SELECT * FROM `#__vikbooking_ordersrooms` WHERE `idorder`=".$bid." AND `idroom`=".$rid." AND `roomindex`=".$old_rindex.";";
10398 $dbo->setQuery($q);
10399 $dbo->execute();
10400 if ($dbo->getNumRows() < 1) {
10401 echo 'e4j.error.#2 Record not found';
10402 exit;
10403 }
10404 $rows = $dbo->loadAssocList();
10405 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".$new_rindex." WHERE `id`=".$rows[0]['id'].";";
10406 $dbo->setQuery($q);
10407 $dbo->execute();
10408 echo 'e4j.ok';
10409 exit;
10410 }
10411
10412 public function searchcustomer()
10413 {
10414 // to be called via ajax
10415 $dbo = JFactory::getDbo();
10416
10417 $kw = VikRequest::getString('kw', '', 'request');
10418 $nopin = VikRequest::getInt('nopin', '', 'request');
10419 $email = VikRequest::getInt('email', 0, 'request');
10420 $selector = VikRequest::getString('selector', 'vbo-custsearchres-entry', 'request');
10421 $no_script = VikRequest::getInt('no_script', 0, 'request');
10422
10423 if (!strlen($kw)) {
10424 VBOHttpDocument::getInstance()->close(200, '');
10425 }
10426
10427 if ($nopin > 0) {
10428 //page all bookings
10429 $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;";
10430 } elseif ($email > 0) {
10431 // page calendar for checking if an email exists
10432 $q = "SELECT `first_name`, `last_name`, `email` FROM `#__vikbooking_customers` WHERE `email`=".$dbo->quote($kw).";";
10433 } else {
10434 //page calendar
10435 $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;";
10436 }
10437 $dbo->setQuery($q);
10438 $customers = $dbo->loadAssocList();
10439
10440 if (!$customers) {
10441 VBOHttpDocument::getInstance()->close(200, '');
10442 }
10443
10444 if ($email > 0) {
10445 VBOHttpDocument::getInstance()->json($customers[0]);
10446 }
10447
10448 $cust_old_fields = array();
10449 $cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
10450 foreach ($customers as $k => $v) {
10451 $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";
10452 $cstring_search .= '<span class="vbo-custsearchres-cflag">';
10453 if (!empty($v['pic'])) {
10454 $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";
10455 } elseif (is_file(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$v['country'].'.png')) {
10456 $cstring_search .= '<img src="'.VBO_ADMIN_URI.'resources/countries/'.$v['country'].'.png'.'" title="'.htmlspecialchars($v['country']).'" class="vbo-country-flag"/>'."\n";
10457 } else {
10458 $cstring_search .= '<i class="' . VikBookingIcons::i('globe') . '"></i>';
10459 }
10460 $cstring_search .= '</span>';
10461 $cstring_search .= '<span class="vbo-custsearchres-name" title="'.htmlspecialchars($v['email']).'">'.$v['first_name'].' '.$v['last_name'].'</span>'."\n";
10462 if (!($nopin > 0)) {
10463 $cstring_search .= '<span class="vbo-custsearchres-pin">'.$v['pin'].'</span>'."\n";
10464 }
10465 $cstring_search .= '</div>'."\n";
10466 if (!empty($v['cfields'])) {
10467 $oldfields = json_decode($v['cfields'], true);
10468 if (is_array($oldfields) && count($oldfields)) {
10469 $cust_old_fields[$v['id']] = $oldfields;
10470 }
10471 }
10472 }
10473 $cstring_search .= '</div>'."\n";
10474
10475 /**
10476 * Add the necessary JS code for the arrow navigation.
10477 */
10478 $cstring_search_js = '<script type="text/javascript">';
10479 $cstring_search_js .= '
10480 var vboCust = jQuery(".' . $selector . '");
10481 var vboCustSelected = null;
10482 jQuery(window).keydown(function(e) {
10483 if (e.which === 40) {
10484 if (vboCustSelected) {
10485 vboCustSelected.removeClass("' . $selector . '-highligthed");
10486 next = vboCustSelected.next();
10487 if (next.length > 0) {
10488 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10489 } else {
10490 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10491 }
10492 } else {
10493 vboCustSelected = vboCust.eq(0).addClass("' . $selector . '-highligthed");
10494 }
10495 } else if (e.which === 38) {
10496 if (vboCustSelected) {
10497 vboCustSelected.removeClass("' . $selector . '-highligthed");
10498 next = vboCustSelected.prev();
10499 if (next.length > 0) {
10500 vboCustSelected = next.addClass("' . $selector . '-highligthed");
10501 } else {
10502 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10503 }
10504 } else {
10505 vboCustSelected = vboCust.last().addClass("' . $selector . '-highligthed");
10506 }
10507 } else if (e.which === 13) {
10508 if (vboCustSelected) {
10509 vboCustSelected.trigger("click");
10510 }
10511 }
10512 });
10513 jQuery(".' . $selector . '").off("hover");
10514 jQuery(".' . $selector . '").hover(function() {
10515 if (vboCustSelected) {
10516 vboCustSelected.removeClass("' . $selector . '-highligthed");
10517 vboCustSelected = null;
10518 }
10519 vboCustSelected = jQuery(this).addClass("' . $selector . '-highligthed");
10520 }, function() {
10521 if (vboCustSelected) {
10522 vboCustSelected.removeClass("' . $selector . '-highligthed");
10523 vboCustSelected = null;
10524 }
10525 jQuery(this).removeClass("' . $selector . '-highligthed");
10526 });';
10527 $cstring_search_js .= '</script>';
10528
10529 if (!$no_script) {
10530 // append JS
10531 $cstring_search .= $cstring_search_js;
10532 }
10533
10534 VBOHttpDocument::getInstance()->json([($nopin > 0 ? '' : $cust_old_fields), $cstring_search]);
10535 }
10536
10537 public function sharesignaturelink() {
10538 //to be called via ajax
10539 $dbo = JFactory::getDBO();
10540 $response = array(
10541 'status' => 0,
10542 'error' => 'Generic Error'
10543 );
10544 $pbid = VikRequest::getInt('bid', '', 'request');
10545 $phow = VikRequest::getString('how', '', 'request');
10546 $pto = VikRequest::getString('to', '', 'request');
10547 $pcustomer = VikRequest::getInt('customer', '', 'request');
10548 $cpin = VikBooking::getCPinIstance();
10549 $customer_info = $cpin->getCustomerByID($pcustomer);
10550 if (!empty($pbid) && !empty($phow) && !empty($pto) && count($customer_info) > 0) {
10551 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$pbid." AND `status`='confirmed' AND `checked` > 0;";
10552 $dbo->setQuery($q);
10553 $dbo->execute();
10554 if ($dbo->getNumRows() > 0) {
10555 $row = $dbo->loadAssoc();
10556
10557 $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'];
10558 if (VBOPlatformDetection::isWordPress()) {
10559 /**
10560 * @wponly Rewrite URI for front-end signature
10561 */
10562 $share_link = str_replace(JUri::root(), '', $share_link);
10563 $model = JModel::getInstance('vikbooking', 'shortcodes');
10564 $itemid = $model->all('post_id', $full = true);
10565 if (count($itemid)) {
10566 $share_link = JRoute::rewrite($share_link . "&Itemid={$itemid[0]->post_id}", false);
10567 }
10568 } else {
10569 /**
10570 * @joomlaonly
10571 */
10572 $best_menuitem_id = VikBooking::findProperItemIdType(['vikbooking', 'booking'], $row['lang']);
10573 if ($best_menuitem_id) {
10574 $share_base = str_replace(JUri::root(), '', $share_link);
10575 $share_link = VikBooking::externalroute($share_base, $xhtml = false, $best_menuitem_id);
10576 }
10577 }
10578
10579 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGE', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10580 if ($phow == 'email') {
10581 $sender = VikBooking::getSenderMail();
10582 $vbo_app = VikBooking::getVboApplication();
10583 $vbo_app->sendMail($sender, $sender, $pto, $sender, JText::translate('VBOSIGNSHARESUBJECT'), $share_message, false);
10584 $response['status'] = 1;
10585 } elseif ($phow == 'sms') {
10586 $share_message = JText::sprintf('VBOSIGNSHAREMESSAGESMS', ltrim($customer_info['first_name'].' '.$customer_info['last_name']), $share_link, VikBooking::getFrontTitle());
10587 $sms_api = VikBooking::getSMSAPIClass();
10588 $sms_api_params = VikBooking::getSMSParams();
10589 if (!empty($sms_api) && file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api) && !empty($sms_api_params)) {
10590 require_once(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'smsapi'.DIRECTORY_SEPARATOR.$sms_api);
10591 $sms_obj = new VikSmsApi(array(), $sms_api_params);
10592 $response_obj = $sms_obj->sendMessage($pto, $share_message);
10593 if ($sms_obj->validateResponse($response_obj)) {
10594 $response['status'] = 1;
10595 } else {
10596 $response['error'] = $sms_obj->getLog();
10597 }
10598 } else {
10599 $response['error'] = 'No SMS Provider Configured';
10600 }
10601 } else {
10602 $response['error'] = 'Invalid Sending Method';
10603 }
10604 } else {
10605 $response['error'] = 'Invalid Booking ID';
10606 }
10607 } else {
10608 $response['error'] = 'Empty values';
10609 }
10610
10611 echo json_encode($response);
10612 exit;
10613 }
10614
10615 public function dayselectioncount() {
10616 //to be called via ajax
10617 $tsinit = VikRequest::getString('dinit', '', 'request');
10618 $tsend = VikRequest::getString('dend', '', 'request');
10619 if (strlen($tsinit) > 0 && strlen($tsend) > 0) {
10620 $ptsinit=VikBooking::getDateTimestamp($tsinit, '0', '0');
10621 $ptsend=VikBooking::getDateTimestamp($tsend, '23', '59');
10622 $diff = $ptsend - $ptsinit;
10623 if ($diff >= 172800) {
10624 $datef = VikBooking::getDateFormat(true);
10625 if ($datef=="%d/%m/%Y") {
10626 $df = 'd-m-Y';
10627 } else {
10628 $df = 'Y-m-d';
10629 }
10630 //minimum 2 days for excluding some days
10631 $daysdiff = floor($diff / 86400);
10632 $infoinit = getdate($ptsinit);
10633 $select = '';
10634 $select .= '<div style="display: inline-block;"><select name="excludeday[]" multiple="multiple" size="'.($daysdiff > 8 ? 8 : $daysdiff).'" id="vboexclusion">';
10635 for($i = 0; $i <= $daysdiff; $i++) {
10636 $ts = $i > 0 ? mktime(0, 0, 0, $infoinit['mon'], ((int)$infoinit['mday'] + $i), $infoinit['year']) : $ptsinit;
10637 $infots = getdate($ts);
10638 $optval = $infots['mon'].'-'.$infots['mday'].'-'.$infots['year'];
10639 $select .= '<option value="'.$optval.'">'.date($df, $ts).'</option>';
10640 }
10641 $select .= '</select></div>';
10642 //excluded days of the week
10643 if ($daysdiff >= 14) {
10644 $select .= '<div style="display: inline-block; margin-left: 40px;"><select name="excludewdays[]" multiple="multiple" size="8" id="excludewdays" onchange="vboExcludeWDays();">';
10645 $select .= '<optgroup label="'.JText::translate('VBOEXCLWEEKD').'">';
10646 $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>';
10647 $select .= '</optgroup>';
10648 $select .= '</select></div>';
10649 }
10650 //
10651 echo $select;
10652 } else {
10653 echo '';
10654 }
10655 } else {
10656 echo '';
10657 }
10658 exit;
10659 }
10660
10661 public function createcheckindoc() {
10662 $cid = VikRequest::getVar('cid', array(0));
10663 $id = $cid[0];
10664
10665 $dbo = JFactory::getDBO();
10666 $mainframe = JFactory::getApplication();
10667 $vbo_tn = VikBooking::getTranslator();
10668 $lang = JFactory::getLanguage();
10669 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10670 $psignature = VikRequest::getString('signature', '', 'request', VIKREQUEST_ALLOWRAW);
10671 $ppad_width = VikRequest::getInt('pad_width', '', 'request');
10672 $ppad_ratio = VikRequest::getInt('pad_ratio', '', 'request');
10673 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed' AND `checked` > 0;";
10674 $dbo->setQuery($q);
10675 $dbo->execute();
10676 if ($dbo->getNumRows() < 1) {
10677 $mainframe->redirect('index.php');
10678 exit;
10679 }
10680 $row = $dbo->loadAssoc();
10681 if (!empty($row['lang'])) {
10682 if ($lang->getTag() != $row['lang']) {
10683 if (VBOPlatformDetection::isWordPress()) {
10684 $lang->load('com_vikbooking', VIKBOOKING_LANG, $row['lang'], true);
10685 } else {
10686 $lang->load('com_vikbooking', JPATH_SITE, $row['lang'], true);
10687 $lang->load('com_vikbooking', JPATH_ADMINISTRATOR, $row['lang'], true);
10688 $lang->load('joomla', JPATH_SITE, $row['lang'], true);
10689 $lang->load('joomla', JPATH_ADMINISTRATOR, $row['lang'], true);
10690 }
10691 }
10692 if ($vbo_tn->getDefaultLang() != $row['lang']) {
10693 // force the translation to start because contents should be translated
10694 $vbo_tn::$force_tolang = $row['lang'];
10695 }
10696 }
10697 $customer = array();
10698 $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'].";";
10699 $dbo->setQuery($q);
10700 $dbo->execute();
10701 if ($dbo->getNumRows() > 0) {
10702 $customer = $dbo->loadAssoc();
10703 if (!empty($customer['country'])) {
10704 if (file_exists(VBO_ADMIN_PATH.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'countries'.DIRECTORY_SEPARATOR.$customer['country'].'.png')) {
10705 $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"/>';
10706 }
10707 }
10708 }
10709 if (!(count($customer) > 0)) {
10710 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10711 $mainframe->redirect('index.php?option=com_vikbooking&task=newcustomer&checkin=1&bid='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10712 exit;
10713 }
10714 $customer['pax_data'] = !empty($customer['pax_data']) ? json_decode($customer['pax_data'], true) : array();
10715 //check if the signature has been submitted
10716 $signature_data = '';
10717 $cont_type = '';
10718 if (!empty($psignature)) {
10719 //check whether the format is accepted
10720 if (strpos($psignature, 'image/png') !== false || strpos($psignature, 'image/jpeg') !== false || strpos($psignature, 'image/svg') !== false) {
10721 $parts = explode(';base64,', $psignature);
10722 $cont_type_parts = explode('image/', $parts[0]);
10723 $cont_type = $cont_type_parts[1];
10724 if (!empty($parts[1])) {
10725 $signature_data = base64_decode($parts[1]);
10726 }
10727 }
10728 }
10729 if (!empty($signature_data)) {
10730 //write file
10731 $sign_fname = $row['id'].'_'.$row['sid'].'_'.$customer['id'].'.'.$cont_type;
10732 $filepath = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'idscans' . DIRECTORY_SEPARATOR . $sign_fname;
10733 $fp = fopen($filepath, 'w+');
10734 $bytes = fwrite($fp, $signature_data);
10735 fclose($fp);
10736 if ($bytes !== false && $bytes > 0) {
10737 //update the signature in the DB
10738 $q = "UPDATE `#__vikbooking_customers_orders` SET `signature`=".$dbo->quote($sign_fname)." WHERE `idorder`=".(int)$row['id'].";";
10739 $dbo->setQuery($q);
10740 $dbo->execute();
10741 $customer['signature'] = $sign_fname;
10742 //resize image for screens with high resolution
10743 if ($ppad_ratio > 1) {
10744 $new_width = floor(($ppad_width / 2));
10745 $creativik = new vikResizer();
10746 $creativik->proportionalImage($filepath, $filepath, $new_width, $new_width);
10747 } else {
10748 /**
10749 * @wponly - trigger files mirroring
10750 */
10751 VikBookingLoader::import('update.manager');
10752 VikBookingUpdateManager::triggerUploadBackup($filepath);
10753 //
10754 }
10755 //
10756 } else {
10757 VikError::raiseWarning('', JText::translate('VBOERRSTORESIGNFILE'));
10758 }
10759 }
10760 //
10761 //generate PDF for check-in document by parsing the apposite template file
10762 $booking_rooms = array();
10763 $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'].";";
10764 $dbo->setQuery($q);
10765 $dbo->execute();
10766 if ($dbo->getNumRows() > 0) {
10767 $booking_rooms = $dbo->loadAssocList();
10768 if (!empty($row['lang'])) {
10769 $vbo_tn->translateContents($booking_rooms, '#__vikbooking_rooms', array('id' => 'idroom', 'room_name' => 'name'), array(), $row['lang']);
10770 }
10771 }
10772 if (!class_exists('TCPDF')) {
10773 require_once(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . 'tcpdf.php');
10774 }
10775 $usepdffont = is_file(VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "tcpdf" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "dejavusans.php") ? 'dejavusans' : 'helvetica';
10776
10777 /**
10778 * Trigger event to allow third party plugins to return a specific font name.
10779 *
10780 * @since 1.16.0 (J) - 1.6.0 (WP)
10781 */
10782 $custom_pdf_font = VBOFactory::getPlatform()->getDispatcher()->filter('onGetPdfFontNameVikBooking', [$usepdffont]);
10783 if (is_array($custom_pdf_font) && !empty($custom_pdf_font[0])) {
10784 $usepdffont = $custom_pdf_font[0];
10785 }
10786
10787 list($checkintpl, $pdfparams) = VikBooking::loadCheckinDocTmpl($row, $booking_rooms, $customer);
10788 $checkin_body = VikBooking::parseCheckinDocTemplate($checkintpl, $row, $booking_rooms, $customer);
10789 $pdffname = $row['id'] . '_' . $row['sid'] . '.pdf';
10790 $pathpdf = VBO_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "checkins" . DIRECTORY_SEPARATOR . "generated" . DIRECTORY_SEPARATOR . $pdffname;
10791 if (file_exists($pathpdf)) @unlink($pathpdf);
10792 $pdf_page_format = is_array($pdfparams['pdf_page_format']) ? $pdfparams['pdf_page_format'] : constant($pdfparams['pdf_page_format']);
10793 $pdf = new TCPDF(constant($pdfparams['pdf_page_orientation']), constant($pdfparams['pdf_unit']), $pdf_page_format, true, 'UTF-8', false);
10794 $pdf->SetTitle(JText::translate('VBOCHECKINDOCTITLE'));
10795 //Header for each page of the pdf
10796 if ($pdfparams['show_header'] == 1 && count($pdfparams['header_data']) > 0) {
10797 $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]);
10798 }
10799 //header and footer fonts
10800 $pdf->setHeaderFont(array($usepdffont, '', $pdfparams['header_font_size']));
10801 $pdf->setFooterFont(array($usepdffont, '', $pdfparams['footer_font_size']));
10802 //margins
10803 $pdf->SetMargins(constant($pdfparams['pdf_margin_left']), constant($pdfparams['pdf_margin_top']), constant($pdfparams['pdf_margin_right']));
10804 $pdf->SetHeaderMargin(constant($pdfparams['pdf_margin_header']));
10805 $pdf->SetFooterMargin(constant($pdfparams['pdf_margin_footer']));
10806 //
10807 $pdf->SetAutoPageBreak(true, constant($pdfparams['pdf_margin_bottom']));
10808 $pdf->setImageScale(constant($pdfparams['pdf_image_scale_ratio']));
10809 $pdf->SetFont($usepdffont, '', (int)$pdfparams['body_font_size']);
10810 if ($pdfparams['show_header'] == 0 || !(count($pdfparams['header_data']) > 0)) {
10811 $pdf->SetPrintHeader(false);
10812 }
10813 if ($pdfparams['show_footer'] == 0) {
10814 $pdf->SetPrintFooter(false);
10815 }
10816 $pdf->AddPage();
10817 $pdf->writeHTML($checkin_body, true, false, true, false, '');
10818 $pdf->lastPage();
10819 $pdf->Output($pathpdf, 'F');
10820 if (!file_exists($pathpdf)) {
10821 VikError::raiseWarning('', JText::translate('VBOERRGENCHECKINDOC'));
10822 } else {
10823 $q = "UPDATE `#__vikbooking_customers_orders` SET `checkindoc`=".$dbo->quote($pdffname)." WHERE `idorder`=".(int)$row['id'].";";
10824 $dbo->setQuery($q);
10825 $dbo->execute();
10826 $mainframe->enqueueMessage(JText::translate('VBOGENCHECKINDOCSUCCESS'));
10827 /**
10828 * @wponly - trigger files mirroring
10829 */
10830 VikBookingLoader::import('update.manager');
10831 VikBookingUpdateManager::triggerUploadBackup($pathpdf);
10832 //
10833 }
10834 //
10835 /**
10836 * @wponly - this task is executed via Ajax for the Modal forms listener. We cannot redirect to tmpl=component
10837 */
10838 $mainframe->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id']);
10839 exit;
10840 }
10841
10842 public function updatebookingcheckin() {
10843 $cid = VikRequest::getVar('cid', array(0));
10844 $id = $cid[0];
10845
10846 $dbo = JFactory::getDbo();
10847 $app = JFactory::getApplication();
10848
10849 $ptmpl = VikRequest::getString('tmpl', '', 'request');
10850 $pnewtotpaid = VikRequest::getFloat('newtotpaid', 0, 'request');
10851 $pguests = VikRequest::getVar('guests', array());
10852 $pcomments = VikRequest::getString('comments', '', 'request', VIKREQUEST_ALLOWHTML);
10853 $pcheckin_action = VikRequest::getInt('checkin_action', '', 'request');
10854 $valid_actions = array(-1, 0, 1, 2);
10855 if (!in_array($pcheckin_action, $valid_actions)) {
10856 $app->redirect('index.php');
10857 exit;
10858 }
10859 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=".(int)$id." AND `status`='confirmed';";
10860 $dbo->setQuery($q);
10861 $dbo->execute();
10862 if ($dbo->getNumRows() < 1) {
10863 $app->redirect('index.php');
10864 exit;
10865 }
10866 $row = $dbo->loadAssoc();
10867 $q = "SELECT * FROM `#__vikbooking_customers_orders` WHERE `idorder`=".$row['id'].";";
10868 $dbo->setQuery($q);
10869 $dbo->execute();
10870 if ($dbo->getNumRows() < 1) {
10871 VikError::raiseWarning('', JText::translate('VBOCHECKINERRNOCUSTOMER'));
10872 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($ptmpl == 'component' ? '&tmpl=component' : ''));
10873 exit;
10874 }
10875 $custorder = $dbo->loadAssoc();
10876 //update checked status and new total paid
10877 $q = "UPDATE `#__vikbooking_orders` SET `checked`=".$pcheckin_action."".($pnewtotpaid > 0 ? ', `totpaid`='.$pnewtotpaid : '')." WHERE `id`=".$row['id'].";";
10878 $dbo->setQuery($q);
10879 $dbo->execute();
10880 // Booking History log for new amount paid (payment update)
10881 if ($pnewtotpaid > 0 && $pnewtotpaid > (float)$row['totpaid']) {
10882 $extra_data = new stdClass;
10883 $extra_data->amount_paid = ($pnewtotpaid - (float)$row['totpaid']);
10884 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->setExtraData($extra_data)->store('PU', JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat((float)$row['totpaid'])));
10885 }
10886 //
10887 //Booking History
10888 $hist_type = 'A';
10889 if ($pcheckin_action < 0) {
10890 $hist_type = 'Z';
10891 } elseif ($pcheckin_action == 1) {
10892 $hist_type = 'B';
10893 } elseif ($pcheckin_action == 2) {
10894 $hist_type = 'C';
10895 }
10896 $user = JFactory::getUser();
10897 VikBooking::getBookingHistoryInstance()->setBid($row['id'])->store('R' . $hist_type, "({$user->name})");
10898 //
10899 //Guests Details
10900 $guests_details = array();
10901 list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields();
10902 // grab also the fields for front-end pre check-in
10903 list($pre_pax_fields, $pre_pax_fields_attributes) = VikBooking::getPaxFields(true);
10904 //
10905 foreach ($pguests as $ind => $adults) {
10906 foreach ($adults as $aduind => $details) {
10907 foreach ($pax_fields as $key => $v) {
10908 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
10909 if (!isset($guests_details[$ind])) {
10910 $guests_details[$ind] = array();
10911 }
10912 if (!isset($guests_details[$ind][$aduind])) {
10913 $guests_details[$ind][$aduind] = array();
10914 }
10915 $guests_details[$ind][$aduind][$key] = $details[$key];
10916 }
10917 }
10918 foreach ($pre_pax_fields as $key => $v) {
10919 if (isset($pax_fields[$key])) {
10920 // we must have parsed this back-end field already
10921 continue;
10922 }
10923 if (isset($details[$key]) && ((is_scalar($details[$key]) && strlen($details[$key])) || !empty($details[$key]))) {
10924 if (!isset($guests_details[$ind])) {
10925 $guests_details[$ind] = array();
10926 }
10927 if (!isset($guests_details[$ind][$aduind])) {
10928 $guests_details[$ind][$aduind] = array();
10929 }
10930 if (!isset($guests_details[$ind][$aduind][$key])) {
10931 $guests_details[$ind][$aduind][$key] = $details[$key];
10932 }
10933 }
10934 }
10935 }
10936 }
10937 if (count($guests_details)) {
10938 // current pax data may contain some extra information collected via front-end pre-checkin so we need to merge them
10939 $curpaxdata = json_decode($custorder['pax_data'], true);
10940 if (is_array($curpaxdata) && count($curpaxdata)) {
10941 foreach ($guests_details as $ind => $groom) {
10942 foreach ($groom as $aduind => $aduinfo) {
10943 if (isset($curpaxdata[$ind][$aduind])) {
10944 $guests_details[$ind][$aduind] = array_merge($curpaxdata[$ind][$aduind], $guests_details[$ind][$aduind]);
10945 // unset some default pax fields that were not specified now, or data cannot be deleted for guests
10946 foreach ($guests_details[$ind][$aduind] as $key => $det) {
10947 if (isset($pguests[$ind][$aduind][$key]) && empty($pguests[$ind][$aduind][$key])) {
10948 // this default pax field was specified as empty now, so we cannot merge it
10949 unset($guests_details[$ind][$aduind][$key]);
10950 }
10951 }
10952 }
10953 }
10954 }
10955 }
10956 //
10957 $q = "UPDATE `#__vikbooking_customers_orders` SET `pax_data`=".$dbo->quote(json_encode($guests_details))." WHERE `id`=".$custorder['id'].";";
10958 $dbo->setQuery($q);
10959 $dbo->execute();
10960 }
10961
10962 //'checked' status comments
10963 $q = "UPDATE `#__vikbooking_customers_orders` SET `comments`=".$dbo->quote($pcomments)." WHERE `id`=".$custorder['id'].";";
10964 $dbo->setQuery($q);
10965 $dbo->execute();
10966
10967 $app->enqueueMessage(JText::translate('VBOCHECKINSTATUSUPDATED'));
10968 $app->redirect('index.php?option=com_vikbooking&task=bookingcheckin&cid[]='.$row['id'].($pcheckin_action != $row['checked'] ? '&changed=1' : '').($ptmpl == 'component' ? '&tmpl=component' : ''));
10969 exit;
10970 }
10971
10972 public function alterbooking()
10973 {
10974 $dbo = JFactory::getDbo();
10975 $app = JFactory::getApplication();
10976 $user = JFactory::getUser();
10977
10978 $response = array(
10979 'esit' => 1,
10980 'message' => '',
10981 'vcm' => '',
10982 );
10983
10984 // must be a string as it may contain a dash
10985 $pidorder = VikRequest::getString('idorder', '', 'request');
10986 $pidorder = intval(str_replace('-', '', $pidorder));
10987
10988 $poldidroom = VikRequest::getInt('oldidroom', '', 'request');
10989 $pidroom = VikRequest::getInt('idroom', 0, 'request');
10990 $pfromdate = VikRequest::getString('fromdate', '', 'request');
10991 $ptodate = VikRequest::getString('todate', '', 'request');
10992 $pdebug = VikRequest::getInt('e4j_debug', 0, 'request');
10993 if ($pdebug == 1) {
10994 echo 'e4j.error.'.print_r($app->input->post->getArray(), true);
10995 exit;
10996 }
10997
10998 $nowdf = VikBooking::getDateFormat(true);
10999 if ($nowdf == "%d/%m/%Y") {
11000 $df = 'd/m/Y';
11001 } elseif ($nowdf == "%m/%d/%Y") {
11002 $df = 'm/d/Y';
11003 } else {
11004 $df = 'Y/m/d';
11005 }
11006 $pcheckinh = 0;
11007 $pcheckinm = 0;
11008 $pcheckouth = 0;
11009 $pcheckoutm = 0;
11010 $timeopst = VikBooking::getTimeOpenStore();
11011 if (is_array($timeopst)) {
11012 $opent = VikBooking::getHoursMinutes($timeopst[0]);
11013 $closet = VikBooking::getHoursMinutes($timeopst[1]);
11014 $pcheckinh = $opent[0];
11015 $pcheckinm = $opent[1];
11016 $pcheckouth = $closet[0];
11017 $pcheckoutm = $closet[1];
11018 }
11019 $info_tsto = getdate(strtotime($ptodate));
11020 $actualtsto = mktime(0, 0, 0, $info_tsto['mon'], ($info_tsto['mday'] + 1), $info_tsto['year']);
11021 $first = VikBooking::getDateTimestamp(date($df, strtotime($pfromdate)), $pcheckinh, $pcheckinm);
11022 $second = VikBooking::getDateTimestamp(date($df, $actualtsto), $pcheckouth, $pcheckoutm);
11023 $ptodate = date('Y-m-d', $second);
11024 if (!($second > $first)) {
11025 echo 'e4j.error.1 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11026 exit;
11027 }
11028 if (!($pidorder > 0) || !($pidroom > 0) || empty($pfromdate) || empty($ptodate)) {
11029 echo 'e4j.error.2 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11030 exit;
11031 }
11032
11033 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $pidorder . " AND `status`='confirmed'";
11034 $dbo->setQuery($q, 0, 1);
11035 $dbo->execute();
11036 if (!$dbo->getNumRows()) {
11037 echo 'e4j.error.3 '.addslashes(JText::translate('VBOVWALTBKERRMISSDATA'));
11038 exit;
11039 }
11040 $ord = $dbo->loadAssoc();
11041
11042 $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;";
11043 $dbo->setQuery($q);
11044 $dbo->execute();
11045 $ordersrooms = $dbo->loadAssocList();
11046
11047 // store for VCM the current rooms before the modification
11048 $ord['rooms_info'] = $ordersrooms;
11049
11050 // package or custom rate
11051 $is_package = !empty($ord['pkg']) ? true : false;
11052 $is_cust_cost = false;
11053 foreach ($ordersrooms as $kor => $or) {
11054 if ($is_package !== true && !empty($or['cust_cost']) && $or['cust_cost'] > 0.00) {
11055 $is_cust_cost = true;
11056 break;
11057 }
11058 }
11059
11060 // availability helper
11061 $av_helper = VikBooking::getAvailabilityInstance();
11062
11063 // room stay dates in case of split stay
11064 $room_stay_dates = [];
11065 if ($ord['split_stay']) {
11066 // no need to get the transient based on booking status, as the booking must be confirmed
11067 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11068 // immediately count the number of nights of stay for each split room
11069 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11070 $room_stay_dates[$sps_r_k]['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11071 }
11072 }
11073
11074 // determine if dates have changed
11075 $dates_changed = false;
11076 if (date('Y-m-d', $ord['checkin']) != $pfromdate || date('Y-m-d', $ord['checkout']) != $ptodate) {
11077 $dates_changed = true;
11078 }
11079
11080 $toswitch = array();
11081 $idbooked = array();
11082 $rooms_units = array();
11083 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms`;";
11084 $dbo->setQuery($q);
11085 $dbo->execute();
11086 $all_rooms = $dbo->loadAssocList();
11087 foreach ($all_rooms as $rr) {
11088 $rooms_units[$rr['id']]['name'] = $rr['name'];
11089 $rooms_units[$rr['id']]['units'] = $rr['units'];
11090 }
11091
11092 // switch room
11093 if ($poldidroom != $pidroom) {
11094 foreach ($ordersrooms as $ind => $or) {
11095 if ($poldidroom == $or['idroom'] && array_key_exists($pidroom, $rooms_units)) {
11096 if (!isset($idbooked[$or['idroom']])) {
11097 $idbooked[$or['idroom']] = 0;
11098 }
11099 // $idbooked is not really needed as switch is never made for the same room id
11100 $idbooked[$or['idroom']]++;
11101 //
11102 $orkey = count($toswitch);
11103 $toswitch[$orkey]['from'] = $or['idroom'];
11104 $toswitch[$orkey]['to'] = $pidroom;
11105 $toswitch[$orkey]['record'] = $or;
11106 $toswitch[$orkey]['record_ind'] = $ind;
11107 break;
11108 }
11109 }
11110 }
11111 if (count($toswitch)) {
11112 foreach ($toswitch as $ksw => $rsw) {
11113 $plusunit = array_key_exists($rsw['to'], $idbooked) ? $idbooked[$rsw['to']] : 0;
11114 $room_checkin = $ord['checkin'];
11115 $room_checkout = $ord['checkout'];
11116 if ($ord['split_stay'] && count($room_stay_dates) && isset($room_stay_dates[$rsw['record_ind']]) && $room_stay_dates[$rsw['record_ind']]['idroom'] == $rsw['from']) {
11117 $room_checkin = $room_stay_dates[$rsw['record_ind']]['checkin'];
11118 $room_checkout = $room_stay_dates[$rsw['record_ind']]['checkout'];
11119 }
11120 if (!VikBooking::roomBookable($rsw['to'], ($rooms_units[$rsw['to']]['units'] + $plusunit), $room_checkin, $room_checkout)) {
11121 // the room is not available
11122 unset($toswitch[$ksw]);
11123 echo 'e4j.error.'.JText::sprintf('VBSWITCHRERR', $rsw['record']['name'], $rooms_units[$rsw['to']]['name']);
11124 exit;
11125 }
11126 }
11127 if (count($toswitch)) {
11128 //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)
11129 reset($ordersrooms);
11130 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=".$ordersrooms[0]['id'].";";
11131 $dbo->setQuery($q);
11132 $dbo->execute();
11133 //
11134 foreach ($toswitch as $ksw => $rsw) {
11135 // update room reservation record
11136 $q = "UPDATE `#__vikbooking_ordersrooms` SET `idroom`=" . $rsw['to'] . ",`idtar`=NULL,`roomindex`=NULL,`room_cost`=NULL WHERE `id`=" . $rsw['record']['id'] . ";";
11137 $dbo->setQuery($q);
11138 $dbo->execute();
11139 $response['message'] .= JText::sprintf('VBOVWALTBKSWITCHROK', $rsw['record']['name'], $rooms_units[$rsw['to']]['name'])."\n";
11140
11141 // update Notes field for this booking to keep track of the previous room that was assigned
11142 $prev_room_name = array_key_exists($rsw['from'], $rooms_units) ? $rooms_units[$rsw['from']]['name'] : '';
11143 if (!empty($prev_room_name)) {
11144 $new_notes = JText::sprintf('VBOPREVROOMMOVED', $prev_room_name, date($df.' H:i:s'))."\n".$ord['adminnotes'];
11145 $q = "UPDATE `#__vikbooking_orders` SET `adminnotes`=".$dbo->quote($new_notes)." WHERE `id`=".(int)$ord['id'].";";
11146 $dbo->setQuery($q);
11147 $dbo->execute();
11148 }
11149
11150 if ($ord['status'] == 'confirmed') {
11151 // update room record in _busy
11152 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'])) {
11153 // in case of a split stay it is fundamental to update the exact busy record ID
11154 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=" . $rsw['to'] . " WHERE `id`=" . (int)$room_stay_dates[$rsw['record_ind']]['id'];
11155 $dbo->setQuery($q);
11156 $dbo->execute();
11157 } else {
11158 // regular processing of a room ID for a reservation, no matter which one, we switch it
11159 $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;";
11160 $dbo->setQuery($q);
11161 $dbo->execute();
11162 if ($dbo->getNumRows() == 1) {
11163 $cur_busy = $dbo->loadAssocList();
11164 $q = "UPDATE `#__vikbooking_busy` SET `idroom`=".$rsw['to']." WHERE `id`=".$cur_busy[0]['id']." AND `idroom`=".$cur_busy[0]['idroom']." LIMIT 1;";
11165 $dbo->setQuery($q);
11166 $dbo->execute();
11167 }
11168 }
11169
11170 // if automated updates enabled, keep $response['vcm'] empty
11171 // Invoke Channel Manager
11172 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11173 $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>';
11174 }
11175 } elseif ($ord['status'] == 'standby') {
11176 // remove record in _tmplock
11177 $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($ord['id']) . ";";
11178 $dbo->setQuery($q);
11179 $dbo->execute();
11180 }
11181 }
11182
11183 // check if sub-units should be assigned again when switching room
11184 if (!$dates_changed && !$ord['split_stay'] && VikBooking::autoRoomUnit()) {
11185 $new_order_rooms = VikBooking::loadOrdersRoomsData($ord['id']);
11186 $room_indexes_usemap = [];
11187 foreach ($new_order_rooms as $kor => $or) {
11188 $num = $kor + 1;
11189 // assign room specific unit
11190 $room_indexes = VikBooking::getRoomUnitNumsAvailable($ord, $or['idroom']);
11191 $use_ind_key = 0;
11192 if ($room_indexes) {
11193 if (!array_key_exists($or['idroom'], $room_indexes_usemap)) {
11194 $room_indexes_usemap[$or['idroom']] = $use_ind_key;
11195 } else {
11196 $use_ind_key = $room_indexes_usemap[$or['idroom']];
11197 }
11198 $q = "UPDATE `#__vikbooking_ordersrooms` SET `roomindex`=".(int)$room_indexes[$use_ind_key]." WHERE `id`=".(int)$or['id'].";";
11199 $dbo->setQuery($q);
11200 $dbo->execute();
11201 $room_indexes_usemap[$or['idroom']]++;
11202 }
11203 }
11204 }
11205
11206 // do not terminate the process when there is a switch, proceed to check the dates.
11207 }
11208 }
11209
11210 // change dates
11211 if ($dates_changed) {
11212 if ($ord['split_stay']) {
11213 // we do not allow to drag and change dates for rooms in a split stay reservation
11214 echo 'e4j.error.' . JText::sprintf('VBO_BOOK_SPLIT_STAY_CANNOTDRAG', $ord['id']);
11215 exit;
11216 }
11217
11218 // total nights of stay
11219 $daysdiff = $ord['days'];
11220
11221 // re-read ordersrooms (as rooms may have been switched)
11222 $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;";
11223 $dbo->setQuery($q);
11224 $dbo->execute();
11225 $ordersrooms = $dbo->loadAssocList();
11226
11227 $groupdays = VikBooking::getGroupDays($first, $second, $daysdiff);
11228 $opertwounits = true;
11229 $units_counter = array();
11230 foreach ($ordersrooms as $ind => $or) {
11231 if (!isset($units_counter[$or['idroom']])) {
11232 $units_counter[$or['idroom']] = -1;
11233 }
11234 $units_counter[$or['idroom']]++;
11235 }
11236
11237 foreach ($ordersrooms as $ind => $or) {
11238 $num = $ind + 1;
11239 $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'] . ";";
11240 $dbo->setQuery($check);
11241 $dbo->execute();
11242 if ($dbo->getNumRows() > 0) {
11243 $busy = $dbo->loadAssocList();
11244 foreach ($groupdays as $gday) {
11245 $bfound = 0;
11246 foreach ($busy as $bu) {
11247 if ($gday >= $bu['checkin'] && $gday <= $bu['realback']) {
11248 $bfound++;
11249 }
11250 }
11251 if ($bfound >= ($or['units'] - $units_counter[$or['idroom']]) || !VikBooking::roomNotLocked($or['idroom'], $or['units'], $first, $second)) {
11252 $opertwounits = false;
11253 break 2;
11254 }
11255 }
11256 }
11257 }
11258 if ($opertwounits !== true) {
11259 $response['esit'] = 0;
11260 $response['message'] = JText::translate('VBROOMNOTRIT')." ".date($df.' H:i', $first)." ".JText::translate('VBROOMNOTCONSTO')." ".date($df.' H:i', $second);
11261 echo json_encode($response);
11262 exit;
11263 }
11264
11265 // update dates and busy records
11266 $realback = VikBooking::getHoursRoomAvail() * 3600;
11267 $realback += $second;
11268 $q = "UPDATE `#__vikbooking_orders` SET `checkin`='".$first."', `checkout`='".$second."' WHERE `id`=".$ord['id'].";";
11269 $dbo->setQuery($q);
11270 $dbo->execute();
11271 if ($ord['status'] == 'confirmed') {
11272 $q = "SELECT `b`.`id` FROM `#__vikbooking_busy` AS `b`,`#__vikbooking_ordersbusy` AS `ob` WHERE `b`.`id`=`ob`.`idbusy` AND `ob`.`idorder`=".$ord['id'].";";
11273 $dbo->setQuery($q);
11274 $dbo->execute();
11275 $allbusy = $dbo->loadAssocList();
11276 foreach ($allbusy as $bb) {
11277 $q = "UPDATE `#__vikbooking_busy` SET `checkin`='".$first."', `checkout`='".$second."', `realback`='".$realback."' WHERE `id`='".$bb['id']."';";
11278 $dbo->setQuery($q);
11279 $dbo->execute();
11280 }
11281 // if automated updates enabled, keep $response['vcm'] empty
11282 // Invoke Channel Manager
11283 if (file_exists(VCM_SITE_PATH . DIRECTORY_SEPARATOR . "helpers" . DIRECTORY_SEPARATOR . "synch.vikbooking.php")) {
11284 $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>';
11285 }
11286 }
11287 $response['message'] .= JText::translate('RESUPDATED')."\n";
11288 }
11289
11290 if (count($toswitch)) {
11291 /**
11292 * Rooms have changed so the new rates must be re-calculated.
11293 * Maybe they should be calculated in any case, even if just
11294 * the dates have changed. For the moment the rates are reset.
11295 */
11296 }
11297
11298 // unset any previously booked room due to calendar sharing
11299 VikBooking::cleanSharedCalendarsBusy($ord['id']);
11300 // check if some of the rooms booked have shared calendars
11301 VikBooking::updateSharedCalendars($ord['id']);
11302 //
11303
11304 //Booking History
11305 VikBooking::getBookingHistoryInstance()->setBid($ord['id'])->store('MB', "({$user->name}) " . VikBooking::getLogBookingModification($ord));
11306 //
11307
11308 $vcm_autosync = VikBooking::vcmAutoUpdate();
11309 if ($vcm_autosync > 0 && !empty($response['vcm'])) {
11310 //unset the vcm property as no buttons should be displayed when in auto-sync
11311 $response['vcm'] = '';
11312 $vcm_obj = VikBooking::getVcmInvoker();
11313 $vcm_obj->setOids(array($ord['id']))->setSyncType('modify')->setOriginalBooking($ord);
11314 $sync_result = $vcm_obj->doSync();
11315 if ($sync_result === false) {
11316 $response['message'] .= JText::translate('VBCHANNELMANAGERRESULTKO')." (".$vcm_obj->getError().")\n";
11317 }
11318 }
11319
11320 // in case of error but not empty VCM message, set an error that will be displayed after the mustReload
11321 if ($response['esit'] < 1 && !empty($response['vcm'])) {
11322 VikError::raiseNotice('', $response['vcm']);
11323 }
11324
11325 $response['message'] = nl2br($response['message']);
11326 echo json_encode($response);
11327 exit;
11328 }
11329
11330 public function modroomrateplans() {
11331 $dbo = JFactory::getDBO();
11332 $session = JFactory::getSession();
11333 $updforvcm = $session->get('vbVcmRatesUpd', '');
11334 $updforvcm = empty($updforvcm) || !is_array($updforvcm) ? array() : $updforvcm;
11335 $pid_room = VikRequest::getInt('id_room', '', 'request');
11336 $pid_price = VikRequest::getInt('id_price', '', 'request');
11337 $ptype = VikRequest::getString('type', '', 'request');
11338 $pfromdate = VikRequest::getString('fromdate', '', 'request');
11339 $ptodate = VikRequest::getString('todate', '', 'request');
11340 if (empty($pid_room) || empty($pid_price) || empty($ptype) || empty($pfromdate) || empty($ptodate) || !(strtotime($pfromdate) > 0) || !(strtotime($ptodate) > 0)) {
11341 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS'));
11342 exit;
11343 }
11344 $price_record = array();
11345 $q = "SELECT * FROM `#__vikbooking_prices` WHERE `id`=".$pid_price.";";
11346 $dbo->setQuery($q);
11347 $dbo->execute();
11348 if ($dbo->getNumRows() > 0) {
11349 $price_record = $dbo->loadAssoc();
11350 }
11351 if (!count($price_record) > 0) {
11352 echo 'e4j.error.'.addslashes(JText::translate('VBRATESOVWERRMODRPLANS')).'.';
11353 exit;
11354 }
11355 $current_closed = array();
11356 if (!empty($price_record['closingd'])) {
11357 $current_closed = json_decode($price_record['closingd'], true);
11358 }
11359 $current_closed = !is_array($current_closed) ? array() : $current_closed;
11360 $start_ts = strtotime($pfromdate);
11361 $end_ts = strtotime($ptodate);
11362 $infostart = getdate($start_ts);
11363 $all_days = array();
11364 $output = array();
11365 while ($infostart[0] > 0 && $infostart[0] <= $end_ts) {
11366 $all_days[] = date('Y-m-d', $infostart[0]);
11367 $indkey = $infostart['mday'].'-'.$infostart['mon'].'-'.$infostart['year'].'-'.$pid_price;
11368 $output[$indkey] = array();
11369 $infostart = getdate(mktime(0, 0, 0, $infostart['mon'], ($infostart['mday'] + 1), $infostart['year']));
11370 }
11371 if ($ptype == 'close') {
11372 if (!array_key_exists($pid_room, $current_closed)) {
11373 $current_closed[$pid_room] = array();
11374 }
11375 foreach ($all_days as $daymod) {
11376 if (!in_array($daymod, $current_closed[$pid_room])) {
11377 $current_closed[$pid_room][] = $daymod;
11378 }
11379 }
11380 } else {
11381 //open
11382 if (array_key_exists($pid_room, $current_closed)) {
11383 foreach ($all_days as $daymod) {
11384 if (in_array($daymod, $current_closed[$pid_room])) {
11385 foreach ($current_closed[$pid_room] as $ck => $cv) {
11386 if ($daymod == $cv) {
11387 unset($current_closed[$pid_room][$ck]);
11388 }
11389 }
11390 }
11391 }
11392 } else {
11393 $current_closed[$pid_room] = array();
11394 }
11395 }
11396 if (!count($current_closed[$pid_room]) > 0) {
11397 unset($current_closed[$pid_room]);
11398 }
11399 $q = "UPDATE `#__vikbooking_prices` SET `closingd`=".(count($current_closed) > 0 ? $dbo->quote(json_encode($current_closed)) : "NULL")." WHERE `id`=".(int)$pid_price.";";
11400 $dbo->setQuery($q);
11401 $dbo->execute();
11402 $oldcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-on' : 'vbo-roverw-rplan-off';
11403 $newcsscls = $ptype == 'close' ? 'vbo-roverw-rplan-off' : 'vbo-roverw-rplan-on';
11404 foreach ($output as $ok => $ov) {
11405 $output[$ok] = array('oldcls' => $oldcsscls, 'newcls' => $newcsscls);
11406 }
11407 //update session values
11408 $updforvcm['count'] = array_key_exists('count', $updforvcm) && !empty($updforvcm['count']) ? ($updforvcm['count'] + 1) : 1;
11409 if (array_key_exists('dfrom', $updforvcm) && !empty($updforvcm['dfrom'])) {
11410 $updforvcm['dfrom'] = $updforvcm['dfrom'] > $start_ts ? $start_ts : $updforvcm['dfrom'];
11411 } else {
11412 $updforvcm['dfrom'] = $start_ts;
11413 }
11414 if (array_key_exists('dto', $updforvcm) && !empty($updforvcm['dto'])) {
11415 $updforvcm['dto'] = $updforvcm['dto'] < $end_ts ? $end_ts : $updforvcm['dto'];
11416 } else {
11417 $updforvcm['dto'] = $end_ts;
11418 }
11419 if (array_key_exists('rooms', $updforvcm) && is_array($updforvcm['rooms'])) {
11420 if (!in_array($pid_room, $updforvcm['rooms'])) {
11421 $updforvcm['rooms'][] = $pid_room;
11422 }
11423 } else {
11424 $updforvcm['rooms'] = array($pid_room);
11425 }
11426 if (array_key_exists('rplans', $updforvcm) && is_array($updforvcm['rplans'])) {
11427 if (array_key_exists($pid_room, $updforvcm['rplans'])) {
11428 if (!in_array($pid_price, $updforvcm['rplans'][$pid_room])) {
11429 $updforvcm['rplans'][$pid_room][] = $pid_price;
11430 }
11431 } else {
11432 $updforvcm['rplans'][$pid_room] = array($pid_price);
11433 }
11434 } else {
11435 $updforvcm['rplans'] = array($pid_room => array($pid_price));
11436 }
11437 $session->set('vbVcmRatesUpd', $updforvcm);
11438 //
11439 $pdebug = VikRequest::getInt('e4j_debug', '', 'request');
11440 if ($pdebug == 1) {
11441 echo "e4j.error.\n".print_r($current_closed, true)."\n";
11442 echo print_r($output, true)."\n\n";
11443 echo print_r($all_days, true)."\n";
11444 }
11445 echo json_encode($output);
11446 exit;
11447 }
11448
11449 public function icsexportlaunch() {
11450 $dbo = JFactory::getDBO();
11451 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11452 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11453 $pstatus = VikRequest::getString('status', '', 'request');
11454 $validstatus = array('confirmed', 'standby', 'cancelled');
11455 $filterstatus = '';
11456 $filterfirst = 0;
11457 $filtersecond = 0;
11458 $nowdf = VikBooking::getDateFormat(true);
11459 if ($nowdf == "%d/%m/%Y") {
11460 $df = 'd/m/Y';
11461 } elseif ($nowdf == "%m/%d/%Y") {
11462 $df = 'm/d/Y';
11463 } else {
11464 $df = 'Y/m/d';
11465 }
11466 $currencyname = VikBooking::getCurrencyName();
11467 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11468 $filterstatus = $pstatus;
11469 }
11470 if (!empty($pcheckindate)) {
11471 if (VikBooking::dateIsValid($pcheckindate)) {
11472 $first=VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11473 $filterfirst = $first;
11474 }
11475 }
11476 if (!empty($pcheckoutdate)) {
11477 if (VikBooking::dateIsValid($pcheckoutdate)) {
11478 $second=VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11479 if ($second > $first) {
11480 $filtersecond = $second;
11481 }
11482 }
11483 }
11484 $clause = array();
11485 if ($filterfirst > 0) {
11486 $clause[] = "`o`.`checkin` >= ".$filterfirst;
11487 }
11488 if ($filtersecond > 0) {
11489 $clause[] = "`o`.`checkout` <= ".$filtersecond;
11490 }
11491 if (!empty($filterstatus)) {
11492 $clause[] = "`o`.`status` = '".$filterstatus."'";
11493 }
11494 $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;";
11495 $dbo->setQuery($q);
11496 $dbo->execute();
11497 if ($dbo->getNumRows() > 0) {
11498 $orders = $dbo->loadAssocList();
11499 $icscontent = "BEGIN:VCALENDAR\n";
11500 $icscontent .= "VERSION:2.0\n";
11501 $icscontent .= "PRODID:-//e4j//VikBooking//EN\n";
11502 $icscontent .= "CALSCALE:GREGORIAN\n";
11503 $str = "";
11504 foreach ($orders as $kord => $ord) {
11505 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11506 continue;
11507 }
11508 $usecurrencyname = $currencyname;
11509 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11510 $statusstr = '';
11511 if ($ord['status'] == 'confirmed') {
11512 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11513 } elseif ($ord['status'] == 'standby') {
11514 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11515 } elseif ($ord['status'] == 'cancelled') {
11516 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11517 }
11518 $uri = JURI::root().'index.php?option=com_vikbooking&view=booking&sid='.$ord['sid'].'&ts='.$ord['ts'];
11519 /**
11520 * @wponly Rewrite URI for front-end
11521 */
11522 $uri = str_replace(JUri::root(), '', $uri);
11523 $model = JModel::getInstance('vikbooking', 'shortcodes');
11524 $itemid = $model->best('booking');
11525 if ($itemid) {
11526 $uri = JRoute::rewrite($uri . "&Itemid={$itemid}", false);
11527 }
11528 //
11529 $ordnumbstr = $ord['id'].(!empty($ord['confirmnumber']) ? ' - '.$ord['confirmnumber'] : '').(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '').' - '.$statusstr;
11530 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11531 $totalstring = ($ord['total'] > 0 ? ($usecurrencyname.' '.VikBooking::numberFormat($ord['total'])) : '');
11532 $totalpaidstring = ($ord['totpaid'] > 0 ? (' ('.VikBooking::numberFormat($ord['totpaid']).')') : '');
11533 $description = JText::sprintf('VBICSEXPDESCRIPTION', $ordnumbstr."\\n", $peoplestr."\\n", $ord['days']."\\n", $totalstring.$totalpaidstring."\\n", "\\n".str_replace("\n", "\\n", trim($ord['custdata'])));
11534 $str .= "BEGIN:VEVENT\n";
11535 $str .= "DTEND:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkout']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11536 $str .= "UID:" . uniqid() . "\n";
11537 $str .= "DTSTAMP:" . JFactory::getDate(date('Y-m-d H:i:s'), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11538 $str .= ((strlen($description) > 0 ) ? "DESCRIPTION:".preg_replace('/([\,;])/','\\\$1', $description)."\n" : "");
11539 $str .= "URL;VALUE=URI:" . preg_replace('/([\,;])/','\\\$1', $uri) . "\n";
11540 $str .= "SUMMARY:" . JText::sprintf('VBICSEXPSUMMARY', date($df, $ord['checkin'])) . "\n";
11541 $str .= "DTSTART:" . JFactory::getDate(date('Y-m-d H:i:s', $ord['checkin']), date_default_timezone_get())->format('Ymd\THis\Z') . "\n";
11542 $str .= "END:VEVENT\n";
11543 }
11544 $icscontent .= $str;
11545 $icscontent .= "END:VCALENDAR\n";
11546 //download file from buffer
11547 header("Content-Type: application/octet-stream; ");
11548 header("Cache-Control: no-store, no-cache");
11549 header('Content-Disposition: attachment; filename="bookings_export.ics"');
11550 $f = fopen('php://output', "w");
11551 fwrite($f, $icscontent);
11552 fclose($f);
11553 exit;
11554 } else {
11555 VikError::raiseWarning('', JText::translate('VBICSEXPNORECORDS'));
11556 $mainframe = JFactory::getApplication();
11557 $mainframe->redirect("index.php?option=com_vikbooking&task=icsexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11558 }
11559 }
11560
11561 public function csvexportlaunch()
11562 {
11563 $dbo = JFactory::getDbo();
11564 $app = JFactory::getApplication();
11565
11566 $pdatefilt = VikRequest::getString('datefilt', '', 'request');
11567 $proomfilt = VikRequest::getString('roomfilt', '', 'request');
11568 $pchfilt = VikRequest::getString('chfilt', '', 'request');
11569 $ppayfilt = VikRequest::getString('payfilt', '', 'request');
11570 $pcheckindate = VikRequest::getString('checkindate', '', 'request');
11571 $pcheckoutdate = VikRequest::getString('checkoutdate', '', 'request');
11572 $pstatus = VikRequest::getString('status', '', 'request');
11573 $pcatfilt = VikRequest::getInt('catfilt', 0, 'request');
11574 $pformat = VikRequest::getString('format', 'csv', 'request');
11575
11576 // let the report class (a generic one) generate the CSV file in the proper format
11577 $report_obj = VikBooking::getReportInstance('revenue')->setExportCSVFormat($pformat);
11578
11579 $validstatus = array('confirmed', 'standby', 'cancelled');
11580 $validdates = array('ts', 'checkin', 'checkout');
11581
11582 $filterdate = '';
11583 $filterstatus = '';
11584 $first = 0;
11585 $filterfirst = 0;
11586 $filtersecond = 0;
11587 $nowdf = VikBooking::getDateFormat(true);
11588 if ($nowdf == "%d/%m/%Y") {
11589 $df = 'd/m/Y';
11590 } elseif ($nowdf == "%m/%d/%Y") {
11591 $df = 'm/d/Y';
11592 } else {
11593 $df = 'Y/m/d';
11594 }
11595 $datesep = VikBooking::getDateSeparator(true);
11596 $currencyname = VikBooking::getCurrencyName();
11597
11598 if (!empty($pstatus) && in_array($pstatus, $validstatus)) {
11599 $filterstatus = $pstatus;
11600 }
11601 if (!empty($pdatefilt) && in_array($pdatefilt, $validdates)) {
11602 $filterdate = $pdatefilt;
11603 }
11604 if (!empty($pcheckindate) && !empty($filterdate)) {
11605 if (VikBooking::dateIsValid($pcheckindate)) {
11606 $first = VikBooking::getDateTimestamp($pcheckindate, '0', '0');
11607 $filterfirst = $first;
11608 }
11609 }
11610 if (!empty($pcheckoutdate) && !empty($filterdate)) {
11611 if (VikBooking::dateIsValid($pcheckoutdate)) {
11612 $second = VikBooking::getDateTimestamp($pcheckoutdate, '23', '59');
11613 if ($second > $first) {
11614 $filtersecond = $second;
11615 }
11616 }
11617 }
11618 $clause = array();
11619 if ($filterfirst > 0) {
11620 $clause[] = "`o`.`".$filterdate."` >= ".$filterfirst;
11621 }
11622 if ($filtersecond > 0) {
11623 $clause[] = "`o`.`".$filterdate."` <= ".$filtersecond;
11624 }
11625 if (!empty($filterstatus)) {
11626 $clause[] = "`o`.`status` = '".$filterstatus."'";
11627 }
11628 if (!empty($pchfilt)) {
11629 $clause[] = "`o`.`channel` LIKE ".$dbo->quote("%".$pchfilt."%");
11630 }
11631 if (!empty($ppayfilt)) {
11632 $clause[] = "`o`.`idpayment` LIKE '".$ppayfilt."=%'";
11633 }
11634 if (!empty($proomfilt)) {
11635 $clause[] = "`or`.`idroom` = '".(int)$proomfilt."'";
11636 }
11637
11638 if (!empty($pcatfilt)) {
11639 $room_cat_ids = array();
11640 $q = "SELECT `id`,`idcat` FROM `#__vikbooking_rooms` WHERE `idcat` LIKE " . $dbo->quote("%$pcatfilt%");
11641 $dbo->setQuery($q);
11642 $dbo->execute();
11643 if ($dbo->getNumRows()) {
11644 $records = $dbo->loadAssocList();
11645 foreach ($records as $rcat) {
11646 $parts = explode(';', $rcat['idcat']);
11647 if (in_array($pcatfilt, $parts)) {
11648 $room_cat_ids[] = $rcat['id'];
11649 }
11650 }
11651 }
11652 if (count($room_cat_ids)) {
11653 $clause[] = "`or`.`idroom` IN (" . implode(', ', $room_cat_ids) . ")";
11654 }
11655 }
11656
11657 $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;";
11658 $dbo->setQuery($q);
11659 $orders = $dbo->loadAssocList();
11660 if (!$orders) {
11661 $app->enqueueMessage(JText::translate('VBCSVEXPNORECORDS'), 'error');
11662 $app->redirect("index.php?option=com_vikbooking&task=csvexportprepare&checkindate=".$pcheckindate."&checkoutdate=".$pcheckoutdate."&status=".$pstatus."&tmpl=component");
11663 $app->close();
11664 }
11665
11666 // options
11667 $all_options = array();
11668 $q = "SELECT * FROM `#__vikbooking_optionals` ORDER BY `#__vikbooking_optionals`.`ordering` ASC;";
11669 $dbo->setQuery($q);
11670 $options = $dbo->loadAssocList();
11671 if ($options) {
11672 foreach ($options as $ok => $ov) {
11673 $all_options[$ov['id']] = $ov;
11674 }
11675 }
11676
11677 // set CSV columns
11678 $report_obj->setReportCols([
11679 [
11680 'label' => JText::translate('VBDASHBOOKINGID'),
11681 ],
11682 [
11683 'label' => JText::translate('VBPVIEWORDERSONE'),
11684 ],
11685 [
11686 'label' => JText::translate('VBCSVCHECKIN'),
11687 ],
11688 [
11689 'label' => JText::translate('VBCSVCHECKOUT'),
11690 ],
11691 [
11692 'label' => JText::translate('VBCSVNIGHTS'),
11693 ],
11694 [
11695 'label' => JText::translate('VBCSVROOM'),
11696 ],
11697 [
11698 'label' => JText::translate('VBCSVPEOPLE'),
11699 ],
11700 [
11701 'label' => JText::translate('VBCSVCUSTINFO'),
11702 ],
11703 [
11704 'label' => JText::translate('ORDER_SPREQUESTS'),
11705 ],
11706 [
11707 'label' => JText::translate('ORDER_NOTES'),
11708 ],
11709 [
11710 'label' => JText::translate('VBCSVCREATEDBY'),
11711 ],
11712 [
11713 'label' => JText::translate('VBCSVCUSTMAIL'),
11714 ],
11715 [
11716 'label' => JText::translate('ORDER_PHONE'),
11717 ],
11718 [
11719 'label' => JText::translate('VBCSVOPTIONS'),
11720 ],
11721 [
11722 'label' => JText::translate('VBCSVPAYMENTMETHOD'),
11723 ],
11724 [
11725 'label' => JText::translate('VBCSVORDIDCONFNUMB'),
11726 ],
11727 [
11728 'label' => JText::translate('VBCSVEXPFILTBSTATUS'),
11729 ],
11730 [
11731 'label' => JText::translate('VBCSVTOTAL'),
11732 ],
11733 [
11734 'label' => JText::translate('VBCSVTOTPAID'),
11735 ],
11736 [
11737 'label' => JText::translate('VBCSVTOTTAXES'),
11738 ],
11739 ]);
11740
11741 // prepare the container for the CSV rows
11742 $orderscsv = [];
11743
11744 // availability helper
11745 $av_helper = VikBooking::getAvailabilityInstance();
11746
11747 $room_inds = [];
11748 $room_stay_dates = [];
11749 foreach ($orders as $kord => $ord) {
11750 // room index in this booking
11751 if (!isset($room_inds[$ord['id']])) {
11752 $room_inds[$ord['id']] = -1;
11753 }
11754 $room_inds[$ord['id']]++;
11755
11756 /**
11757 * Split stay reservation.
11758 *
11759 * @since 1.16.0 (J) - 1.6.0 (WP)
11760 */
11761 $room_stay_dates = $room_inds[$ord['id']] > 0 ? $room_stay_dates : [];
11762 if ($ord['split_stay']) {
11763 if ($ord['status'] == 'confirmed') {
11764 $room_stay_dates = $av_helper->loadSplitStayBusyRecords($ord['id']);
11765 } else {
11766 $room_stay_dates = VBOFactory::getConfig()->getArray('split_stay_' . $ord['id'], []);
11767 }
11768 // immediately count the number of nights of stay for each split room
11769 foreach ($room_stay_dates as $sps_r_k => $sps_r_v) {
11770 if (!empty($sps_r_v['checkin_ts']) && !empty($sps_r_v['checkout_ts'])) {
11771 // overwrite values for compatibility with non-confirmed bookings
11772 $sps_r_v['checkin'] = $sps_r_v['checkin_ts'];
11773 $sps_r_v['checkout'] = $sps_r_v['checkout_ts'];
11774 }
11775 $sps_r_v['nights'] = $av_helper->countNightsOfStay($sps_r_v['checkin'], $sps_r_v['checkout']);
11776 // overwrite the whole array
11777 $room_stay_dates[$sps_r_k] = $sps_r_v;
11778 }
11779 }
11780
11781 // determine nights and dates for this room booking
11782 $booking_nights = $ord['days'];
11783 $booking_checkin = $ord['checkin'];
11784 $booking_checkout = $ord['checkout'];
11785 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']) {
11786 $booking_nights = $room_stay_dates[$room_inds[$ord['id']]]['nights'];
11787 $booking_checkin = $room_stay_dates[$room_inds[$ord['id']]]['checkin'];
11788 $booking_checkout = $room_stay_dates[$room_inds[$ord['id']]]['checkout'];
11789 }
11790
11791 $usecurrencyname = $currencyname;
11792 $usecurrencyname = !empty($ord['idorderota']) && !empty($ord['chcurrency']) ? $ord['chcurrency'] : $usecurrencyname;
11793 $peoplestr = ($ord['adults'] + $ord['children']).($ord['children'] > 0 ? ' ('.JText::translate('VBCSVCHILDREN').': '.$ord['children'].')' : '');
11794 $custinfostr = str_replace(",", " ", $ord['custdata']);
11795 $customer = VikBooking::getCPinIstance()->getCustomerFromBooking($ord['id']);
11796 if (count($customer)) {
11797 $custinfostr = $customer['first_name'] . ' ' . $customer['last_name'];
11798 }
11799 $special_requests = '';
11800 if (preg_match("/(?:special requests:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11801 $special_requests = $match[1];
11802 } elseif (preg_match("/(?:special request:\s*)(.*?)$/is", $ord['custdata'], $match)) {
11803 $special_requests = $match[1];
11804 } elseif (preg_match("/(?:special request\s*)(.*?)$/is", $ord['custdata'], $match)) {
11805 $special_requests = $match[1];
11806 } elseif (preg_match("/(?:" . JText::translate('ORDER_SPREQUESTS') . ":\s*)(.*?)$/is", $ord['custdata'], $match)) {
11807 $special_requests = $match[1];
11808 }
11809 $paystr = '';
11810 if (!empty($ord['idpayment'])) {
11811 $payparts = explode('=', $ord['idpayment']);
11812 $paystr = $payparts[1];
11813 }
11814 $ordnumbstr = $ord['id'].' - '.$ord['confirmnumber'].(!empty($ord['idorderota']) ? ' ('.ucwords($ord['channel']).')' : '');
11815 $statusstr = '';
11816 if ($ord['status'] == 'confirmed') {
11817 $statusstr = JText::translate('VBCSVSTATUSCONFIRMED');
11818 } elseif ($ord['status'] == 'standby') {
11819 $statusstr = JText::translate('VBCSVSTATUSSTANDBY');
11820 } elseif ($ord['status'] == 'cancelled') {
11821 $statusstr = JText::translate('VBCSVSTATUSCANCELLED');
11822 }
11823 $totalstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['total']);
11824 if ($ord['roomsnum'] > 1) {
11825 // take the cost for the individual room
11826 $totalstring = !empty($ord['cust_cost']) && $ord['cust_cost'] > 0 ? ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['cust_cost'])) : ($usecurrencyname . ' ' . VikBooking::numberFormat($ord['room_cost']));
11827 }
11828 $totalpaidstring = $usecurrencyname . ' ' . VikBooking::numberFormat($ord['totpaid']);
11829 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11830 // total paid will be printed only for the last room booked
11831 $totalpaidstring = '';
11832 }
11833 $options_str = '';
11834 if (!empty($ord['optionals'])) {
11835 $stepo = explode(";", $ord['optionals']);
11836 foreach ($stepo as $roptkey => $oo) {
11837 if (!empty($oo)) {
11838 $stept = explode(":", $oo);
11839 if (array_key_exists($stept[0], $all_options)) {
11840 $actopt = $all_options[$stept[0]];
11841 $optpcent = false;
11842 if (!empty($actopt['ageintervals']) && $ord['children'] > 0 && strstr($stept[1], '-') != false) {
11843 $optagenames = VikBooking::getOptionIntervalsAges($actopt['ageintervals']);
11844 $optagepcent = VikBooking::getOptionIntervalsPercentage($actopt['ageintervals']);
11845 $optageovrct = VikBooking::getOptionIntervalChildOverrides($actopt, $ord['adults'], $ord['children']);
11846 $child_num = VikBooking::getRoomOptionChildNumber($ord['optionals'], $actopt['id'], $roptkey, $ord['children']);
11847 $optagecosts = VikBooking::getOptionIntervalsCosts(isset($optageovrct['ageintervals_child' . ($child_num + 1)]) ? $optageovrct['ageintervals_child' . ($child_num + 1)] : $actopt['ageintervals']);
11848 $agestept = explode('-', $stept[1]);
11849 $stept[1] = $agestept[0];
11850 $chvar = $agestept[1];
11851 if (array_key_exists(($chvar - 1), $optagepcent) && $optagepcent[($chvar - 1)] > 0) {
11852 $optpcent = true;
11853 }
11854 $actopt['chageintv'] = $chvar;
11855 if (isset($optagenames[($chvar - 1)])) {
11856 $actopt['name'] .= ' ('.$optagenames[($chvar - 1)].')';
11857 }
11858 if (isset($optagecosts[($chvar - 1)])) {
11859 $realcost = (intval($actopt['perday']) == 1 ? (floatval($optagecosts[($chvar - 1)]) * $booking_nights * $stept[1]) : (floatval($optagecosts[($chvar - 1)]) * $stept[1]));
11860 } else {
11861 $realcost = 0;
11862 }
11863 } else {
11864 // VBO 1.11 - options percentage cost of the room total fee
11865 $optpcent = (int)$actopt['pcentroom'] ? true : $optpcent;
11866 //
11867 $realcost = (intval($actopt['perday']) == 1 ? ($actopt['cost'] * $booking_nights * $stept[1]) : ($actopt['cost'] * $stept[1]));
11868 }
11869 if ($actopt['maxprice'] > 0 && $realcost > $actopt['maxprice']) {
11870 $realcost=$actopt['maxprice'];
11871 if (intval($actopt['hmany']) == 1 && intval($stept[1]) > 1) {
11872 $realcost = $actopt['maxprice'] * $stept[1];
11873 }
11874 }
11875 $realcost = $actopt['perperson'] == 1 ? ($realcost * $ord['adults']) : $realcost;
11876 $tmpopr = VikBooking::sayOptionalsPlusIva($realcost, $actopt['idiva']);
11877 $options_str .= ($stept[1] > 1 ? $stept[1]." " : "").$actopt['name'].": ".(!$optpcent ? $currencyname : '')." ".VikBooking::numberFormat($tmpopr).($optpcent ? ' %' : '')." \r\n";
11878 }
11879 }
11880 }
11881 }
11882
11883 // custom extra costs
11884 if (!empty($ord['extracosts'])) {
11885 $cur_extra_costs = json_decode($ord['extracosts'], true);
11886 foreach ($cur_extra_costs as $eck => $ecv) {
11887 $ecplustax = !empty($ecv['idtax']) ? VikBooking::sayOptionalsPlusIva($ecv['cost'], $ecv['idtax']) : $ecv['cost'];
11888 $options_str .= $ecv['name'].": ".$currencyname." ".VikBooking::numberFormat($ecplustax)." \r\n";
11889 }
11890 }
11891
11892 // taxes
11893 $taxes_str = '';
11894 if ($ord['tot_taxes'] > 0.00) {
11895 $taxes_str .= $usecurrencyname.' '.VikBooking::numberFormat($ord['tot_taxes']);
11896 if (!empty($ord['aliq']) && !empty($ord['breakdown'])) {
11897 $tax_breakdown = json_decode($ord['breakdown'], true);
11898 $tax_breakdown = is_array($tax_breakdown) && count($tax_breakdown) > 0 ? $tax_breakdown : array();
11899 if (count($tax_breakdown)) {
11900 foreach ($tax_breakdown as $tbkk => $tbkv) {
11901 $tax_break_cost = $ord['tot_taxes'] * floatval($tbkv['aliq']) / $ord['aliq'];
11902 $taxes_str .= "\r\n".$tbkv['name'].": ".$usecurrencyname.' '.VikBooking::numberFormat($tax_break_cost);
11903 }
11904 }
11905 }
11906 }
11907 if (isset($orders[($kord + 1)]) && $orders[($kord + 1)]['id'] == $ord['id']) {
11908 // total taxes will be printed only for the last room booked
11909 $taxes_str = '';
11910 }
11911
11912 // created by
11913 $created_by = '';
11914 if (!empty($ord['ujid'])) {
11915 $creator = new JUser($ord['ujid']);
11916 if (property_exists($creator, 'name')) {
11917 $created_by = $creator->name.' ('.$creator->username.')';
11918 }
11919 }
11920 if (empty($created_by) && !empty($ord['t_first_name'])) {
11921 $created_by = $ord['t_first_name'].' '.$ord['t_last_name'];
11922 }
11923
11924 // push line for export
11925 $orderscsv[] = [
11926 [
11927 'value' => $ord['id'],
11928 ],
11929 [
11930 'value' => date(str_replace("/", $datesep, $df), $ord['ts']),
11931 ],
11932 [
11933 'value' => date(str_replace("/", $datesep, $df), $booking_checkin),
11934 ],
11935 [
11936 'value' => date(str_replace("/", $datesep, $df), $booking_checkout),
11937 ],
11938 [
11939 'value' => $booking_nights,
11940 ],
11941 [
11942 'value' => $ord['name'],
11943 ],
11944 [
11945 'value' => $peoplestr,
11946 ],
11947 [
11948 'value' => $custinfostr,
11949 ],
11950 [
11951 'value' => $special_requests,
11952 ],
11953 [
11954 'value' => $ord['adminnotes'],
11955 ],
11956 [
11957 'value' => $created_by,
11958 ],
11959 [
11960 'value' => $ord['custmail'],
11961 ],
11962 [
11963 'value' => $ord['phone'],
11964 ],
11965 [
11966 'value' => $options_str,
11967 ],
11968 [
11969 'value' => $paystr,
11970 ],
11971 [
11972 'value' => $ordnumbstr,
11973 ],
11974 [
11975 'value' => $statusstr,
11976 ],
11977 [
11978 'value' => $totalstring,
11979 ],
11980 [
11981 'value' => $totalpaidstring,
11982 ],
11983 [
11984 'value' => $taxes_str,
11985 ],
11986 ];
11987 }
11988
11989 // set CSV rows
11990 $report_obj->setReportRows($orderscsv);
11991
11992 // build lines to export
11993 $csvlines = $report_obj->getExportCSVLines($no_data = true);
11994
11995 // set export file name
11996 $report_obj->setExportCSVFileName('bookings_export_' . date('Y-m-d') . '.csv');
11997
11998 // force the download of the CSV file
11999 $report_obj->outputHeaders();
12000
12001 // send lines to output
12002 $report_obj->outputCSV($csvlines);
12003
12004 exit;
12005 }
12006
12007 public function exportcustomerslaunch() {
12008 $cid = VikRequest::getVar('cid', array(0));
12009 $dbo = JFactory::getDBO();
12010 $pnotes = VikRequest::getInt('notes', '', 'request');
12011 $pscanimg = VikRequest::getInt('scanimg', '', 'request');
12012 $ppin = VikRequest::getInt('pin', '', 'request');
12013 $pcountry = VikRequest::getString('country', '', 'request');
12014 $pfromdate = VikRequest::getString('fromdate', '', 'request');
12015 $ptodate = VikRequest::getString('todate', '', 'request');
12016 $pdatefilt = VikRequest::getInt('datefilt', '', 'request');
12017 $clauses = array();
12018 if (count($cid) > 0 && !empty($cid[0])) {
12019 $clauses[] = "`c`.`id` IN (".implode(', ', $cid).")";
12020 }
12021 if (!empty($pcountry)) {
12022 $clauses[] = "`c`.`country`=".$dbo->quote($pcountry);
12023 }
12024 $datescol = '`bk`.`ts`';
12025 if ($pdatefilt > 0) {
12026 if ($pdatefilt == 1) {
12027 $datescol = '`bk`.`ts`';
12028 } elseif ($pdatefilt == 2) {
12029 $datescol = '`bk`.`checkin`';
12030 } elseif ($pdatefilt == 3) {
12031 $datescol = '`bk`.`checkout`';
12032 }
12033 }
12034 if (!empty($pfromdate)) {
12035 $from_ts = VikBooking::getDateTimestamp($pfromdate, 0, 0);
12036 $clauses[] = $datescol.">=".$from_ts;
12037 }
12038 if (!empty($ptodate)) {
12039 $to_ts = VikBooking::getDateTimestamp($ptodate, 23, 59);
12040 $clauses[] = $datescol."<=".$to_ts;
12041 }
12042 //this query below is safe with the error #1055 when sql_mode=only_full_group_by
12043 $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`,".
12044 "(SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`,".
12045 "`cy`.`country_3_code`,`cy`.`country_name` ".
12046 "FROM `#__vikbooking_customers` AS `c` LEFT JOIN `#__vikbooking_countries` `cy` ON `cy`.`country_3_code`=`c`.`country` ".
12047 "LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idcustomer`=`c`.`id` ".
12048 "LEFT JOIN `#__vikbooking_orders` `bk` ON `bk`.`id`=`co`.`idorder`".
12049 (count($clauses) > 0 ? " WHERE ".implode(' AND ', $clauses) : "")."
12050 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` ".
12051 "ORDER BY `c`.`last_name` ASC;";
12052 $dbo->setQuery($q);
12053 $dbo->execute();
12054 if (!($dbo->getNumRows() > 0)) {
12055 VikError::raiseWarning('', JText::translate('VBONORECORDSCSVCUSTOMERS'));
12056 $mainframe = JFactory::getApplication();
12057 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12058 exit;
12059 }
12060 $customers = $dbo->loadAssocList();
12061 $csvlines = array();
12062 $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'));
12063 if ($ppin > 0) {
12064 $csvheadline[] = JText::translate('VBCUSTOMERPIN');
12065 }
12066 if ($pscanimg > 0) {
12067 $csvheadline[] = JText::translate('VBCUSTOMERDOCTYPE');
12068 $csvheadline[] = JText::translate('VBCUSTOMERDOCNUM');
12069 $csvheadline[] = JText::translate('VBCUSTOMERDOCIMG');
12070 }
12071 if ($pnotes > 0) {
12072 $csvheadline[] = JText::translate('VBCUSTOMERNOTES');
12073 }
12074 $csvlines[] = $csvheadline;
12075 foreach ($customers as $customer) {
12076 $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']);
12077 if ($ppin > 0) {
12078 $csvcustomerline[] = $customer['pin'];
12079 }
12080 if ($pscanimg > 0) {
12081 $csvcustomerline[] = $customer['doctype'];
12082 $csvcustomerline[] = $customer['docnum'];
12083 $csvcustomerline[] = (!empty($customer['docimg']) ? VBO_ADMIN_URI.'resources/idscans/'.$customer['docimg'] : '');
12084 }
12085 if ($pnotes > 0) {
12086 $csvcustomerline[] = $customer['notes'];
12087 }
12088 $csvlines[] = $csvcustomerline;
12089 }
12090 header("Content-type: text/csv");
12091 header("Cache-Control: no-store, no-cache");
12092 header('Content-Disposition: attachment; filename="customers_export_'.(!empty($pcountry) ? strtolower($pcountry).'_' : '').date('Y-m-d').'.csv"');
12093 $outstream = fopen("php://output", 'w');
12094 foreach ($csvlines as $csvline) {
12095 fputcsv($outstream, $csvline);
12096 }
12097 fclose($outstream);
12098 exit;
12099 }
12100
12101 public function renewsession() {
12102 /*
12103 * @wponly
12104 * We just destroy the session
12105 */
12106 JSessionHandler::destroy();
12107 $mainframe = JFactory::getApplication();
12108 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12109 }
12110
12111 public function trackings() {
12112 VikBookingHelper::printHeader("trackings");
12113
12114 VikRequest::setVar('view', VikRequest::getCmd('view', 'trackings'));
12115
12116 parent::display();
12117
12118 if (VikBooking::showFooter()) {
12119 VikBookingHelper::printFooter();
12120 }
12121 }
12122
12123 public function trkconfig() {
12124 VikBookingHelper::printHeader("trackings");
12125
12126 VikRequest::setVar('view', VikRequest::getCmd('view', 'trkconfig'));
12127
12128 parent::display();
12129
12130 if (VikBooking::showFooter()) {
12131 VikBookingHelper::printFooter();
12132 }
12133 }
12134
12135 public function savetrkconfigstay() {
12136 if (!JSession::checkToken()) {
12137 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12138 }
12139 $this->do_savetrkconfig(true);
12140 }
12141
12142 public function savetrkconfig() {
12143 if (!JSession::checkToken()) {
12144 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12145 }
12146 $this->do_savetrkconfig();
12147 }
12148
12149 private function do_savetrkconfig($stay = false) {
12150 $dbo = JFactory::getDBO();
12151 $trkenabled = VikRequest::getInt('trkenabled', 0, 'request');
12152 $trkenabled = $trkenabled == 1 ? 1 : 0;
12153 $trkcookierfrdur = VikRequest::getFloat('trkcookierfrdur', 1, 'request');
12154 $trkcookierfrdur = $trkcookierfrdur < 0.1 ? 1 : $trkcookierfrdur;
12155 $trkcampname = VikRequest::getVar('trkcampname', array());
12156 $trkcampkey = VikRequest::getVar('trkcampkey', array());
12157 $trkcampval = VikRequest::getVar('trkcampval', array());
12158 $trkcampaigns = array();
12159 foreach ($trkcampname as $k => $v) {
12160 if (empty($trkcampkey[$k])) {
12161 continue;
12162 }
12163 $trkcampkey[$k] = str_replace(' ', '', trim($trkcampkey[$k]));
12164 $name = !empty($v) ? $v : date('Y-m-d').' '.(count($trkcampaigns) + 1);
12165 $trkcampaigns[$trkcampkey[$k]] = array(
12166 'key' => $trkcampkey[$k],
12167 'value' => $trkcampval[$k],
12168 'name' => $name,
12169 );
12170 }
12171
12172 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkenabled)." WHERE `param`='trkenabled';";
12173 $dbo->setQuery($q);
12174 $dbo->execute();
12175 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote($trkcookierfrdur)." WHERE `param`='trkcookierfrdur';";
12176 $dbo->setQuery($q);
12177 $dbo->execute();
12178 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$dbo->quote(json_encode($trkcampaigns))." WHERE `param`='trkcampaigns';";
12179 $dbo->setQuery($q);
12180 $dbo->execute();
12181
12182 $mainframe = JFactory::getApplication();
12183 $mainframe->redirect("index.php?option=com_vikbooking&task=".($stay ? 'trkconfig' : 'trackings'));
12184 }
12185
12186 public function modtracking() {
12187 $dbo = JFactory::getDbo();
12188 $cid = VikRequest::getVar('cid', array());
12189 foreach ($cid as $id) {
12190 if (!empty($id)) {
12191 $q = "SELECT `id`,`published` FROM `#__vikbooking_trackings` WHERE `id`=".(int)$id.";";
12192 $dbo->setQuery($q);
12193 $dbo->execute();
12194 if ($dbo->getNumRows()) {
12195 $data = $dbo->loadAssoc();
12196 $q = "UPDATE `#__vikbooking_trackings` SET `published`=".($data['published'] ? '0' : '1')." WHERE `id`=".(int)$data['id'].";";
12197 $dbo->setQuery($q);
12198 $dbo->execute();
12199 }
12200 }
12201 }
12202 $mainframe = JFactory::getApplication();
12203 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12204 }
12205
12206 public function removetrackings() {
12207 $ids = VikRequest::getVar('cid', array());
12208 $dbo = JFactory::getDbo();
12209
12210 foreach ($ids as $d) {
12211 $q = "DELETE FROM `#__vikbooking_trackings` WHERE `id`=".(int)$d.";";
12212 $dbo->setQuery($q);
12213 $dbo->execute();
12214 $q = "DELETE FROM `#__vikbooking_tracking_infos` WHERE `idtracking`=".(int)$d.";";
12215 $dbo->setQuery($q);
12216 $dbo->execute();
12217 }
12218
12219 $mainframe = JFactory::getApplication();
12220 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12221 }
12222
12223 /**
12224 * Invokes the Tracker class to obtain
12225 * geo information about the IP addresses.
12226 * This task is called via ajax.
12227 *
12228 * @since 1.11
12229 */
12230 public function getgeoinfo() {
12231 $ips = VikRequest::getVar('ips', array());
12232 if (!count($ips)) {
12233 echo 'e4j.error.empty IPs';
12234 exit;
12235 }
12236
12237 // require the Tracker class without instantiating the object
12238 VikBooking::getTracker(true);
12239 $geo_info = VikBookingTracker::getIpGeoInfo($ips);
12240
12241 if ($geo_info === false) {
12242 echo 'e4j.error.Tracker error, could not get geo info from IPs';
12243 exit;
12244 }
12245
12246 // update db values and compose response
12247 $dbo = JFactory::getDbo();
12248 $resp = array();
12249 foreach ($geo_info as $id => $geo) {
12250 if (is_null($geo) || $geo === false) {
12251 continue;
12252 }
12253 // compose geo info string
12254 $geovals = array();
12255 if (!empty($geo['city'])) {
12256 array_push($geovals, $geo['city']);
12257 }
12258 if (!empty($geo['region'])) {
12259 array_push($geovals, $geo['region']);
12260 }
12261 $threecode = '';
12262 $cname = '';
12263 if (!empty($geo['country'])) {
12264 // returned country is a 2-char code, get the 3-char country code
12265 $q = "SELECT `country_3_code`,`country_name` FROM `#__vikbooking_countries` WHERE `country_2_code`=".$dbo->quote($geo['country']).";";
12266 $dbo->setQuery($q);
12267 $dbo->execute();
12268 if ($dbo->getNumRows()) {
12269 $cinfo = $dbo->loadAssoc();
12270 $threecode = $cinfo['country_3_code'];
12271 $cname = $cinfo['country_name'];
12272 }
12273 array_push($geovals, (empty($cname) ? $geo['country'] : $cname));
12274 }
12275
12276 // full geo information string
12277 $geoinfostr = implode(', ', $geovals);
12278
12279 // push data to the response pool
12280 $resp[$id] = array();
12281 $resp[$id]['geo'] = $geoinfostr;
12282 if (!empty($cname)) {
12283 $resp[$id]['country'] = $cname;
12284 }
12285 if (!empty($threecode)) {
12286 $resp[$id]['country3'] = $threecode;
12287 }
12288
12289 // update main tracking record
12290 $q = "UPDATE `#__vikbooking_trackings` SET `geo`=".$dbo->quote($geoinfostr).(!empty($threecode) ? ', `country`='.$dbo->quote($threecode) : '')." WHERE `id`=".(int)$id.";";
12291 $dbo->setQuery($q);
12292 $dbo->execute();
12293 }
12294
12295 // output the JSON response
12296 echo json_encode($resp);
12297 exit;
12298 }
12299
12300 /**
12301 * Counts the orphan dates for all published rooms
12302 * depending on their restrictions and booked dates.
12303 * By default, the task takes up to 3 months ahead.
12304 * It is possible to filter the request by rooms and months.
12305 * This task should be called via ajax.
12306 *
12307 * @since 1.11
12308 */
12309 public function orphanscount()
12310 {
12311 $dbo = JFactory::getDbo();
12312 $orphans = array();
12313
12314 $nowdf = VikBooking::getDateFormat();
12315 if ($nowdf == "%d/%m/%Y") {
12316 $df = 'd/m/Y';
12317 } elseif ($nowdf == "%m/%d/%Y") {
12318 $df = 'm/d/Y';
12319 } else {
12320 $df = 'Y/m/d';
12321 }
12322
12323 // global min los
12324 $glob_minlos = VikBooking::getDefaultNightsCalendar();
12325 $glob_minlos = $glob_minlos < 1 ? 1 : $glob_minlos;
12326
12327 // rooms and dates
12328 $roomids = VikRequest::getVar('roomids', array(), 'request', 'int');
12329 $months = VikRequest::getInt('months', 3, 'request');
12330 $from = VikRequest::getString('from', '', 'request');
12331 $today = strtotime(date('Y').'-'.date('m').'-'.date('d'));
12332 if (!empty($from)) {
12333 $fromts = VikBooking::getDateTimestamp($from, 0, 0);
12334 if (!empty($fromts)) {
12335 // custom starting date
12336 $today = $fromts;
12337 }
12338 }
12339 $until = strtotime("+{$months} months", $today);
12340
12341 // load all rooms
12342 $rooms = array();
12343 $q = "SELECT `id`,`name`,`units` FROM `#__vikbooking_rooms` WHERE `avail`=1".(count($roomids) ? ' AND `id` IN ('.implode(', ', $roomids).')' : '').";";
12344 $dbo->setQuery($q);
12345 $dbo->execute();
12346 if ($dbo->getNumRows()) {
12347 $allrooms = $dbo->loadAssocList();
12348 foreach ($allrooms as $r) {
12349 $rooms[$r['id']] = $r;
12350 }
12351 }
12352 if (!count($rooms)) {
12353 // no rooms found, exit
12354 echo json_encode($orphans);
12355 exit;
12356 }
12357
12358 // load availabilities
12359 $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.");";
12360 $dbo->setQuery($q);
12361 $dbo->execute();
12362 if (!$dbo->getNumRows()) {
12363 // no booked dates found, exit
12364 echo json_encode($orphans);
12365 exit;
12366 }
12367 $busy = $dbo->loadAssocList();
12368
12369 // sort booked dates by room id
12370 $rooms_busy = array();
12371 foreach ($busy as $b) {
12372 if (!isset($rooms_busy[$b['idroom']])) {
12373 $rooms_busy[$b['idroom']] = array();
12374 }
12375 array_push($rooms_busy[$b['idroom']], $b);
12376 }
12377
12378 // load restrictions
12379 $rooms_restr = array();
12380 foreach ($rooms as $rid => $r) {
12381 $restrictions = VikBooking::loadRestrictions(true, array($rid));
12382 if (count($restrictions)) {
12383 $rooms_restr[$rid] = $restrictions;
12384 }
12385 }
12386 if (!count($rooms_restr) && $glob_minlos < 2) {
12387 // no restrictions found and minlos=1, exit
12388 echo json_encode($orphans);
12389 exit;
12390 }
12391
12392 // count availability and minlos per day
12393 $rooms_data = array();
12394 foreach ($rooms as $rid => $r) {
12395 $rooms_data[$rid] = array(
12396 'avail' => array(),
12397 'restr' => array()
12398 );
12399 $nowts = getdate($today);
12400 while ($nowts[0] <= $until) {
12401 $dateind = date('Y-m-d', $nowts[0]);
12402
12403 // remaining availability
12404 if (!isset($rooms_busy[$rid])) {
12405 // no bookings for this room, set full availability for this day
12406 $rooms_data[$rid]['avail'][] = array(
12407 'dt' => $dateind,
12408 'units' => $r['units']
12409 );
12410 } else {
12411 // check remaining availability for this day
12412 $totfound = 0;
12413 foreach ($rooms_busy[$rid] as $b) {
12414 $tmpone = getdate($b['checkin']);
12415 $rit = ($tmpone['mon'] < 10 ? "0".$tmpone['mon'] : $tmpone['mon'])."/".($tmpone['mday'] < 10 ? "0".$tmpone['mday'] : $tmpone['mday'])."/".$tmpone['year'];
12416 $ritts = strtotime($rit);
12417 $tmptwo = getdate($b['checkout']);
12418 $con = ($tmptwo['mon'] < 10 ? "0".$tmptwo['mon'] : $tmptwo['mon'])."/".($tmptwo['mday'] < 10 ? "0".$tmptwo['mday'] : $tmptwo['mday'])."/".$tmptwo['year'];
12419 $conts = strtotime($con);
12420 if ($nowts[0] >= $ritts && $nowts[0] < $conts) {
12421 $totfound++;
12422 }
12423 }
12424 $totfound = $totfound > $r['units'] ? $r['units'] : $totfound;
12425 $rooms_data[$rid]['avail'][] = array(
12426 'dt' => $dateind,
12427 'units' => ($r['units'] - $totfound)
12428 );
12429 }
12430
12431 // restrictions
12432 if (!isset($rooms_restr[$rid])) {
12433 // no restrictions for this room, set global minlos for this day
12434 $rooms_data[$rid]['restr'][] = array(
12435 'dt' => $dateind,
12436 'minlos' => $glob_minlos
12437 );
12438 } else {
12439 // get restriction for this day
12440 $today_tsin = mktime(0, 0, 0, $nowts['mon'], $nowts['mday'], $nowts['year']);
12441 $today_tsout = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12442
12443 $restr = VikBooking::parseSeasonRestrictions($today_tsin, $today_tsout, 1, $rooms_restr[$rid]);
12444 $minlos = count($restr) ? $restr['minlos'] : $glob_minlos;
12445
12446 $rooms_data[$rid]['restr'][] = array(
12447 'dt' => $dateind,
12448 'minlos' => $minlos
12449 );
12450 }
12451
12452 // next loop
12453 $dayts = mktime(0, 0, 0, $nowts['mon'], ($nowts['mday'] + 1), $nowts['year']);
12454 $nowts = getdate($dayts);
12455 }
12456 }
12457
12458 // week days and months labels
12459 $days_labels = array(
12460 JText::translate('VBSUNDAY'),
12461 JText::translate('VBMONDAY'),
12462 JText::translate('VBTUESDAY'),
12463 JText::translate('VBWEDNESDAY'),
12464 JText::translate('VBTHURSDAY'),
12465 JText::translate('VBFRIDAY'),
12466 JText::translate('VBSATURDAY')
12467 );
12468 $months_labels = array(
12469 JText::translate('VBMONTHONE'),
12470 JText::translate('VBMONTHTWO'),
12471 JText::translate('VBMONTHTHREE'),
12472 JText::translate('VBMONTHFOUR'),
12473 JText::translate('VBMONTHFIVE'),
12474 JText::translate('VBMONTHSIX'),
12475 JText::translate('VBMONTHSEVEN'),
12476 JText::translate('VBMONTHEIGHT'),
12477 JText::translate('VBMONTHNINE'),
12478 JText::translate('VBMONTHTEN'),
12479 JText::translate('VBMONTHELEVEN'),
12480 JText::translate('VBMONTHTWELVE')
12481 );
12482
12483 // orphan dates calculation method
12484 $calc_method = VikBooking::orphansCalculation();
12485
12486 // parse data and build orphans if any
12487 foreach ($rooms_data as $rid => $data) {
12488 foreach ($data['avail'] as $ind => $av) {
12489 if (!isset($data['restr'][$ind]) || $av['units'] < 1) {
12490 // continue, no restriction set or no availability for this day
12491 continue;
12492 }
12493 if ($data['restr'][$ind]['minlos'] < 2) {
12494 // continue, no min los > 1 set for this day
12495 continue;
12496 }
12497 // check if any night after today, until min los, is fully booked
12498 $hasorphans = false;
12499 $forward_count = 0;
12500 for ($i = 1; $i < $data['restr'][$ind]['minlos']; $i++) {
12501 if (!isset($data['avail'][($ind + $i)])) {
12502 // break loop, no info for this day after
12503 break;
12504 }
12505 if ($data['avail'][($ind + $i)]['units'] > 0) {
12506 // continue, availability found for tomorrow, we need a non available next-day
12507 continue;
12508 }
12509 // orphan found
12510 $hasorphans = true;
12511 $forward_count = $i;
12512 break;
12513 }
12514
12515 /**
12516 * Backward calculation method only if "prevnext".
12517 *
12518 * @since 1.3.0
12519 */
12520 $backward_count = 0;
12521 for ($i = 1; $i <= $data['restr'][$ind]['minlos']; $i++) {
12522 if (!isset($data['avail'][($ind - $i)])) {
12523 // break loop, no info for this prev day
12524 break;
12525 }
12526 if ($data['avail'][($ind - $i)]['units'] > 0) {
12527 // increase free nights going backward
12528 $backward_count++;
12529 }
12530 }
12531 if ($calc_method == 'prevnext' && $hasorphans && $backward_count > 0 && ($backward_count >= $data['restr'][$ind]['minlos'] || ($backward_count + $forward_count) >= $data['restr'][$ind]['minlos'])) {
12532 // this should not be an orphan date because of enough free days back, or enough free days in between
12533 $hasorphans = false;
12534 }
12535 //
12536
12537 if ($hasorphans) {
12538 // 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
12539 if (!isset($orphans[$rid])) {
12540 $orphans[$rid] = array(
12541 'name' => $rooms[$rid]['name'],
12542 'dates' => array(),
12543 'rdates' => array(),
12544 'linkd' => date($df, strtotime($av['dt']))
12545 );
12546 }
12547 array_push($orphans[$rid]['dates'], $av['dt']);
12548 // build the value for the readable date
12549 $dtinfo = getdate(strtotime($av['dt']));
12550 $rdate = $days_labels[$dtinfo['wday']] . ', ' . $months_labels[($dtinfo['mon'] - 1)] . ' ' . $dtinfo['mday'] . ' ' . $dtinfo['year'];
12551 array_push($orphans[$rid]['rdates'], $rdate);
12552 }
12553 }
12554 }
12555
12556 // output response
12557 echo json_encode($orphans);
12558 exit;
12559 }
12560
12561 public function tableaux() {
12562 VikBookingHelper::printHeader("tableaux");
12563
12564 VikRequest::setVar('view', VikRequest::getCmd('view', 'tableaux'));
12565
12566 parent::display();
12567
12568 if (VikBooking::showFooter()) {
12569 VikBookingHelper::printFooter();
12570 }
12571 }
12572
12573 public function operators() {
12574 VikBookingHelper::printHeader("operators");
12575
12576 VikRequest::setVar('view', VikRequest::getCmd('view', 'operators'));
12577
12578 parent::display();
12579
12580 if (VikBooking::showFooter()) {
12581 VikBookingHelper::printFooter();
12582 }
12583 }
12584
12585 public function newoperator() {
12586 VikBookingHelper::printHeader("operators");
12587
12588 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12589
12590 parent::display();
12591
12592 if (VikBooking::showFooter()) {
12593 VikBookingHelper::printFooter();
12594 }
12595 }
12596
12597 public function editoperator() {
12598 VikBookingHelper::printHeader("operators");
12599
12600 VikRequest::setVar('view', VikRequest::getCmd('view', 'manageoperator'));
12601
12602 parent::display();
12603
12604 if (VikBooking::showFooter()) {
12605 VikBookingHelper::printFooter();
12606 }
12607 }
12608
12609 public function updateoperator() {
12610 if (!JSession::checkToken()) {
12611 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12612 }
12613 $this->do_updateoperator();
12614 }
12615
12616 public function updateoperatorstay() {
12617 if (!JSession::checkToken()) {
12618 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12619 }
12620 $this->do_updateoperator(true);
12621 }
12622
12623 private function do_updateoperator($stay = false) {
12624 $dbo = JFactory::getDBO();
12625 $mainframe = JFactory::getApplication();
12626 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12627 $plast_name = VikRequest::getString('last_name', '', 'request');
12628 $pemail = VikRequest::getString('email', '', 'request');
12629 $pphone = VikRequest::getString('phone', '', 'request');
12630 $pcode = VikRequest::getString('code', '', 'request');
12631 $pujid = VikRequest::getInt('ujid', '', 'request');
12632 $pwhere = VikRequest::getInt('where', '', 'request');
12633 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12634 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `id`=".(int)$pwhere." LIMIT 1;";
12635 $dbo->setQuery($q);
12636 $dbo->execute();
12637 if ($dbo->getNumRows() == 1) {
12638 $customer = $dbo->loadAssoc();
12639 } else {
12640 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12641 exit;
12642 }
12643 $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;";
12644 $dbo->setQuery($q);
12645 $dbo->execute();
12646 if ($dbo->getNumRows() == 0) {
12647 // update fingerprint for the operator
12648 $fingpt = md5($pwhere.$pemail);
12649 //
12650 $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.";";
12651 $dbo->setQuery($q);
12652 $dbo->execute();
12653 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12654 } else {
12655 //email already exists
12656 $ex_operator = $dbo->loadAssoc();
12657 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>');
12658 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12659 exit;
12660 }
12661 } else {
12662 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12663 }
12664 if ($stay) {
12665 $mainframe->redirect("index.php?option=com_vikbooking&task=editoperator&cid[]=".$pwhere);
12666 } else {
12667 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12668 }
12669 }
12670
12671 public function saveoperator() {
12672 if (!JSession::checkToken()) {
12673 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12674 }
12675 $dbo = JFactory::getDbo();
12676 $mainframe = JFactory::getApplication();
12677 $pfirst_name = VikRequest::getString('first_name', '', 'request');
12678 $plast_name = VikRequest::getString('last_name', '', 'request');
12679 $pemail = VikRequest::getString('email', '', 'request');
12680 $pphone = VikRequest::getString('phone', '', 'request');
12681 $pcode = VikRequest::getString('code', '', 'request');
12682 $pujid = VikRequest::getInt('ujid', '', 'request');
12683 if (!empty($pfirst_name) && !empty($pemail) && (!empty($pcode) || !empty($pujid))) {
12684 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `email`=".$dbo->quote($pemail)." OR ".(!empty($pcode) ? "`code`=".$dbo->quote($pcode) : "`ujid`=".$dbo->quote($pujid))." LIMIT 1;";
12685 $dbo->setQuery($q);
12686 $dbo->execute();
12687 if ($dbo->getNumRows() == 0) {
12688 $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).");";
12689 $dbo->setQuery($q);
12690 $dbo->execute();
12691 $lid = $dbo->insertid();
12692 if (!empty($lid)) {
12693 $mainframe->enqueueMessage(JText::translate('VBOPERATORSAVED'));
12694 // generate fingerprint for the operator
12695 $q = "UPDATE `#__vikbooking_operators` SET `fingpt`=".$dbo->quote(md5($lid.$pemail))." WHERE `id`=".(int)$lid.";";
12696 $dbo->setQuery($q);
12697 $dbo->execute();
12698 //
12699 }
12700 } else {
12701 //email already exists
12702 $ex_operator = $dbo->loadAssoc();
12703 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>');
12704 }
12705 } else {
12706 VikError::raiseWarning('', JText::translate('VBERROPERATORDATA'));
12707 }
12708 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12709 }
12710
12711 public function removeoperators() {
12712 if (!JSession::checkToken()) {
12713 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
12714 }
12715 $ids = VikRequest::getVar('cid', array(0));
12716 if (@count($ids)) {
12717 $dbo = JFactory::getDBO();
12718 foreach ($ids as $d) {
12719 $q = "DELETE FROM `#__vikbooking_operators` WHERE `id`=".(int)$d.";";
12720 $dbo->setQuery($q);
12721 $dbo->execute();
12722 }
12723 }
12724 $mainframe = JFactory::getApplication();
12725 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12726 }
12727
12728 public function operatorperms() {
12729 $dbo = JFactory::getDbo();
12730 $permtype = VikRequest::getString('permtype', 'tableaux', 'request');
12731 $permschanged = 0;
12732
12733 if ($permtype == 'tableaux') {
12734 $oper_id = VikRequest::getVar('oper_id', array());
12735 $oper_days = VikRequest::getVar('oper_days', array());
12736 $oper_rooms = VikRequest::getVar('oper_rooms', array());
12737 $oper_guestname = VikRequest::getVar('oper_guestname', array());
12738 $oper_roomextras = VikRequest::getVar('oper_roomextras', array());
12739 $oper_rm = VikRequest::getVar('oper_rm', array());
12740 if (count($oper_rm)) {
12741 // remove permissions first
12742 foreach ($oper_rm as $operatorid) {
12743 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$operatorid.";";
12744 $dbo->setQuery($q);
12745 $dbo->execute();
12746 if ($dbo->getNumRows()) {
12747 $current = $dbo->loadAssoc();
12748 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12749 $perms = !is_array($perms) ? array() : $perms;
12750 foreach ($perms as $kp => $perm) {
12751 if (isset($perm['type']) && $perm['type'] == $permtype) {
12752 unset($perms[$kp]);
12753 break;
12754 }
12755 }
12756 // update permissions for this operator
12757 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12758 $dbo->setQuery($q);
12759 $dbo->execute();
12760 $permschanged++;
12761 }
12762 }
12763 }
12764 foreach ($oper_id as $k => $v) {
12765 if (empty($v) || !isset($oper_days[$k])) {
12766 // missing data
12767 continue;
12768 }
12769 // get operator
12770 $q = "SELECT `id`,`perms` FROM `#__vikbooking_operators` WHERE `id`=".(int)$v.";";
12771 $dbo->setQuery($q);
12772 $dbo->execute();
12773 if (!$dbo->getNumRows()) {
12774 continue;
12775 }
12776 $current = $dbo->loadAssoc();
12777 $perms = !empty($current['perms']) ? json_decode($current['perms'], true) : array();
12778 $perms = !is_array($perms) ? array() : $perms;
12779 foreach ($perms as $kp => $perm) {
12780 if (isset($perm['type']) && $perm['type'] == $permtype) {
12781 unset($perms[$kp]);
12782 break;
12783 }
12784 }
12785 // push new permission
12786 array_push($perms, array(
12787 'type' => $permtype,
12788 'perms' => array(
12789 'days' => (int)$oper_days[$k],
12790 'rooms' => (isset($oper_rooms[$k]) && is_array($oper_rooms[$k]) ? $oper_rooms[$k] : array()),
12791 'guestname' => (isset($oper_guestname[$k]) && (int)$oper_guestname[$k] > 0 ? 1 : 0),
12792 'roomextras' => (isset($oper_roomextras[$k]) && (int)$oper_roomextras[$k] > 0 ? 1 : 0),
12793 )
12794 ));
12795 // update permissions for this operator
12796 $q = "UPDATE `#__vikbooking_operators` SET `perms`=".$dbo->quote(json_encode($perms))." WHERE `id`=".$current['id'].";";
12797 $dbo->setQuery($q);
12798 $dbo->execute();
12799 $permschanged++;
12800 }
12801 }
12802
12803 $mainframe = JFactory::getApplication();
12804 if ($permschanged > 0) {
12805 $mainframe->enqueueMessage(JText::translate('VBOPERMSUPDOPEROK'));
12806 }
12807 $mainframe->redirect("index.php?option=com_vikbooking&task=".$permtype);
12808 }
12809
12810 public function canceloperator() {
12811 $mainframe = JFactory::getApplication();
12812 $mainframe->redirect("index.php?option=com_vikbooking&task=operators");
12813 }
12814
12815 public function cancelcrons() {
12816 $mainframe = JFactory::getApplication();
12817 $mainframe->redirect("index.php?option=com_vikbooking&task=crons");
12818 }
12819
12820 public function cancelpackages() {
12821 $mainframe = JFactory::getApplication();
12822 $mainframe->redirect("index.php?option=com_vikbooking&task=packages");
12823 }
12824
12825 public function cancelcustomer() {
12826 $mainframe = JFactory::getApplication();
12827 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
12828 if (!empty($pgoto)) {
12829 $mainframe->redirect(base64_decode($pgoto));
12830 exit;
12831 }
12832 $mainframe->redirect("index.php?option=com_vikbooking&task=customers");
12833 }
12834
12835 public function cancelbusyvcm() {
12836 $mainframe = JFactory::getApplication();
12837 $mainframe->redirect("index.php?option=com_vikchannelmanager&task=oversight");
12838 }
12839
12840 public function cancelrestriction() {
12841 $mainframe = JFactory::getApplication();
12842 $mainframe->redirect("index.php?option=com_vikbooking&task=restrictions");
12843 }
12844
12845 public function cancelcoupon() {
12846 $mainframe = JFactory::getApplication();
12847 $mainframe->redirect("index.php?option=com_vikbooking&task=coupons");
12848 }
12849
12850 public function cancelcustomf() {
12851 $mainframe = JFactory::getApplication();
12852 $mainframe->redirect("index.php?option=com_vikbooking&task=customf");
12853 }
12854
12855 public function cancelpayment() {
12856 $mainframe = JFactory::getApplication();
12857 $mainframe->redirect("index.php?option=com_vikbooking&task=payments");
12858 }
12859
12860 public function cancelseason() {
12861 $mainframe = JFactory::getApplication();
12862 $mainframe->redirect("index.php?option=com_vikbooking&task=seasons");
12863 }
12864
12865 public function goconfig() {
12866 $mainframe = JFactory::getApplication();
12867 $mainframe->redirect("index.php?option=com_vikbooking&task=config");
12868 }
12869
12870 public function canceledorder() {
12871 $pgoto = VikRequest::getString('goto', 'orders', 'request');
12872 $mainframe = JFactory::getApplication();
12873 $mainframe->redirect("index.php?option=com_vikbooking&task=" . $pgoto);
12874 }
12875
12876 public function cancelbusy() {
12877 $pidorder = VikRequest::getString('idorder', '', 'request');
12878 $pgoto = VikRequest::getString('goto', '', 'request');
12879 $mainframe = JFactory::getApplication();
12880 $mainframe->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=".$pidorder.($pgoto == 'overv' ? '&goto=overv' : ''));
12881 }
12882
12883 public function canceloverv() {
12884 $mainframe = JFactory::getApplication();
12885 $mainframe->redirect("index.php?option=com_vikbooking&task=overv");
12886 }
12887
12888 public function canceltableaux() {
12889 $mainframe = JFactory::getApplication();
12890 $mainframe->redirect("index.php?option=com_vikbooking&task=tableaux");
12891 }
12892
12893 public function cancelcalendar() {
12894 $pidroom = VikRequest::getString('idroom', '', 'request');
12895 $mainframe = JFactory::getApplication();
12896 $mainframe->redirect("index.php?option=com_vikbooking&task=calendar&cid[]=".$pidroom);
12897 }
12898
12899 public function canceloptionals() {
12900 $mainframe = JFactory::getApplication();
12901 $mainframe->redirect("index.php?option=com_vikbooking&task=optionals");
12902 }
12903
12904 public function cancel() {
12905 $mainframe = JFactory::getApplication();
12906 $mainframe->redirect("index.php?option=com_vikbooking&task=rooms");
12907 }
12908
12909 public function cancelcarat() {
12910 $mainframe = JFactory::getApplication();
12911 $mainframe->redirect("index.php?option=com_vikbooking&task=carat");
12912 }
12913
12914 public function cancelcat() {
12915 $mainframe = JFactory::getApplication();
12916 $mainframe->redirect("index.php?option=com_vikbooking&task=categories");
12917 }
12918
12919 public function cancelprice() {
12920 $mainframe = JFactory::getApplication();
12921 $mainframe->redirect("index.php?option=com_vikbooking&task=prices");
12922 }
12923
12924 public function canceliva() {
12925 $mainframe = JFactory::getApplication();
12926 $mainframe->redirect("index.php?option=com_vikbooking&task=iva");
12927 }
12928
12929 public function canceltrk() {
12930 $mainframe = JFactory::getApplication();
12931 $mainframe->redirect("index.php?option=com_vikbooking&task=trackings");
12932 }
12933
12934 public function canceldash() {
12935 $mainframe = JFactory::getApplication();
12936 $mainframe->redirect("index.php?option=com_vikbooking");
12937 }
12938
12939 public function cancelinvoice() {
12940 $mainframe = JFactory::getApplication();
12941 $pgoto = VikRequest::getString('goto', '', 'request', VIKREQUEST_ALLOWRAW);
12942 if (!empty($pgoto)) {
12943 $mainframe->redirect(base64_decode($pgoto));
12944 exit;
12945 }
12946 $mainframe->redirect("index.php?option=com_vikbooking&task=invoices");
12947 }
12948
12949 /**
12950 * AJAX upload the customer documents.
12951 *
12952 * @return void
12953 *
12954 * @throws Exception
12955 */
12956 public function upload_customer_document()
12957 {
12958 $input = JFactory::getApplication()->input;
12959 $dbo = JFactory::getDbo();
12960
12961 $customer_id = $input->getUint('customer', 0);
12962
12963 $result = new stdClass;
12964 $result->status = 0;
12965
12966 try
12967 {
12968 $q = $dbo->getQuery(true)
12969 ->select($dbo->qn(array(
12970 'id',
12971 'first_name',
12972 'last_name',
12973 'email',
12974 'docsfolder',
12975 )))
12976 ->from($dbo->qn('#__vikbooking_customers'))
12977 ->where($dbo->qn('id') . ' = ' . $customer_id);
12978
12979 $dbo->setQuery($q, 0, 1);
12980 $dbo->execute();
12981
12982 if (!$dbo->getNumRows())
12983 {
12984 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
12985 }
12986
12987 $customer = $dbo->loadObject();
12988
12989 // fetch documents folder path
12990 $dirpath = VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR;
12991
12992 // check if we have a valid directory
12993 if (empty($customer->docsfolder) || !is_dir($dirpath . $customer->docsfolder))
12994 {
12995 // randomize string
12996 $customer->seed = uniqid();
12997
12998 // create blocks for hashed folder
12999 $parts = [
13000 $customer->first_name,
13001 $customer->last_name,
13002 md5(serialize($customer)),
13003 ];
13004
13005 // join fetched parts
13006 $customer->docsfolder = JFilterOutput::stringURLSafe(implode('-', array_filter($parts)));
13007
13008 if (strlen($customer->docsfolder) < 16)
13009 {
13010 throw new Exception('Possible security breach. Please specify the most details as possible.', 400);
13011 }
13012
13013 jimport('joomla.filesystem.folder');
13014
13015 // create a folder for this customer
13016 $created = JFolder::create($dirpath . $customer->docsfolder);
13017
13018 if (!$created)
13019 {
13020 throw new Exception(sprintf('Unable to create the folder [%s]', $dirpath . $customer->docsfolder), 403);
13021 }
13022
13023 unset($customer->seed);
13024
13025 // update docs folder
13026 $dbo->updateObject('#__vikbooking_customers', $customer, 'id');
13027 }
13028
13029 // get file from request
13030 $file = $input->files->get('file', array(), 'array');
13031
13032 // try to upload the file
13033 $result = VikBooking::uploadFileFromRequest($file, $dirpath . $customer->docsfolder, "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i");
13034 $result->status = 1;
13035
13036 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
13037 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_CUSTOMERS_PATH . DIRECTORY_SEPARATOR, VBO_CUSTOMERS_URI, $result->path));
13038 }
13039 catch (Exception $e)
13040 {
13041 $result->error = $e->getMessage();
13042 $result->code = $e->getCode();
13043 }
13044
13045 echo json_encode($result);
13046 exit;
13047 }
13048
13049 /**
13050 * AJAX delete the customer documents.
13051 *
13052 * @return void
13053 *
13054 * @throws Exception
13055 */
13056 public function delete_customer_document()
13057 {
13058 $input = JFactory::getApplication()->input;
13059 $dbo = JFactory::getDbo();
13060
13061 $customer_id = $input->getUint('customer', 0);
13062
13063 $result = new stdClass;
13064 $result->status = 0;
13065
13066 $q = $dbo->getQuery(true)
13067 ->select($dbo->qn('docsfolder'))
13068 ->from($dbo->qn('#__vikbooking_customers'))
13069 ->where($dbo->qn('id') . ' = ' . $customer_id);
13070
13071 $dbo->setQuery($q, 0, 1);
13072 $dbo->execute();
13073
13074 if (!$dbo->getNumRows())
13075 {
13076 throw new Exception(sprintf('Customer [%d] not found', $customer_id), 404);
13077 }
13078
13079 $folder = $dbo->loadResult();
13080
13081 if (!$folder)
13082 {
13083 throw new Exception('The customer does not have any documents', 500);
13084 }
13085
13086 $file = $input->getString('file');
13087
13088 if (!$file)
13089 {
13090 throw new Exception('File to remove not specified', 400);
13091 }
13092
13093 $path = implode(DIRECTORY_SEPARATOR, array(VBO_CUSTOMERS_PATH, $folder, $file));
13094
13095 if (!is_file($path))
13096 {
13097 throw new Exception(sprintf('File [%s] not found', $path), 404);
13098 }
13099
13100 jimport('joomla.filesystem.file');
13101
13102 $removed = JFile::delete($path);
13103
13104 echo json_encode(array('status' => (int) $removed));
13105 exit;
13106 }
13107
13108 /**
13109 * AJAX task to invoke a specific report and obtain information.
13110 *
13111 * @since 1.3.0
13112 */
13113 public function get_report_data()
13114 {
13115 $report_name = VikRequest::getString('report_name', '', 'request');
13116 $current_fest = VikRequest::getString('current_fest', '', 'request');
13117 $current_fromdate = VikRequest::getString('current_fromdate', '', 'request');
13118 $current_todate = VikRequest::getString('current_todate', '', 'request');
13119 $step = VikRequest::getString('step', 'weekend', 'request');
13120 $direction = VikRequest::getString('direction', 'load', 'request');
13121 $period = VikRequest::getString('period', 'full', 'request');
13122 $krsort = VikRequest::getString('krsort', 'occupancy', 'request');
13123 $krorder = VikRequest::getString('krorder', 'DESC', 'request');
13124 $chart_datatype = VikRequest::getVar('chart_datatype', array(), 'request');
13125 $chart_meta_data = VikRequest::getString('chart_meta_data', '', 'request', VIKREQUEST_ALLOWRAW);
13126 $chart_meta_data = !empty($chart_meta_data) ? json_decode($chart_meta_data, true) : array();
13127 // idroom can be an array of IDs or just one ID as int/string
13128 $idroom = VikRequest::getVar('idroom', null, 'request');
13129 //
13130
13131 if (empty($report_name) || empty($current_fromdate) || empty($current_todate)) {
13132 throw new Exception("Missing request data", 400);
13133 }
13134
13135 // get requested report instance
13136 $report = VikBooking::getReportInstance($report_name);
13137 if (!$report) {
13138 throw new Exception("Report not found", 404);
13139 }
13140
13141 // chart data
13142 if (empty($chart_datatype)) {
13143 $chart_datatype = array(
13144 'type' => 'doughnut',
13145 'depth' => 1,
13146 'keys' => array($krsort),
13147 );
13148 }
13149
13150 // website date format
13151 $df = $report->getDateFormat();
13152
13153 // prepare request params for the report
13154 $rparams = array(
13155 'fromdate' => $current_fromdate,
13156 'todate' => $current_todate,
13157 'period' => $period,
13158 'krsort' => $krsort,
13159 'krorder' => $krorder,
13160 'idroom' => $idroom,
13161 );
13162
13163 // starting dates info and timestamps
13164 $from_ts = VikBooking::getDateTimestamp($current_fromdate, 0, 0, 0);
13165 $to_ts = VikBooking::getDateTimestamp($current_todate, 23, 59, 59);
13166 $from_info = getdate($from_ts);
13167 $to_info = getdate($to_ts);
13168
13169 // the name of the period requested and whether it's a fest
13170 $period_name = '';
13171 $is_fest = null;
13172
13173 if ($direction == 'prev' || $direction == 'next') {
13174 // calculate prev or next dates
13175 if ($step == 'weekend') {
13176 $period_name = JText::translate('VBOWEEKND');
13177 if ($direction == 'next') {
13178 // next weekend from current end date
13179 $next_ts = strtotime("next friday", $to_ts);
13180 } else {
13181 // prev weekend from current start date
13182 $next_ts = strtotime("previous friday", $from_ts);
13183 }
13184 $next_info = getdate($next_ts);
13185 $new_from_ts = $next_ts;
13186 $new_to_ts = mktime(23, 59, 59, $next_info['mon'], ($next_info['mday'] + 1), $next_info['year']);
13187 $rparams['fromdate'] = date($df, $new_from_ts);
13188 $rparams['todate'] = date($df, $new_to_ts);
13189 } elseif ($step == 'week') {
13190 $period_name = JText::translate('VBOWEEK');
13191 if ($direction == 'next') {
13192 // start next week from the current end date
13193 $new_from_ts = $to_ts;
13194 $new_to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 7), $to_info['year']);
13195 $rparams['fromdate'] = $rparams['todate'];
13196 $rparams['todate'] = date($df, $new_to_ts);
13197 } else {
13198 // end prev week from the current from date
13199 $new_from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 7), $from_info['year']);
13200 $new_to_ts = $from_ts;
13201 $rparams['todate'] = $rparams['fromdate'];
13202 $rparams['fromdate'] = date($df, $new_from_ts);
13203 }
13204 } else {
13205 // month
13206 $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO');
13207 if ($direction == 'next') {
13208 // next month from the current from date
13209 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']);
13210 $new_from_ts = $nextmonts;
13211 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] + 1), date('t', $nextmonts), $from_info['year']);
13212 $rparams['fromdate'] = date($df, $new_from_ts);
13213 $rparams['todate'] = date($df, $new_to_ts);
13214 } else {
13215 // prev month from the current from date
13216 $nextmonts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']);
13217 $new_from_ts = $nextmonts;
13218 $new_to_ts = mktime(23, 59, 59, ($from_info['mon'] - 1), date('t', $nextmonts), $from_info['year']);
13219 $rparams['fromdate'] = date($df, $new_from_ts);
13220 $rparams['todate'] = date($df, $new_to_ts);
13221 }
13222 }
13223
13224 // get the next festivities
13225 $fests = VikBooking::getFestivitiesInstance();
13226 $next_fests = $fests->loadFestDates();
13227 if (count($next_fests)) {
13228 // check whether a festivity should be displayed rather than the calculated period of dates
13229 foreach ($next_fests as $fest) {
13230 $fest_found = false;
13231 if ($direction == 'next' && $fest['festinfo'][0]->from_ts > $from_ts && $fest['festinfo'][0]->from_ts <= $new_to_ts) {
13232 $fest_found = true;
13233 } elseif ($direction == 'prev' && $fest['festinfo'][0]->from_ts < $to_ts && $fest['festinfo'][0]->from_ts >= $new_from_ts) {
13234 $fest_found = true;
13235 }
13236 if ($fest_found && (string)$fest['festinfo'][0]->next_ts != $current_fest) {
13237 // festivity found before next calculated period
13238 $is_fest = $fest['festinfo'][0]->next_ts;
13239 $period_name = $fest['festinfo'][0]->trans_name;
13240 $new_from_ts = $fest['festinfo'][0]->from_ts;
13241 $new_to_ts = $fest['festinfo'][0]->to_ts;
13242 $rparams['fromdate'] = date($df, $new_from_ts);
13243 $rparams['todate'] = date($df, $new_to_ts);
13244 break;
13245 }
13246 }
13247 }
13248 } else {
13249 // load requested dates by skipping the festivities
13250 $new_from_ts = $from_ts;
13251 $new_to_ts = $to_ts;
13252 }
13253
13254 // invoke report
13255 $report->injectParams($rparams);
13256 $report_values = $report->getReportValues(1);
13257 $report_cols = $report->getColumnsValues();
13258 $report_chart = null;
13259 $report_chart_metas = array();
13260 $chart_meta_data = array(
13261 'keys' => array(
13262 'occupancy',
13263 'tot_bookings',
13264 'nights_booked',
13265 ),
13266 );
13267 $error = null;
13268
13269 if (!count($report_values)) {
13270 $error = strlen($report->getError()) ? $report->getError() : JText::translate('VBNOTRACKINGS');
13271 } else {
13272 // get doughnut Chart for the requested key
13273 $report_chart = $report->getChart($chart_datatype);
13274
13275 // get Chart meta data
13276 $all_chart_metas = $report->getChartMetaData(null, $chart_meta_data);
13277 if (count($all_chart_metas)) {
13278 // merge all positions into one array
13279 foreach ($all_chart_metas as $pos_metas) {
13280 $report_chart_metas = array_merge($report_chart_metas, $pos_metas);
13281 }
13282 }
13283
13284 if (empty($period_name)) {
13285 $period_name = $report->getProperty('chartTitle');
13286 }
13287 }
13288
13289 // build response
13290 $response = new stdClass;
13291 $response->error = $error;
13292 $response->fromdate = $rparams['fromdate'];
13293 $response->todate = $rparams['todate'];
13294 $response->in_days = $report->countDaysTo($new_from_ts);
13295 $response->in_days_to = $report->countDaysTo($new_to_ts);
13296 $response->in_days_avg = $report->countAverageDays($response->in_days, $response->in_days_to);
13297 $response->period_name = $period_name;
13298 $response->period_date = count($report_values) && isset($report_values['day']) ? $report_values['day']['display_value'] : '';
13299 $response->is_fest = $is_fest;
13300 $response->report_chart = $report_chart;
13301 $response->report_cols = $report_cols;
13302 $response->report_values = $report_values;
13303 $response->report_script = $report->getScript();
13304 $response->chart_labels = $report->getProperty('chartJsLabels');
13305 $response->dataset_label = $report->getProperty('chartJsDataSetLabel');
13306 $response->chart_colors = $report->getProperty('chartJsColors');
13307 $response->chart_data = $report->getProperty('chartJsData');
13308 $response->report_chart_metas = $report_chart_metas;
13309
13310 echo json_encode($response);
13311 exit;
13312 }
13313
13314 /**
13315 * Go to the previous booking.
13316 *
13317 * @uses navigateToBooking()
13318 *
13319 * @since 1.3.0
13320 */
13321 public function prev_booking()
13322 {
13323 $this->navigateToBooking('prev');
13324 }
13325
13326 /**
13327 * Go to the next booking.
13328 *
13329 * @uses navigateToBooking()
13330 *
13331 * @since 1.3.0
13332 */
13333 public function next_booking()
13334 {
13335 $this->navigateToBooking('next');
13336 }
13337
13338 /**
13339 * Given the current booking ID in the request, we navigate
13340 * either to the next or to the previous reservation (if any).
13341 *
13342 * @param string $direction either next or prev.
13343 *
13344 * @return void
13345 *
13346 * @since 1.3.0
13347 */
13348 private function navigateToBooking($direction = 'next')
13349 {
13350 $bid = VikRequest::getInt('whereup', 0, 'request');
13351 if (empty($bid) || $bid < 1 || !in_array($direction, array('prev', 'next'))) {
13352 throw new Exception("Invalid request", 400);
13353 }
13354
13355 $dbo = JFactory::getDbo();
13356 $app = JFactory::getApplication();
13357
13358 $q = "SELECT `id` FROM `#__vikbooking_orders` WHERE `id`" . ($direction == 'next' ? '>' : '<') . "{$bid} ORDER BY `id` " . ($direction == 'next' ? 'ASC' : 'DESC');
13359 $dbo->setQuery($q, 0, 1);
13360 $dbo->execute();
13361 if (!$dbo->getNumRows()) {
13362 VikError::raiseWarning('', JText::translate('VBPEDITBUSYONE'));
13363 $app->redirect("index.php?option=com_vikbooking&task=orders");
13364 exit;
13365 }
13366
13367 $app->redirect("index.php?option=com_vikbooking&task=editorder&cid[]=" . $dbo->loadResult());
13368 exit;
13369 }
13370
13371 /**
13372 * AJAX request: from a list of reservation IDs, we return the ones
13373 * that have a review with the related review ID on VCM.
13374 *
13375 * @since 1.13
13376 */
13377 public function bookings_have_reviews()
13378 {
13379 $dbo = JFactory::getDbo();
13380 $bids = VikRequest::getVar('bids', array(), 'request', 'array');
13381 $vcm_installed = is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php');
13382 $withreviews = array();
13383
13384 if ($vcm_installed && is_array($bids) && count($bids)) {
13385 try {
13386 $q = "SELECT `id`, `idorder` FROM `#__vikchannelmanager_otareviews` WHERE `idorder` IN (" . implode(', ', $bids) . ");";
13387 $dbo->setQuery($q);
13388 $dbo->execute();
13389 if ($dbo->getNumRows()) {
13390 $reviews = $dbo->loadAssocList();
13391 foreach ($reviews as $r) {
13392 $withreviews[$r['idorder']] = $r['id'];
13393 }
13394 }
13395 } catch (Exception $e) {
13396 // do nothing, outdated version
13397 }
13398 }
13399
13400 echo json_encode($withreviews);
13401 exit;
13402 }
13403
13404 /**
13405 * AJAX request for adding a new room-day note.
13406 *
13407 * @return void
13408 *
13409 * @since 1.13.5
13410 */
13411 public function add_roomdaynote()
13412 {
13413 $dt = VikRequest::getString('dt', '', 'request');
13414 $idroom = VikRequest::getInt('idroom', 0, 'request');
13415 $subunit = VikRequest::getInt('subunit', 0, 'request');
13416 $type = VikRequest::getString('type', '', 'request');
13417 $type = empty($type) ? 'custom' : $type;
13418 $name = VikRequest::getString('name', '', 'request');
13419 $descr = VikRequest::getString('descr', '', 'request');
13420 $cdays = VikRequest::getInt('cdays', 0, 'request');
13421 $cdays = $cdays < 0 ? 0 : $cdays;
13422 $cdays = $cdays > 365 ? 365 : $cdays;
13423 if (empty($idroom) || empty($dt) || !strtotime($dt)) {
13424 echo 'e4j.error.1';
13425 exit;
13426 }
13427
13428 // reload end date
13429 $end_date = $dt;
13430
13431 // build critical date object
13432 $new_note = array(
13433 'name' => $name,
13434 'type' => $type,
13435 'descr' => $descr,
13436 );
13437
13438 // get object
13439 $notes = VikBooking::getCriticalDatesInstance();
13440
13441 // store the notes for all consecutive dates
13442 for ($i = 0; $i <= $cdays; $i++) {
13443 $store_dt = $dt;
13444 if ($i > 0) {
13445 $dt_info = getdate(strtotime($store_dt));
13446 $store_dt = date('Y-m-d', mktime(0, 0, 0, $dt_info['mon'], ($dt_info['mday'] + $i), $dt_info['year']));
13447 $end_date = $store_dt;
13448 }
13449 $result = $notes->storeDayNote($new_note, $store_dt, $idroom, $subunit);
13450 if (!$result) {
13451 echo 'e4j.error.2';
13452 exit;
13453 }
13454 }
13455
13456 // reload all room day notes for this day for the AJAX response
13457 $all_notes = $notes->loadRoomDayNotes($dt, $end_date, $idroom, $subunit);
13458
13459 if (!$all_notes || !count($all_notes)) {
13460 // no notes found even after storing it
13461 echo 'e4j.error.3';
13462 exit;
13463 }
13464
13465 echo json_encode($all_notes);
13466 exit;
13467 }
13468
13469 /**
13470 * AJAX request for removing a room day note.
13471 *
13472 * @return void
13473 *
13474 * @since 1.13.5
13475 */
13476 public function remove_roomdaynote()
13477 {
13478 $dt = VikRequest::getString('dt', '', 'request');
13479 $idroom = VikRequest::getInt('idroom', 0, 'request');
13480 $subunit = VikRequest::getInt('subunit', 0, 'request');
13481 $type = VikRequest::getString('type', '', 'request');
13482 $type = empty($type) ? 'custom' : $type;
13483 $ind = VikRequest::getInt('ind', 0, 'request');
13484 if (empty($dt) || !strtotime($dt)) {
13485 echo 'e4j.error.1';
13486 exit;
13487 }
13488
13489 $notes = VikBooking::getCriticalDatesInstance();
13490 $result = $notes->deleteDayNote($ind, $dt, $idroom, $subunit, $type);
13491 if (!$result) {
13492 echo 'e4j.error.2';
13493 exit;
13494 }
13495
13496 echo 'e4j.ok';
13497 exit;
13498 }
13499
13500 /**
13501 * AJAX request for storing an event for a booking.
13502 * Firstly developed for the VCM Reporting API - Guest Misconduct,
13503 * but it can be used for any other purpose.
13504 *
13505 * @return void
13506 *
13507 * @since 1.13.5
13508 */
13509 public function store_booking_history_event()
13510 {
13511 $bid = VikRequest::getInt('bid', 0, 'request');
13512 $event = VikRequest::getString('event', '', 'request');
13513 $descr = VikRequest::getString('descr', '', 'request');
13514
13515 if (empty($bid) || empty($event)) {
13516 throw new Exception("Missing required information", 500);
13517 }
13518
13519 // Booking History
13520 VikBooking::getBookingHistoryInstance()->setBid($bid)->store($event, $descr);
13521 //
13522
13523 echo 'e4j.ok';
13524 exit;
13525 }
13526
13527 /**
13528 * AJAX request for updating an option/extra service.
13529 * Firstly developed for the VCM Vacation Rentals Essentials API - Damage Deposit,
13530 * but it can be used for any other purpose.
13531 *
13532 * @return void
13533 *
13534 * @since 1.13.5
13535 */
13536 public function update_option_params()
13537 {
13538 $optid = VikRequest::getInt('optid', 0, 'request');
13539 $oparams = VikRequest::getVar('oparams', array(), 'request', 'array');
13540
13541 if (empty($optid) || !is_array($oparams) || empty($oparams)) {
13542 throw new Exception("Missing required information", 500);
13543 }
13544
13545 $dbo = JFactory::getDbo();
13546 $q = "SELECT `oparams` FROM `#__vikbooking_optionals` WHERE `id`=" . (int)$optid . ";";
13547 $dbo->setQuery($q);
13548 $dbo->execute();
13549 if (!$dbo->getNumRows()) {
13550 throw new Exception("Option not found", 404);
13551 }
13552 $cur_params = $dbo->loadResult();
13553 $cur_params = !empty($cur_params) ? json_decode($cur_params, true) : array();
13554 $cur_params = !is_array($cur_params) ? array() : $cur_params;
13555
13556 foreach ($oparams as $k => $v) {
13557 if (empty($k)) {
13558 continue;
13559 }
13560 $cur_params[$k] = $v;
13561 }
13562
13563 $q = "UPDATE `#__vikbooking_optionals` SET `oparams`=" . $dbo->quote(json_encode($cur_params)) ." WHERE `id`=" . (int)$optid . ";";
13564 $dbo->setQuery($q);
13565 $dbo->execute();
13566
13567 echo 'e4j.ok';
13568 exit;
13569 }
13570
13571 /**
13572 * Hidden task to clean up duplicate records in certain database tables
13573 * due to a double execution of the installation queries. Ghost records,
13574 * if any, are also removed to clean up issues with hanging records.
13575 *
13576 * @since November 4th 2020
13577 * @since 1.16.3 (J) - 1.6.3 (WP)
13578 */
13579 public function clean_duplicate_records()
13580 {
13581 $dbo = JFactory::getDbo();
13582
13583 $tables_with_duplicates = [
13584 '#__vikbooking_config' => [
13585 'id_key' => 'id',
13586 'compare_key' => 'param',
13587 ],
13588 '#__vikbooking_countries' => [
13589 'id_key' => 'id',
13590 'compare_key' => 'country_3_code',
13591 ],
13592 '#__vikbooking_custfields' => [
13593 'id_key' => 'id',
13594 'compare_key' => 'name',
13595 ],
13596 '#__vikbooking_texts' => [
13597 'id_key' => 'id',
13598 'compare_key' => 'param',
13599 ],
13600 ];
13601
13602 foreach ($tables_with_duplicates as $tblname => $data) {
13603 $doubles = [];
13604 $storage = [];
13605 $rmlist = [];
13606
13607 $q = "SELECT * FROM `{$tblname}` ORDER BY `{$data['id_key']}` DESC;";
13608 $dbo->setQuery($q);
13609 $rows = $dbo->loadAssocList();
13610 if (!$rows) {
13611 echo "<p>No records found in table {$tblname}</p>";
13612 continue;
13613 }
13614
13615 foreach ($rows as $row) {
13616 if (!isset($doubles[$row[$data['compare_key']]])) {
13617 $doubles[$row[$data['compare_key']]] = 0;
13618 }
13619 $doubles[$row[$data['compare_key']]]++;
13620 if (!isset($storage[$row[$data['compare_key']]])) {
13621 $storage[$row[$data['compare_key']]] = [];
13622 }
13623 array_push($storage[$row[$data['compare_key']]], $row[$data['id_key']]);
13624 }
13625
13626 foreach ($doubles as $paramkey => $paramcount) {
13627 if ($paramcount < 2 || !isset($storage[$paramkey]) || count($storage[$paramkey]) < 2 || $paramcount != count($storage[$paramkey])) {
13628 continue;
13629 }
13630 $exceeding = $paramcount - 1;
13631 for ($x = 0; $x < $exceeding; $x++) {
13632 array_push($rmlist, $storage[$paramkey][$x]);
13633 }
13634 }
13635
13636 echo "<p>Total records found in table {$tblname}: " . count($rows) . "</p>";
13637 echo '<p>Total records to remove: ' . count($rmlist) . '</p>';
13638 echo '<pre style="display: none;">'.print_r($rmlist, true).'</pre><br/>';
13639
13640 if (count($rmlist)) {
13641 $q = "DELETE FROM `{$tblname}` WHERE `{$data['id_key']}` IN (" . implode(', ', $rmlist) . ");";
13642 $dbo->setQuery($q);
13643 $dbo->execute();
13644 }
13645 }
13646
13647 /**
13648 * Clean up busy records where the busy relations contain empty booking IDs.
13649 */
13650 $hanging_busy_ids = [];
13651
13652 $q = "SELECT `idbusy` FROM `#__vikbooking_ordersbusy` WHERE `idorder` = 0 OR `idorder` IS NULL;";
13653 $dbo->setQuery($q);
13654 $removelist = $dbo->loadAssocList();
13655 if ($removelist) {
13656 foreach ($removelist as $hanging_busy) {
13657 $hanging_busy_id = (int)$hanging_busy['idbusy'];
13658 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13659 array_push($hanging_busy_ids, $hanging_busy_id);
13660 }
13661 }
13662 }
13663
13664 // let's check also for ghost records that only occupy the room
13665 $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);";
13666 $dbo->setQuery($q);
13667 $removelist = $dbo->loadAssocList();
13668 if ($removelist) {
13669 foreach ($removelist as $hanging_busy) {
13670 $hanging_busy_id = (int)$hanging_busy['id'];
13671 if (!in_array($hanging_busy_id, $hanging_busy_ids)) {
13672 array_push($hanging_busy_ids, $hanging_busy_id);
13673 }
13674 }
13675 }
13676
13677 if ($hanging_busy_ids) {
13678 $q = "DELETE FROM `#__vikbooking_busy` WHERE `id` IN (" . implode(', ', $hanging_busy_ids) . ");";
13679 $dbo->setQuery($q);
13680 $dbo->execute();
13681 }
13682
13683 echo "<p>Total ghost records removed: " . count($hanging_busy_ids) . "</p>";
13684
13685 return;
13686 }
13687
13688 /**
13689 * Loads a specific admin widget ID and executes the requested method.
13690 * Useful for loading a newly added widget, or to execute custom methods.
13691 *
13692 * @see this is an AJAX endpoint.
13693 *
13694 * @since 1.14 (J) - 1.4.0 (WP)
13695 * @since 1.15 (J) - 1.5.0 (WP) widget callback can return values rather than just echoing.
13696 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
13697 */
13698 public function exec_admin_widget()
13699 {
13700 if (!JSession::checkToken()) {
13701 // missing CSRF-proof token
13702 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13703 }
13704
13705 $widget_id = VikRequest::getString('widget_id', '', 'request');
13706 $call = VikRequest::getString('call', '', 'request');
13707 $return = VikRequest::getInt('return', 0, 'request');
13708 $vbo_page = VikRequest::getString('vbo_page', '', 'request');
13709 $vbo_uri = VikRequest::getString('vbo_uri', '', 'request');
13710 $multitask = VikRequest::getInt('multitask', 0, 'request');
13711
13712 if (empty($widget_id)) {
13713 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget ID');
13714 }
13715
13716 if (empty($call) || !is_string($call)) {
13717 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
13718 }
13719
13720 // invoke admin widgets helper
13721 $widgets_helper = VikBooking::getAdminWidgetsInstance();
13722 $widget = $widgets_helper->getWidget($widget_id);
13723
13724 if ($widget === false) {
13725 VBOHttpDocument::getInstance()->close(404, 'Requested Admin Widget not found');
13726 }
13727
13728 if (!method_exists($widget, $call) || !is_callable(array($widget, $call))) {
13729 VBOHttpDocument::getInstance()->close(403, 'Admin Widget Callback not found or not callable');
13730 }
13731
13732 // get the multitask parser object
13733 $parser = VBOMultitaskParser::getInstance($vbo_page, $vbo_uri);
13734
13735 // check if arguments should be passed
13736 $call_args = [];
13737 if ($multitask && $call === 'render') {
13738 // build the multitask data object and inject it to the args as the first index
13739 $call_args[] = $parser->getData();
13740
13741 // bind options within the widget, if any
13742 $widget->bindOptions($call_args[0]);
13743 } else {
13744 // always bind multitask options, if any
13745 $widget->bindOptions($parser->getOptions());
13746 }
13747
13748 try {
13749 if ($return) {
13750 // invoke the widget's method and get the value returned
13751 $widget_response = $call_args ? call_user_func_array([$widget, $call], $call_args) : $widget->{$call}();
13752 } else {
13753 // invoke the widget's method within a buffer
13754 ob_start();
13755 if ($call_args) {
13756 $res = call_user_func_array([$widget, $call], $call_args);
13757 } else {
13758 $widget->{$call}();
13759 }
13760 $widget_response = ob_get_contents();
13761 ob_end_clean();
13762 }
13763 } catch (Throwable $e) {
13764 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
13765 } catch (Exception $e) {
13766 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
13767 }
13768
13769 // prepare response object with a property equal to the called method
13770 $response = new stdClass;
13771 $response->{$call} = $widget_response;
13772
13773 // output the JSON encoded response and exit
13774 VBOHttpDocument::getInstance()->json($response);
13775 }
13776
13777 /**
13778 * Updates the map of admin widgets.
13779 *
13780 * @throws Exception this is an AJAX endpoint.
13781 *
13782 * @since 1.4.0
13783 */
13784 public function save_admin_widgets()
13785 {
13786 if (!JSession::checkToken()) {
13787 // missing CSRF-proof token
13788 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13789 }
13790
13791 // make sure permissions are sufficient
13792 if (!JFactory::getUser()->authorise('core.vbo.global', 'com_vikbooking')) {
13793 VBOHttpDocument::getInstance()->close(403, 'You are not authorized to modify the widgets.');
13794 }
13795
13796 $psections = VikRequest::getVar('sections', array(), 'request', 'array');
13797 if (!is_array($psections) || !count($psections)) {
13798 VBOHttpDocument::getInstance()->close(500, 'No sections found in map');
13799 }
13800
13801 // request values are all converted to arrays, so restore the object styling
13802 $psections = json_decode(json_encode($psections));
13803
13804 // update map
13805 $result = VikBooking::getAdminWidgetsInstance()->updateWidgetsMap($psections);
13806
13807 $response = new stdClass;
13808 $response->status = (int)$result;
13809
13810 // output the JSON encoded response and exit
13811 VBOHttpDocument::getInstance()->json($response);
13812 }
13813
13814 /**
13815 * Restores the default admin widgets map.
13816 *
13817 * @since 1.4.0
13818 */
13819 public function reset_admin_widgets()
13820 {
13821 // reset map and redirect to dashboard
13822 VikBooking::getAdminWidgetsInstance()->restoreDefaultWidgetsMap();
13823
13824 JFactory::getApplication()->redirect('index.php?option=com_vikbooking');
13825 exit;
13826 }
13827
13828 /**
13829 * Updates the welcome message status for the widget's customizer via AJAX.
13830 *
13831 * @since 1.4.0
13832 */
13833 public function admin_widgets_welcome()
13834 {
13835 if (!JSession::checkToken()) {
13836 // missing CSRF-proof token
13837 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
13838 }
13839
13840 $hide_welcome = VikRequest::getInt('hide_welcome', 0, 'request');
13841 // update configuration value
13842 VikBooking::getAdminWidgetsInstance()->updateWelcome($hide_welcome);
13843
13844 $response = new stdClass;
13845 $response->status = $hide_welcome;
13846
13847 // output the JSON encoded response and exit
13848 VBOHttpDocument::getInstance()->json($response);
13849 }
13850
13851 public function newcondtext()
13852 {
13853 VikBookingHelper::printHeader("11");
13854
13855 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13856
13857 parent::display();
13858
13859 if (VikBooking::showFooter()) {
13860 VikBookingHelper::printFooter();
13861 }
13862 }
13863
13864 public function editcondtext()
13865 {
13866 VikBookingHelper::printHeader("11");
13867
13868 VikRequest::setVar('view', VikRequest::getCmd('view', 'managecondtext'));
13869
13870 parent::display();
13871
13872 if (VikBooking::showFooter()) {
13873 VikBookingHelper::printFooter();
13874 }
13875 }
13876
13877 public function cancelcondtext()
13878 {
13879 JFactory::getApplication()->redirect('index.php?option=com_vikbooking&task=config&tab=7');
13880 }
13881
13882 public function createcondtext()
13883 {
13884 if (!JSession::checkToken()) {
13885 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13886 }
13887 $this->_doCreateCondText();
13888 }
13889
13890 public function createcondtextstay()
13891 {
13892 if (!JSession::checkToken()) {
13893 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13894 }
13895 $this->_doCreateCondText(true);
13896 }
13897
13898 private function _doCreateCondText($stay = false)
13899 {
13900 $dbo = JFactory::getDbo();
13901 $app = JFactory::getApplication();
13902 $rules_helper = VikBooking::getConditionalRulesInstance();
13903 $rules_list = $rules_helper->composeRulesParamsFromRequest();
13904
13905 $condtextname = VikRequest::getString('condtextname', '', 'request');
13906 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
13907 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
13908 $debug = VikRequest::getInt('debug', 0, 'request');
13909 if (empty($condtextname)) {
13910 $condtextname = date('Y-m-dHis');
13911 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
13912 }
13913
13914 $existing_tokens = $rules_helper->getSpecialTags();
13915 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn])) {
13916 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists');
13917 $app->redirect('index.php?option=com_vikbooking&task=newcondtext');
13918 exit;
13919 }
13920
13921 $data = new stdClass;
13922 $data->name = $condtextname;
13923 $data->token = $condtexttkn;
13924 $data->rules = json_encode($rules_list);
13925 $data->msg = $msg;
13926 $data->lastupd = JDate::getInstance()->toSql();
13927 $data->debug = $debug;
13928
13929 $dbo->insertObject('#__vikbooking_condtexts', $data, 'id');
13930
13931 if (isset($data->id)) {
13932 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
13933 }
13934
13935 if (!$stay || !isset($data->id)) {
13936 $this->cancelcondtext();
13937 exit;
13938 }
13939
13940 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
13941 }
13942
13943 public function updatecondtext()
13944 {
13945 if (!JSession::checkToken()) {
13946 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13947 }
13948 $this->_doUpdateCondText();
13949 }
13950
13951 public function updatecondtextstay()
13952 {
13953 if (!JSession::checkToken()) {
13954 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
13955 }
13956 $this->_doUpdateCondText(true);
13957 }
13958
13959 private function _doUpdateCondText($stay = false)
13960 {
13961 $dbo = JFactory::getDbo();
13962 $app = JFactory::getApplication();
13963 $rules_helper = VikBooking::getConditionalRulesInstance();
13964 $rules_list = $rules_helper->composeRulesParamsFromRequest();
13965
13966 $pwhere = VikRequest::getInt('where', '', 'request');
13967 $condtextname = VikRequest::getString('condtextname', '', 'request');
13968 $condtexttkn = VikRequest::getString('condtexttkn', '', 'request');
13969 $msg = VikRequest::getString('msg', '', 'request', VIKREQUEST_ALLOWRAW);
13970 $debug = VikRequest::getInt('debug', 0, 'request');
13971 if (empty($condtextname)) {
13972 $condtextname = date('Y-m-dHis');
13973 $condtexttkn = '{condition: ' . date('YmdHis') . '}';
13974 }
13975
13976 $existing_tokens = $rules_helper->getSpecialTags();
13977 if (count($existing_tokens) && isset($existing_tokens[$condtexttkn]) && ($existing_tokens[$condtexttkn]['id'] != $pwhere)) {
13978 VikError::raiseWarning('', 'Another conditional text with the same special tag already exists (' . $existing_tokens[$condtexttkn]['name'] . ')');
13979 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $pwhere);
13980 exit;
13981 }
13982
13983 $data = new stdClass;
13984 $data->id = $pwhere;
13985 $data->name = $condtextname;
13986 $data->token = $condtexttkn;
13987 $data->rules = json_encode($rules_list);
13988 $data->msg = $msg;
13989 $data->lastupd = JDate::getInstance()->toSql();
13990 $data->debug = $debug;
13991
13992 $dbo->updateObject('#__vikbooking_condtexts', $data, 'id');
13993
13994 $app->enqueueMessage(JText::translate('VBSEASONUPDATED'));
13995
13996 if (!$stay) {
13997 $this->cancelcondtext();
13998 exit;
13999 }
14000
14001 $app->redirect('index.php?option=com_vikbooking&task=editcondtext&cid[]=' . $data->id);
14002 }
14003
14004 public function removecondtext()
14005 {
14006 $dbo = JFactory::getDbo();
14007 $ids = VikRequest::getVar('cid', array());
14008
14009 VikBooking::getConditionalRulesInstance(true);
14010 $templates = VikBookingHelperConditionalRules::getTemplateFilesPaths();
14011
14012 foreach ($ids as $d) {
14013 $q = "SELECT `token` FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14014 $dbo->setQuery($q);
14015 $dbo->execute();
14016 if (!$dbo->getNumRows()) {
14017 continue;
14018 }
14019 $special_tag = $dbo->loadResult();
14020
14021 // remove the token from each template file if it was used before
14022 if (!empty($special_tag)) {
14023 // remove token from all template files
14024 foreach ($templates as $tkey => $tpath) {
14025 // get requested file content
14026 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($tkey);
14027 if (empty($fcontent) || !is_string($fcontent)) {
14028 break;
14029 }
14030 // remove tag from code content
14031 $fcontent = str_replace($special_tag, '', $fcontent);
14032 // update the file code
14033 VikBookingHelperConditionalRules::writeTemplateFileCode($tkey, $fcontent);
14034 }
14035 }
14036
14037 // delete the record
14038 $q = "DELETE FROM `#__vikbooking_condtexts` WHERE `id`=" . (int)$d . ";";
14039 $dbo->setQuery($q);
14040 $dbo->execute();
14041 }
14042
14043 $this->cancelcondtext();
14044 }
14045
14046 /**
14047 * AJAX endpoint to update one template file with the given tag or styles.
14048 * A JSON response will be echoed by exiting the process.
14049 */
14050 public function condtext_update_tmpl()
14051 {
14052 VikBooking::getConditionalRulesInstance(true);
14053
14054 $tagaction = VikRequest::getString('tagaction', '', 'request');
14055 $tag = VikRequest::getString('tag', '', 'request');
14056 $file = VikRequest::getString('file', '', 'request', VIKREQUEST_ALLOWRAW);
14057 $newcontent = VikRequest::getString('newcontent', '', 'request', VIKREQUEST_ALLOWRAW);
14058 $custom_classes = VikRequest::getVar('custom_classes', array(), 'request', 'array');
14059
14060 $allowed_actions = array(
14061 'add',
14062 'remove',
14063 'styles',
14064 'restore',
14065 );
14066
14067 if (empty($tagaction) || empty($file) || !in_array($tagaction, $allowed_actions)) {
14068 throw new Exception("Invalid request submitted", 500);
14069 }
14070
14071 if (in_array($tagaction, array('add', 'remove')) && empty($tag)) {
14072 throw new Exception("Invalid request submitted - missing tag", 500);
14073 }
14074
14075 if (in_array($tagaction, array('add', 'styles')) && empty($newcontent)) {
14076 throw new Exception("Invalid request submitted - missing new HTML content", 500);
14077 }
14078
14079 if ($tagaction == 'styles' && (!is_array($custom_classes) || !count($custom_classes))) {
14080 throw new Exception("No custom CSS classes to parse", 500);
14081 }
14082
14083 if ($tagaction == 'restore') {
14084 // immediately restore the requested file to avoid script interruptions
14085 VikBookingHelperConditionalRules::restoreTemplateFileCode($file);
14086 }
14087
14088 // get requested file content
14089 $fcontent = VikBookingHelperConditionalRules::getTemplateFileCode($file);
14090 if (empty($fcontent) || !is_string($fcontent)) {
14091 throw new Exception("File not found or its code is unreadable", 404);
14092 }
14093
14094 if ($tagaction == 'remove') {
14095 // remove tag from code content
14096 $fcontent = str_replace($tag, '', $fcontent);
14097 } elseif ($tagaction == 'add') {
14098 // add tag to code content in the same exact position
14099 $fcontent = VikBookingHelperConditionalRules::addTagByComparingSources($tag, $file, $newcontent, $fcontent);
14100 } elseif ($tagaction == 'styles') {
14101 // apply the same styling rules
14102 $fcontent = VikBookingHelperConditionalRules::addStylesByComparingSources($custom_classes, $file, $newcontent, $fcontent);
14103 }
14104
14105 // update the file code
14106 $res = VikBookingHelperConditionalRules::writeTemplateFileCode($file, $fcontent);
14107
14108 if (!$res) {
14109 throw new Exception("Could not update the source code of the template file", 500);
14110 }
14111
14112 // parse new HTML content
14113 $newhtmls = VikBookingHelperConditionalRules::getTemplateFilesContents($file);
14114 if (!is_array($newhtmls) || !isset($newhtmls[$file])) {
14115 throw new Exception("Could not parse new template file content", 404);
14116 }
14117
14118 // trigger backup/mirroring, if available
14119 if (VBOPlatformDetection::isWordPress()) {
14120 VikBookingUpdateManager::storeTemplateContent($file, $newhtmls[$file]);
14121 }
14122
14123 // build output
14124 $output = new stdClass;
14125 $output->newhtml = $newhtmls[$file];
14126 $output->log = VikBookingHelperConditionalRules::getEditingLog();
14127
14128 echo json_encode($output);
14129 exit;
14130 }
14131
14132 /**
14133 * AJAX endpoint to invoke methods of the geocoding helper.
14134 */
14135 public function geocoding_endpoint()
14136 {
14137 $geo = VikBooking::getGeocodingInstance();
14138 $callback = VikRequest::getString('callback', '', 'request');
14139
14140 if (empty($callback) || !method_exists($geo, $callback) || !is_callable(array($geo, $callback))) {
14141 throw new Exception("Callback not available", 403);
14142 }
14143
14144 // invoke requested method
14145 $res = $geo->{$callback}();
14146
14147 // prepare response
14148 $response = new stdClass;
14149 $response->{$callback} = $res;
14150
14151 echo json_encode($response);
14152 exit;
14153 }
14154
14155 public function refundtn()
14156 {
14157 //modal box, so we do not set menu or footer
14158
14159 VikRequest::setVar('view', VikRequest::getCmd('view', 'refundtn'));
14160
14161 parent::display();
14162 }
14163
14164 public function do_refundtn()
14165 {
14166 $dbo = JFactory::getDbo();
14167 $app = JFactory::getApplication();
14168
14169 $bid = VikRequest::getInt('bid', 0, 'request');
14170 $amount = VikRequest::getFloat('amount', 0, 'request');
14171 $refund_reason = VikRequest::getString('refund_reason', '', 'request');
14172 $tmpl = VikRequest::getString('tmpl', '', 'request');
14173 $nav_suffix = $tmpl == 'component' ? '&tmpl=component' : '';
14174
14175 $currencysymb = VikBooking::getCurrencySymb();
14176
14177 if (empty($bid) || $amount <= 0) {
14178 VikError::raiseWarning('', JText::translate('VBO_PLEASE_FILL_FIELDS'));
14179 $app->redirect('index.php?option=com_vikbooking');
14180 exit;
14181 }
14182
14183 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid . " AND `status`!='standby';";
14184 $dbo->setQuery($q);
14185 $dbo->execute();
14186 if ($dbo->getNumRows() < 1) {
14187 VikError::raiseWarning('', 'Booking not found');
14188 $app->redirect('index.php?option=com_vikbooking');
14189 exit;
14190 }
14191 $row = $dbo->loadAssoc();
14192
14193 // get booking history instance
14194 $history_obj = VikBooking::getBookingHistoryInstance();
14195 $history_obj->setBid($row['id']);
14196
14197 // get payment information
14198 $payment = VikBooking::getPayment($row['idpayment']);
14199 $tn_driver = is_array($payment) ? $payment['file'] : null;
14200
14201 // transaction data validation callback
14202 $tn_data_callback = function($data) use ($tn_driver) {
14203 return (is_object($data) && isset($data->driver) && basename($data->driver, '.php') == basename($tn_driver, '.php'));
14204 };
14205 // get previous transactions
14206 $prev_tn_data = $history_obj->getEventsWithData(array('P0', 'PN'), $tn_data_callback);
14207
14208 if (!is_array($prev_tn_data) || !count($prev_tn_data)) {
14209 // no previous transactions found
14210 VikError::raiseWarning('', 'No previous transactions found, unable to issue the refund');
14211 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14212 exit;
14213 }
14214
14215 // push refund information for the payment gateway
14216 $row['total_to_refund'] = $amount;
14217 $row['transaction'] = $prev_tn_data;
14218 $row['refund_reason'] = $refund_reason;
14219
14220 // push the transaction currency information
14221 $row['transaction_currency'] = VikBooking::getCurrencyCodePp();
14222
14223 /**
14224 * @wponly The payment gateway is loaded
14225 * through the apposite dispatcher.
14226 */
14227 JLoader::import('adapter.payment.dispatcher');
14228 $obj = JPaymentDispatcher::getInstance('vikbooking', $payment['file'], $row, $payment['params']);
14229
14230 if (!method_exists($obj, 'isRefundSupported') || !$obj->isRefundSupported()) {
14231 // refund not supported
14232 VikError::raiseWarning('', 'The selected payment method does not support refunds');
14233 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14234 exit;
14235 }
14236
14237 // perform the refund transaction
14238 $array_result = $obj->refund();
14239
14240 if ($array_result['verified'] != 1) {
14241 // raise warning by getting the message
14242 if (!empty($array_result['log']) && is_string($array_result['log'])) {
14243 VikError::raiseWarning('', $array_result['log']);
14244 } else {
14245 VikError::raiseWarning('', 'Operation failed');
14246 }
14247 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . $nav_suffix);
14248 exit;
14249 }
14250
14251 /**
14252 * New payment plugins can return the total amount refunded ('tot_paid').
14253 *
14254 * @since 1.15.4 (J) - 1.5.10 (WP)
14255 */
14256 if (!empty($array_result['tot_paid'])) {
14257 // overwrite the requested amount with the returned one
14258 $amount = (float)$array_result['tot_paid'];
14259 }
14260
14261 // update total paid, total and refund columns for the booking
14262 $booking = new stdClass;
14263 $booking->id = $row['id'];
14264 if ($row['totpaid'] > 0) {
14265 $booking->totpaid = $row['totpaid'] - $amount;
14266 }
14267 if ($row['total'] > 0) {
14268 $booking->total = $row['total'] - $amount;
14269 }
14270 $booking->refund = (float)$row['refund'] + $amount;
14271 // update record in db
14272 $dbo->updateObject('#__vikbooking_orders', $booking, 'id');
14273
14274 // store the refund event
14275 $event_descr = array(
14276 '(' . $payment['name'] . ')',
14277 $refund_reason,
14278 $currencysymb . ' ' . VikBooking::numberFormat($amount),
14279 );
14280 $history_obj->store('RF', implode("\n", $event_descr));
14281
14282 // display success message and redirect
14283 $app->enqueueMessage(JText::translate('VBO_REFUND_SUCCESS'));
14284 $app->redirect('index.php?option=com_vikbooking&task=refundtn&cid[]=' . $row['id'] . '&success=1' . $nav_suffix);
14285 exit;
14286 }
14287
14288 /**
14289 * AJAX upload endpoint for media files.
14290 *
14291 * @return void
14292 *
14293 * @throws Exception
14294 *
14295 * @since 1.15.0 (J) - 1.5.0 (WP)
14296 */
14297 public function upload_media_file()
14298 {
14299 $input = JFactory::getApplication()->input;
14300
14301 // allowed types
14302 $type = $input->getString('type', '');
14303 $mask = "/(image\/.+)|(application\/(zip|rar|pdf|msword|vnd.*?))|(text\/(plain|markdown|csv))$/i";
14304 if ($type == 'image') {
14305 $mask = "/(image\/.+)$/i";
14306 }
14307
14308 // response object
14309 $result = new stdClass;
14310 $result->status = 0;
14311
14312 try
14313 {
14314 // get file from request
14315 $file = $input->files->get('file', array(), 'array');
14316
14317 // try to upload the file
14318 $result = VikBooking::uploadFileFromRequest($file, VBO_MEDIA_PATH, $mask);
14319 $result->status = 1;
14320
14321 $result->size = JHtml::fetch('number.bytes', filesize($result->path), 'auto', 0);
14322 $result->url = str_replace(DIRECTORY_SEPARATOR, '/', str_replace(VBO_MEDIA_PATH . DIRECTORY_SEPARATOR, VBO_MEDIA_URI, $result->path));
14323 }
14324 catch (Exception $e)
14325 {
14326 $result->error = $e->getMessage();
14327 $result->code = $e->getCode();
14328 }
14329
14330 echo json_encode($result);
14331 exit;
14332 }
14333
14334 /**
14335 * AJAX endpoint to invoke a report object's method.
14336 *
14337 * @return void
14338 *
14339 * @throws Exception
14340 *
14341 * @since 1.15.0 (J) - 1.5.0 (WP)
14342 */
14343 public function invoke_report()
14344 {
14345 $report_name = VikRequest::getString('report', '', 'request');
14346 $report_call = VikRequest::getString('call', '', 'request');
14347 $params = VikRequest::getVar('params', array(), 'request', 'array');
14348
14349 if (empty($report_name)) {
14350 VBOHttpDocument::getInstance()->close(400, 'Missing report name');
14351 }
14352
14353 if (empty($report_call)) {
14354 VBOHttpDocument::getInstance()->close(400, 'Missing report call');
14355 }
14356
14357 // get requested report instance
14358 $report = VikBooking::getReportInstance($report_name);
14359 if (!$report) {
14360 VBOHttpDocument::getInstance()->close(404, 'Report not found');
14361 }
14362
14363 if (!method_exists($report, $report_call) || !is_callable(array($report, $report_call))) {
14364 VBOHttpDocument::getInstance()->close(403, sprintf('Cannot call [%s] on report', $report_call));
14365 }
14366
14367 // call on report's method
14368 $result = $report->{$report_call}($params);
14369
14370 if (is_null($result)) {
14371 VBOHttpDocument::getInstance()->close(400, 'Null response');
14372 }
14373
14374 if (is_scalar($result)) {
14375 // wrap result within an array for a JSON encoded response
14376 VBOHttpDocument::getInstance()->json([$result]);
14377 }
14378
14379 // output the JSON encoded array/object returned
14380 VBOHttpDocument::getInstance()->json($result);
14381 }
14382
14383 /**
14384 * Handles requests for the multitask widgets panel.
14385 *
14386 * @see this is an AJAX endpoint.
14387 *
14388 * @since 1.15.0 (J) - 1.5.0 (WP)
14389 * @since 1.16.5 (J) - 1.6.5 (WP) widgets are rendered within a try-catch statement.
14390 */
14391 public function exec_multitask_widgets()
14392 {
14393 if (!JSession::checkToken()) {
14394 // missing CSRF-proof token
14395 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14396 }
14397
14398 $call = VikRequest::getString('call', '', 'request');
14399 $call_args = VikRequest::getVar('call_args', array(), 'request', 'array');
14400
14401 if (empty($call)) {
14402 VBOHttpDocument::getInstance()->close(500, 'Empty Admin Widget Callback');
14403 }
14404
14405 // invoke admin widgets helper
14406 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14407
14408 if (!method_exists($widgets_helper, $call) || !is_callable(array($widgets_helper, $call))) {
14409 VBOHttpDocument::getInstance()->close(403, 'Admin Widgets Callback not found or not callable');
14410 }
14411
14412 try {
14413 // invoke the helper's method and get the value returned
14414 if (is_array($call_args) && count($call_args)) {
14415 $result = call_user_func_array(array($widgets_helper, $call), $call_args);
14416 } else {
14417 $result = $widgets_helper->{$call}();
14418 }
14419 } catch (Throwable $e) {
14420 VBOHttpDocument::getInstance()->close($e->getCode() ?: 500, $e->getMessage());
14421 } catch (Exception $e) {
14422 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14423 }
14424
14425 // prepare response object with a property equal to the called method
14426 $response = new stdClass;
14427 $response->result = $result;
14428
14429 // output the JSON response and exit
14430 VBOHttpDocument::getInstance()->json($response);
14431 }
14432
14433 /**
14434 * Handles requests for displaying a browser notification being dispatched.
14435 *
14436 * @see this is an AJAX endpoint.
14437 *
14438 * @since 1.15.0 (J) - 1.5.0 (WP)
14439 */
14440 public function notification_displayer()
14441 {
14442 $payload_str = VikRequest::getString('payload', '', 'request', VIKREQUEST_ALLOWRAW);
14443
14444 if (empty($payload_str)) {
14445 VBOHttpDocument::getInstance()->close(500, 'Empty notification payload');
14446 }
14447
14448 // attempt to decode the notification payload
14449 $payload = json_decode($payload_str);
14450
14451 if (!is_object($payload)) {
14452 VBOHttpDocument::getInstance()->close(500, 'Could not decode notification payload: ' . $payload_str);
14453 }
14454
14455 // get notification displayer for this type of notification
14456 $displayer = VBONotificationBuilder::getInstance($payload)->getDisplayer();
14457 if (!$displayer) {
14458 VBOHttpDocument::getInstance()->close(500, 'Could not build notification display data from payload: ' . $payload_str);
14459 }
14460
14461 // compose the notification display data object
14462 try {
14463 $notif_data = $displayer->getData();
14464 if (!$notif_data) {
14465 throw new Exception('Error building the notification display data', 500);
14466 }
14467 } catch (Exception $e) {
14468 VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage());
14469 }
14470
14471 // output the JSON response and exit
14472 VBOHttpDocument::getInstance()->json($notif_data);
14473 }
14474
14475 /**
14476 * Handles requests for watching widgets data and getting
14477 * new events to trigger browser notifications.
14478 *
14479 * @see this is an AJAX endpoint.
14480 *
14481 * @since 1.15.0 (J) - 1.5.0 (WP)
14482 */
14483 public function widgets_watch_data()
14484 {
14485 if (!JSession::checkToken()) {
14486 // missing CSRF-proof token
14487 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
14488 }
14489
14490 $app = JFactory::getApplication();
14491
14492 $watch_data_str = $app->input->get('watch_data', '', 'raw');
14493 $pushed_data_str = $app->input->get('pushed_data', '[]', 'raw');
14494
14495 if (empty($watch_data_str)) {
14496 VBOHttpDocument::getInstance()->close(500, 'Empty watch-data payload');
14497 }
14498
14499 // attempt to decode the watch-data payload
14500 $watch_data = json_decode($watch_data_str, true);
14501
14502 if (!$watch_data) {
14503 VBOHttpDocument::getInstance()->close(500, 'Could not decode watch-data payload: ' . $watch_data_str);
14504 }
14505
14506 // check if any pushed data was set
14507 $pushed_data = (array)json_decode($pushed_data_str, true);
14508
14509 // container for new notifications
14510 $notifs_pool = [];
14511
14512 // get admin widgets helper
14513 $widgets_helper = VikBooking::getAdminWidgetsInstance();
14514
14515 foreach ($watch_data as $widget_id => $data) {
14516 // invoke admin widget (with no pre-loading)
14517 $widget_instance = $widgets_helper->getWidget($widget_id);
14518 if (!$widget_instance) {
14519 continue;
14520 }
14521
14522 // build the widget watch data object
14523 $widget_watch_data = VBONotificationWatchdata::getInstance($data)->setPushedData($pushed_data);
14524
14525 // check if the widget needs to emit browser notifications
14526 list($watch_next, $notifications) = $widget_instance->getNotifications($widget_watch_data);
14527
14528 if ($watch_next) {
14529 // update next watch-data object for this widget
14530 $watch_data[$widget_id] = $watch_next;
14531 }
14532
14533 if (is_array($notifications) && $notifications) {
14534 $notifs_pool = array_merge($notifs_pool, $notifications);
14535 }
14536 }
14537
14538 // build the response object
14539 $response = new stdClass;
14540 $response->watch_data = $watch_data;
14541 $response->notifications = $notifs_pool;
14542
14543 // output the JSON response and exit
14544 VBOHttpDocument::getInstance()->json($response);
14545 }
14546
14547 /**
14548 * Outputs a list of CSS assets required to render the admin widgets
14549 * externally from Vik Booking. Useful i.e. to Vik Channel Manager.
14550 *
14551 * @see this is an AJAX endpoint.
14552 *
14553 * @since 1.16.0 (J) - 1.6.0 (WP)
14554 */
14555 public function widgets_get_assets()
14556 {
14557 // list of needed CSS asset details
14558 $assets_pool = [];
14559
14560 // appearance preference assets (one or none)
14561 $app_pref_asset = VikBooking::loadAppearancePreferenceAssets($get_info = true);
14562
14563 if (VBOPlatformDetection::isWordPress()) {
14564 // WordPress (main CSS)
14565 $assets_pool[] = [
14566 'rel' => 'stylesheet',
14567 'id' => 'vbo-style-css',
14568 'href' => VIKBOOKING_ADMIN_ASSETS_URI . 'vikbooking.css?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14569 'media' => 'all',
14570 ];
14571
14572 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14573 // appearance preference CSS
14574 $assets_pool[] = [
14575 'rel' => 'stylesheet',
14576 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14577 'href' => $app_pref_asset['href'] . '?ver=' . VIKBOOKING_SOFTWARE_VERSION,
14578 'media' => 'all',
14579 ];
14580 }
14581 } else {
14582 // Joomla (main CSS)
14583 $assets_pool[] = [
14584 'rel' => 'stylesheet',
14585 'id' => 'vbo-style-css',
14586 'href' => VBO_ADMIN_URI . 'vikbooking.css?' . VIKBOOKING_SOFTWARE_VERSION,
14587 'media' => 'all',
14588 ];
14589
14590 if (is_array($app_pref_asset) && !empty($app_pref_asset['href'])) {
14591 // appearance preference CSS
14592 $assets_pool[] = [
14593 'rel' => 'stylesheet',
14594 'id' => (!empty($app_pref_asset['id']) ? $app_pref_asset['id'] : rand()),
14595 'href' => $app_pref_asset['href'] . '?' . VIKBOOKING_SOFTWARE_VERSION,
14596 'media' => 'all',
14597 ];
14598 }
14599 }
14600
14601 // output the JSON response and exit
14602 VBOHttpDocument::getInstance()->json($assets_pool);
14603 }
14604 }
14605