knowledge(마스터): 전력을 재료_유가전력으로 연결 — 자재품목 전력 2줄 뺌
- 품셈재료 「전력」 연결 = {이름: 전력량요금, 계약종별: 입력} — 유가전력 전력 줄을 가리킴
- 전력 쓰는 로직 8 줄에 입력 「전력 계약종별」(주택용 저압 · 일반용(갑)Ⅰ 저압 · 산업용(갑)Ⅰ 저압) — 품셈·계약예규에 계약종별 규정 없어 기본값 두지 않음
- 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가) — 따로 고르기에 두지 않음
- master_material: 자재품목 아닌 줄은 「값」 한 칸으로 읽고 계약종별 후보를 고름 · check_master 연결 모양·끊김 검사도 맞춤
- 자재품목 MT000006 · MT000007 삭제 → _키대장.json 「폐기」 · 빌더 DROP 에 더해 다시 만들어도 같음
- _틀.md 재료 절 · 시험 둘 고침(전력 계약종별 · 연결 낮은 값은 시멘트로)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"다음": {"LB": 409, "EQ": 655, "RT": 20, "MN": 7000, "MT": 24361, "MO": 73, "MP": 364, "FX": 6, "CF": 159, "QF": 477, "GF": 252, "CC": 337, "GC": 1104, "QC": 2060},
|
||||
"폐기": {"MT000001": "자재품목 휘발유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000002": "자재품목 경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000003": "자재품목 선박용경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000004": "자재품목 중유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000005": "자재품목 등유 — 값이 비고 글뿐 · 유가 테이블로 감", "LB000399": "이름 「〃」 — 직종이 아니라 되풀이 기호 · 소요량 13-6-9 에서 윗줄 직종으로 바로잡음", "MN": "재료_나라장터자재 — old 로 옮김 · 로직은 자재품목·품셈재료로 갈아 끼움", "LB000372": "미확보 고급기능사 — 측량노임 항공사진고급기능사 옛이름으로 옮김", "LB000393": "미확보 리베팅공 — 건설노임 철골공 옛이름으로 옮김(2010 통합표 연번10)", "LB000405": "미확보 Belt Conveyor 설치공 — 품셈 13-10-1 주② 배분으로 다섯 직종에 나눔"},
|
||||
"폐기": {"MT000001": "자재품목 휘발유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000002": "자재품목 경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000003": "자재품목 선박용경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000004": "자재품목 중유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000005": "자재품목 등유 — 값이 비고 글뿐 · 유가 테이블로 감", "LB000399": "이름 「〃」 — 직종이 아니라 되풀이 기호 · 소요량 13-6-9 에서 윗줄 직종으로 바로잡음", "MN": "재료_나라장터자재 — old 로 옮김 · 로직은 자재품목·품셈재료로 갈아 끼움", "LB000372": "미확보 고급기능사 — 측량노임 항공사진고급기능사 옛이름으로 옮김", "LB000393": "미확보 리베팅공 — 건설노임 철골공 옛이름으로 옮김(2010 통합표 연번10)", "LB000405": "미확보 Belt Conveyor 설치공 — 품셈 13-10-1 주② 배분으로 다섯 직종에 나눔", "MT000006": "자재품목 전력 — 재료_유가전력 전력 줄로 감", "MT000007": "자재품목 전력 — 재료_유가전력 전력 줄로 감"},
|
||||
"키": {
|
||||
"CC000001": {"원문번호": "공통 1-3-1 콘크리트 및 포장용 재료", "파일": "계수_건설품셈_01장_적용기준.json"},
|
||||
"CC000002": {"원문번호": "공통 1-3-1 노상 및 노반재료", "파일": "계수_건설품셈_01장_적용기준.json"},
|
||||
@@ -3348,8 +3348,6 @@
|
||||
"MP000361": {"원문번호": "동 및 동합금용 용접봉 BCUP3", "파일": "재료_품셈재료.json"},
|
||||
"MP000362": {"원문번호": "폴리에틸렌필름 0.04㎜", "파일": "재료_품셈재료.json"},
|
||||
"MP000363": {"원문번호": "아스팔트싱글 336×1,000×3㎜", "파일": "재료_품셈재료.json"},
|
||||
"MT000006": {"원문번호": "M0005250064", "파일": "재료_자재품목.json"},
|
||||
"MT000007": {"원문번호": "M0005250065", "파일": "재료_자재품목.json"},
|
||||
"MT000008": {"원문번호": "M0005250066", "파일": "재료_자재품목.json"},
|
||||
"MT000009": {"원문번호": "M0005250067", "파일": "재료_자재품목.json"},
|
||||
"MT000010": {"원문번호": "M0005250068", "파일": "재료_자재품목.json"},
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
| -------------------- | --------------------------------------------------------------------------------------- |
|
||||
| 인력 | `인력.json` 하나 — 줄마다 `조사` |
|
||||
| 기계 | `기계.json` 하나 — 줄마다 `세부분류` |
|
||||
| 재료 | `재료_<원문>.json` — 자재품목 · 오피넷유가 · 품셈재료 |
|
||||
| 재료 | `재료_<원문>.json` — 자재품목 · 유가전력 · 품셈재료 |
|
||||
| 환율 · 요율 | `환율_한국은행환율.json` · `요율_조달청제비율.json` |
|
||||
| 소요량 · 계수 · 로직 | `<그룹>_<원문>_<NN>장_<장 제목>.json` — 예 `소요량_건설품셈_10장_창호_및_유리공사.json` |
|
||||
|
||||
- 장 파일 — 장 번호는 두 자리 · 장 제목은 원문 본문 폴더 이름 그대로 · 부문은 이름에 넣지 않음.
|
||||
- 장 파일 머리 — `부문`(건설품셈만 · 공통 · 토목 · 건축 · 기계설비 · 유지관리) · `차례`(그룹 안 목록 차례: 산림 1~14장 → 건설 공통 → 토목 → 건축 → 기계설비 → 유지관리).
|
||||
- 원문 이름 = 산림품셈 · 건설품셈 · 건설노임 · 제조노임 · 엔지니어링노임 · 측량노임 · 건설사업관리노임 · SW노임 · 산림노임 · 준용대상 · 오피넷유가 · 자재품목 · 한국은행환율 · 조달청제비율 · 품셈재료 · 자체
|
||||
- 원문 이름 = 산림품셈 · 건설품셈 · 건설노임 · 제조노임 · 엔지니어링노임 · 측량노임 · 건설사업관리노임 · SW노임 · 산림노임 · 준용대상 · 유가전력 · 자재품목 · 한국은행환율 · 조달청제비율 · 품셈재료 · 자체
|
||||
|
||||
## 3. 키
|
||||
|
||||
@@ -114,11 +114,11 @@
|
||||
- `구분` · `상세구분` = 원문(ESTX)에 대·중분류 칸이 없어 비움 — 지어내지 않음.
|
||||
- `면수` = 물가지 값의 원문 면수 묶음 `{ 물가자료, 유통물가, 물가정보, 거래가격 }` · 없으면 `null` · 화면에는 접어 둠.
|
||||
- **원문번호 칸 없음** — 원문(ESTX)이 준 품번 `M0005250505` 는 남의 번호라 이름 몫을 못 함 · 대조는 `_키대장.json` 에만 둠(조달청에서 새로 더한 줄의 조달청 번호도 같음). 로직·연결은 키로 적음.
|
||||
- 유류(휘발유 · 경유 · 선박용경유 · 중유 · 등유)는 값이 비고 글뿐이라 뗌 — 유가는 `재료_오피넷유가` · 중유는 받지 않음.
|
||||
- `재료_오피넷유가` · `환율_한국은행환율` 도 열 한 벌 — 키 · 원문번호 · 구분 · 상세구분 · 이름 · 규격 · 단위 · 값 · 출처 · 비고. 유가 `구분` = 전국평균 · 시도별 · `상세구분` = 지역 이름 · `규격` = 기준일. 환율은 `규격` = 기준일 · 구분·상세구분 비움.
|
||||
- 유류·전력은 뗌 — 유가·전기요금은 `재료_유가전력`(유류는 값이 비고 글뿐 · 중유는 받지 않음).
|
||||
- `재료_유가전력` · `환율_한국은행환율` 도 열 한 벌 — 키 · 원문번호 · 구분 · 상세구분 · 이름 · 규격 · 단위 · 값 · 출처 · 비고. 유가전력 `구분` = 유류 · 전력 · `상세구분` = 유류(지역 이름) · 전력(계약종별) · `규격` = 기준일(유류 수집일 · 전력 시행일). 환율은 `규격` = 기준일 · 구분·상세구분 비움.
|
||||
- 로직 호표가 자재품목 키(`MT…`)를 바로 가리키면 그 줄의 값 열 가운데 낮은 값 — **시험 계산용**.
|
||||
- `재료_품셈재료` = 품셈이 부르는 재료 목록 — `{ 키, 원문번호, 이름, 규격, 단위, 요구절: [출처 모양], 연결 }` · 값 칸 없음.
|
||||
- `연결` = 자재품목 키 하나 · 후보 조건 `{ 이름, 규격, 지역: "입력" }`(지역이 갈리는 레미콘·골재·아스콘) · `null`(아직 못 이음).
|
||||
- `연결` = 자재품목·유가전력 키 하나 · 후보 조건 `{ 이름, 규격, 지역: "입력" }`(지역이 갈리는 레미콘·골재·아스콘) · `{ 이름, 계약종별: "입력" }`(전력 — 로직 입력 `전력 계약종별`) · `null`(아직 못 이음).
|
||||
- 단가 = 연결된 줄의 값 열 다섯 가운데 낮은 값 · 호표 결과 줄에 `출처`(`<키>.<열>`) — **시험 계산용**. 후보 조건 = 품명 뿌리가 `이름` 으로 끝남 · 이름에 로직 입력 `자재지역` 글자 · 단위 같음 · 규격이 둘 이상 갈리면 멈춤 「후보 여럿」 · 그 지역 줄이 없으면 가까운 시군을 고르지 않고 멈춤 「지역 값 없음」.
|
||||
|
||||
## 6. 표형 요소 (소요량 · 계수)
|
||||
|
||||
@@ -27,13 +27,15 @@ from compare_estx import ESTX, ROOT, SLOTS, Estx # noqa: E402
|
||||
OUT = ROOT / "resources/master_data/재료_자재품목.json"
|
||||
BASE = SLOTS[0] # Cost1 「가격정보」 — 관급이면 관급 열 · 아니면 비고
|
||||
MARKET = SLOTS[1:5] # 물가지 넷 · 견적가(Cost6)는 마스터 아님
|
||||
# 유류 — 값이 비고 글뿐이라 뺌 · 유가는 재료_오피넷유가 · 중유는 받지 않음(대장 「폐기」)
|
||||
# 유류·전력 — 유가·전기요금은 재료_유가전력(유류는 값이 비고 글뿐 · 중유는 받지 않음 · 대장 「폐기」)
|
||||
DROP = {
|
||||
"M0003039885": "휘발유",
|
||||
"M0003039886": "경유",
|
||||
"M0004805582": "선박용경유",
|
||||
"M0003039887": "중유",
|
||||
"M0003039888": "등유",
|
||||
"M0005250064": "전력",
|
||||
"M0005250065": "전력(주택용저압)",
|
||||
}
|
||||
|
||||
|
||||
@@ -133,9 +135,10 @@ def main():
|
||||
"비고": [
|
||||
"다산소프트 EST 2026-07 자재 · 개발용 · 배포 전 판권 구매",
|
||||
"값 열 다섯 = 물가지 넷(물가자료 · 유통물가 · 물가정보 · 거래가격) · 관급(조달) — 채택값·기본가 없음 · 쓰는 곳이 값을 고르고 출처를 밝힘",
|
||||
"유류(휘발유 · 경유 · 선박용경유 · 중유 · 등유)는 값이 비고 글뿐이라 뺌 — 유가는 재료_오피넷유가 · 중유는 받지 않음",
|
||||
"유류·전력은 뺌 — 유가·전기요금은 재료_유가전력(유류는 값이 비고 글뿐 · 중유는 받지 않음)",
|
||||
"원문번호(다산소프트 품번) 칸 없음 — 대조는 _키대장.json 에만",
|
||||
"관급 = 원문 「가격정보」 칸의 조달청 관급 단가(철근 · 레미콘 · 아스콘 · H형강 등) · 기간은 비고 「조달 26.7」",
|
||||
"조달청에만 있는 품목 380 줄은 관급 열만 채움 — 출처 「자재품목 조달청 …」 · 원문번호는 _키대장.json 에만",
|
||||
"원문 「가격정보」 칸에 시중 값이 남은 줄은 값 열에 넣지 않고 비고 「가격정보 ○○」 로만 둠 — 출처가 조달인지 물가지인지 원문이 안 가름",
|
||||
"구분 · 상세구분 = 원문에 대·중분류 칸이 없어 비움(지어내지 않음)",
|
||||
"면수 = 물가지 값의 원문 면수 · 화면에는 접어 둠",
|
||||
|
||||
@@ -300,8 +300,9 @@ def _check_linked(where: str, row: dict) -> list[str]:
|
||||
link = row.get("연결")
|
||||
if isinstance(link, dict) and (
|
||||
not link.get("이름")
|
||||
or set(link) - {"이름", "규격", "지역"}
|
||||
or set(link) - {"이름", "규격", "지역", "계약종별"}
|
||||
or link.get("지역") not in (None, "입력")
|
||||
or link.get("계약종별") not in (None, "입력")
|
||||
):
|
||||
out.append(f"{where} · 후보 조건 모양 「{link}」")
|
||||
elif link is not None and not isinstance(link, (str, dict)):
|
||||
@@ -314,8 +315,8 @@ def check_links(whole: mf.Master) -> list[str]:
|
||||
out = []
|
||||
for key, row in whole.index.get("MP", {}).items():
|
||||
link = row.get("연결")
|
||||
if isinstance(link, str) and link not in whole.index.get("MT", {}):
|
||||
out.append(f"{whole.label(key)} · 연결 「{link}」 이 자재품목에 없음")
|
||||
if isinstance(link, str) and link not in whole.index.get(link[:2], {}):
|
||||
out.append(f"{whole.label(key)} · 연결 「{link}」 이 자재품목·유가전력에 없음")
|
||||
for key, row in whole.index.get("LB", {}).items():
|
||||
for col in ("준용",):
|
||||
ref = row.get(col)
|
||||
|
||||
@@ -567,6 +567,12 @@ def _check_node(row, node, known: set, master: Master, where: str, out: list, ca
|
||||
continue
|
||||
if isinstance(link, dict) and link.get("지역") == "입력" and REGION not in known:
|
||||
out.append(f"{where} · 「{master.label(ref)}」 는 입력 「{REGION}」 필요")
|
||||
if (
|
||||
isinstance(link, dict)
|
||||
and link.get("계약종별") == "입력"
|
||||
and TARIFF not in known
|
||||
):
|
||||
out.append(f"{where} · 「{master.label(ref)}」 는 입력 「{TARIFF}」 필요")
|
||||
if kind == "field" and part[1][0] == "ref":
|
||||
for ref in _expand(row, part[1][1], master) or []:
|
||||
try:
|
||||
@@ -678,4 +684,4 @@ def find_loops(graph: dict[str, set]) -> list[list[str]]:
|
||||
|
||||
|
||||
# 품셈재료 단가 — 서로 부르는 모듈이라 끝에서 읽음
|
||||
from master_material import LINKED, REGION, SLOTS, element # noqa: E402, F401
|
||||
from master_material import LINKED, REGION, SLOTS, TARIFF, element # noqa: E402, F401
|
||||
|
||||
@@ -14,8 +14,10 @@ from decimal import Decimal
|
||||
|
||||
LINKED = "MP" # 품셈재료 테이블ID
|
||||
MARKET = "MT" # 자재품목 테이블ID
|
||||
PRICED = "MO" # 유가전력 테이블ID — 값 한 칸
|
||||
SLOTS = ("물가자료", "유통물가", "물가정보", "거래가격", "관급") # 자재품목 값 열
|
||||
REGION = "자재지역" # 로직 입력 — 「지역」 은 유가 고르기가 씀
|
||||
TARIFF = "전력 계약종별" # 로직 입력 — 품셈·계약예규에 계약종별 규정 없음
|
||||
_UNITS = {"ea": "개", "ton": "톤", "t": "톤", "l": "ℓ", "리터": "ℓ", "set": "조", "세트": "조"}
|
||||
|
||||
|
||||
@@ -35,8 +37,10 @@ def plain_unit(s) -> str:
|
||||
|
||||
|
||||
def _offers(master: mf.Master, key: str) -> list[tuple[Decimal, str]]:
|
||||
"""자재품목 줄 하나의 (값, 출처) — 값이 있는 열마다 하나 · 출처는 그 열 이름."""
|
||||
"""줄 하나의 (값, 출처) — 자재품목은 값이 있는 열마다 하나 · 그 밖(유가전력)은 「값」 한 칸."""
|
||||
row = master.get(key)
|
||||
if key[:2] != MARKET:
|
||||
return [(row["값"], f"{row['키']}.값")] if row.get("값") is not None else []
|
||||
return [(row[slot], f"{row['키']}.{slot}") for slot in SLOTS if row.get(slot) is not None]
|
||||
|
||||
|
||||
@@ -59,9 +63,30 @@ def _market_index(master: mf.Master) -> list[tuple[str, str, str, str, str]]:
|
||||
return master._market
|
||||
|
||||
|
||||
def _tariff(master: mf.Master, ref: str, row: dict, env: dict) -> list[str]:
|
||||
"""후보 조건{이름 · 계약종별: 입력} — 유가전력 전력 줄 가운데 그 계약종별·이름으로 시작하는 줄."""
|
||||
cond = row["연결"]
|
||||
if TARIFF not in env:
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 입력 「{TARIFF}」 없음")
|
||||
want, kind = plain(cond["이름"]), plain(env[TARIFF])
|
||||
hits = [
|
||||
key
|
||||
for key, one in master.index.get(PRICED, {}).items()
|
||||
if one.get("구분") == "전력"
|
||||
and plain(one.get("상세구분")) == kind
|
||||
and plain(one.get("이름")).startswith(want)
|
||||
and one.get("값") is not None
|
||||
]
|
||||
if not hits:
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 계약종별 값 없음 — {env[TARIFF]}")
|
||||
return hits
|
||||
|
||||
|
||||
def _candidates(master: mf.Master, ref: str, row: dict, env: dict) -> list[str]:
|
||||
"""후보 조건{이름 · 규격 · 지역: 입력} — 뿌리가 이름으로 끝나고 이름에 지역 글자 · 단위 같음."""
|
||||
cond = row["연결"]
|
||||
if cond.get("계약종별") == "입력":
|
||||
return _tariff(master, ref, row, env)
|
||||
if cond.get("지역") == "입력" and REGION not in env:
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 입력 「{REGION}」 없음")
|
||||
region = plain(env.get(REGION, "")) if cond.get("지역") == "입력" else ""
|
||||
|
||||
@@ -2324,6 +2324,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "규정 층수 용접 · Net Arc Time 품 ÷ 작업효율(주②) · Beveling 포함 · 공구손료 · 비파괴 · Preheating · Annealing 별도 · 합금강은 13-2-3 전기아크처럼",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "두께",
|
||||
"단위": "㎜",
|
||||
@@ -2426,6 +2436,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "규정 층수 용접 · Net Arc Time 품 ÷ 작업효율(주②) · Beveling 포함 · 공구손료 · 비파괴 · Preheating · Annealing 별도 · 합금강은 13-2-3 전기아크처럼",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "두께",
|
||||
"단위": "㎜",
|
||||
@@ -2523,6 +2543,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "규정 층수 용접 · Net Arc Time 품 ÷ 작업효율(주②) · Beveling 포함 · 공구손료 · 비파괴 · Preheating · Annealing 별도 · 합금강은 13-2-3 전기아크처럼 · Gouging 제외(표2 Arc Air Gouging 참고)",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "두께",
|
||||
"단위": "㎜",
|
||||
@@ -2628,6 +2658,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "하향식 · Beveling 포함 · 품 ÷ 작업효율(V형 주②) · 공구손료 · 비파괴 · Preheating · Annealing 별도",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "두께",
|
||||
"단위": "㎜",
|
||||
@@ -2728,6 +2768,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "하향식 · Beveling 포함 · 품 ÷ 작업효율(V형 주②) · 공구손료 · 비파괴 · Preheating · Annealing 별도",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "두께",
|
||||
"단위": "㎜",
|
||||
@@ -8411,6 +8461,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "소모자재는 원문 참고표 Tainter 칸 · 공정별 품의 합(ton당) · 검사 · 교정은 기술관리, 도장을 뺀 품의 10%(원문 줄) — 각 직종에 더함 · 해석: 원문 「〃」 · 「수량」 칸 = 앞 직종(플랜트제관공) · 해석: 목공 = 건축목공 · 「건설기계운전조 · Crane운전조」 = 건설기계운전사 · 「윈치운전조」 = 일반기계운전사(조 = 1인) · 건설노임에 없는 직종(기계기사 · 측량사 · 마킹공 등)은 인력_자체(값은 관리자가 채움) · 막힘: 장비 중 기계 목록에 없는 것 — Lathe 365.76㎝×5.60㎾ · Planer 121.92㎝×243.84㎝ · Boring machine Horizontal Type 2.24㎾ · Gouging machine 중형 · Gas cutting machine Auto형 · Gas cutting machine Mannual · Gas heating touch 중형 · Over head crane 30ton · Over head crane 20ton · Hydro Press 300ton · Bending roller 701.04㎝ · Edge bending roller 701.04㎝ · Shearing machine · Drilling machine 2.24㎾ · Drilling machine Radial 3.73㎾ · Portable drill 0.73㎾ — 그 줄 빠짐",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "공작공장",
|
||||
"고르기": [
|
||||
@@ -8709,6 +8769,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "소모자재는 원문 참고표 Roller 칸 · 공정별 품의 합(ton당) · 검사 · 교정은 기술관리, 도장을 뺀 품의 10%(원문 줄) — 각 직종에 더함 · 해석: 원문 「〃」 · 「수량」 칸 = 앞 직종(플랜트제관공) · 해석: 목공 = 건축목공 · 「건설기계운전조 · Crane운전조」 = 건설기계운전사 · 「윈치운전조」 = 일반기계운전사(조 = 1인) · 건설노임에 없는 직종(기계기사 · 측량사 · 마킹공 등)은 인력_자체(값은 관리자가 채움) · 막힘: 장비 중 기계 목록에 없는 것 — Lathe 365.76㎝×5.60㎾ · Planer 121.92㎝×243.84㎝ · Boring machine Horizontal Type 2.24㎾ · Gouging machine 중형 · Gas cutting machine Auto 중형 · Gas cutting machine Mannual · Gas heating touch 중형 · over head crane 30 ton · Hydro Press 100 ton · Bending roller 701.04㎝ · Shearing machine · Drilling machine 2.24㎾ · Drilling machine Radial 3.73㎾ · Portable drill 0.373㎾ — 그 줄 빠짐",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "공작공장",
|
||||
"고르기": [
|
||||
@@ -9901,6 +9971,16 @@
|
||||
"소유": "공용",
|
||||
"비고": "공정별 품의 합(ton당) · 검사 · 교정은 기술관리, 도장, 전원배선을 뺀 품의 10%(원문 줄) — 각 직종에 더함 · 해석: 원문 「〃」 · 「수량」 칸 = 앞 직종(플랜트제관공) · 해석: 목공 = 건축목공 · 「건설기계운전조 · Crane운전조」 = 건설기계운전사 · 「윈치운전조」 = 일반기계운전사(조 = 1인) · 건설노임에 없는 직종(기계기사 · 측량사 · 마킹공 등)은 인력_자체(값은 관리자가 채움) · 막힘: 장비 중 기계 목록에 없는 것 — Gas Cutting machine 중형 · Portable Drill 1.12㎾ · Portable Grinder 0.37㎾ · Guy Derrick 10 ton · Truck 5 ton · Angle Griner 0.37 ㎾ — 그 줄 빠짐",
|
||||
"입력": [
|
||||
{
|
||||
"이름": "전력 계약종별",
|
||||
"고르기": [
|
||||
"주택용 저압",
|
||||
"일반용(갑)Ⅰ 저압",
|
||||
"산업용(갑)Ⅰ 저압"
|
||||
],
|
||||
"출처": "유가전력 한전 전기요금표 2025-01-01",
|
||||
"비고": "품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 임시전력(갑)은 주택용 저압 요금 그대로(요금표 6.가)"
|
||||
},
|
||||
{
|
||||
"이름": "장비일수",
|
||||
"단위": "일",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"비고": [
|
||||
"다산소프트 EST 2026-07 자재 · 개발용 · 배포 전 판권 구매",
|
||||
"값 열 다섯 = 물가지 넷(물가자료 · 유통물가 · 물가정보 · 거래가격) · 관급(조달) — 채택값·기본가 없음 · 쓰는 곳이 값을 고르고 출처를 밝힘",
|
||||
"유류(휘발유 · 경유 · 선박용경유 · 중유 · 등유)는 값이 비고 글뿐이라 뺌 — 유가는 재료_오피넷유가 · 중유는 받지 않음",
|
||||
"유류·전력은 뺌 — 유가·전기요금은 재료_유가전력(유류는 값이 비고 글뿐 · 중유는 받지 않음)",
|
||||
"원문번호(다산소프트 품번) 칸 없음 — 대조는 _키대장.json 에만",
|
||||
"관급 = 원문 「가격정보」 칸의 조달청 관급 단가(철근 · 레미콘 · 아스콘 · H형강 등) · 기간은 비고 「조달 26.7」",
|
||||
"조달청에만 있는 품목 380 줄은 관급 열만 채움 — 출처 「자재품목 조달청 …」 · 원문번호는 _키대장.json 에만",
|
||||
@@ -21,8 +21,6 @@
|
||||
"면수 = 물가지 값의 원문 면수 · 화면에는 접어 둠"
|
||||
],
|
||||
"줄": [
|
||||
{ "키": "MT000006", "구분": null, "상세구분": null, "이름": "전 력", "규격": "", "단위": "KWH", "물가자료": 114.8, "유통물가": null, "물가정보": 114.8, "거래가격": null, "관급": null, "출처": "자재품목 M0005250064", "비고": null, "면수": {"물가자료": "하326(26.7)", "유통물가": null, "물가정보": "부534(26.7)", "거래가격": null} },
|
||||
{ "키": "MT000007", "구분": null, "상세구분": null, "이름": "전 력", "규격": "주택용저압", "단위": "KWH", "물가자료": 120, "유통물가": null, "물가정보": 120, "거래가격": null, "관급": null, "출처": "자재품목 M0005250065", "비고": null, "면수": {"물가자료": "하326(26.7)", "유통물가": null, "물가정보": "부533(26.7)", "거래가격": null} },
|
||||
{ "키": "MT000008", "구분": null, "상세구분": null, "이름": "치 즐(0.2㎥)", "규격": "", "단위": "EA", "물가자료": null, "유통물가": null, "물가정보": 83000, "거래가격": null, "관급": null, "출처": "자재품목 M0005250066", "비고": null, "면수": {"물가자료": null, "유통물가": null, "물가정보": "1032(23.11)", "거래가격": null} },
|
||||
{ "키": "MT000009", "구분": null, "상세구분": null, "이름": "치 즐(0.4㎥)", "규격": "", "단위": "EA", "물가자료": null, "유통물가": null, "물가정보": null, "거래가격": null, "관급": null, "출처": "자재품목 M0005250067", "비고": "가격정보 56,000 · 품셈(2016)", "면수": null },
|
||||
{ "키": "MT000010", "구분": null, "상세구분": null, "이름": "치 즐(0.6㎥)", "규격": "", "단위": "EA", "물가자료": null, "유통물가": null, "물가정보": 220000, "거래가격": null, "관급": null, "출처": "자재품목 M0005250068", "비고": null, "면수": {"물가자료": null, "유통물가": null, "물가정보": "1032(23.11)", "거래가격": null} },
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
{ "키": "MP000355", "원문번호": "페인트붓(표기용)", "이름": "페인트붓(표기용)", "규격": "", "단위": "개", "요구절": ["건설품셈 기계설비 13-11-5"], "연결": null, "비고": "자재품목 후보 1줄 — 지역·규격 선택 필요 (MT008178)" },
|
||||
{ "키": "MP000356", "원문번호": "벤토나이트알갱이", "이름": "벤토나이트알갱이", "규격": "", "단위": "kg", "요구절": ["건설품셈 건축 6-5-3"], "연결": "MT007749", "비고": "연결: 자재품목 한 줄" },
|
||||
{ "키": "MP000357", "원문번호": "카트리지 화약", "이름": "카트리지", "규격": "화약", "단위": "개", "요구절": ["건설품셈 건축 6-5-3"], "연결": "MT007751", "비고": "연결: 자재품목 한 줄" },
|
||||
{ "키": "MP000358", "원문번호": "전력", "이름": "전력", "규격": "", "단위": "㎾h", "요구절": ["건설품셈 기계설비 13-2-4", "건설품셈 기계설비 13-6-3", "건설품셈 기계설비 13-6-6"], "연결": "MT000006", "비고": "연결: 자재품목 한 줄" },
|
||||
{ "키": "MP000358", "원문번호": "전력", "이름": "전력", "규격": "", "단위": "㎾h", "요구절": ["건설품셈 기계설비 13-2-4", "건설품셈 기계설비 13-6-3", "건설품셈 기계설비 13-6-6"], "연결": {"이름": "전력량요금", "계약종별": "입력"}, "비고": "연결: 유가전력 전력 줄 · 계약종별은 로직 입력 「전력 계약종별」 — 품셈·계약예규에 계약종별 규정 없음(전력비는 실비 계상) · 시험 계산은 그 계약종별 전력량요금 가운데 낮은 값" },
|
||||
{ "키": "MP000359", "원문번호": "중유", "이름": "중유", "규격": "", "단위": "ℓ", "요구절": ["건설품셈 기계설비 13-6-9", "건설품셈 기계설비 13-6-11", "건설품셈 기계설비 13-6-17"], "연결": null, "비고": "중유는 받지 않기로 함 — 미연결" },
|
||||
{ "키": "MP000360", "원문번호": "징크프라이머", "이름": "징크프라이머", "규격": "", "단위": "ℓ", "요구절": ["건설품셈 기계설비 13-6-9"], "연결": "MT003383", "비고": "연결: 자재품목 한 줄" },
|
||||
{ "키": "MP000361", "원문번호": "동 및 동합금용 용접봉 BCUP3", "이름": "동 및 동합금용 용접봉", "규격": "BCUP3", "단위": "㎏", "요구절": ["건설품셈 기계설비 1-2-1"], "연결": null, "비고": "자재품목에 같은 품명 없음" },
|
||||
|
||||
@@ -346,10 +346,18 @@ def test_못_이은_줄만_거름(client: TestClient) -> None:
|
||||
|
||||
|
||||
def test_품셈재료_단가는_연결의_낮은_값과_출처(client: TestClient) -> None:
|
||||
key = key_of("GC000893")
|
||||
key = key_of("GC000628")
|
||||
one = _get(client, "/api/m01/logic", key=key)
|
||||
cement = one["prices"][key_of("MP:시멘트")]
|
||||
assert cement["값"] > 0 and cement["출처"].startswith("MT004176" + ".")
|
||||
|
||||
|
||||
def test_전력은_계약종별을_골라야_값이_섬(client: TestClient) -> None:
|
||||
"""후보 조건 「계약종별: 입력」 — 화면에선 값 없음 · 계산 때 로직 입력으로 정해짐."""
|
||||
one = _get(client, "/api/m01/logic", key=key_of("GC000893"))
|
||||
power = one["prices"][key_of("MP:전력")]
|
||||
assert power["값"] > 0 and power["출처"] == "MT000006.물가자료" # 전력
|
||||
assert power["값"] is None and power["출처"] is None
|
||||
assert "전력 계약종별" in {x["이름"] for x in one["logic"]["입력"]}
|
||||
|
||||
|
||||
def test_하위_거름과_참조_이름(client: TestClient) -> None:
|
||||
|
||||
@@ -638,7 +638,7 @@ def test_노임_갈래_파일_원문_대조():
|
||||
"건설사업관리": 4,
|
||||
"SW": 17,
|
||||
"산림": 2,
|
||||
"미확보": 31,
|
||||
"미확보": 28, # 고급기능사·리베팅공·Belt Conveyor 설치공은 적용해 뺌
|
||||
}
|
||||
assert {tuple(r) for r in rows} == {cm.LABOR_COLS}
|
||||
# 「미공표」 는 남지 않음 — 건설·제조 미공표 직종은 모두 「산정」(원 미만 버림)
|
||||
@@ -662,10 +662,19 @@ def test_노임_갈래_파일_원문_대조():
|
||||
|
||||
def test_품셈재료_연결_낮은_값과_출처(whole):
|
||||
"""연결 하나 — 값 열 다섯 가운데 낮은 값 · 출처 = 「<키>.<열>」."""
|
||||
row = whole.get("MT000006") # 전력
|
||||
row = whole.get("MT004176") # 시멘트
|
||||
low = min(row[s] for s in mm.SLOTS if row.get(s) is not None)
|
||||
value, source = mf.element(whole, "MP:전력", {})
|
||||
assert value == low and source.split(".") == [row["키"], "물가자료"]
|
||||
value, source = mf.element(whole, "MP:시멘트", {})
|
||||
assert value == low and source.split(".")[0] == row["키"]
|
||||
|
||||
|
||||
def test_전력은_계약종별로_고름(whole):
|
||||
"""전력은 자재품목이 아니라 유가전력 줄 — 계약종별은 로직 입력 · 그 안에서 낮은 값."""
|
||||
assert whole.index["MT"].get("MT000006") is None # 자재품목 전력 2줄 뺌
|
||||
with pytest.raises(mf.FormulaError): # 계약종별 없이는 값이 안 섬
|
||||
mf.element(whole, "MP:전력", {})
|
||||
value, source = mf.element(whole, "MP:전력", {mf.TARIFF: "주택용 저압"})
|
||||
assert value == 120 and source == "MO000058.값"
|
||||
|
||||
|
||||
def test_자재품목_열_한_벌():
|
||||
@@ -679,14 +688,14 @@ def test_자재품목_열_한_벌():
|
||||
"관급: 조달청 다수공급자계약"
|
||||
)
|
||||
assert all(steel[s] is None for s in ("물가자료", "유통물가", "물가정보", "거래가격"))
|
||||
# 제조사별로 값이 갈려 조달청 값을 못 고른 줄 — 관급은 비고만 남김
|
||||
bare = rows["MT001637"]
|
||||
assert bare["관급"] is None and bare["비고"].startswith("관급: 조달청 값 못 채움")
|
||||
# 제조사별로 값이 갈린 줄 — 같은 규격 가운데 최저가와 그 제조사를 비고에
|
||||
low = rows["MT001637"]
|
||||
assert low["관급"] == Decimal(1228830) and "최저" in low["비고"]
|
||||
left = [r for r in rows.values() if str(r["비고"] or "").startswith("가격정보")]
|
||||
assert len(left) == 67 and all(r["관급"] is None for r in left)
|
||||
# 유류 다섯 줄(값이 비고 글뿐)은 뗌 — 대장에 폐기로 남음
|
||||
book = mk.load_book()
|
||||
fuel = [f"MT{i:06d}" for i in range(1, 6)]
|
||||
fuel = [f"MT{i:06d}" for i in range(1, 8)] # 6·7 = 전력 — 재료_유가전력으로 감
|
||||
assert all(k not in rows and k not in book["키"] and k in book["폐기"] for k in fuel)
|
||||
assert {r["구분"] for r in rows.values()} == {None}
|
||||
assert {r["상세구분"] for r in rows.values()} == {None}
|
||||
|
||||
Reference in New Issue
Block a user