diff --git a/app/src/app.js b/app/src/app.js index 0da4b43..a7121cd 100644 --- a/app/src/app.js +++ b/app/src/app.js @@ -480,6 +480,20 @@ app.delete('/api/invoices', requireAuth, async (req, res, next) => { }); const pdfText = (value) => String(value || 'Neuvedeno'); +const formatCzechDate = (value) => { + const date = new Date(`${value}T00:00:00`); + return Number.isNaN(date.getTime()) ? '' : date.toLocaleDateString('cs-CZ'); +}; +const toDateInputValue = (date) => date.toISOString().slice(0, 10); +const resolveIssueDate = (issueDate) => issueDate || toDateInputValue(new Date()); +const resolveDueDate = (dueDate, issueDate) => { + if (dueDate) { + return dueDate; + } + const due = new Date(`${resolveIssueDate(issueDate)}T00:00:00`); + due.setDate(due.getDate() + 14); + return toDateInputValue(due); +}; const formatCzechNumber = (value) => Number(value || 0).toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 @@ -554,13 +568,25 @@ const renderInvoicePdf = async (document, invoice) => { const partyWidth = (pageWidth - 24) / 2; const customerX = document.page.margins.left + partyWidth + 24; + const issueDate = resolveIssueDate(data.issueDate); + const dueDate = resolveDueDate(data.dueDate, data.issueDate); + const headerY = document.y; document.fillColor(navy).font(boldFont).fontSize(25).text('Faktura', document.page.margins.left, headerY); document.fillColor(navy).font(boldFont).fontSize(16).text(invoice.invoice_number, customerX, headerY, { width: partyWidth, align: 'right' }); - document.y = headerY + 40; + document.fillColor(bodyText).font(regularFont).fontSize(9) + .text(`Datum vystavení: ${formatCzechDate(issueDate)}`, customerX, headerY + 22, { + width: partyWidth, + align: 'right' + }) + .text(`Datum splatnosti: ${formatCzechDate(dueDate)}`, customerX, headerY + 35, { + width: partyWidth, + align: 'right' + }); + document.y = headerY + 52; const partyTop = document.y; const drawParty = (x, title, profile, name) => { diff --git a/app/src/static/index.html b/app/src/static/index.html index d7ab60d..7f9c63e 100644 --- a/app/src/static/index.html +++ b/app/src/static/index.html @@ -325,13 +325,13 @@
- - + + +
+
+ +
-
diff --git a/app/src/static/script.js b/app/src/static/script.js index d45cc68..241f0b3 100644 --- a/app/src/static/script.js +++ b/app/src/static/script.js @@ -46,8 +46,8 @@ const invoiceStartingNumberInput = document.getElementById("invoiceStartingNumbe const saveNumberingSettingsButton = document.getElementById("saveNumberingSettingsButton"); const cancelNumberingSettingsButton = document.getElementById("cancelNumberingSettingsButton"); const numberingSettingsStatus = document.getElementById("numberingSettingsStatus"); -const dueDateOption = document.getElementById("dueDateOption"); -const dueDateDisplay = document.getElementById("dueDateDisplay"); +const issueDateInput = document.getElementById("issueDate"); +const dueDateInput = document.getElementById("dueDate"); const paymentPresetSelect = document.getElementById("paymentPresetSelect"); const paymentPresetName = document.getElementById("paymentPresetName"); const savePaymentPresetButton = document.getElementById("savePaymentPresetButton"); @@ -207,17 +207,17 @@ const getClientLabel = (client) => [ const formatCzechDate = (dateValue) => new Date(`${dateValue}T00:00:00`).toLocaleDateString("cs-CZ"); -const getDueDays = () => Number.parseInt(dueDateOption.value, 10) || 14; +const toDateInputValue = (date) => date.toISOString().slice(0, 10); + +const getIssueDate = () => issueDateInput.value || toDateInputValue(new Date()); const getDueDate = () => { - const dueDate = new Date(); - dueDate.setHours(0, 0, 0, 0); - dueDate.setDate(dueDate.getDate() + getDueDays()); - return dueDate.toISOString().slice(0, 10); -}; - -const updateDueDate = () => { - dueDateDisplay.textContent = `Splatnost: ${formatCzechDate(getDueDate())}`; + if (dueDateInput.value) { + return dueDateInput.value; + } + const dueDate = new Date(`${getIssueDate()}T00:00:00`); + dueDate.setDate(dueDate.getDate() + 14); + return toDateInputValue(dueDate); }; const updateClientTypeFields = () => { @@ -333,6 +333,8 @@ deletePaymentPresetButton.addEventListener("click", async () => { }); const readInvoiceData = () => ({ + issueDate: getIssueDate(), + dueDate: getDueDate(), supplier: { ...readProfileFields("dodavatel"), typSubjektu: supplierTypeSelect.value @@ -363,6 +365,8 @@ const clearInvoiceEditor = () => { currentInvoiceId = null; invoiceNumberDisplay.textContent = "Nová faktura"; invoiceSaveStatus.textContent = ""; + issueDateInput.value = ""; + dueDateInput.value = ""; writeProfileFields("odberatel", {}); clientSelect.value = ""; clientTypeSelect.value = "osoba"; @@ -384,6 +388,8 @@ const loadInvoiceIntoEditor = (invoice) => { currentInvoiceId = invoice.id; invoiceNumberDisplay.textContent = invoice.invoiceNumber; invoiceSaveStatus.textContent = ""; + issueDateInput.value = invoice.data.issueDate || ""; + dueDateInput.value = invoice.data.dueDate || ""; writeProfileFields("dodavatel", invoice.data.supplier || {}); supplierTypeSelect.value = invoice.data.supplier?.typSubjektu || "osoba"; updateSupplierTypeFields();