mirror of
https://github.com/mblanke/Gov_Travel_App.git
synced 2026-03-01 14:10:22 -05:00
Add complete Government Travel Cost Estimator web application
Co-authored-by: mblanke <9078342+mblanke@users.noreply.github.com>
This commit is contained in:
159
njcRates.js
Normal file
159
njcRates.js
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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-Rivieres": { 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user