diff --git a/M02_MasterTemplete/DataFlow/_standard/금액단위표준.json b/M02_MasterTemplete/DataFlow/_standard/금액단위표준.json new file mode 100644 index 000000000..2d19a5bd8 --- /dev/null +++ b/M02_MasterTemplete/DataFlow/_standard/금액단위표준.json @@ -0,0 +1,42 @@ +{ + "이름": "금액의 단위표준", + "출처": "산림품셈 1-2-2 2", + "원문": "resources/knowledge/original/원가계산/산림_표준품셈/본문/제01장_적용기준/1-02_설계_및_수량.md", + "줄": [ + { + "종목": "설계서의 총액", + "단위": "원", + "지위": 1000, + "비고": "미만버림", + "원문 줄": 145 + }, + { + "종목": "설계서의 소계", + "단위": "원", + "지위": 1, + "비고": "미만버림", + "원문 줄": 146 + }, + { + "종목": "설계서의 금액란", + "단위": "원", + "지위": 1, + "비고": "미만버림", + "원문 줄": 147 + }, + { + "종목": "일위대가표의 계금", + "단위": "원", + "지위": 1, + "비고": "미만버림", + "원문 줄": 148 + }, + { + "종목": "일위대가표의 금액란", + "단위": "원", + "지위": 0.1, + "비고": "미만버림", + "원문 줄": 149 + } + ] +} diff --git a/M02_MasterTemplete/DataFlow/_standard/단위표준.json b/M02_MasterTemplete/DataFlow/_standard/단위표준.json new file mode 100644 index 000000000..a8a9f23fb --- /dev/null +++ b/M02_MasterTemplete/DataFlow/_standard/단위표준.json @@ -0,0 +1,680 @@ +{ + "이름": "설계서의 단위 및 소수의 표준", + "출처": "산림품셈 1-2-2 1", + "원문": "resources/knowledge/original/원가계산/산림_표준품셈/본문/제01장_적용기준/1-02_설계_및_수량.md", + "바꿈": "소수자리 「-」 = 0 · 단위 「-」 = 「없음」 · 빈 칸 = null · 병합 칸은 위 종목을 폄(「병합」: true)", + "줄": [ + { + "종목": "공사연장", + "규격 단위": "m", + "규격 소수자리": 2, + "단위수량 단위": "m", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 60 + }, + { + "종목": "공사폭원", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 61 + }, + { + "종목": "직공인부", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "인", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 62 + }, + { + "종목": "공사 및 사업면적", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 63 + }, + { + "종목": "용지면적", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 64 + }, + { + "종목": "토적(높이, 너비)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 65 + }, + { + "종목": "토적(단면적)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 66 + }, + { + "종목": "토적(체적)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 67 + }, + { + "종목": "토적(체적합계)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 68 + }, + { + "종목": "떼", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 69 + }, + { + "종목": "모래, 자갈", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 70 + }, + { + "종목": "조약돌", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 71 + }, + { + "종목": "견치돌, 깬돌", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 72 + }, + { + "종목": "견치돌, 깬돌", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": null, + "비고": "", + "원문 줄": 73, + "병합": true + }, + { + "종목": "야면석(野面石)", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 74 + }, + { + "종목": "돌쌓기 및 돌붙임", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 75 + }, + { + "종목": "돌쌓기 및 돌붙임", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 76, + "병합": true + }, + { + "종목": "돌쌓기 및 돌붙임", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 77, + "병합": true + }, + { + "종목": "돌쌓기 및 돌붙임", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 78, + "병합": true + }, + { + "종목": "사석(捨石)", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 79 + }, + { + "종목": "다듬돌(切石, 板石)", + "규격 단위": "cm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 80 + }, + { + "종목": "벽돌", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 81 + }, + { + "종목": "블록", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 82 + }, + { + "종목": "시멘트", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 83 + }, + { + "종목": "모르타르", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 84 + }, + { + "종목": "콘크리트", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎥", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 85 + }, + { + "종목": "석분", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 86 + }, + { + "종목": "석회", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 87 + }, + { + "종목": "화산회", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 88 + }, + { + "종목": "아스팔트", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 89 + }, + { + "종목": "목재(판재)", + "규격 단위": "길이m", + "규격 소수자리": 1, + "단위수량 단위": "㎡", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 90 + }, + { + "종목": "목재(판재)", + "규격 단위": "폭,두께cm", + "규격 소수자리": 1, + "단위수량 단위": "㎥", + "단위수량 소수자리": 3, + "비고": "", + "원문 줄": 91, + "병합": true + }, + { + "종목": "합판", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "장", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 92 + }, + { + "종목": "말뚝", + "규격 단위": "길이m", + "규격 소수자리": 1, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 93 + }, + { + "종목": "말뚝", + "규격 단위": "지름mm", + "규격 소수자리": 0, + "단위수량 단위": null, + "단위수량 소수자리": null, + "비고": "", + "원문 줄": 94, + "병합": true + }, + { + "종목": "철강재", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 3, + "비고": "", + "원문 줄": 95 + }, + { + "종목": "용접봉", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 96 + }, + { + "종목": "구리판, 함석류", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 97 + }, + { + "종목": "철근", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 98 + }, + { + "종목": "볼트・너트", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 99 + }, + { + "종목": "꺽쇠", + "규격 단위": "mm", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 100 + }, + { + "종목": "철선류", + "규격 단위": "mm", + "규격 소수자리": 1, + "단위수량 단위": "kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 101 + }, + { + "종목": "PC강선", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 102 + }, + { + "종목": "돌망태", + "규격 단위": "길이m", + "규격 소수자리": 1, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 103 + }, + { + "종목": "돌망태", + "규격 단위": "지름m", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 104, + "병합": true + }, + { + "종목": "돌망태", + "규격 단위": "높이m", + "규격 소수자리": 0, + "단위수량 단위": null, + "단위수량 소수자리": null, + "비고": "", + "원문 줄": 105, + "병합": true + }, + { + "종목": "로프류", + "규격 단위": "mm", + "규격 소수자리": 1, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 106 + }, + { + "종목": "못", + "규격 단위": "길이cm", + "규격 소수자리": 1, + "단위수량 단위": "kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 107 + }, + { + "종목": "석유, 휘발유, 모빌유", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "ℓ", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 108 + }, + { + "종목": "구리스", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 109 + }, + { + "종목": "넝마", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 110 + }, + { + "종목": "화약류", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 3, + "비고": "", + "원문 줄": 111 + }, + { + "종목": "뇌관", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 112 + }, + { + "종목": "도화선", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 113 + }, + { + "종목": "석탄, 목탄, 코크스", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 114 + }, + { + "종목": "산소", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "ℓ", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 115 + }, + { + "종목": "카바이트", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "kg", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 116 + }, + { + "종목": "도료(塗料)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "ℓ또는kg", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 117 + }, + { + "종목": "도장(塗裝)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 118 + }, + { + "종목": "관류(管類)", + "규격 단위": "길이m", + "규격 소수자리": 2, + "단위수량 단위": "개", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 119 + }, + { + "종목": "관류(管類)", + "규격 단위": "지름mm", + "규격 소수자리": 0, + "단위수량 단위": null, + "단위수량 소수자리": null, + "비고": "", + "원문 줄": 120, + "병합": true + }, + { + "종목": "관류(管類)", + "규격 단위": "두께mm", + "규격 소수자리": 0, + "단위수량 단위": null, + "단위수량 소수자리": null, + "비고": "", + "원문 줄": 121, + "병합": true + }, + { + "종목": "수로연장", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 122 + }, + { + "종목": "옹벽", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 123 + }, + { + "종목": "승강장옹벽 및 울타리", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 124 + }, + { + "종목": "궤도부설", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "km", + "단위수량 소수자리": 3, + "비고": "", + "원문 줄": 125 + }, + { + "종목": "시험하중", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "ton", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 126 + }, + { + "종목": "보오링", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 127 + }, + { + "종목": "방수면적", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 128 + }, + { + "종목": "건물(면적)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 2, + "비고": "", + "원문 줄": 129 + }, + { + "종목": "건물(지붕, 벽붙이기)", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "㎡", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 130 + }, + { + "종목": "우물", + "규격 단위": "깊이", + "규격 소수자리": 0, + "단위수량 단위": "m", + "단위수량 소수자리": 1, + "비고": "", + "원문 줄": 131 + }, + { + "종목": "마대", + "규격 단위": "없음", + "규격 소수자리": 0, + "단위수량 단위": "매", + "단위수량 소수자리": 0, + "비고": "", + "원문 줄": 132 + } + ], + "주": [ + "① 설계서 수량의 단위와 소수자리 표시는 본 표에 따르며, 반올림하여 적용한다.", + "② 품셈 각 항목에서 제시한 소숫자리가 본 표의 내용과 상이할 경우 항목에서 제시하는 소숫자리를 우선하여 적용한다.", + "③ 본 표에 제시하지 않은 품의 경우 유사품의 규격과 단위수량을 참고하여 적용하며, C.G.S 단위로 하는 것을 원칙으로 한다." + ] +} diff --git a/resources/tester/test_m02_df_standards.py b/resources/tester/test_m02_df_standards.py new file mode 100644 index 000000000..26af3dd7b --- /dev/null +++ b/resources/tester/test_m02_df_standards.py @@ -0,0 +1,80 @@ +"""M02 단가산출 흐름도 — 단위 · 금액 표준 표(35-9 · 정함 11) 시험. + +· `_standard/단위표준.json` — 산림품셈 1-2-2 「설계서의 단위 및 소수의 표준」 표 줄 수 · 병합 칸 폄 · 「-」 바꾸기 · 주 ①~③ +· `_standard/금액단위표준.json` — 「금액의 단위표준」 다섯 줄 · 미만버림 +· 원문 줄 번호가 원문의 그 줄을 가리킴 · 원문 흠은 고치지 않음(사용자가 시험판에서 고침) +""" + +from __future__ import annotations + +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +STD = ROOT / "M02_MasterTemplete" / "DataFlow" / "_standard" +SRC = ( + ROOT + / "resources/knowledge/original/원가계산/산림_표준품셈/본문/제01장_적용기준/1-02_설계_및_수량.md" +) +UNIT = json.loads((STD / "단위표준.json").read_text(encoding="utf-8")) +MONEY = json.loads((STD / "금액단위표준.json").read_text(encoding="utf-8")) +LINES = SRC.read_text(encoding="utf-8").split("\n") + + +def _cells(no: int) -> list[str]: + return [c.strip() for c in LINES[no - 1].strip().strip("|").split("|")] + + +def test_단위표준_줄_수_병합_원문줄() -> None: + rows = UNIT["줄"] + # 원문 표 = 머리 · 가름 · 몸 1행(단위 · 소수자리) 다음 73 줄 — 병합 칸 10 줄(주석의 14~15 · 17~20 · 32~33 · 35~36 · 45~47 · 61~63) + assert len(rows) == 73 + assert sum(1 for r in rows if r.get("병합")) == 10 + spread = {r["종목"] for r in rows if r.get("병합")} + assert spread == { + "견치돌, 깬돌", + "돌쌓기 및 돌붙임", + "목재(판재)", + "말뚝", + "돌망태", + "관류(管類)", + } + for r in rows: + cells = _cells(r["원문 줄"]) + assert cells[0] == ("" if r.get("병합") else r["종목"]) + assert [r["종목"] for r in rows[:3]] == ["공사연장", "공사폭원", "직공인부"] + assert rows[-1]["종목"] == "마대" + + +def test_단위표준_바꾸기() -> None: + """소수자리 「-」 = 0 · 단위 「-」 = 「없음」 · 빈 칸 = null · 원문 글자는 그대로""" + for r in UNIT["줄"]: + src = _cells(r["원문 줄"]) + for i, key in [(2, "규격 소수자리"), (4, "단위수량 소수자리")]: + want = 0 if src[i] == "-" else (int(src[i]) if src[i] else None) + assert r[key] == want, (r["원문 줄"], key) + for i, key in [(1, "규격 단위"), (3, "단위수량 단위")]: + want = "없음" if src[i] == "-" else (src[i] or None) + assert r[key] == want, (r["원문 줄"], key) + 공사연장 = UNIT["줄"][0] + assert (공사연장["규격 단위"], 공사연장["규격 소수자리"], 공사연장["단위수량 소수자리"]) == ( + "m", + 2, + 0, + ) + 말뚝 = [r for r in UNIT["줄"] if r["종목"] == "말뚝"] + assert 말뚝[1]["단위수량 단위"] is None # 원문 빈 칸 그대로 + assert [n[:1] for n in UNIT["주"]] == ["①", "②", "③"] + + +def test_금액_다섯_줄() -> None: + rows = MONEY["줄"] + assert [(r["종목"], r["지위"]) for r in rows] == [ + ("설계서의 총액", 1000), + ("설계서의 소계", 1), + ("설계서의 금액란", 1), + ("일위대가표의 계금", 1), + ("일위대가표의 금액란", 0.1), + ] + assert all(r["단위"] == "원" and r["비고"] == "미만버림" for r in rows) + assert all(_cells(r["원문 줄"])[0] == r["종목"] for r in rows)