| @@ -32,9 +32,11 @@ | ||
| 32 | 32 | case 'operators': |
| 33 | 33 | case 'tableaux': |
| 34 | 34 | case 'precheckin': |
| 35 | 35 | case 'revstay': |
| 36 | + case 'chat': | |
| 36 | 37 | case 'tinyurl': |
| 38 | + case 'quote': | |
| 37 | 39 | VikRequest::setVar('view', $view); |
| 38 | 40 | break; |
| 39 | 41 | default: |
| 40 | 42 | VikRequest::setVar('view', 'vikbooking'); |
| @@ -301,8 +303,12 @@ | ||
| 301 | 303 | foreach ($cfields as $cf) { |
| 302 | 304 | $user_inp_val = VikRequest::getString('vbf' . $cf['id'], '', 'request'); |
| 303 | 305 | if (intval($cf['isemail']) == 1 && $emailwasfound == false) { |
| 304 | 306 | $useremail = trim($user_inp_val); |
| 307 | + if (!preg_match('/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/', $useremail)) { | |
| 308 | + showSelectVb('Invalid email address provided.'); | |
| 309 | + return; | |
| 310 | + } | |
| 305 | 311 | $emailwasfound = true; |
| 306 | 312 | } |
| 307 | 313 | if ($cf['isnominative'] == 1) { |
| 308 | 314 | if (strlen(str_replace(' ', '', trim($user_inp_val)))) { |
| @@ -1879,9 +1885,12 @@ | ||
| 1879 | 1885 | $vbo_tn = VikBooking::getTranslator(); |
| 1880 | 1886 | |
| 1881 | 1887 | if ($row['status'] == 'confirmed' && !(VikBooking::multiplePayments() && $row['paymcount'] > 0)) { |
| 1882 | 1888 | // booking can be paid only if not confirmed or if multiple payments are enabled and payment counter for booking greater than zero |
| 1883 | - VBOHttpDocument::getInstance()->close(409, 'Conflicting and unexpected payment validation for this reservation'); | |
| 1889 | + if (empty($row['idorderota']) || !empty($row['totpaid'])) { | |
| 1890 | + // accept only the first payment for an OTA reservation | |
| 1891 | + VBOHttpDocument::getInstance()->close(409, 'Conflicting and unexpected payment validation for this reservation'); | |
| 1892 | + } | |
| 1884 | 1893 | } |
| 1885 | 1894 | |
| 1886 | 1895 | /** |
| 1887 | 1896 | * Check split stay reservation data. |
| @@ -2146,13 +2155,13 @@ | ||
| 2146 | 2155 | $row['sid'] = $row['idorderota']; |
| 2147 | 2156 | } |
| 2148 | 2157 | |
| 2149 | 2158 | /** |
| 2150 | - * Trigger event to allow third-party plugins to manipulate the transaction data. | |
| 2151 | - * | |
| 2152 | - * @since 1.18.5 (J) - 1.8.5 (WP) | |
| 2153 | - */ | |
| 2154 | - VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$row, &$payment['params'], []]); | |
| 2159 | + * Trigger event to allow third-party plugins to manipulate the transaction data. | |
| 2160 | + * | |
| 2161 | + * @since 1.18.5 (J) - 1.8.5 (WP) | |
| 2162 | + */ | |
| 2163 | + VBOFactory::getPlatform()->getDispatcher()->trigger('onInitPaymentTransaction', [&$row, &$payment['params'], []]); | |
| 2155 | 2164 | |
| 2156 | 2165 | if (VBOPlatformDetection::isWordPress()) { |
| 2157 | 2166 | /** |
| 2158 | 2167 | * @wponly The payment gateway is now loaded |
| @@ -2268,8 +2277,9 @@ | ||
| 2268 | 2277 | } |
| 2269 | 2278 | |
| 2270 | 2279 | // deposit may be skipped by customer choice |
| 2271 | 2280 | $shouldpay_befdep = $shouldpay; |
| 2281 | + $shouldpay_befdep_no_dd = $shouldpay - ($damage_deposit_payment['damagedep_gross'] ?? 0); | |
| 2272 | 2282 | |
| 2273 | 2283 | if (!VikBooking::payTotal()) { |
| 2274 | 2284 | $percentdeposit = VikBooking::getAccPerCent(); |
| 2275 | 2285 | if ($percentdeposit > 0) { |
| @@ -2274,10 +2284,12 @@ | ||
| 2274 | 2284 | $percentdeposit = VikBooking::getAccPerCent(); |
| 2275 | 2285 | if ($percentdeposit > 0) { |
| 2276 | 2286 | if (VikBooking::getTypeDeposit() == "fixed") { |
| 2277 | 2287 | $shouldpay = $percentdeposit; |
| 2288 | + $shouldpay_befdep_no_dd = $percentdeposit; | |
| 2278 | 2289 | } else { |
| 2279 | 2290 | $shouldpay = $shouldpay * $percentdeposit / 100; |
| 2291 | + $shouldpay_befdep_no_dd = $shouldpay_befdep_no_dd * $percentdeposit / 100;; | |
| 2280 | 2292 | } |
| 2281 | 2293 | } |
| 2282 | 2294 | } |
| 2283 | 2295 | |
| @@ -2288,17 +2300,31 @@ | ||
| 2288 | 2300 | // check if the total amount paid is the same as the order total |
| 2289 | 2301 | if (isset($array_result['tot_paid'])) { |
| 2290 | 2302 | $shouldpay = round($shouldpay, 2); |
| 2291 | 2303 | $shouldpay_befdep = round($shouldpay_befdep, 2); |
| 2304 | + $shouldpay_befdep_no_dd = round($shouldpay_befdep_no_dd, 2); | |
| 2292 | 2305 | $shouldpay_less_damagedep = round(($row['total'] - $row['tot_damage_dep']), 2); |
| 2293 | 2306 | $totreceived = round($array_result['tot_paid'], 2); |
| 2294 | - if ($shouldpay != $totreceived && $shouldpay_befdep != $totreceived && $shouldpay_befdd != $totreceived && $shouldpay_less_damagedep != $totreceived && $shouldpay_dd != $totreceived && $row['paymcount'] == 0) { | |
| 2307 | + if ($shouldpay != $totreceived && $shouldpay_befdep != $totreceived && $shouldpay_befdep_no_dd != $totreceived && $shouldpay_befdd != $totreceived && $shouldpay_less_damagedep != $totreceived && $shouldpay_dd != $totreceived && $row['paymcount'] == 0) { | |
| 2295 | 2308 | // the amount paid is different than the order total |
| 2296 | 2309 | // fares might have changed or the deposit might be different |
| 2297 | 2310 | // Sending just an email to the admin that will check |
| 2298 | 2311 | $vbo_app = VikBooking::getVboApplication(); |
| 2299 | 2312 | $adsendermail = VikBooking::getSenderMail(); |
| 2300 | - $vbo_app->sendMail($adsendermail, $adsendermail, $recipient_mail, $adsendermail, JText::translate('VBTOTPAYMENTINVALID'), JText::sprintf('VBTOTPAYMENTINVALIDTXT', $row['id'], $totreceived." (".$array_result['tot_paid'].")", $shouldpay), false); | |
| 2313 | + $vbo_app->sendMail( | |
| 2314 | + $adsendermail, | |
| 2315 | + $adsendermail, | |
| 2316 | + $recipient_mail, | |
| 2317 | + $adsendermail, | |
| 2318 | + JText::translate('VBTOTPAYMENTINVALID'), | |
| 2319 | + JText::sprintf( | |
| 2320 | + 'VBTOTPAYMENTINVALIDTXT', | |
| 2321 | + $row['id'], | |
| 2322 | + $totreceived . " (" . $array_result['tot_paid'] . ")", | |
| 2323 | + $shouldpay | |
| 2324 | + ), | |
| 2325 | + false | |
| 2326 | + ); | |
| 2301 | 2327 | } |
| 2302 | 2328 | |
| 2303 | 2329 | // amount paid should be stored as exclusive of transaction fees/discounts |
| 2304 | 2330 | if ($payment['charge'] > 0.00) { |
| @@ -2378,9 +2404,15 @@ | ||
| 2378 | 2404 | $booking_record->paymentlog = $newpaymentlog; |
| 2379 | 2405 | } |
| 2380 | 2406 | $booking_record->payable = $new_payable; |
| 2381 | 2407 | |
| 2382 | - $dbo->updateObject('#__vikbooking_orders', $booking_record, 'id'); | |
| 2408 | + // update booking record | |
| 2409 | + if (!$dbo->updateObject('#__vikbooking_orders', $booking_record, 'id')) { | |
| 2410 | + // payments log content may break the update | |
| 2411 | + unset($booking_record->paymentlog); | |
| 2412 | + // try once more | |
| 2413 | + $dbo->updateObject('#__vikbooking_orders', $booking_record, 'id'); | |
| 2414 | + } | |
| 2383 | 2415 | |
| 2384 | 2416 | // assign room specific unit |
| 2385 | 2417 | $set_room_indexes = VikBooking::autoRoomUnit(); |
| 2386 | 2418 | $room_indexes_usemap = []; |
| @@ -2420,8 +2452,13 @@ | ||
| 2420 | 2452 | $q = "DELETE FROM `#__vikbooking_tmplock` WHERE `idorder`=" . intval($row['id']) . ";"; |
| 2421 | 2453 | $dbo->setQuery($q); |
| 2422 | 2454 | $dbo->execute(); |
| 2423 | 2455 | |
| 2456 | + if (!empty($row['idquote'])) { | |
| 2457 | + // let the quote model handle the release of other locked room records (OTAs included), if any | |
| 2458 | + VBOMvcModel::getInstance('quote')->releaseUnconfirmedSolutions((int) $row['idquote'], (int) $row['id']); | |
| 2459 | + } | |
| 2460 | + | |
| 2424 | 2461 | // customer booking |
| 2425 | 2462 | $q = "SELECT `idcustomer` FROM `#__vikbooking_customers_orders` WHERE `idorder`=".(int)$row['id'].";"; |
| 2426 | 2463 | $dbo->setQuery($q); |
| 2427 | 2464 | $customer_id = $dbo->loadResult(); |
| @@ -2848,13 +2885,13 @@ | ||
| 2848 | 2885 | // push the transaction currency information |
| 2849 | 2886 | $order[0]['transaction_currency'] = VikBooking::getCurrencyCodePp(); |
| 2850 | 2887 | |
| 2851 | 2888 | /** |
| 2852 | - * Trigger event to allow third-party plugins to manipulate the transaction data. | |
| 2853 | - * | |
| 2854 | - * @since 1.18.5 (J) - 1.8.5 (WP) | |
| 2855 | - */ | |
| 2856 | - VBOFactory::getPlatform()->getDispatcher()->trigger('onInitRefundTransaction', [&$order[0], &$payment['params']]); | |
| 2889 | + * Trigger event to allow third-party plugins to manipulate the transaction data. | |
| 2890 | + * | |
| 2891 | + * @since 1.18.5 (J) - 1.8.5 (WP) | |
| 2892 | + */ | |
| 2893 | + VBOFactory::getPlatform()->getDispatcher()->trigger('onInitRefundTransaction', [&$order[0], &$payment['params']]); | |
| 2857 | 2894 | |
| 2858 | 2895 | /** |
| 2859 | 2896 | * @wponly The payment gateway is loaded |
| 2860 | 2897 | * through the apposite dispatcher. |
| @@ -3234,13 +3271,18 @@ | ||
| 3234 | 3271 | |
| 3235 | 3272 | foreach ($pguests as $ind => $adults) { |
| 3236 | 3273 | foreach ($adults as $aduind => $details) { |
| 3237 | 3274 | foreach ($details as $detkey => $detval) { |
| 3275 | + // accept no raw HTML tags as keys | |
| 3276 | + $detkey = htmlspecialchars(strip_tags($detkey)); | |
| 3277 | + if (!$detkey) { | |
| 3278 | + continue; | |
| 3279 | + } | |
| 3238 | 3280 | if (!in_array($detkey, $front_keys)) { |
| 3239 | 3281 | // push the key of the guest details for later comparison |
| 3240 | 3282 | array_push($front_keys, $detkey); |
| 3241 | 3283 | } |
| 3242 | - if (strlen($detval)) { | |
| 3284 | + if (is_scalar($detval) && strlen($detval)) { | |
| 3243 | 3285 | // push value only if not empty |
| 3244 | 3286 | if (!isset($guests_details[$ind])) { |
| 3245 | 3287 | $guests_details[$ind] = array(); |
| 3246 | 3288 | } |
| @@ -3269,8 +3311,13 @@ | ||
| 3269 | 3311 | // current pax data include a guest not present, set it to not lose it |
| 3270 | 3312 | $guests_details[$ind][$aduind] = $details; |
| 3271 | 3313 | } |
| 3272 | 3314 | foreach ($details as $detkey => $detval) { |
| 3315 | + // accept no raw HTML tags as keys | |
| 3316 | + $detkey = htmlspecialchars(strip_tags($detkey)); | |
| 3317 | + if (!$detkey) { | |
| 3318 | + continue; | |
| 3319 | + } | |
| 3273 | 3320 | if (!in_array($detkey, $front_keys)) { |
| 3274 | 3321 | // merge this key probably reserved to the back-end |
| 3275 | 3322 | $guests_details[$ind][$aduind][$detkey] = $detval; |
| 3276 | 3323 | } |
| @@ -4545,11 +4592,11 @@ | ||
| 4545 | 4592 | $checkout_h = $input->getInt('checkouth', 0); |
| 4546 | 4593 | $checkout_m = $input->getInt('checkoutm', 0); |
| 4547 | 4594 | $categories = $input->getString('categories', ''); |
| 4548 | 4595 | $roomsnum = $input->getInt('roomsnum', 1); |
| 4549 | - $adults = $input->get('adults', array(), 'int'); | |
| 4550 | - $children = $input->get('children', array(), 'int'); | |
| 4551 | - $inquiry = $input->get('inquiry', array(), 'raw'); | |
| 4596 | + $adults = $input->get('adults', [], 'int'); | |
| 4597 | + $children = $input->get('children', [], 'int'); | |
| 4598 | + $inquiry = $input->get('inquiry', [], 'array'); | |
| 4552 | 4599 | $ulang = $input->getString('ulang', ''); |
| 4553 | 4600 | |
| 4554 | 4601 | $timeopst = VikBooking::getTimeOpenStore(); |
| 4555 | 4602 | if (empty($checkin_h) && empty($checkout_h) && is_array($timeopst)) { |
| @@ -4594,8 +4641,10 @@ | ||
| 4594 | 4641 | if (!is_scalar($info_val) || !strlen($info_val)) { |
| 4595 | 4642 | // empty or invalid field |
| 4596 | 4643 | continue; |
| 4597 | 4644 | } |
| 4645 | + // accept only text from submitted value | |
| 4646 | + $info_val = strip_tags($info_val); | |
| 4598 | 4647 | if ($info_type == 'nominative') { |
| 4599 | 4648 | if (empty($t_first_name)) { |
| 4600 | 4649 | $t_first_name = $info_val; |
| 4601 | 4650 | $res_custdata[JText::translate('VBNAME')] = $info_val; |