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:
@@ -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 ""
|
||||
|
||||
Reference in New Issue
Block a user