Files
svsmspcalc/quote-pricing.js
2026-03-15 18:24:36 -04:00

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);