fix(paths): 옛 자료 폴더 이동 뒤 서버 불러오기 복구 - 경로 상수만 old/ref 새 자리로
B05·B06·B08·B09·Z01·common_util 의 data_* 폴더·파일 이름 상수를 master_data/old · ref 의 새 이름으로 돌림. 로직은 그대로. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
@@ -24,8 +24,8 @@ from typing import Any
|
||||
from B09_Estimation.B09_Estimation_PriceBook import PriceKind
|
||||
from B09_Estimation.B09_Estimation_ResourceAxis_UnitBasis import similar_occupation_note
|
||||
|
||||
_MANIFEST = ("resources", "data_cost_input_value", "_manifest.json")
|
||||
_MASTER_DIR = ("resources", "data_work_item_master")
|
||||
_MANIFEST = ("resources", "master_data", "old", "_manifest.json")
|
||||
_MASTER_DIR = ("resources", "master_data", "old")
|
||||
|
||||
SHEET_NOTE = (
|
||||
"산출기초는 새로 세는 장이 아니라 **줄에 달린 근거를 한 장으로 모은 것**입니다 —"
|
||||
|
||||
@@ -131,6 +131,6 @@ class CostInput:
|
||||
enabled_items: tuple[str, ...] | str = DEFAULT_ITEMS
|
||||
|
||||
#: 요율 데이터 파일명. **연도를 갈아끼우는 자리.**
|
||||
rate_file_name: str = "rates_2026.json"
|
||||
rate_file_name: str = "1_기초_제비율_토목_조달청_2026-04-13.json"
|
||||
#: 매니페스트 밖 요율 파일(옛 연도 재현 검산 전용). 주면 이쪽이 우선.
|
||||
rate_file_path: str | None = None
|
||||
|
||||
@@ -32,7 +32,7 @@ from decimal import Decimal
|
||||
from functools import lru_cache
|
||||
from typing import Any
|
||||
|
||||
_DATASET = ("resources", "data_cost_input_value", "coef_2026.json")
|
||||
_DATASET = ("resources", "master_data", "old", "3_품셈_산림_계수_2026-01-01.json")
|
||||
_FOREST_SPEC = (
|
||||
"resources",
|
||||
"knowledge",
|
||||
|
||||
@@ -34,7 +34,7 @@ from B09_Estimation.B09_Estimation_Guards import (
|
||||
)
|
||||
from B09_Estimation.B09_Estimation_PriceBook import Money3
|
||||
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
_THOUSAND = Decimal(1000)
|
||||
|
||||
|
||||
@@ -224,7 +224,9 @@ class MachineCatalog:
|
||||
raise MachineCostError(f"기종 카탈로그에 없는 코드입니다: {machine_code}") from exc
|
||||
|
||||
|
||||
def load_machine_catalog(file_name: str = "mach_base_2026.json") -> MachineCatalog:
|
||||
def load_machine_catalog(
|
||||
file_name: str = "3_품셈_건설_기계경비기준_8장_2026-01-01.json",
|
||||
) -> MachineCatalog:
|
||||
"""취득가 613건에 손료계수 387건을 붙여 카탈로그 한 벌을 만든다."""
|
||||
variables = _read_json(file_name)["variables"]
|
||||
coefficients = {
|
||||
|
||||
@@ -33,7 +33,7 @@ from B09_Estimation.B09_Estimation_PriceBook import PriceKind
|
||||
#: 조합 사용(굴착기+부착장비)일 때의 본체 잡재료비율 — 품셈 제8장 [주]⑤.
|
||||
COMBINED_MISC_PERCENT = 16
|
||||
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
_THOUSAND = Decimal(1000)
|
||||
_ZERO = Decimal(0)
|
||||
|
||||
@@ -66,7 +66,9 @@ def _project_root() -> str:
|
||||
@lru_cache(maxsize=1)
|
||||
def _loss_records() -> dict[str, dict[str, Any]]:
|
||||
"""기종코드 → 손료계수 원문 줄(상각·정비·관리 계수까지)."""
|
||||
path = os.path.join(_project_root(), *_CATALOG_SUBPATH, "mach_base_2026.json")
|
||||
path = os.path.join(
|
||||
_project_root(), *_CATALOG_SUBPATH, "3_품셈_건설_기계경비기준_8장_2026-01-01.json"
|
||||
)
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
payload = json.load(handle)
|
||||
records = payload["variables"]["mach_loss_coef"]["records"]
|
||||
|
||||
@@ -27,8 +27,8 @@ from dataclasses import dataclass, field
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_OUTPUT_SUBPATH = ("resources", "data_cost_machine_operating")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
_OUTPUT_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
#: 품셈 8-4 운전경비 표의 머리글 — 이 여섯이 다 있어야 그 표로 본다.
|
||||
_REQUIRED_HEADERS = ("분류번호", "기계명", "규격", "주연료", "잡재료", "조종원")
|
||||
@@ -359,8 +359,8 @@ def enrich_with_catalog(
|
||||
|
||||
|
||||
def load_operating_records(
|
||||
pum_file: str = "pum_const_2026.json",
|
||||
labor_file: str = "labor_const_2026-01-01.json",
|
||||
pum_file: str = "3_품셈_건설_표전체_2026-01-01.json",
|
||||
labor_file: str = "1_기초_노임_건설업_대한건설협회_2026-01-01.json",
|
||||
) -> OperatingParseResult:
|
||||
from B09_Estimation.B09_Estimation_MachineCost import load_machine_catalog
|
||||
|
||||
@@ -394,7 +394,7 @@ def write_operating_records(
|
||||
"""파생 파일로 낸다. **어느 기준자료 판에서 파생됐는지**를 함께 적는다."""
|
||||
directory = output_dir or os.path.join(_project_root(), *_OUTPUT_SUBPATH)
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
path = os.path.join(directory, "machine_operating_2026.json")
|
||||
path = os.path.join(directory, "3_품셈_건설_기계운전경비_8-4_2026-01-01.json")
|
||||
|
||||
payload = {
|
||||
"schema_version": "1.0",
|
||||
@@ -419,7 +419,7 @@ def write_operating_records(
|
||||
|
||||
#: 시도별 유가 판 — 품셈 8-1-7 5호 「유류가격은 **해당지역의 가격**으로 한다」.
|
||||
#: ⚠ **파일이 있을 때만 지역을 고를 수 있다** — 없으면 전국평균 한 벌로 돈다(코드로 막지 않음).
|
||||
REGIONAL_OIL_FILE = "oil_regional_2026-09-09.json"
|
||||
REGIONAL_OIL_FILE = "1_기초_유가_시도별_오피넷_2026-09-09.json"
|
||||
#: 운전경비표 연료 종류 → 유가 판 변수. ⚠ 종류를 안 읽고 경유로 때우면 휘발유 기계가 싸게 섬
|
||||
#: (2026-09-14 661 뒤 ② — 플레이트 콤팩터·진동기·믹서·래머·커터가 경유값이었음).
|
||||
FUEL_VARIABLES = {"경유": "oil_diesel", "휘발유": "oil_gasoline"}
|
||||
@@ -455,7 +455,9 @@ def load_regional_fuel_table(
|
||||
|
||||
|
||||
def load_fuel_price(
|
||||
oil_file: str = "oil_2026-08-14.json", region: str | None = None, kind: str = "경유"
|
||||
oil_file: str = "1_기초_유가_전국평균_오피넷_2026-08-14.json",
|
||||
region: str | None = None,
|
||||
kind: str = "경유",
|
||||
) -> tuple[Decimal, dict[str, str]]:
|
||||
"""경유 단가와 그 판의 신원. `region`(시도코드)을 주면 **그 지역 값**으로 선다.
|
||||
|
||||
@@ -490,7 +492,9 @@ def load_fuel_price(
|
||||
}
|
||||
|
||||
|
||||
def load_operator_wages(labor_file: str = "labor_const_2026-01-01.json") -> dict[str, Decimal]:
|
||||
def load_operator_wages(
|
||||
labor_file: str = "1_기초_노임_건설업_대한건설협회_2026-01-01.json",
|
||||
) -> dict[str, Decimal]:
|
||||
"""직종코드 → 일당."""
|
||||
records = _read_json(*_CATALOG_SUBPATH, labor_file)["variables"]["labor_rate"]["records"]
|
||||
return {
|
||||
@@ -513,7 +517,9 @@ LABOR_RELIABILITY_LABEL = {
|
||||
}
|
||||
|
||||
|
||||
def load_labor_reliability(labor_file: str = "labor_const_2026-01-01.json") -> dict[str, str]:
|
||||
def load_labor_reliability(
|
||||
labor_file: str = "1_기초_노임_건설업_대한건설협회_2026-01-01.json",
|
||||
) -> dict[str, str]:
|
||||
"""직종코드 → 신뢰도 기호(`*`·`**`). 정상 공표 직종은 아예 안 담는다."""
|
||||
records = _read_json(*_CATALOG_SUBPATH, labor_file)["variables"]["labor_rate"]["records"]
|
||||
return {
|
||||
|
||||
@@ -17,8 +17,8 @@ from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATA_DIR = Path(__file__).resolve().parent.parent / "resources" / "data_machine_productivity"
|
||||
PREFIX = "machine_productivity_"
|
||||
DATA_DIR = Path(__file__).resolve().parent.parent / "resources" / "master_data" / "old"
|
||||
PREFIX = "3_품셈_산림건설_기계작업량_"
|
||||
|
||||
|
||||
class MachineProductivityDataError(FileNotFoundError):
|
||||
|
||||
@@ -27,7 +27,7 @@ from dataclasses import dataclass, field
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
#: 두 창이 맞춘 구분 이름 — 값을 바꾸면 B08 자재총괄과 안 맞는다.
|
||||
SUPPLY_OWNER = "owner_supplied"
|
||||
@@ -108,7 +108,7 @@ class MaterialCatalog:
|
||||
|
||||
|
||||
def load_material_catalog(
|
||||
public_file: str = "mat_price_public_2026-08-14.json",
|
||||
public_file: str = "1_기초_자재_시설공통_나라장터_2026-08-14.json",
|
||||
) -> MaterialCatalog:
|
||||
"""관급 자재를 읽고, 사급은 **없다는 사실을 목록으로** 남긴다."""
|
||||
payload = _read_json(public_file)
|
||||
|
||||
@@ -119,7 +119,7 @@ def material_catalog_rows() -> dict[str, dict[str, str]]:
|
||||
from B09_Estimation.B09_Estimation_ResourceAxis_Join import EXT_CATALOG_FILE
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
path = os.path.join(root, "resources", "data_resource_catalog", EXT_CATALOG_FILE)
|
||||
path = os.path.join(root, "resources", "master_data", "old", EXT_CATALOG_FILE)
|
||||
if not os.path.isfile(path):
|
||||
return {}
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
|
||||
@@ -27,7 +27,7 @@ _UNIT_MULTIPLIER: dict[str, int] = {
|
||||
"billion": 1_000_000_000,
|
||||
}
|
||||
|
||||
_RESOURCE_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_RESOURCE_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
# 라벨 문법 — 숫자 구간만 해석한다. 그 밖(`turnkey_or_alternative` 등)은 명시 선택자로 고른다.
|
||||
_RE_LT = re.compile(r"^lt_(\d+(?:\.\d+)?)_(million|billion)$")
|
||||
@@ -89,7 +89,7 @@ def _manifest_entry(file_name: str) -> dict[str, Any]:
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def load_rate_dataset(file_name: str = "rates_2026.json") -> RateDataset:
|
||||
def load_rate_dataset(file_name: str = "1_기초_제비율_토목_조달청_2026-04-13.json") -> RateDataset:
|
||||
"""요율 파일 한 벌을 읽는다. 매니페스트의 지문·적용일을 함께 실어 재현성을 남긴다."""
|
||||
entry = _manifest_entry(file_name)
|
||||
with open(os.path.join(_dataset_dir(), file_name), encoding="utf-8") as handle:
|
||||
|
||||
@@ -44,8 +44,8 @@ NON_WORK_ITEM_FORMS = frozenset({"coefficient", "reference"})
|
||||
#: 형태 판정이 안 된 표 — 값을 쓰지 않는다.
|
||||
UNUSABLE_FORMS = frozenset({"undetermined"})
|
||||
|
||||
_MASTER_SUBPATH = ("resources", "data_work_item_master")
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_MASTER_SUBPATH = ("resources", "master_data", "old")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
#: 규격이 이름 안에 붙어 있는 흔한 모양 — 「굴착기(0.7㎥)」·「덤프트럭 15톤」.
|
||||
_RE_SPEC = re.compile(r"[((]([^))]+)[))]|(\d+(?:\.\d+)?\s*(?:톤|ton|㎥|m3|㎡|㎜|mm|HP|kW))")
|
||||
|
||||
@@ -22,7 +22,7 @@ from B09_Estimation.B09_Estimation_ResourceAxis import (
|
||||
|
||||
#: 자원 축 산출물이 나가는 자리 — **메인의 `data_work_item_master/` 안에 넣지 않는다.**
|
||||
#: 메인이 품셈을 다시 돌리면 그 폴더가 덮이므로 섞으면 사라진다.
|
||||
OUTPUT_SUBPATH = ("resources", "data_cost_resource_axis")
|
||||
OUTPUT_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
|
||||
def _master_file_fingerprint(master: dict[str, Any]) -> dict[str, str]:
|
||||
|
||||
@@ -36,8 +36,8 @@ from B09_Estimation.B09_Estimation_ResourceAxis_Sources import (
|
||||
)
|
||||
from common_util.common_util_aliases import AliasError, in_scope, load_aliases, parse_aliases
|
||||
|
||||
_EXT_SUBPATH = ("resources", "data_resource_catalog")
|
||||
EXT_CATALOG_FILE = "resource_catalog_ext_2026-01-01.json"
|
||||
_EXT_SUBPATH = ("resources", "master_data", "old")
|
||||
EXT_CATALOG_FILE = "3_품셈_산림_자원목록보충_2026-01-01.json"
|
||||
|
||||
#: 명세 §2 ③ — `AR-<M|L|X>-<8자리 소문자 16진>`. 종류 글자는 PriceKind 글자 그대로.
|
||||
_RE_AR_CODE = re.compile(r"^AR-([MLX])-[0-9a-f]{8}$")
|
||||
|
||||
@@ -29,11 +29,13 @@ from B09_Estimation.B09_Estimation_ResourceAxis import (
|
||||
_RE_ALTERNATIVE,
|
||||
)
|
||||
|
||||
_CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_MASTER_SUBPATH = ("resources", "data_work_item_master")
|
||||
_CATALOG_SUBPATH = ("resources", "master_data", "old")
|
||||
_MASTER_SUBPATH = ("resources", "master_data", "old")
|
||||
|
||||
|
||||
def load_labor_catalog(file_name: str = "labor_const_2026-01-01.json") -> ResourceCatalog:
|
||||
def load_labor_catalog(
|
||||
file_name: str = "1_기초_노임_건설업_대한건설협회_2026-01-01.json",
|
||||
) -> ResourceCatalog:
|
||||
"""노임 카탈로그 132직종 + `aliases`. 코드는 `occupation_code`."""
|
||||
payload = _read_json(*_CATALOG_SUBPATH, file_name)
|
||||
variables = payload["variables"]
|
||||
@@ -45,7 +47,9 @@ def load_labor_catalog(file_name: str = "labor_const_2026-01-01.json") -> Resour
|
||||
return ResourceCatalog(entries=entries, aliases=dict(variables.get("aliases", {})))
|
||||
|
||||
|
||||
def load_machine_catalog_entries(file_name: str = "mach_base_2026.json") -> list[CatalogEntry]:
|
||||
def load_machine_catalog_entries(
|
||||
file_name: str = "3_품셈_건설_기계경비기준_8장_2026-01-01.json",
|
||||
) -> list[CatalogEntry]:
|
||||
"""기종 카탈로그 613건을 매칭용 항목으로 편다.
|
||||
|
||||
⚠ **규격이 매칭의 일부**다 — 「굴착기(무한궤도)」만 23 규격이라 이름만으로는
|
||||
@@ -61,7 +65,7 @@ def load_machine_catalog_entries(file_name: str = "mach_base_2026.json") -> list
|
||||
|
||||
|
||||
def load_material_catalog_entries(
|
||||
file_name: str = "mat_price_public_2026-08-14.json",
|
||||
file_name: str = "1_기초_자재_시설공통_나라장터_2026-08-14.json",
|
||||
) -> list[CatalogEntry]:
|
||||
"""관급 자재 6,999건을 매칭용 항목으로 편다.
|
||||
|
||||
@@ -102,7 +106,7 @@ def load_combined_catalog() -> ResourceCatalog:
|
||||
|
||||
|
||||
def load_work_item_master(
|
||||
file_name: str = "work_item_master_2026-01-01.json",
|
||||
file_name: str = "2_공종_산림_마스터_2026-01-01.json",
|
||||
) -> dict[str, Any]:
|
||||
"""메인 창 산출물 — **읽기 전용**."""
|
||||
return _read_json(*_MASTER_SUBPATH, file_name)
|
||||
|
||||
@@ -38,7 +38,7 @@ def _sources() -> tuple[dict[str, dict[str, Any]], dict[str, int]]:
|
||||
"""(기계 코드 → 손료 성분 레코드, 규칙 이름 → 암석 가산 %)."""
|
||||
from B09_Estimation.B09_Estimation_MachineCost import _read_json
|
||||
|
||||
variables = _read_json("mach_base_2026.json")["variables"]
|
||||
variables = _read_json("3_품셈_건설_기계경비기준_8장_2026-01-01.json")["variables"]
|
||||
records = {r["machine_code"]: r for r in variables["mach_loss_coef"]["records"]}
|
||||
rules = {r["machine_group"]: int(r["rock_work"]) for r in variables["mach_rock_adj"]["rules"]}
|
||||
return records, rules
|
||||
|
||||
@@ -92,7 +92,7 @@ class CostRequest(BaseModel):
|
||||
equipment_guarantee_work_type: str = "civil_general"
|
||||
subcontract_guarantee_variant: str = "integrated_civil_or_industrial"
|
||||
|
||||
rate_file_name: str = "rates_2026.json"
|
||||
rate_file_name: str = "1_기초_제비율_토목_조달청_2026-04-13.json"
|
||||
|
||||
#: 공종별 수량 `{공종코드: 수량}`. 주면 **직접비 3분할을 여기서 만들어** 쓴다.
|
||||
#: ⚠ 일위대가 합계를 뭉쳐 넣지 않는다 — 밑수가 항목마다 갈린다(PLAN 8-9 규칙 2).
|
||||
|
||||
@@ -500,7 +500,7 @@ def _add_machine_layers(
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def load_basis_missing(
|
||||
file_name: str = "basis_missing_2026-01-01.json",
|
||||
file_name: str = "2_공종_산림_밑수없음_2026-01-01.json",
|
||||
) -> dict[str, str]:
|
||||
"""B08 이 낸 **밑수 못 찾은 표** 목록 — `{표 번호: 절 이름}`.
|
||||
|
||||
@@ -512,7 +512,7 @@ def load_basis_missing(
|
||||
import os
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
path = os.path.join(root, "resources", "data_work_item_master", file_name)
|
||||
path = os.path.join(root, "resources", "master_data", "old", file_name)
|
||||
if not os.path.exists(path):
|
||||
return {}
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
|
||||
@@ -57,7 +57,9 @@ def operating_record(node: dict[str, Any] | None = None):
|
||||
values = _table_values(node)
|
||||
if values is None:
|
||||
return None
|
||||
aliases = _read_json(*_CATALOG_SUBPATH, "labor_const_2026-01-01.json")["variables"]["aliases"]
|
||||
aliases = _read_json(*_CATALOG_SUBPATH, "1_기초_노임_건설업_대한건설협회_2026-01-01.json")[
|
||||
"variables"
|
||||
]["aliases"]
|
||||
return OperatingRecord(
|
||||
machine_code=MACHINE,
|
||||
machine_name="이동식 임목파쇄기",
|
||||
|
||||
Reference in New Issue
Block a user