Smart Invoice Due Date Calculator

Smart Invoice Due Date Calculator

Calculate payment due dates based on your business rules.

${daysRemainingText}

Issue Date: ${formatDate(new Date(appData.inputs.issueDate + 'T00:00:00Z'))}
Terms: ${appData.inputs.paymentTerm === 'custom' ? `${appData.inputs.customDays} days` : `Net ${appData.inputs.paymentTerm.replace('net', '')}`}
Adjustment: ${adjustmentApplied}
`; attachCalculatorListeners(); }; const renderHolidayConfig = () => { const configContent = document.getElementById('content-holiday-config'); if (!configContent) return; const holidaysByYear = appData.config.holidays.reduce((acc, holiday) => { const year = holiday.date.substring(0, 4); if (!acc[year]) acc[year] = []; acc[year].push(holiday); return acc; }, {}); let holidaysHtml = Object.keys(holidaysByYear).sort().map(year => { const yearHtml = holidaysByYear[year].map((h, i) => `
${h.date}
`).join(''); return `

${year}

${yearHtml}
`; }).join(''); configContent.innerHTML = `

Manage Public Holidays

Holidays are used to adjust due dates that fall on a non-business day.
${holidaysHtml}

Add New Holiday

`; lucide.createIcons(); attachConfigListeners(); }; // --- EVENT HANDLERS --- const attachCalculatorListeners = () => { const updateAndRecalculate = () => { appData.inputs.issueDate = document.getElementById('issue-date').value; appData.inputs.paymentTerm = document.getElementById('payment-term').value; appData.inputs.customDays = document.getElementById('custom-days').value; appData.inputs.weekendRule = document.querySelector('input[name="weekend-rule"]:checked').value; calculateDueDate(); renderCalculator(); }; document.getElementById('issue-date').addEventListener('change', updateAndRecalculate); document.getElementById('payment-term').addEventListener('change', (e) => { document.getElementById('custom-days').classList.toggle('hidden', e.target.value !== 'custom'); updateAndRecalculate(); }); document.getElementById('custom-days').addEventListener('input', updateAndRecalculate); document.querySelectorAll('input[name="weekend-rule"]').forEach(radio => radio.addEventListener('change', updateAndRecalculate)); document.getElementById('download-pdf-btn').addEventListener('click', generatePdf); }; const attachConfigListeners = () => { document.getElementById('add-holiday-btn').addEventListener('click', () => { const dateInput = document.getElementById('new-holiday-date'); const nameInput = document.getElementById('new-holiday-name'); if (dateInput.value && nameInput.value) { if (!appData.config.holidays.some(h => h.date === dateInput.value)) { appData.config.holidays.push({ date: dateInput.value, name: nameInput.value }); appData.config.holidays.sort((a,b) => new Date(a.date) - new Date(b.date)); renderHolidayConfig(); calculateDueDate(); // Recalculate as holidays changed } else { alert('This date is already in the holiday list.'); } } }); document.querySelectorAll('.remove-holiday-btn').forEach(btn => btn.addEventListener('click', e => { const dateToRemove = e.currentTarget.dataset.date; appData.config.holidays = appData.config.holidays.filter(h => h.date !== dateToRemove); renderHolidayConfig(); calculateDueDate(); })); document.querySelectorAll('.holiday-name-input').forEach(input => input.addEventListener('change', e => { const dateToUpdate = e.target.dataset.date; const holiday = appData.config.holidays.find(h => h.date === dateToUpdate); if(holiday) holiday.name = e.target.value; })); }; const generatePdf = () => { loadingOverlay.style.display = 'flex'; const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content-area'); const pdfHeader = document.getElementById('pdf-header'); document.getElementById('pdf-generated-date').textContent = new Date().toLocaleDateString('en-US'); pdfHeader.classList.remove('hidden'); html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false }) .then(canvas => { pdfHeader.classList.add('hidden'); const imgData = canvas.toDataURL('image/jpeg', 0.95); const pdf = new jsPDF({ orientation: 'portrait', unit: 'px', format: [canvas.width * 0.5, canvas.height * 0.5] }); pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width * 0.5, canvas.height * 0.5); pdf.save('Invoice-DueDate-Report.pdf'); loadingOverlay.style.display = 'none'; }).catch(err => { console.error("PDF generation failed:", err); pdfHeader.classList.add('hidden'); loadingOverlay.style.display = 'none'; alert('An error occurred generating the PDF.'); }); }; // --- TAB NAVIGATION & INITIALIZATION --- const switchTab = (tabIndex) => { activeTabIndex = tabIndex; document.querySelectorAll('.tab-btn').forEach((btn, i) => btn.classList.toggle('active', i === tabIndex)); document.querySelectorAll('.tab-content').forEach((content, i) => content.classList.toggle('hidden', i !== tabIndex)); updateNavButtons(); }; const updateNavButtons = () => { prevTabBtn.disabled = activeTabIndex === 0; nextTabBtn.disabled = activeTabIndex === tabIdentifiers.length - 1; }; const initializeUI = () => { const tabs = [ { name: 'Due Date Calculator', id: 'calculator' }, { name: 'Holiday Configuration', id: 'holiday-config' } ]; tabIdentifiers = tabs.map(t => t.id); tabsContainer.innerHTML = tabs.map(tab => ``).join(''); mainContent.innerHTML = tabs.map(tab => `
`).join(''); tabs.forEach((tab, index) => { document.getElementById(`tab-${tab.id}`).addEventListener('click', () => switchTab(index)); }); renderCalculator(); renderHolidayConfig(); switchTab(0); }; initializeUI(); prevTabBtn.addEventListener('click', () => { if (activeTabIndex > 0) switchTab(activeTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (activeTabIndex < tabIdentifiers.length - 1) switchTab(activeTabIndex + 1); }); });
Scroll to Top