diff --git a/resources/tester/test_est_native_export.py b/resources/tester/test_est_native_export.py index 53ea53345..55e199385 100644 --- a/resources/tester/test_est_native_export.py +++ b/resources/tester/test_est_native_export.py @@ -97,11 +97,14 @@ def test_estx_quantity_item_labels_round_trip_when_sample_exists(): script = """const fs=require('fs'),m=require('./tools/est-test/import-estx.cjs'),e=require('./tools/est-test/export-estx.cjs'); const p=m.importEstx(fs.readFileSync(process.argv[1])),before=structuredClone(p.quantitySheets),sheet=p.quantitySheets[0]; sheet.items[0].Name='changed name';sheet.items[0].Size='changed size'; + const mismatch=p.quantitySheets.find(s=>s.Code==='N0000000083');mismatch.items[4].Name='preserved mismatch'; const q=m.importEstx(e.exportEstx(p)),item=q.quantitySheets[0].items[0]; + const restored=q.quantitySheets.find(s=>s.Code==='N0000000083'); const other=JSON.stringify(q.quantitySheets[0].items.slice(1))===JSON.stringify(before[0].items.slice(1)); - const rest=JSON.stringify(q.quantitySheets.slice(1))===JSON.stringify(before.slice(1)); + const rest=JSON.stringify(q.quantitySheets.filter(s=>s.Code!==sheet.Code && s.Code!==mismatch.Code))===JSON.stringify(before.filter(s=>s.Code!==sheet.Code && s.Code!==mismatch.Code)); + const preserved=restored.items[4].Name==='preserved mismatch' && restored.items[4].GN===286 && JSON.stringify(restored.rows)===JSON.stringify(before.find(s=>s.Code===mismatch.Code).rows); p.quantitySheets[0].items[0].TargetCode='new target';let rejected=false;try{e.exportEstx(p)}catch{rejected=true} - console.log(JSON.stringify({name:item.Name,size:item.Size,other,rest,rejected}));""" + console.log(JSON.stringify({name:item.Name,size:item.Size,other,rest,preserved,rejected}));""" result = json.loads( subprocess.check_output(["node", "-e", script, str(sample)], cwd=ROOT, timeout=45).decode( "utf-8" @@ -112,6 +115,7 @@ def test_estx_quantity_item_labels_round_trip_when_sample_exists(): "size": "changed size", "other": True, "rest": True, + "preserved": True, "rejected": True, } diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md index 2b8d70e0f..3689a8573 100644 --- a/tools/est-test/PLAN.md +++ b/tools/est-test/PLAN.md @@ -1,4 +1,6 @@ ## Codex · EST 독립 테스트 앱 (2026-11-04) +- [x] 기존 계산 불일치 수량산출서도 품명·규격만 바꿀 때 원본 수량 유지 → 실자료 재열기 확인. + - 자체 검증: 설치 main.estx N0000000083의 저장 286·재계산 100.1 불일치 항목에서 품명만 변경한 뒤 원본 수량 286·문서·다른 문서 보존 확인. 저장·서식 시험 2개 통과. - [x] 기존 수량산출 항목의 품명·규격을 ESTX에 저장 → 재열기·다른 항목 보존·연결 변경 차단 확인. - 자체 검증: 설치 main.estx 기존 항목의 품명·규격 저장·재열기, 다른 항목·문서 보존과 연결 변경 차단 확인. 저장·수량 관련 시험 22개 통과. - [x] 인쇄 서식의 상·하·좌·우 여백 개별 설정과 ESTX 저장 → 기존 단일 여백 호환·실제 서식 재읽기 확인. diff --git a/tools/est-test/README.md b/tools/est-test/README.md index 3b6ed378c..a3a897528 100644 --- a/tools/est-test/README.md +++ b/tools/est-test/README.md @@ -57,6 +57,7 @@ Ctrl+S는 입력 중인 셀도 확정한 뒤 저장합니다. 연속 저장 요 수량 화면에서 새 산출서를 만들고 이름과 산출 항목의 품명·규격을 편집할 수 있습니다. `산출 행 추가`로 결과 표지가 연결된 행과 항목을 함께 만든 뒤 수식을 입력하고, 연결 내역코드를 지정해 계산 수량을 내역에 반영합니다. 행 아래 삽입, 위·아래 이동과 산출 행·산출서 삭제도 가능하며, 이 구조 변경은 JSON 저장과 다시 열기를 지원합니다. 기존 연결은 내역코드를 비워 해제할 수 있습니다. 원본 ESTX의 기존 수량산출 항목은 품명·규격을 수정해 ESTX에 저장할 수 있습니다. 연결 변경과 새 항목 추가·삭제는 계속 JSON으로 보관합니다. +품명·규격만 변경한 경우 기존 산식의 저장 수량과 재계산 수량이 다르더라도 산식과 저장 수량을 그대로 유지합니다. 재계산 메뉴의 수량 반영도 현재 선택한 산출서 또는 직접 작성 수식표를 사용합니다. 반영 전에 모든 연결 대상과 수식을 검사하며, 기존 원본 연결 데이터는 그대로 보관합니다. diff --git a/tools/est-test/export-quantity.cjs b/tools/est-test/export-quantity.cjs index a3dfbc924..c292e44d8 100644 --- a/tools/est-test/export-quantity.cjs +++ b/tools/est-test/export-quantity.cjs @@ -162,6 +162,15 @@ function updateQuantities(project, base, cp949, memory) { const text = new TextDecoder("euc-kr", { fatal: true }).decode(bytes); if (!cp949(text).equals(bytes)) throw Error("수량산출서 원본 인코딩 보존 불가"); let document = editDocument(text, originals[i], sheets[i]); + if (same(sheets[i].rows, originals[i].rows)) { + if (!same(row.MulList, oldRow.MulList)) throw Error("수량산출서 목록 데이터 충돌"); + row.MulList = { + binary: memory(Buffer.from(row.MulList.binary, "base64"), sheets[i].items).toString( + "base64", + ), + }; + continue; + } const baseline = calculateQuantity(originals[i]), calculated = calculateQuantity(sheets[i]); if (calculated.errors.length || baseline.errors.length)