Files
Aislo/tools/est-test/native-escalation.js

119 lines
4.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// REA 10a7ad4/10a7d7c/10a82cc/10a8fa8, e42260, 10ad5ac.
const EstEscalation = (() => {
const { num, units, components, floating, sum } = EstMath;
const special = (row) => [54, 55, 57, 58, 59, 62, 67].includes(num(row.LinkIndex));
const total = (p) =>
p.tables.Wonga.length ? num(p.calculation.total) : num(p.calculation.direct.TC);
function calculate(project) {
const key = EstBusiness.rowKey,
errors = [],
rows = structuredClone(project.tables.EstMainDat);
const original =
project.baseline?.tables.EstMainDat ||
rows.map((row) => {
const old = { ...row };
for (const field of ["GN", "TU", "TC", ...units, ...components])
if (row[field + "_"] != null) old[field] = row[field + "_"];
return old;
});
const identities = EstRowMatch.identities(original, rows, key),
originalKeys = identities.original,
rowKeys = identities.current;
const contracts = new Map(original.map((row, index) => [originalKeys[index], row]));
const design = structuredClone(original),
excluded = structuredClone(original);
rows.forEach((row, index) => {
const old = contracts.get(rowKeys[index]) || row;
units.forEach((unit) => (row[`Contract${unit}`] = num(old[unit])));
const auto = row.EscAuto !== false;
const quantity = auto
? Math.max(num(row.EscPlanned), num(row.EscActual), num(row.EscProgress))
: num(row.EscManualQuantity ?? row.EscExcluded);
row.EscExcluded = quantity;
row.EscApplied = num(old.GN) - quantity;
if (num(row.Level) > 0 || special(row)) return;
const factor = num(old.GN) / (["%", "%"].includes(row.Unite) ? 100 : 1);
units.forEach((unit, i) => {
const A = num(row["A" + unit]),
B = num(row[unit]),
C = num(old[unit]);
const D = A && B ? floating(((B - A) / A) * 100, 2, 2) : 0;
let E = 0;
if (A && B && A >= C && B >= A) E = Math.trunc((C * D) / 100);
else if (A && B && A < C && B >= C) E = Math.trunc(B - C);
row["D" + unit] = D;
row["E" + unit] = E;
row["F" + unit] = C + E;
row["E" + components[i]] = Math.trunc(E * factor);
if (![1, 3].includes(num(row.CalcIndex))) {
row[unit] = C + E;
row[components[i]] = Math.trunc((C + E) * factor);
}
});
if (![1, 3].includes(num(row.CalcIndex))) row.TC = sum(row);
});
const current = new Map(rows.map((row, index) => [rowKeys[index], row]));
design.forEach((row, index) => {
if (num(row.Level) > 0 || special(row)) return;
const now = current.get(originalKeys[index]);
if (!now) return;
units.forEach((unit) => {
if (now["A" + unit] != null) row[unit] = num(now["A" + unit]);
});
});
excluded.forEach((row, index) => {
if (num(row.Level) > 0 || special(row)) return;
const now = current.get(originalKeys[index]),
quantity = num(now?.EscExcluded),
oldQuantity = num(row.GN);
if ([1, 3].includes(num(row.CalcIndex))) {
const fraction = oldQuantity ? quantity / oldQuantity : 0;
components.forEach((field) => (row[field] = Math.trunc(num(row[field]) * fraction)));
row.TC = sum(row);
}
row.GN = quantity;
});
function costCopy(source) {
const copy = EstNative.empty();
copy.tables.EstMainDat = source;
copy.tables.Wonga = project.baseline?.tables.Wonga || project.tables.Wonga;
copy.options = { ...project.options, SourceRefresh: false, TotalFix: false };
const calculated = EstNative.calculate(copy);
errors.push(...calculated.calculation.errors);
return calculated;
}
const adjusted = costCopy(rows),
contract = costCopy(structuredClone(original)),
designProject = costCopy(design),
excludedProject = costCopy(excluded);
const originalTotal = total(contract),
adjustedTotal = total(adjusted),
excludedTotal = total(excludedProject);
const target = project.tables.Wonga.find((row) => num(row.LinkIndex) === 55);
const designTotal =
num(project.options.EscDesignTotal) || num(target?.EsDesignCost) || total(designProject);
if (!designTotal)
errors.push("조사금액이 없습니다. 입찰 당시 단가 또는 조사 도급액을 입력하세요.");
const applied = originalTotal - excludedTotal;
const rate = designTotal
? floating(((adjustedTotal - originalTotal) / designTotal) * 100, 2, 2)
: 0;
return {
rows: adjusted.tables.EstMainDat,
direct: adjusted.calculation.direct,
wonga: adjusted.tables.Wonga,
contractWonga: contract.tables.Wonga,
excludedWonga: excludedProject.tables.Wonga,
designTotal,
contractTotal: originalTotal,
adjustedTotal,
excludedTotal,
applied,
rate,
adjustment: Math.trunc((applied * rate) / 100),
errors: [...new Set(errors)],
};
}
return { calculate };
})();