Files
Aislo/resources/tester/test_812_2_match_logic.py
T
eomsangdonandClaude Opus 5.5 28acddb4b9 feat(812-11): 연결 찾기 값 기준 넓힘 — 같은 기종 규격 · 수량 = 참고 · 바꾸기 때 기계 줄 갈아 끼움 · 기계 작업 갈래
- 새 M02_Doc_Match_Value — 같은 기종(이름 머리 + 괄호 낱말 · 조합 구성) 규격만 다름 = 참고 「규격」 + 바꿈 · 같은 자원 수량 다름 = 참고 「수량 끝자리」 · 「품 숫자」 · 「수량」 · 같은 배 두 줄 넘음 = 단위 환산(로직) · 기계 한 묶음 + 작업량 식 = 「기계 작업」(수량 · 규격까지 같은 기초만 확정) · 작업량 틀 꼴 참고 · 옵션 값으로 못 가름 = 「옵션 확인」
- M02_Doc_Match — 사실에 단가 기호 · 규격 · 수량 글 · 조합 표지 · 값 참고 적은 조합 먼저 · 선택 글 근거 쉼표 무시(D1,800 = D1800) · 같은 자원 아닌 수량 짝 = 그 로직 까닭
- M02_Doc_MatchSk — 바꾸기 뒤 사본 문서 기계 입력(원문번호) · 줄 이름 · 규격 · 묶음 제목 = 가져온 규격(수식 길 저장) · 되돌리기 = 보관 몸 수식 사본 그대로
- 띠 — 기계 작업 「기계 한 줄 단가산출 — 그대로 씀 · 값은 [단가 갱신]으로 우리 값」 · 참고 요약에 규격 · 수량 · 옵션 확인
- helper_810_4_sweep — 과녁 = 부품 뺀 문서(화면과 같음)
- 시험 고침: 810_4 단위 환산 = 같은 배 두 줄(한 줄만 배 = 수량 값) · 812_2 기계 규격 = 무한궤도 ↔ 타이어(같은 기종 규격 = 값)
- 전수 2,220: 확정 184 → 337 · 근접 576 → 848 · 없음 1,460 → 837 · 기계 작업 198 · 확정 다시 셈 다름 0 · 목록 _목록_812-11_연결판정.xlsx

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 00:11:55 +09:00

