From 28acddb4b918d798532633f92fc44a2e2916e765 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 10 Nov 2026 00:11:55 +0900 Subject: [PATCH] =?UTF-8?q?feat(812-11):=20=EC=97=B0=EA=B2=B0=20=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EA=B0=92=20=EA=B8=B0=EC=A4=80=20=EB=84=93=ED=9E=98?= =?UTF-8?q?=20=E2=80=94=20=EA=B0=99=EC=9D=80=20=EA=B8=B0=EC=A2=85=20?= =?UTF-8?q?=EA=B7=9C=EA=B2=A9=20=C2=B7=20=EC=88=98=EB=9F=89=20=3D=20?= =?UTF-8?q?=EC=B0=B8=EA=B3=A0=20=C2=B7=20=EB=B0=94=EA=BE=B8=EA=B8=B0=20?= =?UTF-8?q?=EB=95=8C=20=EA=B8=B0=EA=B3=84=20=EC=A4=84=20=EA=B0=88=EC=95=84?= =?UTF-8?q?=20=EB=81=BC=EC=9B=80=20=C2=B7=20=EA=B8=B0=EA=B3=84=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=20=EA=B0=88=EB=9E=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 새 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 --- M02_MasterTemplete/M02_Doc_Match.py | 60 ++++- M02_MasterTemplete/M02_Doc_MatchSk.py | 51 +++- M02_MasterTemplete/M02_Doc_Match_Note.py | 29 ++- M02_MasterTemplete/M02_Doc_Match_Value.py | 220 ++++++++++++++++ .../M02_MasterTemplete_Sangeun_MatchBand.ts | 2 +- M02_MasterTemplete/logic/M02_Sangeun_Match.ts | 21 +- docs/raw/요구_1104/_목록_812-11_연결판정.xlsx | Bin 0 -> 89083 bytes resources/tester/helper_810_4_sweep.py | 3 +- resources/tester/test_810_4_match.py | 6 +- resources/tester/test_812_11_match_values.py | 239 ++++++++++++++++++ resources/tester/test_812_2_match_logic.py | 5 +- 11 files changed, 605 insertions(+), 31 deletions(-) create mode 100644 M02_MasterTemplete/M02_Doc_Match_Value.py create mode 100644 docs/raw/요구_1104/_목록_812-11_연결판정.xlsx create mode 100644 resources/tester/test_812_11_match_values.py diff --git a/M02_MasterTemplete/M02_Doc_Match.py b/M02_MasterTemplete/M02_Doc_Match.py index debdf6b48..0ef8c1f75 100644 --- a/M02_MasterTemplete/M02_Doc_Match.py +++ b/M02_MasterTemplete/M02_Doc_Match.py @@ -7,10 +7,13 @@ ② 옵션 풀이 = 그 문서의 선택 · 입력 변수 값을 줄마다 좁힘(줄 수량 · 단가가 의존하는 변수만 돌림 · 값이 가져온 줄 수량 · 단가 묶음에 있거나 0(꺼진 줄)인 값만 남김) → 남은 조합(상한 `CAP_ALL`)을 문서 셈 · 입력 변수 후보 = 기본값 · 0 · 가져온 식에 나온 수 · 선택은 가져온 글에 든 값부터. - ③ 판정 = 줄 대조 = 로직(812-2 · 요구 712 — `M02_Doc_Match_Note`): 다른 항 = 자원 · 기계 규격 · 수량 · - 비목 · 율 구조(대상 · 비목) · 줄 없음 · 이름 · 참고 = 단가 · 끝수 · 율 값 %(값 — 확정을 안 막음) — - 다른 항 0 = 「확정」 · 같은 줄이 하나 넘고 핵심 줄 반 넘게 짝 = 「근접」(다른 항 목록) · 그 밖 「없음」. -결과 `{판정, 키, 이름, 옵션, 다른, 참고, 금액 {가져온, 우리}, 후보수}` = 가져온 식 원본 `연결후보`. + ③ 판정 = 줄 대조 = 로직(812-2 · 요구 712 — `M02_Doc_Match_Note`): 다른 항 = 자원 · 기종 · 단위 환산 · + 비목 · 율 구조(대상 · 비목) · 줄 없음 · 이름 · 참고 = 단가 · 끝수 · 율 값 % · 같은 기종 규격 · 수량 + (값 — 확정을 안 막음 · 812-11 `M02_Doc_Match_Value`) — 다른 항 0 = 「확정」 · 같은 줄이 하나 넘고 + 핵심 줄 반 넘게 짝 = 「근접」(다른 항 목록) · 그 밖 「없음」 · 값이 맞는 조합 없으면 기본 옵션 + 「옵션 확인」. + ⓪ 기계 한 묶음 + 작업량 식 수량 = 「기계 작업」(우리 기초에 안 붙임 · 요구 728 · 735-4). +결과 `{판정, 키, 이름, 옵션, 다른, 참고, 바꿈, 금액 {가져온, 우리}, 후보수}` = 가져온 식 원본 `연결후보` · +`바꿈` = [바꾸기] 때 갈아 끼울 기계 줄 [{기호(우리 단가 기호), 기계(가져온 원문번호), 이름, 규격}]. """ from __future__ import annotations @@ -24,6 +27,7 @@ from typing import Any from M02_MasterTemplete import M02_Doc_Copy as dc from M02_MasterTemplete import M02_Doc_Match_Note as note +from M02_MasterTemplete import M02_Doc_Match_Value as val md, mc, ml = dc.md, dc.mc, dc.ml if not hasattr( @@ -133,8 +137,12 @@ def facts(doc: dict, got: dict) -> list[dict]: "비목": {k: _key(v) for k, v in (row.get("비목") or {}).items() if v}, "금액": _key(row.get("금액")), "합밖": bool(row.get("합밖")), + "기호": _single(line.get("단가")), + "규격": str(line.get("규격") or ""), + "수량글": str(line.get("수량") or ""), } ) + val.mark_combo(doc, out) note.rates(doc, got, out) return out @@ -284,7 +292,11 @@ def _words(doc: dict) -> str: bits += [x.get("규격") for x in doc.get("금액") or []] for v in doc.get("변수") or []: bits += [str(x) for x in ((v.get("연결") or {}).get("입력") or {}).values()] - return " ".join(str(b or "") for b in bits).replace(" ", "") + return " ".join(str(b or "") for b in bits).replace(" ", "").replace(",", "") + + +def _bare(o: Any) -> str: + return str(o).replace(" ", "").replace(",", "") # 「D1,800」 = 글 「D1800」 def domains( @@ -300,7 +312,7 @@ def domains( kind, base = link.get("갈래"), link.get("값") if kind == "선택": opts = list(link.get("목록") or []) - seen = [o for o in opts if str(o).replace(" ", "") in words and len(str(o)) > 1] + seen = [o for o in opts if _bare(o) in words and len(str(o)) > 1] seen.sort(key=lambda o: -len(str(o))) if seen: ev[md.var_id(v)] = set(seen) @@ -437,6 +449,7 @@ def compare(mine: list[dict], ours: list[dict]) -> dict[str, Any]: and a["단가"] == b["단가"] and a["비목"] == b["비목"] and (a["코드"] == b["코드"] or not (a["코드"] and b["코드"])) # 코드 다름 = 짝 대조 + and val.same_combo(a, b) ) ) same += len(exact) @@ -452,11 +465,14 @@ def compare(mine: list[dict], ours: list[dict]) -> dict[str, Any]: same, paired = (same + 1, paired) if not bad else (same, paired + 1) diffs += bad notes += ref + bad, ref, n = val.pairs(take, core, cls, note.pair, _ratio) # 같은 자원 수량 다름 = 값(812-11) + same, paired, diffs, notes = same + n, paired + len(bad), diffs + bad, notes + ref for a, b in take(lambda a, b: core(a, b) and cls(a, b) and a["단가"] == b["단가"]): paired += 1 how = _ratio(a["수량"], b["수량"]) what = "단위 환산" if how else "수량" - diffs.append({"항": what, "글": f"{a['이름']} 수량 {a['수량']} ↔ {b['수량']} {how or ''}"}) + say = {"항": what, "글": f"{a['이름']} 수량 {a['수량']} ↔ {b['수량']} {how or ''}"} + diffs += note.pair(a, b)[0] or [say] # 같은 자원 아님 = 그 로직 까닭(비목 · 자원) for a, b in take(lambda a, b: core(a, b) and a["갈래"] == b["갈래"] == "기계"): paired += 1 diffs.append( @@ -473,7 +489,15 @@ def compare(mine: list[dict], ours: list[dict]) -> dict[str, Any]: what = "줄 없음" diffs.append({"항": what, "글": f"{side} — {x['이름']}"}) n_core = sum(1 for a in mine if a["갈래"] != "율") - return {"같음": same, "짝": same + paired, "핵심": n_core, "다른": diffs, "참고": notes} + swaps = [x.pop("바꿈") for x in notes if "바꿈" in x] + return { + "같음": same, + "짝": same + paired, + "핵심": n_core, + "다른": diffs, + "참고": notes, + "바꿈": swaps, + } def _totals(got: dict) -> dict: @@ -542,6 +566,7 @@ def try_doc( dom = narrow(base, links, dom, want, ev) named = [] if same_name(imported, base) else [_unnamed(imported, base)] best: dict | None = None + ties: list[tuple] = [] for pick in combos(base, dom) or [{}]: got = _calc(base, links, _given(base, pick)) if got is None: @@ -549,9 +574,11 @@ def try_doc( off = [_off(base, k, pick[k], ev[k]) for k in ev if k in pick and pick[k] not in ev[k]] off += named res = verdict(mine, facts(base, got), got_imp, got, off) + values = sum(1 for x in res["참고"] if x["항"] in val.VALUE) if res["판정"] == SURE else 0 rank = ( res["판정"] == SURE, -len(off), + -values, # 값 참고(규격 · 수량)가 적은 조합 먼저(812-11) res["같음"], res["짝"], -len(res["다른"]), @@ -559,18 +586,28 @@ def try_doc( ) if best is None or rank > best["순위"]: best = {**res, "순위": rank, "옵션": pick, "금액": _totals(got)} + ties.append((rank, pick)) if res["판정"] == SURE and not res["참고"]: break + if best and best["판정"] == SURE and any(x["항"] in val.VALUE[1:] for x in best["참고"]): + same = [p for r, p in ties if r == best["순위"]] # 값으로 못 가른 조합(요구 733 ㉢) + best["참고"] += val.option_check(base, best["옵션"], same, _qty_vars(base)) return best or { "판정": NONE, "같음": 0, "짝": 0, "다른": [], "참고": [], - "순위": (False, -9, 0, 0, 0, 0), + "순위": (False, -9, 0, 0, 0, 0, 0), } +def _qty_vars(doc: dict) -> set[str]: + """금액 줄 수량이 (거쳐서) 부르는 변수.""" + close = _closure(doc) + return set().union(*(_uses(x.get("수량"), close) or set() for x in doc.get("금액") or [])) + + def _off(doc: dict, vid: str, value: Any, seen: set) -> dict: """옵션 값이 가져온 글 근거와 다름 — 다른 항 「옵션 글」.""" var = next((v for v in doc.get("변수") or [] if md.var_id(v) == vid), {}) @@ -585,6 +622,7 @@ def match(imported: dict, links_imp: Any, index: Index, links: Any) -> dict[str, if got_imp is None: return {"판정": NONE, "까닭": "가져온 식을 우리 단가로 못 셈", "후보수": 0} mine = facts(imported, got_imp) + alone = val.work(imported, mine, note._names) keys = index.candidates(imported) best, best_key = None, None for key in keys: @@ -593,6 +631,9 @@ def match(imported: dict, links_imp: Any, index: Index, links: Any) -> dict[str, best, best_key = res, key if res["판정"] == SURE and not res["참고"]: break + exact = best and best["판정"] == SURE and not {x["항"] for x in best["참고"]} & set(val.CHECK) + if alone and not exact: # 기계 작업 — 우리 기초와 수량 · 규격까지 같을 때만 확정으로 붙임 + return alone if best is None: return {"판정": NONE, "후보수": 0} base = index.docs[best_key] @@ -606,6 +647,7 @@ def match(imported: dict, links_imp: Any, index: Index, links: Any) -> dict[str, "옵션": _shown(base, best["옵션"]), "다른": best["다른"], "참고": best["참고"], + "바꿈": best.get("바꿈") or [], "금액": {"가져온": _plain(_totals(got_imp)), "우리": _plain(best["금액"])}, "후보수": len(keys), } diff --git a/M02_MasterTemplete/M02_Doc_MatchSk.py b/M02_MasterTemplete/M02_Doc_MatchSk.py index 72e7b9067..67bb3280e 100644 --- a/M02_MasterTemplete/M02_Doc_MatchSk.py +++ b/M02_MasterTemplete/M02_Doc_MatchSk.py @@ -5,18 +5,24 @@ 바꾸기(`swap`) = 서버가 다시 찾아 「확정」 일 때만 — 같은 SK 키에 M01 사본 SK(바탕 = 그 기초 · 입력값 = 찾은 옵션 · 802-4a 꼴 · 수식 사본은 저장 때 서버가 찍음)를 씀 · 원래 가져온 식 SK 몸은 `가져온보관` 칸에 그대로 둠 · 일위대가 줄 참조 = 키 그대로(SK 내용만 바뀜 → 금액 다시 셈). - 되돌리기(`back`) = `가져온보관` 몸을 그 키에 다시 씀(가져온 식 금액 그대로). -우리 M01 기초는 어느 갈래에서도 안 바뀜(708) · 근접 · 없음 = 바꾸기 409(703). + + 찾은 `바꿈`(같은 기종 규격만 다른 기계 줄 · 812-11 · 요구 733-2) = 사본 문서 그 줄 기계 입력(원문번호)을 + 가져온 규격의 우리 기계로 갈아 끼움(수식 길 저장 = 따로) · 품 · 율 · 단가 · 조건 값은 우리 값 그대로 · + 기계가 옵션 기호 · 식이면 안 바꿈. + 되돌리기(`back`) = `가져온보관` 몸을 그 키에 다시 씀(가져온 식 금액 그대로 · 수식 사본도 보관 몸 그대로). +우리 M01 기초는 어느 갈래에서도 안 바뀜(708) · 근접 · 없음 · 기계 작업 = 바꾸기 409(703). """ from __future__ import annotations +import copy as cp +import re from typing import Any from common_util.common_util_time import utc_now_text from M02_MasterTemplete import M02_Doc_Copy as dc from M02_MasterTemplete import M02_Doc_Import as dim from M02_MasterTemplete import M02_Doc_Match as dm +from M02_MasterTemplete import M02_Doc_Sk as dsk from M02_MasterTemplete import M02_MasterTemplete_Store as store from M02_MasterTemplete import M02_Sangeun_Doc as sd from M02_MasterTemplete import M02_Sangeun_Imported as imp @@ -92,7 +98,36 @@ def swap(key: str, version: str) -> dict[str, Any]: if found.get("판정") != dm.SURE: raise _bad(f"우리 기초와 「확정」 일치가 아님({found.get('판정')}) — 바꾸지 않음", 409) info = store.write(sd.KIND, key, version or got["판"], copy_body(sk, found)) - return {dm.KEY: found, "판": info.get("판")} + done = refit(key, found.get("바꿈") or []) + return {dm.KEY: found, "판": done[0] or info.get("판"), "바꾼기계": done[1]} + + +def refit(key: str, swaps: list[dict]) -> tuple[str | None, list[dict]]: + """사본 문서 기계 줄 → 가져온 규격 우리 기계(그 줄 단가 기호 연결의 입력 「기계」 · 줄 이름 · 규격) → + 수식 길 저장 · (판, 바꾼 것).""" + from M02_MasterTemplete import M02_Doc_Sk_Path as path # 수식 길 — 늦게(돌아 부름 피함) + + if not swaps: + return None, [] + got = path.read(key) + doc = cp.deepcopy(got["문서"]) + done = [] + for one in swaps: + var = next((v for v in doc.get("변수") or [] if dm.md.var_id(v) == one["기호"]), None) + link = (var or {}).get("연결") or {} + given = link.get("입력") or {} + if link.get("갈래") != "단가산출" or not re.fullmatch(r"'[^']+'", str(given.get("기계"))): + continue + link["입력"] = {**given, "기계": f"'{one['기계']}'"} + for line in doc.get("금액") or []: + if dm._single(line.get("단가")) == one["기호"]: + if line.get("묶음") == line.get("이름"): # 그 줄 이름을 단 묶음 제목도 + line["묶음"] = f"{one['이름']} {one['규격']}".strip() + line["이름"], line["규격"] = one["이름"], one["규격"] + done.append(one) + if not done: + return None, [] + return path.save(key, {"문서": doc, "판": got["판"]})["판"], done def back(key: str, version: str) -> dict[str, Any]: @@ -101,5 +136,13 @@ def back(key: str, version: str) -> dict[str, Any]: old = got["문서"].get(KEEP) if not isinstance(old, dict) or not old.get(imp.KEY): raise _bad("되돌릴 가져온 식 없음") - info = store.write(sd.KIND, key, version or got["판"], {**old, "키": key}) + keep = ( + old.get(dc.KEY) if dc.has(old) else None + ) # 보관 몸 수식 사본 그대로(바꾼 기계 = 따로 버림) + token = dsk.SAVING.set({"키": key, "사본": keep}) if keep else None + try: + info = store.write(sd.KIND, key, version or got["판"], {**old, "키": key}) + finally: + if token is not None: + dsk.SAVING.reset(token) return {"판": info.get("판")} diff --git a/M02_MasterTemplete/M02_Doc_Match_Note.py b/M02_MasterTemplete/M02_Doc_Match_Note.py index 7fe1fe20d..9b9ee23d7 100644 --- a/M02_MasterTemplete/M02_Doc_Match_Note.py +++ b/M02_MasterTemplete/M02_Doc_Match_Note.py @@ -1,8 +1,9 @@ """연결 찾기 — 로직 차이(다른 항) 대 값 차이(참고) 가르기(PLAN 812-2 · 요구 712) — `M02_Doc_Match` 가 부름. -확정을 막는 「다른 항」 = 로직 차이만 — 자원 갈래 · 기계 규격 · 노임 종류 · 자재 이름 종류 · 비목 · 산출 단가 · - 율 구조(있고 없음 · 대상 비목 — 율 값 % 는 참고) · 수량(옵션 풀이 뒤 · 원 단위 같아야 함). -「참고」 = 값 차이 — 인력 · 재료 · 기계 시간당 단가 · 끝수(합만 다름) · 율 값(%) · 그로 인한 비목 금액 · 계. +확정을 막는 「다른 항」 = 로직 차이만 — 자원 갈래 · 기종 · 노임 종류 · 자재 이름 종류 · 비목 · 산출 단가 · + 율 구조(있고 없음 · 대상 비목 — 율 값 % 는 참고) · 단위 환산(`M02_Doc_Match_Value`). +「참고」 = 값 차이 — 인력 · 재료 · 기계 시간당 단가 · 끝수(합만 다름) · 율 값(%) · 같은 기종 규격 · 수량(812-11) · + 그로 인한 비목 금액 · 계. 율 = 율 줄 셈값 ÷ 대상 금액 합 — 대상 = 율 식이 (거쳐서) 부르는 금액 줄 · 비목 이름이면 그 비목 몫 · 번지 합 = 핵심 줄 전부 · 대상 금액 끝수 자리 차이만 지움(유효 6 자리 · 두 바탕 중 짧은 꼴) — 지어 맞추기 아님. """ @@ -14,6 +15,7 @@ from decimal import Decimal, InvalidOperation from typing import Any from M02_MasterTemplete import M02_Doc_Copy as dc +from M02_MasterTemplete import M02_Doc_Match_Value as val from M02_MasterTemplete import M02_Machine_Find as mfind md = dc.md @@ -158,15 +160,24 @@ def _grams(text: str) -> set[str]: def pair(a: dict, b: dict) -> tuple[list[dict], list[dict]]: - """수량 같은 짝 줄 → (다른 항, 참고) — 단가만 다르면 참고 · 자원 · 비목이 다르면 다른 항.""" + """짝 줄 → (다른 항, 참고) — 단가 · 같은 기종 규격만 다르면 참고 · 자원 · 기종 · 비목이 다르면 다른 항.""" diffs: list[dict] = [] + spec: list[dict] = [] # 같은 기종 규격만 다름 = 값(812-11 · 요구 733-2) kinds = {a["갈래"], b["갈래"]} # 기계경비 숫자 묶음(코드 없음 · 원파일 값) ↔ 우리 기계 = 이름 종류로 같은 기계인지 loose = kinds == {"기계", "산출"} and not (a if a["갈래"] == "산출" else b)["코드"] - if a["갈래"] == b["갈래"] == "기계" and a["코드"] != b["코드"]: - diffs.append({"항": "기계 규격", "글": f"{a['이름']} {a['코드']} ↔ {b['코드']}"}) + combo = not val.same_combo(a, b) # 조합 기계 ↔ 낱 기계 = 다른 기종 + if a["갈래"] == b["갈래"] == "기계" and (a["코드"] != b["코드"] or combo): + if not combo and val.same_machine(a, b): + spec.append(val.spec_note(a, b)) + else: + diffs.append( + {"항": "기계 규격", "글": f"{a['이름']} {a['코드']} ↔ {b['코드']} — 다른 기종"} + ) elif loose and not _same_machine(a["이름"], b["이름"]): diffs.append({"항": "기계 규격", "글": f"{a['이름']} ↔ {b['이름']} {b['코드']}"}) + elif loose: + spec += [x for x in (val.loose_note(a, b),) if x] elif a["갈래"] == b["갈래"] == "노임" and a["코드"] != b["코드"]: diffs.append({"항": "자원", "글": f"{a['이름']} {a['코드']} ↔ {b['이름']} {b['코드']}"}) elif a["갈래"] == b["갈래"] == "재료" and not _same_stuff(a, b): @@ -178,11 +189,11 @@ def pair(a: dict, b: dict) -> tuple[list[dict], list[dict]]: {"항": "비목", "글": f"{a['이름']} 비목 {'·'.join(a['비목'])} ↔ {'·'.join(b['비목'])}"} ) if a["단가"] == b["단가"]: - return diffs, [] + return diffs, spec say = f"{a['이름']} 단가 {txt(a['단가'])} ↔ {txt(b['단가'])}" if (a["갈래"] == b["갈래"] and a["갈래"] in PRICED) or loose: - return diffs, [{"항": "단가 차이", "글": say}] - return [*diffs, {"항": "산출 단가", "글": say}], [] + return diffs, [*spec, {"항": "단가 차이", "글": say}] + return [*diffs, {"항": "산출 단가", "글": say}], spec def _same_stuff(a: dict, b: dict) -> bool: diff --git a/M02_MasterTemplete/M02_Doc_Match_Value.py b/M02_MasterTemplete/M02_Doc_Match_Value.py new file mode 100644 index 000000000..3b8487e9e --- /dev/null +++ b/M02_MasterTemplete/M02_Doc_Match_Value.py @@ -0,0 +1,220 @@ +"""연결 찾기 값 기준 넓힘(PLAN 812-11 · 요구 714 · 733 · 734 · 735) — `M02_Doc_Match` 가 부름. + +값(참고 · 확정을 안 막음 · 바꾸면 우리 값): + 같은 기종 규격만 다름(굴착기 0.7㎥ ↔ 1.0㎥ — 기종 = 기계표 이름 머리 + 괄호 낱말 · 무한궤도 대 타이어 = 다른 기종 · + 조합 기계는 구성 줄마다) = 「규격」(바꾸면 가져온 규격 — [바꾸기] 때 그 줄 기계를 갈아 끼움 `바꿈`) · + 수량 차이(같은 자원 줄) = 「수량 끝자리」(1 % 안) · 「품 숫자」(가져온 수량 = 수 하나) · 「수량」(조건 값 · 비율 · 표 값). +로직(다른 항): 자원 줄 구성(갈래 · 기종 · 노임 직종 · 재료 종류 · 비목) · 줄 없음 · 율 구조 · 단위 환산 = + 같은 배(× 6 등)가 두 줄 넘게 같이 걸림(결과 단위 기준이 다름) — 한 줄만 배가 맞는 것은 수량 값. +기계 작업(`work`) = 가져온 문서가 기계 한 묶음(한 기계 줄 · 조합 기계면 그 구성 줄들)뿐 · 수량이 작업량 식(Q) = + 우리 기초에 안 붙임(요구 728 · 735-4 — 수량 · 규격까지 같은 우리 기초가 있을 때만 확정) · 공식 꼴이 그 기종 + 「작업량 틀」(813-2 부품)과 같으면 참고에 틀 이름. +""" + +from __future__ import annotations + +import re +from decimal import Decimal +from functools import lru_cache +from typing import Any + +from M02_MasterTemplete import M02_Machine_Find as mfind + +WORK = "기계 작업" +SPEC, QTY, TAIL, POOM = "규격", "수량", "수량 끝자리", "품 숫자" +VALUE = (SPEC, QTY, TAIL, POOM) # 확정 순위 — 값 참고가 적은 조합 · 기초 먼저 +CHECK = (*VALUE, "옵션 확인") # 기계 작업 꼴이 확정으로 붙지 않는 참고 +_NUMBER = re.compile(r"^\s*\d+(?:\.\d+)?\s*$") + + +# ── 기종 ────────────────────────────────────────────────────────────── +def row_of(code: Any) -> Any: + """원문번호 → 기계표 줄(`M02_Machine_Find.Row`) · 없음 None.""" + key = mfind.by_code(code) + return mfind.table()[2].get(key) if key else None + + +def same_kind(a: Any, b: Any) -> bool: + """두 원문번호 = 같은 기종 — 이름 머리 + 괄호 낱말 같음(규격만 다름).""" + x, y = row_of(a), row_of(b) + return bool(x and y) and x.base == y.base and x.words == y.words + + +@lru_cache(maxsize=4096) +def _combo(name: str) -> tuple | None: + """조합 기계 이름 → 구성 기종 묶음(정렬) · 낱 기계 = None.""" + got = mfind.parts(name) + return tuple(sorted(mfind.split_name(n)[0] for n, _ in got)) if len(got) > 1 else None + + +def mark_combo(doc: dict, facts: list[dict]) -> None: + """기계 사실에 `조합`(구성 묶음 · 낱 = None) · `갈라짐`(가져온 조합을 둘로 가른 줄 = 낱 기계로도 맞음).""" + head = _machines(doc) + for f in facts: + if f["갈래"] in ("기계", "산출"): + f["조합"] = _combo(f["이름"]) + f["갈라짐"] = any(head.get(str(f.get("기호")), {}).get(k) for k in ("조합", "조합첫")) + + +def same_combo(a: dict, b: dict) -> bool: + """조합 여부 같음 — 구성 묶음 같음 · 가른 줄 ↔ 낱 기계도 같음(「굴착기+부착용 집게」 ↔ 굴착기 하나 = 다름).""" + x, y = a.get("조합"), b.get("조합") + return x == y or (a.get("갈라짐") and y is None) or (b.get("갈라짐") and x is None) + + +def same_machine(a: dict, b: dict) -> bool: + """같은 기종 기계 줄 — 원문번호 기종 같음 + 조합 구성 같음.""" + return same_kind(a["코드"], b["코드"]) and same_combo(a, b) + + +def _eq(code: Any) -> str: + r = row_of(code) + return f"{r.raw.get('이름')} {r.raw.get('규격') or ''}".strip() if r else str(code) + + +def spec_note(a: dict, b: dict) -> dict: + """같은 기종 규격 다름 → 참고 「규격」 + 바꿈(우리 줄 단가 기호 → 가져온 원문번호).""" + ra = row_of(a["코드"]) + say = f"규격 다름 {_eq(a['코드'])} ↔ {(row_of(b['코드']).raw.get('규격') or '')}" + swap = {"기호": b.get("기호"), "기계": a["코드"], "이름": ra.raw.get("이름"), + "규격": ra.raw.get("규격") or ""} # fmt: skip + return {"항": SPEC, "글": f"{say} — 바꾸면 가져온 규격", "바꿈": swap} + + +def loose_note(a: dict, b: dict) -> dict | None: + """못 이은 가져온 기계(원파일 묶음 값) ↔ 우리 기계 — 규격 글이 다르면 「안 바꿈」 참고.""" + loose, ours = (a, b) if a["갈래"] == "산출" else (b, a) + row = row_of(ours["코드"]) + if not row or not loose.get("규격"): + return None + if mfind.spec_fit(mfind.tokens(loose["규격"]), row.spec) == "같음": + return None + say = f"규격 다름 {loose['이름']} {loose['규격']} ↔ {_eq(ours['코드'])}" + return { + "항": SPEC, + "글": f"{say} — 가져온 기계를 우리 표에서 못 찾음 · 바꾸면 우리 기계 그대로", + } + + +# ── 수량 ────────────────────────────────────────────────────────────── +def _show(v: Any) -> str: + return f"{v:.4g}" if isinstance(v, Decimal) else str(v) + + +def qty_note(a: dict, b: dict) -> dict: + """같은 자원 줄 수량 다름 → 참고(끝자리 · 품 숫자 · 수량).""" + x, y = a["수량"], b["수량"] + if isinstance(x, Decimal) and isinstance(y, Decimal) and y and abs(x - y) <= abs(y) / 100: + what = TAIL + elif _NUMBER.match(str(a.get("수량글") or "")): + what = POOM + else: + what = QTY + return {"항": what, "글": f"{a['이름']} 수량 다름 {_show(x)} ↔ {_show(y)} — 바꾸면 우리 값"} + + +def pairs( + take: Any, core: Any, cls: Any, pair: Any, ratio: Any +) -> tuple[list[dict], list[dict], int]: + """수량 다른 같은 자원 짝(로직 같음 · `pair` 다른 항 0) → (다른 항 = 단위 환산 무리, 참고, 같은 줄 수) · + `ratio` = 단위 환산 배 글(「× 6」) · 없음 None.""" + got = take( + lambda a, b: core(a, b) and cls(a, b) and a["수량"] != b["수량"] and not pair(a, b)[0] + ) + hows = [ratio(a["수량"], b["수량"]) for a, b in got] + many = { + h for h in hows if h and hows.count(h) >= 2 + } # 같은 배가 두 줄 넘게 = 결과 단위 기준 다름 + diffs: list[dict] = [] + notes: list[dict] = [] + for (a, b), how in zip(got, hows): + if how in many: + diffs.append( + {"항": "단위 환산", "글": f"{a['이름']} 수량 {a['수량']} ↔ {b['수량']} {how}"} + ) + else: + notes.append(qty_note(a, b)) + notes += pair(a, b)[1] + return diffs, notes, len(got) - sum(1 for h in hows if h in many) + + +# ── 기계 작업 ───────────────────────────────────────────────────────── +def _machines(doc: dict) -> dict[str, dict]: + head = (doc.get("가져온") or {}).get("기계") + return {str(x.get("기호")): x for x in head or [] if isinstance(x, dict)} + + +def _one_group(rows: list[dict]) -> bool: + if len(rows) == 1: + return True + return sum(1 for x in rows if x.get("조합첫")) == 1 and all( + x.get("조합") or x.get("조합첫") for x in rows + ) + + +def _form(text: Any) -> str: + """작업량 식 꼴 — 끝수 함수 벗김 · 빈칸 뺌 · 작은 글자(Cm = cm).""" + t = re.sub(r"\s", "", str(text or "")) + m = re.match(r"^(?:반올림|버림|올림)\((.*),\d+\)$", t) + return (m.group(1) if m else t).lower() + + +def _q_form(doc: dict, names: set[str]) -> str: + for line in doc.get("식") or []: + if str(line.get("기호")) in names and str(line.get("기호")).lower().startswith("q"): + return _form(line.get("식")) + return "" + + +def work(doc: dict, mine: list[dict], names: Any) -> dict | None: + """가져온 문서가 기계 한 묶음 + 작업량 식 수량이면 {판정 기계 작업, 참고} · 아니면 None + (`names` = 식 글 → 쓰는 이름 · 인력 · 재료 · 율 줄이 섞이면 보통 길).""" + heads = _machines(doc) + if not mine or not heads or any(f["갈래"] == "율" for f in mine): + return None + rows = [f for f in mine if not f["합밖"]] + if not rows or any( + str(f.get("기호")) not in heads or f["갈래"] not in ("기계", "산출") for f in rows + ): + return None + if not _one_group([heads[str(f["기호"])] for f in rows]): + return None + used = [names(f.get("수량글")) for f in rows] + if not all(used): # 수량이 수뿐 = 작업량 식 아님 + return None + notes = [] + form = _q_form(doc, set().union(*used)) + from M01_MasterData import M01_MasterData_Parts as parts # M02 가 M01 을 부름 — 늦게 + + for f in rows: + if not form or not row_of(f["코드"]): + continue + got = parts.of_machine(str(f["코드"])) + for t in got["틀"]: + if any( + _form(x.get("식")) == form + for x in t["문서"].get("식") or [] + if x.get("기호") == "Q" + ): + say = f"{got['기계']['이름']} — 작업량 공식 꼴 = {t['키']} {t['이름']}" + notes.append({"항": "작업량 틀", "글": say}) + break + return {"판정": WORK, "참고": notes, "후보수": 0} + + +# ── 옵션 확인 ───────────────────────────────────────────────────────── +def option_check(doc: dict, pick: dict, same: list[dict], qty_vars: set[str]) -> list[dict]: + """값이 정확히 맞는 조합이 없고 수량을 정하는 선택이 값으로 안 갈림(같은 순위 조합에 값 여럿) = + 고른 값(기본 먼저) + 참고 「옵션 확인」.""" + from M02_MasterTemplete.M02_Doc_Copy import md + + out = [] + for v in doc.get("변수") or []: + vid, link = md.var_id(v), v.get("연결") or {} + if link.get("갈래") != "선택" or vid not in qty_vars: + continue + if len({str(p.get(vid)) for p in same}) > 1: + how = "기본값" if pick.get(vid) == link.get("값") else "고른 값" + say = f"옵션 확인 — {v.get('이름') or vid} = {pick.get(vid)}({how} · 값으로 못 가름)" + out.append({"항": "옵션 확인", "글": say}) + return out diff --git a/M02_MasterTemplete/M02_MasterTemplete_Sangeun_MatchBand.ts b/M02_MasterTemplete/M02_MasterTemplete_Sangeun_MatchBand.ts index d73d377a2..adc45d641 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Sangeun_MatchBand.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Sangeun_MatchBand.ts @@ -34,7 +34,7 @@ const LABEL: Record, string> = { }; const ASK: Partial, string>> = { 바꾸기: - "이 단가산출을 우리 기초 사본(찾은 옵션)으로 바꿈 — 키 그대로 · 일위대가 금액이 다시 셈됨 · 원래 가져온 식은 보관", + "이 단가산출을 우리 기초 사본(찾은 옵션 · 우리 값)으로 바꿈 — 규격만 다른 기계 줄은 가져온 규격의 우리 기계 · 키 그대로 · 일위대가 금액이 다시 셈됨 · 원래 가져온 식은 보관", 되돌리기: "우리 기초 사본을 원래 가져온 식으로 되돌림 — 가져온 식 금액 그대로", }; diff --git a/M02_MasterTemplete/logic/M02_Sangeun_Match.ts b/M02_MasterTemplete/logic/M02_Sangeun_Match.ts index 66da16d97..f655d15a2 100644 --- a/M02_MasterTemplete/logic/M02_Sangeun_Match.ts +++ b/M02_MasterTemplete/logic/M02_Sangeun_Match.ts @@ -4,11 +4,12 @@ * SK `가져온.원본.연결후보`(서버 `M02_Doc_Match` 가 적음) → 띠 글 · 다른 항 · 단추 하나: * 확정 = [우리 기초 사본으로 바꾸기] · 근접 · 없음 = 단추 없음(703) · 안 찾음 = [연결 찾기] · * 다른 항 = 로직 차이(확정을 막음) · 참고 = 단가 · 끝수 · 율 값 %(값 차이 — 「우리 단가로 셈 ○○ 원」 · 812-2 · 812-4) · - * 바꾼 SK(`가져온보관` 있음) = 「우리 기초 사본 ○○」 + [가져온 식으로 되돌리기] + * 바꾼 SK(`가져온보관` 있음) = 「우리 기초 사본 ○○」 + [가져온 식으로 되돌리기] · + * 같은 기종 규격 · 수량 차이 = 참고(812-11) · 기계 작업 = 기계 한 줄 단가산출(우리 기초에 안 붙임 · 단추 없음) * 화면 · DOM · fetch 없음 * ========================================================================== */ -export type MatchVerdict = "확정" | "근접" | "없음"; +export type MatchVerdict = "확정" | "근접" | "없음" | "기계 작업"; export interface MatchFound { 판정?: MatchVerdict; @@ -16,7 +17,7 @@ export interface MatchFound { 이름?: string; 옵션?: Record; 다른?: { 항: string; 글: string }[]; - /** 값 차이(단가 · 끝수 · 율 값) — 확정을 안 막음 */ + /** 값 차이(단가 · 끝수 · 율 값 · 규격 · 수량) — 확정을 안 막음 */ 참고?: { 항: string; 글: string }[]; 금액?: { 가져온?: Record; 우리?: Record }; 후보수?: number; @@ -49,15 +50,21 @@ const lines = (d?: { 항: string; 글: string }[]): string[] => const won = (n?: number | null): string => n == null ? "" : `${Math.round(n).toLocaleString("ko-KR")} 원`; +const QTY = ["수량", "수량 끝자리", "품 숫자"]; /** 참고 요약 — 「참고: 단가 다름 3 줄 · 율 값 다름 1 줄 · 우리 단가로 셈 53,218 원」 · 참고 없음 = "" */ const noteText = (f: MatchFound): string => { const n = f.참고 ?? []; if (!n.length) return ""; const price = n.filter((x) => x.항 === "단가 차이").length; const rate = n.filter((x) => x.항 === "율 값").length; + const spec = n.filter((x) => x.항 === "규격").length; + const qty = n.filter((x) => QTY.includes(x.항)).length; const bits = [ + spec ? `규격 다름 ${spec} 줄` : "", + qty ? `수량 다름 ${qty} 줄` : "", price ? `단가 다름 ${price} 줄` : "", rate ? `율 값 다름 ${rate} 줄` : "", + n.some((x) => x.항 === "옵션 확인") ? "옵션 확인" : "", n.some((x) => x.항 === "끝수") ? "끝수 다름" : "", ].filter(Boolean); const ours = won(f.금액?.우리?.계); @@ -80,6 +87,14 @@ export function matchBand(sk: SkLike | null | undefined): MatchBand | null { if (!f?.판정) { return { tone: "info", text: "우리 기초와 연결을 아직 안 찾음", details: [], action: "찾기" }; } + if (f.판정 === "기계 작업") { + return { + tone: "info", + text: "기계 한 줄 단가산출 — 그대로 씀 · 값은 [단가 갱신]으로 우리 값", + details: lines(f.참고), + action: null, + }; + } const base = `${f.키 ?? ""} ${f.이름 ?? ""} ${opts(f.옵션)}`.trim(); if (f.판정 === "확정") { return { diff --git a/docs/raw/요구_1104/_목록_812-11_연결판정.xlsx b/docs/raw/요구_1104/_목록_812-11_연결판정.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6ad7a18b74a59423b6fb22ef8072166d38939d5f GIT binary patch literal 89083 zcmZ^JV{m1`w{M(@ZQHiZNixaA_QZB_VouD7&51LyPHdgnwr$<~?|mQMeO2#6_wHS_ z_NvvZcmEcZze7S{f`Ng31G59S)|b}lK@9qOtNR+LU&GA7RN2|V(S^m>(UIBH&Q>v2 z5uukARq|8*c->z8ij<9Xu5fF_N0x^>-b}(h^bMfe6Spe3!5ZC$HLBH5;lUNwU+RZ8 zA_LZhAl)Z1`xj4!3g1eLSai}W3S-%#pR$%<2+{~kfnzfBjp(eA|B$eQYlrT*qB%4z z%Qe-SjrJ+k<~BBTv4f<^;n^6vE9nJV`G3i~>04HN{UzrZI2ah(|1GbngR}X61Wrll zQR-tw3^O!8>2#a1f-I=SDajTUH$jikP4?84oR$2o(%xLkq{{=9O0@fVYoVLK|LvRt zC`rPaIKX+Tw@#VgM=yX14IY07o-Hr+gVVR=cAD-a*9k@J_(!7*EuL&~vM5ktz`(L-z`!uR^y6vE z;%aGbXZ}Ak+kZ54uA}R+!i(v5Sp)L4c(6klFpkC3ASh>vem$@g5H)cJ`2UdNyF;8Mu?SdKCXEMaRLAv|*ow;|Xg_EylbM979u#x;3KV=Gk`OZDm8)eCn8=h&|Arl|YNsf6}3J zPe~_YTdlXh+uA}z!)9oDMm8X5#5WnbP41y^7V8^3k^q0U)}%Y&q5nKLdUVB=(++=Y z_u7-UX>2CSkq~N2r9G!N`_8tjNDQu_&
^srK$P*NVF`eXLdck?vUG7CON_s6V_ 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 literal 0 HcmV?d00001 diff --git a/resources/tester/helper_810_4_sweep.py b/resources/tester/helper_810_4_sweep.py index 08fa5d1fc..69b3dcdb5 100644 --- a/resources/tester/helper_810_4_sweep.py +++ b/resources/tester/helper_810_4_sweep.py @@ -31,7 +31,8 @@ def _ctx(): whole = t.whole() docs = dm.ml.load_all() - return t, dim, dm, whole, docs, dm.Index(docs), dm.Memo(dm.ml.Links(whole, docs)) + aims = {k: d for k, d in docs.items() if not d.get("부품")} # 화면과 같은 과녁(813-2) + return t, dim, dm, whole, docs, dm.Index(aims), dm.Memo(dm.ml.Links(whole, docs)) def file_docs(t, dim, dm, whole, kind: str, tag: str) -> dict[int, dict]: diff --git a/resources/tester/test_810_4_match.py b/resources/tester/test_810_4_match.py index 35adaea70..a50d6f3f6 100644 --- a/resources/tester/test_810_4_match.py +++ b/resources/tester/test_810_4_match.py @@ -120,9 +120,9 @@ def test_compare_kinds_and_no_tolerance() -> None: assert dm.verdict(a, list(a), tot, tot)["판정"] == dm.SURE off = dm.verdict(a, list(a), tot, {**tot, "노무비": 10, "계": 10}) assert off["판정"] == dm.SURE and off["참고"][0]["항"] == "끝수" # 끝수 = 참고(812-2) - b = [_line("인부", "노임", "0.24", "100"), _line("공", "노임", "0.5", "11")] - res = dm.verdict(a, b, tot, tot) - assert [d["항"] for d in res["다른"]] == ["단위 환산"] and res["판정"] == dm.NEAR + b = [_line("인부", "노임", "0.24", "100"), _line("공", "노임", "3", "11")] + res = dm.verdict(a, b, tot, tot) # 같은 배(× 6)가 두 줄 = 단위 환산(812-11 · 한 줄만 = 수량 값) + assert [d["항"] for d in res["다른"]] == ["단위 환산"] * 2 and res["판정"] == dm.NEAR assert [d["항"] for d in res["참고"]] == ["단가 차이"] rate = {**_line("율", "율", "1", "3", "경비"), "수량": None, "단가": None} res = dm.verdict([*a, rate], a, tot, tot) diff --git a/resources/tester/test_812_11_match_values.py b/resources/tester/test_812_11_match_values.py new file mode 100644 index 000000000..119c3724e --- /dev/null +++ b/resources/tester/test_812_11_match_values.py @@ -0,0 +1,239 @@ +# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀 +"""812-11 지킴 — 연결 찾기 값 기준 넓힘(요구 733 · 734 · 735 · `M02_Doc_Match_Value`). + +(a) 줄 대조 — 같은 기종 규격만 다름 = 확정 + 참고 「규격」(바꿈 = 가져온 원문번호) · 무한궤도 ↔ 타이어 = 다른 항 · + 수량 다름 = 참고(끝자리 · 품 숫자 · 수량) · 같은 배가 두 줄 = 단위 환산(다른 항) · 줄 구성 다름 = 다른 항 +(b) 견본 — main 230 되메우기(백호 0.2㎥ 70 % + 인력 30 %) ↔ GF000113 확정 + 규격 · 수량 · main 850 PC 슬래브(2ton 미만) + ↔ GC000257 확정 + 수량 끝자리 · main 828 조립식 PC 맨홀(D1800) ↔ GC000252 확정 + 품 숫자(옵션 ㉠ 글 「D1800」 = + D1,800) · 거창 46 토사절취(백호 0.7㎥) = 기계 작업 + 작업량 틀 · 거창 19 파형강관 Φ800 ↔ GF000179 근접 그대로 +(c) 옵션 확인(㉢) — 값으로 못 가른 선택 = 고른 값 + 참고 「옵션 확인」 +(d) 바꾸기(임시 층) — main 230: 사본 기계 줄 = 가져온 규격(0201-0020) · 금액 = M01 문서에 그 기계만 바꾼 셈 · + 되돌리기 = 원래 금액 · 기계 작업 SK 바꾸기 = 409 · M01 문서 파일 그대로 +(e) 전수(S81211_ALL=1) — 2,220 블록 · 오류 0 · 확정 다시 셈 다름 0 · 기계 작업 있음 · 근접 까닭에 값 항 없음 +원파일 없으면 (b) · (d) · (e) skip(다른 PC). +""" + +from __future__ import annotations + +import copy +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)) + +import test_810_2_native_doc as t2 # noqa: E402 +import test_810_4_match as t4 # noqa: E402 + +from M02_MasterTemplete import M02_Doc_Match as dm # noqa: E402 +from M02_MasterTemplete import M02_Doc_Match_Value as val # noqa: E402 +from M02_MasterTemplete import M02_Doc_MatchSk as msk # noqa: E402 +from M02_MasterTemplete import M02_MasterTemplete_Store as store # noqa: E402 +from M02_MasterTemplete import M02_Sangeun_FromHopyo as fh # noqa: E402 +from resources.tester.test_m02_labor_ref import world # noqa: E402, F401 — 같은 임시 층 + +TOT = {"노무비": 9, "재료비": 0, "경비": 0, "계": 9} + + +def _line(name, kind, qty, price, cost="노무비", code="", sym="", text=""): + 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, "기호": sym, + "규격": "", "수량글": text or qty} # fmt: skip + + +MAN = _line("보통인부", "노임", "0.01", "100", code="LB000002") + + +# ── (a) 줄 대조 ────────────────────────────────────────────────────────── +def test_same_kind_spec_is_value_other_kind_is_logic() -> None: + a = [MAN, _line("굴착기", "기계", "0.03", "500", "경비", "0201-0020", "P_a", "1 ÷ Q")] + b = [MAN, _line("굴착기", "기계", "0.02", "600", "경비", "0201-0070", "P_b", "r ÷ Q")] + res = dm.verdict(a, b, TOT, TOT) + assert res["판정"] == dm.SURE and not res["다른"] + assert {x["항"] for x in res["참고"]} == {"규격", "수량", "단가 차이"} + spec = next(x for x in res["참고"] if x["항"] == "규격") + assert "0.2㎥ ↔ 0.7㎥" in spec["글"] and "바꾸면 가져온 규격" in spec["글"] + assert res["바꿈"] == [ + {"기호": "P_b", "기계": "0201-0020", "이름": "굴착기(무한궤도)", "규격": "0.2㎥"} + ] + same_qty = dm.verdict(a, [MAN, {**b[1], "수량": a[1]["수량"]}], TOT, TOT) + assert same_qty["판정"] == dm.SURE and len(same_qty["바꿈"]) == 1 # 수량 같아도 규격 = 값 + tire = [MAN, _line("굴착기", "기계", "0.02", "600", "경비", "0211-0060", "P_b")] + crawler = [MAN, _line("굴착기", "기계", "0.02", "600", "경비", "0201-0060", "P_a")] + res = dm.verdict(crawler, tire, TOT, TOT) # 무한궤도 ↔ 타이어 = 다른 기종 + assert res["판정"] != dm.SURE and [x["항"] for x in res["다른"]] == ["기계 규격"] + assert not res["바꿈"] + + +def test_combo_machine_is_its_own_kind() -> None: + one = _line("굴삭기(무한궤도)", "기계", "0.02", "5", "경비", "0201-0060", "P_a") + grab = _line("굴착기+부착용 집게 1.0㎥", "기계", "0.07", "5", "경비", "0201-0100", "P_b") + val.mark_combo({}, [one, grab]) # facts 가 붙이는 조합 표지 + res = dm.verdict([MAN, one], [MAN, grab], TOT, TOT) # 조합 기계 ↔ 낱 기계 = 다른 기종 + assert res["판정"] != dm.SURE and "기계 규격" in {x["항"] for x in res["다른"]} + pair = "로더(타이어)+소형노면파쇄기" + a = _line(pair, "기계", "0.1", "5", "경비", "0302-0095", "P_a") + val.mark_combo({}, [a]) + res = dm.verdict([MAN, a], [MAN, {**a, "기호": "P_b"}], TOT, TOT) # 같은 조합 = 같음 + assert res["판정"] == dm.SURE and not res["참고"] + + +def test_quantity_kinds_and_unit_conversion() -> None: + tail = dm.verdict([_line("크레인", "노임", "0.2959", "9", code="LB1")], + [_line("크레인", "노임", "0.2963", "9", code="LB1")], TOT, TOT) # fmt: skip + assert tail["판정"] == dm.SURE and [x["항"] for x in tail["참고"]] == ["수량 끝자리"] + poom = dm.verdict([_line("특별인부", "노임", "0.46", "9", code="LB3")], + [_line("특별인부", "노임", "0.48", "9", code="LB3", text="Q")], TOT, TOT) # fmt: skip + assert [x["항"] for x in poom["참고"]] == ["품 숫자"] and "0.46 ↔ 0.48" in poom["참고"][0]["글"] + assert "바꾸면 우리 값" in poom["참고"][0]["글"] + two = [ + _line("배관공", "노임", "0.04", "9", code="LB1"), + _line("인부", "노임", "0.02", "9", code="LB2"), + ] + six = [ + _line("배관공", "노임", "0.24", "9", code="LB1"), + _line("인부", "노임", "0.12", "9", code="LB2"), + ] + res = dm.verdict(two, six, TOT, TOT) # 같은 배(× 6)가 두 줄 = 결과 단위 기준 다름 = 로직 + assert [x["항"] for x in res["다른"]] == ["단위 환산", "단위 환산"] and res["판정"] == dm.NEAR + one = dm.verdict(two[:1] + six[1:], six, TOT, TOT) # 한 줄만 배 = 수량 값 + assert one["판정"] == dm.SURE and [x["항"] for x in one["참고"]] == ["품 숫자"] + kind = dm.verdict([MAN], [_line("특별인부", "노임", "0.02", "100", code="LB000003")], TOT, TOT) + assert kind["판정"] != dm.SURE and kind["다른"] # 직종 다름 = 로직 + more = dm.verdict([MAN], [MAN, _line("모래", "재료", "1", "9", "재료비")], TOT, TOT) + assert more["판정"] != dm.SURE and more["다른"][0]["항"] == "줄 없음" # 줄 구성(㉡) = 로직 + + +# ── (b) 견본 ───────────────────────────────────────────────────────────── +def _judge(tag: str, no: int) -> dict: + whole, _, index, links = t4.ctx() + try: + doc = t4.dim.derive(t2.sk_of(t2.fn.emit(t2.native("EST", tag), no)), None, t2.whole()) + except FileNotFoundError: + pytest.skip("원파일 없음") + return dm.match(doc, t4.dim.Links(whole, "우리"), index, links) + + +def _kinds(got: dict) -> list[str]: + return [x["항"] for x in got.get("참고") or []] + + +def test_backfill_spec_and_quantity() -> None: + got = _judge("main", 230) + assert got["판정"] == dm.SURE and got["키"] == "GF000113" and not got["다른"] + assert {"규격", "수량"} <= set(_kinds(got)) + assert got["바꿈"] == [ + {"기호": "P_굴착기무한궤", "기계": "0201-0020", "이름": "굴착기(무한궤도)", "규격": "0.2㎥"} + ] + + +def test_pc_slab_tail_and_manhole_poom() -> None: + slab = _judge("main", 850) + assert slab["판정"] == dm.SURE and slab["키"] == "GC000257" and _kinds(slab) == ["수량 끝자리"] + hole = _judge("main", 828) + assert hole["판정"] == dm.SURE and hole["키"] == "GC000252" and "품 숫자" in _kinds(hole) + assert hole["옵션"] == {"규격": "D1,800"} # ㉠ 이름 글 「D1800」 = 선택 「D1,800」 + + +def test_cut_soil_is_machine_work_and_pipe_stays_near() -> None: + work = _judge("거창", 46) + assert work["판정"] == val.WORK and not work.get("키") + assert _kinds(work) == ["작업량 틀"] and "GC001147" in work["참고"][0]["글"] + pipe = _judge("거창", 19) + kinds = [d["항"] for d in pipe["다른"]] + assert pipe["판정"] == dm.NEAR and pipe["키"] == "GF000179" + assert kinds.count("단위 환산") == 2 and "율 줄" in kinds + + +def test_machine_work_needs_one_machine_group() -> None: + names = dm.note._names + head = {"가져온": {"기계": [{"기호": "P_a"}, {"기호": "P_b"}]}, "식": []} + one = [_line("굴착기", "기계", "0.03", "5", "경비", "0201-0070", "P_a", "1 ÷ Q")] + assert val.work(head, one, names)["판정"] == val.WORK + assert val.work(head, [{**one[0], "수량글": "0.03"}], names) is None # 수량 = 수뿐 + assert val.work(head, [*one, {**MAN, "기호": "w"}], names) is None # 인력 섞임 = 보통 길 + both = [*one, {**one[0], "기호": "P_b", "코드": "0240-0007"}] + assert val.work(head, both, names) is None # 기계 둘(조합 아님) + combo = {"가져온": {"기계": [{"기호": "P_a", "조합첫": True}, {"기호": "P_b", "조합": True}]}} + assert val.work(combo, both, names)["판정"] == val.WORK # 조합 기계 = 한 묶음 + + +# ── (c) 옵션 확인 ──────────────────────────────────────────────────────── +def test_option_check_when_values_tie() -> None: + doc = {"변수": [{"기호": "S", "아래": "규격", "이름": "규격", "열쇠": "규격", + "연결": {"갈래": "선택", "목록": ["A", "B"], "값": "A"}}]} # fmt: skip + vid = dm.md.var_id(doc["변수"][0]) + got = val.option_check(doc, {vid: "A"}, [{vid: "A"}, {vid: "B"}], {vid}) + assert len(got) == 1 and "규격 = A(기본값" in got[0]["글"] + assert not val.option_check(doc, {vid: "A"}, [{vid: "A"}], {vid}) # 하나로 갈림 = 없음 + assert not val.option_check(doc, {vid: "A"}, [{vid: "A"}, {vid: "B"}], set()) # 수량 무관 + + +# ── (d) 바꾸기 · 되돌리기 ──────────────────────────────────────────────── +def test_swap_puts_imported_spec_machine_and_back(world) -> None: + folder = world["personal"] + try: + est = t2._file(t2.EST["main"]) + except FileNotFoundError: + pytest.skip("원파일 없음") + before = {p.name: p.read_bytes() for p in dm.ml.FOLDER.glob("수식_*.json")} + with store.at(folder): + hp = fh.upload_native(folder, est.name, est.read_bytes(), t2.WHO)["키"] + name = fh.make(folder, hp, 230)["이름"] + money0 = t4._money(name) + found = msk.find(name, store.read("sangeun", name)["판"]) + meta = found[dm.KEY] + assert meta["판정"] == dm.SURE and meta["바꿈"][0]["기계"] == "0201-0020" + out = msk.swap(name, found["판"]) + assert [x["기계"] for x in out["바꾼기계"]] == ["0201-0020"] + from M02_MasterTemplete import M02_Doc_Sk_Path as path + + doc = path.read(name)["문서"] + var = next(v for v in doc["변수"] if dm.md.var_id(v) == "P_굴착기무한궤") + assert var["연결"]["입력"]["기계"] == "'0201-0020'" + line = next(x for x in doc["금액"] if x["단가"] == "P_굴착기무한궤") + assert (line["이름"], line["규격"]) == ("굴착기(무한궤도)", "0.2㎥") + assert line["묶음"] == "굴착기(무한궤도) 0.2㎥" # 묶음 제목도 가져온 규격 + base = copy.deepcopy(dm.ml.load_all()["GF000113"]) # M01 값 그대로 · 기계만 가져온 규격 + for v in base["변수"]: + if dm.md.var_id(v) == "P_굴착기무한궤": + v["연결"]["입력"]["기계"] = "'0201-0020'" + want = dm._calc(base, dm.ml.Links(t2.whole()), dict(meta["옵션"])) + assert t4._money(name) == [want[k] for k in t4.COSTS] and t4._money(name) != money0 + msk.back(name, store.read("sangeun", name)["판"]) + again = store.read("sangeun", name)["문서"] + assert again["가져온"]["로직"] and not again.get("바탕") + assert t4._money(name) == money0 # 되돌리기 = 원래 가져온 식 금액 + with store.at(folder): + gc = t2._file(t2.EST["거창"]) + hp2 = fh.upload_native(folder, gc.name, gc.read_bytes(), t2.WHO)["키"] + cut = fh.make(folder, hp2, 46)["이름"] + found = msk.find(cut, store.read("sangeun", cut)["판"]) + assert found[dm.KEY]["판정"] == val.WORK + with pytest.raises(store.StoreError) as e: + msk.swap(cut, found["판"]) + assert e.value.status == 409 + assert before == {p.name: p.read_bytes() for p in dm.ml.FOLDER.glob("수식_*.json")} + + +# ── (e) 전수 ───────────────────────────────────────────────────────────── +@pytest.mark.skipif(os.environ.get("S81211_ALL") != "1", reason="전수 = S81211_ALL=1") +def test_every_block_values() -> 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 got["판정"].get(val.WORK, 0) >= 1 and got["판정"][dm.SURE] >= 184 + assert not set(val.VALUE) & set(got["근접항"]) # 값 차이 = 참고 diff --git a/resources/tester/test_812_2_match_logic.py b/resources/tester/test_812_2_match_logic.py index 2e39ccc89..36501fbec 100644 --- a/resources/tester/test_812_2_match_logic.py +++ b/resources/tester/test_812_2_match_logic.py @@ -98,7 +98,10 @@ def test_rate_value_is_note_structure_is_logic() -> None: def test_machine_labor_kind_differs_blocks() -> None: a = [*A, _line("굴삭기", "기계", "0.1", "500", "경비", "0201-0070")] - b = [*A, _line("굴삭기", "기계", "0.1", "500", "경비", "0201-0080")] + 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]]