PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
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
yatra / templates / partials / pricing-summary.php

pricing-summary.php in Yatra – Travel Booking & Tour Operator Software 3.0.15, at templates/partials/pricing-summary.php

334 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Pricing Summary Template
4 *
5 * Displays the pricing breakdown in the booking summary.
6 * This template is loaded via AJAX when pricing needs to be updated.
7 *
8 * @package Yatra
9 * @since 3.0.0
10 *
11 * Variables available:
12 * @var \Yatra\Models\Checkout $checkout Checkout model with all pricing data
13 */
14
15 defined('ABSPATH') || exit;
16
17 // Fallback: if $checkout is not available, try to get it from $booking
18 if (!isset($checkout) && isset($booking) && isset($booking->checkout)) {
19 $checkout = $booking->checkout;
20 }
21
22 // If still no checkout model, we can't display anything
23 if (!isset($checkout) || !($checkout instanceof \Yatra\Models\Checkout)) {
24 echo '<p>' . esc_html__('Pricing information not available.', 'yatra') . '</p>';
25 return;
26 }
27 ?>
28
29 <?php if ($checkout->isTravelerBased() && !empty($checkout->getCategoryBreakdown())) : ?>
30 <!-- Traveler-based pricing breakdown -->
31 <div class="yatra-price-breakdown-categories" id="price-breakdown-categories">
32 <?php foreach ($checkout->getCategoryBreakdown() as $cat) : ?>
33 <?php
34 // Get pricing mode from category data
35 $pricing_mode = $cat['pricing_mode'] ?? 'per_person';
36 $is_per_group = ($pricing_mode === 'per_group');
37
38 // Calculate per-unit price for display
39 $per_unit_price = $cat['count'] > 0 ? $cat['subtotal'] / $cat['count'] : 0;
40 $per_unit_formatted = $checkout->formatPrice($per_unit_price);
41 ?>
42 <div class="yatra-price-row yatra-category-subtotal" data-category-id="<?php echo esc_attr($cat['category_id']); ?>">
43 <span>
44 <?php echo esc_html($cat['label']); ?> x <span class="category-count"><?php echo (int) $cat['count']; ?></span>
45 <?php if ($cat['count'] > 0) : ?>
46 <span class="yatra-price-calculation" style="color: #6b7280; font-size: 0.9em; font-weight: normal;">
47 <?php if ($is_per_group) : ?>
48 (<?php echo esc_html($checkout->formatPrice($cat['subtotal'])); ?> <?php esc_html_e('per group', 'yatra'); ?>)
49 <?php else : ?>
50 (<?php echo esc_html($per_unit_formatted); ?> x <?php echo (int) $cat['count']; ?>)
51 <?php endif; ?>
52 </span>
53 <?php endif; ?>
54 </span>
55 <span class="category-subtotal"><?php echo esc_html($checkout->formatPrice($cat['subtotal'])); ?></span>
56 </div>
57 <?php endforeach; ?>
58 </div>
59 <?php else : ?>
60 <!-- Regular pricing -->
61 <div class="yatra-price-row">
62 <span><?php esc_html_e('Price per person', 'yatra'); ?></span>
63 <span><?php echo esc_html($checkout->getFormattedPricePerPerson()); ?></span>
64 </div>
65 <div class="yatra-price-row">
66 <span><?php esc_html_e('Number of travelers', 'yatra'); ?></span>
67 <span id="summary-travelers"><?php echo (int) $checkout->getTotalTravelers(); ?></span>
68 </div>
69 <?php endif; ?>
70
71 <?php
72 // Pull dynamic-pricing breakdown — either from the explicit `$dynamic_pricing`
73 // template var (used by the AJAX summary refresh + initial page render) or, as
74 // a fallback, from the Checkout model. Both paths point at the same data; the
75 // fallback covers any future render context that forgets to pass the variable.
76 if (!isset($dynamic_pricing) || !is_array($dynamic_pricing)) {
77 $dynamic_pricing = $checkout->getDynamicPricing();
78 }
79 $dp_total_adjustment = (float) $checkout->getDynamicPricingTotalAdjustment();
80 $has_dp = !empty($dynamic_pricing) && !empty($dynamic_pricing['rules']);
81 ?>
82
83 <?php
84 // Additional Services are picked above the Pricing Summary in their own card
85 // (see booking-content.php). When the user toggles a checkbox, booking.js
86 // POSTs to /booking/session then refreshes this partial via /booking/summary —
87 // the selected-services iteration further down then renders them inline as
88 // compact price rows so the customer sees what's contributing to the total.
89 ?>
90
91 <?php
92 // Dynamic-pricing caption removed per UX request — the customer can see the
93 // effective per-unit price in the traveler row itself; an extra "X pricing
94 // rule applied" line just adds noise. The DP impact is implicit in the
95 // post-DP price now displayed in the category row above.
96 ?>
97
98 <?php if ($checkout->hasAdditionalServices()) : ?>
99 <!-- Selected Additional Services rendered ABOVE Trip Subtotal so the
100 subtotal reads as the natural sum of (traveler categories + services).
101 The Pro AdditionalServicesModule already folds these into the gross
102 total, so we only render the rows here for transparency not for
103 summing again. -->
104 <?php foreach ($checkout->getAdditionalServices() as $service) : ?>
105 <?php if (!empty($service['selected'])) :
106 $service_price = $service['calculated_price'] ?? $service['price'] ?? 0;
107 $is_included = !empty($service['is_included']);
108 $is_required = !empty($service['is_required']);
109 ?>
110 <div class="yatra-price-row yatra-price-service<?php echo $is_included ? ' yatra-service-included' : ''; ?>">
111 <span>
112 <?php echo esc_html($service['name']); ?>
113 <?php if ($is_required && !$is_included) : ?>
114 <span class="yatra-service-badge yatra-badge-required"><?php esc_html_e('Required', 'yatra'); ?></span>
115 <?php endif; ?>
116 </span>
117 <?php if ($is_included) : ?>
118 <span class="yatra-service-included-badge"><?php esc_html_e('Included', 'yatra'); ?></span>
119 <?php else : ?>
120 <span><?php echo esc_html($checkout->formatPrice($service_price)); ?></span>
121 <?php endif; ?>
122 </div>
123 <?php endif; ?>
124 <?php endforeach; ?>
125 <?php endif; ?>
126
127 <!-- Trip Subtotal (categories + services, before discounts/taxes) -->
128 <div class="yatra-price-row yatra-price-subtotal">
129 <span><strong><?php esc_html_e('Trip Subtotal', 'yatra'); ?></strong></span>
130 <span id="summary-gross-total"><strong><?php echo esc_html($checkout->getFormattedGrossTotal()); ?></strong></span>
131 </div>
132
133 <?php if ($checkout->hasCoupon()) : ?>
134 <!-- Coupon Discount -->
135 <div class="yatra-price-row yatra-price-discount" id="yatra-discount-row">
136 <span class="yatra-discount-label">
137 <?php echo esc_html($checkout->getCouponDiscountLabel()); ?>
138 <span class="yatra-discount-code">(<?php echo esc_html($checkout->getCouponCode()); ?>)</span>
139 </span>
140 <span class="yatra-discount-amount" style="color: #059669;">-<?php echo esc_html($checkout->getFormattedCouponDiscount()); ?></span>
141 </div>
142 <?php endif; ?>
143
144 <?php if ($checkout->getGroupDiscountAmount() > 0) : ?>
145 <!-- Group Discount -->
146 <div class="yatra-price-row yatra-price-discount yatra-group-discount-row" id="yatra-group-discount-row">
147 <span class="yatra-discount-label">
148 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 4px;">
149 <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
150 <circle cx="9" cy="7" r="4"></circle>
151 <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
152 <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
153 </svg>
154 <?php echo esc_html($checkout->getGroupDiscountLabel()); ?>
155 </span>
156 <span class="yatra-discount-amount" style="color: #059669; font-weight: 500;">-<?php echo esc_html($checkout->getFormattedGroupDiscount()); ?></span>
157 </div>
158 <?php endif; ?>
159
160 <?php if ($checkout->hasItineraryCosts()) : ?>
161 <style>
162 .yatra-price-tooltip {
163 position: relative;
164 display: inline-block;
165 margin-left: 4px;
166 vertical-align: middle;
167 }
168
169 .yatra-price-tooltip:hover::after {
170 content: attr(title);
171 position: absolute;
172 bottom: 125%;
173 left: 50%;
174 transform: translateX(-50%);
175 background: #1f2937;
176 color: white;
177 padding: 6px 10px;
178 border-radius: 6px;
179 font-size: 12px;
180 white-space: nowrap;
181 z-index: 1000;
182 pointer-events: none;
183 opacity: 0;
184 transition: opacity 0.3s;
185 }
186
187 .yatra-price-tooltip:hover::before {
188 content: '';
189 position: absolute;
190 bottom: 120%;
191 left: 50%;
192 transform: translateX(-50%);
193 border: 5px solid transparent;
194 border-top-color: #1f2937;
195 z-index: 1000;
196 pointer-events: none;
197 opacity: 0;
198 transition: opacity 0.3s;
199 }
200
201 .yatra-price-tooltip:hover::after,
202 .yatra-price-tooltip:hover::before {
203 opacity: 1;
204 }
205 </style>
206 <!-- Itinerary Costs -->
207 <div class="yatra-price-section">
208 <div class="yatra-price-section-title">
209 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
210 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
211 <polyline points="9 22 9 12 15 12 15 22"></polyline>
212 </svg>
213 <?php esc_html_e('Itinerary Costs', 'yatra'); ?>
214 </div>
215 <?php foreach ($checkout->getItineraryCosts() as $cost) : ?>
216 <div class="yatra-price-row yatra-price-itinerary">
217 <span>
218 <?php
219 echo esc_html($cost['name']);
220 if (!empty($cost['price_per'])) {
221 if ($cost['price_per'] === 'person') {
222 echo ' ' . esc_html_x('(per person)', 'pricing type', 'yatra');
223 $quantity = $checkout->getTotalTravelers();
224 $unit_price = $cost['price'] ?? 0;
225 $total_cost = $unit_price * $quantity;
226 ?>
227 <span class="yatra-price-tooltip" title="<?php
228 // Tooltip: unit price × travelers = line total. Formatted
229 // through the canonical formatter so decimals, separators
230 // and currency symbol match the rest of the site (single
231 // source of truth). zero_is_unknown=false so a 0 line
232 // renders as a number, not "Contact for pricing".
233 $tooltip_text = sprintf(
234 /* translators: 1: formatted unit price, 2: number of travelers, 3: formatted line total */
235 __('%1$s × %2$d travelers = %3$s', 'yatra'),
236 yatra_format_price($unit_price, null, false),
237 (int) $quantity,
238 yatra_format_price($total_cost, null, false)
239 );
240 echo esc_attr($tooltip_text);
241 ?>">
242 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="opacity: 0.6; cursor: help;">
243 <circle cx="12" cy="12" r="10"></circle>
244 <line x1="12" y1="16" x2="12" y2="12"></line>
245 <line x1="12" y1="8" x2="12.01" y2="8"></line>
246 </svg>
247 </span>
248 <?php
249 } elseif ($cost['price_per'] === 'group') {
250 echo ' ' . esc_html_x('(per booking)', 'pricing type', 'yatra');
251 } else {
252 echo ' ' . esc_html_x('(flat rate)', 'pricing type', 'yatra');
253 }
254 }
255 ?>
256 </span>
257 <span><?php
258 if (!empty($cost['price_per']) && $cost['price_per'] === 'person') {
259 $quantity = $checkout->getTotalTravelers();
260 $unit_price = $cost['price'] ?? 0;
261 $total_cost = $unit_price * $quantity;
262 echo esc_html($checkout->formatPrice($total_cost));
263 } else {
264 echo esc_html($checkout->formatPrice($cost['price'] ?? 0));
265 }
266 ?></span>
267 </div>
268 <?php endforeach; ?>
269 </div>
270 <?php endif; ?>
271
272 <?php
273 // (Selected Additional Services moved above the Trip Subtotal line for the
274 // correct visual order: categories → services → subtotal. Old position
275 // rendered them after the subtotal, which is what made the "double-count
276 // looking" sidebar — visually it seemed like services were added on top of
277 // an already-services-inclusive subtotal.)
278 ?>
279
280 <?php
281 // (Old "Dynamic Pricing" section with Original Price strike-through, savings
282 // badge, and urgency banner removed — the compact line item at the top of
283 // this template is now the single source of truth for DP in the sidebar.
284 // Admins who want the strike-through / badge / urgency styling can re-add it
285 // in a custom template override; keeping the default summary clean.)
286 ?>
287
288 <!-- Taxable Amount (SubTotal - amount that tax is calculated on) -->
289 <?php
290 $has_discount = $checkout->hasCoupon() || $checkout->getGroupDiscountAmount() > 0;
291 // Only show taxable amount if there are taxes AND if there's a discount
292 if ($checkout->hasTaxes() && $has_discount) :
293 $taxable_amount = $checkout->getTaxableAmount();
294 ?>
295 <div class="yatra-price-row yatra-price-subtotal" style="border-top: 1px dashed #e5e7eb; margin-top: 8px; padding-top: 8px;">
296 <span><strong><?php esc_html_e('Subtotal (Taxable Amount)', 'yatra'); ?></strong></span>
297 <span id="summary-taxable-amount"><strong><?php echo esc_html($checkout->formatPrice($taxable_amount)); ?></strong></span>
298 </div>
299 <?php endif; ?>
300
301 <?php if ($checkout->hasTaxes()) : ?>
302 <!-- Tax Breakdown -->
303 <div class="yatra-price-section yatra-tax-section">
304 <div class="yatra-price-section-title">
305 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
306 <line x1="19" y1="5" x2="5" y2="19"></line>
307 <circle cx="6.5" cy="6.5" r="2.5"></circle>
308 <circle cx="17.5" cy="17.5" r="2.5"></circle>
309 </svg>
310 <?php esc_html_e('Tax', 'yatra'); ?>
311 </div>
312 <?php foreach ($checkout->getTaxBreakdown() as $tax) : ?>
313 <div class="yatra-price-row yatra-price-tax">
314 <span><?php echo esc_html($tax['name']); ?> (<?php echo esc_html($tax['rate']); ?>%)</span>
315 <span><?php echo esc_html($checkout->formatPrice($tax['amount'])); ?></span>
316 </div>
317 <?php endforeach; ?>
318 </div>
319 <?php endif; ?>
320
321 <!-- Net Amount -->
322 <div class="yatra-price-row yatra-price-total">
323 <span><strong><?php esc_html_e('Net Amount', 'yatra'); ?></strong></span>
324 <span id="summary-total"><strong><?php echo esc_html($checkout->getFormattedNetTotal()); ?></strong></span>
325 </div>
326
327 <?php if ($checkout->getPaymentMethod() !== 'full') : ?>
328 <!-- Due Now -->
329 <div class="yatra-price-row yatra-price-due">
330 <span><?php esc_html_e('Due Now', 'yatra'); ?></span>
331 <span id="summary-due"><strong><?php echo esc_html($checkout->getFormattedAmountDue()); ?></strong></span>
332 </div>
333 <?php endif; ?>
334