| @@ -205,9 +205,14 @@ | ||
| 205 | 205 | const decimalSep = (typeof cfg.decimalSeparator === 'string') ? cfg.decimalSeparator : '.'; |
| 206 | 206 | |
| 207 | 207 | const num = Number(amount) || 0; |
| 208 | 208 | |
| 209 | - 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', { | |
| 210 | 215 | minimumFractionDigits: decimals, |
| 211 | 216 | maximumFractionDigits: decimals, |
| 212 | 217 | }).format(num) |
| 213 | 218 | .replace(/,/g, 'TEMP_THOUSAND') |
| @@ -3891,8 +3896,9 @@ | ||
| 3891 | 3896 | // Check for traveler-based pricing first |
| 3892 | 3897 | const categoryInputs = this.section.querySelectorAll(`.yatra-availability-category[data-item="${itemIndex}"]`); |
| 3893 | 3898 | let totalPrice = 0; |
| 3894 | 3899 | let totalTravelers = 0; |
| 3900 | + let totalGroups = 0; // per-group categories: number of group prices charged | |
| 3895 | 3901 | |
| 3896 | 3902 | if (categoryInputs.length > 0) { |
| 3897 | 3903 | // Traveler-based pricing: sum up each category's price * quantity (respecting pricing mode) |
| 3898 | 3904 | categoryInputs.forEach((input) => { |
| @@ -3904,11 +3910,11 @@ | ||
| 3904 | 3910 | const maxPax = parseInt((row ? row.getAttribute('data-max-pax') : null) || input.getAttribute('data-max-pax')) || 0; |
| 3905 | 3911 | |
| 3906 | 3912 | if (pricingMode === 'per_group') { |
| 3907 | 3913 | if (quantity > 0) { |
| 3908 | - totalPrice += (groupOverflow === 'per_block' && maxPax > 0) | |
| 3909 | - ? price * Math.ceil(quantity / maxPax) | |
| 3910 | - : price; | |
| 3914 | + const blocks = (groupOverflow === 'per_block' && maxPax > 0) ? Math.ceil(quantity / maxPax) : 1; | |
| 3915 | + totalPrice += price * blocks; | |
| 3916 | + totalGroups += blocks; | |
| 3911 | 3917 | } |
| 3912 | 3918 | } else { |
| 3913 | 3919 | totalPrice += quantity * price; |
| 3914 | 3920 | } |
| @@ -3936,14 +3942,21 @@ | ||
| 3936 | 3942 | } else { |
| 3937 | 3943 | totalAmountElement.textContent = String(finalPrice.toFixed(2)); |
| 3938 | 3944 | } |
| 3939 | 3945 | |
| 3940 | - // 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). | |
| 3941 | 3950 | const cardRoot = this.section.querySelector('.yatra-availability-card[data-item="' + itemIndex + '"]'); |
| 3942 | - 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; | |
| 3943 | 3953 | if (headerSaleEl) { |
| 3954 | + const headerUnit = headerPriceWrap.getAttribute('data-price-unit') || 'per_person'; | |
| 3944 | 3955 | let perPerson = 0; |
| 3945 | - if (totalTravelers > 0) { | |
| 3956 | + if (headerUnit === 'per_group') { | |
| 3957 | + perPerson = totalGroups > 0 ? finalPrice / totalGroups : (totalPrice > 0 ? totalPrice : 0); | |
| 3958 | + } else if (totalTravelers > 0) { | |
| 3946 | 3959 | perPerson = finalPrice / totalTravelers; |
| 3947 | 3960 | } else if (totalPrice > 0) { |
| 3948 | 3961 | perPerson = totalPrice; |
| 3949 | 3962 | } |