From f07b1e9ae0d66959a5289f1f5dc1134bc4d9025e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 24 May 2026 16:25:32 +0000 Subject: [PATCH] Per-recipient project codes Each charge-to entry in config.yml can now have its own project-codes list. Selecting a recipient swaps the project code dropdown to that recipient's codes; switching back to Select or Other restores the global list. Falls back to the global list if a recipient has no project-codes defined. --- app/config.yml | 8 ++++++++ app/index.html | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/app/config.yml b/app/config.yml index 9178ce3..5702c3b 100644 --- a/app/config.yml +++ b/app/config.yml @@ -119,6 +119,10 @@ charge-to: vat-id: "US-EIN-12-3456789" reg-no: "" currency: USD + project-codes: + - AC-100 + - AC-110 + - AC-200 - display: Example NGO name: Example Non-Profit Organisation address1: 45 Charity Lane @@ -131,6 +135,10 @@ charge-to: vat-id: "GB123456789" reg-no: "01234567" currency: GBP + project-codes: + - NGO-2026-01 + - NGO-2026-02 + - NGO-2026-03 # ── Project codes ────────────────────────────────────────────────────────────── project-codes: diff --git a/app/index.html b/app/index.html index 2ff8e71..31eb867 100644 --- a/app/index.html +++ b/app/index.html @@ -693,6 +693,20 @@ function buildForm() { calcPayBy(); // compute initial pay-by from default 7-day term } +// ── Project-code dropdown ───────────────────────────────────────────────────── +function updateProjectCodes(codes) { + const arr = (codes && codes.length) ? codes : (cfg["project-codes"] || []); + const sel = document.getElementById("pcode"); + if (!sel) return; + const prev = sel.value; + sel.innerHTML = `` + + arr.map(pc => ``).join("") + + ``; + sel.value = arr.includes(prev) ? prev : ""; + const wrap = document.getElementById("pcode-other-wrap"); + if (wrap) wrap.style.display = sel.value === "__other__" ? "block" : "none"; +} + // ── Fill charge-to ──────────────────────────────────────────────────────────── function fillChargeTo(v) { const f = (id, val) => { const el = document.getElementById(id); if (el) el.value = val ?? ""; }; @@ -704,10 +718,12 @@ function fillChargeTo(v) { if (v === "") { ["ctn","ca1","ca2","ca3","ca4","cc","cph","cem","cvat","creg"].forEach(id => f(id, "")); fields?.classList.add("locked"); + updateProjectCodes(null); // restore global project codes return; } if (v === "__other__") { fields?.classList.remove("locked"); + updateProjectCodes(null); // restore global project codes return; } const ct = (cfg["charge-to"] || [])[+v]; @@ -719,6 +735,9 @@ function fillChargeTo(v) { f("cvat", ct["vat-id"]); f("creg", ct["reg-no"]); fields?.classList.add("locked"); + // Swap project codes to this recipient's list (falls back to global if none defined) + updateProjectCodes(ct["project-codes"] || null); + // Auto-set invoice currency from recipient config if (ct.currency) { const icurEl = document.getElementById("icur");