// ── Shared line item helpers ── // Format stored: "desc,qty,price,discount(0-1),total;desc,..." let lineCount = 0; function parseLines(content) { if (!content || !content.trim()) return []; return content.split(';').map(s => s.trim()).filter(Boolean).map(line => { const p = line.split(','); return { description: p[0] || '', quantity: parseFloat(p[1]) || 0, price: parseFloat(p[2]) || 0, discount: parseFloat(p[3]) || 0, total: parseFloat(p[4]) || 0 }; }); } // Build back to "desc,qty,price,discount(0-1),total;" string function buildContent() { let result = ''; for (let i = 1; i <= lineCount; i++) { const row = document.getElementById('line-' + i); if (!row) continue; const desc = document.getElementById('ld_' + i)?.value || ''; const qty = parseFloat(document.getElementById('lq_' + i)?.value) || 0; const price = parseFloat(document.getElementById('lp_' + i)?.value) || 0; const discPct = parseFloat(document.getElementById('ldis_' + i)?.value) || 0; const discRaw = discPct / 100; // convert % input to 0-1 for storage const total = parseFloat(document.getElementById('lt_' + i)?.value) || 0; result += desc + ',' + qty + ',' + price + ',' + discRaw + ',' + total + ';'; } return result; } function calcLine(n) { const qty = parseFloat(document.getElementById('lq_' + n)?.value) || 0; const price = parseFloat(document.getElementById('lp_' + n)?.value) || 0; const discPct = parseFloat(document.getElementById('ldis_' + n)?.value) || 0; const total = qty * price * (1 - discPct / 100); const el = document.getElementById('lt_' + n); if (el) el.value = Math.round(total * 100) / 100; calcTotal(); } function calcTotal() { let t = 0; for (let i = 1; i <= lineCount; i++) { const el = document.getElementById('lt_' + i); if (el && document.getElementById('line-' + i)) t += parseFloat(el.value) || 0; } const gt = document.getElementById('grand-total'); if (gt) gt.textContent = 'R\u00a0' + t.toLocaleString('en-ZA', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); return t; } function addLine(data) { lineCount++; const n = data ? lineCount : lineCount; const d = data || { description: '', quantity: 1, price: 0, discount: 0, total: 0 }; // discount stored as 0-1, display as 0-100 % const discDisplay = data ? (d.discount * 100) : 0; const row = document.createElement('tr'); row.id = 'line-' + n; const s = (id, val, ev) => ``; row.innerHTML = ` ${s('lq_' + n, d.quantity || 1, 'calcLine(' + n + ')')} ${s('lp_' + n, d.price || 0, 'calcLine(' + n + ')')} ${s('ldis_' + n, discDisplay, 'calcLine(' + n + ')')} `; document.getElementById('lines-body').appendChild(row); if (data) calcLine(n); // recalculate to confirm total } function removeLine(n) { document.getElementById('line-' + n)?.remove(); calcTotal(); }