feat(master_data): 산림품셈 13장 로직 36줄 · 기계 경비 로직 둘(일반 · 굴착기+부착용 집게)
- 로직_산림품셈_13장: 13-2 ~ 13-16 돈 로직 35 · 작업량 로직 1 (13-4-1 그대로) - 로직_건설품셈_공통8장: 8 기계 시간당 경비 · 8 굴착기+부착용 집게 시간당 경비(잡재료 16% · 집게 손료) - 계수: 8-4-8 주⑤ 조합 잡재료율 · 13-13-2 비율 - 로직_산림품셈_9장: 인력 10% · 장비 90% 줄 비고 「해석: 전량 인력 품 × 비율」 - master_formula: 범위규칙 「이하 · 칸마다 위 끝만」 · 「마지막 칸 이하 포함」 - 시험 셋 더함(14 통과) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -251,11 +251,18 @@ def _match(table: dict, row: dict, cond: str, want) -> bool:
|
||||
have = row[cond]
|
||||
if table.get("조건", {}).get(cond) == "범위":
|
||||
low, high = have
|
||||
rule = table.get("범위규칙", "초과·이하").split(" · ")[0]
|
||||
rule, *more = table.get("범위규칙", "초과·이하").split(" · ")
|
||||
if rule == "초과·이하":
|
||||
return (low is None or want > low) and (high is None or want <= high)
|
||||
if rule == "이상·미만":
|
||||
return (low is None or want >= low) and (high is None or want < high)
|
||||
# 「마지막 칸(80~100)은 이하 포함」 — 가장 윗줄만 위 끝 포함
|
||||
top = max(r[cond][1] for r in table["줄"] if r.get(cond) and r[cond][1] is not None)
|
||||
closed = any("이하 포함" in x for x in more) and high == top
|
||||
return (low is None or want >= low) and (
|
||||
high is None or want < high or (closed and want == high)
|
||||
)
|
||||
if rule == "이하": # 칸마다 위 끝만 — 맞는 줄 가운데 위 끝이 가장 작은 줄(find)
|
||||
return (low is None or want > low) and (high is None or want <= high)
|
||||
raise FormulaError(f"모르는 범위규칙 「{table.get('범위규칙')}」")
|
||||
return have == want
|
||||
|
||||
@@ -265,6 +272,11 @@ def find(table: dict, conds: dict) -> dict:
|
||||
if cond not in table.get("조건", {}):
|
||||
raise FormulaError(f"「{table['열쇠']}」 에 없는 조건 「{cond}」")
|
||||
hits = [row for row in table["줄"] if all(_match(table, row, c, v) for c, v in conds.items())]
|
||||
if len(hits) > 1 and table.get("범위규칙", "").split(" · ")[0] == "이하":
|
||||
for c in conds:
|
||||
ups = [r[c][1] for r in hits if table["조건"].get(c) == "범위" and r.get(c)]
|
||||
if ups and None not in ups:
|
||||
hits = [r for r in hits if not r.get(c) or r[c][1] == min(ups)]
|
||||
if len(hits) != 1:
|
||||
raise FormulaError(f"「{table['열쇠']}」 {conds} 맞는 줄 {len(hits)}개")
|
||||
return hits[0]
|
||||
|
||||
@@ -22,6 +22,18 @@
|
||||
"① 전용덤프트럭(18톤이상)과 불도저(19톤이상)의 경우는 보정하지 않는다. 단, 타이어 불도저, 습지 불도저는 보정한다.",
|
||||
"② 전석섞인 토사는 전석(0.5㎥이상)의 혼입율이 30%이상 말한다."
|
||||
]
|
||||
},
|
||||
{
|
||||
"열쇠": "8-4-8 주⑤ 조합 잡재료율",
|
||||
"이름": "불도저·굴착기에 리퍼·브레이커·부착용 집게 조합 시 잡재료 비율",
|
||||
"기준": "",
|
||||
"출처": "건설품셈 공통 8-4-8 주⑤",
|
||||
"조건": { "구분": "고르기" },
|
||||
"값칸": { "적용": "%" },
|
||||
"줄": [{ "구분": "불도저 및 굴착기 잡재료 비율", "적용": 16 }],
|
||||
"주": [
|
||||
"⑤ 불도저 및 굴착기에 리퍼, 브레이커, 부착용집게를 조합하여 사용할 때는 불도저 및 굴착기의 잡재료 비율을 16%로 계상하고, 리퍼, 브레이커, 부착용 집게의 손료 및 치즐 소모율을 추가하는 것이다."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -363,6 +363,20 @@
|
||||
{ "구분": "공구손료 및 경장비(봉합기) 기계경비(인력품의)", "적용": 4, "단위": "%" }
|
||||
],
|
||||
"주": []
|
||||
},
|
||||
{
|
||||
"열쇠": "13-13-2 비율",
|
||||
"이름": "토양개량제 부설 인력·장비 비율",
|
||||
"기준": "",
|
||||
"출처": "산림품셈 13-13-2",
|
||||
"조건": { "구분": "고르기" },
|
||||
"값칸": { "적용": "단위 칸 따름", "단위": "글" },
|
||||
"줄": [
|
||||
{ "구분": "인력", "적용": 10, "단위": "%" },
|
||||
{ "구분": "장비", "적용": 90, "단위": "%" },
|
||||
{ "구분": "굴착기 버킷", "적용": 0.2, "단위": "㎥" }
|
||||
],
|
||||
"주": ["표 머리 「인력(10%)」 · 「장비(90%)」 · 「굴착기(0.2㎥)」"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -61,6 +61,160 @@
|
||||
{ "이름": "기계손료", "식": "손료", "비목": "경비", "출처": "건설품셈 공통 8-1-6 2" }
|
||||
],
|
||||
"끝수": "손료 원 미만 버림(건설품셈 공통 8-1-5 12) · 합계 원문 규정 없음"
|
||||
},
|
||||
{
|
||||
"열쇠": "8 기계 시간당 경비",
|
||||
"이름": "기계 시간당 기계경비(손료 보정 없는 기종)",
|
||||
"결과단위": "원/시간",
|
||||
"출처": "건설품셈 공통 8-1-5 · 8-1-6",
|
||||
"소유": "공용",
|
||||
"입력": [
|
||||
{ "이름": "기계", "고르기": ["1730-0015", "7204-0055"] },
|
||||
{
|
||||
"이름": "지역",
|
||||
"고르기": [
|
||||
"전국평균",
|
||||
"전국",
|
||||
"서울",
|
||||
"경기",
|
||||
"강원",
|
||||
"충북",
|
||||
"충남",
|
||||
"전북",
|
||||
"경북",
|
||||
"경남",
|
||||
"부산",
|
||||
"제주",
|
||||
"대구",
|
||||
"인천",
|
||||
"대전",
|
||||
"울산",
|
||||
"세종",
|
||||
"전남광주"
|
||||
],
|
||||
"출처": "건설품셈 공통 8-1-7 5"
|
||||
}
|
||||
],
|
||||
"중간": [
|
||||
{
|
||||
"이름": "손료",
|
||||
"식": "버림(기계:건설품셈:{기계}.가격 * 1000 * ((기계:건설품셈:{기계}.상각비계수 + 기계:건설품셈:{기계}.정비비계수) + 기계:건설품셈:{기계}.관리비계수) / 10000000, 0)",
|
||||
"출처": "건설품셈 공통 8-1-5 12 · 8-1-6 4"
|
||||
},
|
||||
{ "이름": "연료", "식": "기계:건설품셈:{기계}.주연료종류", "출처": "건설품셈 공통 8-4 주①㉰" },
|
||||
{ "이름": "직종", "식": "기계:건설품셈:{기계}.조종원직종", "출처": "건설품셈 공통 8-1-3 5" }
|
||||
],
|
||||
"호표": [
|
||||
{
|
||||
"종류": "재료",
|
||||
"요소": "재료:오피넷유가:{연료}:{지역}",
|
||||
"이름": "주연료",
|
||||
"단위": "ℓ",
|
||||
"수량": "기계:건설품셈:{기계}.주연료",
|
||||
"비목": "재료비",
|
||||
"출처": "건설품셈 공통 8-4-1"
|
||||
},
|
||||
{
|
||||
"종류": "인력",
|
||||
"요소": "인력:건설노임:{직종}",
|
||||
"이름": "조종원",
|
||||
"단위": "인",
|
||||
"수량": "기계:건설품셈:{기계}.조종원 / 8",
|
||||
"비목": "노무비",
|
||||
"출처": "건설품셈 공통 8-1-3 6",
|
||||
"비고": "환산 근거 미확인 — 우선 하루 ÷ 8"
|
||||
}
|
||||
],
|
||||
"덧줄": [
|
||||
{ "이름": "잡재료비", "식": "재료비 * 기계:건설품셈:{기계}.잡재료율 / 100", "비목": "재료비", "출처": "건설품셈 공통 8-4 주②" },
|
||||
{ "이름": "기계손료", "식": "손료", "비목": "경비", "출처": "건설품셈 공통 8-1-6 2" }
|
||||
],
|
||||
"끝수": "손료 원 미만 버림(건설품셈 공통 8-1-5 12) · 합계 원문 규정 없음",
|
||||
"비고": "고르기는 쓰는 기계만 — 주연료·조종원이 있는 기계는 더 넣어 씀"
|
||||
},
|
||||
{
|
||||
"열쇠": "8 굴착기+부착용 집게 시간당 경비",
|
||||
"이름": "굴착기(무한궤도)+부착용 집게 시간당 기계경비",
|
||||
"결과단위": "원/시간",
|
||||
"출처": "건설품셈 공통 8-1-5 · 8-1-6 · 8-1-7 · 8-4-8 주⑤",
|
||||
"소유": "공용",
|
||||
"입력": [
|
||||
{ "이름": "기계", "고르기": ["0201-0060"] },
|
||||
{ "이름": "집게", "고르기": ["7206-0070"] },
|
||||
{
|
||||
"이름": "지역",
|
||||
"고르기": [
|
||||
"전국평균",
|
||||
"전국",
|
||||
"서울",
|
||||
"경기",
|
||||
"강원",
|
||||
"충북",
|
||||
"충남",
|
||||
"전북",
|
||||
"경북",
|
||||
"경남",
|
||||
"부산",
|
||||
"제주",
|
||||
"대구",
|
||||
"인천",
|
||||
"대전",
|
||||
"울산",
|
||||
"세종",
|
||||
"전남광주"
|
||||
],
|
||||
"출처": "건설품셈 공통 8-1-7 5"
|
||||
},
|
||||
{ "이름": "보정작업", "고르기": ["해당 없음", "암석작업(연암・보통암・경암)", "전석섞인토사"], "출처": "건설품셈 공통 8-1-7 1" }
|
||||
],
|
||||
"중간": [
|
||||
{
|
||||
"이름": "가산비율",
|
||||
"식": "만약(보정작업 == '해당 없음', 0, 찾기(계수:건설품셈:8-1-7 손료보정, 기종='굴착기(무한궤도) 및 로더(무한궤도)', 작업=보정작업).가산비율)",
|
||||
"출처": "건설품셈 공통 8-1-7 1"
|
||||
},
|
||||
{
|
||||
"이름": "손료",
|
||||
"식": "버림(기계:건설품셈:{기계}.가격 * 1000 * ((기계:건설품셈:{기계}.상각비계수 + 기계:건설품셈:{기계}.정비비계수) * (1 + 가산비율 / 100) + 기계:건설품셈:{기계}.관리비계수) / 10000000, 0)",
|
||||
"출처": "건설품셈 공통 8-1-5 12 · 8-1-6 4 · 8-1-7 1"
|
||||
},
|
||||
{
|
||||
"이름": "집게손료",
|
||||
"식": "버림(기계:건설품셈:{집게}.가격 * 1000 * ((기계:건설품셈:{집게}.상각비계수 + 기계:건설품셈:{집게}.정비비계수) + 기계:건설품셈:{집게}.관리비계수) / 10000000, 0)",
|
||||
"출처": "건설품셈 공통 8-1-5 12 · 8-4-8 주⑤"
|
||||
},
|
||||
{ "이름": "조합잡재료율", "식": "찾기(계수:건설품셈:8-4-8 주⑤ 조합 잡재료율, 구분='불도저 및 굴착기 잡재료 비율').적용", "출처": "건설품셈 공통 8-4-8 주⑤" },
|
||||
{ "이름": "연료", "식": "기계:건설품셈:{기계}.주연료종류", "출처": "건설품셈 공통 8-4 주①㉰" },
|
||||
{ "이름": "직종", "식": "기계:건설품셈:{기계}.조종원직종", "출처": "건설품셈 공통 8-1-3 5" }
|
||||
],
|
||||
"호표": [
|
||||
{
|
||||
"종류": "재료",
|
||||
"요소": "재료:오피넷유가:{연료}:{지역}",
|
||||
"이름": "주연료",
|
||||
"단위": "ℓ",
|
||||
"수량": "기계:건설품셈:{기계}.주연료",
|
||||
"비목": "재료비",
|
||||
"출처": "건설품셈 공통 8-4-1"
|
||||
},
|
||||
{
|
||||
"종류": "인력",
|
||||
"요소": "인력:건설노임:{직종}",
|
||||
"이름": "조종원",
|
||||
"단위": "인",
|
||||
"수량": "기계:건설품셈:{기계}.조종원 / 8",
|
||||
"비목": "노무비",
|
||||
"출처": "건설품셈 공통 8-1-3 6",
|
||||
"비고": "환산 근거 미확인 — 우선 하루 ÷ 8"
|
||||
}
|
||||
],
|
||||
"덧줄": [
|
||||
{ "이름": "잡재료비", "식": "재료비 * 조합잡재료율 / 100", "비목": "재료비", "출처": "건설품셈 공통 8-4-8 주⑤" },
|
||||
{ "이름": "기계손료", "식": "손료", "비목": "경비", "출처": "건설품셈 공통 8-1-6 2" },
|
||||
{ "이름": "집게손료", "식": "집게손료", "비목": "경비", "출처": "건설품셈 공통 8-4-8 주⑤" }
|
||||
],
|
||||
"끝수": "손료 원 미만 버림(건설품셈 공통 8-1-5 12) · 합계 원문 규정 없음",
|
||||
"비고": "집게는 굴착기 부수물(8-3-1 (0250) 주 · 규격은 해당 굴착기 규격) — 0.6∼0.8 집게를 0.6㎥ 굴착기에 붙임"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -440,7 +440,8 @@
|
||||
}
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null
|
||||
"끝수": null,
|
||||
"비고": "해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-1 구조물터파기 육상토사(0~1m) 작업량",
|
||||
@@ -515,7 +516,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-2 구조물터파기 육상토사(1~2m) 작업량",
|
||||
@@ -590,7 +591,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "장비 「육상토사(0~1m)와 동일」 — 9-13-1 표 · 비율도 9-13-1 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "장비 「육상토사(0~1m)와 동일」 — 9-13-1 표 · 비율도 9-13-1 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-3 구조물터파기 육상토사(2~3m) 작업량",
|
||||
@@ -665,7 +666,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "장비 「육상토사(0~1m)와 동일」 — 9-13-1 표 · 비율도 9-13-1 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "장비 「육상토사(0~1m)와 동일」 — 9-13-1 표 · 비율도 9-13-1 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-4 구조물터파기 용수토사(0~1m) 작업량",
|
||||
@@ -740,7 +741,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-5 구조물터파기 용수토사(1~2m) 작업량",
|
||||
@@ -815,7 +816,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "장비 「용수토사(0~1m)와 동일」 — 9-13-4 표 · 비율도 9-13-4 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "장비 「용수토사(0~1m)와 동일」 — 9-13-4 표 · 비율도 9-13-4 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-13-6 구조물터파기 용수토사(2~3m) 작업량",
|
||||
@@ -890,7 +891,7 @@
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"비고": "장비 「용수토사(0~1m)와 동일」 — 9-13-4 표 · 비율도 9-13-4 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단)"
|
||||
"비고": "장비 「용수토사(0~1m)와 동일」 — 9-13-4 표 · 비율도 9-13-4 · 9-13 머리 ※ 관보호공·관부설 보통인력 30% 가산 미반영(적용 여부 설계자 판단) · 해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-14-1 되메우기 작업량",
|
||||
@@ -964,7 +965,8 @@
|
||||
}
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null
|
||||
"끝수": null,
|
||||
"비고": "해석: 전량 인력 품 × 비율"
|
||||
},
|
||||
{
|
||||
"열쇠": "9-14-2 다짐 작업량",
|
||||
|
||||
@@ -97,6 +97,35 @@ def test_분수_글자_값(whole):
|
||||
assert mf.run(whole, "산림품셈:9-4-2 암절취 집토 작업량", {})["결과"] == Decimal("17.325")
|
||||
|
||||
|
||||
def test_범위규칙_이하_위끝만(whole):
|
||||
"""13-4-2 뒷길이 「35cm 이하 · 55cm 이하」 — 36 은 55 칸."""
|
||||
region = {"지역": "전국평균", "보정작업": "해당 없음"}
|
||||
qty = [
|
||||
mf.run(whole, "산림품셈:13-4-2 메쌓기(장비)", {"뒷길이": x, **region})["줄"][0]["수량"]
|
||||
for x in (35, 36, 75)
|
||||
]
|
||||
assert qty == [Decimal("0.1"), Decimal("0.09"), Decimal("0.08")]
|
||||
|
||||
|
||||
def test_범위규칙_마지막칸_이하_포함(whole):
|
||||
"""13-6-1 직경 「80㎝이상∼100㎝이하」 — 100 은 맞고 101 은 막힘."""
|
||||
given = {"직경": 100, "지역": "전국평균", "보정작업": "해당 없음"}
|
||||
assert mf.run(whole, "산림품셈:13-6-1 큰돌 메쌓기", given)["줄"][0]["수량"] == Decimal("0.68")
|
||||
with pytest.raises(mf.FormulaError):
|
||||
mf.run(whole, "산림품셈:13-6-1 큰돌 메쌓기", {**given, "직경": 101})
|
||||
|
||||
|
||||
def test_굴착기_부착용_집게(whole):
|
||||
"""잡재료 16%(8-4-8 주⑤) · 집게 손료 7,783천원×7435×10⁻⁷ 버림."""
|
||||
got = mf.run(
|
||||
whole,
|
||||
"건설품셈:8 굴착기+부착용 집게 시간당 경비",
|
||||
{"기계": "0201-0060", "집게": "7206-0070", "지역": "전국평균", "보정작업": "해당 없음"},
|
||||
)
|
||||
assert got["중간"]["집게손료"] == 5786
|
||||
assert cents(got["계"]) == "86467.61"
|
||||
|
||||
|
||||
def test_범위_입력은_막음(whole):
|
||||
with pytest.raises(mf.FormulaError):
|
||||
mf.run(
|
||||
@@ -113,9 +142,12 @@ def test_견본_파일_검사_통과(whole):
|
||||
# 9장 계수 표는 같은 절의 소요량 표와 함께 대조 — 소요량 파일 자체의 알림은 그 창 몫
|
||||
with_09 = files | cm.load(["소요량_산림품셈_09장.json"])
|
||||
# 절 통째를 출처로 둔 다른 창 표(9-13 · 9-20)의 결손도 그 창 몫
|
||||
others = ("9-13 관보호공 인력 가산", "9-20 대상 근주")
|
||||
# 8-4-8 주⑤ 표는 절의 운전경비 수가 기계 요소(표 그룹 밖)에 있어 결손으로 뜸
|
||||
others = ("9-13 관보호공 인력 가산", "9-20 대상 근주", "8-4-8 주⑤ 조합 잡재료율")
|
||||
body = cm.check_body(with_09)
|
||||
assert [x for x in body if not x.startswith("소요량_산림품셈_09장") and not x.endswith(others)] == []
|
||||
assert [
|
||||
x for x in body if not x.startswith("소요량_산림품셈_09장") and not x.endswith(others)
|
||||
] == []
|
||||
assert cm.check_logics(files, whole) == []
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user