🧮GM Calculator
Revenue:
Cost:
Contingency %:
📈Revenue Projection
Cost:
Contingency %:
GM %:
💰Costing Calculator
Revenue:
GM %:
⏱Effort Estimator
Units (off = Hours, on = PD):
Dev + UT Effort (Y):
Dev+UT as % of Total:
1 PD = hours
Phase Percentages (excluding Dev+UT)
Requirements %
Design %
Testing %
UAT %
Hypercare %
📅Schedule Generator
Developers:
Dev Boost %:
Testers:
Tester Boost %:
GM: ” + gm.toFixed(2) + “%”; } /* Revenue projection */ function revCalc(){ const cost = +revCost.value; const contPct = (+revCont.value || 0) / 100; const gmPct = +revGM.value; if (!cost || gmPct = 100) { revResult.innerHTML = “Invalid inputs”; return; } const finalCost = cost * (1 + contPct); const gm = gmPct / 100; const rev = finalCost / (1 – gm); revResult.innerHTML = “Final Cost: ” + finalCost.toFixed(2) + “
Revenue: ” + rev.toFixed(2); } /* Cost reverse calc */ function costCalc(){ const rev = +costRevenue.value; const gmPct = +costGM.value; if (!rev || gmPct = 100) { costResult.innerHTML = “Invalid inputs”; return; } const max = rev * (1 – gmPct / 100); costResult.innerHTML = “Max Cost: ” + max.toFixed(2); } /* Effort estimator with phase % auto-balance */ function effCalc(){ const Y = +devValue.value; const xPct = +devPct.value; const x = xPct / 100; const hpd = +hoursPerDay.value || 8; let reqP = +pReq.value || 0; let desP = +pDes.value || 0; let testP = +pTest.value || 0; let uatP = +pUAT.value || 0; let hcP = +pHC.value || 0; effortResult.innerHTML = “”; pctWarn.innerHTML = “”; if (!Y || !x || x = 1) { effortResult.innerHTML = “Enter valid Dev+UT effort and Dev% (0–100).”; return; } const remainingAllowed = 100 – xPct; if (remainingAllowed 0) { if (remainingSum 0.01) { const scale = remainingAllowed / remainingSum; reqP *= scale; desP *= scale; testP *= scale; uatP *= scale; hcP *= scale; autoAdjusted = true; } } else { // remainingAllowed = 0 → all effort is Dev reqP = desP = testP = uatP = hcP = 0; autoAdjusted = true; } if (autoAdjusted) { pReq.value = reqP.toFixed(1); pDes.value = desP.toFixed(1); pTest.value = testP.toFixed(1); pUAT.value = uatP.toFixed(1); pHC.value = hcP.toFixed(1); pctWarn.innerHTML = “Phase % auto-balanced to ” + remainingAllowed.toFixed(1) + “% (remaining after Dev).”; } const hrsDevPlus = isPD ? Y * hpd : Y; const totalHrs = hrsDevPlus / x; const hrsReq = totalHrs * (reqP / 100); const hrsDes = totalHrs * (desP / 100); const hrsTest = totalHrs * (testP / 100); const hrsUAT = totalHrs * (uatP / 100); const hrsHC = totalHrs * (hcP / 100); const hrsDev = totalHrs * x; // dev portion const daysReq = hrsReq / hpd; const daysDes = hrsDes / hpd; const daysDev = hrsDev / hpd; const daysTest = hrsTest / hpd; const daysUAT = hrsUAT / hpd; const daysHC = hrsHC / hpd; window.pmEffort = { req: daysReq, des: daysDes, dev: daysDev, test: daysTest, uat: daysUAT, hc: daysHC }; function fmt(h){ return isPD ? (h / hpd).toFixed(2) + ” PD” : h.toFixed(1) + ” hrs”; } effortResult.innerHTML = “Total Effort: ” + fmt(totalHrs) + “
” + “Requirements: ” + fmt(hrsReq) + “
” + “Design: ” + fmt(hrsDes) + “
” + “Development: ” + fmt(hrsDev) + “
” + “Testing: ” + fmt(hrsTest) + “
” + “UAT: ” + fmt(hrsUAT) + “
” + “Hypercare: ” + fmt(hrsHC); scheduleGrid.innerHTML = “”; totalWeeksLabel.innerHTML = “”; window.pmSchedule = null; } /* Schedule generator with Dev & Tester boosts */ function generateSchedule(){ if (!window.pmEffort) { scheduleGrid.innerHTML = “Run Effort Estimator first.”; return; } const d = window.pmEffort; // FIX: always use getElementById const devCnt = Math.max(1, +(document.getElementById(“devCount”).value) || 1); const devBoostPct = +(document.getElementById(“devBoost”).value) || 0; const devBoost = devBoostPct / 100; const testerCnt = Math.max(1, +(document.getElementById(“testerCount”).value) || 1); const testerBoostPct = +(document.getElementById(“testerBoost”).value) || 0; const testerBoost = testerBoostPct / 100; const reqDays0 = d.req || 0; const desDays0 = d.des || 0; const devDays0 = d.dev || 0; const testDays0 = d.test || 0; const uatDays0 = d.uat || 0; const hcDays0 = d.hc || 0; // Apply developer boost to Design & Dev const devFactor = 1 + (devCnt – 1) * devBoost; const adjDes = devFactor > 0 ? desDays0 / devFactor : desDays0; const adjDev = devFactor > 0 ? devDays0 / devFactor : devDays0; // Apply tester boost to Testing const testFactor = 1 + (testerCnt – 1) * testerBoost; const adjTest = testFactor > 0 ? testDays0 / testFactor : testDays0; const totalDays = reqDays0 + adjDes + adjDev + adjTest + uatDays0 + hcDays0; const weeks = Math.max(1, Math.ceil(totalDays / 5)); totalWeeksLabel.innerHTML = “Total Project Weeks: ” + weeks; const phases = [ [“Requirements”, reqDays0], [“Design”, adjDes], [“Development”, adjDev], [“Testing”, adjTest], [“UAT”, uatDays0], [“Hypercare”, hcDays0] ]; let html = “
| Phase | “; for (let i = 1; i <= weeks; i++) html += "W” + i + “ | “; html += “|
|---|---|---|
| ” + name + “ | “; for (let w = 0; w 0 && start wkStart; cells.push(fill ? 1 : 0); html += fill ? “” : “ | “; } html += “ |