From 7d62337896ade53beb041d8ccee169fbe2e32898 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 20 Sep 2026 22:47:02 +0900 Subject: [PATCH 1/2] =?UTF-8?q?knowledge(=EB=A7=88=EC=8A=A4=ED=84=B0):=20?= =?UTF-8?q?=EA=B1=B7=EC=9D=84=20=EC=98=9B=20=EC=BD=94=EB=93=9C=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=E2=80=94=20old=20=C2=B7=20ref=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EB=95=8C=20=EA=B0=99=EC=9D=B4=20=EA=B1=B7=EC=9D=84=20Z01=20?= =?UTF-8?q?=C2=B7=20B08=20=C2=B7=20B09=20=C2=B7=20common=5Futil=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ --- resources/master_data/ref/_걷을_옛코드.md | 78 +++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 resources/master_data/ref/_걷을_옛코드.md diff --git a/resources/master_data/ref/_걷을_옛코드.md b/resources/master_data/ref/_걷을_옛코드.md new file mode 100644 index 00000000..ac2d3007 --- /dev/null +++ b/resources/master_data/ref/_걷을_옛코드.md @@ -0,0 +1,78 @@ +# 걷을 옛 코드 목록 + +`old/` · `ref/` 를 지울 때 같이 걷을 코드. 읽기 조사만 — 코드는 안 고침. + +판정: 걷음 = 부르는 곳 없음 · 바꿈 = 부르는 곳 있음(새 마스터 읽기로 바꾼 뒤 걷음). + +## 걷음 (부르는 곳 없음) + +| 파일 | 읽는 것 | 부르는 곳 | 판정 | +|---|---|---|---| +| B09_Estimation/B09_Estimation_ResourceAxis_Dump.py | old/ 에 씀 | 없음 | 걷음 | +| old/_build_mach.py · _build_mat_price.py · _build_pum.py | old/ 자기 폴더 | 없음(폴더째) | old/ 와 함께 걷음 | +| resources/master_data/scripts/update_관급단가_보강.py | ref/_관급_보강_후보.json 에 씀 | 손으로만 | 결과물 처분 뒤 걷음 | + +## 바꿈 — Z01 + +| 파일 | old/ref 에서 읽는 것 | 부르는 곳 | +|---|---|---| +| Z01_MasterData/Z01_MasterData_Tables.py | old/ 화면 이름표 | Z01 BasePrices · BasePrices_Machine · Router · WorkItems · test_z01_master_data | +| Z01_MasterData/Z01_MasterData_BasePrices_Machine.py | old/ 기계 파일 | Z01 BasePrices | +| Z01_MasterData/Z01_MasterData_WorkItems.py | old/ 공종 마스터 · 연결 | Z01 BasePrices · Router · test_z01_work_items · test_z01_base_tables | + +## 바꿈 — B08 + +| 파일 | old/ref 에서 읽는 것 | 부르는 곳 | +|---|---|---| +| B08_Quantity_Build_WorkItemMaster.py | old/3_품셈_산림_표전체 (읽고 old/ 에 씀) | WorkItemMaster_Const · _Table · 시험 6 | +| B08_Quantity_Build_WorkItemMaster_Const.py | old/3_품셈_건설_표전체 · work_item_keys_const.json | WorkItemMaster · test_work_item_master_const | +| B08_Quantity_Build_WorkItemMaster_Keys.py | old/ 열쇠대장 | WorkItemMaster · _Const · Z01 WorkItems · 시험 3 | +| B08_Quantity_Engine_BasisUnit.py | old/ 기준 원단위 | Handoff · Handoff_Rows · test_b08_basis_unit | +| B08_Quantity_Engine_Formwork.py | old/ 거푸집 사용횟수 | Handoff_Mapping · UnitQuantity · 시험 3 | +| B08_Quantity_Engine_Handoff_Mapping.py | ref/ 수량 연결 · old/ 철근 · 돌쌓기 · 목재 갈래 | Handoff 계열 7 · RockSplit · Provenance | +| B08_Quantity_Engine_MaterialSummary.py | ref/ 재료 할증 | Handoff_Boundaries · Provenance · Router_Material · 시험 다수 | +| B08_Quantity_Engine_ObservedUnit.py | ref/ 구조물 원단위 | StructureFigure · UnitQuantity · UnitQuantity_Base · 시험 다수 | +| B08_Quantity_Engine_Pipe.py | ref/ 사방 기슭막이 치수 | StructureFigure · StructureSummary · Router_Material · B06_Section_Structure_Layouts.ts · 시험 다수 | +| B08_Quantity_Engine_UnitQuantity_StoneSpec.py | ref/ 돌 종류 · old/ 돌쌓기 경사 | ObservedUnit · StructureTemplate · UnitQuantity · _Masonry · common_util_masonry_slope.ts · 시험 3 | + +## 바꿈 — B09 + +| 파일 | old/ref 에서 읽는 것 | 부르는 곳 | +|---|---|---| +| B09_Estimation_BasisSheet.py | old/_manifest.json · 마스터 | Provenance_Sources · Router · 시험 3 | +| B09_Estimation_LaborSurcharge.py | old/3_품셈_산림_계수 | BasisSheet · Router · Router_Factors · UnitPrice · 시험 2 | +| B09_Estimation_MachineCost.py | old/ 기계 카탈로그 | Lists · Lists_Sources · MachineExpenseSheet · MachineOperating · MachineProductivity 계열 | +| B09_Estimation_MachineExpenseSheet.py | old/ 기계 카탈로그 | Provenance · Router · 시험 4 | +| B09_Estimation_MachineOperating.py | old/ 기계 카탈로그 (읽고 old/ 에 씀) | Consumables · Lists_Sources · UnitPrice · UnitPrice_View · WoodChipping · 시험 다수 | +| B09_Estimation_MachineProductivity_Data.py | old/ 작업량 | MachineProductivity_Dozer · _Dump | +| B09_Estimation_MaterialCatalog.py | old/ 재료 카탈로그 | MaterialSheet · ResourceAxis_Sources · UnitPrice_View | +| B09_Estimation_MaterialPrices.py | old/재료_나라장터자재.json | BillOfQuantities 계열 · Router 계열 · UnitPrice · test_b09_material_prices | +| B09_Estimation_Rates.py | old/ 제비율 | CostSheet · Engine_Cost · Provenance · RateOverride · RateTable · Router 계열 | +| B09_Estimation_ResourceAxis.py | old/ 공종 마스터 · 카탈로그 | B08 Variants · BillOfQuantities · 공종 계산 모듈 다수 | +| B09_Estimation_ResourceAxis_Join.py | old/ 자원줄 | MaterialPrices · ResourceAxis · _ChooseOne · _JudgedTable · _Sources · 시험 2 | +| B09_Estimation_ResourceAxis_Sources.py | old/ 마스터 · 카탈로그 | B08 Variants · ResourceAxis · _Join · 시험 2 | +| B09_Estimation_UnitPrice.py | old/ 각종 (파일명 인자) | B08 Variants · StructurePriceLink · Router 계열 · BillOfQuantities 계열 | + +## 바꿈 — common_util · 화면 + +| 파일 | old/ref 에서 읽는 것 | 부르는 곳 | +|---|---|---| +| common_util/common_util_node_bundle.py | old/ 통째(SOURCE_DATA_DIRS) | B05 Corridor_Prebuild · B06 Router_HaulPlan · B06 Server_Calc_Prebuild · B08 Engine_Formula | +| common_util/common_util_work_item_key.py | old/ 열쇠대장 | B08 Handoff · B09 BillOfQuantities_Input · 시험 2 | +| common_util/common_util_work_item_link.py | old/ 연결 | B09 BillOfQuantities · _Input · test_work_item_link_choice | +| B05_Profile/B05_Profile_UI_Drainage_Facility_Fields.ts | ref/수량_사방기슭막이치수 (import) | B05 화면 | +| B06_Section/B06_Section_UI_Cross_Lean.ts | old/3_품셈_산림_돌쌓기경사 (import) | B06 화면 | + +## 바꿈 — 시험 + +- resources/tester/test_b05_revetment_sabang_basis.py — ref/ 읽음 +- resources/tester/test_b06_wall_lean_table.py — old/ 읽음 +- 위 코드를 부르는 시험 전부(약 40 파일) — 코드 교체 때 같이 고침 + +## 걷는 순서 + +1. 걷음 표의 셋. +2. Z01 셋(화면 이름표 · 공종 마스터 · 기계) — 새 마스터 읽기로. +3. B08 Build · Keys → B08 Engine → B09 → common_util. +4. `.ts` import 둘 · 시험 둘. +5. `old/` · `ref/` 삭제. From 1476c79489ab3ae08a5e8733d0951a8c97223aaa Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 20 Sep 2026 22:47:50 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(=EB=A7=88=EC=8A=A4=ED=84=B0):=20?= =?UTF-8?q?=ED=99=98=EC=9C=A8=20=EB=B9=8C=EB=8D=94=20=E2=80=94=20ECOS=20?= =?UTF-8?q?=EC=9D=BC=EB=B3=84=20CSV=20=EC=97=90=EC=84=9C=20=EC=B5=9C?= =?UTF-8?q?=EC=8B=A0=20=EC=9D=BC=EC=9E=90=205=ED=86=B5=ED=99=94=20=C2=B7?= =?UTF-8?q?=20--check=20=EB=A1=9C=20=EC=A7=80=EA=B8=88=20JSON=20=EA=B3=BC?= =?UTF-8?q?=20=EA=B0=99=EC=9D=8C=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ --- resources/master_data/_갱신절차.md | 6 +- resources/master_data/scripts/build_환율.py | 90 +++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 resources/master_data/scripts/build_환율.py diff --git a/resources/master_data/_갱신절차.md b/resources/master_data/_갱신절차.md index cda71a51..a399abdc 100644 --- a/resources/master_data/_갱신절차.md +++ b/resources/master_data/_갱신절차.md @@ -103,8 +103,8 @@ | 출처 | 한국은행환율 · `원가계산/환율_한국은행ECOS/환율_일별_*.csv` (ECOS 731Y001 · 5통화) | | 받는 법 | `collect_cost_sources.py values` (ECOS API) | | 주기 | 일별 · 견적 기준일마다 | -| 빌더 | 빌더 없음 (`scripts/_migrate_base.py` 는 옛 파일 한 번 옮기기) | -| 검사 | `check_master.py 틀 환율_한국은행환율.json` | +| 빌더 | `scripts/build_환율.py` (최신 일자 5통화 · `--check` 는 지금 JSON 과 비교만) | +| 검사 | `build_환율.py --check` · `check_master.py 틀 환율_한국은행환율.json` | ## 요율 (`요율_조달청제비율.json`) @@ -129,7 +129,7 @@ ## 구멍 목록 -- 환율 · 요율 · 품셈재료 · 로직 — 빌더 없음. +- 요율 · 품셈재료 · 로직 — 빌더 없음. - 기계 산림품셈 · 소요량 건설 건축·유지관리 · 소요량 산림 전 장 · 계수 건설 전 장 · 계수 산림 1장 밖 — 빌더 없음. - 자재품목 — 나라장터 스냅샷 → 마스터 줄 빌더 없음 · 유료 물가지 받는 길 미정. - 유가전력 — 휘발유·경유 새 판 반영 없음. diff --git a/resources/master_data/scripts/build_환율.py b/resources/master_data/scripts/build_환율.py new file mode 100644 index 00000000..a00f158f --- /dev/null +++ b/resources/master_data/scripts/build_환율.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +"""한국은행 ECOS 환율 일별 CSV → 환율_한국은행환율.json (테이블ID FX · 최신 일자 5통화). + +쓰기: ./venv/Scripts/python.exe resources/master_data/scripts/build_환율.py +비교: ./venv/Scripts/python.exe resources/master_data/scripts/build_환율.py --check (파일·대장 안 씀) +""" + +from __future__ import annotations + +import csv +import hashlib +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parent)) +import master_keys as mk # noqa: E402 +from _migrate_base import dump_master # noqa: E402 + +ROOT = Path(__file__).resolve().parents[3] +OUT = Path(__file__).resolve().parents[1] / "환율_한국은행환율.json" +CSV_DIR = ROOT / "resources/knowledge/original/원가계산/환율_한국은행ECOS" +NAMES = { # 항목코드 → (이름, 단위) + "0000001": ("USD", "원/USD"), + "0000002": ("JPY100", "원/JPY100"), + "0000003": ("EUR", "원/EUR"), + "0000012": ("GBP", "원/GBP"), + "0000053": ("CNY", "원/CNY"), +} + + +def build() -> tuple[Path, dict, list[dict], dict]: + path = sorted(CSV_DIR.glob("환율_일별_*.csv"))[-1] + last: dict[str, tuple[str, float]] = {} + with path.open(encoding="utf-8-sig", newline="") as f: + for r in csv.DictReader(f): + code, day, val = r["항목코드"], r["일자"], r["환율"] + if code in NAMES and val and (code not in last or day > last[code][0]): + last[code] = (day, float(val)) + day = max(d for d, _ in last.values()) + date = f"{day[:4]}-{day[4:6]}-{day[6:]}" + book = mk.load_book() + rows = [] + for code in sorted(NAMES): + name, unit = NAMES[code] + key = mk.issue(book, "FX", code, OUT.name) + rows.append( + { + "키": key, + "원문번호": code, + "구분": None, + "상세구분": None, + "이름": name, + "규격": date, + "단위": unit, + "값": last[code][1], + "출처": f"한국은행환율 {code}", + "비고": None, + } + ) + head = { + "그룹": "환율", + "원문": "한국은행환율", + "판": date, + "원천": [ + { + "경로": path.relative_to(ROOT).as_posix(), + "해시": hashlib.sha256(path.read_bytes()).hexdigest(), + "역할": "primary", + } + ], + "비고": ["규격 = 기준일 · 구분 · 상세구분은 두되 비움"], + } + return path, head, rows, book + + +def main() -> None: + _, head, rows, book = build() + if "--check" in sys.argv: + now = json.loads(OUT.read_text(encoding="utf-8")) + same = now["줄"] == rows and {k: now[k] for k in head} == head + print("같음" if same else "다름") + sys.exit(0 if same else 1) + mk.finish(book) + mk.save_book(book) + dump_master(OUT, head, rows) + + +if __name__ == "__main__": + main()