feat(master_data): 키 개편 — 테이블ID+6자리 키 · 인력·기계 한 테이블 · 장 파일 이름
- 모든 요소·표·로직 줄의 열쇠 → 키(LB000123 꼴) · 옛 열쇠·원문 번호는 원문번호 칸 · 대장 _키대장.json (키 36,840 · 다음 번호)
- 변수 적는 법 키로 — 로직 식·연결·준용·통합·후보·조달 연결 일괄 변환 · {이름} 낀 참조는 ID:원문번호
- 인력 8 파일 → 인력.json(줄마다 조사 · 머리 조사 묶음) · 기계 2 파일 → 기계.json(세부분류)
- 소요량·계수·로직 파일 이름 = 그룹_원문_NN장_장 제목 · 머리 부문·차례
- 엔진(값 찾기 · 알림에 키 옆 이름) · check_master(키 모양·겹침·대장·끊긴 키 · 기계 요소 줄도 본문 결손 대조) · M01 서버(새 줄 키는 대장 다음 번호 · 키 못 고침) · 화면 칸 이름만 맞춤
- 로직 일괄 시험 계산 1,351 줄 — 옮기기 전후 줄마다 결과·금액 같음
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -10,7 +10,7 @@ import re
|
||||
import unicodedata
|
||||
from decimal import Decimal
|
||||
|
||||
LINKED = "재료:품셈재료:"
|
||||
LINKED = "MP" # 품셈재료 테이블ID
|
||||
MARKET = ("가격정보", "물가자료", "유통물가", "물가정보", "거래가격")
|
||||
REGION = "자재지역" # 로직 입력 — 「지역」 은 유가 고르기가 씀
|
||||
_UNITS = {"ea": "개", "ton": "톤", "t": "톤", "l": "ℓ", "리터": "ℓ", "set": "조", "세트": "조"}
|
||||
@@ -33,27 +33,27 @@ def plain_unit(s) -> str:
|
||||
|
||||
def _offers(master: mf.Master, key: str) -> list[tuple[Decimal, str]]:
|
||||
"""시중물가 줄 하나의 (값, 출처) — 시중 다섯 칸 · 조달(나라장터 연결은 그 줄 값)."""
|
||||
value = master.get(f"재료:시중물가:{key}")["값"]
|
||||
value = master.get(key)["값"]
|
||||
out = [
|
||||
(value["시중"][slot], f"재료:시중물가:{key}.시중.{slot}")
|
||||
(value["시중"][slot], f"{key}.시중.{slot}")
|
||||
for slot in MARKET
|
||||
if value["시중"].get(slot) is not None
|
||||
]
|
||||
supply = value["조달"]
|
||||
if supply.get("값") is not None:
|
||||
out.append((supply["값"], f"재료:시중물가:{key}.조달"))
|
||||
out.append((supply["값"], f"{key}.조달"))
|
||||
elif str(supply.get("출처") or "").startswith("나라장터:"):
|
||||
ref = "재료:나라장터자재:" + supply["출처"].split(":", 1)[1]
|
||||
ref = supply["출처"].split(":", 1)[1]
|
||||
if master.get(ref).get("값") is not None:
|
||||
out.append((master.get(ref)["값"], ref))
|
||||
return out
|
||||
|
||||
|
||||
def _market_index(master: mf.Master) -> list[tuple[str, str, str, str, str]]:
|
||||
"""(품명 뿌리, 이름, 규격, 단위, 열쇠) — 「레미콘(관급)-경상북도(울진군)」 뿌리 = 레미콘."""
|
||||
"""(품명 뿌리, 이름, 규격, 단위, 키) — 「레미콘(관급)-경상북도(울진군)」 뿌리 = 레미콘."""
|
||||
if not hasattr(master, "_market"):
|
||||
master._market = []
|
||||
for key, row in master.index.get(("재료", "시중물가"), {}).items():
|
||||
for key, row in master.index.get("MT", {}).items():
|
||||
name = plain(row.get("이름"))
|
||||
root = re.sub(r"\(.*?\)", "", name.split(",")[0]).split("-")[0]
|
||||
master._market.append(
|
||||
@@ -66,7 +66,7 @@ def _candidates(master: mf.Master, ref: str, row: dict, env: dict) -> list[str]:
|
||||
"""후보 조건{이름 · 규격 · 지역: 입력} — 뿌리가 이름으로 끝나고 이름에 지역 글자 · 단위 같음."""
|
||||
cond = row["연결"]
|
||||
if cond.get("지역") == "입력" and REGION not in env:
|
||||
raise mf.FormulaError(f"「{ref}」 입력 「{REGION}」 없음")
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 입력 「{REGION}」 없음")
|
||||
region = plain(env.get(REGION, "")) if cond.get("지역") == "입력" else ""
|
||||
want, spec, unit = plain(cond["이름"]), plain_spec(cond.get("규격")), plain_unit(row["단위"])
|
||||
hits = [
|
||||
@@ -76,16 +76,16 @@ def _candidates(master: mf.Master, ref: str, row: dict, env: dict) -> list[str]:
|
||||
]
|
||||
hits = [(s, key) for s, key in hits if _offers(master, key)]
|
||||
if not hits:
|
||||
raise mf.FormulaError(f"「{ref}」 지역 값 없음 — {env.get(REGION)}")
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 지역 값 없음 — {env.get(REGION)}")
|
||||
if len({s for s, _ in hits}) > 1:
|
||||
raise mf.FormulaError(f"「{ref}」 후보 여럿 — 규격 선택 필요 ({len(hits)}줄)")
|
||||
raise mf.FormulaError(f"「{master.label(ref)}」 후보 여럿 — 규격 선택 필요 ({len(hits)}줄)")
|
||||
return [key for _, key in hits]
|
||||
|
||||
|
||||
def element(master: mf.Master, ref: str, env: dict) -> tuple[object, str | None]:
|
||||
"""요소 값과 출처 — 품셈재료는 연결을 따라가 낮은 값 · 그 밖은 줄의 `값` 그대로(출처 None)."""
|
||||
row = master.get(ref)
|
||||
if not ref.startswith(LINKED):
|
||||
if ref[:2] != LINKED:
|
||||
return master.value(ref)
|
||||
link = row.get("연결")
|
||||
if not link:
|
||||
|
||||
Reference in New Issue
Block a user