fix(est): match project costs and stored formulas

This commit is contained in:
2026-11-05 07:12:08 +09:00
parent 1856aa897d
commit d922ad13f3
19 changed files with 569 additions and 150 deletions
+50 -14
View File
@@ -88,6 +88,28 @@ const EstNative = (() => {
});
return result;
}
function materialBase(rows, options = {}, field = "GC") {
const levels = [];
let amount = 0;
for (const row of rows) {
if (num(row.LinkIndex) === 54) break;
const level = num(row.Level);
if (level > 0) {
while (levels.length && levels.at(-1).level <= level) levels.pop();
levels.push({
level,
direct: String(row.Name || "")
.trim()
.endsWith("*"),
});
} else if (
num(row.CalcIndex) < 2 &&
(options.GCToWonga || levels.some((group) => group.direct))
)
amount += num(row[field]);
}
return amount;
}
function calculate(input) {
const project = clone(input),
tables = project.tables,
@@ -139,7 +161,11 @@ const EstNative = (() => {
const result =
kind === 103
? EstRows.head(group.rows, options, resolve)
: EstText.calculate(group.rows, options, options.SourceRefresh ? resolve : () => null);
: EstText.calculate(
group.rows,
options,
options.SourceRefresh || options.ResourceTracing ? resolve : () => null,
);
const title = {
...tables[sourceTables[kind]].find((row) => row.Code === code),
...result.titles[0],
@@ -208,36 +234,46 @@ const EstNative = (() => {
errors.push(...estimate.errors);
const direct = estimate.direct;
const boundary = tables.EstMainDat.findIndex((row) => num(row.LinkIndex) === 54);
const leaves = tables.EstMainDat.slice(
0,
boundary < 0 ? tables.EstMainDat.length : boundary,
).filter((row) => !num(row.Level) && num(row.CalcIndex) < 2);
const directMaterial = options.GCToWonga
? num(direct.GC)
: leaves.filter((row) => num(row.LinkIndex) === 5).reduce((n, row) => n + num(row.GC), 0);
const directMaterial = materialBase(tables.EstMainDat, options);
const governmentHeading = tables.EstMainDat.findIndex(
(row, i) => i > boundary && num(row.Level) > 0 && normalize(row.Name).includes("관급"),
);
let government = null;
let government = null,
procurementFees = 0;
if (governmentHeading >= 0) {
government = 0;
government = num(tables.EstMainDat[governmentHeading].TC);
const level = num(tables.EstMainDat[governmentHeading].Level);
for (
let i = governmentHeading + 1;
i < tables.EstMainDat.length && num(tables.EstMainDat[i].Level) < level;
i++
)
if (!num(tables.EstMainDat[i].Level)) government += num(tables.EstMainDat[i].TC);
if (num(tables.EstMainDat[i].LinkIndex) === 57)
procurementFees += num(tables.EstMainDat[i].TC);
}
if (options.AutoWongaBase !== false)
for (const row of tables.Wonga) {
if (row.VSusic || [1, 3].includes(num(row.CalcIndex)) || row.BaseField) continue;
if (
(row.VSusic && !/^원금액\s*:/.test(row.VSusic)) ||
[1, 3].includes(num(row.CalcIndex)) ||
row.BaseField
)
continue;
const name = normalize(row.Name);
if (name.includes("직접재료")) row.Cost = directMaterial;
else if (name.includes("간접재료")) row.Cost = num(direct.GC) - directMaterial;
else if (name.includes("직접노무")) row.Cost = num(direct.NC);
else if (name.includes("산출경비")) row.Cost = num(direct.JC);
else if (name.includes("관급자재") && government !== null) row.Cost = government;
else if (name.includes("관급자재") && government !== null) {
row.Cost = government;
row.TC = government;
row.NC = procurementFees;
if (/^원금액\s*:/.test(row.VSusic))
row.VSusic = row.VSusic.replace(
/(원금액\s*:)[\d,.]+/,
`$1${government.toLocaleString("en-US")}`,
).replace(/(조달수수료\s*:)[\d,.]+/, `$1${procurementFees.toLocaleString("en-US")}`);
}
}
const wonga = EstWonga.calculate(tables.Wonga, options, {
NC: num(direct.NC),
@@ -282,5 +318,5 @@ const EstNative = (() => {
drawings: [],
};
}
return { calculate, price, groups, empty, allTables, sourceTables, normalize };
return { calculate, price, groups, empty, allTables, sourceTables, normalize, materialBase };
})();