diff --git a/resources/master_data/_틀.md b/resources/master_data/_틀.md index 5a393a4e..c9323756 100644 --- a/resources/master_data/_틀.md +++ b/resources/master_data/_틀.md @@ -44,7 +44,7 @@ ## 4. 출처 -- 한 칸 · `원문 이름 + 번호` — 「산림품셈 13-4-1」 · 「건설품셈 공통 8-4-1」(건설은 부문 필수) · 「건설노임 1018」 · 「질의회신 건협기술-2230」 · 「자체」 +- 한 칸 · `원문 이름 + 번호` — 「산림품셈 13-4-1」 · 「건설품셈 공통 8-4-1」(건설은 부문 필수) · 「건설노임 1018」 · 「질의회신 건협기술-2230」 · 「엔산법 시행령 별표2」 · 「자체」 - [주] 는 뒤에 붙임 — 「산림품셈 13-4-4 주⑩」 - 판(기준일)은 파일 머리에 한 번 · 인력·기계는 갈래 묶음 안에. @@ -92,7 +92,7 @@ - 인력 `구분` = 건설업 · 제조업 · 엔지니어링 · 측량 · 건설사업관리 · SW · 산림 · 미확보 · 구분별 원문·기관·판·공표일·원천·상세구분·비고는 머리 `구분` 묶음. - 새 조사 = 머리 `구분` 에 한 항목 더하고 줄을 붙이면 끝 · 키는 LB 일련번호 이어 받음. - `상세구분` = 제조업 업종 · 엔지니어링 부문 · 측량 기술계/기능계 분야 — 없으면 `null` · 목록은 머리에. -- `상태` = 공표 · 산정(미공표 직종의 원문 4-라 값을 `값` 에 넣음 · 근거는 `비고` 한 줄) · 미공표(원문에 값 없음) · 미확보(공표 노임에 같은 직종 없음) · 추정(원문이 이름을 맞대지 않아 작업 범위로 짐작한 대응 — `구분` 은 대응 직종 것 · `값` 은 비움 · `준용` 에 대응 직종 키 · 근거는 `비고` 한 줄). +- `상태` = 공표 · 산정(미공표 직종의 원문 4-라 값을 `값` 에 넣음 · 근거는 `비고` 한 줄) · 미공표(원문에 값 없음) · 미확보(공표 노임에 같은 직종 없음) · 추정(원문이 이름을 맞대지 않아 작업 범위로 짐작한 대응 — `구분` 은 대응 직종 것 · `준용` 에 그 직종 키 · `값`·`단위`·`일시간` 은 빌더가 준용 직종에서 채움 · 근거 문서는 `출처` 짧게). - `일시간` = 1일 노임 기준 시간 — 8 · 잠수부만 6(원문 4-가). - 기계 `세부분류` = 건설품셈 · 산림품셈 · 세부분류별 원문·판·주는 머리 `세부분류` 묶음. - 값이 여럿인 요소(기계)는 `값` 을 묶음으로 — `{ "가격": …, "상각비계수": …, "정비비계수": …, "관리비계수": …, "손료계수": …, "주연료": …, "주연료종류": …, "잡재료율": …, "조종원": …, "조종원직종": … }` · `손료계수` = 원문 「계」. @@ -100,7 +100,7 @@ - 원문에 없는 값을 지어 넣지 않음. 원문 「-」 = 칸을 비움(`null`). - `준용` = 모든 줄의 공통 칸 — 관리자가 고르는 다른 요소 키 · 준용 값을 미리 채우지 않음. 공표 노임에 이름이 온전히 같은 직종이 없으면 구분 「미확보」. - `옛이름` = 품셈이 쓰는 옛 직종명 목록(읽기 전용) · 이름 바뀜·통합 근거가 선 것은 준용이 아니라 현행 줄에 바로 적음 · 이력은 그 줄 `비고` · 근거는 `노임단가_직종대응_근거.md`. -- 엔진 차례 = 준용이 있으면 그 요소 값 · 없으면 제 값 · 호표 출처에 「준용: <이름>」 · 상태 「추정」 이면 「준용: <이름>(추정)」. +- 엔진 차례 = 준용이 있으면 그 요소 값 · 없으면 제 값 · 호표 출처에 「준용: <이름>」 · 상태 「추정」 은 제 값을 쓰고 호표 출처에 「추정(준용: <이름>)」. - 원문 이름 대신 번호로 적은 값(`조종원직종` = 노임 원문번호 「1048」)은 원문 이름을 `비고` 칸에. 재료 값: diff --git a/resources/master_data/scripts/build_인력_노임.py b/resources/master_data/scripts/build_인력_노임.py index fe94f957..cb31f1df 100644 --- a/resources/master_data/scripts/build_인력_노임.py +++ b/resources/master_data/scripts/build_인력_노임.py @@ -354,6 +354,24 @@ def main(): estimate(wage) estimate_make(make) print("새 틀로 받음", mk.adopt()) + refill_estimated() + + +def refill_estimated() -> None: + """상태 「추정」 줄 — 값·단위·일시간을 준용 직종에서 다시 채움(공표 회차가 바뀌면 같이 바뀜).""" + path = MD / "인력.json" + data = json.loads(path.read_text(encoding="utf-8")) + by_key = {r["키"]: r for r in data["줄"]} + n = 0 + for r in data["줄"]: + if r.get("상태") != "추정": + continue + target = by_key[r["준용"]] + r["값"], r["단위"], r["일시간"] = target["값"], target["단위"], target["일시간"] + n += 1 + head = {k: v for k, v in data.items() if k != "줄"} + path.write_text(mk.dump_rows(head, data["줄"]), encoding="utf-8", newline="\n") + print(f"추정 {n} 줄 값 = 준용 직종 값") # ── 건설노임 미공표 산정 ───────────────────────────────────────────── diff --git a/resources/master_data/scripts/check_master.py b/resources/master_data/scripts/check_master.py index fa3a8b20..c75282fb 100644 --- a/resources/master_data/scripts/check_master.py +++ b/resources/master_data/scripts/check_master.py @@ -47,6 +47,7 @@ BOOKS = ( "조달청제비율", "품셈재료", "질의회신", + "엔산법", "자체", ) DIVISIONS = { @@ -311,7 +312,7 @@ def _check_linked(where: str, row: dict) -> list[str]: def check_links(whole: mf.Master) -> list[str]: - """끊긴 키 — 품셈재료 연결 · 인력 준용이 가리키는 줄.""" + """끊긴 키 — 품셈재료 연결 · 인력 준용이 가리키는 줄 · 추정 줄 값 = 준용 직종 값.""" out = [] for key, row in whole.index.get("MP", {}).items(): link = row.get("연결") @@ -320,8 +321,16 @@ def check_links(whole: mf.Master) -> list[str]: for key, row in whole.index.get("LB", {}).items(): for col in ("준용",): ref = row.get(col) - if ref not in (None, "") and str(ref) not in whole.index.get("LB", {}): + if ref in (None, ""): + continue + target = whole.index.get("LB", {}).get(str(ref)) + if target is None: out.append(f"{whole.label(key)} · {col} 「{ref}」 없는 인력 키") + elif row.get("상태") == "추정" and row.get("값") != target.get("값"): + out.append( + f"{whole.label(key)} · 추정 값 「{row.get('값')}」 이" + f" 준용 「{target.get('이름')}」 값 「{target.get('값')}」 과 다름" + ) return out diff --git a/resources/master_data/scripts/master_formula.py b/resources/master_data/scripts/master_formula.py index 36d5f7db..17c1744d 100644 --- a/resources/master_data/scripts/master_formula.py +++ b/resources/master_data/scripts/master_formula.py @@ -274,8 +274,10 @@ class Master: alias = row.get("준용") if alias not in (None, ""): target = self.get(str(alias)) - mark = "(추정)" if row.get("상태") == "추정" else "" - return target.get("값"), f"준용: {target.get('이름') or alias}{mark}" + name = target.get("이름") or alias + if row.get("상태") == "추정": # 값을 이미 준용 직종에서 채워 둠 + return row.get("값"), f"추정(준용: {name})" + return target.get("값"), f"준용: {name}" return row.get("값"), None def logic(self, ref: str) -> dict: diff --git a/resources/master_data/인력.json b/resources/master_data/인력.json index 96b92820..08231091 100644 --- a/resources/master_data/인력.json +++ b/resources/master_data/인력.json @@ -2,8 +2,8 @@ "그룹": "인력", "비고": [ "열 한 벌 = 키 · 원문번호 · 구분 · 상세구분 · 이름 · 규격 · 단위 · 값 · 출처 · 일시간 · 상태 · 옛이름 · 비고 · 준용 — 모든 줄이 모든 칸을 가짐(없으면 null · 빈 목록)", - "상태 = 공표 · 산정(원문 4-라 산정값을 값에 넣음 · 근거는 비고) · 미공표(원문에 값 없음) · 미확보(공표 노임에 같은 직종 없음) · 추정(원문이 이름을 맞대지 않아 작업 범위로 짐작 · 구분은 대응 직종 것 · 값은 비움 · 준용에 대응 직종 키 · 근거는 비고)", - "준용 = 관리자가 고르는 다른 직종 키 — 있으면 엔진이 그 직종 값을 씀(값이 있어도 앞섬) · 없으면 값 · 호표 출처에 「준용: <이름>」", + "상태 = 공표 · 산정(원문 4-라 산정값을 값에 넣음 · 근거는 비고) · 미공표(원문에 값 없음) · 미확보(공표 노임에 같은 직종 없음) · 추정(원문이 이름을 맞대지 않아 작업 범위로 짐작 · 구분·값·단위·일시간은 준용 직종 것 · 준용에 그 직종 키 · 근거 문서는 출처)", + "준용 = 관리자가 고르는 다른 직종 키 — 있으면 엔진이 그 직종 값을 씀(값이 있어도 앞섬) · 없으면 값 · 호표 출처에 「준용: <이름>」 · 상태 「추정」 은 제 값을 쓰고 「추정(준용: <이름>)」", "새 조사 = 머리 「구분」 에 한 항목(원문 · 기관 · 판 · 공표일 · 원천 · 상세구분) 더하고 줄을 붙이면 끝 · 키는 LB 일련번호 이어 받음", "옛이름 = 품셈이 쓰는 옛 직종명 목록(읽기 전용) · 근거 resources/knowledge/original/원가계산/노임단가_직종대응_근거.md" ], @@ -597,10 +597,10 @@ { "키": "LB000359", "원문번호": "나무의사", "구분": "산림", "상세구분": null, "이름": "나무의사", "규격": "", "단위": "원/일", "값": 326359, "출처": "산림노임 나무의사", "일시간": 8, "상태": "공표", "옛이름": [], "비고": null, "준용": null }, { "키": "LB000360", "원문번호": "수목치료기술자", "구분": "산림", "상세구분": null, "이름": "수목치료기술자", "규격": "", "단위": "원/일", "값": 238447, "출처": "산림노임 수목치료기술자", "일시간": 8, "상태": "공표", "옛이름": [], "비고": null, "준용": null }, { "키": "LB000362", "원문번호": "절단공", "구분": "미확보", "상세구분": null, "이름": "절단공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-11 · 건설품셈 기계설비 13-6-13 · 건설품셈 기계설비 13-6-17", "준용": null }, - { "키": "LB000373", "원문번호": "정보처리기사", "구분": "엔지니어링", "상세구분": "정보통신", "이름": "정보처리기사", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 엔산법 별표2 기사자격 = 초급기술자 · 부문은 일반값", "준용": "LB000292" }, + { "키": "LB000373", "원문번호": "정보처리기사", "구분": "엔지니어링", "상세구분": "정보통신", "이름": "정보처리기사", "규격": "", "단위": "원/일", "값": 249574, "출처": "엔산법 시행령 별표2", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000292" }, { "키": "LB000384", "원문번호": "사진제판공", "구분": "미확보", "상세구분": null, "이름": "사진제판공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 토목 9-5-6-2가 · 건설품셈 토목 9-5-7-2", "준용": null }, { "키": "LB000385", "원문번호": "사진식자공", "구분": "미확보", "상세구분": null, "이름": "사진식자공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 토목 9-5-6-2가 · 건설품셈 토목 9-5-7-2", "준용": null }, - { "키": "LB000386", "원문번호": "옵셋인쇄공", "구분": "제조업", "상세구분": "출판․인쇄", "이름": "옵셋인쇄공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 제조노임 31호 예시 「오프셋인쇄기조작원」", "준용": "LB000163" }, + { "키": "LB000386", "원문번호": "옵셋인쇄공", "구분": "제조업", "상세구분": "출판․인쇄", "이름": "옵셋인쇄공", "규격": "", "단위": "원/일", "값": 121205, "출처": "제조노임 직종해설 31호", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000163" }, { "키": "LB000390", "원문번호": "측량사", @@ -617,15 +617,15 @@ "비고": "건설품셈 기계설비 13-5-2 · 건설품셈 기계설비 13-5-8 · 건설품셈 기계설비 13-6-1 · 건설품셈 기계설비 13-6-2 · 건설품셈 기계설비 13-6-3 · 건설품셈 기계설비 13-6-4 · 건설품셈 기계설비 13-6-6 · 건설품셈 기계설비 13-6-7 · 건설품셈 기계설비 13-6-8 · 건설품셈 기계설비 13-6-10 · 건설품셈 기계설비 13-6-12 · 건설품셈 기계설비 13-6-16 · 건설품셈 기계설비 13-7-1 · 건설품셈 기계설비 13-7-2 · 건설품셈 기계설비 13-7-4 · 건설품셈 기계설비 13-9-2 · 건설품셈 기계설비 13-10-2 · 건설품셈 기계설비 13-10-3 · 건설품셈 기계설비 13-11-3", "준용": null }, - { "키": "LB000391", "원문번호": "제관공", "구분": "건설업", "상세구분": null, "이름": "제관공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 13-6 노무 항목 · 공표는 플랜트제관공뿐", "준용": "LB000057" }, - { "키": "LB000392", "원문번호": "공작기계공", "구분": "제조업", "상세구분": "공작기계 조작", "이름": "공작기계공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 제조노임 옛 코드 37.선반원 → 69.선반기조작원 · 밀링원일 수 있음", "준용": "LB000202" }, - { "키": "LB000394", "원문번호": "마킹공", "구분": "건설업", "상세구분": null, "이름": "마킹공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 13-6 노무 항목 · 공표는 플랜트제관공뿐", "준용": "LB000057" }, - { "키": "LB000395", "원문번호": "산소절단공", "구분": "건설업", "상세구분": null, "이름": "산소절단공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 13-6 노무 항목 · 공표는 플랜트제관공뿐", "준용": "LB000057" }, + { "키": "LB000391", "원문번호": "제관공", "구분": "건설업", "상세구분": null, "이름": "제관공", "규격": "", "단위": "원/일", "값": 266029, "출처": "건설품셈 기계설비 13-06", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000057" }, + { "키": "LB000392", "원문번호": "공작기계공", "구분": "제조업", "상세구분": "공작기계 조작", "이름": "공작기계공", "규격": "", "단위": "원/일", "값": 123489, "출처": "제조노임 직종해설 70·85호", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "밀링원일 수 있음", "준용": "LB000202" }, + { "키": "LB000394", "원문번호": "마킹공", "구분": "건설업", "상세구분": null, "이름": "마킹공", "규격": "", "단위": "원/일", "값": 266029, "출처": "건설품셈 기계설비 13-06", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000057" }, + { "키": "LB000395", "원문번호": "산소절단공", "구분": "건설업", "상세구분": null, "이름": "산소절단공", "규격": "", "단위": "원/일", "값": 266029, "출처": "건설품셈 기계설비 13-06", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000057" }, { "키": "LB000396", "원문번호": "측량기사", "구분": "미확보", "상세구분": null, "이름": "측량기사", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-8", "준용": null }, - { "키": "LB000397", "원문번호": "시험사1급", "구분": "건설업", "상세구분": null, "이름": "시험사1급", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 13-6 X-Ray촬영 = 비파괴검사", "준용": "LB000067" }, + { "키": "LB000397", "원문번호": "시험사1급", "구분": "건설업", "상세구분": null, "이름": "시험사1급", "규격": "", "단위": "원/일", "값": 199588, "출처": "건설노임 명칭변경표 2010.1", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000068" }, { "키": "LB000398", "원문번호": "특수운전공", "구분": "미확보", "상세구분": null, "이름": "특수운전공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-8 · 건설품셈 기계설비 13-6-9", "준용": null }, - { "키": "LB000400", "원문번호": "제도공", "구분": "제조업", "상세구분": "CAD설계", "이름": "제도공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 제조노임 1호 예시 「기계 제도사」", "준용": "LB000133" }, - { "키": "LB000401", "원문번호": "현도공", "구분": "건설업", "상세구분": null, "이름": "현도공", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "추정", "옛이름": [], "비고": "추정: 작업 범위 해설로 짐작 — 13-6 노무 항목 · 공표는 플랜트제관공뿐", "준용": "LB000057" }, + { "키": "LB000400", "원문번호": "제도공", "구분": "제조업", "상세구분": "CAD설계", "이름": "제도공", "규격": "", "단위": "원/일", "값": 160065, "출처": "제조노임 직종해설 1호", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000133" }, + { "키": "LB000401", "원문번호": "현도공", "구분": "건설업", "상세구분": null, "이름": "현도공", "규격": "", "단위": "원/일", "값": 266029, "출처": "건설품셈 기계설비 13-06", "일시간": 8, "상태": "추정", "옛이름": [], "비고": null, "준용": "LB000057" }, { "키": "LB000402", "원문번호": "측량조수", "구분": "미확보", "상세구분": null, "이름": "측량조수", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-12 · 건설품셈 기계설비 13-6-16", "준용": null }, { "키": "LB000403", "원문번호": "시공측량기사", "구분": "미확보", "상세구분": null, "이름": "시공측량기사", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-14", "준용": null }, { "키": "LB000404", "원문번호": "시공측량조수", "구분": "미확보", "상세구분": null, "이름": "시공측량조수", "규격": "", "단위": "원/일", "값": null, "출처": "준용대상", "일시간": 8, "상태": "미확보", "옛이름": [], "비고": "건설품셈 기계설비 13-6-14", "준용": null } diff --git a/resources/tester/test_masterdata_check.py b/resources/tester/test_masterdata_check.py index 29dbc57d..58df726d 100644 --- a/resources/tester/test_masterdata_check.py +++ b/resources/tester/test_masterdata_check.py @@ -626,11 +626,13 @@ def test_미공표_준용(): def test_추정은_준용_값에_표시(whole): - """추정 = 원문이 이름을 맞대지 않아 작업 범위로 짐작한 대응 — 값은 비우고 준용 직종 값 · 출처에 「(추정)」.""" + """추정 = 작업 범위로 짐작한 대응 — 값은 준용 직종 것 그대로 · 출처는 근거 문서 · 호표에 「추정(준용: ○○)」.""" row = whole.get("LB:제관공") - assert row["상태"] == "추정" and row["값"] is None and row["구분"] == "건설업" - assert row["비고"].startswith("추정: ") and row["옛이름"] == [] - assert whole.value("LB:제관공") == (whole.get("LB:1057")["값"], "준용: 플랜트제관공(추정)") + target = whole.get("LB:1057") + assert row["상태"] == "추정" and row["구분"] == "건설업" and row["옛이름"] == [] + assert row["값"] == target["값"] and row["단위"] == target["단위"] + assert row["출처"] == "건설품셈 기계설비 13-06" + assert whole.value("LB:제관공") == (target["값"], "추정(준용: 플랜트제관공)") def test_노임_갈래_파일_원문_대조():