feat(est): compare design change cost items
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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: "금액",
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user