PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.7
Yatra – Travel Booking & Tour Operator Software v3.0.2.7
3.0.16 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 All 84 releases
yatra / app / Core / Handlers / BookingPageHandler.php

BookingPageHandler.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.7, at app/Core/Handlers/BookingPageHandler.php

278 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Core\Handlers;
6
7 use Yatra\Services\SettingsService;
8
9 /**
10 * Booking Page Handler
11 *
12 * Handles booking page requests
13 */
14 class BookingPageHandler extends BasePageHandler
15 {
16 /**
17 * Handle booking page request
18 *
19 * @param array $route_data Route data from RouteMatcher
20 * @return bool True if handled successfully
21 */
22 public function handle(array $route_data): bool
23 {
24 // Check if custom booking page is enabled
25 if (SettingsService::useCustomBookingPage()) {
26 return false;
27 }
28
29 $page = $route_data['page'] ?? 'main';
30 $base = $route_data['base'];
31
32 if (!empty($route_data['trip']) && is_string($route_data['trip'])) {
33 $_GET['trip'] = sanitize_title($route_data['trip']);
34 }
35
36 // Prevent 404 handling
37 $this->prevent404();
38
39 // Set up query vars for backward compatibility
40 $this->setQueryVars([
41 'yatra_page' => $base,
42 ]);
43
44 // Hydrate global $booking from session so templates don't crash
45 $booking = null;
46 if (function_exists('yatra_get_booking_session')) {
47 $session = yatra_get_booking_session();
48
49 // If no session exists, initialize with defaults for display purposes
50 // This allows logged-out users to see pricing without "Contact for pricing" error
51 if (empty($session) || empty($session['trip_id'])) {
52 // Try to get trip_id from URL parameters (for direct booking page access)
53 $trip_id = isset($_GET['trip_id']) ? (int) $_GET['trip_id'] : null;
54
55 if ($trip_id) {
56 // Initialize minimal session for pricing display
57 $session = [
58 'trip_id' => $trip_id,
59 'travelers' => 1, // Default to 1 traveler
60 'travel_date' => '',
61 'timestamp' => time(),
62 ];
63 } elseif (function_exists('yatra_has_remaining_session') && yatra_has_remaining_session()) {
64 // "Pay remaining balance" from My Account clears booking session and only sets
65 // yatra remaining session — hydrate a virtual booking session so checkout can render.
66 $rem = yatra_get_remaining_session();
67 if (!empty($rem['trip_id'])) {
68 if (function_exists('yatra_start_session')) {
69 yatra_start_session();
70 }
71 $session = [
72 'trip_id' => (int) $rem['trip_id'],
73 'travelers' => max(1, (int) ($rem['travelers'] ?? 1)),
74 'travel_date' => is_string($rem['travel_date'] ?? null) ? $rem['travel_date'] : '',
75 'timestamp' => time(),
76 'remaining_amount' => isset($rem['remaining_amount']) ? (float) $rem['remaining_amount'] : null,
77 'amount_paid' => isset($rem['amount_paid']) ? (float) $rem['amount_paid'] : null,
78 'total_amount' => isset($rem['total_amount']) ? (float) $rem['total_amount'] : null,
79 'booking_reference' => $rem['booking_reference'] ?? '',
80 'booking_id' => (int) ($rem['booking_id'] ?? 0),
81 'is_remaining_payment' => true,
82 ];
83 }
84 }
85 }
86
87 if (!empty($session) && !empty($session['trip_id'])) {
88 // Load trip for display context
89 try {
90 $tripRepo = new \Yatra\Repositories\TripRepository();
91 $trip = $tripRepo->findPublished((int) $session['trip_id']);
92 } catch (\Throwable $e) {
93 $trip = null;
94 }
95
96 // Ensure trip has a price property for templates (centralized pricing)
97 if ($trip && !isset($trip->price)) {
98 $trip->price = \Yatra\Services\TripPricingService::resolveRegularCurrentPrice($trip);
99 }
100
101 // Ensure trip has a usable featured_image URL (not attachment ID)
102 if ($trip) {
103 // If featured_image is not set, try to get it from WordPress
104 if (empty($trip->featured_image) && !empty($trip->id)) {
105 $attachment_id = get_post_thumbnail_id($trip->id);
106 if ($attachment_id) {
107 $trip->featured_image = $attachment_id;
108 }
109 }
110
111 // Convert attachment ID to URL if needed
112 if (!empty($trip->featured_image) && is_numeric($trip->featured_image)) {
113 $imgUrl = wp_get_attachment_url((int) $trip->featured_image);
114 if ($imgUrl) {
115 $trip->featured_image = $imgUrl;
116 } else {
117 // If attachment URL fails, use placeholder
118 $trip->featured_image = plugins_url('assets/images/trip-placeholder.svg', YATRA_PLUGIN_FILE);
119 }
120 } elseif (empty($trip->featured_image)) {
121 // No featured image at all, use placeholder
122 $trip->featured_image = plugins_url('assets/images/trip-placeholder.svg', YATRA_PLUGIN_FILE);
123 }
124 }
125
126 // Load trip attributes for booking page display
127 if ($trip && !empty($trip->id)) {
128 try {
129 $singleTripController = new \Yatra\Controllers\SingleTripController();
130 // Use reflection to access private method
131 $reflection = new \ReflectionClass($singleTripController);
132 $method = $reflection->getMethod('getTripAttributes');
133 $method->setAccessible(true);
134 $trip->attributes = $method->invoke($singleTripController, (int) $trip->id);
135 } catch (\Throwable $e) {
136 $trip->attributes = [];
137 }
138 }
139
140 // Checkout must always reflect current Settings + registry — never filter by session.
141 // Session snapshots enabled_gateways at "add to booking" time; admin/site changes and older
142 // sessions would otherwise hide newly enabled gateways (e.g. only Pay Later forever).
143 $gatewayRegistry = \Yatra\PaymentGateways\PaymentGatewayRegistry::getInstance();
144 $enabled_gateways = [];
145 foreach ($gatewayRegistry->getForCheckout() as $gateway) {
146 if (!empty($gateway['id'])) {
147 $enabled_gateways[$gateway['id']] = $gateway;
148 }
149 }
150
151 if (function_exists('yatra_start_session')) {
152 yatra_start_session();
153 if (isset($_SESSION['yatra_booking']) && is_array($_SESSION['yatra_booking'])) {
154 $_SESSION['yatra_booking']['enabled_gateways'] = $enabled_gateways;
155 $token = $_SESSION['yatra_booking_token'] ?? '';
156 if (is_string($token) && $token !== '') {
157 $transient_payload = array_merge($_SESSION['yatra_booking'], [
158 'enabled_gateways' => $enabled_gateways,
159 ]);
160 set_transient($token, $transient_payload, 1800);
161 }
162 }
163 }
164 // Calculate pricing using CalculationService (single source of truth)
165 $calculationService = new \Yatra\Services\CalculationService();
166 $pricing_calculation = [];
167
168 // Get coupon code from session if available
169 $coupon_code = isset($session['coupon']['code']) ? $session['coupon']['code'] : '';
170
171 try {
172 $pricing_calculation = $calculationService->calculateFromSession($session, $coupon_code);
173 } catch (\Throwable $e) {
174 // If calculation fails, set empty pricing
175 $pricing_calculation = [
176 'base_amount' => 0,
177 'gross_total' => 0,
178 'final_total' => 0,
179 'amount_due' => 0,
180 'tax_calculation' => [
181 'tax_breakdown' => [],
182 'total_tax_amount' => 0,
183 'tax_inclusive' => false,
184 ],
185 ];
186 }
187
188 // Get itinerary costs (premium feature)
189 $trip_id = (int) $session['trip_id'];
190 $total_travelers = (int) ($session['travelers'] ?? 1);
191 $traveler_counts = $session['traveler_counts'] ?? [];
192 $travel_date = $session['travel_date'] ?? '';
193
194 $itinerary_costs = apply_filters('yatra_booking_itinerary_costs', [], $trip_id, $total_travelers, $traveler_counts, $travel_date);
195 $itinerary_costs_total = 0.0;
196
197 foreach ($itinerary_costs as $cost) {
198 $basePrice = (float) ($cost['price'] ?? 0);
199 $pricePer = $cost['price_per'] ?? 'person';
200
201 switch ($pricePer) {
202 case 'person':
203 $calculatedPrice = $basePrice * $total_travelers;
204 break;
205 case 'group':
206 $calculatedPrice = $basePrice;
207 break;
208 case 'day':
209 $duration_days = (int) ($trip->duration_days ?? 1);
210 $calculatedPrice = $basePrice * $duration_days;
211 break;
212 default:
213 $calculatedPrice = $basePrice;
214 break;
215 }
216
217 $itinerary_costs_total += $calculatedPrice;
218 }
219
220 // Add itinerary costs to pricing calculation
221 $pricing_calculation['itinerary_costs'] = $itinerary_costs;
222 $pricing_calculation['itinerary_costs_total'] = $itinerary_costs_total;
223
224 // Note: CalculationService already includes itinerary costs in final_total and amount_due
225 // No need to add them again here
226
227 // Create Checkout model instance
228 $checkout = new \Yatra\Models\Checkout($trip, $session, $pricing_calculation);
229
230 // Build booking view model expected by templates
231 $booking = (object) [
232 'trip' => $trip,
233 'travel_date' => $session['travel_date'] ?? '',
234 'travelers' => $session['travelers'] ?? 0,
235 'pricing_type' => $session['pricing_type'] ?? 'regular',
236 'price_types' => $session['price_types'] ?? [],
237 'traveler_counts' => $session['traveler_counts'] ?? [],
238 'partial_payment' => $session['partial_payment'] ?? null,
239 'partial_payment_percentage' => $session['partial_payment_percentage'] ?? null,
240 'deposit_required' => $session['deposit_required'] ?? null,
241 'deposit_percentage' => $session['deposit_percentage'] ?? null,
242 'enabled_gateways' => $enabled_gateways,
243 'group_discount' => $session['group_discount'] ?? null,
244 // Pre-calculated pricing data
245 'pricing_calculation' => $pricing_calculation,
246 'tax_calculation' => $pricing_calculation['tax_calculation'] ?? [],
247 // amounts for templates
248 'total_amount' => $session['total_amount'] ?? null,
249 'amount_paid' => $session['amount_paid'] ?? null,
250 'remaining_amount' => $session['remaining_amount'] ?? null,
251 'booking_reference' => $session['booking_reference'] ?? null,
252 'is_remaining_payment' => !empty($session['is_remaining_payment']),
253 'existing_booking_id' => (int) ($session['booking_id'] ?? 0),
254 // Checkout model for clean template access
255 'checkout' => $checkout,
256 ];
257 }
258 }
259
260 if ($booking !== null) {
261 $this->setGlobal('booking', $booking);
262 }
263
264 // Load the booking page template
265 $template_path = YATRA_PLUGIN_PATH . 'templates/booking.php';
266
267 if (!file_exists($template_path)) {
268 $this->logError("Booking template not found: {$template_path}");
269 return false;
270 }
271
272 include $template_path;
273 $this->exit();
274
275 return true;
276 }
277 }
278