feat(M01): 재료 기본 검색어 찾기 · 고름 받기 · 단위 환산 · 단위 경고 (PLAN 8-2)

- 새 master_pick.py — 검색어 찾기(지역 낱말은 차례만) · 고름(호표 줄 차례 → 자재 키) · 같은 성격 단위 환산 · 단위경고 칸 · 기계 목록 밖 원문 분류번호 받기
- Router 몸에 고름 칸 · check_master 검색어 후보 0 · 단위 경고
- 검색어 없는 줄은 옛 길 그대로 — 1,354 자동값 금액 변화 0
- 시험 test_m01_pick 8개

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
2026-09-24 20:24:43 +09:00
co-authored by Claude Sonnet 5
parent f29dc14c9a
commit af842c0337
5 changed files with 304 additions and 17 deletions
@@ -120,7 +120,9 @@ def static(cond: dict) -> dict:
def cond_text(cond: dict) -> str:
"""고르기 조건 한 글자 열쇠 — 「구분|상세구분|규격|대표」 · 화면 단가 미리보기가 줄을 찾는 이름."""
return "|".join(str(cond.get(k) or "") for k in PICK_KEYS)
return "|".join(str(cond.get(k) or "") for k in PICK_KEYS) + (
f"|{cond['검색어']}" if cond.get("검색어") else ""
)
def by_class(master: mf.Master) -> dict[str, dict]:
@@ -140,7 +142,10 @@ def candidates(
) -> list[str]:
"""고르기 조건 안 자재품목 키 — 구분 · 상세구분 · 이름 · 규격 낱말이 모두 든 줄 · 파일 차례대로.
`unit` 을 주면 그 단위(호표 줄 단위)와 같은 줄만 — 단위가 다르면 다른 물건.
입력 `자재지역` 이 있으면 이름에 그 지역이 든 줄만(그런 줄이 없으면 조건 안 전부)."""
입력 `자재지역` 이 있으면 이름에 그 지역이 든 줄만(그런 줄이 없으면 조건 안 전부).
조건에 `검색어` 가 있으면 기본 검색어 찾기(`master_pick`)."""
if cond.get("검색어"):
return mp.search(master, cond, env, unit)
want = [plain_spec(w) for w in str(cond.get("규격") or "").split()]
want_name = [plain(w) for w in str(cond.get("이름") or "").split()]
detail = cond.get("상세구분")
@@ -160,6 +165,8 @@ def candidates(
def pick(master: mf.Master, cond: dict, env: dict, unit: str | None = None) -> str:
"""시험 계산이 쓸 줄 — 관리자가 정한 `대표`, 없으면 조건 안 값 있는 첫 줄(단위 같은 줄만)."""
if cond.get("검색어"):
return mp.pick(master, cond, env, unit)
if cond.get("대표"):
return str(cond["대표"])
keys = candidates(master, cond, env, unit)
@@ -173,6 +180,8 @@ def pick(master: mf.Master, cond: dict, env: dict, unit: str | None = None) -> s
def check_unit(master: mf.Master, where: str, cond: dict, unit: str | None) -> list[str]:
"""단위 경고 — 호표 줄·품셈재료 줄 단위와 맞는 후보가 없거나 대표 줄 단위가 다름.
틀린 데이터가 아니라 좁혀야 할 조건이라 `check_pick` 과 따로 봄(`check_master 단위`)."""
if cond.get("검색어"):
return mp.check_warn(master, where, cond, unit)
cond = static(cond)
rows = master.index.get(MARKET, {})
rep = str(cond.get("대표") or "")
@@ -194,6 +203,8 @@ def check_pick(master: mf.Master, where: str, cond: dict, unit: str | None = Non
값에 `{입력}` 이 든 칸(관경 등)은 계산 때 채워지므로 검사에서 뺌.
지역·계약종별 조건은 구분 없이 이름 하나로 자재품목·유가전력을 넓게 찾음(_region · _tariff)
— 여기서는 이름 칸만 있는지 봄(후보 0 은 계산 때 판단)."""
if cond.get("검색어") is not None and not set(cond) - {*PICK_KEYS, "검색어"}:
return mp.check_zero(master, where, cond)
if set(cond) - set(PICK_KEYS):
return [f"{where} · 재료 고르기 조건 모양 「{cond}」 — {' · '.join(PICK_KEYS)}"]
if ("지역" in cond and cond["지역"] != "입력") or (
@@ -257,3 +268,4 @@ def element(
import master_formula as mf # noqa: E402 — 서로 부름 · 이 모듈 이름이 다 선 뒤에 읽음
import master_pick as mp # noqa: E402 — 검색어 찾기