mirror of
https://github.com/kbenestad/invoice.git
synced 2026-06-18 08:04:32 +00:00
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
This commit is contained in:
parent
15addbeae8
commit
bdb2cb28a3
2 changed files with 37 additions and 30 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -516,29 +516,27 @@ function buildForm() {
|
|||
<option value="__other__">${t("other")}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="ct-fields" class="two-col">
|
||||
<div>
|
||||
<div class="fg"><label id="lbl-ctn" for="ctn">${t("charge-to-name")}</label>
|
||||
<input id="ctn" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca1" for="ca1">${t("charge-to-address1")}</label>
|
||||
<input id="ca1" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca2" for="ca2">${t("charge-to-address2")}</label>
|
||||
<input id="ca2" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca3" for="ca3">${t("charge-to-address3")}</label>
|
||||
<input id="ca3" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca4" for="ca4">${t("charge-to-address4")}</label>
|
||||
<input id="ca4" type="text"></div>
|
||||
<div class="fg"><label id="lbl-cc" for="cc">${t("charge-to-country")}</label>
|
||||
<select id="cc">${countryOpts("")}</select></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fi"><label id="lbl-cph">${t("charge-to-phone")}:</label>
|
||||
<input id="cph" type="tel"></div>
|
||||
<div class="fi"><label id="lbl-cem">${t("charge-to-email")}:</label>
|
||||
<input id="cem" type="email"></div>
|
||||
<div class="fi"><label id="lbl-cvat">${t("vat-id")}:</label>
|
||||
<input id="cvat" type="text"></div>
|
||||
</div>
|
||||
<div id="ct-fields">
|
||||
<div class="fg"><label id="lbl-ctn" for="ctn">${t("charge-to-name")}</label>
|
||||
<input id="ctn" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca1" for="ca1">${t("charge-to-address1")}</label>
|
||||
<input id="ca1" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca2" for="ca2">${t("charge-to-address2")}</label>
|
||||
<input id="ca2" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca3" for="ca3">${t("charge-to-address3")}</label>
|
||||
<input id="ca3" type="text"></div>
|
||||
<div class="fg"><label id="lbl-ca4" for="ca4">${t("charge-to-address4")}</label>
|
||||
<input id="ca4" type="text"></div>
|
||||
<div class="fg"><label id="lbl-cc" for="cc">${t("charge-to-country")}</label>
|
||||
<select id="cc">${countryOpts("")}</select></div>
|
||||
<div class="fi"><label id="lbl-cph">${t("charge-to-phone")}:</label>
|
||||
<input id="cph" type="tel"></div>
|
||||
<div class="fi"><label id="lbl-cem">${t("charge-to-email")}:</label>
|
||||
<input id="cem" type="email"></div>
|
||||
<div class="fi"><label id="lbl-cvat">${t("vat-id")}:</label>
|
||||
<input id="cvat" type="text"></div>
|
||||
<div class="fi"><label id="lbl-creg">${t("registration-no")}:</label>
|
||||
<input id="creg" type="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -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 ? `<span><strong>${h(td("charge-to-phone"))}:</strong> ${h(ctPh)}</span>` : ""}
|
||||
${ctEm ? `<span><strong>${h(td("charge-to-email"))}:</strong> ${h(ctEm)}</span>` : ""}
|
||||
${ctVat ? `<span><strong>${h(td("vat-id"))}:</strong> ${h(ctVat)}</span>` : ""}
|
||||
${ctReg ? `<span><strong>${h(td("registration-no"))}:</strong> ${h(ctReg)}</span>` : ""}
|
||||
</div>
|
||||
</div>` : ""}
|
||||
<table class="d-lines">
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue