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:
@@ -9,7 +9,7 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { FORD_MANNING_N, FORD_SLOPE } from "@config/config_frontend";
|
||||
import revetmentSabang from "../resources/data_masonry/revetment_sabang_2026-01-01.json";
|
||||
import revetmentSabang from "../resources/master_data/ref/수량_사방기슭막이치수_사방기술교본_2026-01-01.json";
|
||||
|
||||
/* ── 유입구 구조 ──────────────────────────────────────────────────────────── */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* =============================================================================
|
||||
* B06_Section_UI_Cross_Lean.ts
|
||||
* 횡단도 벽 전면 기울기 — 품셈 13-4-4 [주]⑪ 표준경사 표(`resources/data_masonry/masonry_slope_*`)를
|
||||
* 횡단도 벽 전면 기울기 — 품셈 13-4-4 [주]⑪ 표준경사 표(`resources/master_data/old/3_품셈_산림_돌쌓기경사_*`)를
|
||||
* 읽는 자리 하나(2026-09-14 B5 · B08 과 한 벌). 표 읽기 식은 `common_util_masonry_slope.ts`(파이썬 짝).
|
||||
*
|
||||
* 따로 뗀 까닭 — 표(JSON)를 가져오는 모듈을 상수 파일에 두면 그 상수를 쓰는 기하 조각을 Node 로
|
||||
@@ -10,7 +10,7 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { type WallLeanInput, wallLeanRatio } from "../common_util/common_util_masonry_slope";
|
||||
import masonrySlope from "../resources/data_masonry/masonry_slope_2026-01-01.json";
|
||||
import masonrySlope from "../resources/master_data/old/3_품셈_산림_돌쌓기경사_13-4-4_2026-01-01.json";
|
||||
|
||||
/** 벽 전면 기울기 n — 표를 못 고르면 종전 0.3. */
|
||||
export function leanOf(input: WallLeanInput): number {
|
||||
|
||||
@@ -56,8 +56,8 @@ from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Table import ( # noqa: F401
|
||||
)
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SOURCE = ROOT / "resources" / "data_cost_input_value" / "pum_forest_2026.json"
|
||||
OUT_DIR = ROOT / "resources" / "data_work_item_master"
|
||||
SOURCE = ROOT / "resources" / "master_data" / "old" / "3_품셈_산림_표전체_2026-01-01.json"
|
||||
OUT_DIR = ROOT / "resources" / "master_data" / "old"
|
||||
#: 불변 열쇠 장부 — **판이 붙지 않는다.** 판마다 새로 짓는 산출물이 아니라 대대로 잇는 장부다.
|
||||
KEY_REGISTRY = OUT_DIR / "work_item_keys.json"
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SOURCE = ROOT / "resources" / "data_cost_input_value" / "pum_const_2026.json"
|
||||
SOURCE = ROOT / "resources" / "master_data" / "old" / "3_품셈_건설_표전체_2026-01-01.json"
|
||||
#: 건설 열쇠 장부 — 산림 장부(`work_item_keys.json`)와 일련번호를 안 섞음
|
||||
CONST_KEY_REGISTRY = ROOT / "resources" / "data_work_item_master" / "work_item_keys_const.json"
|
||||
CONST_KEY_REGISTRY = ROOT / "resources" / "master_data" / "old" / "work_item_keys_const.json"
|
||||
KEY_PREFIX = "CW" # Construction Work item
|
||||
BOOK_NAME = "2026년_건설공사_표준품셈.md"
|
||||
CODE_PREFIX = "CP" # Construction Pumsem — 목차 코드
|
||||
|
||||
@@ -33,7 +33,8 @@ PATH_SEP = " › "
|
||||
AXIS_POLICY = (
|
||||
Path(__file__).resolve().parent.parent
|
||||
/ "resources"
|
||||
/ "data_work_item_master"
|
||||
/ "master_data"
|
||||
/ "old"
|
||||
/ "axis_policy.json"
|
||||
)
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
|
||||
MASTER_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_work_item_master"
|
||||
MASTER_PREFIX = "work_item_master_"
|
||||
MASTER_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
MASTER_PREFIX = "2_공종_산림_마스터_"
|
||||
|
||||
#: 같은 뜻인데 표기만 다른 단위 — **환산이 아니라 표기 흡수**다.
|
||||
UNIT_ALIASES = {
|
||||
|
||||
@@ -23,8 +23,8 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_formwork"
|
||||
DATASET_PREFIX = "formwork_reuse_"
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
DATASET_PREFIX = "3_품셈_산림_거푸집사용횟수_"
|
||||
|
||||
#: 거푸집으로 보는 성분 이름. 정확히 같은 이름으로만 본다 — 부분일치면 「거푸집씻기」가 걸린다.
|
||||
FORMWORK_NAMES = frozenset({"합판거푸집", "유로폼", "문양거푸집", "거푸집"})
|
||||
|
||||
@@ -15,22 +15,22 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_work_item_mapping"
|
||||
DATASET_PREFIX = "work_item_mapping_"
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "ref"
|
||||
DATASET_PREFIX = "공종_수량연결_실무_"
|
||||
|
||||
#: 철근 갈래표 — **품셈 12-3 [주]① 원문**이 구조물 예시로 갈라 둔 것이라 사람이 고르는 값이
|
||||
#: 아니다(거푸집 사용횟수 1-7-1 과 같은 자리). 원문 예시에 안 걸리면 지어내지 않는다.
|
||||
REBAR_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_rebar"
|
||||
REBAR_PREFIX = "rebar_complexity_"
|
||||
REBAR_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
REBAR_PREFIX = "3_품셈_산림_철근가공갈래_"
|
||||
|
||||
#: 돌쌓기 규격 갈래표 — 저장 제원 값으로 자동 판정한다(사람이 고르는 값이 아니다).
|
||||
MASONRY_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_masonry"
|
||||
MASONRY_PREFIX = "masonry_class_"
|
||||
MASONRY_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
MASONRY_PREFIX = "3_품셈_산림_돌쌓기규격갈래_"
|
||||
|
||||
|
||||
#: 목재공작물 구조 갈래표 — 품셈 13-13-1 [주]③ 이 **재료 구성**으로 가른다.
|
||||
TIMBER_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_timber"
|
||||
TIMBER_PREFIX = "timber_structure_class_"
|
||||
TIMBER_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
TIMBER_PREFIX = "3_품셈_산림_목재구조갈래_"
|
||||
|
||||
|
||||
def load_timber_table(path: Path | None = None) -> dict[str, Any]:
|
||||
|
||||
@@ -53,8 +53,8 @@ from typing import Any, Iterable
|
||||
from common_util.common_util_quantity_spread import spread_by_unit
|
||||
|
||||
# ── 데이터 자리 ──────────────────────────────────────────────────────
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_material_surcharge"
|
||||
DATASET_PREFIX = "material_surcharge_"
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "ref"
|
||||
DATASET_PREFIX = "품셈_산림_재료할증_울진_"
|
||||
|
||||
#: 이 표가 받는 성분 갈래. 나머지는 각자 다른 표로 간다.
|
||||
ACCEPTED_DESTINATION = "material"
|
||||
|
||||
@@ -32,8 +32,8 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_structure_unit"
|
||||
DATASET_PREFIX = "structure_unit_observed_"
|
||||
DATASET_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "ref"
|
||||
DATASET_PREFIX = "수량_구조물원단위_울진_"
|
||||
|
||||
#: 값이 어디서 왔나 — 한 표에 섞이므로 줄마다 단다.
|
||||
BASIS_DERIVED = "derived" # 저장된 치수에서 식으로
|
||||
|
||||
@@ -222,8 +222,8 @@ NOTE_WALL_HEIGHT_PIPE = " · 높이는 횡단도와 같은 관경 기준 최소
|
||||
|
||||
#: 독립 기슭막이 치수 **한 벌**(`resources/data_masonry/revetment_sabang_*.json`) — B05 칸 밑 근거와
|
||||
#: 이 사유가 같은 파일을 읽음(2026-09-14 브레인 판정). 높이는 **설계자 입력** — 등록부 기본 2.5 걷음.
|
||||
REVET_SABANG_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_masonry"
|
||||
REVET_SABANG_PREFIX = "revetment_sabang_"
|
||||
REVET_SABANG_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "ref"
|
||||
REVET_SABANG_PREFIX = "수량_사방기슭막이치수_사방기술교본_"
|
||||
UNCONFIRMED_OWN_HEIGHT = "높이를 안 적음 — {rule}({source}) 설계자 입력 · 적으면 금액이 섬"
|
||||
|
||||
|
||||
|
||||
@@ -131,8 +131,8 @@ STONE_PILE_BASIS = "⚠ 정본에 없는 줄 — 소광리 시트에만 있음(
|
||||
#: ⚠ 지금까지 **건설품셈 참고자료 한 벌**(돌 종류로 안 갈리는 표)로만 돌고 있었다.
|
||||
#: 그 값이 「깬돌」 계열이라, **자재로는 야면석을 내면서 계수는 깬돌**을 쓰는 어긋남이
|
||||
#: 있었다(2026-09-08 지식DB 대조). 랩탑 창이 `stone_kind` 칸을 만들어 축이 생겼다.
|
||||
STONE_KIND_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_masonry"
|
||||
STONE_KIND_PREFIX = "stone_kind_"
|
||||
STONE_KIND_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "ref"
|
||||
STONE_KIND_PREFIX = "품셈_산림_돌종류계수_울진_"
|
||||
STONE_KIND_OPTION = "stone_kind"
|
||||
|
||||
|
||||
@@ -336,8 +336,8 @@ BLINDING_OPTION_KEYS = ("blinding_concrete", "base_blinding")
|
||||
|
||||
|
||||
#: 표준경사표 — 품셈 13-4-4 [주]⑪. 파일이 없으면 종전 기본값(0.3)으로 돈다.
|
||||
SLOPE_DIR = Path(__file__).resolve().parents[1] / "resources" / "data_masonry"
|
||||
SLOPE_PREFIX = "masonry_slope_"
|
||||
SLOPE_DIR = Path(__file__).resolve().parents[1] / "resources" / "master_data" / "old"
|
||||
SLOPE_PREFIX = "3_품셈_산림_돌쌓기경사_"
|
||||
#: 사용자가 덮어쓰는 칸 — 값이 있으면 **그 값이 이긴다**(확정 ⑨).
|
||||
FACE_SLOPE_KEYS = ("face_slope_ratio",)
|
||||
#: 성토/절토는 **측점 단면유형(`design.section_mode`) + 설치 측**으로 판정한다
|
||||
@@ -469,7 +469,7 @@ def dry_masonry_height_note(height_m: float) -> str | None:
|
||||
|
||||
#: 뒷길이 표준표 — 품셈 13-4-4 [주]⑩. 안 고른 돌쌓기는 붙박이 45 가 아니라 이 표의 하한
|
||||
#: (2026-09-14 브레인 판정 ㉮ 「범위 안에 드는 규격 중 가장 작은 것」). 파일이 없으면 종전 45.
|
||||
BACK_LENGTH_PREFIX = "masonry_back_length_"
|
||||
BACK_LENGTH_PREFIX = "3_품셈_산림_돌쌓기뒷길이_"
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
|
||||
@@ -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="이동식 임목파쇄기",
|
||||
|
||||
@@ -23,7 +23,11 @@ from B09_Estimation.B09_Estimation_MachineOperating import FUEL_VARIABLES, load_
|
||||
from Z01_MasterData.Z01_MasterData_Tables import RESOURCES
|
||||
|
||||
#: B09 셈이 여는 원본 셋 — 바뀌면 캐시를 새로 읽음
|
||||
_INPUT_FILES = ("mach_base_2026.json", "pum_const_2026.json", "labor_const_2026-01-01.json")
|
||||
_INPUT_FILES = (
|
||||
"3_품셈_건설_기계경비기준_8장_2026-01-01.json",
|
||||
"3_품셈_건설_표전체_2026-01-01.json",
|
||||
"1_기초_노임_건설업_대한건설협회_2026-01-01.json",
|
||||
)
|
||||
EDITABLE = ["price_thousand_krw", "loss_coefficient_per_hour"]
|
||||
COMPUTED = ("hourly_loss_krw", "hourly_fuel_krw", "hourly_operator_krw", "hourly_total_krw")
|
||||
#: 조종원 식 글자 — B09 식 문자열(좌→우 차례)을 사람이 읽게만 바꿈
|
||||
@@ -90,7 +94,7 @@ def _cached(_mtimes: tuple[int, ...]):
|
||||
|
||||
|
||||
def _inputs():
|
||||
folder = RESOURCES / "data_cost_input_value"
|
||||
folder = RESOURCES / "master_data" / "old"
|
||||
return _cached(tuple((folder / name).stat().st_mtime_ns for name in _INPUT_FILES))
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
RESOURCES = ROOT / "resources"
|
||||
LABEL_DIR = RESOURCES / "data_master_labels"
|
||||
LABEL_DIR = RESOURCES / "master_data" / "old"
|
||||
DEFAULT_PAGE_SIZE = 50
|
||||
MAX_PAGE_SIZE = 500
|
||||
ROW_KEY = "@key"
|
||||
@@ -132,7 +132,7 @@ def _labels_at(path: str, _mtime_ns: int) -> dict[str, Any]:
|
||||
|
||||
def load_labels() -> dict[str, Any]:
|
||||
"""이름표 끝 판(이름 차례) — 없으면 빈 이름표(파일도 안 보임)."""
|
||||
found = sorted(LABEL_DIR.glob("labels_*.json")) if LABEL_DIR.is_dir() else []
|
||||
found = sorted(LABEL_DIR.glob("4_화면_이름표_*.json")) if LABEL_DIR.is_dir() else []
|
||||
if not found:
|
||||
return {"kinds": {}, "files": [], "columns": {}, "column_overrides": {}}
|
||||
return _labels_at(str(found[-1]), found[-1].stat().st_mtime_ns)
|
||||
|
||||
@@ -24,7 +24,7 @@ SOURCE_OF = {
|
||||
"work_item_forest": "pum_forest",
|
||||
"work_item_const": "pum_const",
|
||||
} # 이름표 `work_item_axis` 와 같은 이름
|
||||
FOLDER = tables.RESOURCES / "data_work_item_master"
|
||||
FOLDER = tables.RESOURCES / "master_data" / "old"
|
||||
#: 불변 열쇠 칸 — ⚠ 데스크탑 서브 자료가 오면 칸 이름을 맞출 것(여기 한 곳)
|
||||
KEY_FIELD = "work_item_key"
|
||||
PATH_JOIN = " › "
|
||||
@@ -127,7 +127,7 @@ def base_rows(kind: str) -> list[dict[str, Any]]:
|
||||
return rows
|
||||
|
||||
|
||||
LINK_FOLDER = tables.RESOURCES / "data_work_item_link"
|
||||
LINK_FOLDER = tables.RESOURCES / "master_data" / "old"
|
||||
LINKED = "연결됨"
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ def linked_keys() -> frozenset[str]:
|
||||
|
||||
⚠ 목록을 코드에 안 둠 — 판정은 그 표 · 미판정은 안 이음(표의 `unconfirmed_action: do_not_link`).
|
||||
"""
|
||||
found = sorted(LINK_FOLDER.glob("work_item_link_*.json")) if LINK_FOLDER.is_dir() else []
|
||||
found = sorted(LINK_FOLDER.glob("2_공종_산림건설_연결_*.json")) if LINK_FOLDER.is_dir() else []
|
||||
if not found:
|
||||
return frozenset()
|
||||
links = _read(str(found[-1]), found[-1].stat().st_mtime_ns).get("links") or []
|
||||
|
||||
@@ -22,7 +22,11 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
ALIAS_FILE = (
|
||||
Path(__file__).resolve().parents[1] / "resources" / "data_aliases" / "aliases_2026-01-01.json"
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "resources"
|
||||
/ "master_data"
|
||||
/ "ref"
|
||||
/ "공종_자원별칭_실무_2026-01-01.json"
|
||||
)
|
||||
AXES = frozenset({"resource", "variant"})
|
||||
_FIELDS = ("axis", "from", "to", "scope", "pum_edition")
|
||||
|
||||
@@ -22,7 +22,7 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
# 번들이 낡았는지 재는 대상 — 기하 계통이 걸쳐 있는 폴더 + 구조물도 식 풀이(B08, 2026-09-13).
|
||||
SOURCE_DIRS = ("B05_Profile", "B06_Section", "B08_Quantity", "common_util")
|
||||
# 번들에 박히는 자료(JSON) — 벽 전면 기울기 표준경사 표(2026-09-14 B5). 표만 바뀌어도 다시 빌드.
|
||||
SOURCE_DATA_DIRS = ("resources/data_masonry",)
|
||||
SOURCE_DATA_DIRS = ("resources/master_data/old",)
|
||||
# 번들 만들기·실행 상한(초). 실측 번들 실행 0.1초, 빌드 3초 수준이라 넉넉하다.
|
||||
BUILD_TIMEOUT_S = 300
|
||||
RUN_TIMEOUT_S = 600
|
||||
|
||||
@@ -20,7 +20,7 @@ from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
|
||||
MASTER_DIR = Path(__file__).resolve().parent.parent / "resources" / "data_work_item_master"
|
||||
MASTER_DIR = Path(__file__).resolve().parent.parent / "resources" / "master_data" / "old"
|
||||
#: 우리가 세운 공종·구조물 — 난수 코드가 곧 불변 열쇠
|
||||
_STABLE_CODE = re.compile(r"^AX-(?:WK|ST)-[0-9a-f]{8}$")
|
||||
|
||||
@@ -38,7 +38,7 @@ def _read(path: str, _mtime_ns: int) -> dict[tuple[str, str], str | None]:
|
||||
|
||||
def _keys() -> dict[tuple[str, str], str | None]:
|
||||
out: dict[tuple[str, str], str | None] = {}
|
||||
for path in sorted(MASTER_DIR.glob("*work_item_master_*.json")): # 산림 + 건설(`const_`)
|
||||
for path in sorted(MASTER_DIR.glob("2_공종_*_마스터_*.json")): # 산림 + 건설(`const_`)
|
||||
out.update(_read(str(path), path.stat().st_mtime_ns))
|
||||
return out
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
FOLDER = Path(__file__).resolve().parent.parent / "resources" / "data_work_item_link"
|
||||
FOLDER = Path(__file__).resolve().parent.parent / "resources" / "master_data" / "old"
|
||||
CONFIRMED = "확정"
|
||||
#: 표 `policy.both_precedence` 낱말 → 그 행의 열쇠 칸
|
||||
_KEY_COLUMN = {"forest": "forest_key", "construction": "const_key"}
|
||||
@@ -39,7 +39,7 @@ def _read(path: str, _mtime_ns: int) -> dict[str, Any]:
|
||||
|
||||
|
||||
def _doc() -> dict[str, Any]:
|
||||
found = sorted(FOLDER.glob("work_item_link_*.json")) if FOLDER.is_dir() else []
|
||||
found = sorted(FOLDER.glob("2_공종_산림건설_연결_*.json")) if FOLDER.is_dir() else []
|
||||
return _read(str(found[-1]), found[-1].stat().st_mtime_ns) if found else {}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user