feat(master_data): 키 개편 뒤따름 — _틀.md 새 규칙 · 빌더 잇기(adopt) · ESTX 비교 · 화면 계약
- _틀.md: 파일 이름(인력.json · 기계.json · NN장_장 제목) · 머리 부문·차례 · 키·테이블ID·대장 · 변수(키 · ID:원문번호 · 찾기(QF…) · 로직(GC…)) - master_keys: old_view(옛 이름으로 읽기) · adopt(빌더 옛 모양 → 키·한 테이블·장 이름 · 부문 앞말 · 참조 변환) · order_chapters(차례) - 빌더 7개 끝에서 adopt · 노임·시중물가 빌더 다시 돌려 결과 같음(시중물가 머리 비고 글 한 줄만 「키」) · 기계·기계설비 7장은 사본 폴더에서 같음 - compare_estx: 인력.json 조사 · 기계.json 세부분류 · 로직 GC:원문번호 · 네 갈래 모두 돌아감 - _화면_계약.md: key = 키 · 새 줄 키는 서버가 대장 다음 번호 · 키 못 고침 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -122,9 +122,10 @@ def labor(estx: Estx, files: dict):
|
||||
heads = [r["Name"] for r in rows if r.get("Name") and not r.get("Unite")]
|
||||
print("## 노임 — ESTX 머리줄", heads)
|
||||
ours = {}
|
||||
for fname, tag in (("인력_건설노임.json", "건설"), ("인력_제조노임.json", "제조")):
|
||||
for r in files[fname]["줄"]:
|
||||
ours.setdefault((tag, norm(r["이름"])), r)
|
||||
for survey, tag in (("건설업", "건설"), ("제조업", "제조")):
|
||||
for r in files["인력.json"]["줄"]:
|
||||
if r["조사"] == survey:
|
||||
ours.setdefault((tag, norm(r["이름"])), r)
|
||||
theirs = {}
|
||||
for r in rows:
|
||||
if r.get("Unite") != "인":
|
||||
@@ -230,7 +231,7 @@ def material(estx: Estx, files: dict):
|
||||
for r in files["재료_품셈재료.json"]["줄"]:
|
||||
if r.get("연결"):
|
||||
continue
|
||||
mine = {base_name(r["이름"]), base_name(r["열쇠"])}
|
||||
mine = {base_name(r["이름"]), base_name(r["원문번호"])}
|
||||
hits = [e for m in mine for e in by_name.get(m, [])]
|
||||
if hits:
|
||||
have.append((r, hits))
|
||||
@@ -243,15 +244,15 @@ def material(estx: Estx, files: dict):
|
||||
f"### 재료_품셈재료 못 이음 {len(have) + len(near) + len(none)} — ESTX 품명 같음 {len(have)} · 품명 끝 같음 {len(near)} · 없음 {len(none)}"
|
||||
)
|
||||
for r, hits in near:
|
||||
print(f" 비슷 {r['열쇠']} | {sorted({e['Name'] for e in hits})[:4]}")
|
||||
print(f" 비슷 {r['원문번호']} | {sorted({e['Name'] for e in hits})[:4]}")
|
||||
for r, hits in have:
|
||||
s = bare_spec(r["이름"], r.get("규격"))
|
||||
same = [e for e in hits if s and spec_match(s, bare_spec(e["Name"], e.get("Size")))]
|
||||
h = (same or hits)[0]
|
||||
print(
|
||||
f" 있음 {r['열쇠']} [{r.get('단위')}] | ESTX {len(hits)}줄 규격같음 {len(same)} | 예 {h['Name']} {h.get('Size')} {h.get('Unite')} {h['TC']:.0f}"
|
||||
f" 있음 {r['원문번호']} [{r.get('단위')}] | ESTX {len(hits)}줄 규격같음 {len(same)} | 예 {h['Name']} {h.get('Size')} {h.get('Unite')} {h['TC']:.0f}"
|
||||
)
|
||||
print(" 없음", [r["열쇠"] for r, _ in none])
|
||||
print(" 없음", [r["원문번호"] for r, _ in none])
|
||||
|
||||
|
||||
# ── (3) 기계경비 ──────────────────────────────────────────────────────
|
||||
@@ -284,7 +285,7 @@ def mach_key(name, size) -> str:
|
||||
def machine_cost(master: mf.Master, mid: str, region="전국평균"):
|
||||
"""로직으로 계산 — 고르기 밖 기계는 메모리에서만 고르기에 더함."""
|
||||
for key in LOGICS:
|
||||
row = master.logic("건설품셈:" + key)
|
||||
row = master.logic("GC:" + key)
|
||||
spec = next(i for i in row["입력"] if i["이름"] == "기계")
|
||||
added = mid not in spec["고르기"]
|
||||
if added:
|
||||
@@ -292,7 +293,7 @@ def machine_cost(master: mf.Master, mid: str, region="전국평균"):
|
||||
try:
|
||||
given = {"기계": mid, "지역": region}
|
||||
given = {k: v for k, v in given.items() if any(i["이름"] == k for i in row["입력"])}
|
||||
return key, mf.run(master, "건설품셈:" + key, given)
|
||||
return key, mf.run(master, "GC:" + key, given)
|
||||
except (mf.FormulaError, ArithmeticError, KeyError, TypeError):
|
||||
continue
|
||||
finally:
|
||||
@@ -306,17 +307,17 @@ def machine(estx: Estx, files: dict, master: mf.Master):
|
||||
for r in estx.table("MachTitleDat"):
|
||||
if r.get("Unite") == "hr" and r.get("TC"):
|
||||
est.setdefault(mach_key(r.get("Name"), r.get("Size")), r)
|
||||
ours = files["기계_건설품셈.json"]["줄"]
|
||||
ours = [m for m in files["기계.json"]["줄"] if m["세부분류"] == "건설품셈"]
|
||||
pairs = [(m, est[k]) for m in ours if (k := mach_key(m["이름"], m["규격"])) in est]
|
||||
print(f"## 기계 — 우리 {len(ours)} · ESTX 시간당 {len(est)} · 기종·규격 짝 {len(pairs)}")
|
||||
out = []
|
||||
for m, e in pairs:
|
||||
key, res = machine_cost(master, m["열쇠"])
|
||||
key, res = machine_cost(master, m["원문번호"])
|
||||
if not res:
|
||||
continue
|
||||
out.append((m, e, key, res))
|
||||
print(f" 로직 계산됨 {len(out)}")
|
||||
first = [x for x in out if x[0]["열쇠"].startswith(FIRST)]
|
||||
first = [x for x in out if x[0]["원문번호"].startswith(FIRST)]
|
||||
for label, group in (("임도 기계", first), ("전체", out)):
|
||||
print(f"### {label}")
|
||||
print(" 계:", spread([rate(e["TC"], res["계"]) for m, e, k, res in group]))
|
||||
@@ -340,18 +341,18 @@ def machine(estx: Estx, files: dict, master: mf.Master):
|
||||
e.get("GC") and abs(rate(e["GC"], res["재료비"])) > 5
|
||||
):
|
||||
print(
|
||||
f" {m['열쇠']} {m['이름']} {m['규격']} {k} | ESTX 재 {e.get('GC', 0):.0f} 경 {e['JC']:.0f} | 우리 재 {res['재료비']:.0f} 경 {res['경비']:.0f}"
|
||||
f" {m['원문번호']} {m['이름']} {m['규격']} {k} | ESTX 재 {e.get('GC', 0):.0f} 경 {e['JC']:.0f} | 우리 재 {res['재료비']:.0f} 경 {res['경비']:.0f}"
|
||||
)
|
||||
for m, e, k, res in first:
|
||||
print(
|
||||
f" {m['열쇠']} {m['이름']} {m['규격']} | ESTX {e['TC']:.0f} (노 {e.get('NC', 0):.0f} 재 {e.get('GC', 0):.0f} 경 {e.get('JC', 0):.0f})"
|
||||
f" {m['원문번호']} {m['이름']} {m['규격']} | ESTX {e['TC']:.0f} (노 {e.get('NC', 0):.0f} 재 {e.get('GC', 0):.0f} 경 {e.get('JC', 0):.0f})"
|
||||
f" | 우리 {res['계']:.0f} (노 {res['노무비']:.0f} 재 {res['재료비']:.0f} 경 {res['경비']:.0f}) {rate(e['TC'], res['계']):+.1f}%"
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
# ── (4) 일위대가 ──────────────────────────────────────────────────────
|
||||
# (ESTX 제목 코드, 로직 열쇠, 입력[, 단위 환산 배수 — 우리 값 × 배수 = ESTX 단위])
|
||||
# (ESTX 제목 코드, 로직 원문번호, 입력[, 단위 환산 배수 — 우리 값 × 배수 = ESTX 단위])
|
||||
REGION = {"지역": "전국평균", "보정작업": "해당 없음"}
|
||||
PAIRS = [
|
||||
(
|
||||
@@ -456,14 +457,15 @@ def with_estx_materials(master: mf.Master, estx: Estx, code: str):
|
||||
"""ESTX 일위대가의 자재 단가를 품명으로 우리 빈 재료(값 없음)에만 임시로 넣은 사본 — 파일에 안 씀."""
|
||||
temp = copy.copy(master)
|
||||
temp.index = {k: dict(v) for k, v in master.index.items()}
|
||||
temp.numbers = {k: dict(v) for k, v in master.numbers.items()}
|
||||
items = [
|
||||
d
|
||||
for d in estx.details("HeadMainDat").get(code, [])
|
||||
if str(d.get("Code", "")).startswith("M")
|
||||
]
|
||||
put = []
|
||||
for book in (("재료", "자체"), ("재료", "나라장터자재")):
|
||||
rows = temp.index.get(book, {})
|
||||
for tid in ("MN",):
|
||||
rows = temp.index.get(tid, {})
|
||||
for key, row in list(rows.items()):
|
||||
if row.get("값") is not None:
|
||||
continue
|
||||
@@ -472,6 +474,7 @@ def with_estx_materials(master: mf.Master, estx: Estx, code: str):
|
||||
)
|
||||
if hit:
|
||||
rows[key] = {**row, "값": Decimal(str(hit["TU"]))}
|
||||
temp.numbers[tid][str(row["원문번호"])] = rows[key]
|
||||
put.append(f"{key}={hit['TU']:.0f}")
|
||||
return temp, put
|
||||
|
||||
@@ -484,11 +487,11 @@ def unit_price(estx: Estx, master: mf.Master):
|
||||
h = heads[code]
|
||||
k = Decimal(scale[0]) if scale else Decimal(1)
|
||||
temp, put = with_estx_materials(master, estx, code)
|
||||
row = temp.logic("건설품셈:" + key)
|
||||
row = temp.logic("GC:" + key)
|
||||
given = {k: v for k, v in given.items() if any(i["이름"] == k for i in row.get("입력", []))}
|
||||
given = {k: Decimal(str(v)) if isinstance(v, (int, float)) else v for k, v in given.items()}
|
||||
try:
|
||||
res = mf.run(temp, "건설품셈:" + key, given)
|
||||
res = mf.run(temp, "GC:" + key, given)
|
||||
res = {c: res[c] * k for c in ("계", *mf.COST_ITEMS)}
|
||||
except (mf.FormulaError, ArithmeticError, KeyError, TypeError) as e:
|
||||
print(f" {code} {h['Name']} {h.get('Size')} | {key} | 멈춤: {str(e)[:120]}")
|
||||
|
||||
Reference in New Issue
Block a user