184 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""812-2 지킴 — 연결 찾기 확정 = 로직(요구 712) · 값 차이 = 참고(`M02_Doc_Match_Note`).
(a) 단가만 다름 = 확정 + 참고 「단가 차이」(원파일 기계경비 묶음 ↔ 우리 기계 = 이름 종류 같을 때) ·
끝수만 다름 = 확정 + 참고 「끝수」
(b) 로직 차이 = 다른 항 — 율 대상 · 기계 규격 · 노임 종류(「자원」) · 산출 단가 · 비목
(c) 율 = 비율 — 거창 합판거푸집(블록 41): 가져온 「주자재소계 × 9 %」 = M01 소모자재 9 % 짝 · 율_2 1 % 재료비 ↔
공구손료 1 % 경비 = 「비목」 · 대전 합판 단가 = 참고
(d) 요구 704 배수관부설 D=800 ↔ GF000179 = 여전히 근접(단위 환산 × 6 · 기계 규격 · 율 줄)
(e) 전수(S8122_ALL=1) — 2,220 블록 · 확정 다시 셈 같음 · 근접 까닭에 단가 차이 · 끝수 없음 · 확정 참고 있음
원파일 없으면 (c) · (d) · (e) skip(다른 PC).
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
from decimal import Decimal as D
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
for p in (ROOT, HERE):
if str(p) not in sys.path:
sys.path.insert(0, str(p))
from M02_MasterTemplete import M02_Doc_Match as dm # noqa: E402
TOT = {"노무비": 9, "재료비": 0, "경비": 0, "계": 9}
def _line(name, kind, qty, price, cost="노무비", code=""):
q, p = D(qty), D(price)
return {"번": 0, "이름": name, "갈래": kind, "코드": code, "수량": dm._key(q),
"단가": dm._key(p), "비목": {cost: dm._key(q * p)}, "금액": dm._key(q * p), "합밖": False} # fmt: skip
def _rate(name, rate, target=(("노임", "노무비"),), cost="경비"):
return {"번": 0, "이름": name, "갈래": "율", "코드": "", "수량": None, "단가": None,
"비목": {cost: D(1)}, "금액": D(1), "합밖": False, "율": D(rate), "대상": frozenset(target)} # fmt: skip
A = [_line("인부", "노임", "0.04", "100", code="LB1"), _line("공", "노임", "0.5", "10", code="LB2")]
# ── (a) 값 차이 = 참고 ───────────────────────────────────────────────────
def test_price_only_is_sure_with_note() -> None:
b = [_line("인부", "노임", "0.04", "120", code="LB1"), A[1]]
res = dm.verdict(A, b, TOT, {**TOT, "노무비": 10, "계": 10})
assert res["판정"] == dm.SURE and not res["다른"] and res["같음"] == 2
assert [d["항"] for d in res["참고"]] == ["단가 차이"]
mach = [_line("굴삭기", "기계", "0.1", "500", "경비", "0201-0070")]
other = [_line("굴삭기", "기계", "0.1", "530", "경비", "0201-0070")]
assert dm.verdict(mach, other, TOT, TOT)["판정"] == dm.SURE # 기계 시간당 단가 = 참고
file = [
_line("머캐덤로울러(자주식)", "산출", "0.1", "530", "경비")
] # 원파일 기계경비 묶음(코드 없음)
ours = [_line("탠덤롤러", "기계", "0.1", "500", "경비", "1206-0008")]
ours.append(_line("머캐덤롤러 10∼12ton", "기계", "0.1", "500", "경비", "1106-0012"))
res = dm.verdict(file, ours, TOT, TOT) # 이름 종류 같은 기계와 짝 · 단가 = 참고
assert (
not [d for d in res["다른"] if d["항"] != "줄 없음"] and res["참고"][0]["항"] == "단가 차이"
)
run = [{**_line("드릴", "산출", "0.1", "530", "경비"), "비목": {"노무비": D(1), "경비": D(2)}}]
res = dm.verdict(run, [_line("드릴", "기계", "0.1", "500", "경비", "0901-0010")], TOT, TOT)
assert res["판정"] == dm.SURE # 기계경비 구성(운전 노무비 포함) 차이 = 시간당 단가 = 참고
none = [{**_line("모래", "재료", "1", "0", "재료비"), "비목": {}}]
assert (
dm.verdict([_line("모래", "재료", "1", "9", "재료비")], none, TOT, TOT)["판정"] == dm.SURE
)
res = dm.verdict(file, ours[:1], TOT, TOT)
assert [d["항"] for d in res["다른"]] == ["기계 규격"]
def test_rounding_only_is_sure_with_note() -> None:
res = dm.verdict(A, list(A), TOT, {**TOT, "노무비": 10, "계": 10})
assert res["판정"] == dm.SURE and [d["항"] for d in res["참고"]] == ["끝수"]
# ── (b) 로직 차이 = 다른 항 ──────────────────────────────────────────────
def test_rate_value_is_note_structure_is_logic() -> None:
res = dm.verdict([*A, _rate("공구손료", "0.02")], [*A, _rate("공구손료", "0.03")], TOT, TOT)
assert not res["다른"] and res["판정"] == dm.SURE
assert [d["항"] for d in res["참고"]] == ["율 값"] # 율 값(%) 다름 = 참고(812-4) · 로직 같음
assert "2 % ↔" in res["참고"][0]["글"] and "3 %" in res["참고"][0]["글"]
same = dm.verdict([*A, _rate("율", "0.02")], [*A, _rate("공구손료", "0.02")], TOT, TOT)
assert same["판정"] == dm.SURE # 율 · 대상 · 비목 같음 = 이름 달라도 같은 율 줄
tgt = dm.verdict(
[*A, _rate("율", "0.02", (("재료", "재료비"),))], [*A, _rate("율", "0.02")], TOT, TOT
)
assert [d["항"] for d in tgt["다른"]] == ["율 대상"]
cost = dm.verdict([*A, _rate("율", "0.02", cost="재료비")], [*A, _rate("율", "0.02")], TOT, TOT)
assert [d["항"] for d in cost["다른"]] == ["비목"]
def test_machine_labor_kind_differs_blocks() -> None:
a = [*A, _line("굴삭기", "기계", "0.1", "500", "경비", "0201-0070")]
b = [
*A,
_line("굴삭기", "기계", "0.1", "500", "경비", "0211-0080"),
] # 타이어 = 다른 기종(812-11)
res = dm.verdict(a, b, TOT, TOT)
assert [d["항"] for d in res["다른"]] == ["기계 규격"] and res["판정"] == dm.NEAR
c = [_line("특별인부", "노임", "0.04", "120", code="LB9"), A[1]]
res = dm.verdict(A, c, TOT, TOT)
assert [d["항"] for d in res["다른"]] == ["자원"] and res["판정"] != dm.SURE
sub = [_line("모르타르", "산출", "0.1", "500", "재료비")]
res = dm.verdict(sub, [_line("모르타르", "산출", "0.1", "520", "재료비")], TOT, TOT)
assert [d["항"] for d in res["다른"]] == ["산출 단가"] # 안쪽 산출 = 로직 결과
# ── (c) · (d) 원파일 블록 ────────────────────────────────────────────────
def _judge(no: int) -> dict:
t4 = pytest.importorskip("test_810_4_match")
try:
return t4.judge(no)
except FileNotFoundError:
pytest.skip("원파일 없음")
def test_formwork_rate_ratio_pairs() -> None:
got = _judge(41) # 합판거푸집 4회 ↔ GC000211
assert got["판정"] == dm.NEAR and got["키"] == "GC000211"
assert [d["항"] for d in got["다른"]] == ["비목"] and "1 %" in got["다른"][0]["글"]
assert [d["항"] for d in got["참고"]] == ["단가 차이"]
def test_req704_still_near() -> None:
got = _judge(19) # 배수관부설 D=800 ↔ GF000179
kinds = [d["항"] for d in got["다른"]]
assert got["판정"] == dm.NEAR and got["키"] == "GF000179"
assert kinds.count("단위 환산") == 2 and "기계 규격" in kinds and "율 줄" in kinds
# ── (e) 전수 ─────────────────────────────────────────────────────────────
@pytest.mark.skipif(os.environ.get("S8122_ALL") != "1", reason="전수 = S8122_ALL=1")
def test_every_block_logic() -> None:
out = subprocess.run(
[sys.executable, str(HERE / "helper_810_4_sweep.py")], capture_output=True, text=True
)
assert out.returncode == 0, out.stderr[-2000:]
got = json.loads(out.stdout.strip().splitlines()[-1])
assert got["블록"] == 2220 and got["오류"] == 0 and got["확정다시셈다름"] == 0
assert not {"단가 차이", "끝수"} & set(got["근접항"])
assert got["확정참고블록"] >= 1 and got["판정"][dm.SURE] >= 98
def test_rate_target_scope() -> None:
"""율 대상 — 줄 기호 = 그 줄 · 비목 이름 = 그 비목 몫(기계 운전 노무비 포함) · 번지 합 = 핵심 줄 전부."""
from M02_MasterTemplete import M02_Doc_Match_Note as note
def run(rate_text: str) -> dict:
money = [
{"이름": "인부", "수량": "1", "단가": "100", "기호": "C_인부"},
{"이름": "굴삭기", "수량": "1", "단가": "300"},
{"이름": "율", "단가": rate_text},
]
rows = [
{"수량": D(1), "단가": D(100), "금액": D(100)},
{"수량": D(1), "단가": D(300), "금액": D(300)},
{"수량": D(1), "단가": D(0), "금액": D(0)},
]
facts = [
{"번": 0, "갈래": "노임", "비목": {"노무비": D(100)}, "합밖": False},
{"번": 1, "갈래": "산출", "비목": {"노무비": D(100), "경비": D(200)}, "합밖": False},
{"번": 2, "갈래": "율", "비목": {"경비": D(4)}, "합밖": False},
]
doc = {"변수": [], "식": [], "금액": money}
rows[2]["단가"] = {"C_인부 × 4%": D(4), "노무비 × 2%": D(4), "번지.A01.계 × 1%": D(4)}[
rate_text
]
note.rates(doc, {"줄": rows}, facts)
return facts[2]
one = run("C_인부 × 4%")
assert one["율"] == D("0.04") and one["대상"] == {("노임", "노무비")}
labor = run("노무비 × 2%") # 노무비 200(인부 100 + 굴삭기 운전 100)
assert labor["율"] == D("0.02") and labor["대상"] == {("노임", "노무비"), ("기계", "노무비")}
whole = run("번지.A01.계 × 1%") # 400 × 1 %
assert whole["율"] == D("0.01") and ("기계", "경비") in whole["대상"]