- 원천(서버 단독) = 연결된 사본 → 사본 셈 한 벌(142-1) 수량 ÷ 배 · 같은 원본 + 같은 입력값 = 한 호표(내용 해시) 승격 아닌 로직 = 품셈 호표(노무 · 재료 · 중기 · % 줄) · 승격 · 옛 SP = 산근 참조 · SC = 겹 대가 - 셈 짝(파이썬 · TS) = 줄 ROUNDDOWN 1 · % 줄 = 밑수 × % / 100 · 합계 ROUNDDOWN 0 · 관급 · 별도계상 = 대가 안 0원 · 빈칸 규칙 - 내역서 이음 daega_price(sheets, owner) / daegaPrice · 집계표 이음 = 블록 key · 줄 ref.key - 탭 둘(목록표 · 블록표 · 호표 누름 이동 · 사본 없으면 「연결 없음」) · 길 = GET · PUT 셈에 대가 - 단가 수요(used_keys) = 사본 셈과 같은 길(빈 입력 자동값 · 참조사본 안 로직) — 144 시험 옛 단언 고침 - 새 시험 test_145_2_b09_labor_calc(엑셀 대가 1 · 2 · 9 · 14 검산 · 거울 · 견본 사본 · 빈 표 · 이음 꼴) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
74 lines
3.2 KiB
Python
74 lines
3.2 KiB
Python
"""B09 연결된 사본 → 원가 수요 자원 키(PLAN 144 · 143-1 원천) — 서버 단독 · 읽기만.
|
|
|
|
연결된 사본 = `M02_Item_Snapshot.linked_snapshots`(지정 ∩ 같은 항목 사본 · B08 · B09 공용).
|
|
사본마다 `일위대가.json` 담은 로직을 그 사본 단가 묶음(`단가.json`) · 입력값 · 고른자재로 돌리며
|
|
실제로 부른 자원 줄(인력 LB · 기계 EQ · 자재 MT · 유가 MO)만 모음 — 단가 묶음 통째
|
|
(고르기 후보 전부)는 안 씀 · 값은 쓰지 않음(단가는 원가 한 벌 `price_book.json` 이 맡음).
|
|
구조물 조합 사본 없으면 그 구조물은 없음 · 일위대가 없는 사본은 자원 없음.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from M02_MasterTemplete import M02_Item_Prices as item_prices
|
|
from M02_MasterTemplete import M02_Labor_Doc as labor_doc
|
|
from M02_MasterTemplete.M02_Item_Snapshot import (
|
|
PICKS_FILE,
|
|
VALUES_FILE,
|
|
linked_snapshots,
|
|
structures_dir,
|
|
)
|
|
from M02_MasterTemplete.M02_Item_Source import LABOR_FILE, PRICE_FILE, read_json
|
|
|
|
#: 원가 단가 목록에 오르는 자원 표
|
|
RESOURCE_TABLES = ("LB", "EQ", "MT", "MO")
|
|
|
|
mf = item_prices.mf
|
|
|
|
|
|
def used_keys(folder: Path) -> list[str]:
|
|
"""사본 하나가 담은 로직을 돌릴 때 부른 자원 키 — 부른 차례 · 겹침 없음."""
|
|
labor = read_json(folder / LABOR_FILE)
|
|
if not isinstance(labor, dict):
|
|
return []
|
|
snapshot = item_prices.load_prices(read_json(folder / PRICE_FILE) or {})
|
|
values = read_json(folder / VALUES_FILE) or {}
|
|
picks = read_json(folder / PICKS_FILE) or {}
|
|
seen: list[str] = []
|
|
base_get = snapshot.get
|
|
|
|
def get(ref: str) -> dict[str, Any]:
|
|
row = base_get(ref)
|
|
key = str(row.get("키") or "")
|
|
if key[:2] in RESOURCE_TABLES and key not in seen:
|
|
seen.append(key)
|
|
return row
|
|
|
|
snapshot.get = get # 이 사본 묶음 한 벌에만 — 마스터 캐시는 안 건드림
|
|
# 사본 셈 한 벌(142-1)과 같은 길 — 빈 입력 = 자동값 · 켜쌓기율 · 고름 ·
|
|
# 굳힌 참조사본 안 로직까지
|
|
doc = item_prices.with_values(labor.get("줄") or {}, values, picks)
|
|
inner = [d for d in (labor.get("참조사본") or {}).values() if isinstance(d, dict)]
|
|
for one in [*(doc.get("담은로직") or []), *(x for d in inner for x in d.get("담은로직") or [])]:
|
|
# 못 돈 로직 — 부른 데까지만(까닭은 안 봄)
|
|
if isinstance(one, dict) and one.get("로직"):
|
|
labor_doc.run_line(
|
|
snapshot, one["로직"], one.get("입력값"), one.get("켜쌓기율"), one.get("고름")
|
|
)
|
|
return seen
|
|
|
|
|
|
def linked_resource_keys(project_root: str | Path) -> list[str]:
|
|
"""연결된 사본 전부가 부른 자원 키 — 구조물 id 차례 · 겹침 없음."""
|
|
base = structures_dir(project_root)
|
|
out: list[str] = []
|
|
for _owner, linked in sorted(linked_snapshots(project_root).items()):
|
|
if "일위대가" not in linked.get("부분", []):
|
|
continue
|
|
for key in used_keys(base / linked["폴더"]):
|
|
if key not in out:
|
|
out.append(key)
|
|
return out
|