Files
Aislo/tools/est-test/native-quantity-total.js
eomsangdonandClaude Opus 5.5 c0d49e0bbb feat(est-test): 수량산출 누계 계산과 넣기
- 원본 누계 표지(F·a)를 읽어 계산마다 소계로 다시 구함
- 산출 줄 커서 자리에 누계 넣기, 표지 반올림 방식·자리 반영

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:06:29 +09:00

62 lines
3.1 KiB
JavaScript

// 원본 수량산출 누계(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 };
})();