| @@ -67,11 +67,67 @@ | ||
| 67 | 67 | <span id="summary-travelers"><?php echo (int) $checkout->getTotalTravelers(); ?></span> |
| 68 | 68 | </div> |
| 69 | 69 | <?php endif; ?> |
| 70 | 70 | |
| 71 | -<!-- Gross Total (base trip cost before services/discounts/taxes) --> | |
| 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) --> | |
| 72 | 128 | <div class="yatra-price-row yatra-price-subtotal"> |
| 73 | - <span><strong><?php esc_html_e('Gross Total', 'yatra'); ?></strong></span> | |
| 129 | + <span><strong><?php esc_html_e('Trip Subtotal', 'yatra'); ?></strong></span> | |
| 74 | 130 | <span id="summary-gross-total"><strong><?php echo esc_html($checkout->getFormattedGrossTotal()); ?></strong></span> |
| 75 | 131 | </div> |
| 76 | 132 | |
| 77 | 133 | <?php if ($checkout->hasCoupon()) : ?> |
| @@ -168,18 +224,19 @@ | ||
| 168 | 224 | $unit_price = $cost['price'] ?? 0; |
| 169 | 225 | $total_cost = $unit_price * $quantity; |
| 170 | 226 | ?> |
| 171 | 227 | <span class="yatra-price-tooltip" title="<?php |
| 172 | - // Build tooltip data with proper escaping and currency symbol | |
| 173 | - $currency_symbol = $checkout->getCurrencySymbol(); | |
| 174 | - $unit_price_formatted = number_format($unit_price, 2); | |
| 175 | - $total_cost_formatted = number_format($total_cost, 2); | |
| 176 | - $tooltip_text = sprintf('%s%s × %d travelers = %s%s', | |
| 177 | - $currency_symbol, | |
| 178 | - $unit_price_formatted, | |
| 179 | - (int) $quantity, | |
| 180 | - $currency_symbol, | |
| 181 | - $total_cost_formatted | |
| 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) | |
| 182 | 239 | ); |
| 183 | 240 | echo esc_attr($tooltip_text); |
| 184 | 241 | ?>"> |
| 185 | 242 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="opacity: 0.6; cursor: help;"> |
| @@ -211,94 +268,23 @@ | ||
| 211 | 268 | <?php endforeach; ?> |
| 212 | 269 | </div> |
| 213 | 270 | <?php endif; ?> |
| 214 | 271 | |
| 215 | -<?php if ($checkout->hasAdditionalServices()) : ?> | |
| 216 | -<!-- Additional Services --> | |
| 217 | -<?php foreach ($checkout->getAdditionalServices() as $service) : ?> | |
| 218 | - <?php if (!empty($service['selected'])) : ?> | |
| 219 | - <?php | |
| 220 | - $service_price = $service['calculated_price'] ?? $service['price'] ?? 0; | |
| 221 | - $is_included = !empty($service['is_included']); | |
| 222 | - $is_required = !empty($service['is_required']); | |
| 223 | - ?> | |
| 224 | - <div class="yatra-price-row yatra-price-service<?php echo $is_included ? ' yatra-service-included' : ''; ?>"> | |
| 225 | - <span> | |
| 226 | - <?php echo esc_html($service['name']); ?> | |
| 227 | - <?php if ($is_required && !$is_included) : ?> | |
| 228 | - <span class="yatra-service-badge yatra-badge-required"><?php esc_html_e('Required', 'yatra'); ?></span> | |
| 229 | - <?php endif; ?> | |
| 230 | - </span> | |
| 231 | - <?php if ($is_included) : ?> | |
| 232 | - <span class="yatra-service-included-badge"><?php esc_html_e('Included', 'yatra'); ?></span> | |
| 233 | - <?php else : ?> | |
| 234 | - <span><?php echo esc_html($checkout->formatPrice($service_price)); ?></span> | |
| 235 | - <?php endif; ?> | |
| 236 | - </div> | |
| 237 | - <?php endif; ?> | |
| 238 | -<?php endforeach; ?> | |
| 239 | -<?php endif; ?> | |
| 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 | +?> | |
| 240 | 279 | |
| 241 | -<?php if (!empty($dynamic_pricing) && !empty($dynamic_pricing['rules'])) : ?> | |
| 242 | -<!-- Dynamic Pricing Information --> | |
| 243 | -<div class="yatra-price-section yatra-dynamic-pricing-section"> | |
| 244 | - <div class="yatra-price-section-title"> | |
| 245 | - <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| 246 | - <path d="M12 2v20m8-10H4"></path> | |
| 247 | - <circle cx="12" cy="12" r="3"></circle> | |
| 248 | - </svg> | |
| 249 | - <?php echo esc_html($dynamic_pricing['label']); ?> | |
| 250 | - </div> | |
| 251 | - | |
| 252 | - <?php if (!empty($dynamic_pricing['show_original_price']) && $dynamic_pricing['original_price'] > 0 && $dynamic_pricing['original_price'] != $dynamic_pricing['final_price']) : ?> | |
| 253 | - <div class="yatra-price-row yatra-original-price"> | |
| 254 | - <span><?php esc_html_e('Original Price', 'yatra'); ?></span> | |
| 255 | - <span class="yatra-original-price-amount" style="text-decoration: line-through; color: #6b7280;"> | |
| 256 | - <?php echo esc_html(yatra_format_price($dynamic_pricing['original_price'], $currency ?? null)); ?> | |
| 257 | - </span> | |
| 258 | - </div> | |
| 259 | - <?php endif; ?> | |
| 260 | - | |
| 261 | - <?php if (!empty($dynamic_pricing['show_savings_badge']) && $dynamic_pricing['savings'] > 0) : ?> | |
| 262 | - <div class="yatra-price-row yatra-savings-badge" style="background-color: #dcfce7; color: #166534; padding: 8px 12px; border-radius: 6px; margin: 8px 0;"> | |
| 263 | - <span style="font-weight: 600;"> | |
| 264 | - <?php | |
| 265 | - printf( | |
| 266 | - /* translators: %s: savings percentage */ | |
| 267 | - esc_html__('You save %s', 'yatra'), | |
| 268 | - '<span style="color: #16a34a; font-weight: 700;">' . number_format($dynamic_pricing['savings_percent'], 1) . '%</span>' | |
| 269 | - ); | |
| 270 | - ?> | |
| 271 | - </span> | |
| 272 | - <span style="font-weight: 600; color: #16a34a;"> | |
| 273 | - <?php echo esc_html(yatra_format_price($dynamic_pricing['savings'], $currency ?? null)); ?> | |
| 274 | - </span> | |
| 275 | - </div> | |
| 276 | - <?php endif; ?> | |
| 277 | - | |
| 278 | - <?php if (!empty($dynamic_pricing['show_urgency_messages']) && !empty($dynamic_pricing['rules'])) : ?> | |
| 279 | - <div class="yatra-price-row yatra-urgency-message" style="background-color: #fef3c7; color: #92400e; padding: 8px 12px; border-radius: 6px; margin: 8px 0; font-size: 14px;"> | |
| 280 | - <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: 6px;"> | |
| 281 | - <circle cx="12" cy="12" r="10"></circle> | |
| 282 | - <line x1="12" y1="8" x2="12" y2="12"></line> | |
| 283 | - <line x1="12" y1="16" x2="12.01" y2="16"></line> | |
| 284 | - </svg> | |
| 285 | - <?php | |
| 286 | - $ruleCount = count($dynamic_pricing['rules']); | |
| 287 | - if ($ruleCount === 1) { | |
| 288 | - esc_html_e('Limited time offer! Dynamic pricing applied.', 'yatra'); | |
| 289 | - } else { | |
| 290 | - printf( | |
| 291 | - /* translators: %d: number of rules */ | |
| 292 | - esc_html(_n('%d dynamic pricing rule applied!', '%d dynamic pricing rules applied!', $ruleCount, 'yatra')), | |
| 293 | - (int) $ruleCount | |
| 294 | - ); | |
| 295 | - } | |
| 296 | - ?> | |
| 297 | - </div> | |
| 298 | - <?php endif; ?> | |
| 299 | -</div> | |
| 300 | -<?php endif; ?> | |
| 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 | +?> | |
| 301 | 287 | |
| 302 | 288 | <!-- Taxable Amount (SubTotal - amount that tax is calculated on) --> |
| 303 | 289 | <?php |
| 304 | 290 | $has_discount = $checkout->hasCoupon() || $checkout->getGroupDiscountAmount() > 0; |
| @@ -315,11 +301,12 @@ | ||
| 315 | 301 | <?php if ($checkout->hasTaxes()) : ?> |
| 316 | 302 | <!-- Tax Breakdown --> |
| 317 | 303 | <div class="yatra-price-section yatra-tax-section"> |
| 318 | 304 | <div class="yatra-price-section-title"> |
| 319 | - <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| 320 | - <path d="M9 14l2 2 4-4"></path> | |
| 321 | - <path d="M21 12c.552 0 1-.448 1-1V8c0-.552-.448-1-1-1h-1V6a2 2 0 00-2-2H4a2 2 0 00-2 2v1c0 .552.448 1 1 1h1v1c0 .552.448 1 1 1h1M3 15a1 1 0 011-1h2.5a1 1 0 011 1v1.5"></path> | |
| 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> | |
| 322 | 309 | </svg> |
| 323 | 310 | <?php esc_html_e('Tax', 'yatra'); ?> |
| 324 | 311 | </div> |
| 325 | 312 | <?php foreach ($checkout->getTaxBreakdown() as $tax) : ?> |