From 1d02b0205af09de813904e3e1ddc381405ab8ee7 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 7 Nov 2026 08:14:32 +0900 Subject: [PATCH] fix(est): block missing quantity markers --- .../tester/test_est_quantity_workflow.py | 21 +++++++++++++++++++ tools/est-test/README.md | 2 ++ tools/est-test/native-quantity.cjs | 8 ++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/resources/tester/test_est_quantity_workflow.py b/resources/tester/test_est_quantity_workflow.py index f09de4c74..bbe55e142 100644 --- a/resources/tester/test_est_quantity_workflow.py +++ b/resources/tester/test_est_quantity_workflow.py @@ -160,3 +160,24 @@ def test_target_row_ids_support_blank_and_duplicate_codes_for_both_modes(): assert result["manual"] == [1, 7, 4] assert result["sheet"] == [[3, 4], [2, 7], [1, 5]] assert result["error"] + + +def test_missing_or_extra_result_markers_block_quantity_application(): + result = run( + "math", + """(()=>{ + const p=EstNative.empty();p.tables.EstMainDat=[{PkID:1,Code:'X',GN:1}]; + p.quantitySheets=[{Code:'Q',options:{},rows:[{LineData:'2*3 = \\x120\\x12',markers:['r1']}], + items:[{Code:'r1',GN:9,TargetKey:'id:1'}]}]; + const sheet=p.quantitySheets[0],valid=EstQuantity.calculate(sheet); + const bad=[];for(const line of ['2*3 = 0','2*3 = \\x120\\x12 + \\x120\\x12']){ + sheet.rows[0].LineData=line;let blocked=false; + try{EstQuantity.applyTotals(p,EstQuantity.totals(p,'Q'))}catch{blocked=true} + bad.push({blocked,errors:EstQuantity.calculate(sheet).errors,quantity:p.tables.EstMainDat[0].GN}); + } + return {valid,bad}; + })()""", + ) + assert result["valid"]["errors"] == [] + assert result["valid"]["items"][0]["GN"] == 6 + assert all(row["blocked"] and row["errors"] and row["quantity"] == 1 for row in result["bad"]) diff --git a/tools/est-test/README.md b/tools/est-test/README.md index ed2036eb9..4fa4b9024 100644 --- a/tools/est-test/README.md +++ b/tools/est-test/README.md @@ -34,6 +34,8 @@ Ctrl+S는 입력 중인 셀도 확정한 뒤 저장합니다. 연속 저장 요 수량산출서 인쇄 서식에는 직접 작성한 수식표와 산출서의 산식, 계산 수량, 연결 내역이 함께 표시됩니다. 계산할 수 없는 수식은 오류를 표시합니다. +산출 행의 결과 표지 개수가 연결 정보와 다르면 계산 오류로 표시하며, 기존 저장 수량을 내역에 반영하지 않습니다. 화면이나 Excel에서 수식을 수정할 때 결과 표지와 연결 항목을 유지하세요. + ## 검증과 남은 범위 기계 성분·합계 48건, 일위 41건, 내역 37건, 산출 결과 118건과 호표 8건, 원가 수식 23건을 대조합니다. 원가 도급액 고정 반복 차이 `324 → -32 → 3 → 0`을 재현합니다. 단가 갱신 후 전체 재계산과 반복 계산의 안정성도 시험합니다. diff --git a/tools/est-test/native-quantity.cjs b/tools/est-test/native-quantity.cjs index 3abea1d08..85a409322 100644 --- a/tools/est-test/native-quantity.cjs +++ b/tools/est-test/native-quantity.cjs @@ -56,6 +56,12 @@ const EstQuantity = (() => { return { Code: code, Name: name, rows, items, options }; } function calculate(sheet) { + const markerErrors = sheet.rows.flatMap((row, index) => { + const count = [...String(row.LineData || "").matchAll(/\x12([-\d.,]+)\x12/g)].length; + return count === (row.markers || []).length + ? [] + : [`${index + 1}행: 결과 표지 수가 다릅니다.`]; + }); const input = [ { Index: 1, Code: sheet.Code, LineData: "" }, ...sheet.rows.map((row) => { @@ -110,7 +116,7 @@ const EstQuantity = (() => { rows: result.rows.slice(1), items: sheet.items.map((item) => ({ ...item, GN: values.get(item.Code) ?? item.GN })), checks, - errors: result.errors, + errors: [...result.errors, ...markerErrors], }; } function manual(items) {