fix(est): compare imported original contract values

This commit is contained in:
2026-11-05 13:46:42 +09:00
parent c6118c97ed
commit 9a4070fae5
5 changed files with 49 additions and 3 deletions
+36
View File
@@ -172,3 +172,39 @@ def test_unlinked_text_price_does_not_inherit_the_previous_rows_source():
assert resources["M"]["quantity"] == 1
assert resources["M"]["amount"] == 150
assert resources["MZZZZZZZZZZ"]["amount"] == 100
def test_change_comparison_uses_original_file_values_without_overwriting_a_baseline():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.tables.EstMainDat=[
{PkID:1,Code:'R',GN:3,TC:150,GN_:2,TC_:100},
{PkID:2,Code:'Z',GN:1,TC:10,GN_:0,TC_:0},
{PkID:3,Code:'N',GN:1,TC:20}];
const stored=EstBusiness.changes(p);
p.baseline={name:'explicit',tables:{EstMainDat:[{PkID:1,Code:'R',GN:4,TC:200}]}};
return {stored,explicit:EstBusiness.changes(p),unchanged:p.tables.EstMainDat[0].TC_};
})()""",
)
assert result["stored"][0]["originalGN"] == 2
assert result["stored"][0]["originalTC"] == 100
assert result["stored"][0]["difference"] == 50
assert result["stored"][0]["originalSource"] == "file"
assert not result["stored"][1]["NewItem"]
assert result["stored"][2]["NewItem"]
assert result["explicit"][0]["originalTC"] == 200
assert result["explicit"][0]["difference"] == -50
assert result["explicit"][1]["NewItem"]
assert result["unchanged"] == 100
def test_original_numeric_fields_reject_invalid_saved_values():
result = run(
"math",
"""(()=>{
const p=EstNative.empty();p.tables.EstMainDat=[{GN:1,GN_:'invalid'}];
try {EstModel.validate(p);return false;}catch(error){return error.message;}
})()""",
)
assert "GN_" in result
+2
View File
@@ -28,6 +28,8 @@
동원 집계는 비목별 낙찰률과 단위환산을 하위 산근·일위대가에도 전달합니다. 연결 단가가 없는 금액 입력분은 원본 전용 코드로 따로 합산하고, 장비 시간으로 바꿀 수 없는 경비는 `제외금액` 단위로 보존합니다. 산근에서 연결을 해제한 단가는 앞 행의 원천을 가져오지 않습니다.
설계변경 비교는 웹에서 확정한 당초 사본이 없을 때 원본 파일의 당초 수량·금액을 사용합니다. 별도 당초 확정 사본이 있으면 그 사본이 우선합니다. 원본 당초 전체 자료와 원가 서식의 활성 선택을 자동 추정하지는 않습니다.
**전체 원본 동등성은 아직 확보하지 못했습니다.** 기성·물가변동·연차 등은 분석 분기와 합성 시나리오를 시험했으며 원본 업무 샘플 대조는 없습니다. 원본 화면 실행 비교는 못했습니다. 원본 페이지·도면 배치, CAD/VEC0650 편집, 원본 인쇄 서식, Excel/XML/JDL 변환, ESTX 수정 저장은 미구현입니다. 원본 대체품의 완료 판정으로 보지 않습니다.
검사:
+7 -1
View File
@@ -34,7 +34,12 @@ const EstBusiness = (() => {
function changes(project) {
const old = project.baseline?.tables.EstMainDat || [];
return project.tables.EstMainDat.map((row, index) => {
const original = old.find((r, i) => rowKey(r, i) === rowKey(row, index));
const saved = old.find((r, i) => rowKey(r, i) === rowKey(row, index));
const stored =
!project.baseline && ["Code_", "Name_", "GN_", "TC_"].some((key) => row[key] != null)
? { GN: row.GN_, TC: row.TC_ }
: null;
const original = saved || stored;
return {
key: rowKey(row, index),
Code: row.Code,
@@ -45,6 +50,7 @@ const EstBusiness = (() => {
originalTC: num(original?.TC),
difference: num(row.TC) - num(original?.TC),
NewItem: !original,
originalSource: saved ? "baseline" : stored ? "file" : null,
};
});
}
+3 -1
View File
@@ -75,7 +75,9 @@ const EstExtra = (() => {
),
project.baseline
? `당초: ${esc(project.baseline.name)}. 당초 자료는 별도 사본으로 보존합니다.`
: "현재 작업을 저장한 뒤 당초 내역을 확정하세요.",
: changes.some((row) => row.originalSource === "file")
? "원본 파일에 저장된 당초 수량·금액과 비교합니다."
: "현재 작업을 저장한 뒤 당초 내역을 확정하세요.",
);
} else if (view === "progress") {
state.roundId ||= project.progress[0]?.id;
+1 -1
View File
@@ -269,7 +269,7 @@ const EstModel = (() => {
if (["__proto__", "constructor", "prototype"].includes(key))
throw Error("허용하지 않는 필드 이름");
if (
numeric.has(key) &&
(numeric.has(key) || (key.endsWith("_") && numeric.has(key.slice(0, -1)))) &&
value != null &&
(typeof value !== "number" ||
!Number.isFinite(value) ||