fix(재료): 품셈재료 고르기 단위 거름 — 단위·이름 같은 줄을 대표로, 없으면 비움

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
2026-09-20 23:00:17 +09:00
co-authored by Claude Sonnet 5
parent 53151917ba
commit 817c0331f6
2 changed files with 148 additions and 122 deletions
@@ -65,6 +65,9 @@ OVERRIDE = {
}
NO_GROUP = "자재품목 묶음에 짝이 없음 — 관리자가 화면에서 이음"
NO_ROW = "자재품목에 그 묶음 줄이 없음"
NO_UNIT = "자재품목 그 묶음에 같은 단위·이름 줄이 없음"
UNIT = {"": "kg", "": "ton", "Ton": "ton", "M": "m", "": "", "L": "", "EA": "", "set": "SET", "Set": "SET"}
PRICE = ("물가자료", "유통물가", "물가정보", "거래가격", "관급")
NOTE = re.compile(r"\s*·?\s*고르기 없음\([^)]*\)")
FIELD = re.compile(r'("연결": (?:null|"[^"]*"|\{[^{}]*\}))(, "고르기": (?:null|\{[^{}]*\}))?')
NOTE_FIELD = re.compile(r'(, "비고": )(null|"(?:[^"\\]|\\.)*")')
@@ -90,9 +93,32 @@ def 고르기(row: dict, market: list[dict]) -> tuple[dict | None, str]:
return None, NO_ROW
대표 = {"대표": rep[0]} if rep else {}
want = [mm.plain_spec(w) for w in str(row.get("규격") or "").replace(",", " ").split()]
cond = {"구분": sub, "상세구분": detail, **대표}
if want and any(all(w in mm.plain_spec(r.get("규격")) for w in want) for r in hits):
return {"구분": sub, "상세구분": detail, "규격": row["규격"], **대표}, ""
return {"구분": sub, "상세구분": detail, **대표}, ""
cond = {"구분": sub, "상세구분": detail, "규격": row["규격"], **대표}
hits = [r for r in hits if all(w in mm.plain_spec(r.get("규격")) for w in want)]
return _단위(row, cond, hits, market)
def _단위(row: dict, cond: dict, hits: list[dict], market: list[dict]) -> tuple[dict | None, str]:
"""후보 첫 줄의 단위가 원문 단위와 다르면 — 단위·이름이 같은 줄을 대표로, 없으면 비움."""
u = lambda x: UNIT.get(x, x) # noqa: E731
want = u(str(row.get("단위") or ""))
val = lambda r: [r[k] for k in PRICE if r.get(k) is not None] # noqa: E731
if not want:
return cond, ""
if cond.get("대표"):
rep = next(r for r in market if r[""] == cond["대표"])
return (cond, "") if u(rep["단위"]) == want else (None, NO_UNIT)
first = next((r for r in hits if val(r)), hits[0])
if u(first["단위"]) == want:
return cond, ""
root = re.sub(r"\s+", "", re.split(r"[(,\-]", str(row["이름"]))[0])
same = [r for r in hits if u(r["단위"]) == want and val(r) and root in re.sub(r"\s+", "", r["이름"])]
if not same:
return None, NO_UNIT
best = min(same, key=lambda r: (min(val(r)), r[""]))
return {**cond, "대표": best[""]}, ""
def main(show: bool) -> int: