126 lines
3.4 KiB
JavaScript
126 lines
3.4 KiB
JavaScript
(function(global) {
|
|
'use strict';
|
|
|
|
const DEFAULTS = {
|
|
RATE_M365: 130,
|
|
RATE_M365_M2M: 140,
|
|
RATE_BYOL: 110,
|
|
M365_RETAIL_MONTHLY: 35,
|
|
M365_RETAIL_ANNUAL: 30,
|
|
ADDON_EXT_HOURS: 25,
|
|
ADDON_1PASSWORD: 9,
|
|
ADDON_INKY: 8,
|
|
ADDON_ZERO_TRUST_USER: 55,
|
|
RATE_ENDPOINT: 35,
|
|
RATE_SERVER: 120,
|
|
ADDON_USB_BLOCKING: 4,
|
|
ADDON_BARE_METAL_BACKUP: 25,
|
|
ZT_SEAT_RATE: 25,
|
|
ZT_ROUTER_RATE: 100,
|
|
ADMIN_FEE_FLOOR: 150,
|
|
ADMIN_FEE_MINIMUM: 650,
|
|
ADMIN_FEE_ZT: 250,
|
|
ADMIN_1PWM_PCT: 0.10,
|
|
VOIP_RATE_BASIC: 28,
|
|
VOIP_RATE_STANDARD: 35,
|
|
VOIP_RATE_PREMIUM: 45,
|
|
VOIP_PHONE_RATE: 15,
|
|
VOIP_FAX_RATE: 10,
|
|
TOOL_COST_PER_USER: 42,
|
|
TOOL_COST_PER_ENDPOINT: 23,
|
|
TOOL_COST_MIN: 650,
|
|
IT_SALARY_1: 85000,
|
|
IT_SALARY_5: 420000,
|
|
DISCOUNT_M2M: 0,
|
|
DISCOUNT_12MO: 0.03,
|
|
DISCOUNT_24MO: 0.05,
|
|
HST_RATE: 0.13
|
|
};
|
|
|
|
const KNOWN_KEYS = Object.keys(DEFAULTS);
|
|
let pricingFallbackShown = false;
|
|
|
|
function applyValues(values) {
|
|
KNOWN_KEYS.forEach(key => {
|
|
global[key] = values[key];
|
|
});
|
|
}
|
|
|
|
function getSnapshot() {
|
|
return KNOWN_KEYS.reduce((snapshot, key) => {
|
|
snapshot[key] = global[key];
|
|
return snapshot;
|
|
}, {});
|
|
}
|
|
|
|
function showPricingStatus(message) {
|
|
const host = document.querySelector('.top-bar-right');
|
|
if (!host) return;
|
|
let el = document.getElementById('pricingStatus');
|
|
if (!el) {
|
|
el = document.createElement('div');
|
|
el.id = 'pricingStatus';
|
|
el.style.marginTop = '6px';
|
|
el.style.fontSize = '11px';
|
|
el.style.letterSpacing = '0.02em';
|
|
el.style.color = 'var(--amber)';
|
|
host.appendChild(el);
|
|
}
|
|
el.textContent = message;
|
|
}
|
|
|
|
function reportPricingFallback(reason) {
|
|
if (pricingFallbackShown) return;
|
|
pricingFallbackShown = true;
|
|
console.warn(`[SVS Quote] ${reason} Using built-in pricing defaults.`);
|
|
showPricingStatus('Pricing file unavailable - using built-in defaults');
|
|
}
|
|
|
|
function applyPricingData(data) {
|
|
let applied = 0;
|
|
Object.keys(data).forEach(category => {
|
|
const group = data[category];
|
|
if (typeof group !== 'object' || group === null) return;
|
|
Object.keys(group).forEach(key => {
|
|
const entry = group[key];
|
|
if (typeof entry !== 'object' || entry === null) return;
|
|
const val = parseFloat(entry.value);
|
|
if (!KNOWN_KEYS.includes(key) || Number.isNaN(val)) return;
|
|
global[key] = val;
|
|
applied++;
|
|
});
|
|
});
|
|
return applied;
|
|
}
|
|
|
|
async function loadPricing() {
|
|
pricingFallbackShown = false;
|
|
applyValues(DEFAULTS);
|
|
|
|
// Pricing loaded via <script src="package-prices-data.js"> which sets window.SVS_PRICING_DATA
|
|
if (global.SVS_PRICING_DATA && typeof global.SVS_PRICING_DATA === 'object') {
|
|
const applied = applyPricingData(global.SVS_PRICING_DATA);
|
|
if (applied > 0) return true;
|
|
}
|
|
|
|
reportPricingFallback('package-prices-data.js not loaded.');
|
|
return false;
|
|
}
|
|
|
|
applyValues(DEFAULTS);
|
|
|
|
global.SVSQuotePricing = {
|
|
DEFAULTS: Object.freeze({ ...DEFAULTS }),
|
|
KNOWN_KEYS: Object.freeze([...KNOWN_KEYS]),
|
|
getSnapshot,
|
|
loadPricing,
|
|
reportPricingFallback,
|
|
showPricingStatus
|
|
};
|
|
|
|
// Backward-compatible globals for the current calculator runtime.
|
|
global.loadPricing = loadPricing;
|
|
global.reportPricingFallback = reportPricingFallback;
|
|
global.showPricingStatus = showPricingStatus;
|
|
})(window);
|