feat(est): preserve mismatched quantity results
This commit is contained in:
@@ -120,6 +120,31 @@ def test_estx_quantity_item_labels_round_trip_when_sample_exists():
|
||||
}
|
||||
|
||||
|
||||
def test_estx_quantity_description_preserves_mismatched_result_when_sample_exists():
|
||||
sample = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/main.estx")
|
||||
if not sample.exists():
|
||||
pytest.skip("installed EST sample unavailable")
|
||||
script = """const fs=require('fs'),m=require('./tools/est-test/import-estx.cjs'),e=require('./tools/est-test/export-estx.cjs'),w=require('./tools/est-test/export-quantity.cjs');
|
||||
const bytes=fs.readFileSync(process.argv[1]),p=m.importEstx(bytes),base=m.importEstx(bytes),sheet=p.quantitySheets.find(s=>s.Code==='N0000000083');
|
||||
sheet.rows[0].LineData=sheet.rows[0].LineData.replace('석축쌓기','석축공사');
|
||||
const q=m.importEstx(e.exportEstx(p)),saved=q.quantitySheets.find(s=>s.Code===sheet.Code);
|
||||
sheet.rows[3].LineData=sheet.rows[3].LineData.replace('220','221');let rejected=false;
|
||||
try{w.updateQuantities(p,base,e.cp949,e.memory)}catch{rejected=true}
|
||||
sheet.rows[3].LineData=sheet.rows[3].LineData.replace('221','220');
|
||||
sheet.rows[5].LineData=sheet.rows[5].LineData.replace('286','287');let markerRejected=false;
|
||||
try{w.updateQuantities(p,base,e.cp949,e.memory)}catch{markerRejected=true}
|
||||
console.log(JSON.stringify({text:saved.rows[0].LineData,quantity:saved.items[4].GN,
|
||||
preserved:JSON.stringify(saved.rows.slice(1))===JSON.stringify(base.quantitySheets.find(s=>s.Code===sheet.Code).rows.slice(1)),rejected,markerRejected}));"""
|
||||
result = json.loads(
|
||||
subprocess.check_output(["node", "-e", script, str(sample)], cwd=ROOT, timeout=45).decode(
|
||||
"utf-8"
|
||||
)
|
||||
)
|
||||
assert result["text"].startswith("석축공사")
|
||||
assert result["quantity"] == 286
|
||||
assert result["preserved"] and result["rejected"] and result["markerRejected"]
|
||||
|
||||
|
||||
def test_quantity_document_edit_across_character_styles_preserves_tags():
|
||||
script = r"""const q=require('./tools/est-test/native-quantity.cjs'),w=require('./tools/est-test/export-quantity.cjs');
|
||||
const doc='<cs nr=1/><cs nr=2/><div><c nr=1/>abc<c nr=2/>def<c nr=1/>ghi</div>';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
## Codex · EST 독립 테스트 앱 (2026-11-04)
|
||||
- [x] 계산 불일치 수량산출서의 계산값을 바꾸지 않는 문구 수정 저장 → 원본 수량·표지 보존과 수량 변경 차단 확인.
|
||||
- 자체 검증: main.estx N0000000083 문구를 수정해 저장·재열기한 뒤 원래 수량 286과 다른 행 보존. 산식 계산값·결과 표지 변경 차단, 기존 산식 저장 시험 통과.
|
||||
- [x] 삭제된 Excel 연결 대상의 행 식별자 재사용 방지 → 새 행·붙여넣기·Excel 가져오기 오연결 차단.
|
||||
- 자체 검증: 삭제된 2번을 예약해 Edge 추가·붙여넣기가 3·4번을 사용. Excel 가져오기 오연결 차단·연결 제거 후 적용 확인. 관련 시험 35개 통과, openpyxl 경고 8건.
|
||||
- [x] Excel 수량 연결을 전체 자료 Excel에 포함 → 재가져오기와 잘못된 내역 연결의 전체 적용 차단 확인.
|
||||
|
||||
@@ -61,6 +61,7 @@ Ctrl+S는 입력 중인 셀도 확정한 뒤 저장합니다. 연속 저장 요
|
||||
|
||||
원본 ESTX의 기존 수량산출 항목은 품명·규격을 수정해 ESTX에 저장할 수 있습니다. 연결 변경과 새 항목 추가·삭제는 계속 JSON으로 보관합니다.
|
||||
품명·규격만 변경한 경우 기존 산식의 저장 수량과 재계산 수량이 다르더라도 산식과 저장 수량을 그대로 유지합니다.
|
||||
산출서 문구를 수정해도 계산 결과와 결과 표지가 바뀌지 않으면 원래 저장 수량을 보존합니다. 원본 결과가 재계산값과 다른 문서에서 계산 결과를 바꾸는 편집은 JSON으로 보관해야 합니다.
|
||||
|
||||
재계산 메뉴의 수량 반영도 현재 선택한 산출서 또는 직접 작성 수식표를 사용합니다. 반영 전에 모든 연결 대상과 수식을 검사하며, 기존 원본 연결 데이터는 그대로 보관합니다.
|
||||
|
||||
|
||||
@@ -176,6 +176,31 @@ function updateQuantities(project, base, cp949, memory) {
|
||||
if (calculated.errors.length || baseline.errors.length)
|
||||
throw Error(`수량산출서 계산 오류: ${calculated.errors[0] || baseline.errors[0]}`);
|
||||
const markerCount = originals[i].rows.reduce((total, row) => total + row.markers.length, 0);
|
||||
const results = (value) => ({
|
||||
checks: value.checks.map(({ name, calculated }) => ({ name, calculated })),
|
||||
items: value.items.map(({ Code, GN }) => ({ Code, GN })),
|
||||
});
|
||||
const resultMarkers = (sheet) =>
|
||||
sheet.rows.map((row) => [...row.LineData.matchAll(/\x12[^\x12]*\x12/g)].map((m) => m[0]));
|
||||
if (
|
||||
baseline.checks.length === markerCount &&
|
||||
calculated.checks.length === markerCount &&
|
||||
baseline.checks.every((value) => Number.isFinite(value.calculated)) &&
|
||||
calculated.checks.every((value) => Number.isFinite(value.calculated)) &&
|
||||
same(resultMarkers(originals[i]), resultMarkers(sheets[i])) &&
|
||||
same(results(baseline), results(calculated))
|
||||
) {
|
||||
if (!same(row.MulList, oldRow.MulList)) throw Error("수량산출서 목록 데이터 충돌");
|
||||
if (!same(sheets[i].items, originals[i].items))
|
||||
row.MulList = {
|
||||
binary: memory(Buffer.from(row.MulList.binary, "base64"), sheets[i].items).toString(
|
||||
"base64",
|
||||
),
|
||||
};
|
||||
const output = cp949(document);
|
||||
row.Editor = { binary: (compressed ? zlib.deflateSync(output) : output).toString("base64") };
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
baseline.checks.length !== markerCount ||
|
||||
calculated.checks.length !== markerCount ||
|
||||
|
||||
Reference in New Issue
Block a user