Files
Aislo/resources/tester/helper_stmate_progress_rea.cjs
T

119 lines
4.4 KiB
JavaScript

// STMATE 재현 앱 기성 계산(progress_calc.js) — 원본 정적 분석 규칙 시험용 stdin JSON 실행기
// 입력 { mode, args } → 출력 JSON · 근거: 지식DB STmate/REA 분석/33_기성준공단계_작업자료_20261114
const Progress = require("../../tools/stmate-test/progress_calc.js");
// 합성 계약 기준 — leaves [{id, qty, m, l, s, pct, gov}] · lines [{code, amount}] · direct · contractFinal
function mkBase(spec) {
const leaves = spec.leaves.map((x, i) => {
const amt = {
mAmt: Math.trunc(x.m * x.qty + 1e-9),
lAmt: Math.trunc(x.l * x.qty + 1e-9),
sAmt: Math.trunc(x.s * x.qty + 1e-9),
};
amt.tAmt = amt.mAmt + amt.lAmt + amt.sAmt;
return {
id: x.id,
recno: i,
code: x.id,
name: x.id,
spec: "",
unit: x.pct ? "%" : "식",
gov: !!x.gov,
pct: !!x.pct,
qty: x.qty,
u: { m: x.m, l: x.l, s: x.s },
amt,
};
});
const direct =
spec.direct != null
? spec.direct
: leaves.filter((l) => !l.gov).reduce((a, l) => a + l.amt.tAmt, 0);
const lines = spec.lines.map((l) => ({ code: l.code, label: l.code, amount: l.amount }));
const ratePct = Object.fromEntries(lines.map((l) => [l.code, (l.amount / direct) * 100]));
const rates = Object.fromEntries(lines.map((l) => [l.code, ratePct[l.code] / 100]));
return {
leaves,
lines,
rates,
ratePct,
direct,
kj: { contractFinal: spec.contractFinal || 0 },
nodes: [],
};
}
const MODES = {
cap: ({ cases }) => cases.map((c) => Progress.capCur(c[0], c[1], c[2], c[3])),
jab: ({ spec, cur, opt, prev, accDirect }) =>
Progress.jabFor(mkBase(spec), cur, opt || {}, prev || null, accDirect),
run: ({ spec, rounds, seed }) => Progress.run(mkBase(spec), rounds, seed),
store({ spec, rounds }) {
const base = mkBase(spec);
const all = Progress.run(base, rounds);
const st = Progress.toStorage(base, all[0]);
const rows = st.boq.map((u) => Object.assign({}, u));
const fs = Progress.fromStorage(base, rows, st.prjlst, st.smt);
// 제 1 회 저장본을 「전회」로 다시 읽어 제 2 회를 셈 — STmate 회차 생성(전회<-누계, 금회=0)과 같은 흐름
const seedRows = st.boq.map((u) =>
Object.assign({}, u, {
QTY3: u.QTY2,
QTY4: 0,
M_AMT3: u.M_AMT2,
L_AMT3: u.L_AMT2,
S_AMT3: u.S_AMT2,
T_AMT3: u.T_AMT2,
}),
);
const smt3 = Object.fromEntries(
Object.entries(st.smt["2_KANJUB"]).map(([k, v]) => [k.replace(/^2_/, "3_"), v]),
);
const fs2 = Progress.fromStorage(base, seedRows, { K_ORD: 2 }, smt3);
const next = Progress.run(base, [rounds[1]], fs2.seed);
// 원본 회차 등록 규칙(nextRound)으로 만든 저장본에서 다시 읽은 제 2 회
const nr = Progress.nextRound(st);
const fs3 = Progress.fromStorage(
base,
nr.boq,
nr.prjlst,
Object.assign({}, ...Object.values(nr.smt)),
);
const next2 = Progress.run(base, [rounds[1]], fs3.seed);
return { all, st, fs, fs2, next, nr, next2 };
},
// 실제 STC(설계 판) → 계약 기준 → 회차 → 저장 형식
real({ load, opts, rounds }) {
const Calc = require("../../tools/stmate-test/calc.js");
const Change = require("../../tools/stmate-test/change_calc.js");
const Contract = require("../../tools/stmate-test/contract_calc.js");
const state = load.sim_state;
const comp = Calc.calculateAll(state);
const tree = Change.buildTree(load.boq_rows, state, comp, [1]);
const conv = Contract.convert(tree, opts, 1, null);
const kj = Contract.contractKanjub(conv, state.kanjubStages[1] || state.kanjubConfig);
const base = Progress.contractBase(conv, kj);
const all = Progress.run(base, rounds);
const last = all[all.length - 1];
const st = Progress.toStorage(base, last);
const lv = Progress.aggregate(base, last, 3).map((nd) => nd.level);
return {
direct: base.direct,
lines: base.lines.map((l) => [l.code, l.amount]),
cur: all.map((r) => r.totals.cur),
accT: all.map((r) => r.totals.acc.tAmt),
rounds: all.map((r) => r.jab),
st,
lv,
gov: base.leaves.map((l) => l.gov),
};
},
};
let buf = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (d) => (buf += d));
process.stdin.on("end", () => {
const inp = JSON.parse(buf);
process.stdout.write(JSON.stringify(MODES[inp.mode](inp.args || {})));
});