// Travel Cost Calculator Module // Main calculation engine for government travel costs // Calculate number of days between two dates function calculateDays(startDate, endDate) { const start = new Date(startDate); const end = new Date(endDate); const diffTime = Math.abs(end - start); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return diffDays; } // Calculate number of nights function calculateNights(startDate, endDate) { const days = calculateDays(startDate, endDate); return Math.max(0, days); } // Calculate total travel costs async function calculateTravelCosts(params) { const { departureCity, destinationCity, departureDate, returnDate, currency, privateAccommodation, privateAccommodationRate, searchFlights } = params; // Validate inputs if (!departureCity || !destinationCity || !departureDate || !returnDate) { throw new Error('Missing required travel information'); } // Get city details const departureCityDetails = getCityDetails(departureCity); const destinationCityDetails = getCityDetails(destinationCity); if (!departureCityDetails) { throw new Error(`Invalid departure city: ${departureCity}`); } if (!destinationCityDetails) { throw new Error(`Invalid destination city: ${destinationCity}`); } // Calculate days and nights const travelDays = calculateDays(departureDate, returnDate) + 1; // Include both start and end days const nights = calculateNights(departureDate, returnDate); // Get NJC rates for destination const rates = getCityRates(destinationCity); // Calculate per diem (meals and incidentals) const perDiemTotal = calculatePerDiem(destinationCity, travelDays); const mealBreakdown = getMealBreakdown(destinationCity); // Calculate accommodation const accommodationTotal = calculateAccommodation( destinationCity, nights, privateAccommodation, privateAccommodationRate ); // Flight information let flightInfo = null; let flightCost = 0; if (searchFlights) { flightInfo = await window.searchFlights( departureCity, destinationCity, departureDate, returnDate, departureCityDetails, destinationCityDetails ); // Use economy cost by default, business if eligible flightCost = flightInfo.businessClassEligible ? flightInfo.pricing.business : flightInfo.pricing.economy; } // Calculate subtotal in CAD const subtotalCAD = perDiemTotal + accommodationTotal + flightCost; // Convert to selected currency if needed let totalInSelectedCurrency = subtotalCAD; let conversionInfo = null; if (currency !== 'CAD') { totalInSelectedCurrency = convertCurrency(subtotalCAD, 'CAD', currency); conversionInfo = getConversionDetails(subtotalCAD, 'CAD', currency); } // Build result object return { tripDetails: { departure: { city: departureCity, province: departureCityDetails.province, date: departureDate }, destination: { city: destinationCity, province: destinationCityDetails.province, date: returnDate }, duration: { days: travelDays, nights: nights } }, costs: { perDiem: { total: perDiemTotal, dailyRate: rates.perDiem, breakdown: mealBreakdown, currency: 'CAD' }, accommodation: { total: accommodationTotal, nightlyRate: privateAccommodation ? (privateAccommodationRate || PRIVATE_ACCOMMODATION_RATE) : rates.accommodation, nights: nights, type: privateAccommodation ? 'Private' : 'Commercial', currency: 'CAD' }, flights: flightInfo ? { total: flightCost, details: flightInfo, currency: 'CAD' } : null }, totals: { cadTotal: subtotalCAD, selectedCurrency: currency, selectedCurrencyTotal: totalInSelectedCurrency, conversion: conversionInfo }, rates: rates, timestamp: new Date().toISOString() }; } // Format calculation results for display function formatResults(results) { const { tripDetails, costs, totals } = results; let html = ''; // Trip summary html += '