mirror of
https://github.com/mblanke/Gov_Travel_App.git
synced 2026-03-01 14:10:22 -05:00
160 lines
6.6 KiB
JavaScript
160 lines
6.6 KiB
JavaScript
// NJC Travel Directive Rates - Appendices C & D (January 2026)
|
|
// Per Diem and Accommodation Rates for Canadian Cities
|
|
|
|
const NJC_RATES = {
|
|
// Major Cities - Tier 1
|
|
"Toronto": { perDiem: 95.00, accommodation: 204.00, tier: 1 },
|
|
"Montreal": { perDiem: 93.00, accommodation: 198.00, tier: 1 },
|
|
"Vancouver": { perDiem: 98.00, accommodation: 223.00, tier: 1 },
|
|
"Calgary": { perDiem: 92.00, accommodation: 195.00, tier: 1 },
|
|
"Ottawa": { perDiem: 94.00, accommodation: 205.00, tier: 1 },
|
|
"Edmonton": { perDiem: 90.00, accommodation: 188.00, tier: 1 },
|
|
"Quebec City": { perDiem: 88.00, accommodation: 185.00, tier: 1 },
|
|
"Winnipeg": { perDiem: 85.00, accommodation: 175.00, tier: 1 },
|
|
"Halifax": { perDiem: 87.00, accommodation: 178.00, tier: 1 },
|
|
"Victoria": { perDiem: 91.00, accommodation: 192.00, tier: 1 },
|
|
|
|
// Large Cities - Tier 2
|
|
"Mississauga": { perDiem: 90.00, accommodation: 195.00, tier: 2 },
|
|
"Brampton": { perDiem: 88.00, accommodation: 185.00, tier: 2 },
|
|
"Hamilton": { perDiem: 85.00, accommodation: 172.00, tier: 2 },
|
|
"London": { perDiem: 83.00, accommodation: 168.00, tier: 2 },
|
|
"Markham": { perDiem: 89.00, accommodation: 190.00, tier: 2 },
|
|
"Vaughan": { perDiem: 88.00, accommodation: 188.00, tier: 2 },
|
|
"Kitchener": { perDiem: 82.00, accommodation: 165.00, tier: 2 },
|
|
"Windsor": { perDiem: 80.00, accommodation: 160.00, tier: 2 },
|
|
"Richmond Hill": { perDiem: 87.00, accommodation: 185.00, tier: 2 },
|
|
"Oakville": { perDiem: 86.00, accommodation: 180.00, tier: 2 },
|
|
"Burlington": { perDiem: 84.00, accommodation: 170.00, tier: 2 },
|
|
"Oshawa": { perDiem: 81.00, accommodation: 162.00, tier: 2 },
|
|
"Barrie": { perDiem: 82.00, accommodation: 165.00, tier: 2 },
|
|
"Sudbury": { perDiem: 80.00, accommodation: 158.00, tier: 2 },
|
|
"St. Catharines": { perDiem: 79.00, accommodation: 155.00, tier: 2 },
|
|
"Cambridge": { perDiem: 81.00, accommodation: 163.00, tier: 2 },
|
|
"Kingston": { perDiem: 83.00, accommodation: 168.00, tier: 2 },
|
|
"Guelph": { perDiem: 82.00, accommodation: 165.00, tier: 2 },
|
|
"Thunder Bay": { perDiem: 78.00, accommodation: 152.00, tier: 2 },
|
|
"Waterloo": { perDiem: 81.00, accommodation: 164.00, tier: 2 },
|
|
|
|
// Quebec Cities - Tier 2
|
|
"Laval": { perDiem: 88.00, accommodation: 185.00, tier: 2 },
|
|
"Gatineau": { perDiem: 87.00, accommodation: 182.00, tier: 2 },
|
|
"Longueuil": { perDiem: 86.00, accommodation: 180.00, tier: 2 },
|
|
"Sherbrooke": { perDiem: 79.00, accommodation: 155.00, tier: 2 },
|
|
"Saguenay": { perDiem: 76.00, accommodation: 148.00, tier: 2 },
|
|
"Levis": { perDiem: 82.00, accommodation: 168.00, tier: 2 },
|
|
"Trois-Rivières": { perDiem: 77.00, accommodation: 150.00, tier: 2 },
|
|
"Terrebonne": { perDiem: 84.00, accommodation: 172.00, tier: 2 },
|
|
|
|
// BC Cities - Tier 2
|
|
"Surrey": { perDiem: 90.00, accommodation: 195.00, tier: 2 },
|
|
"Burnaby": { perDiem: 92.00, accommodation: 200.00, tier: 2 },
|
|
"Richmond": { perDiem: 91.00, accommodation: 198.00, tier: 2 },
|
|
"Abbotsford": { perDiem: 82.00, accommodation: 165.00, tier: 2 },
|
|
"Coquitlam": { perDiem: 88.00, accommodation: 185.00, tier: 2 },
|
|
"Kelowna": { perDiem: 85.00, accommodation: 175.00, tier: 2 },
|
|
"Saanich": { perDiem: 87.00, accommodation: 180.00, tier: 2 },
|
|
"Kamloops": { perDiem: 79.00, accommodation: 158.00, tier: 2 },
|
|
"Nanaimo": { perDiem: 82.00, accommodation: 168.00, tier: 2 },
|
|
"Prince George": { perDiem: 78.00, accommodation: 155.00, tier: 2 },
|
|
|
|
// Prairie Cities - Tier 2
|
|
"Saskatoon": { perDiem: 83.00, accommodation: 168.00, tier: 2 },
|
|
"Regina": { perDiem: 82.00, accommodation: 165.00, tier: 2 },
|
|
"Red Deer": { perDiem: 80.00, accommodation: 160.00, tier: 2 },
|
|
"Lethbridge": { perDiem: 78.00, accommodation: 155.00, tier: 2 },
|
|
|
|
// Atlantic Cities - Tier 2
|
|
"St. John's": { perDiem: 84.00, accommodation: 172.00, tier: 2 },
|
|
"Moncton": { perDiem: 79.00, accommodation: 158.00, tier: 2 },
|
|
"Saint John": { perDiem: 78.00, accommodation: 155.00, tier: 2 },
|
|
"Fredericton": { perDiem: 77.00, accommodation: 152.00, tier: 2 },
|
|
"Dartmouth": { perDiem: 83.00, accommodation: 168.00, tier: 2 },
|
|
"Charlottetown": { perDiem: 80.00, accommodation: 162.00, tier: 2 },
|
|
|
|
// Smaller Cities and Towns - Tier 3 (Default Rate)
|
|
"DEFAULT": { perDiem: 75.00, accommodation: 145.00, tier: 3 }
|
|
};
|
|
|
|
// Private Accommodation Rate (per NJC)
|
|
const PRIVATE_ACCOMMODATION_RATE = 50.00; // Daily rate when staying with friends/family
|
|
|
|
// Meal allowances breakdown (part of per diem)
|
|
const MEAL_BREAKDOWN = {
|
|
breakfast: 0.20, // 20% of per diem
|
|
lunch: 0.30, // 30% of per diem
|
|
dinner: 0.40, // 40% of per diem
|
|
incidentals: 0.10 // 10% of per diem
|
|
};
|
|
|
|
// Get rates for a city
|
|
function getCityRates(cityName) {
|
|
if (!cityName) return null;
|
|
|
|
// Try to find exact match
|
|
if (NJC_RATES[cityName]) {
|
|
return NJC_RATES[cityName];
|
|
}
|
|
|
|
// Try case-insensitive match
|
|
const cityKey = Object.keys(NJC_RATES).find(
|
|
key => key.toLowerCase() === cityName.toLowerCase()
|
|
);
|
|
|
|
if (cityKey) {
|
|
return NJC_RATES[cityKey];
|
|
}
|
|
|
|
// Return default rates if city not found
|
|
return NJC_RATES.DEFAULT;
|
|
}
|
|
|
|
// Calculate per diem for number of days
|
|
function calculatePerDiem(cityName, numberOfDays) {
|
|
const rates = getCityRates(cityName);
|
|
if (!rates) return 0;
|
|
|
|
return rates.perDiem * numberOfDays;
|
|
}
|
|
|
|
// Calculate accommodation costs
|
|
function calculateAccommodation(cityName, numberOfNights, isPrivate = false, customRate = null) {
|
|
if (isPrivate) {
|
|
// Use custom rate if provided, otherwise use standard private rate
|
|
const rate = customRate || PRIVATE_ACCOMMODATION_RATE;
|
|
return rate * numberOfNights;
|
|
}
|
|
|
|
const rates = getCityRates(cityName);
|
|
if (!rates) return 0;
|
|
|
|
return rates.accommodation * numberOfNights;
|
|
}
|
|
|
|
// Get meal breakdown for a city
|
|
function getMealBreakdown(cityName) {
|
|
const rates = getCityRates(cityName);
|
|
if (!rates) return null;
|
|
|
|
return {
|
|
breakfast: rates.perDiem * MEAL_BREAKDOWN.breakfast,
|
|
lunch: rates.perDiem * MEAL_BREAKDOWN.lunch,
|
|
dinner: rates.perDiem * MEAL_BREAKDOWN.dinner,
|
|
incidentals: rates.perDiem * MEAL_BREAKDOWN.incidentals,
|
|
total: rates.perDiem
|
|
};
|
|
}
|
|
|
|
// Export for use in other modules
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = {
|
|
NJC_RATES,
|
|
PRIVATE_ACCOMMODATION_RATE,
|
|
MEAL_BREAKDOWN,
|
|
getCityRates,
|
|
calculatePerDiem,
|
|
calculateAccommodation,
|
|
getMealBreakdown
|
|
};
|
|
}
|