feat(est): compare design change cost items

This commit is contained in:
2026-11-07 10:29:31 +09:00
parent 5f9b5432ec
commit eb3dba0e9e
5 changed files with 100 additions and 1 deletions
@@ -1,6 +1,42 @@
from test_est_rea_parity import run
def test_design_change_costs_include_duplicate_new_and_deleted_cost_rows():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.tables.Wonga=[
{Gubun:'A',Name:'first',Cost:200},{Gubun:'A',Name:'second',Cost:60},
{Gubun:'C',Name:'new',Cost:25}];
p.baseline={name:'old',tables:{EstMainDat:[],Wonga:[
{Gubun:'A',Name:'first',Cost:100},{Gubun:'A',Name:'second',Cost:50},
{Gubun:'B',Name:'removed',Cost:30}]}};
const before=JSON.stringify(p), rows=EstBusiness.costChanges(p);
const output=EstForms.data('change-costs',p);
const node={innerHTML:''};globalThis.EstApp={esc:x=>String(x??''),number:x=>String(x??0),byId:()=>node};
EstExtra.render({project:p,view:'change'});
return {rows,output,html:node.innerHTML,same:before===JSON.stringify(p)};
})()""",
)
assert result["same"]
assert [row["difference"] for row in result["rows"]] == [100, 10, 25, -30]
assert result["output"]["rows"] == result["rows"]
assert "removed" in result["html"]
def test_stored_original_costs_remain_attached_to_each_duplicate_row():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.tables.Wonga=[
{Gubun:'A',Name:'new',Cost:10},{Gubun:'A',Name:'existing',Cost:50,Cost_:30}];
return EstBusiness.costChanges(p);
})()""",
)
assert [row["originalCost"] for row in result] == [0, 30]
assert [row["difference"] for row in result] == [10, 20]
def test_change_view_includes_named_rows_without_codes():
result = run(
"math",
+45
View File
@@ -105,6 +105,50 @@ const EstBusiness = (() => {
});
return changes;
}
function costChanges(project) {
const current = project.tables.Wonga || [];
if (!project.baseline) {
if (!current.some((row) => row.Cost_ != null)) return [];
return current.map((row) => ({
Gubun: row.Gubun,
Name: row.Name,
originalCost: num(row.Cost_),
changedCost: num(row.Cost),
difference: num(row.Cost) - num(row.Cost_),
}));
}
const old = project.baseline.tables.Wonga || [];
function keyed(rows) {
const counts = new Map();
return rows.map((row) => {
const identity = JSON.stringify(row.Gubun ? ["code", row.Gubun] : ["name", row.Name || ""]);
const occurrence = counts.get(identity) || 0;
counts.set(identity, occurrence + 1);
return { row, key: JSON.stringify([identity, occurrence]) };
});
}
const previous = new Map(keyed(old).map(({ row, key }) => [key, row]));
const rows = keyed(current).map(({ row, key }) => {
const saved = previous.get(key);
previous.delete(key);
return {
Gubun: row.Gubun,
Name: row.Name,
originalCost: num(saved?.Cost),
changedCost: num(row.Cost),
difference: num(row.Cost) - num(saved?.Cost),
};
});
for (const row of previous.values())
rows.push({
Gubun: row.Gubun,
Name: row.Name,
originalCost: num(row.Cost),
changedCost: 0,
difference: -num(row.Cost),
});
return rows;
}
function bid(project, rates) {
const next = copy(project);
for (const key of ["HeadMainDat", "EstMainDat"])
@@ -298,6 +342,7 @@ const EstBusiness = (() => {
return {
baseline,
changes,
costChanges,
bid,
original,
progress,
+11 -1
View File
@@ -70,7 +70,17 @@ const EstExtra = (() => {
number(row.TC),
number(row.difference),
]),
),
) +
table(
["원가 구분", "비목", "당초 금액", "변경 금액", "증감"],
EstBusiness.costChanges(project).map((row) => [
esc(row.Gubun),
esc(row.Name),
number(row.originalCost),
number(row.changedCost),
number(row.difference),
]),
),
project.baseline
? `당초: ${esc(project.baseline.name)}. 당초 자료는 별도 사본으로 보존합니다.`
: changes.some((row) => row.originalSource === "file")
+7
View File
@@ -1,6 +1,11 @@
const EstForms = (() => {
const common = ["Code", "Name", "Size", "Unite"];
function data(id, project, state = {}) {
if (id === "change-costs")
return {
columns: ["Gubun", "Name", "originalCost", "changedCost", "difference"],
rows: EstBusiness.costChanges(project),
};
if (id === "annual-summary") {
const output = EstBusiness.annual(project, false);
return {
@@ -282,6 +287,8 @@ const EstForms = (() => {
TotalCost: "누계 금액",
adjustedCost: "조정 금액",
excludedCost: "제외 금액",
originalCost: "당초 금액",
changedCost: "변경 금액",
TargetCode: "연결 내역",
TU: "단가",
TC: "금액",
+1
View File
@@ -141,6 +141,7 @@ const EstReport = (() => {
{ Index: "escalation-summary", Name: "물가변동 내역서", Name2: "물가변동 내역서" },
{ Index: "escalation-costs", Name: "물가변동 원가계산서", Name2: "물가변동 원가계산서" },
{ Index: "annual-summary", Name: "연차 배분표", Name2: "연차 배분표" },
{ Index: "change-costs", Name: "설계변경 원가 증감표", Name2: "설계변경 원가 증감표" },
);
const table = EstApp.state.project.tables[EstApp.state.view];
const s = setting(),