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 / site / helpers / tac.vikbooking.php

tac.vikbooking.php in VikBooking Hotel Booking Engine & PMS 1.6.5, at site/helpers/tac.vikbooking.php

605 lines 21.9 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 /**
14 * Helper class originally introcued to get the hotel availability and rates.
15 */
16 class TACVBO
17 {
18 /**
19 * @var bool whether to return an array.
20 */
21 public static $getArray = false;
22
23 /**
24 * @var bool flag to ignore booking restrictions.
25 *
26 * @since 1.15.0 (J) - 1.5.0 (WP)
27 */
28 public static $ignoreRestrictions = false;
29
30 /**
31 * Error code identifier:
32 *
33 * 1 = missing/invalid request options.
34 * 2 = invalid authentication.
35 * 3 = no rooms found for the given party.
36 * 4 = not compliant with booking restrictions.
37 * 5 = not compliant with global closing dates.
38 * 6 = no rates defined for the given length of stay.
39 * 7 = no availability for the dates requested (error code 8 might have occurred as well).
40 * 8 = no rooms available due to restrictions at room or rate plan level.
41 *
42 * @var int the error code identifier.
43 *
44 * @since 1.15.0 (J) - 1.5.0 (WP)
45 */
46 protected static $errorCode = 0;
47
48 /**
49 * Given the request or injected arguments, calulcates the availability and rates.
50 *
51 * @param array $options forced options injected rather than request variables.
52 *
53 * @return mixed array with values or error description if getArray=true, or void.
54 *
55 * @since 1.15.0 (J) - 1.5.0 (WP) added $options argument.
56 */
57 public static function tac_av_l($options = array())
58 {
59 $dbo = JFactory::getDbo();
60 $vbo_tn = VikBooking::getTranslator();
61
62 $response = 'e4j.error';
63 $args = $options;
64
65 /**
66 * All the calls to VikRequest's methods should not use 'request' as 3rd argument,
67 * but rather 'default' to get the right $input object in the VikRequest Class.
68 * This will resolve issues after the setVar() method was called by other functions.
69 * POST and GET requests will still provide non-empty values by using 'default'.
70 *
71 * @since 1.10
72 */
73 $args['hash'] = empty($args['hash']) ? VikRequest::getString('e4jauth', '', 'default') : $args['hash'];
74 $args['start_date'] = empty($args['start_date']) ? VikRequest::getString('start_date', '', 'default') : $args['start_date'];
75 $args['end_date'] = empty($args['end_date']) ? VikRequest::getString('end_date', '', 'default') : $args['end_date'];
76 $args['nights'] = empty($args['nights']) ? VikRequest::getInt('nights', 1, 'default') : $args['nights'];
77 $args['num_rooms'] = empty($args['num_rooms']) ? VikRequest::getInt('num_rooms', 1, 'default') : $args['num_rooms'];
78
79 $args['start_ts'] = strtotime($args['start_date']);
80 $args['end_ts'] = strtotime($args['end_date']);
81
82 $valid = true;
83 $mandatory_keys = array(
84 'start_date',
85 'end_date',
86 'nights',
87 'num_rooms',
88 );
89 foreach ($mandatory_keys as $man_key) {
90 $valid = $valid && isset($args[$man_key]) && !empty($args[$man_key]);
91 }
92
93 // request type
94 $req_type = VikRequest::getString('req_type', '', 'default');
95 $req_type = empty($req_type) && !empty($args['req_type']) ? $args['req_type'] : $req_type;
96
97 // API version
98 $tac_apiv = 4;
99 // API v4
100 $args['num_adults'] = empty($args['num_adults']) ? VikRequest::getInt('num_adults', 1, 'request') : $args['num_adults'];
101 // API v5
102 $args['adults'] = empty($args['adults']) ? VikRequest::getVar('adults', array()) : $args['adults'];
103 $args['children'] = empty($args['children']) ? VikRequest::getVar('children', array()) : $args['children'];
104 $args['children_age'] = empty($args['children_age']) ? VikRequest::getVar('children_age', array()) : $args['children_age'];
105 if (!empty($args['adults']) && !empty($args['children'])) {
106 $tac_apiv = 5;
107 }
108
109 if ($tac_apiv == 4) {
110 $valid = !empty($args['num_adults']) ? $valid : false;
111 } elseif ($tac_apiv == 5) {
112 $valid = !empty($args['adults']) ? $valid : false;
113 }
114
115 /**
116 * The back-end page Calendar can allow the admin to force bookings in case of
117 * no-availability. Its AJAX requests will contain "only_rates=1" and we compose
118 * an extra array-key with all the fully-booked rooms for the requested dates.
119 *
120 * @since 1.14 (J) - 1.4.0 (WP)
121 */
122 $only_rates = VikRequest::getInt('only_rates', 0, 'request');
123 $only_rates = empty($only_rates) && !empty($args['only_rates']) ? $args['only_rates'] : $only_rates;
124 $fullybooked = array();
125
126 if (!$valid) {
127 // set error code
128 self::$errorCode = 1;
129
130 if (self::$getArray) {
131 return $response;
132 }
133 echo $response;
134 exit;
135 }
136
137 $checkauth = md5('vbo.e4j.vbo');
138 if ($checkauth != $args['hash'] && !count($options)) {
139 // set error code
140 self::$errorCode = 2;
141
142 $response = 'e4j.error.auth';
143 if (self::$getArray) {
144 return $response;
145 }
146 echo $response;
147 exit;
148 }
149
150 $avail_rooms = array();
151 if ($tac_apiv == 5) {
152 // compose adults-children array and sql clause
153 $arradultsrooms = array();
154 $arradultsclause = array();
155 $arrpeople = array();
156 if (count($args['adults']) > 0) {
157 foreach ($args['adults'] as $kad => $adu) {
158 $roomnumb = $kad + 1;
159 if (strlen($adu)) {
160 $numadults = intval($adu);
161 if ($numadults >= 0) {
162 $arradultsrooms[$roomnumb] = $numadults;
163 $arrpeople[$roomnumb]['adults'] = $numadults;
164 $strclause = "(`fromadult`<=".$numadults." AND `toadult`>=".$numadults."";
165 if (!empty($args['children'][$kad]) && intval($args['children'][$kad]) > 0) {
166 $numchildren = intval($args['children'][$kad]);
167 $arrpeople[$roomnumb]['children'] = $numchildren;
168 $arrpeople[$roomnumb]['children_age'] = isset($args['children_age'][$roomnumb]) && count($args['children_age'][$roomnumb]) ? $args['children_age'][$roomnumb] : array();
169 $strclause .= " AND `fromchild`<=".$numchildren." AND `tochild`>=".$numchildren."";
170 } else {
171 $arrpeople[$roomnumb]['children'] = 0;
172 $arrpeople[$roomnumb]['children_age'] = array();
173 if (intval($args['children'][$kad]) == 0) {
174 $strclause .= " AND `fromchild` = 0";
175 }
176 }
177 $strclause .= " AND `totpeople` >= ".($arrpeople[$roomnumb]['adults'] + $arrpeople[$roomnumb]['children']);
178 $strclause .= " AND `mintotpeople` <= ".($arrpeople[$roomnumb]['adults'] + $arrpeople[$roomnumb]['children']);
179 $strclause .= ")";
180 $arradultsclause[] = $strclause;
181 }
182 }
183 }
184 }
185 // set $args['adults'] to the number of adults occupying the first room but it could be a party of multiple rooms
186 $args['num_adults'] = $arrpeople[1]['adults'];
187 // this clause would return one room type for each party type: implode(" OR ", $arradultsclause) - the AND clause must be used rather than OR.
188 $q = "SELECT `id`, `units` FROM `#__vikbooking_rooms` WHERE `avail`=1 AND (".implode(" AND ", $arradultsclause).");";
189 } else {
190 // API v4
191 $arrpeople = array();
192 $arrpeople[1]['adults'] = $args['num_adults'];
193 $arrpeople[1]['children'] = 0;
194 $q = "SELECT `id`, `units` FROM `#__vikbooking_rooms` WHERE `avail`=1 AND `toadult`>=".$args['num_adults'].";";
195 }
196 $dbo->setQuery($q);
197 $avail_rooms = $dbo->loadAssocList();
198 if (!$avail_rooms) {
199 // set error code
200 self::$errorCode = 3;
201
202 if (self::$getArray) {
203 return array('e4j.error' => 'The Query for fetching the rooms returned an empty result');
204 }
205 echo json_encode(array('e4j.error' => 'The Query for fetching the rooms returned an empty result'));
206 exit;
207 }
208
209 // arr[0] = (sec) checkin, arr[1] = (sec) checkout
210 $check_in_out = VikBooking::getTimeOpenStore();
211 if (is_array($check_in_out)) {
212 $args['start_ts'] += $check_in_out[0];
213 $args['end_ts'] += $check_in_out[1];
214 }
215
216 $room_ids = array();
217 for ($i = 0; $i < count($avail_rooms); $i++) {
218 $room_ids[$i] = $avail_rooms[$i]['id'];
219 }
220
221 $all_restrictions = VikBooking::loadRestrictions(true, $room_ids);
222 $glob_restrictions = VikBooking::globalRestrictions($all_restrictions);
223
224 // validate restrictions error message
225 $x_restr = count($glob_restrictions) ? VikBooking::validateRoomRestriction($glob_restrictions, getdate($args['start_ts']), getdate($args['end_ts']), $args['nights']) : '';
226
227 if (!self::$ignoreRestrictions && strlen($x_restr) > 0) {
228 // set error code
229 self::$errorCode = 4;
230
231 if (self::$getArray) {
232 return array('e4j.error' => 'Unable to proceed because of booking Restrictions in these dates (' . $x_restr . ')');
233 }
234 echo json_encode(array('e4j.error' => 'Unable to proceed because of booking Restrictions in these dates (' . $x_restr . ')'));
235 exit;
236 }
237
238 $nowdf = VikBooking::getDateFormat();
239 if ($nowdf == "%d/%m/%Y") {
240 $df = 'd/m/Y';
241 } elseif ($nowdf == "%m/%d/%Y") {
242 $df = 'm/d/Y';
243 } else {
244 $df = 'Y/m/d';
245 }
246 // closing dates
247 $err_closingdates = VikBooking::validateClosingDates($args['start_ts'], $args['end_ts'], $df);
248 if (!self::$ignoreRestrictions && !empty($err_closingdates)) {
249 // set error code
250 self::$errorCode = 5;
251
252 if (self::$getArray) {
253 return array('e4j.error' => JText::sprintf('VBERRDATESCLOSED', $err_closingdates));
254 }
255 echo json_encode(array('e4j.error' => JText::sprintf('VBERRDATESCLOSED', $err_closingdates)));
256 exit;
257 }
258
259 // hours to arrival may affect rate plan restrictions
260 $hoursdiff = VikBooking::countHoursToArrival($args['start_ts']);
261
262 // get rates
263 $room_ids = array();
264 foreach ($avail_rooms as $k => $room) {
265 $room_ids[$room['id']] = $room;
266 }
267 $rates = array();
268 $q = "SELECT `p`.*, `r`.`id` AS `r_reference_id`, `r`.`name` AS `r_short_desc`, `r`.`img`, `r`.`units`, `r`.`moreimgs`, `r`.`imgcaptions`, `prices`.`id` AS `price_reference_id`, `prices`.`name` AS `pricename`, `prices`.`breakfast_included`, `prices`.`free_cancellation`, `prices`.`canc_deadline`, `prices`.`minlos`, `prices`.`minhadv` FROM `#__vikbooking_dispcost` AS `p`, `#__vikbooking_rooms` AS `r`, `#__vikbooking_prices` AS `prices` WHERE `r`.`id`=`p`.`idroom` AND `p`.`idprice`=`prices`.`id` AND `p`.`days`=".$args['nights']." AND `r`.`id` IN (".implode(',', array_keys($room_ids)).") ORDER BY `p`.`cost` ASC;";
269 $dbo->setQuery($q);
270 $rates = $dbo->loadAssocList();
271 if (!$rates) {
272 // set error code
273 self::$errorCode = 6;
274
275 if (self::$getArray) {
276 return array('e4j.error' => 'The Query for fetching the rates returned an empty result');
277 }
278 echo json_encode(array('e4j.error' => 'The Query for fetching the rates returned an empty result'));
279 exit;
280 }
281 $vbo_tn->translateContents($rates, '#__vikbooking_rooms', array('id' => 'r_reference_id', 'r_short_desc' => 'name'));
282 $vbo_tn->translateContents($rates, '#__vikbooking_prices', array('id' => 'price_reference_id', 'pricename' => 'name'));
283 $arr_rates = array();
284 /**
285 * If all results are excluded because of restrictions at rate plan level, we use this flag
286 * to know that the rate plans have a Min LOS or a Min Hours in Advance (Advance Booking Offset).
287 * This is to avoid users to say "why do I get no availability?"
288 *
289 * @since 1.12.1
290 */
291 $err_rplan_restr = false;
292 //
293 foreach ($rates as $rate) {
294 // rate plans with a minlos, or with a min hours in advance
295 if ((!empty($rate['minlos']) && $rate['minlos'] > $args['nights']) || $hoursdiff < $rate['minhadv']) {
296 // this flag will tell us that some results were excluded due to restrictions at rate plan level
297 $err_rplan_restr = true;
298 continue;
299 } else {
300 // we don't want the properties 'minlos' and 'minhadv' in the response.
301 unset($rate['minlos']);
302 unset($rate['minhadv']);
303 }
304 if (!isset($arr_rates[$rate['idroom']])) {
305 $arr_rates[$rate['idroom']] = array();
306 }
307 $arr_rates[$rate['idroom']][] = $rate;
308 }
309
310 // flags to understand exactly what's making some rooms unavailable
311 $err_rtype_restr = false;
312 $err_rtype_booked = false;
313
314 // check availability for the rooms with a rate for this number of nights
315 $minus_units = 0;
316 if (count($arr_rates) < $args['num_rooms']) {
317 $minus_units = $args['num_rooms'] - count($arr_rates);
318 }
319 foreach ($arr_rates as $k => $datarate) {
320 $room = $room_ids[$k];
321 $consider_units = $room['units'] - $minus_units;
322 if (!VikBooking::roomBookable($room['id'], $consider_units, $args['start_ts'], $args['end_ts']) || $consider_units <= 0) {
323 // unset room from results
324 unset($arr_rates[$k]);
325 // push room as fully booked
326 array_push($fullybooked, (int)$room['id']);
327 // turn flag on
328 $err_rtype_booked = true;
329 } else {
330 if (!self::$ignoreRestrictions && count($all_restrictions)) {
331 $room_restr = VikBooking::roomRestrictions($room['id'], $all_restrictions);
332 if (count($room_restr)) {
333 if (strlen(VikBooking::validateRoomRestriction($room_restr, getdate($args['start_ts']), getdate($args['end_ts']), $args['nights'])) > 0) {
334 // unset room from results
335 unset($arr_rates[$k]);
336 // turn flag on
337 $err_rtype_restr = true;
338 }
339 }
340 }
341 }
342 }
343
344 if (!count($arr_rates)) {
345 // set error code
346 self::$errorCode = $err_rtype_booked ? 7 : 8;
347
348 // build error response
349 $err_mess = JText::translate('VBNOROOMSINDATE');
350 $err_mess = $err_mess == 'VBNOROOMSINDATE' ? JText::translate('VBO_AV_ECODE_7') : $err_mess;
351 $res = array('e4j.error' => 'No availability for these dates');
352 if ($only_rates && count($fullybooked)) {
353 $res['fullybooked'] = $fullybooked;
354 }
355
356 if (self::$getArray) {
357 return $res;
358 }
359
360 // concatenate rate plan restriction errors, if any
361 if ($err_rplan_restr === true) {
362 $res['e4j.error'] .= ' (Rate Plan Restrictions)';
363 }
364
365 echo json_encode($res);
366 exit;
367 }
368
369 // apply special prices
370 $arr_rates = VikBooking::applySeasonalPrices($arr_rates, $args['start_ts'], $args['end_ts']);
371 $multi_rates = 1;
372 foreach ($arr_rates as $idr => $tars) {
373 $multi_rates = count($tars) > $multi_rates ? count($tars) : $multi_rates;
374 }
375 if ($multi_rates > 1) {
376 for ($r = 1; $r < $multi_rates; $r++) {
377 $deeper_rates = array();
378 foreach ($arr_rates as $idr => $tars) {
379 foreach ($tars as $tk => $tar) {
380 if ($tk == $r) {
381 $deeper_rates[$idr][0] = $tar;
382 break;
383 }
384 }
385 }
386 if (!count($deeper_rates) > 0) {
387 continue;
388 }
389 $deeper_rates = VikBooking::applySeasonalPrices($deeper_rates, $args['start_ts'], $args['end_ts']);
390 foreach ($deeper_rates as $idr => $dtars) {
391 foreach ($dtars as $dtk => $dtar) {
392 $arr_rates[$idr][$r] = $dtar;
393 }
394 }
395 }
396 }
397
398 // children ages charge
399 $children_sums = array();
400
401 // sum charges/discounts per occupancy for each room party
402 foreach ($arrpeople as $roomnumb => $party) {
403 // charges/discounts per adults occupancy
404 foreach ($arr_rates as $r => $rates) {
405 $children_charges = VikBooking::getChildrenCharges($r, $party['children'], $party['children_age'], $args['nights']);
406 if (count($children_charges) > 0) {
407 $children_sums[$r] += $children_charges['total'];
408 }
409 $diffusageprice = VikBooking::loadAdultsDiff($r, $party['adults']);
410 // Occupancy Override - Special Price may be setting a charge/discount for this occupancy while default price had no occupancy pricing
411 if (!is_array($diffusageprice)) {
412 foreach ($rates as $kpr => $vpr) {
413 if (array_key_exists('occupancy_ovr', $vpr) && array_key_exists($party['adults'], $vpr['occupancy_ovr']) && strlen($vpr['occupancy_ovr'][$party['adults']]['value'])) {
414 $diffusageprice = $vpr['occupancy_ovr'][$party['adults']];
415 break;
416 }
417 }
418 reset($rates);
419 }
420 if (is_array($diffusageprice)) {
421 foreach ($rates as $kpr => $vpr) {
422 if ($roomnumb == 1) {
423 $arr_rates[$r][$kpr]['costbeforeoccupancy'] = $arr_rates[$r][$kpr]['cost'];
424 }
425 // Occupancy Override
426 if (array_key_exists('occupancy_ovr', $vpr) && array_key_exists($party['adults'], $vpr['occupancy_ovr']) && strlen($vpr['occupancy_ovr'][$party['adults']]['value'])) {
427 $diffusageprice = $vpr['occupancy_ovr'][$party['adults']];
428 }
429 $arr_rates[$r][$kpr]['diffusage'] = $party['adults'];
430 if ($diffusageprice['chdisc'] == 1) {
431 // charge
432 if ($diffusageprice['valpcent'] == 1) {
433 // fixed value
434 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arr_rates[$r][$kpr]['days'] : $diffusageprice['value'];
435 $arr_rates[$r][$kpr]['diffusagecost'][$roomnumb] = $aduseval;
436 $arr_rates[$r][$kpr]['cost'] += $aduseval;
437 } else {
438 // percentage value
439 $aduseval = $diffusageprice['pernight'] == 1 ? round(($arr_rates[$r][$kpr]['costbeforeoccupancy'] * $diffusageprice['value'] / 100) * $arr_rates[$r][$kpr]['days'], 2) : round(($arr_rates[$r][$kpr]['costbeforeoccupancy'] * $diffusageprice['value'] / 100), 2);
440 $arr_rates[$r][$kpr]['diffusagecost'][$roomnumb] = $aduseval;
441 $arr_rates[$r][$kpr]['cost'] += $aduseval;
442 }
443 } else {
444 // discount
445 if ($diffusageprice['valpcent'] == 1) {
446 // fixed value
447 $aduseval = $diffusageprice['pernight'] == 1 ? $diffusageprice['value'] * $arr_rates[$r][$kpr]['days'] : $diffusageprice['value'];
448 $arr_rates[$r][$kpr]['diffusagediscount'][$roomnumb] = $aduseval;
449 $arr_rates[$r][$kpr]['cost'] -= $aduseval;
450 } else {
451 // percentage value
452 $aduseval = $diffusageprice['pernight'] == 1 ? round(((($arr_rates[$r][$kpr]['costbeforeoccupancy'] / $arr_rates[$r][$kpr]['days']) * $diffusageprice['value'] / 100) * $arr_rates[$r][$kpr]['days']), 2) : round(($arr_rates[$r][$kpr]['costbeforeoccupancy'] * $diffusageprice['value'] / 100), 2);
453 $arr_rates[$r][$kpr]['diffusagediscount'][$roomnumb] = $aduseval;
454 $arr_rates[$r][$kpr]['cost'] -= $aduseval;
455 }
456 }
457 }
458 } elseif ($roomnumb == 1) {
459 foreach ($rates as $kpr => $vpr) {
460 $arr_rates[$r][$kpr]['costbeforeoccupancy'] = $arr_rates[$r][$kpr]['cost'];
461 }
462 }
463 }
464 }
465
466 // if the rooms are given to a party of multiple rooms, multiply the basic rates per room per number of rooms
467 for($i = 2; $i <= $args['num_rooms']; $i++) {
468 foreach ($arr_rates as $r => $rates) {
469 foreach ($rates as $kpr => $vpr) {
470 $arr_rates[$r][$kpr]['cost'] += $arr_rates[$r][$kpr]['costbeforeoccupancy'];
471 }
472 }
473 }
474
475 // children ages charge
476 if (count($children_sums) > 0) {
477 foreach ($arr_rates as $r => $rates) {
478 if (array_key_exists($r, $children_sums)) {
479 foreach ($rates as $kpr => $vpr) {
480 $arr_rates[$r][$kpr]['cost'] += $children_sums[$r];
481 }
482 }
483 }
484 }
485
486 //sort results by price ASC
487 $arr_rates = VikBooking::sortResults($arr_rates);
488
489 // compose taxes information
490 $ivainclusa = VikBooking::ivaInclusa();
491 $rates_ids = array();
492 foreach ($arr_rates as $r => $rate) {
493 foreach ($rate as $ids) {
494 if (!in_array($ids['idprice'], $rates_ids)) {
495 $rates_ids[] = $ids['idprice'];
496 }
497 }
498 }
499 $tax_rates = array();
500 $q = "SELECT `p`.`id`,`t`.`aliq`,`t`.`taxcap` FROM `#__vikbooking_prices` AS `p` LEFT JOIN `#__vikbooking_iva` `t` ON `p`.`idiva`=`t`.`id` WHERE `p`.`id` IN (".implode(',', $rates_ids).");";
501 $dbo->setQuery($q);
502 $alltaxrates = $dbo->loadAssocList();
503 if ($alltaxrates) {
504 foreach ($alltaxrates as $tx) {
505 if (!empty($tx['aliq']) && $tx['aliq'] > 0) {
506 /**
507 * Tax Cap implementation.
508 *
509 * @since 1.12
510 */
511 $tax_rates[$tx['id']] = array($tx['aliq'], (float)$tx['taxcap']);
512 }
513 }
514 }
515 if (count($tax_rates) > 0) {
516 foreach ($arr_rates as $r => $rates) {
517 foreach ($rates as $k => $rate) {
518 if (array_key_exists($rate['idprice'], $tax_rates)) {
519 if (intval($ivainclusa) == 1) {
520 // prices tax included
521 $realcost = $rate['cost'];
522 $tax_oper = ($tax_rates[$rate['idprice']][0] + 100) / 100;
523 $taxes = $rate['cost'] - ($rate['cost'] / $tax_oper);
524 /**
525 * Tax Cap implementation.
526 *
527 * @since 1.12
528 */
529 if ($tax_rates[$rate['idprice']][1] > 0 && $taxes > $tax_rates[$rate['idprice']][1]) {
530 $taxes = $tax_rates[$rate['idprice']][1];
531 }
532 } else {
533 // prices tax excluded
534 $realcost = $rate['cost'] * (100 + $tax_rates[$rate['idprice']][0]) / 100;
535 $taxes = $realcost - $rate['cost'];
536 /**
537 * Tax Cap implementation.
538 *
539 * @since 1.12
540 */
541 if ($tax_rates[$rate['idprice']][1] > 0 && $taxes > $tax_rates[$rate['idprice']][1]) {
542 $realcost = $rate['cost'] + $tax_rates[$rate['idprice']][1];
543 $taxes = $tax_rates[$rate['idprice']][1];
544 }
545 }
546 if ($req_type == 'hotel_availability' || $req_type == 'booking_availability') {
547 // always set 'cost' to the base rate tax excluded
548 $realcost = $realcost - $taxes;
549 }
550 $arr_rates[$r][$k]['cost'] = round($realcost, 2);
551 $arr_rates[$r][$k]['taxes'] = round($taxes, 2);
552 }
553 }
554 }
555 // sum taxes/fees for each room party
556 foreach ($arrpeople as $roomnumb => $party) {
557 foreach ($arr_rates as $r => $rates) {
558 $city_tax_fees = VikBooking::getMandatoryTaxesFees(array($r), $party['adults'], $args['nights']);
559 foreach ($rates as $k => $rate) {
560 if (!isset($arr_rates[$r][$k]['city_taxes'])) {
561 $arr_rates[$r][$k]['city_taxes'] = 0;
562 }
563 if (!isset($arr_rates[$r][$k]['fees'])) {
564 $arr_rates[$r][$k]['fees'] = 0;
565 }
566 $arr_rates[$r][$k]['city_taxes'] += round($city_tax_fees['city_taxes'], 2);
567 $arr_rates[$r][$k]['fees'] += round($city_tax_fees['fees'], 2);
568 }
569 }
570 }
571 } else {
572 foreach ($arr_rates as $r => $rates) {
573 foreach ($rates as $k => $rate) {
574 $arr_rates[$r][$k]['taxes'] = round(0, 2);
575 $arr_rates[$r][$k]['city_taxes'] = round(0, 2);
576 $arr_rates[$r][$k]['fees'] = round(0, 2);
577 }
578 }
579 }
580
581 if (self::$getArray) {
582 return $arr_rates;
583 }
584
585 if ($only_rates && count($fullybooked)) {
586 $arr_rates['fullybooked'] = $fullybooked;
587 }
588
589 echo json_encode($arr_rates);
590 exit;
591 }
592
593 /**
594 * Returns the error code to understand what produced an error.
595 *
596 * @return int the error code identifier.
597 *
598 * @since 1.15.0 (J) - 1.5.0 (WP)
599 */
600 public static function getErrorCode()
601 {
602 return self::$errorCode;
603 }
604 }
605