knowledge(M01): 값 없는 자재품목 줄 가운데 로직이 실제로 쓰는 것만 가림
- `scripts/check_값없는줄.py` 신설 — 로직 1,354 줄을 훑어 호표 직접 지정·고르기 조건 후보· 대표 줄·품셈재료 연결(문자열 키·지역 조건)까지 실제 참조를 셈, 값은 안 채움 - 재료_자재품목.json 다섯 칸(물가자료·유통물가·물가정보·거래가격·관급) 모두 빈 줄 345 가운데 로직이 실제로 가리키는 진짜 구멍은 31 줄 — `ref/_분석_값없는줄.md` 신설 - `ref/_관리자값_미확보.md` 재검증 — 45종 가운데 6종은 고르기 조건으로 바뀌었거나 로직이 재료 자체를 뺀 것이라 로직이 안 씀으로 옮김, 남은 39종·로직 49개는 그대로 관리자 몫 - `ref/_없는_재료.md` 재검증 — 111줄 모두 지금도 로직이 부름, 뺄 줄 없음 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 관리자가 채울 재료 값 (읽기 전용 · 자동 생성)
|
||||
|
||||
일괄 시험 계산(`check_master 계산전부`)이 「값 없음 — 관리자가 채울 값」 으로 멈춘 자리 — 재료 45 종 · 로직 56 개.
|
||||
일괄 시험 계산(`check_master 계산전부`)이 「값 없음 — 관리자가 채울 값」 으로 멈춘 자리 — 재료 39 종 · 로직 49 개.
|
||||
|
||||
값을 어디서 가져올지(자재품목 줄 잇기 · 시중물가)는 관리자 몫 — 여기서는 이름만 모음.
|
||||
|
||||
@@ -10,16 +10,13 @@
|
||||
| MP000290 | Nozzle | 3 | GC000933 · GC000934 · GC000938 |
|
||||
| MP000293 | 세유 | 3 | GC000939 · GC000986 · GC000993 |
|
||||
| MP000048 | JOINT FILLER | 2 | GF000197 · GF000208 |
|
||||
| MP000094 | 쉬즈관 | 2 | GC000230 · GC000237 |
|
||||
| MP000216 | 철구(Shot ball) | 2 | GC000375 · GC000822 |
|
||||
| MP000299 | 탄소봉 | 2 | GC000941 · GC000942 |
|
||||
| MP000359 | 중유 | 2 | GC000943 · GC000948 |
|
||||
| MP000023 | VR관(소켓식) | 1 | GF000173 |
|
||||
| MP000052 | 스페이셔(몰탈 블록) | 1 | GF000200 |
|
||||
| MP000055 | 스티로폴 | 1 | GF000202 |
|
||||
| MP000060 | 콘크리트 표면 강화재(하드너) | 1 | GF000209 |
|
||||
| MP000065 | 틈메우기돌 | 1 | GF000223 |
|
||||
| MP000066 | 철망태(사각형 돌망태) | 1 | GF000235 |
|
||||
| MP000070 | 깃발 | 1 | GF000081 |
|
||||
| MP000076 | 피복제 | 1 | GC000145 |
|
||||
| MP000082 | 에폭시 | 1 | GC000337 |
|
||||
@@ -34,10 +31,8 @@
|
||||
| MP000176 | 표준보강메시 | 1 | GC000628 |
|
||||
| MP000177 | 고강도메시 | 1 | GC000629 |
|
||||
| MP000201 | 실리콘 | 1 | GC000752 |
|
||||
| MP000202 | IV전선 | 1 | GC000409 |
|
||||
| MP000209 | 버너 | 1 | GC000360 |
|
||||
| MP000211 | 테르밋용재 | 1 | GC000361 |
|
||||
| MP000215 | 용접봉 | 1 | GC000374 |
|
||||
| MP000218 | 철편(Grit) | 1 | GC000376 |
|
||||
| MP000235 | 슈 | 1 | GC000433 |
|
||||
| MP000239 | 베인 전용로드 | 1 | GC000435 |
|
||||
@@ -49,7 +44,6 @@
|
||||
| MP000310 | Tar Epoxy | 1 | GC000944 |
|
||||
| MP000314 | drill | 1 | GC000947 |
|
||||
| MP000319 | Tar Epoxy | 1 | GC000950 |
|
||||
| MP000357 | 카트리지 | 1 | GC000646 |
|
||||
| MP000363 | 아스팔트싱글 | 1 | GC000654 |
|
||||
|
||||
## 값 말고 다른 까닭으로 남은 멈춤 (손대지 않음)
|
||||
@@ -66,3 +60,18 @@
|
||||
- 자재품목에 후보는 있으나 규격·지역 선택이 관리자 몫이라 못 이은 것 3건 — MP000023 VR관(소켓식, 후보 있음·단위 본→m 환산 안 함) · MP000066 철망태(사각형 돌망태, 후보 있음·단위 조→㎥ 환산 안 함) · MP000215 용접봉(강교 제작용, 후보 12줄·규격 다수).
|
||||
- 나머지 42건 — 자재품목 전체(30,592줄) · 재료_유가전력.json(오피넷 휘발유·경유·등유·한전 전력 56줄) 다시 훑어도 짝 없음 확인(바뀐 것 없음). 코크스·세유·중유·그리스·머신오일 계열은 해당 상세구분(잡재료/용접·가스 등) 통째로 훑어도 없음.
|
||||
- 오피넷 홈페이지(중유·벙커C유) 검색 — 시세표가 동적 페이지라 검색 결과에 실제 값이 안 잡힘 · 값을 지어내지 않아 그대로 둠.
|
||||
|
||||
## 2026-09-22 로직이 실제로 부르는지 다시 잣대질(로직이 안 쓰는 6건 표에서 뺌)
|
||||
|
||||
`check_값없는줄.py` — 로직 1,354 줄을 다시 훑어 위 표 45종이 지금도 로직 호표에서 그 MP 키를 부르는지 확인. 6건은 더 안 불러 뺌.
|
||||
|
||||
| 키 | 이름 | 까닭 |
|
||||
|---|---|---|
|
||||
| MP000094 | 쉬즈관 | GC000230·GC000237 호표에서 재료 줄 자체가 빠짐 — 로직이 이제 재료를 안 씀 |
|
||||
| MP000023 | VR관(소켓식) | GF000173 고무링이 재료 고르기 조건(관·이음관·PVC관)으로 바뀌어 이 MP 줄을 더 안 부름 |
|
||||
| MP000066 | 철망태(사각형 돌망태) | GF000235 철망태·채움재가 고르기 조건(매트·토목섬유·돌망태·사방)으로 바뀜 |
|
||||
| MP000202 | IV전선 | GC000409 IV전선이 고르기 조건(전기·통신·케이블·전선)으로 바뀜 |
|
||||
| MP000215 | 용접봉 | GC000374 용접봉(강교 제작)이 고르기 조건(잡재료·용접·가스)으로 바뀜 |
|
||||
| MP000357 | 카트리지 | GC000646 카트리지가 고르기 조건(볼트·앵커·철물·앵커, 대표 MT007751 — 그 줄은 값 있음)으로 바뀜 |
|
||||
|
||||
나머지 39종·로직 49개는 그대로 관리자 몫.
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 값 없는 줄 분석 — 다섯 칸이 모두 빈 줄 가운데 로직이 실제로 쓰는 것
|
||||
|
||||
읽기 전용 분석 · 값 새로 안 채움 · 뽑은 법 `scripts/check_값없는줄.py`(로직 1,354 줄을 훑어 실제 참조를 셈).
|
||||
|
||||
문제 삼는 자리 = **다섯 칸(물가자료·유통물가·물가정보·거래가격·관급)이 하나도 없는 줄** 뿐 — 다섯 칸 가운데 일부만 있으면 문제 아님.
|
||||
|
||||
## ① 재료_자재품목.json 다섯 칸 모두 빈 줄
|
||||
|
||||
MT 30,592 줄 가운데 **345 줄**이 다섯 칸 모두 없음.
|
||||
|
||||
## ② 그 가운데 로직이 실제로 가리키는 줄 — 진짜 구멍
|
||||
|
||||
호표 요소가 그 키를 바로 적거나 · 재료 고르기 조건(구분·상세구분·규격)의 후보로 걸리거나 · 대표 줄로 콕 집힌 것만 셈 — 345 줄 가운데 **31 줄**.
|
||||
|
||||
## ③ 관리 파일 두 개 다시 잣대질(같은 방법으로 재확인)
|
||||
|
||||
- `ref/_관리자값_미확보.md`(품셈재료 연결 안 된 45종) — 재검증 결과 **6종**이 이제 로직이 안 씀(고르기 조건으로 바뀌었거나 그 로직 자체가 재료 줄을 뺌) → 표에서 빼고 「로직이 안 씀」 절로 옮김. 남은 **39종·로직 49개**는 그대로 관리자 몫.
|
||||
- `ref/_없는_재료.md`(자재품목에 짝 없는 품셈재료 111줄) — 재검증 결과 **111줄 모두 지금도 로직이 부름** → 뺄 줄 없음.
|
||||
|
||||
두 파일에 각각 「2026-09-22 로직이 실제로 부르는지 다시 잣대질」 절로 적어 둠.
|
||||
|
||||
## ④ 끝 수로 · 재료 이름 목록(20개까지)
|
||||
|
||||
- 다섯 칸 모두 빈 줄 — **345**
|
||||
- 그 가운데 로직이 쓰는 줄(진짜 구멍) — **31**
|
||||
- 이름 목록(20개, 나머지 11개는 스크립트 재실행으로 확인):
|
||||
|
||||
| 키 | 이름 | 구분·상세구분 |
|
||||
|---|---|---|
|
||||
| MT000009 | 치 즐(0.4㎥) | 기계·설비·기계류 |
|
||||
| MT000011 | 치 즐(0.7㎥) | 기계·설비·기계류 |
|
||||
| MT000519 | 시스템동바리(멍애제) | 거푸집·가설재·동바리·비계 |
|
||||
| MT000521 | 수직재 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000522 | 수직재 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000523 | 수평재 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000524 | 수평재 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000527 | 안전발판 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000528 | 받침철물 | 볼트·앵커·철물·와이어로프·클램프 |
|
||||
| MT000529 | 비계버팀대 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000531 | 수평재 | 거푸집·가설재·동바리·비계 |
|
||||
| MT000533 | 안전발판 | 거푸집·가설재·동바리·비계 |
|
||||
| MT003480 | 필러 | 시멘트·골재·모르타르 |
|
||||
| MT003850 | 자연자갈, 대전, 도착도 | 시멘트·골재·골재 |
|
||||
| MT003860 | 쇄석골재, 가평, 도착도 | 시멘트·골재·골재 |
|
||||
| MT004059 | 혼합골재, 가평, 도착도 | 시멘트·골재·골재 |
|
||||
| MT005950 | 원타임Ⅰ | 도료·방수·접착·접착·혼화 |
|
||||
| MT007609 | 낙방사다리 | 거푸집·가설재·동바리·비계 |
|
||||
| MT007751 | 카트리지 | 볼트·앵커·철물·앵커 |
|
||||
| MT007754 | 기포제 | 도료·방수·접착·접착·혼화 |
|
||||
|
||||
거푸집·가설재(동바리·비계) 묶음이 절반 가까이 — 시스템동바리 계열 자재품목 줄에 값이 통째로 안 채워진 자리로 보임. 나머지는 토목자재 낱개.
|
||||
|
||||
값 확정은 관리자 몫 — 여기서는 찾아서 셈만 함.
|
||||
@@ -128,3 +128,7 @@
|
||||
- 자재품목에 후보는 있으나 규격·지역 선택이 관리자 몫이라 못 이은 것 5건 — MP000078 색소(후보 1줄 MT006740) · MP000082 에폭시(포켓식 후보 4줄) · MP000209 버너(후보 1줄 MT009352) · MP000214 퓨즈(후보 5줄) · MP000285 땜납(후보 2줄 MT001251·MT001252, 원문 규격 50:50과는 안 맞음).
|
||||
- 나머지 106건 — 자재품목 전체(30,592줄) 다시 훑어도(이름 겹침만·규격 대조 포함) 짝 없음 확인 · `_검증_재료_공공출처.md` 의 2022 하반기 조달청 시설자재 대조(에폭시·보호막·실리콘·노즐·아스팔트싱글 이름 겹침)도 지금 자재품목에는 없음(그 옛 자료는 새 마스터에 아직 안 들어옴).
|
||||
- 오피넷·한전 — 중유·코크스·세유·머신오일 계열은 재료_유가전력.json(오피넷 휘발유·경유·등유, 한전 전력 56줄) 어디에도 없음 · 오피넷 홈페이지 검색은 동적 페이지라 실제 값을 못 얻어 지어내지 않고 그대로 둠.
|
||||
|
||||
## 2026-09-22 로직이 실제로 부르는지 다시 잣대질
|
||||
|
||||
`check_값없는줄.py` — 로직 1,354 줄을 다시 훑어 위 표 111줄이 지금도 로직 호표에서 그 MP 키를 부르는지 확인. 111줄 모두 지금도 부름 — 뺄 줄 없음.
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""재료_자재품목.json 다섯 값 칸이 모두 빈 줄 가운데 로직이 실제로 가리키는 줄 — 읽기 전용 분석.
|
||||
|
||||
· 「빈 줄」 = 물가자료·유통물가·물가정보·거래가격·관급 다섯 칸이 모두 없음
|
||||
· 「로직이 가리킴」 = 로직 호표 요소가 그 키를 바로 적음 · 재료 고르기 조건(구분·상세구분·규격)의
|
||||
후보 줄 · 대표 줄로 콕 집음 · 품셈재료 연결(문자열 키 · 지역 조건)을 따라간 줄
|
||||
· 지역 조건(모래·자갈 등)은 실제 프로젝트 자재지역을 모르므로 지역을 안 가리고 이름·단위만 맞춤
|
||||
(후보를 넓게 잡아 「안 쓰임」 판정이 헛짚지 않게)
|
||||
· 값은 채우지 않음 · 마스터 파일을 고치지 않음
|
||||
|
||||
돌리기: ./venv/Scripts/python.exe resources/master_data/scripts/check_값없는줄.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
MASTER = HERE.parent
|
||||
sys.path.insert(0, str(HERE))
|
||||
|
||||
import check_master as cm # noqa: E402
|
||||
import master_material as mm # noqa: E402
|
||||
|
||||
PRICE = ("물가자료", "유통물가", "물가정보", "거래가격", "관급")
|
||||
|
||||
# 두 ref 표의 키 목록 — 로직이 지금도 부르는지 다시 잣대질할 때 씀 (`_관리자값_미확보.md`·`_없는_재료.md`)
|
||||
ADMIN_KEYS = (
|
||||
"MP000253 MP000290 MP000293 MP000048 MP000094 MP000216 MP000299 MP000359 "
|
||||
"MP000023 MP000052 MP000055 MP000060 MP000065 MP000066 MP000070 MP000076 MP000082 "
|
||||
"MP000095 MP000113 MP000129 MP000134 MP000144 MP000150 MP000169 MP000172 MP000176 "
|
||||
"MP000177 MP000201 MP000202 MP000209 MP000211 MP000215 MP000218 MP000235 MP000239 "
|
||||
"MP000241 MP000242 MP000250 MP000269 MP000294 MP000310 MP000314 MP000319 MP000357 "
|
||||
"MP000363"
|
||||
).split()
|
||||
NO_ITEM_KEYS = (
|
||||
"MP000012 MP000038 MP000048 MP000052 MP000055 MP000056 MP000057 MP000060 "
|
||||
"MP000065 MP000070 MP000076 MP000077 MP000078 MP000082 MP000095 MP000096 MP000101 "
|
||||
"MP000113 MP000129 MP000134 MP000139 MP000144 MP000148 MP000150 MP000169 MP000172 "
|
||||
"MP000176 MP000177 MP000201 MP000209 MP000210 MP000211 MP000212 MP000213 MP000214 "
|
||||
"MP000216 MP000218 MP000220 MP000221 MP000223 MP000235 MP000239 MP000240 MP000241 "
|
||||
"MP000242 MP000250 MP000253 MP000254 MP000255 MP000257 MP000258 MP000259 MP000260 "
|
||||
"MP000261 MP000262 MP000265 MP000269 MP000271 MP000272 MP000273 MP000274 MP000275 "
|
||||
"MP000276 MP000280 MP000281 MP000285 MP000286 MP000287 MP000288 MP000290 MP000293 "
|
||||
"MP000294 MP000295 MP000296 MP000297 MP000298 MP000299 MP000301 MP000302 MP000303 "
|
||||
"MP000304 MP000305 MP000306 MP000308 MP000309 MP000310 MP000314 MP000315 MP000319 "
|
||||
"MP000325 MP000326 MP000327 MP000328 MP000330 MP000334 MP000335 MP000336 MP000337 "
|
||||
"MP000338 MP000340 MP000341 MP000342 MP000343 MP000344 MP000345 MP000349 MP000351 "
|
||||
"MP000352 MP000353 MP000359 MP000363"
|
||||
).split()
|
||||
|
||||
|
||||
def all_empty(master) -> set[str]:
|
||||
"""MT 다섯 값 칸이 모두 빈 키."""
|
||||
return {
|
||||
key for key, row in master.index.get(mm.MARKET, {}).items() if not mm._offers(master, key)
|
||||
}
|
||||
|
||||
|
||||
def region_reach(master, name, unit) -> set[str]:
|
||||
"""MP 연결이 지역 조건(모래·자갈 등)일 때 이름 뿌리·단위만으로 넓게 잡은 후보."""
|
||||
want, need = mm.plain(name), (mm.plain_unit(unit) if unit else "")
|
||||
return {
|
||||
key
|
||||
for root, _, _, u, key in mm._market_index(master)
|
||||
if root.endswith(want) and (not need or u == need)
|
||||
}
|
||||
|
||||
|
||||
def reached(master) -> tuple[set[str], set[str]]:
|
||||
"""(로직이 가리키는 MT 키, 로직이 지금도 문자열로 부르는 MP 키)."""
|
||||
mt_hit: set[str] = set()
|
||||
mp_hit: set[str] = set()
|
||||
for path in sorted(MASTER.glob("로직_*.json")):
|
||||
rows = json.loads(path.read_text(encoding="utf-8")).get("줄", [])
|
||||
for row in rows:
|
||||
for h in row.get("호표") or []:
|
||||
e, unit = h.get("요소"), h.get("단위")
|
||||
if isinstance(e, str) and e[:2] == mm.MARKET:
|
||||
mt_hit.add(e)
|
||||
elif isinstance(e, dict) and "구분" in e:
|
||||
mt_hit.update(mm.candidates(master, e, None, unit))
|
||||
if e.get("대표"):
|
||||
mt_hit.add(str(e["대표"]))
|
||||
elif isinstance(e, str) and e[:2] == mm.LINKED:
|
||||
mp_hit.add(e)
|
||||
link = master.index.get(mm.LINKED, {}).get(e, {}).get("연결")
|
||||
if isinstance(link, str) and link[:2] == mm.MARKET:
|
||||
mt_hit.add(link)
|
||||
elif isinstance(link, dict) and "계약종별" not in link:
|
||||
mrow = master.index[mm.LINKED][e]
|
||||
mt_hit.update(region_reach(master, link.get("이름"), mrow.get("단위")))
|
||||
return mt_hit, mp_hit
|
||||
|
||||
|
||||
def main() -> int:
|
||||
master = cm.master()
|
||||
empty = all_empty(master)
|
||||
mt_hit, mp_hit = reached(master)
|
||||
gap = sorted(empty & mt_hit)
|
||||
print(f"MT 줄 {len(master.index.get(mm.MARKET, {}))}")
|
||||
print(f"다섯 칸 모두 빈 줄 {len(empty)} · 그 가운데 로직이 가리키는 줄 {len(gap)}")
|
||||
for key in gap:
|
||||
row = master.get(key)
|
||||
print(f" {key} {row.get('이름')} ({row.get('구분')}·{row.get('상세구분')})")
|
||||
print(f"\n로직이 지금도 MP 키를 문자열로 부르는 곳 {len(mp_hit)}")
|
||||
for title, keys in (
|
||||
("_관리자값_미확보.md 45종", ADMIN_KEYS),
|
||||
("_없는_재료.md 111줄", NO_ITEM_KEYS),
|
||||
):
|
||||
unused = [k for k in keys if k not in mp_hit]
|
||||
print(f"{title} 가운데 로직이 이제 안 씀 {len(unused)} — {unused}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user