Inventory Management Cost Tracker
Setup Information
Enter all subsequent costs based on this defined tracking period.
Holding Costs (Carrying Costs)
Ordering Costs
Shortage Costs (Stockout Costs)
Cost Summary
Please enter costs in the respective tabs. The summary will be calculated here.
Error: Tool UI elements missing.
"; return; } imcOpenTab(null, imcTabContents[0].id); imcUpdateNavButtons(); }); function imcOpenTab(event, tabId) { let targetButton = null; imcTabContents.forEach(tc => { tc.style.display = "none"; tc.classList.remove('imc-active'); }); imcTabButtons.forEach((btn, index) => { btn.classList.remove('imc-active'); if (btn.getAttribute('onclick').includes(tabId)) { targetButton = btn; imcCurrentTabIndex = index;} }); const targetTab = document.getElementById(tabId); if (targetTab) { targetTab.style.display = "block"; targetTab.classList.add('imc-active');} if (event && event.currentTarget) event.currentTarget.classList.add('imc-active'); else if (targetButton) targetButton.classList.add('imc-active'); imcUpdateNavButtons(); if (tabId === 'imcTabSummary' && typeof imcCalculateAndDisplay === 'function') imcCalculateAndDisplay(); } function imcNavigateTab(direction) { let newIdx = imcCurrentTabIndex; if (direction === 'next') newIdx = (imcCurrentTabIndex + 1) % imcTabButtons.length; else if (direction === 'prev') newIdx = (imcCurrentTabIndex - 1 + imcTabButtons.length) % imcTabButtons.length; const targetTabId = imcTabContents[newIdx].id; imcOpenTab({currentTarget: imcTabButtons[newIdx]}, targetTabId); } function imcUpdateNavButtons() { if (!imcPrevButton || !imcNextButton || imcTabButtons.length === 0) return; imcPrevButton.disabled = (imcCurrentTabIndex === 0); imcNextButton.disabled = (imcCurrentTabIndex === imcTabButtons.length - 1); } function imcGetNum(id) { const el = imcAllInputElements[id]; if (!el) return 0; const val = parseFloat(el.value); return isNaN(val) || val < 0 ? 0 : val; } function imcFormat(value) { return `$${value.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; } function imcCalculateCosts() { const businessName = imcBusinessNameElem.value || "Your Business"; const periodName = imcPeriodNameElem.value || "Selected Period"; let totalHolding = 0; imcHoldingCostIds.forEach(id => totalHolding += imcGetNum(id)); let totalOrdering = 0; imcOrderingCostIds.forEach(id => totalOrdering += imcGetNum(id)); let totalShortage = 0; imcShortageCostIds.forEach(id => totalShortage += imcGetNum(id)); const grandTotal = totalHolding + totalOrdering + totalShortage; const holdingPercent = grandTotal > 0 ? (totalHolding / grandTotal) * 100 : 0; const orderingPercent = grandTotal > 0 ? (totalOrdering / grandTotal) * 100 : 0; const shortagePercent = grandTotal > 0 ? (totalShortage / grandTotal) * 100 : 0; return { businessName, periodName, totalHolding, totalOrdering, totalShortage, grandTotal, holdingPercent, orderingPercent, shortagePercent }; } function imcCalculateAndDisplay() { if (!imcSummaryOutputDiv || !imcDownloadPdfButtonElem) return; const results = imcCalculateCosts(); imcSummaryOutputDiv.innerHTML = `Cost Summary for ${results.businessName} (${results.periodName})
Total Holding Costs: ${imcFormat(results.totalHolding)}
Total Ordering Costs: ${imcFormat(results.totalOrdering)}
Total Shortage Costs: ${imcFormat(results.totalShortage)}
Grand Total Inventory Costs: ${imcFormat(results.grandTotal)}
Cost Category Percentages:
Holding Costs: ${results.holdingPercent.toFixed(1)}%
Ordering Costs: ${results.orderingPercent.toFixed(1)}%
Shortage Costs: ${results.shortagePercent.toFixed(1)}%
Inventory Cost Details for ${results.businessName} (${results.periodName})
`; inputsHTML += `Holding Costs:
`; imcHoldingCostIds.forEach(id => { const label = document.querySelector(`label[for='${id}']`).childNodes[0].textContent.trim(); inputsHTML += `${label} ${imcFormat(imcGetNum(id))}
`;
});
inputsHTML += `Total Holding Costs: ${imcFormat(results.totalHolding)}
`;
inputsHTML += `Ordering Costs:
`; imcOrderingCostIds.forEach(id => { const label = document.querySelector(`label[for='${id}']`).childNodes[0].textContent.trim(); inputsHTML += `${label} ${imcFormat(imcGetNum(id))}
`;
});
inputsHTML += `Total Ordering Costs: ${imcFormat(results.totalOrdering)}
`;
inputsHTML += `Shortage Costs:
`; imcShortageCostIds.forEach(id => { const label = document.querySelector(`label[for='${id}']`).childNodes[0].textContent.trim(); inputsHTML += `${label} ${imcFormat(imcGetNum(id))}
`;
});
inputsHTML += `Total Shortage Costs: ${imcFormat(results.totalShortage)}
`;
inputsHTML += `Grand Total & Percentages:
`; inputsHTML += `Grand Total Inventory Costs: ${imcFormat(results.grandTotal)}
`;
inputsHTML += `Holding Cost %: ${results.holdingPercent.toFixed(1)}%
`;
inputsHTML += `Ordering Cost %: ${results.orderingPercent.toFixed(1)}%
`;
inputsHTML += `Shortage Cost %: ${results.shortagePercent.toFixed(1)}%
`;
pdfContentWrapper.innerHTML = `
Inventory Management Cost Report
${inputsHTML}Report generated on: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}
`; document.body.appendChild(pdfContentWrapper); try { const canvas = await html2canvas(pdfContentWrapper, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgProps = pdf.getImageProperties(imgData); const ratio = Math.min((pdfWidth - 40) / imgProps.width, (pdfHeight - 40) / imgProps.height); pdf.addImage(imgData, 'PNG', (pdfWidth - imgProps.width * ratio) / 2, 20, imgProps.width * ratio, imgProps.height * ratio); pdf.save('Inventory_Cost_Report.pdf'); } catch (error) { console.error("Error during PDF generation:", error); alert("An error occurred while generating the PDF."); } finally { document.body.removeChild(pdfContentWrapper); } }