PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.2
VikBooking Hotel Booking Engine & PMS v1.7.2
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.7.2, at site/helpers/tac.vikbooking.php

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