PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
← All changes | app/Controllers/BookingSessionController.php +56 -23 3.0.13trunk View file →
@@ -351,11 +351,19 @@
351 351 $total_paid = $paymentRepository->getTotalPaidForBooking($booking_id);
352 352 $total_amount = (float) $booking->total_amount;
353 353
354 354 if ($total_paid >= $total_amount) {
355 + // Fully paid. Respect the Auto-Confirm mode (same as every
356 + // other payment-completion path) — only confirm when the
357 + // mode is 'online' or 'all'; otherwise record the payment
358 + // and leave the booking pending for manual confirmation.
355 359 $prevStatus = (string) ($booking->status ?? 'pending');
356 - $bookingRepository->update($booking_id, ['status' => 'confirmed', 'payment_status' => 'paid']);
357 - \yatra_trigger_booking_confirmed((int) $booking_id, $prevStatus);
360 + if (\yatra_should_confirm_booking_on_payment(true, (int) $booking_id)) {
361 + $bookingRepository->update($booking_id, ['status' => 'confirmed', 'payment_status' => 'paid']);
362 + \yatra_trigger_booking_confirmed((int) $booking_id, $prevStatus, true);
363 + } else {
364 + $bookingRepository->update($booking_id, ['payment_status' => 'paid']);
365 + }
358 366 } else {
359 367 $bookingRepository->update($booking_id, ['payment_status' => 'partial']);
360 368 }
361 369 }
@@ -888,8 +896,11 @@
888 896 'slug' => $trip->slug,
889 897 'featured_image' => $trip->featured_image,
890 898 'duration_days' => (int) $trip->duration_days,
891 899 'duration_nights' => (int) $trip->duration_nights,
900 + // Hour-based day tours (0 on every day-based trip). Additive field:
901 + // existing consumers keep reading duration_days/duration_nights.
902 + 'duration_hours' => (int) ($trip->duration_hours ?? 0),
892 903 'difficulty_level' => $trip->difficulty_level,
893 904 'min_travelers' => (int) ($trip->min_travelers ?: 1),
894 905 'max_travelers' => (int) ($trip->max_travelers ?: 20),
895 906 'original_price' => (float) $trip->original_price,
@@ -1279,9 +1290,9 @@
1279 1290 // GET BOOKING SETTINGS
1280 1291 // ========================================
1281 1292 $settings = [
1282 1293 'booking_confirmation' => \Yatra\Services\SettingsService::get('booking_confirmation', true),
1283 - 'auto_confirm_bookings' => \Yatra\Services\SettingsService::get('auto_confirm_bookings', false),
1294 + 'auto_confirm_mode' => \yatra_get_auto_confirm_mode(),
1284 1295 'require_login' => \Yatra\Services\SettingsService::get('require_login', false),
1285 1296 'allow_guest_checkout' => \Yatra\Services\SettingsService::get('allow_guest_checkout', true),
1286 1297 'booking_expiry_hours' => (int) \Yatra\Services\SettingsService::get('booking_expiry_hours', 24),
1287 1298 'auto_confirm_pay_later' => \Yatra\Services\SettingsService::get('auto_confirm_pay_later', true),
@@ -1364,9 +1375,13 @@
1364 1375 // Which booking-form sections are enabled (Pro Dynamic Form module).
1365 1376 // The default config has every section enabled, so on existing/un-customised
1366 1377 // sites $contact_enabled and $traveler_enabled are both true and the logic
1367 1378 // below behaves exactly as before — only disabled sections change anything.
1368 - $form_config = function_exists('yatra_get_booking_form_config') ? yatra_get_booking_form_config() : [];
1379 + // Scoped to the trip being booked — the same config the checkout
1380 + // rendered, so a field hidden for this trip is never treated as required.
1381 + $form_config = function_exists('yatra_get_booking_form_config')
1382 + ? yatra_get_booking_form_config($trip_id > 0 ? (int) $trip_id : null)
1383 + : [];
1369 1384 $contact_enabled = !isset($form_config['contact_form']['enabled']) || (bool) $form_config['contact_form']['enabled'];
1370 1385 $traveler_enabled = !isset($form_config['traveler_form']['enabled']) || (bool) $form_config['traveler_form']['enabled'];
1371 1386
1372 1387 // Get contact email - handle both flat and nested formats
@@ -2429,21 +2444,29 @@
2429 2444
2430 2445 // ========================================
2431 2446 // DETERMINE BOOKING STATUS
2432 2447 // ========================================
2433 - // Priority:
2434 - // 1. auto_confirm_bookings setting (confirms ALL bookings automatically)
2435 - // 2. For pay_later: auto_confirm_pay_later setting
2436 - // 3. For bank_transfer: always pending until verified
2437 -
2448 + // Priority (Auto-Confirm mode: none | online | all):
2449 + // - 'all' → confirm every booking here at checkout.
2450 + // - 'online' → confirm nothing at checkout; only a successful online
2451 + // gateway payment confirms later (offline stays pending).
2452 + // - 'none' → per-method: pay_later uses auto_confirm_pay_later,
2453 + // bank_transfer stays pending, everything else pending.
2454 +
2438 2455 $booking_status = 'pending';
2439 2456 $status_message = __('Booking received!', 'yatra');
2440 -
2441 - // Check if auto-confirm all bookings is enabled
2442 - if ($settings['auto_confirm_bookings']) {
2443 - // Auto-confirm is enabled - confirm immediately regardless of payment
2457 +
2458 + $auto_confirm_mode = $settings['auto_confirm_mode'] ?? 'none';
2459 + if ($auto_confirm_mode === 'all') {
2460 + // Confirm every booking immediately, regardless of payment.
2444 2461 $booking_status = 'confirmed';
2445 2462 $status_message = __('Booking confirmed!', 'yatra');
2463 + } elseif ($auto_confirm_mode === 'online') {
2464 + // Only successful online payments auto-confirm (at payment
2465 + // completion). Leave the booking pending at checkout; offline
2466 + // methods (bank transfer, pay-later) stay pending for the operator.
2467 + $booking_status = 'pending';
2468 + $status_message = __('Booking received!', 'yatra');
2446 2469 } elseif ($payment_gateway === 'pay_later') {
2447 2470 // Pay Later: Check the specific pay_later auto-confirm setting
2448 2471 if ($settings['auto_confirm_pay_later']) {
2449 2472 $booking_status = 'confirmed';
@@ -2863,11 +2886,15 @@
2863 2886 // Default return_url to the configured booking confirmation URL so redirect gateways
2864 2887 // (e.g. PayPal Advanced, Mollie, Paystack) do not fall back to wrong paths; gateways
2865 2888 // may still append their own query args on top of this URL.
2866 2889 $ref = isset($params['reference']) ? trim((string) $params['reference']) : '';
2890 + // Cancel returns must land on the booking-confirmation page (always resolvable);
2891 + // `home_url('/book/?...')` 404s under a custom booking base/page. Use the reference,
2892 + // falling back to the booking id so the confirmation route always has a token.
2893 + $cancelRef = $ref !== '' ? $ref : (string) ($params['booking_id'] ?? '');
2867 2894 $paymentData = array_merge($params, [
2868 2895 'description' => $params['trip_title'] ?? '',
2869 - 'cancel_url' => home_url('/book/?payment=cancelled&ref=' . ($params['reference'] ?? '')),
2896 + 'cancel_url' => add_query_arg('payment', 'cancelled', $this->getConfirmationUrl($cancelRef)),
2870 2897 'metadata' => [
2871 2898 'booking_id' => $params['booking_id'],
2872 2899 'reference' => $params['reference'] ?? ''
2873 2900 ]
@@ -3068,17 +3095,18 @@
3068 3095 // (Square, Authorize.Net) reach this generic path but previously left
3069 3096 // the booking at pending/pending — only the payment row was written.
3070 3097 // This now matches handle_successful_payment(): accumulate amount_paid,
3071 3098 // recompute amount_due, set payment_status (paid vs partial), and
3072 - // confirm the booking (a deposit confirms too, consistent with Stripe).
3099 + // confirm the booking only when "Auto-Confirm Bookings" is on
3100 + // (consistent with every gateway).
3073 3101 $newAmountPaid = (float) ($booking->amount_paid ?? 0) + $amount;
3074 3102 $newAmountDue = max(0.0, (float) ($booking->total_amount ?? 0) - $newAmountPaid);
3075 3103 $paymentStatus = $newAmountDue > 0.0 ? 'partial' : 'paid';
3076 3104 $previousStatus = (string) ($booking->status ?? 'pending');
3077 3105
3078 - // Only auto-confirm when the operator allows it (or fully paid). A
3079 - // deposit / partial payment must not confirm when "Auto-Confirm
3080 - // Bookings" is off.
3106 + // Only auto-confirm when "Auto-Confirm Bookings" is on; otherwise the
3107 + // booking stays pending for the operator to confirm manually,
3108 + // regardless of a successful (full or partial) payment.
3081 3109 $shouldConfirm = \yatra_should_confirm_booking_on_payment($newAmountDue <= 0.0, $bookingId);
3082 3110
3083 3111 $bookingUpdate = [
3084 3112 'amount_paid' => $newAmountPaid,
@@ -3090,9 +3118,9 @@
3090 3118 }
3091 3119 $this->bookingRepository->update($bookingId, $bookingUpdate);
3092 3120
3093 3121 if ($shouldConfirm && function_exists('yatra_trigger_booking_confirmed')) {
3094 - \yatra_trigger_booking_confirmed($bookingId, $previousStatus);
3122 + \yatra_trigger_booking_confirmed($bookingId, $previousStatus, true);
3095 3123 }
3096 3124
3097 3125 // Fire payment completed action
3098 3126 do_action('yatra_payment_completed', [
@@ -3160,9 +3188,9 @@
3160 3188 'description' => $params['trip_title'],
3161 3189 ]],
3162 3190 'application_context' => [
3163 3191 'return_url' => add_query_arg('payment', 'success', $this->getConfirmationUrl($params['reference'])),
3164 - 'cancel_url' => home_url('/book/?payment=cancelled&ref=' . $params['reference']),
3192 + 'cancel_url' => add_query_arg('payment', 'cancelled', $this->getConfirmationUrl($params['reference'])),
3165 3193 ],
3166 3194 ]),
3167 3195 ]);
3168 3196
@@ -3281,9 +3309,12 @@
3281 3309 'su' => add_query_arg(
3282 3310 ['payment' => 'success', 'gateway' => 'esewa'],
3283 3311 $this->getConfirmationUrl($params['reference'])
3284 3312 ),
3285 - 'fu' => home_url('/book/?payment=failed&ref=' . $params['reference']),
3313 + 'fu' => add_query_arg(
3314 + ['payment' => 'failed', 'gateway' => 'esewa'],
3315 + $this->getConfirmationUrl($params['reference'])
3316 + ),
3286 3317 ], $base_url);
3287 3318
3288 3319 return ['success' => true, 'payment_url' => $payment_url];
3289 3320 }
@@ -3435,9 +3466,9 @@
3435 3466 <p style="margin:0 0 8px;"><strong><?php esc_html_e('Booking reference', 'yatra'); ?>:</strong> <?php echo esc_html($reference); ?></p>
3436 3467 <p style="margin:0 0 8px;"><strong><?php esc_html_e('Trip', 'yatra'); ?>:</strong> <?php echo esc_html($trip->title); ?></p>
3437 3468 <p style="margin:0 0 8px;"><strong><?php esc_html_e('Travel date', 'yatra'); ?>:</strong> <?php echo esc_html(date_i18n(get_option('date_format'), strtotime($travel_date))); ?></p>
3438 3469 <p style="margin:0 0 8px;"><strong><?php esc_html_e('Duration', 'yatra'); ?>:</strong> <?php /* translators: 1: number of days, 2: number of nights. */
3439 -echo esc_html(sprintf(__('%1$d days / %2$d nights', 'yatra'), (int) $trip->duration_days, (int) $trip->duration_nights)); ?></p>
3470 +echo esc_html(yatra_format_duration((int) $trip->duration_days, (int) $trip->duration_nights, (int) ($trip->duration_hours ?? 0))); ?></p>
3440 3471 <p style="margin:0;"><strong><?php esc_html_e('Travelers', 'yatra'); ?>:</strong> <?php echo esc_html((string) count($travelers)); ?></p>
3441 3472 </div>
3442 3473 <h3 style="font-size:16px;"><?php esc_html_e('Payment details', 'yatra'); ?></h3>
3443 3474 <p><?php /* translators: %s: total amount (formatted). */
@@ -4511,9 +4542,11 @@
4511 4542 // Pro can already override per-trip via trip.deposit_percentage), then
4512 4543 // hand off to `yatra_calculate_amount_due` so Pro can apply absolute
4513 4544 // overrides too (e.g. trip.deposit_amount as a fixed cap). Doing both
4514 4545 // keeps the math consistent with CalculationService::calculatePaymentAmounts().
4515 - $context = ['trip_id' => $trip_id];
4546 + // Tour start → Pro can force full payment when the tour is within the
4547 + // balance-due window (tour-anchored scheduled payments).
4548 + $context = ['trip_id' => $trip_id, 'travel_date' => (string) ($travel_date ?? '')];
4516 4549 $flexible_payments_enabled = apply_filters('yatra_flexible_payments_enabled', false);
4517 4550 $deposit_percentage = (int) apply_filters('yatra_deposit_percentage', 20, $context);
4518 4551 $partial_percentage = (int) apply_filters('yatra_partial_payment_percentage', 30, $context);
4519 4552