knowledge(마스터): 인력 열 한 벌 정리 — 조사 → 구분 · 상세구분 · 상태 · 일시간 · 준용 공통 칸

- 인력.json 392 줄이 같은 열 한 벌(키 · 원문번호 · 구분 · 상세구분 · 이름 · 규격 · 단위 · 값 · 출처 · 일시간 · 상태 · 옛이름 · 비고 · 준용)
- 건설업 미공표 14 는 4-라 산정값을 값에 · 상태 「산정」 · 근거는 비고 한 줄 · 산정·신뢰도·업종·부문·환산비·후보 등 열두 칸 없앰
- 머리 「구분」 에 원문 · 기관 · 판 · 공표일 · 원천 · 상세구분 등록 — 새 조사는 한 항목 더하고 줄만 붙이면 끝
- 엔진은 준용이 있으면 그 직종 값 · 없으면 값 · check_master 인력 열 검사 · M01 구분·상세구분 거름과 구분 목록 API · 빌더도 새 열

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
2026-09-20 15:12:54 +09:00
co-authored by Claude Opus 5
parent cfd8f67471
commit 1447750e89
17 changed files with 775 additions and 653 deletions
+31 -6
View File
@@ -134,11 +134,36 @@ def refs_of(rows_: list[dict]) -> dict[str, str]:
return out
def rows(file: str, page: int, size: int, q: str, unlinked: bool = False, sub: str = "") -> dict:
def subs(file: str) -> dict:
"""하위 거름 목록 — 인력 「구분」 · 기계 「세부분류」 묶음(머리에 등록된 것) · 그 밖은 빈 목록."""
data, version = read(file)
slot = next((s for s in ("구분", "세부분류") if isinstance(data.get(s), dict)), "")
return {
"file": file,
"version": version,
"slot": slot,
"subs": [
{"name": name, "book": head.get("원문"), "details": head.get("상세구분") or []}
for name, head in (data.get(slot) or {}).items()
],
}
def rows(
file: str,
page: int,
size: int,
q: str,
unlinked: bool = False,
sub: str = "",
detail: str = "",
) -> dict:
data, version = read(file)
hits = [r for r in data.get(items_key(data)) or [] if _hit(r, q)]
if sub: # 인력 조사 · 기계 세부분류
hits = [r for r in hits if sub in (r.get("조사"), r.get("세부분류"))]
if sub: # 인력 구분 · 기계 세부분류
hits = [r for r in hits if sub in (r.get("구분"), r.get("세부분류"))]
if detail: # 인력 상세구분
hits = [r for r in hits if r.get("상세구분") == detail]
if unlinked: # 품셈재료 — 아직 못 이은 줄
hits = [r for r in hits if not r.get("연결")]
page, size = max(page, 1), min(max(size, 1), 500)
@@ -298,13 +323,13 @@ def _lowest(value) -> object:
def pick(kind: str, q: str, limit: int) -> dict:
"""고르기 창 — `procure` 나라장터자재(ref = 나라장터:<키>) · `price` 시중물가(관급 조달 줄 포함 · ref = 키)
· `job` 값 있는 공표 노임 직종(준용대상 빼고 모든 조사)(ref = 키) · 이름·규격 낱말이 모두 들어간 줄."""
· `job` 값 있는 공표 노임 직종(미확보 빼고 모든 구분)(ref = 키) · 이름·규격 낱말이 모두 들어간 줄."""
if kind not in _PICK:
raise StoreError(404, f"없는 고르기 「{kind}」")
words = [_squash(w) for w in q.split()]
hits = []
for row in read(_PICK[kind])[0].get("줄") or []:
if kind == "job" and (row.get("값") is None or row.get("조사") == "준용대상"):
if kind == "job" and (row.get("값") is None or row.get("구분") == "미확보"):
continue
text = _squash(f"{row.get('이름')} {row.get('규격')} {' '.join(row.get('옛이름') or [])}")
if all(w in text for w in words):
@@ -312,7 +337,7 @@ def pick(kind: str, q: str, limit: int) -> dict:
hits.append(
{
"ref": f"나라장터:{key}" if kind == "procure" else key,
**{k: row.get(k) for k in ("원문번호", "조사", "이름", "규격", "단위")},
**{k: row.get(k) for k in ("원문번호", "구분", "이름", "규격", "단위")},
"값": _lowest(row.get("값")),
"관급": kind == "price" and row["값"]["조달"].get("값") is not None,
}