PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
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
← All changes | assets/js/trip.js +45 -19 3.0.10 → 3.0.16 View file →
@@ -5,8 +5,21 @@
5 5 /* jshint esversion: 6 */
6 6
7 7 // Translation helpers (booking.js installs the same shims if it runs first;
8 8 // idempotent setup so either load order works).
9 +// Parse a numeric min/max attribute while preserving a legitimate 0.
10 +// `parseInt(el.getAttribute('max')) || 99` treated max="0" — what a sold-out
11 +// departure renders — as "unset" and fell back to the placeholder ceiling, so
12 +// the guest selector stayed usable and ignored the departure's real capacity.
13 +// Only an absent or non-numeric value may fall back. Installed once and shared
14 +// by every frontend script, so load order does not matter.
15 +if (typeof window.yatraNumOr !== 'function') {
16 + window.yatraNumOr = function (raw, fallback) {
17 + var parsed = parseInt(raw, 10);
18 + return isNaN(parsed) ? fallback : parsed;
19 + };
20 +}
21 +
9 22 (function () {
10 23 var i18n = (window.wp && window.wp.i18n) ? window.wp.i18n : null;
11 24 if (i18n && typeof i18n.__ === 'function') {
12 25 window.__ = function (text, domain) { return i18n.__(text, domain || 'yatra'); };
@@ -192,9 +205,14 @@
192 205 const decimalSep = (typeof cfg.decimalSeparator === 'string') ? cfg.decimalSeparator : '.';
193 206
194 207 const num = Number(amount) || 0;
195 208
196 - const formatted = new Intl.NumberFormat(undefined, {
209 + // Format with a FIXED 'en-US' base (grouping ',', decimal '.') so the
210 + // replace-with-configured-separators below is deterministic. With the
211 + // viewer's locale (undefined), a European browser already yields
212 + // '1.234,56' and the naive comma/dot replacement SWAPS the separators —
213 + // making the configured decimal separator appear ignored.
214 + const formatted = new Intl.NumberFormat('en-US', {
197 215 minimumFractionDigits: decimals,
198 216 maximumFractionDigits: decimals,
199 217 }).format(num)
200 218 .replace(/,/g, 'TEMP_THOUSAND')
@@ -1591,10 +1609,10 @@
1591 1609 if (!minusBtn || !plusBtn) return;
1592 1610
1593 1611 const updateButtonStates = () => {
1594 1612 const current = parseInt(input.value) || 1;
1595 - const min = parseInt(input.getAttribute('min')) || 1;
1596 - const max = parseInt(input.getAttribute('max')) || 20;
1613 + const min = window.yatraNumOr(input.getAttribute('min'), 1);
1614 + const max = window.yatraNumOr(input.getAttribute('max'), 20);
1597 1615
1598 1616 minusBtn.disabled = current <= min;
1599 1617 plusBtn.disabled = current >= max;
1600 1618 };
@@ -1604,9 +1622,9 @@
1604 1622 e.preventDefault();
1605 1623 e.stopPropagation();
1606 1624
1607 1625 const current = parseInt(input.value) || 1;
1608 - const min = parseInt(input.getAttribute('min')) || 1;
1626 + const min = window.yatraNumOr(input.getAttribute('min'), 1);
1609 1627
1610 1628 if (current > min) {
1611 1629 input.value = current - 1;
1612 1630 updateButtonStates();
@@ -1619,9 +1637,9 @@
1619 1637 e.preventDefault();
1620 1638 e.stopPropagation();
1621 1639
1622 1640 const current = parseInt(input.value) || 1;
1623 - const max = parseInt(input.getAttribute('max')) || 20;
1641 + const max = window.yatraNumOr(input.getAttribute('max'), 20);
1624 1642
1625 1643 if (current < max) {
1626 1644 input.value = current + 1;
1627 1645 updateButtonStates();
@@ -2365,15 +2383,15 @@
2365 2383 const row = travelerSelector.querySelector('.yatra-quantity-row[data-category-id="' + categoryId + '"]');
2366 2384 if (row) {
2367 2385 const cardInput = row.querySelector('input[type="number"]');
2368 2386 if (cardInput) {
2369 - const max = parseInt(cardInput.getAttribute('max')) || 99;
2387 + const max = window.yatraNumOr(cardInput.getAttribute('max'), 99);
2370 2388 cardInput.value = Math.min(value, max);
2371 2389
2372 2390 // Update button states
2373 2391 const minusBtn = row.querySelector('.yatra-quantity-minus');
2374 2392 const plusBtn = row.querySelector('.yatra-quantity-plus');
2375 - const min = parseInt(cardInput.getAttribute('min')) || 0;
2393 + const min = window.yatraNumOr(cardInput.getAttribute('min'), 0);
2376 2394 if (minusBtn) minusBtn.disabled = cardInput.value <= min;
2377 2395 if (plusBtn) plusBtn.disabled = cardInput.value >= max;
2378 2396 }
2379 2397 }
@@ -2384,9 +2402,9 @@
2384 2402
2385 2403 } else if (simpleTravelers && numTravelersInput) {
2386 2404 // Simple pricing - sync total count
2387 2405 const totalCount = parseInt(numTravelersInput.value) || 1;
2388 - const max = parseInt(simpleTravelers.getAttribute('max')) || 99;
2406 + const max = window.yatraNumOr(simpleTravelers.getAttribute('max'), 99);
2389 2407 simpleTravelers.value = Math.min(totalCount, max);
2390 2408
2391 2409 // Update button states
2392 2410 const controls = simpleTravelers.closest('.yatra-quantity-controls-inline');
@@ -2392,9 +2410,9 @@
2392 2410 const controls = simpleTravelers.closest('.yatra-quantity-controls-inline');
2393 2411 if (controls) {
2394 2412 const minusBtn = controls.querySelector('.yatra-quantity-minus');
2395 2413 const plusBtn = controls.querySelector('.yatra-quantity-plus');
2396 - const min = parseInt(simpleTravelers.getAttribute('min')) || 1;
2414 + const min = window.yatraNumOr(simpleTravelers.getAttribute('min'), 1);
2397 2415 if (minusBtn) minusBtn.disabled = simpleTravelers.value <= min;
2398 2416 if (plusBtn) plusBtn.disabled = simpleTravelers.value >= max;
2399 2417 }
2400 2418 }
@@ -3690,10 +3708,10 @@
3690 3708 const isMinus = btn.classList.contains('yatra-quantity-minus');
3691 3709 const isPlus = btn.classList.contains('yatra-quantity-plus');
3692 3710
3693 3711 let current = parseInt(input.value) || 0;
3694 - const min = parseInt(input.getAttribute('min')) || 0;
3695 - const max = parseInt(input.getAttribute('max')) || 999;
3712 + const min = window.yatraNumOr(input.getAttribute('min'), 0);
3713 + const max = window.yatraNumOr(input.getAttribute('max'), 999);
3696 3714 let newValue = current;
3697 3715
3698 3716 if (isPlus && current < max) {
3699 3717 newValue = current + 1;
@@ -3765,10 +3783,10 @@
3765 3783 const isMinus = btn.classList.contains('yatra-quantity-minus');
3766 3784 const isPlus = btn.classList.contains('yatra-quantity-plus');
3767 3785
3768 3786 let current = parseInt(input.value) || 1;
3769 - const min = parseInt(input.getAttribute('min')) || 1;
3770 - const max = parseInt(input.getAttribute('max')) || 999;
3787 + const min = window.yatraNumOr(input.getAttribute('min'), 1);
3788 + const max = window.yatraNumOr(input.getAttribute('max'), 999);
3771 3789 let newValue = current;
3772 3790
3773 3791 if (isPlus && current < max) {
3774 3792 newValue = current + 1;
@@ -3878,8 +3896,9 @@
3878 3896 // Check for traveler-based pricing first
3879 3897 const categoryInputs = this.section.querySelectorAll(`.yatra-availability-category[data-item="${itemIndex}"]`);
3880 3898 let totalPrice = 0;
3881 3899 let totalTravelers = 0;
3900 + let totalGroups = 0; // per-group categories: number of group prices charged
3882 3901
3883 3902 if (categoryInputs.length > 0) {
3884 3903 // Traveler-based pricing: sum up each category's price * quantity (respecting pricing mode)
3885 3904 categoryInputs.forEach((input) => {
@@ -3891,11 +3910,11 @@
3891 3910 const maxPax = parseInt((row ? row.getAttribute('data-max-pax') : null) || input.getAttribute('data-max-pax')) || 0;
3892 3911
3893 3912 if (pricingMode === 'per_group') {
3894 3913 if (quantity > 0) {
3895 - totalPrice += (groupOverflow === 'per_block' && maxPax > 0)
3896 - ? price * Math.ceil(quantity / maxPax)
3897 - : price;
3914 + const blocks = (groupOverflow === 'per_block' && maxPax > 0) ? Math.ceil(quantity / maxPax) : 1;
3915 + totalPrice += price * blocks;
3916 + totalGroups += blocks;
3898 3917 }
3899 3918 } else {
3900 3919 totalPrice += quantity * price;
3901 3920 }
@@ -3923,14 +3942,21 @@
3923 3942 } else {
3924 3943 totalAmountElement.textContent = String(finalPrice.toFixed(2));
3925 3944 }
3926 3945
3927 - // Header "per person" must match chargable average (row totals + group discount), not static PHP.
3946 + // Header price must match the chargeable amount (row totals + group discount), not static PHP.
3947 + // Its unit follows the card's price label: "per person" → average per traveller;
3948 + // "per group" → the price per group actually charged (never divided by headcount,
3949 + // which would turn a flat $1,100 group price into "$550 per group" for two travellers).
3928 3950 const cardRoot = this.section.querySelector('.yatra-availability-card[data-item="' + itemIndex + '"]');
3929 - const headerSaleEl = cardRoot ? cardRoot.querySelector('.yatra-card-header-price .yatra-sale-price') : null;
3951 + const headerPriceWrap = cardRoot ? cardRoot.querySelector('.yatra-card-header-price') : null;
3952 + const headerSaleEl = headerPriceWrap ? headerPriceWrap.querySelector('.yatra-sale-price') : null;
3930 3953 if (headerSaleEl) {
3954 + const headerUnit = headerPriceWrap.getAttribute('data-price-unit') || 'per_person';
3931 3955 let perPerson = 0;
3932 - if (totalTravelers > 0) {
3956 + if (headerUnit === 'per_group') {
3957 + perPerson = totalGroups > 0 ? finalPrice / totalGroups : (totalPrice > 0 ? totalPrice : 0);
3958 + } else if (totalTravelers > 0) {
3933 3959 perPerson = finalPrice / totalTravelers;
3934 3960 } else if (totalPrice > 0) {
3935 3961 perPerson = totalPrice;
3936 3962 }