From ce0529ff2c5dc2bee54095d780e0f7876b84d42b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 21 Sep 2026 19:58:04 +0900 Subject: [PATCH] =?UTF-8?q?fix(M01):=20=EB=AA=AB=EC=9D=B4=20=EB=AA=A8?= =?UTF-8?q?=EB=91=90=200=20=EC=9D=B8=20=EC=9E=A5=EB=B9=84=20=EC=A4=84?= =?UTF-8?q?=EC=9D=B4=20=EC=9D=BD=EB=8A=94=20=EC=8B=9D=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=82=AC=EB=9D=BC=EC=A7=80=EB=8D=98=20=EA=B2=83=20=E2=80=94=20?= =?UTF-8?q?0=20=EC=9B=90=20=ED=95=9C=20=EC=A4=84=EA=B3=BC=20=EA=B9=8C?= =?UTF-8?q?=EB=8B=AD=EC=9C=BC=EB=A1=9C=20=EB=82=A8=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj --- resources/master_data/ref/_검증_텍스트_수식.md | 4 ++++ resources/master_data/scripts/master_text.py | 17 ++++++++++++----- resources/tester/test_m01_text.py | 11 +++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/resources/master_data/ref/_검증_텍스트_수식.md b/resources/master_data/ref/_검증_텍스트_수식.md index 9e1e7427..e0992513 100644 --- a/resources/master_data/ref/_검증_텍스트_수식.md +++ b/resources/master_data/ref/_검증_텍스트_수식.md @@ -47,6 +47,10 @@ - `GC001091`·`GC001096` 진공흡입 준설차 13톤 · 물탱크(살수차) 5,500ℓ · `GC001092` 트럭탑재형 크레인 5톤 · `GC001099` 진공흡입 준설차 13톤 - `GF000137` 트럭 10.5ton · `GF000241` 굴착기(무한궤도) 0.6㎥ +### 고친 뒤 (2026-09-21) + +`master_text.py` 에 몫 나누기를 `_shares()` 한 자리로 모아, 몫이 전부 0 이면 첫 비목에 0 원 한 줄을 남기고 까닭(「수량 0 — 이 조건에서는 안 쓰는 줄」)을 붙임 — 같은 대조를 다시 돌려 **③ 어긋남 83줄 → 0** · 나머지(①②④·터짐)도 그대로 0(1,291개 전부). + ## 딸린 사실 - 비목이 나뉜 하위 로직 줄은 비목마다 한 줄씩 같은 이름으로 나옴(계약대로 · 어긋남 아님). diff --git a/resources/master_data/scripts/master_text.py b/resources/master_data/scripts/master_text.py index 6b6c33d9..17cc4ddf 100644 --- a/resources/master_data/scripts/master_text.py +++ b/resources/master_data/scripts/master_text.py @@ -86,10 +86,10 @@ def _env_of(master, row: dict, given: dict, depth: int = 0) -> dict: def _why(item: dict, line: dict) -> str: """단가를 못 구했거나 0 인 줄의 까닭 한 마디.""" - if line["단가"] not in (0, None): - return "" if line["수량"] == 0: return "수량 0 — 이 조건에서는 안 쓰는 줄" + if line["단가"] not in (0, None): + return "" where = item.get("요소") where = "재료 고르기 조건" if isinstance(where, dict) else f"「{where}」" return f"단가 0 — {where} 값이 아직 없음" @@ -101,6 +101,15 @@ def _label(item: dict, line: dict) -> str: return f"{name}({spec})" if spec else name +def _shares(line: dict) -> list[tuple[str, Decimal]]: + """글로 적을 (비목, 몫) — 비목이 나뉜 로직 줄은 몫이 없는 비목을 건너뜀. + 몫이 전부 0 이면 호표 줄이 사라지지 않게 첫 비목에 0 원 한 줄을 남김.""" + parts = list(line["비목"].items()) + if len(parts) <= 1: + return parts + return [(part, money) for part, money in parts if money != 0] or parts[:1] + + def _line_text(item: dict, line: dict, env: dict, master, part: str | None) -> str: """「단가 * 수량식 = 금액」 — 비목이 나뉜 로직 줄은 그 비목 몫만.""" qty = render(mf.parse(item["수량"]), env, master) @@ -134,9 +143,7 @@ def lines(files: dict, key: str, given: dict) -> dict: env["줄"] = {r["이름"]: r["금액"] for r in shown if r["이름"]} items = row.get("호표") or [] for item, line in zip(items, shown): - for part, money in line["비목"].items(): - if money == 0 and len(line["비목"]) > 1: - continue # 비목이 나뉜 로직 줄 — 몫이 없는 비목엔 안 적음 + for part, money in _shares(line): split = part if len(line["비목"]) > 1 else None one = { "이름": _label(item, line), diff --git a/resources/tester/test_m01_text.py b/resources/tester/test_m01_text.py index f1839073..eed49ada 100644 --- a/resources/tester/test_m01_text.py +++ b/resources/tester/test_m01_text.py @@ -25,6 +25,7 @@ REAL = store.FOLDER STACK = "GF000219" # 13-4-1 메쌓기(인력) — 증가율이 걸린 줄 FORM = "GF000160" # 12-4 합판거푸집 — 재료 여럿 · 수량 0 줄 PUMP = "GF000182" # 12-17-1 펌프카 타설 — 하위 로직이 세 비목에 걸리고 덧줄이 있음 +IDLE = "GC000999" # 일반전정 — 세 비목에 걸린 장비 줄이 수량 0 이라 몫이 모두 0 @pytest.fixture @@ -95,6 +96,16 @@ def test_펌프카는_하위로직이_비목마다_한_줄씩이고_덧줄이_ assert extra["글"].endswith(f"= {mt.fmt(Decimal(str(extra['금액'])))}") and "%" in extra["글"] +def test_몫이_모두_0인_장비_줄도_글에_남는다(client: TestClient) -> None: + got, calc = _both(client, IDLE) + idle = [one for one in _all_lines(got) if one["이름"] == "고소작업차"] + assert len(idle) == 1 # 비목 셋 몫이 다 0 이라도 줄이 사라지지 않음 + assert Decimal(str(idle[0]["금액"])) == 0 and "수량 0" in idle[0]["까닭"] + assert idle[0]["글"].endswith(" * 0 = 0") + for group in got["groups"]: + assert Decimal(str(group["소계"])) == Decimal(str(calc["sums"][group["비목"]])) + + def test_멈추는_로직은_까닭_한_줄(client: TestClient) -> None: got = client.post("/api/m01/text", json={"key": STACK, "inputs": {}}).json() assert got["ok"] is False and "입력" in got["reason"]