| @@ -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'; |
| @@ -3072,17 +3095,18 @@ | ||
| 3072 | 3095 | // (Square, Authorize.Net) reach this generic path but previously left |
| 3073 | 3096 | // the booking at pending/pending — only the payment row was written. |
| 3074 | 3097 | // This now matches handle_successful_payment(): accumulate amount_paid, |
| 3075 | 3098 | // recompute amount_due, set payment_status (paid vs partial), and |
| 3076 | - // 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). | |
| 3077 | 3101 | $newAmountPaid = (float) ($booking->amount_paid ?? 0) + $amount; |
| 3078 | 3102 | $newAmountDue = max(0.0, (float) ($booking->total_amount ?? 0) - $newAmountPaid); |
| 3079 | 3103 | $paymentStatus = $newAmountDue > 0.0 ? 'partial' : 'paid'; |
| 3080 | 3104 | $previousStatus = (string) ($booking->status ?? 'pending'); |
| 3081 | 3105 | |
| 3082 | - // Only auto-confirm when the operator allows it (or fully paid). A | |
| 3083 | - // deposit / partial payment must not confirm when "Auto-Confirm | |
| 3084 | - // 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. | |
| 3085 | 3109 | $shouldConfirm = \yatra_should_confirm_booking_on_payment($newAmountDue <= 0.0, $bookingId); |
| 3086 | 3110 | |
| 3087 | 3111 | $bookingUpdate = [ |
| 3088 | 3112 | 'amount_paid' => $newAmountPaid, |
| @@ -3094,9 +3118,9 @@ | ||
| 3094 | 3118 | } |
| 3095 | 3119 | $this->bookingRepository->update($bookingId, $bookingUpdate); |
| 3096 | 3120 | |
| 3097 | 3121 | if ($shouldConfirm && function_exists('yatra_trigger_booking_confirmed')) { |
| 3098 | - \yatra_trigger_booking_confirmed($bookingId, $previousStatus); | |
| 3122 | + \yatra_trigger_booking_confirmed($bookingId, $previousStatus, true); | |
| 3099 | 3123 | } |
| 3100 | 3124 | |
| 3101 | 3125 | // Fire payment completed action |
| 3102 | 3126 | do_action('yatra_payment_completed', [ |
| @@ -3442,9 +3466,9 @@ | ||
| 3442 | 3466 | <p style="margin:0 0 8px;"><strong><?php esc_html_e('Booking reference', 'yatra'); ?>:</strong> <?php echo esc_html($reference); ?></p> |
| 3443 | 3467 | <p style="margin:0 0 8px;"><strong><?php esc_html_e('Trip', 'yatra'); ?>:</strong> <?php echo esc_html($trip->title); ?></p> |
| 3444 | 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> |
| 3445 | 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. */ |
| 3446 | -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> | |
| 3447 | 3471 | <p style="margin:0;"><strong><?php esc_html_e('Travelers', 'yatra'); ?>:</strong> <?php echo esc_html((string) count($travelers)); ?></p> |
| 3448 | 3472 | </div> |
| 3449 | 3473 | <h3 style="font-size:16px;"><?php esc_html_e('Payment details', 'yatra'); ?></h3> |
| 3450 | 3474 | <p><?php /* translators: %s: total amount (formatted). */ |