fix(재료): 품셈재료 고르기 검증 반영 — 다른 물건 18줄 비움 · 규격 표기 정규화(∅→Φ) · 숫자 경계 맞대기
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import unicodedata
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
@@ -56,12 +57,14 @@ OVERRIDE = {
|
||||
# 이름이 같은 자재품목 줄이 하나뿐인 재료 — 그 줄을 대표로
|
||||
"MP000105": ("건축마감", "천장·바닥·마감재", "MT007262"), # ROOFSHEET
|
||||
"MP000168": ("건축마감", "천장·바닥·마감재", "MT008074"), # 초배지
|
||||
"MP000289": ("잡재료", "고철·기타금속", "MT003499"), # 함석
|
||||
"MP000292": ("잡재료", "고철·기타금속", "MT003499"),
|
||||
"MP000307": ("잡재료", "고철·기타금속", "MT003499"),
|
||||
"MP000312": ("잡재료", "고철·기타금속", "MT003499"),
|
||||
"MP000318": ("잡재료", "고철·기타금속", "MT003499"),
|
||||
"MP000339": ("잡재료", "고철·기타금속", "MT003499"),
|
||||
# 검증(ref/_검증_품셈재료_고르기.md) — 이름만 비슷한 다른 물건 · 규격 다른 대표 · 묶음 안 맞음: 비움
|
||||
**{
|
||||
k: None
|
||||
for k in (
|
||||
"MP000013 MP000268 MP000284 MP000291 MP000322 MP000354 MP000080 MP000244 MP000071 "
|
||||
"MP000122 MP000138 MP000059 MP000289 MP000292 MP000307 MP000312 MP000318 MP000339"
|
||||
).split()
|
||||
},
|
||||
}
|
||||
NO_GROUP = "자재품목 묶음에 짝이 없음 — 관리자가 화면에서 이음"
|
||||
NO_ROW = "자재품목에 그 묶음 줄이 없음"
|
||||
@@ -73,6 +76,17 @@ FIELD = re.compile(r'("연결": (?:null|"[^"]*"|\{[^{}]*\}))(, "고르기": (?:n
|
||||
NOTE_FIELD = re.compile(r'(, "비고": )(null|"(?:[^"\\]|\\.)*")')
|
||||
|
||||
|
||||
def _spec(s) -> str:
|
||||
"""규격 표기 맞춤 — 지름 기호(∅ø⌀→Φ) 뒤 빈칸 없앰 · ㎜→mm."""
|
||||
return re.sub(r"[∅ø⌀]\s*", "Φ", unicodedata.normalize("NFKC", str(s or "")).replace("∅", "Φ"))
|
||||
|
||||
|
||||
def _has(word: str, spec) -> bool:
|
||||
"""낱말이 규격 글자에 숫자 경계로 듦 — 「50mm」 가 「150mm」 에 걸리지 않게."""
|
||||
w = re.escape(mm.plain_spec(_spec(word)))
|
||||
return re.search(rf"(?<![\d.]){w}(?!\d)", mm.plain_spec(_spec(spec))) is not None
|
||||
|
||||
|
||||
def 고르기(row: dict, market: list[dict]) -> tuple[dict | None, str]:
|
||||
"""한 줄의 고르기 조건 — (조건 또는 None, 까닭)."""
|
||||
key = str(row.get("키"))
|
||||
@@ -92,11 +106,12 @@ def 고르기(row: dict, market: list[dict]) -> tuple[dict | None, str]:
|
||||
if not hits:
|
||||
return None, NO_ROW
|
||||
대표 = {"대표": rep[0]} if rep else {}
|
||||
want = [mm.plain_spec(w) for w in str(row.get("규격") or "").replace(",", " ").split()]
|
||||
spec = _spec(row.get("규격")).replace(",", " ").strip()
|
||||
want = spec.split()
|
||||
cond = {"구분": sub, "상세구분": detail, **대표}
|
||||
if want and any(all(w in mm.plain_spec(r.get("규격")) for w in want) for r in hits):
|
||||
cond = {"구분": sub, "상세구분": detail, "규격": row["규격"], **대표}
|
||||
narrow = [r for r in hits if all(w in mm.plain_spec(r.get("규격")) for w in want)]
|
||||
narrow = [r for r in hits if all(_has(w, r.get("규격")) for w in want)] if want else []
|
||||
if narrow:
|
||||
cond = {"구분": sub, "상세구분": detail, "규격": spec, **대표}
|
||||
got = _단위(row, cond, narrow, market)
|
||||
if got[0]:
|
||||
return got
|
||||
|
||||
Reference in New Issue
Block a user