Medium Risk Items
${currentData.mediumRiskCount}
Forecast Period
${currentData.weeks} Weeks
Stockout Risk Summary
| Product | Supplier | Est. Stockout | Status |
${forecastTableRows}
`;
const ctx = getElem('forecastChart').getContext('2d');
const labels = Array.from({ length: currentData.weeks + 1 }, (_, i) => `W${i}`);
const chartData = {
labels,
datasets: currentData.results.slice(0, 4).map((p, i) => {
const colors = ['#3B82F6', '#16A34A', '#F97316', '#9333EA'];
return {
label: p.name,
data: p.history,
borderColor: colors[i % colors.length],
tension: 0.1,
fill: false
};
})
};
if (forecastChart) forecastChart.destroy();
forecastChart = new Chart(ctx, { type: 'line', data: chartData, options: { responsive: true, maintainAspectRatio: false } });
downloadSection.classList.remove('hidden');
showTab(1);
};
generateBtn.addEventListener('click', generateForecast);
// --- PDF DOWNLOAD ---
const downloadPDF = () => {
if (!currentData || !forecastChart) return;
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' });
const btnText = getElem('pdf-btn-text');
const btnSpinner = getElem('pdf-btn-spinner');
btnText.classList.add('hidden');
btnSpinner.classList.remove('hidden');
downloadPdfBtn.disabled = true;
try {
const pageWidth = pdf.internal.pageSize.getWidth();
const margin = 40;
let y = margin;
pdf.setFont('helvetica', 'bold');
pdf.setFontSize(22);
pdf.text("Inventory Forecast Report", pageWidth / 2, y, { align: 'center' });
y += 15;
pdf.setFont('helvetica', 'normal');
pdf.setFontSize(10);
pdf.text(`Forecast Period: ${currentData.weeks} Weeks | Report Date: ${today.toLocaleDateString('en-US')}`, pageWidth / 2, y, { align: 'center' });
y += 35;
pdf.autoTable({
startY: y,
theme: 'grid',
head: [['Metric', 'Value']],
body: [
['High Risk Items (Stockout in <2 wks)', `${currentData.highRiskCount}`],
['Medium Risk Items (Stockout in <4 wks)', `${currentData.mediumRiskCount}`],
],
didDrawPage: (data) => { y = data.cursor.y; }
});
y += 20;
pdf.setFont('helvetica', 'bold');
pdf.text("Forecast Summary", margin, y);
y += 15;
const tableData = currentData.results.map(p => [p.name, p.supplier, p.stockoutWeek !== -1 ? `Week ${p.stockoutWeek}` : 'None', p.risk]);
pdf.autoTable({
startY: y,
head: [['Product Name', 'Supplier', 'Estimated Stockout', 'Risk Level']],
body: tableData,
theme: 'striped',
headStyles: { fillColor: [29, 78, 216] },
didParseCell: function (data) {
if (data.section === 'body' && data.column.index === 3) {
if (data.cell.raw === 'High') data.cell.styles.textColor = '#DC2626';
if (data.cell.raw === 'Medium') data.cell.styles.textColor = '#D97706';
}
},
});
pdf.save(`Inventory-Forecast-Report.pdf`);
} catch(e) { console.error("PDF Generation failed:", e); }
finally {
btnText.classList.remove('hidden');
btnSpinner.classList.remove('hidden');
downloadPdfBtn.disabled = false;
}
};
downloadPdfBtn.addEventListener('click', downloadPDF);
initialize();
});