// 원본 수량산출 누계(TfrmMulWord ActionAdd Ctrl+U → 0x11155c4, 재계산 0x111c0b0 에서 F·a 표지 다시 계산). // 누계 값 = 가장 가까운 위쪽 품명 줄(포함) 또는 앞 누계 줄(제외)부터 누계 줄 바로 위까지, 줄마다 첫 결과 수량의 합. // 앞 누계는 더하지 않는 소계다. 반올림은 표지 이름 뒤 방식·자리(F000003 + 1 + 2), 없으면 산출서 설정. // 웹은 누계를 \x16 쌍으로 적고 이름을 row.totals 에 둔다. 「누계」·「∴」 같은 글자는 넣지 않는다. const EstQuantityTotal = (() => { const first = (line) => { const match = String(line ?? "").match(/\x12([-\d.,]+)\x12/); return match ? Number(match[1].replaceAll(",", "")) || 0 : 0; }; function format(value, digits) { return value.toLocaleString("en-US", { maximumFractionDigits: digits, useGrouping: true }); } function rounding(sheet, name) { const match = String(name ?? "").match(/^[Fa]\d{6}([123])(\d)$/); return { method: match ? Number(match[1]) : (sheet.options?.roundMode ?? 2), digits: match ? Number(match[2]) : (sheet.options?.digits ?? 2), }; } // rows: 계산이 끝난 줄(LineData 의 결과 값이 갱신된 것). 누계 줄의 \x16 값을 고쳐 쓴다. function apply(sheet, rows) { let start = 0; rows.forEach((row, i) => { const line = String(row.LineData ?? ""); if (line.includes("\x16")) { let sum = 0; for (let j = start; j < i; j++) sum += first(rows[j].LineData); const names = sheet.rows[i]?.totals || []; let part = 0; row.LineData = line.replace(/\x16[^\x16]*\x16/g, () => { const { method, digits } = rounding(sheet, names[part++]); return `\x16${format(EstMath.fixed(sum, digits, method), digits)}\x16`; }); start = i + 1; } else if (line.includes("\x0e")) start = i; }); return rows; } // 커서 자리에 새 누계를 넣는다. text 는 화면 표기(⟦누계⟧) 줄, caret 은 그 안의 위치. function insert(sheet, rowIndex, caret, text) { const row = sheet.rows[rowIndex]; if (!row) throw Error("누계를 넣을 산출 줄을 고르세요."); const used = new Set(sheet.rows.flatMap((r) => (r.totals || []).map((n) => n.slice(1, 7)))); let n = 1; while (used.has(String(n).padStart(6, "0"))) n++; const { method, digits } = rounding(sheet, ""); const name = `F${String(n).padStart(6, "0")}${method}${digits}`, shown = text ?? EstText.display(row.LineData), at = Math.max(0, Math.min(caret, shown.length)), position = shown.slice(0, at).split("⟦누계⟧").length - 1; const before = shown.slice(0, at); if (position % 2 || before.lastIndexOf("⟦") > before.lastIndexOf("⟧")) throw Error("누계 표지 안에는 넣을 수 없습니다."); row.LineData = EstText.encode(`${shown.slice(0, at)}⟦누계⟧0⟦누계⟧${shown.slice(at)}`); row.totals = [...(row.totals || [])]; row.totals.splice(position / 2, 0, name); sheet.markerEdited = true; return name; } return { apply, insert, rounding }; })();