feat(est): reproduce native tables and calculations

This commit is contained in:
2026-11-05 06:07:05 +09:00
parent 646eab6245
commit 60ccedcd9a
30 changed files with 5249 additions and 22 deletions
+112
View File
@@ -0,0 +1,112 @@
const EstResources = (() => {
const { num, components } = EstMath;
function calculate(input) {
const project = EstNative.calculate({
...structuredClone(input),
options: { ...input.options, SourceRefresh: true },
});
const tables = project.tables,
heads = EstNative.groups(tables.HeadMainDat),
costs = EstNative.groups(tables.CostMainDat),
output = new Map(),
errors = [...project.calculation.errors];
function record(kind, code, quantity, amount = 0) {
const source = (tables[EstNative.sourceTables[kind]] || []).find((row) => row.Code === code);
if (!source) {
errors.push(`동원 원천 없음: ${kind}/${code}`);
return;
}
const id = `${kind}:${code}`;
const row = output.get(id) || {
Code: code,
Name: source.Name,
Size: source.Size,
Unite: source.Unite,
kind,
quantity: 0,
amount: 0,
};
row.quantity += quantity;
row.amount += amount;
output.set(id, row);
}
function expand(kind, code, multiplier, path) {
const id = `${kind}:${code}`;
if (path.includes(id)) {
errors.push(`동원 순환 참조: ${id}`);
return;
}
if (kind === 104) {
const group = costs.get(code);
if (!group) {
errors.push(`산근 없음: ${code}`);
return;
}
for (const row of group.rows) {
if (!row.ResourceCode || row.ResourceFactor == null) continue;
if ([103, 104].includes(num(row.ResourceKind)))
expand(num(row.ResourceKind), row.ResourceCode, multiplier * num(row.ResourceFactor), [
...path,
id,
]);
else if (num(row.ResourceKind) === 105)
record(105, row.ResourceCode, 0, multiplier * num(row.TC));
else
record(
num(row.ResourceKind),
row.ResourceCode,
multiplier * num(row.ResourceFactor),
multiplier * num(row.TC),
);
}
return;
}
if (kind === 103) {
const group = heads.get(code);
if (!group) {
errors.push(`일위 없음: ${code}`);
return;
}
let rate = 1;
const bid = group.rows.find((row) => num(row.LinkIndex) === 52);
if (bid) rate = num(bid.GN) / 100;
for (const row of group.rows.slice(1)) {
if (num(row.CalcIndex) >= 2 || [51, 52, 58, 62, 68].includes(num(row.LinkIndex)))
continue;
const quantity =
(multiplier * num(row.GN) * rate) / (["%", "%"].includes(row.Unite) ? 100 : 1);
if ([103, 104].includes(num(row.LinkIndex)))
expand(num(row.LinkIndex), row.Code, quantity, [...path, id]);
else if (EstNative.sourceTables[num(row.LinkIndex)])
record(num(row.LinkIndex), row.Code, quantity, multiplier * num(row.TC));
}
return;
}
record(kind, code, multiplier);
}
for (const row of tables.EstMainDat) {
if (num(row.LinkIndex) === 54) break;
if (
num(row.Level) > 0 ||
num(row.CalcIndex) >= 2 ||
!EstNative.sourceTables[num(row.LinkIndex)]
)
continue;
expand(num(row.LinkIndex), row.Code, num(row.GN), []);
}
const rows = [...output.values()];
for (const row of rows)
if (row.kind === 105 && row.amount) {
const price = num(tables.MachTitleDat.find((r) => r.Code === row.Code)?.TC);
if (price) {
row.quantity += row.amount / price;
row.Unite = "HR";
} else {
row.Unite = "제외금액";
row.quantity = 0;
}
}
return { rows, errors: [...new Set(errors)] };
}
return { calculate };
})();