Swap Invoice details / Payment positions; bank fields only for Other

- New layout: Sender | Invoice details (top row), Charge to | Payment (bottom row)
- Bank account fields (#bank-section) are hidden by default and only revealed
  when "Other" is selected for charge-to; hidden again for predefined recipients
- gatherData() only collects bank fields when bank-section is visible
- Preview and PDF panels updated to match the new quadrant order

https://claude.ai/code/session_015iyCBgoTXNNqaErR287U1u
This commit is contained in:
Claude 2026-05-19 09:34:43 +00:00
parent 275d3a3b71
commit a63fcc8a42
No known key found for this signature in database

View file

@ -507,27 +507,23 @@ function buildForm() {
<input id="se" type="email" data-ls="se" autocomplete="email"></div> <input id="se" type="email" data-ls="se" autocomplete="email"></div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-title" id="lbl-pay-sec">${t("payment")}</div> <div class="card-title" id="sec-invdet">${t("invoice-details-section")}</div>
<div class="pay-terms-row"> <div class="fg"><label id="lbl-idate" for="idate">${t("invoice-date")}</label>
<label id="lbl-pterm">${t("payment-terms")}:</label> <input id="idate" type="date" value="${dateDef}"></div>
<input id="pterm" type="number" min="0" value="7" oninput="calcPayBy()" data-ls="pterm"> <div class="fg"><label id="lbl-icur" for="icur">${t("invoice-currency")}</label>
<span id="lbl-days">${t("payment-days")}</span> <select id="icur" data-ls="icur">${curOpts}</select></div>
<div class="fg"><label id="lbl-pcode" for="pcode">${t("project-code")}</label>
<select id="pcode">
<option value="">${t("select")}</option>
${pcOpts}
<option value="__other__">${t("other")}</option>
</select></div>
<div class="fg" id="pcode-other-wrap" style="display:none">
<label id="lbl-pcode-other" for="pcode-other">${t("project-code")} (${t("other")})</label>
<input id="pcode-other" type="text">
</div> </div>
<div class="pay-by-row"> <div class="fg"><label id="lbl-ino" for="ino">${t("invoice-no")}</label>
<label id="lbl-paybyl">${t("pay-by")}:</label> <input id="ino" type="text" data-ls="ino"></div>
<span id="paybydisp"></span>
</div>
<div class="fg"><label id="lbl-pacct">${t("account-holder")}</label>
<input id="pacct" type="text" data-ls="pacct"></div>
<div class="fg"><label id="lbl-piban">${t("account-no")}</label>
<input id="piban" type="text" data-ls="piban"></div>
<div class="fg"><label id="lbl-pbic">${t("bank-bic")}</label>
<input id="pbic" type="text" data-ls="pbic"></div>
<div class="fg"><label id="lbl-pbadr">${t("bank-address")}</label>
<input id="pbadr1" type="text" data-ls="pbadr1">
<input id="pbadr2" type="text" style="margin-top:6px" data-ls="pbadr2"></div>
<div class="fg"><label id="lbl-pref">${t("payment-ref")}</label>
<input id="pref" type="text" data-ls="pref"></div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-title" style="display:flex;align-items:center;gap:8px;flex-wrap:wrap"> <div class="card-title" style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
@ -562,23 +558,29 @@ function buildForm() {
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-title" id="sec-invdet">${t("invoice-details-section")}</div> <div class="card-title" id="lbl-pay-sec">${t("payment")}</div>
<div class="fg"><label id="lbl-idate" for="idate">${t("invoice-date")}</label> <div class="pay-terms-row">
<input id="idate" type="date" value="${dateDef}"></div> <label id="lbl-pterm">${t("payment-terms")}:</label>
<div class="fg"><label id="lbl-icur" for="icur">${t("invoice-currency")}</label> <input id="pterm" type="number" min="0" value="7" oninput="calcPayBy()" data-ls="pterm">
<select id="icur" data-ls="icur">${curOpts}</select></div> <span id="lbl-days">${t("payment-days")}</span>
<div class="fg"><label id="lbl-pcode" for="pcode">${t("project-code")}</label> </div>
<select id="pcode"> <div class="pay-by-row">
<option value="">${t("select")}</option> <label id="lbl-paybyl">${t("pay-by")}:</label>
${pcOpts} <span id="paybydisp"></span>
<option value="__other__">${t("other")}</option> </div>
</select></div> <div id="bank-section" style="display:none">
<div class="fg" id="pcode-other-wrap" style="display:none"> <div class="fg"><label id="lbl-pacct">${t("account-holder")}</label>
<label id="lbl-pcode-other" for="pcode-other">${t("project-code")} (${t("other")})</label> <input id="pacct" type="text" data-ls="pacct"></div>
<input id="pcode-other" type="text"> <div class="fg"><label id="lbl-piban">${t("account-no")}</label>
<input id="piban" type="text" data-ls="piban"></div>
<div class="fg"><label id="lbl-pbic">${t("bank-bic")}</label>
<input id="pbic" type="text" data-ls="pbic"></div>
<div class="fg"><label id="lbl-pbadr">${t("bank-address")}</label>
<input id="pbadr1" type="text" data-ls="pbadr1">
<input id="pbadr2" type="text" style="margin-top:6px" data-ls="pbadr2"></div>
<div class="fg"><label id="lbl-pref">${t("payment-ref")}</label>
<input id="pref" type="text" data-ls="pref"></div>
</div> </div>
<div class="fg"><label id="lbl-ino" for="ino">${t("invoice-no")}</label>
<input id="ino" type="text" data-ls="ino"></div>
</div> </div>
</div> </div>
@ -645,6 +647,9 @@ function fillChargeTo(v) {
const f = (id, val) => { const el = document.getElementById(id); if (el) el.value = val ?? ""; }; const f = (id, val) => { const el = document.getElementById(id); if (el) el.value = val ?? ""; };
const fields = document.getElementById("ct-fields"); const fields = document.getElementById("ct-fields");
const bsec = document.getElementById("bank-section");
if (bsec) bsec.style.display = v === "__other__" ? "" : "none";
if (v === "" || v === "__other__") { if (v === "" || v === "__other__") {
if (v === "") ["ctn","ca1","ca2","ca3","ca4","cc","cph","cem","cvat","creg"].forEach(id => f(id, "")); if (v === "") ["ctn","ca1","ca2","ca3","ca4","cc","cph","cem","cvat","creg"].forEach(id => f(id, ""));
fields?.classList.remove("locked"); fields?.classList.remove("locked");
@ -1043,12 +1048,14 @@ function gatherData(renderLang) {
const pTerm = parseInt(document.getElementById("pterm")?.value) || 0; const pTerm = parseInt(document.getElementById("pterm")?.value) || 0;
const pPayBy = document.getElementById("paybydisp")?.textContent || ""; const pPayBy = document.getElementById("paybydisp")?.textContent || "";
const pAcct = g("pacct"); const bsecEl = document.getElementById("bank-section");
const pIban = g("piban"); const bankVis = bsecEl && bsecEl.style.display !== "none";
const pBic = g("pbic"); const pAcct = bankVis ? g("pacct") : "";
const pBadr1 = g("pbadr1"); const pIban = bankVis ? g("piban") : "";
const pBadr2 = g("pbadr2"); const pBic = bankVis ? g("pbic") : "";
const pRef = g("pref"); const pBadr1 = bankVis ? g("pbadr1"): "";
const pBadr2 = bankVis ? g("pbadr2"): "";
const pRef = bankVis ? g("pref") : "";
const hasBank = !!(pAcct || pIban || pBic || pBadr1 || pRef); const hasBank = !!(pAcct || pIban || pBic || pBadr1 || pRef);
const hidePaymentOut = cfg["hide-payment-info"] === true || cfg["hide-payment-info"] === "yes"; const hidePaymentOut = cfg["hide-payment-info"] === true || cfg["hide-payment-info"] === "yes";
@ -1142,16 +1149,14 @@ function buildPreviewHTML() {
${sPh ? `<p>${h(td("sender-phone"))}: ${h(sPh)}</p>` : ""} ${sPh ? `<p>${h(td("sender-phone"))}: ${h(sPh)}</p>` : ""}
${sEm ? `<p>${h(td("sender-email"))}: ${h(sEm)}</p>` : ""} ${sEm ? `<p>${h(td("sender-email"))}: ${h(sEm)}</p>` : ""}
</div> </div>
<div class="d-tr d-pay-hdr"> <div class="d-tr d-inv-meta">
<div class="ph-lbl">${h(td("payment"))}</div> <h1>${h(td("invoice"))}</h1>
${pTerm > 0 ? `<div class="ph-terms">${h(td("payment-terms"))}: <strong>${pTerm}</strong> ${h(td("payment-days"))}${pPayBy ? ` &mdash; ${h(td("pay-by"))}: <strong>${h(pPayBy)}</strong>` : ""}</div>` : ""} <table class="d-meta">
${showBank ? `<div class="ph-grid"> ${iNo ? `<tr><td class="ml">${h(td("invoice-no"))}</td><td class="mv">${h(iNo)}</td></tr>` : ""}
${pAcct ? `<span class="pl">${h(td("account-holder"))}</span><span class="pv">${h(pAcct)}</span>` : ""} ${iDate ? `<tr><td class="ml">${h(td("invoice-date"))}</td><td class="mv">${h(fmtDate(iDate))}</td></tr>` : ""}
${pIban ? `<span class="pl">${h(td("account-no"))}</span><span class="pv">${h(pIban)}</span>` : ""} ${pCode ? `<tr><td class="ml">${h(td("project-code"))}</td><td class="mv">${h(pCode)}</td></tr>` : ""}
${pBic ? `<span class="pl">${h(td("bank-bic"))}</span><span class="pv">${h(pBic)}</span>` : ""} ${iCur ? `<tr><td class="ml">${h(td("invoice-currency"))}</td><td class="mv">${h(iCur)}</td></tr>` : ""}
${pBadr1 || pBadr2 ? `<span class="pl">${h(td("bank-address"))}</span><span class="pv">${[pBadr1,pBadr2].filter(Boolean).map(l=>h(l)).join("<br>")}</span>` : ""} </table>
</div>
${pRef ? `<div class="ph-ref">${h(td("payment-ref"))}: <strong>${h(pRef)}</strong></div>` : ""}` : ""}
</div> </div>
<div class="d-bl d-bill"> <div class="d-bl d-bill">
<div class="bt-lbl">${h(td("charge-to"))}</div> <div class="bt-lbl">${h(td("charge-to"))}</div>
@ -1165,14 +1170,16 @@ function buildPreviewHTML() {
${ctReg ? `<span><strong>${h(td("registration-no"))}:</strong> ${h(ctReg)}</span>` : ""} ${ctReg ? `<span><strong>${h(td("registration-no"))}:</strong> ${h(ctReg)}</span>` : ""}
</div> </div>
</div> </div>
<div class="d-br d-inv-meta"> <div class="d-br d-pay-hdr">
<h1>${h(td("invoice"))}</h1> <div class="ph-lbl">${h(td("payment"))}</div>
<table class="d-meta"> ${pTerm > 0 ? `<div class="ph-terms">${h(td("payment-terms"))}: <strong>${pTerm}</strong> ${h(td("payment-days"))}${pPayBy ? ` &mdash; ${h(td("pay-by"))}: <strong>${h(pPayBy)}</strong>` : ""}</div>` : ""}
${iNo ? `<tr><td class="ml">${h(td("invoice-no"))}</td><td class="mv">${h(iNo)}</td></tr>` : ""} ${showBank ? `<div class="ph-grid">
${iDate ? `<tr><td class="ml">${h(td("invoice-date"))}</td><td class="mv">${h(fmtDate(iDate))}</td></tr>` : ""} ${pAcct ? `<span class="pl">${h(td("account-holder"))}</span><span class="pv">${h(pAcct)}</span>` : ""}
${pCode ? `<tr><td class="ml">${h(td("project-code"))}</td><td class="mv">${h(pCode)}</td></tr>` : ""} ${pIban ? `<span class="pl">${h(td("account-no"))}</span><span class="pv">${h(pIban)}</span>` : ""}
${iCur ? `<tr><td class="ml">${h(td("invoice-currency"))}</td><td class="mv">${h(iCur)}</td></tr>` : ""} ${pBic ? `<span class="pl">${h(td("bank-bic"))}</span><span class="pv">${h(pBic)}</span>` : ""}
</table> ${pBadr1 || pBadr2 ? `<span class="pl">${h(td("bank-address"))}</span><span class="pv">${[pBadr1,pBadr2].filter(Boolean).map(l=>h(l)).join("<br>")}</span>` : ""}
</div>
${pRef ? `<div class="ph-ref">${h(td("payment-ref"))}: <strong>${h(pRef)}</strong></div>` : ""}` : ""}
</div> </div>
</div> </div>
<table class="d-lines"> <table class="d-lines">
@ -1253,34 +1260,19 @@ function buildPDF() {
fn(8); tc(107,114,128); tL(parts.join(" "), ML, ly); ly += 5; fn(8); tc(107,114,128); tL(parts.join(" "), ML, ly); ly += 5;
} }
// ── Row 1 right: Payment ── // ── Row 1 right: INVOICE + meta ──
if (pTerm > 0 || showBank) { fb(24); tc(30,45,69); tR(td("invoice"), XR, ry); ry += 10;
fb(7); tc(107,114,128); tL(td("payment").toUpperCase(), XM_L, ry); ry += 5; const metaRows = [
if (pTerm > 0) { iNo ? [td("invoice-no"), iNo] : null,
const ts = `${td("payment-terms")}: ${pTerm} ${td("payment-days")}${pPayBy ? ` ${td("pay-by")}: ${pPayBy}` : ""}`; iDate ? [td("invoice-date"), fmtDate(iDate)] : null,
fn(8.5); tc(17,24,39); tL(ts, XM_L, ry); ry += 5; pCode ? [td("project-code"), pCode] : null,
} iCur ? [td("invoice-currency"), iCur] : null,
if (showBank) { ].filter(Boolean);
const LLBL = 46; metaRows.forEach(([lbl, val]) => {
const payRows = [ fn(8.5); tc(107,114,128); tR(lbl + ":", XR - 42, ry);
pAcct ? [td("account-holder"), pAcct] : null, fb(8.5); tc(17,24,39); tR(val, XR, ry);
pIban ? [td("account-no"), pIban] : null, ry += 5;
pBic ? [td("bank-bic"), pBic] : null, });
(pBadr1||pBadr2) ? [td("bank-address"), [pBadr1,pBadr2].filter(Boolean).join(", ")] : null,
].filter(Boolean);
payRows.forEach(([lbl, val]) => {
fn(8); tc(107,114,128); tL(lbl + ":", XM_L, ry);
fn(8.5); tc(17,24,39);
const wrapped = sp(val, LW - LLBL - 2);
wrapped.forEach((line, i) => tL(line, XM_L + LLBL, ry + i * 4));
ry += Math.max(4.5, wrapped.length * 4);
});
if (pRef) {
fn(8); tc(107,114,128); tL(td("payment-ref") + ":", XM_L, ry);
fb(8.5); tc(17,24,39); tL(pRef, XM_L + LLBL, ry); ry += 5;
}
}
}
// Row 1 divider // Row 1 divider
const row1Y = Math.max(ly, ry) + 4; const row1Y = Math.max(ly, ry) + 4;
@ -1302,19 +1294,34 @@ function buildPDF() {
if (ctParts.length) { fn(8); tc(107,114,128); tL(ctParts.join(" "), ML, ly2); ly2 += 5; } if (ctParts.length) { fn(8); tc(107,114,128); tL(ctParts.join(" "), ML, ly2); ly2 += 5; }
} }
// ── Row 2 right: INVOICE + meta ── // ── Row 2 right: Payment ──
fb(24); tc(30,45,69); tR(td("invoice"), XR, ry2); ry2 += 10; if (pTerm > 0 || showBank) {
const metaRows = [ fb(7); tc(107,114,128); tL(td("payment").toUpperCase(), XM_L, ry2); ry2 += 5;
iNo ? [td("invoice-no"), iNo] : null, if (pTerm > 0) {
iDate ? [td("invoice-date"), fmtDate(iDate)] : null, const ts = `${td("payment-terms")}: ${pTerm} ${td("payment-days")}${pPayBy ? ` ${td("pay-by")}: ${pPayBy}` : ""}`;
pCode ? [td("project-code"), pCode] : null, fn(8.5); tc(17,24,39); tL(ts, XM_L, ry2); ry2 += 5;
iCur ? [td("invoice-currency"), iCur] : null, }
].filter(Boolean); if (showBank) {
metaRows.forEach(([lbl, val]) => { const LLBL = 46;
fn(8.5); tc(107,114,128); tR(lbl + ":", XR - 42, ry2); const payRows = [
fb(8.5); tc(17,24,39); tR(val, XR, ry2); pAcct ? [td("account-holder"), pAcct] : null,
ry2 += 5; pIban ? [td("account-no"), pIban] : null,
}); pBic ? [td("bank-bic"), pBic] : null,
(pBadr1||pBadr2) ? [td("bank-address"), [pBadr1,pBadr2].filter(Boolean).join(", ")] : null,
].filter(Boolean);
payRows.forEach(([lbl, val]) => {
fn(8); tc(107,114,128); tL(lbl + ":", XM_L, ry2);
fn(8.5); tc(17,24,39);
const wrapped = sp(val, LW - LLBL - 2);
wrapped.forEach((line, i) => tL(line, XM_L + LLBL, ry2 + i * 4));
ry2 += Math.max(4.5, wrapped.length * 4);
});
if (pRef) {
fn(8); tc(107,114,128); tL(td("payment-ref") + ":", XM_L, ry2);
fb(8.5); tc(17,24,39); tL(pRef, XM_L + LLBL, ry2); ry2 += 5;
}
}
}
y = Math.max(ly2, ry2) + 5; y = Math.max(ly2, ry2) + 5;