feat(820-1): 품셈에 없는 소형·보조 기계 13 줄 · 파워트로웰 기계경비식 GC001195 · 가격 = EST 씨앗(갱신 필요)
- 기계.json EQ000656~668 더함 — 발전기 5.5·7·10㎾(손료계수 2362 발전기 계열) · 대형 브레이커 0.18㎥(0.2㎥ 계수·가격) · 에어 호스 1.91㎝ · 모노펌프 5-20㎥/hr · 파워트로웰 3.73㎾ · 콘크리트펌프용 파이프 여섯($ × 환율 FX000001 · 비고에 $ 값) - 원문번호 「자체 이름 규격」 · 출처 가격 = 자체 · 비고 = EST 단가 구성 → 우리 줄 · 가격 갱신 필요 - 계산식 — 손료만 = GC000273 · 발전기 5.5 = GC000268 고르기 끝에 더함(814-1 빌더 · 로직 + 수식 문서) · 파워트로웰 = 새 GC001195(휘발유 + 잡품(주연료 줄 %) + 전력 + 손료) - 발전기 7·10㎾ = 2016 사방품셈(안) 기계경비 가격 · 그 표대로 손료만 - M02_Machine_Hourly 시간당 부름에서 빈칸 든 입력 이름(전력 계약종별) 따옴표 — 파워트로웰 시간당 이음 - 기술정보 기계경비_산정 7 절(표) - 낡은 시험 고침: 812_9 test_no_guess · 815_1 test_alias_machine 이 「에어 호스 · 모노펌프 = 우리 표에 없음」 예로 씀 → 아직 없는 기종(진공흡입기 · 스키드로더)으로 - 기존 수식 문서 1,514 기본 금액 전후 같음 · check_master 전후 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
"""품셈에 없는 소형 · 보조 기계를 우리 기계표 줄로(PLAN 820-1 · 요구 785 ~ 787 · 방향 장부 Q1 · R).
|
||||
|
||||
EST 단가 구성 → 우리 줄 — 손료계수 · 연료 · 잡품 · 조종원 = 품셈 값(발전기 계열 2,362 · 대형 브레이커 6,601) ·
|
||||
가격 = EST 씨앗(출처 「자체」 · 비고 「갱신 필요」) · 콘크리트펌프용 파이프 = 달러값 × 한국은행 환율(FX000001).
|
||||
계산식:
|
||||
손료만(브레이커 0.18 · 에어 호스 · 모노펌프 · 파이프 · 발전기 7 · 10㎾) = GC000273 고르기에 더함
|
||||
발전기 5.5㎾(경유 · 잡품 · 일반기계운전사) = GC000268 고르기에 더함
|
||||
→ 고르기 더하기는 `build_기계목록_빠진기계_814_1`(로직 · 수식 문서 목록 같이)
|
||||
파워트로웰(휘발유 · 잡품 · 전력 · 조종원 없음) = 새 기계경비식 GC001195 — 기계 줄 값을 바로 읽음
|
||||
(`M02_Machine_Hourly._own` 이 고름) · 잡품 = 주연료 줄의 % (전력 줄엔 안 붙임)
|
||||
더하기만 — 다른 줄 · 서식 그대로 · 두 번 돌려도 같음.
|
||||
|
||||
쓰기: venv python resources/master_data/scripts/build_기계_소형보조_820_1.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
DATA = HERE.parent
|
||||
ROOT = DATA.parents[1]
|
||||
MACHINE = DATA / "기계.json"
|
||||
BOOK = DATA / "_키대장.json"
|
||||
LOGIC = DATA / "로직_건설품셈_08장_건설기계.json"
|
||||
DOC = DATA / "수식문서" / "수식_건설품셈_08장_건설기계.json"
|
||||
|
||||
USD = 1414.9 # 원/USD — 한국은행 환율 FX000001(2026-08-14)
|
||||
SEED = "EST 단가 구성 → 우리 줄 · 손료계수·연료 = 품셈 값 · 가격 = EST 씨앗(갱신 필요)"
|
||||
GEN = {"상각비계수": 1125, "정비비계수": 563, "관리비계수": 674, "손료계수": 2362} # 발전기 계열
|
||||
BRK = {"상각비계수": 3000, "정비비계수": 2833, "관리비계수": 768, "손료계수": 6601} # 0230-0002
|
||||
UNIT = {
|
||||
"가격": "천원", "상각비계수": "10^-7/시간", "정비비계수": "10^-7/시간",
|
||||
"관리비계수": "10^-7/시간", "손료계수": "10^-7/시간", "주연료": "ℓ/hr", "주연료종류": "",
|
||||
"잡재료율": "주연료의 %", "조종원": "인/일", "조종원직종": "", "전력": "㎾h/hr",
|
||||
} # fmt: skip
|
||||
FIX_SRC = {"발전기": "건설품셈 공통 8-3-8", "브레이커": "건설품셈 공통 8-3-1"}
|
||||
WAGE = "건설품셈 공통 8-1-3 5 · 건설노임 1050"
|
||||
SAB = "2016 사방사업표준품셈(안) 기계경비"
|
||||
PIPE = {"150㎜×1m": 25, "150㎜×2m": 37, "150㎜×3m": 46,
|
||||
"곡관 150㎜ 45°": 67, "곡관 150㎜ 60°": 84, "곡관 150㎜ 90°": 103} # fmt: skip
|
||||
|
||||
|
||||
def _row(n, gubun, detail, name, spec, value, note, fix=None):
|
||||
src = {k: (FIX_SRC[fix] if fix and k in GEN else "자체") for k in value}
|
||||
if "조종원직종" in value:
|
||||
src["조종원직종"] = WAGE
|
||||
return {
|
||||
"키": f"EQ{n:06d}",
|
||||
"원문번호": f"자체 {name} {spec}",
|
||||
"원문": "건설품셈",
|
||||
"구분": gubun,
|
||||
"상세구분": detail,
|
||||
"이름": name,
|
||||
"규격": spec,
|
||||
"단위": {k: UNIT[k] for k in value},
|
||||
"값": value,
|
||||
"출처": src,
|
||||
"비고": f"{SEED} · {note}",
|
||||
}
|
||||
|
||||
|
||||
def rows() -> list[dict]:
|
||||
g, c, t = "[70]기타기계", "[40]콘크리트기계", "[00]토공기계"
|
||||
fuel5 = {
|
||||
"주연료": 0.625,
|
||||
"주연료종류": "경유",
|
||||
"잡재료율": 11,
|
||||
"조종원": 1,
|
||||
"조종원직종": "1050",
|
||||
}
|
||||
out = [
|
||||
_row(656, g, "발전기", "발전기", "5.5㎾", {"가격": 1063, **GEN, **fuel5},
|
||||
"EST 계 37,760 · 주연료 · 잡품 · 조종원(일반기계운전사) = " + SAB + "과 같음", "발전기"),
|
||||
_row(657, g, "발전기", "발전기", "7㎾", {"가격": 1828.9, **GEN},
|
||||
f"가격 = {SAB}(1,828,900 원) · 그 표 = 손료만(연료 · 조종원 없음)", "발전기"),
|
||||
_row(658, g, "발전기", "발전기", "10㎾", {"가격": 3213, **GEN},
|
||||
f"가격 = {SAB}(3,213,000 원) · 그 표 = 손료만(연료 · 조종원 없음)", "발전기"),
|
||||
_row(659, t, "브레이커", "대형 브레이커", "0.18㎥", {"가격": 4559, **BRK},
|
||||
"손료만(굴착기 부속) · 가격 = 0.2㎥(0230-0002) 값 · 계수 = 0.2㎥ 계수", "브레이커"),
|
||||
_row(660, g, "에어 호스", "에어 호스", "1.91㎝", {"가격": 105, "손료계수": 5625},
|
||||
"손료만 · EST 계 59"),
|
||||
_row(661, g, "모노펌프", "모노펌프", "5-20㎥/hr", {"가격": 4900, "손료계수": 4346},
|
||||
"손료만 · EST 계 2,129"),
|
||||
_row(662, c, "파워트로웰", "파워트로웰", "3.73㎾",
|
||||
{"가격": 2680, "손료계수": 5313, "주연료": 1.0, "주연료종류": "휘발유", "잡재료율": 10, "전력": 3.73},
|
||||
"주연료 휘발유 · 잡품 · 전력 3.73 ㎾h · 조종원 없음 · EST 계 3,858 · 시간당 경비 = GC001195"),
|
||||
] # fmt: skip
|
||||
for i, (spec, usd) in enumerate(PIPE.items()):
|
||||
out.append(
|
||||
_row(663 + i, c, "콘크리트펌프용 파이프", "콘크리트펌프용 파이프", spec,
|
||||
{"가격": round(usd * USD / 1000, 4), "손료계수": 4500},
|
||||
f"압송관 · 손료만 · ${usd} 표기 · 환율 적용({USD:,} 원/USD · 한국은행 2026-08-14 FX000001) 또는 원화 갱신 필요")
|
||||
) # fmt: skip
|
||||
return out
|
||||
|
||||
|
||||
EQ = "EQ000662"
|
||||
LOGIC_ROW = {
|
||||
"키": "GC001195",
|
||||
"원문번호": "8",
|
||||
"구분": "건설품셈 공통",
|
||||
"상세구분": "08장 건설기계",
|
||||
"이름": "파워트로웰 시간당 기계경비",
|
||||
"결과단위": "원/시간",
|
||||
"출처": "건설품셈 공통 8-1-5 · 8-1-6",
|
||||
"부품": {"갈래": "기계경비식"},
|
||||
"소유": "공용",
|
||||
"비고": f"품셈에 없는 기계 — {SEED} · 기계표 {EQ} 파워트로웰 3.73㎾ 값을 읽음 · 손료 = 가격 × 손료계수 · 잡품 = 주연료 줄의 % · 전력 = 기계표 전력 칸 · 조종원 없음",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "지역",
|
||||
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
|
||||
"출처": "건설품셈 공통 8-1-7 5",
|
||||
},
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": ["주택용 저압", "일반용(갑)Ⅰ 저압"],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)",
|
||||
},
|
||||
],
|
||||
"중간": [
|
||||
{"이름": "손료", "식": f"버림({EQ}.가격 * 1000 * {EQ}.손료계수 / 10000000, 0)", "출처": "건설품셈 공통 8-1-5 12 · 8-1-6 4"},
|
||||
],
|
||||
"호표": [
|
||||
{"종류": "재료", "요소": "MO:휘발유:{지역}", "이름": "주연료", "단위": "ℓ", "수량": f"{EQ}.주연료", "비목": "재료비", "출처": "건설품셈 공통 8-4-1"},
|
||||
{"종류": "재료", "요소": {"이름": "전력량요금", "계약종별": "입력"}, "이름": "전력", "단위": "㎾h", "수량": f"{EQ}.전력", "비목": "재료비", "출처": "자체"},
|
||||
],
|
||||
"덧줄": [
|
||||
{"이름": "잡재료비", "식": f"줄.'주연료' * {EQ}.잡재료율 / 100", "비목": "재료비", "출처": "건설품셈 공통 8-4 주②"},
|
||||
{"이름": "기계손료", "식": "손료", "비목": "경비", "출처": "건설품셈 공통 8-1-6 2"},
|
||||
],
|
||||
"끝수": "손료 원 미만 버림(건설품셈 공통 8-1-5 12) · 합계 원문 규정 없음",
|
||||
"변수표": {
|
||||
"지역": {"기호": "S", "아래": "지역"},
|
||||
"전력 계약종별": {"기호": "S", "아래": "전력계약종별"},
|
||||
"손료": {"기호": "C", "아래": "손료"},
|
||||
},
|
||||
} # fmt: skip
|
||||
|
||||
|
||||
def _block(obj: dict, nl: str) -> str:
|
||||
"""줄 하나 — 두 칸 들여쓴 JSON 을 넷 칸 자리에."""
|
||||
text = json.dumps(obj, ensure_ascii=False, indent=2)
|
||||
return nl.join(" " + line for line in text.split("\n"))
|
||||
|
||||
|
||||
def _insert_tail(path: Path, objs: list[dict]) -> None:
|
||||
"""「줄」 목록 끝(`]` 앞)에 더함 — 이미 있는 키는 건너뜀."""
|
||||
text = path.read_text("utf-8")
|
||||
have = {r["키"] for r in json.loads(text)["줄"]}
|
||||
new = [o for o in objs if o["키"] not in have]
|
||||
if not new:
|
||||
return
|
||||
nl = "\r\n" if "\r\n" in text else "\n"
|
||||
close = text.rstrip().rindex("]")
|
||||
head = text[:close].rstrip()
|
||||
body = "".join(f",{nl}{_block(o, nl)}" for o in new)
|
||||
out = head + body + nl + " " + text[close:]
|
||||
json.loads(out)
|
||||
path.write_text(out, "utf-8", newline="")
|
||||
|
||||
|
||||
def _insert_after(path: Path, after_key: str, obj: dict) -> None:
|
||||
"""키 `after_key` 블록 뒤에 줄 하나 — 이미 있으면 건너뜀."""
|
||||
text = path.read_text("utf-8")
|
||||
if f'"키": "{obj["키"]}"' in text:
|
||||
return
|
||||
nl = "\r\n" if "\r\n" in text else "\n"
|
||||
data = json.loads(text)
|
||||
at = text.index(f'"키": "{after_key}"')
|
||||
nxt = [r["키"] for r in data["줄"]]
|
||||
follow = nxt[nxt.index(after_key) + 1]
|
||||
cut = text.rindex("{", 0, text.index(f'"키": "{follow}"'))
|
||||
cut = text.rindex(",", at, cut) + 1
|
||||
out = text[:cut] + nl + _block(obj, nl) + "," + text[cut:]
|
||||
json.loads(out)
|
||||
path.write_text(out, "utf-8", newline="")
|
||||
|
||||
|
||||
def _book(machines: list[dict]) -> None:
|
||||
text = BOOK.read_text("utf-8")
|
||||
nl = "\r\n" if "\r\n" in text else "\n"
|
||||
adds = [(r["키"], r["원문번호"], "기계.json", "EQ000655") for r in machines]
|
||||
adds.append(("GC001195", "공통 8 파워트로웰 시간당 경비", LOGIC.name, "GC001194"))
|
||||
for key, number, file, after in adds:
|
||||
if f'"{key}":' in text:
|
||||
continue
|
||||
line = f' "{key}": {json.dumps({"원문번호": number, "파일": file}, ensure_ascii=False)},'
|
||||
prev = max((k for k, *_ in adds if k[:2] == key[:2] and f'"{k}":' in text), default=after)
|
||||
at = text.index(f' "{prev}":')
|
||||
end = text.index(nl, at) + len(nl)
|
||||
text = text[:end] + line + nl + text[end:]
|
||||
book = json.loads(text)
|
||||
nums = {"EQ": 669, "GC": 1196}
|
||||
for tid, n in nums.items():
|
||||
old = book["다음"][tid]
|
||||
if old < n:
|
||||
text = text.replace(f'"{tid}": {old},', f'"{tid}": {n},', 1)
|
||||
json.loads(text)
|
||||
BOOK.write_text(text, "utf-8", newline="")
|
||||
|
||||
|
||||
def _doc() -> None:
|
||||
"""GC001195 수식 문서 — 옛 로직 변환(`master_doc_convert`) · 파일 끝에 더함."""
|
||||
for p in (str(ROOT), str(HERE)):
|
||||
if p not in sys.path:
|
||||
sys.path.insert(0, p)
|
||||
import master_doc_convert as cv
|
||||
import master_doc_link as ml
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
|
||||
data = json.loads(DOC.read_text("utf-8"))
|
||||
if any(d.get("키") == "GC001195" for d in data["줄"]):
|
||||
return
|
||||
files, whole = m01.loaded()
|
||||
doc, notes = cv.convert(whole, LOGIC_ROW)
|
||||
if notes:
|
||||
print("변환 알림:", notes)
|
||||
data["줄"].append(doc)
|
||||
DOC.write_text(ml.dump(data), "utf-8", newline="")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
machines = rows()
|
||||
_insert_tail(MACHINE, machines)
|
||||
_book(machines)
|
||||
_insert_after(LOGIC, "GC000276", LOGIC_ROW)
|
||||
_doc()
|
||||
import build_기계목록_빠진기계_814_1 as b814
|
||||
|
||||
b814.main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(HERE))
|
||||
main()
|
||||
Reference in New Issue
Block a user