feat(M01): 조달 찾기 확정 모양 · 품셈재료 가격 연결 · 건설노임 준용 직종 고르기
- 고르기 API GET /api/m01/pick (나라장터자재 · 시중물가 · 공표 직종) — 조달 찾기 옛 API 대체 - 시중물가 조달›출처 「나라장터:<열쇠>」 연결 · 끊기 뒤 변화 없음 · 조달 값·기준 칸 - 품셈재료 「가격 연결」 모달(이름·규격 미리 찾기 · 관급 표시 · 후보 조건 · 끊기) · 못 이은 줄만 보기 - 건설노임 미공표 줄 「준용」 직종 고르기 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
@@ -92,9 +92,11 @@ def files_of(group: str) -> list[dict]:
|
||||
return out
|
||||
|
||||
|
||||
def rows(file: str, page: int, size: int, q: str) -> dict:
|
||||
def rows(file: str, page: int, size: int, q: str, unlinked: bool = False) -> dict:
|
||||
data, version = read(file)
|
||||
hits = [r for r in data.get(items_key(data)) or [] if _hit(r, q)]
|
||||
if unlinked: # 품셈재료 — 아직 못 이은 줄
|
||||
hits = [r for r in hits if not r.get("연결")]
|
||||
page, size = max(page, 1), min(max(size, 1), 500)
|
||||
return {
|
||||
"file": file,
|
||||
@@ -227,19 +229,47 @@ def elements(group: str, q: str, limit: int) -> dict:
|
||||
return {"total": len(hits), "items": hits[: min(max(limit, 1), 200)]}
|
||||
|
||||
|
||||
def procurement(q: str, limit: int) -> dict:
|
||||
"""조달 찾기 창 — 나라장터자재 + 시중물가 안의 조달 줄에서 이름·규격 찾기 · `ref` = 「나라장터:<열쇠>」."""
|
||||
words = q.lower().split()
|
||||
_PICK = {
|
||||
"procure": "재료_나라장터자재.json",
|
||||
"price": "재료_시중물가.json",
|
||||
"job": "인력_건설노임.json",
|
||||
}
|
||||
|
||||
|
||||
def _squash(text) -> str:
|
||||
return "".join(str(text or "").lower().split())
|
||||
|
||||
|
||||
def _lowest(value) -> object:
|
||||
"""시중물가 줄 — 시중 다섯 칸 · 조달 값 가운데 낮은 값 · 그 밖은 `값` 그대로."""
|
||||
if not isinstance(value, dict):
|
||||
return value
|
||||
nums = [v for v in value["시중"].values() if isinstance(v, (int, float))]
|
||||
supply = value["조달"].get("값")
|
||||
return min(nums + ([supply] if supply is not None else []), default=None)
|
||||
|
||||
|
||||
def pick(kind: str, q: str, limit: int) -> dict:
|
||||
"""고르기 창 — `procure` 나라장터자재(ref = 나라장터:<열쇠>) · `price` 시중물가(관급 조달 줄 포함 · ref = 열쇠)
|
||||
· `job` 값 있는 건설노임 직종(ref = 열쇠) · 이름·규격 낱말이 모두 들어간 줄."""
|
||||
if kind not in _PICK:
|
||||
raise StoreError(404, f"없는 고르기 「{kind}」")
|
||||
words = [_squash(w) for w in q.split()]
|
||||
hits = []
|
||||
for book, only_procured in (("나라장터자재", False), ("시중물가", True)):
|
||||
data, _ = read(f"재료_{book}.json")
|
||||
for row in data.get("줄") or []:
|
||||
if only_procured and "조달" not in row:
|
||||
continue
|
||||
text = f"{row.get('이름', '')} {row.get('규격', '')}".lower()
|
||||
if all(w in text for w in words):
|
||||
brief = {k: row.get(k) for k in ("이름", "규격", "단위", "값")}
|
||||
hits.append({"ref": f"{book}:{row.get('열쇠')}", **brief})
|
||||
for row in read(_PICK[kind])[0].get("줄") or []:
|
||||
if kind == "job" and row.get("값") is None:
|
||||
continue
|
||||
text = _squash(f"{row.get('이름')} {row.get('규격')}")
|
||||
if all(w in text for w in words):
|
||||
key = str(row.get("열쇠"))
|
||||
hits.append(
|
||||
{
|
||||
"ref": f"나라장터:{key}" if kind == "procure" else key,
|
||||
**{k: row.get(k) for k in ("이름", "규격", "단위")},
|
||||
"값": _lowest(row.get("값")),
|
||||
"관급": kind == "price" and row["값"]["조달"].get("값") is not None,
|
||||
}
|
||||
)
|
||||
return {"total": len(hits), "items": hits[: min(max(limit, 1), 200)]}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user