From bdb2cb28a382d37f18db7a1121d0655bdf1489be Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 08:42:39 +0000 Subject: [PATCH] Add Registration no. field to charge-to section - Add reg-no key to charge-to entries in config.yml - Add registration-no translation key (en/de/fr/no) - Add Registration no. input below VAT ID in the charge-to form - fillChargeTo() populates and clears creg; field locks when predefined recipient is selected - relabel() maps lbl-creg to registration-no translation - gatherData() collects ctReg; buildPreviewHTML() and buildPDF() display it in the bill-to block https://claude.ai/code/session_015iyCBgoTXNNqaErR287U1u --- app/config.yml | 7 ++++++ app/index.html | 60 +++++++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/app/config.yml b/app/config.yml index 3b91aff..38e6132 100644 --- a/app/config.yml +++ b/app/config.yml @@ -112,6 +112,7 @@ charge-to: phone: "+1-212-555-0100" email: accounts@acmecorp.example vat-id: "US-EIN-12-3456789" + reg-no: "" currency: USD - display: Example NGO name: Example Non-Profit Organisation @@ -123,6 +124,7 @@ charge-to: phone: "+44 20 7123 4567" email: finance@examplengo.example vat-id: "GB123456789" + reg-no: "01234567" currency: GBP # ── Project codes ────────────────────────────────────────────────────────────── @@ -288,6 +290,11 @@ translations: de: USt-IdNr. fr: "N° TVA / ID fiscal" "no": MVA-nummer + registration-no: + en: "Registration no." + de: "Handelsreg.-Nr." + fr: "N° d'enregistrement" + "no": "Organisasjonsnr." invoice-date: en: Invoice date de: Rechnungsdatum diff --git a/app/index.html b/app/index.html index e691181..cac1a29 100644 --- a/app/index.html +++ b/app/index.html @@ -516,29 +516,27 @@ function buildForm() { -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -604,7 +602,7 @@ function fillChargeTo(v) { const fields = document.getElementById("ct-fields"); if (v === "" || v === "__other__") { - if (v === "") ["ctn","ca1","ca2","ca3","ca4","cc","cph","cem","cvat"].forEach(id => f(id, "")); + if (v === "") ["ctn","ca1","ca2","ca3","ca4","cc","cph","cem","cvat","creg"].forEach(id => f(id, "")); fields?.classList.remove("locked"); return; } @@ -614,7 +612,7 @@ function fillChargeTo(v) { f("ca2", ct.address2); f("ca3", ct.address3); f("ca4", ct.address4); f("cc", ct.country); f("cph", ct.phone); f("cem", ct.email); - f("cvat", ct["vat-id"]); + f("cvat", ct["vat-id"]); f("creg", ct["reg-no"]); fields?.classList.add("locked"); // Auto-set invoice currency from recipient config @@ -886,7 +884,7 @@ function relabel() { "lbl-idate":"invoice-date","lbl-icur":"invoice-currency","lbl-pcode":"project-code","lbl-ino":"invoice-no", "lbl-ctn":"charge-to-name","lbl-ca1":"charge-to-address1","lbl-ca2":"charge-to-address2", "lbl-ca3":"charge-to-address3","lbl-ca4":"charge-to-address4","lbl-cc":"charge-to-country", - "lbl-cph":"charge-to-phone","lbl-cem":"charge-to-email","lbl-cvat":"vat-id", + "lbl-cph":"charge-to-phone","lbl-cem":"charge-to-email","lbl-cvat":"vat-id","lbl-creg":"registration-no", "th-qty":"qty","th-uom":"uom","th-desc":"description","th-price":"price","th-tot":"line-total", "lbl-sub":"subtotal","lbl-paid":"paid","lbl-topay":"to-pay", }; @@ -980,7 +978,7 @@ function gatherData(renderLang) { const ctName = g("ctn"); const ctAddr = [g("ca1"),g("ca2"),g("ca3"),g("ca4")].filter(Boolean); const ctCntry= COUNTRY_MAP[g("cc")] || ""; - const ctPh = g("cph"), ctEm = g("cem"), ctVat = g("cvat"); + const ctPh = g("cph"), ctEm = g("cem"), ctVat = g("cvat"), ctReg = g("creg"); let sub = 0; const rows = []; @@ -1034,14 +1032,14 @@ function gatherData(renderLang) { const toPay = sub + totalTax - paid; return { dl, td, sName, sAddr, sCntry, sPh, sEm, iDate, pCode, iNo, iCur, - ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, + ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, ctReg, rows, sub, taxes, totalTax, paid, toPay }; } // ── Build HTML preview ──────────────────────────────────────────────────────── function buildPreviewHTML() { const { td, sName, sAddr, sCntry, sPh, sEm, iDate, pCode, iNo, iCur, - ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, + ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, ctReg, rows, sub, taxes, paid, toPay } = gatherData(); const linesHTML = rows.map(row => { @@ -1089,6 +1087,7 @@ function buildPreviewHTML() { ${ctPh ? `${h(td("charge-to-phone"))}: ${h(ctPh)}` : ""} ${ctEm ? `${h(td("charge-to-email"))}: ${h(ctEm)}` : ""} ${ctVat ? `${h(td("vat-id"))}: ${h(ctVat)}` : ""} + ${ctReg ? `${h(td("registration-no"))}: ${h(ctReg)}` : ""} ` : ""} @@ -1143,7 +1142,7 @@ function buildPDF() { const sp = (s,w) => doc.splitTextToSize(String(s??""), w); const { dl, td, sName, sAddr, sCntry, sPh, sEm, iDate, pCode, iNo, iCur, - ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, + ctName, ctAddr, ctCntry, ctPh, ctEm, ctVat, ctReg, rows, sub, taxes, paid, toPay } = gatherData(); // ── HEADER ──────────────────────────────────────────────────────────────── @@ -1199,6 +1198,7 @@ function buildPDF() { if (ctPh) ctParts.push(`${td("charge-to-phone")}: ${ctPh}`); if (ctEm) ctParts.push(`${td("charge-to-email")}: ${ctEm}`); if (ctVat) ctParts.push(`${td("vat-id")}: ${ctVat}`); + if (ctReg) ctParts.push(`${td("registration-no")}: ${ctReg}`); const ctContact = ctParts.join(" "); const boxH = 4.5 + 5 + 5.5 + bLines.length * 4.5 + (ctContact ? 4.5 : 0) + 4;