Merge remote-tracking branch 'origin/sub_desktop_1' into main_laptop_1 — 갈래 불변 열쇠(FW-00105#01 꼴 · 데스크탑 서브) 받음 · 자료 파일 충돌은 합친 코드로 다시 뽑아 풂 · 갈래 수 335 → 332(헛단위 13-3 갈래 뺀 것 반영)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -303,6 +303,7 @@ def finish(
|
||||
# ⚠ 장부에 없는 목차 코드는 **새 열쇠**를 받는다. 짐작으로 옛 열쇠를 물려주지 않는다.
|
||||
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Keys import (
|
||||
assign_keys,
|
||||
assign_variant_keys,
|
||||
decorate,
|
||||
load_registry,
|
||||
toc_edition,
|
||||
@@ -311,6 +312,8 @@ def finish(
|
||||
edition = toc_edition(data.get("sources"), data["effective_date"])
|
||||
registry = load_registry(registry_path, key_prefix)
|
||||
newly_issued, toc_duplicates = assign_keys(nodes, registry, edition=edition)
|
||||
# 갈래도 불변 열쇠 — 갈래 글자를 열쇠에 담으면 원문이 다듬어질 때 열쇠가 갈린다(2026-09-17 브레인).
|
||||
newly_variants = assign_variant_keys(nodes, registry)
|
||||
decorate(nodes, edition=edition, roots=general_roots) # None = 산림 잣대(`axis_policy.json`)
|
||||
role_counts: dict[str, int] = {}
|
||||
for node in nodes:
|
||||
@@ -357,6 +360,8 @@ def finish(
|
||||
# 표도 아래도 없는 잎(`empty`). 화면·조합은 공종 축만 보면 된다.
|
||||
"axis_roles": role_counts,
|
||||
"keys_newly_issued": len(newly_issued),
|
||||
"variant_keys_newly_issued": len(newly_variants),
|
||||
"variant_keys": sum(len(n.get("variants") or []) for n in nodes),
|
||||
"toc_duplicate_rows": len(toc_duplicates),
|
||||
"toc_corrections": len(toc_corrections),
|
||||
},
|
||||
|
||||
@@ -163,6 +163,82 @@ def assign_keys(
|
||||
return newly, duplicates
|
||||
|
||||
|
||||
#: 갈래 열쇠 자릿수 — `FW-00105#01` 의 뒤 두 자리.
|
||||
VARIANT_DIGITS = 2
|
||||
#: 원문이 섞어 쓰는 물결표 — 맞댈 때 하나로 모은다.
|
||||
_TILDES = {"~": "∼", "〜": "∼", "~": "∼"}
|
||||
|
||||
|
||||
def variant_match(text: str) -> str:
|
||||
"""갈래를 맞대는 꼴 — **공백을 다 떼고** 물결표를 하나로.
|
||||
|
||||
⚠ 왜 이렇게까지 지우나 — 원문이 「간 단」·「간 단」처럼 자간을 들쭉날쭉 쓰고, 이름 다듬기가
|
||||
앞으로 더 들어올 자리다. 맞대는 꼴이 공백에 걸리면 **다듬는 날 열쇠가 갈린다.**
|
||||
(산림 335 갈래로 재 보니 한 공종 안에서 이 꼴이 겹치는 자리는 없다 — 2026-09-17.)
|
||||
"""
|
||||
squeezed = "".join(str(text or "").split())
|
||||
return "".join(_TILDES.get(ch, ch) for ch in squeezed)
|
||||
|
||||
|
||||
def variant_display(text: str) -> str:
|
||||
"""다듬은 갈래 이름 — 자간 공백을 한 칸으로, 물결표를 하나로. 원문은 따로 남긴다."""
|
||||
spaced = " ".join(str(text or "").split())
|
||||
return "".join(_TILDES.get(ch, ch) for ch in spaced)
|
||||
|
||||
|
||||
def format_variant(serial: int) -> str:
|
||||
return f"{serial:0{VARIANT_DIGITS}d}"
|
||||
|
||||
|
||||
def assign_variant_keys(
|
||||
nodes: list[dict[str, Any]], registry: dict[str, Any], *, issued_on: str | None = None
|
||||
) -> list[dict[str, str]]:
|
||||
"""갈래마다 **불변 열쇠**(`FW-00105#01`)를 주고 `variants` 칸을 얹는다.
|
||||
|
||||
공종 열쇠와 같은 병을 갈래가 그대로 앓고 있었다 — 갈래 글자가 열쇠에 들어가 있어
|
||||
**원문 자간이나 물결표가 손질되면 열쇠가 갈렸다.** 그래서 장부에 올린다(2026-09-17 브레인).
|
||||
|
||||
장부 자리는 **공종 열쇠 아래**다(목차 코드 아래가 아니다) — 목차 번호가 밀려도 안 흔들린다.
|
||||
⚠ 장부에 없는 갈래는 **새 번호**를 받는다. 비슷하다고 옛 번호를 물려주지 않는다.
|
||||
사라진 갈래의 번호는 **비워 둔 채 다시 쓰지 않는다** — 옛 일위대가가 가리키던 자리다.
|
||||
"""
|
||||
issued_on = issued_on or date.today().isoformat()
|
||||
newly: list[dict[str, str]] = []
|
||||
for node in sorted(nodes, key=lambda n: n["sort_order"]):
|
||||
raw = node.get("variant_keys") or []
|
||||
if not raw:
|
||||
node["variants"] = []
|
||||
continue
|
||||
# ⚠ 갈래가 하나도 없으면 장부에 빈 칸을 만들지 않는다 — 건설처럼 아직 갈래가 없는 벌에
|
||||
# 빈 `variants` 가 생기면 이름표가 「있는데 이름이 없는 표」로 잡는다.
|
||||
book = registry.setdefault("variants", {})
|
||||
entry = book.setdefault(node["work_item_key"], {"next_serial": 1, "slots": {}})
|
||||
variants = []
|
||||
for text in raw:
|
||||
slot = variant_match(text)
|
||||
serial = entry["slots"].get(slot)
|
||||
if serial is None:
|
||||
serial = format_variant(entry["next_serial"])
|
||||
entry["next_serial"] += 1
|
||||
entry["slots"][slot] = serial
|
||||
newly.append(
|
||||
{
|
||||
"variant_key": f"{node['work_item_key']}#{serial}",
|
||||
"name": text,
|
||||
"issued_on": issued_on,
|
||||
}
|
||||
)
|
||||
variants.append(
|
||||
{
|
||||
"variant_key": serial,
|
||||
"name": text, # 원문 그대로 — 손대지 않는다
|
||||
"name_clean": variant_display(text), # 다듬은 것
|
||||
}
|
||||
)
|
||||
node["variants"] = variants
|
||||
return newly
|
||||
|
||||
|
||||
def path_names(nodes: list[dict[str, Any]]) -> list[str]:
|
||||
"""`["토공 › 토사깍기 › 인력", …]` — `nodes` 차례에 맞춘 전체 경로 이름.
|
||||
|
||||
|
||||
@@ -91,17 +91,19 @@ def base_rows(kind: str) -> list[dict[str, Any]]:
|
||||
)
|
||||
key = _key(item)
|
||||
# 갈래마다 한 줄 — 일위대가가 갈래마다 달라 집는 단위가 갈래임(교목굴취 나무높이 9 · 2026-09-17 브레인 ③).
|
||||
# 열쇠 = 공종 열쇠#갈래 키(B08·B09 `코드#갈래` 꼴) · 갈래 키 글자는 마스터 것 그대로(조립 두 벌 금지).
|
||||
for variant in item.get("variant_keys") or [None]:
|
||||
# 열쇠 = `공종 열쇠#갈래 번호`(`FW-00105#01`) — **갈래 글자를 열쇠에 담지 않는다.**
|
||||
# 담으면 원문 자간·물결표가 다듬어지는 날 열쇠가 갈린다(2026-09-17 브레인 · 장부가 번호를 준다).
|
||||
for variant in item.get("variants") or [None]:
|
||||
rows.append(
|
||||
{
|
||||
"@id": f"{key}#{variant}" if variant else key,
|
||||
"@id": f"{key}#{variant['variant_key']}" if variant else key,
|
||||
"@key": key, # 공종 열쇠 — 거르기·줄 수는 공종 단위로
|
||||
"@source": name,
|
||||
"work_item_code": item["work_item_code"], # 목차 코드 — 열쇠 아님, 칸으로만
|
||||
"number": item["number"],
|
||||
"name": _path(item, by),
|
||||
"variant": variant,
|
||||
"variant": variant["name"] if variant else None, # 원문 그대로
|
||||
"variant_clean": variant["name_clean"] if variant else None, # 다듬은 것
|
||||
"pum_tables": [t["pum_table_id"] for t in item["tables"]],
|
||||
"rule": (named.get(f"work_item_master::{parent.get('parent_mode')}") or {}).get(
|
||||
"name_ko"
|
||||
|
||||
@@ -1395,6 +1395,13 @@
|
||||
"visible": true,
|
||||
"note": "갈래마다 한 줄(일위대가가 갈래마다 다름) — 줄 열쇠는 공종 열쇠#갈래."
|
||||
},
|
||||
{
|
||||
"key": "variant_clean",
|
||||
"name_ko": "갈래(다듬은 것)",
|
||||
"unit": "",
|
||||
"visible": false,
|
||||
"note": "자간 공백을 한 칸으로 · 물결표를 하나로. 열쇠는 글자가 아니라 번호(`#01`)다."
|
||||
},
|
||||
{
|
||||
"key": "pum_tables",
|
||||
"name_ko": "딸린 품셈 표",
|
||||
@@ -1473,6 +1480,13 @@
|
||||
"visible": true,
|
||||
"note": "갈래마다 한 줄(일위대가가 갈래마다 다름) — 줄 열쇠는 공종 열쇠#갈래."
|
||||
},
|
||||
{
|
||||
"key": "variant_clean",
|
||||
"name_ko": "갈래(다듬은 것)",
|
||||
"unit": "",
|
||||
"visible": false,
|
||||
"note": "자간 공백을 한 칸으로 · 물결표를 하나로. 열쇠는 글자가 아니라 번호(`#01`)다."
|
||||
},
|
||||
{
|
||||
"key": "pum_tables",
|
||||
"name_ko": "딸린 품셈 표",
|
||||
@@ -1960,10 +1974,10 @@
|
||||
},
|
||||
"counts": {
|
||||
"merged_tables": 17,
|
||||
"merged_columns": 176,
|
||||
"merged_columns": 178,
|
||||
"files": 41,
|
||||
"tables": 100,
|
||||
"columns": 534,
|
||||
"tables": 101,
|
||||
"columns": 540,
|
||||
"value_groups": 203,
|
||||
"unknown": 0,
|
||||
"value_groups_by_kind": {
|
||||
@@ -2245,6 +2259,12 @@
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "variants",
|
||||
"name_ko": "갈래(열쇠·이름)",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "steps",
|
||||
"name_ko": "단계 합산 구성",
|
||||
@@ -7143,6 +7163,12 @@
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "variants",
|
||||
"name_ko": "갈래(열쇠·이름)",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "work_item_key",
|
||||
"name_ko": "공종 열쇠",
|
||||
@@ -7385,6 +7411,34 @@
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "variants",
|
||||
"name_ko": "갈래 열쇠 장부",
|
||||
"summary": "공종 열쇠 아래 갈래마다 번호를 매긴 것. 사라진 갈래의 번호는 다시 쓰지 않는다.",
|
||||
"shape": "map",
|
||||
"rows": 66,
|
||||
"columns": [
|
||||
{
|
||||
"key": "@key",
|
||||
"name_ko": "갈래를 지닌 산림 공종",
|
||||
"unit": "",
|
||||
"visible": true,
|
||||
"is_row_key": true
|
||||
},
|
||||
{
|
||||
"key": "next_serial",
|
||||
"name_ko": "다음 갈래 번호",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "slots",
|
||||
"name_ko": "갈래 자리→번호",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"value_groups": [
|
||||
@@ -7675,6 +7729,12 @@
|
||||
"name_ko": "줄 구실 셈",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"key": "settled_note",
|
||||
"name_ko": "확정 덧말",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8368,11 +8428,21 @@
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"name_clean": {
|
||||
"name_ko": "다듬은 이름",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"needs": {
|
||||
"name_ko": "있어야 열리는 것",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"next_serial": {
|
||||
"name_ko": "다음 일련번호",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"note": {
|
||||
"name_ko": "비고",
|
||||
"unit": "",
|
||||
@@ -8698,6 +8768,11 @@
|
||||
"unit": "byte",
|
||||
"visible": false
|
||||
},
|
||||
"slots": {
|
||||
"name_ko": "갈래 자리→번호",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"soil_type": {
|
||||
"name_ko": "토질",
|
||||
"unit": "",
|
||||
@@ -8863,11 +8938,21 @@
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variant_clean": {
|
||||
"name_ko": "갈래(다듬은 것)",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variant_from": {
|
||||
"name_ko": "갈래 원본 칸",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variant_key": {
|
||||
"name_ko": "갈래 번호",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variant_keys": {
|
||||
"name_ko": "갈래 키",
|
||||
"unit": "",
|
||||
@@ -8893,6 +8978,11 @@
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variants": {
|
||||
"name_ko": "갈래",
|
||||
"unit": "",
|
||||
"visible": true
|
||||
},
|
||||
"variation_coefficient": {
|
||||
"name_ko": "변동계수",
|
||||
"unit": "%",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-17T17:19:56+09:00",
|
||||
"generated_at": "2026-09-17T18:21:40+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_forest",
|
||||
@@ -12,8 +12,8 @@
|
||||
"files": [
|
||||
{
|
||||
"file": "work_item_master_2026-01-01.json",
|
||||
"sha256": "aa065ec629bde8af403cf9246e0ef65d1870da80c6eaea14f26c06a5cd5563d5",
|
||||
"size_bytes": 870603
|
||||
"sha256": "1cae4b3cdba4b7c13b1d0e7854a2754da3bda9402754263e801287fe20d019c7",
|
||||
"size_bytes": 925084
|
||||
},
|
||||
{
|
||||
"file": "form_undetermined_2026-01-01.json",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-17T17:19:56+09:00",
|
||||
"generated_at": "2026-09-17T18:21:40+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_const",
|
||||
@@ -12,8 +12,8 @@
|
||||
"files": [
|
||||
{
|
||||
"file": "const_work_item_master_2026-01-01.json",
|
||||
"sha256": "4f7d61f283d07626501ff0ca0a0446aa99a118980360e4fdcac802899e174086",
|
||||
"size_bytes": 3752575
|
||||
"sha256": "52ac9f352106e61cbb0d548763808f967afb152e17eb6dce4a1cd1dd51f59e7d",
|
||||
"size_bytes": 3780649
|
||||
},
|
||||
{
|
||||
"file": "const_form_undetermined_2026-01-01.json",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
"const": {
|
||||
"name_ko": "건설 공종",
|
||||
"settled": false,
|
||||
"settled": true,
|
||||
"source": "resources/data_cost_input_value/pum_const_2026.json",
|
||||
"toc_source": "합본 원문 머리 「목 차」 글줄 — 목차표가 없어 랩탑 메인이 글에서 읽음(부문 5 · 장 45 · 1,367줄)",
|
||||
"code_prefix": "CP",
|
||||
@@ -82,26 +82,11 @@
|
||||
"code_shape": "CP-<부문2>-<장2>-<절…>",
|
||||
"code_shape_why": "⚠ **부문마다 장 번호가 1부터 다시 시작한다** — 공통 1장은 적용기준, 토목 1장은 도로포장공사다. 부문 자리가 없으면 부문이 다른 공종끼리 덮는다(산림에서 목차 번호 겹침 둘이 실제로 덮고 있었다).",
|
||||
"general_provision_roots": [
|
||||
"01_공통부문/제1장_적용기준.md"
|
||||
],
|
||||
"general_provision_basis": "공통부문 제1장 적용기준(`CP-01-01`) — 줄 37 · 표 46. 산림 FP-01 적용기준과 짝. 단위표준·토질·할증 같은 기준표다.",
|
||||
"general_provision_pending": [
|
||||
{
|
||||
"chapter": "01_공통부문/제8장_건설기계.md",
|
||||
"code": "CP-01-08",
|
||||
"rows": 75,
|
||||
"tables": 351,
|
||||
"why": "산림 FP-02 「소요재료 및 기계손료」와 짝으로 보이나, 기계 시공능력·손료 파라미터라 공종으로 볼 여지도 있음. ⬜ 안티그래비티 조사 대기.",
|
||||
"already_extracted": "C0426·C0427 은 `resources/data_machine_productivity/` 로 이미 꺼냈음"
|
||||
},
|
||||
{
|
||||
"chapter": "05_유지관리부문/제1장_공통.md",
|
||||
"code": "CP-05-01",
|
||||
"rows": 37,
|
||||
"tables": 40,
|
||||
"why": "이름이 「공 통」 — 기준표 장인지 공종 장인지 원문 확인 필요. ⬜ 안티그래비티 조사 대기."
|
||||
}
|
||||
"01_공통부문/제1장_적용기준.md",
|
||||
"01_공통부문/제8장_건설기계.md"
|
||||
],
|
||||
"general_provision_basis": "공통부문 제1장 적용기준(`CP-01-01`) 줄 37 · 표 46 — 산림 FP-01 과 짝. 공통부문 제8장 건설기계(`CP-01-08`) 줄 75 · 표 351 — 산림 FP-02(소요재료 및 기계손료)와 짝. 시공능력·손료 파라미터라 값을 정하는 자리다(C0426·C0427 은 이미 기초데이터로 꺼냈다). 2026-09-17 안티그래비티 조사 · 브레인 확정.",
|
||||
"general_provision_pending": [],
|
||||
"known_defects": [
|
||||
"형태 미판정 881 / 2,192 — B09 표 읽기가 산림 표로만 검증됨",
|
||||
"밑수 미확보 447 — 곱하면 안 되는 줄이라 받는 쪽이 가려야 함",
|
||||
@@ -115,7 +100,8 @@
|
||||
"general_provision": 0,
|
||||
"empty": 100,
|
||||
"note": "총칙 표시 전 셈(랩탑 메인 첫 산출). 뿌리를 붙이면 `general_provision` 으로 옮겨 간다 — 줄이 줄지는 않는다."
|
||||
}
|
||||
},
|
||||
"settled_note": "유지관리부문 제1장 「공 통」(`CP-05-01`) 표 40 은 **공종**으로 둔다 — 총칙이 아니다(2026-09-17 안티그래비티 조사 · 브레인 확정)."
|
||||
}
|
||||
},
|
||||
"list_default": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3833,5 +3833,672 @@
|
||||
"first_toc_number": "14-2",
|
||||
"first_name": "근주이식"
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"FW-00097": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"5m미만": "01",
|
||||
"5m이상∼8m미만": "02",
|
||||
"8m이상": "03"
|
||||
}
|
||||
},
|
||||
"FW-00104": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"0.3m미만": "01",
|
||||
"0.3∼0.7m이하": "02",
|
||||
"0.8∼1.1m이하": "03",
|
||||
"1.2∼1.5m이하": "04"
|
||||
}
|
||||
},
|
||||
"FW-00105": {
|
||||
"next_serial": 10,
|
||||
"slots": {
|
||||
"1.0이하": "01",
|
||||
"1.1∼1.5": "02",
|
||||
"1.6∼2.0": "03",
|
||||
"2.1∼2.5": "04",
|
||||
"2.6∼3.0": "05",
|
||||
"3.1∼3.5": "06",
|
||||
"3.6∼4.0": "07",
|
||||
"4.1∼4.5": "08",
|
||||
"4.6∼5.0": "09"
|
||||
}
|
||||
},
|
||||
"FW-00107": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"줄떼": "01",
|
||||
"평떼": "02"
|
||||
}
|
||||
},
|
||||
"FW-00112": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"0.3m미만": "01",
|
||||
"0.3∼0.7m이하": "02",
|
||||
"0.8∼1.1m이하": "03",
|
||||
"1.2∼1.5m이하": "04"
|
||||
}
|
||||
},
|
||||
"FW-00113": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"0.3m미만": "01",
|
||||
"0.3∼0.7m이하": "02",
|
||||
"0.8∼1.1m이하": "03",
|
||||
"1.2∼1.5m이하": "04"
|
||||
}
|
||||
},
|
||||
"FW-00125": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"줄떼심기": "01",
|
||||
"띠떼심기": "02"
|
||||
}
|
||||
},
|
||||
"FW-00129": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"보통토사": "01",
|
||||
"경질ㆍ고사점토및자갈섞인점토": "02",
|
||||
"호박돌섞인토사": "03"
|
||||
}
|
||||
},
|
||||
"FW-00139": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"채취": "01",
|
||||
"운반": "02",
|
||||
"붙이기": "03"
|
||||
}
|
||||
},
|
||||
"FW-00160": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"폭1.5m이하": "01",
|
||||
"폭2.0m이하": "02"
|
||||
}
|
||||
},
|
||||
"FW-00171": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"1,500본미만": "01",
|
||||
"1,500본이상3,000본미만": "02",
|
||||
"3,000본이상": "03"
|
||||
}
|
||||
},
|
||||
"FW-00172": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"조림당해연도(전년도추기조림포함)": "01",
|
||||
"조림2년차": "02",
|
||||
"조림3년차이상": "03"
|
||||
}
|
||||
},
|
||||
"FW-00234": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"소형헬기(160ha당)": "01",
|
||||
"대형헬기(400ha당)": "02"
|
||||
}
|
||||
},
|
||||
"FW-00236": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"차량살포(동력분무기)": "01"
|
||||
}
|
||||
},
|
||||
"FW-00242": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"1㎥": "01",
|
||||
"2㎥": "02"
|
||||
}
|
||||
},
|
||||
"FW-00250": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"연암": "01",
|
||||
"보통암": "02",
|
||||
"경암": "03",
|
||||
"평균": "04"
|
||||
}
|
||||
},
|
||||
"FW-00251": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"연암": "01",
|
||||
"보통암": "02",
|
||||
"경암": "03",
|
||||
"평균": "04"
|
||||
}
|
||||
},
|
||||
"FW-00253": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"연암": "01",
|
||||
"보통암": "02",
|
||||
"경암": "03"
|
||||
}
|
||||
},
|
||||
"FW-00255": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"연암": "01",
|
||||
"보통암": "02",
|
||||
"경암": "03"
|
||||
}
|
||||
},
|
||||
"FW-00309": {
|
||||
"next_serial": 11,
|
||||
"slots": {
|
||||
"절토면·모래ㆍ사질토ㆍ점토ㆍ점질토": "01",
|
||||
"절토면·연질토ㆍ불순자갈": "02",
|
||||
"절토면·호박돌섞인고결토ㆍ경질토": "03",
|
||||
"절토면·풍화암": "04",
|
||||
"절토면·연암": "05",
|
||||
"절토면·보통암ㆍ경암": "06",
|
||||
"성토면·인력·점토또는점질토": "07",
|
||||
"성토면·인력·모래또는사질토": "08",
|
||||
"성토면·기계·무한궤도": "09",
|
||||
"성토면·기계·타이어": "10"
|
||||
}
|
||||
},
|
||||
"FW-00315": {
|
||||
"next_serial": 7,
|
||||
"slots": {
|
||||
"굴착기(무한궤도)0.2·소": "01",
|
||||
"굴착기(무한궤도)0.2·중": "02",
|
||||
"굴착기(무한궤도)0.2·밀": "03",
|
||||
"굴착기(무한궤도)0.7·소": "04",
|
||||
"굴착기(무한궤도)0.7·중": "05",
|
||||
"굴착기(무한궤도)0.7·밀": "06"
|
||||
}
|
||||
},
|
||||
"FW-00344": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"토사": "01",
|
||||
"파쇄암": "02",
|
||||
"발파암": "03"
|
||||
}
|
||||
},
|
||||
"FW-00353": {
|
||||
"next_serial": 21,
|
||||
"slots": {
|
||||
"길이3M·폭2.4M": "01",
|
||||
"길이3M·폭3.0M": "02",
|
||||
"길이3M·폭3.5M": "03",
|
||||
"길이3M·폭4.8M": "04",
|
||||
"길이3M·폭6.0M": "05",
|
||||
"길이6M·폭2.4M": "06",
|
||||
"길이6M·폭3.0M": "07",
|
||||
"길이6M·폭3.5M": "08",
|
||||
"길이6M·폭4.8M": "09",
|
||||
"길이6M·폭6.0M": "10",
|
||||
"길이9M·폭2.4M": "11",
|
||||
"길이9M·폭3.0M": "12",
|
||||
"길이9M·폭3.5M": "13",
|
||||
"길이9M·폭4.8M": "14",
|
||||
"길이9M·폭6.0M": "15",
|
||||
"길이12M·폭2.4M": "16",
|
||||
"길이12M·폭3.0M": "17",
|
||||
"길이12M·폭3.5M": "18",
|
||||
"길이12M·폭4.8M": "19",
|
||||
"길이12M·폭6.0M": "20"
|
||||
}
|
||||
},
|
||||
"FW-00359": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"무근구조물": "01",
|
||||
"철근구조물": "02",
|
||||
"소형구조물": "03"
|
||||
}
|
||||
},
|
||||
"FW-00360": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"무근구조물": "01",
|
||||
"철근구조물": "02",
|
||||
"소형구조물": "03"
|
||||
}
|
||||
},
|
||||
"FW-00361": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"무근구조물": "01",
|
||||
"철근구조물": "02",
|
||||
"소형구조물": "03"
|
||||
}
|
||||
},
|
||||
"FW-00363": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"간단": "01",
|
||||
"보통": "02",
|
||||
"복잡": "03",
|
||||
"매우복잡": "04"
|
||||
}
|
||||
},
|
||||
"FW-00364": {
|
||||
"next_serial": 7,
|
||||
"slots": {
|
||||
"1회": "01",
|
||||
"2회": "02",
|
||||
"3회": "03",
|
||||
"4회": "04",
|
||||
"5회": "05",
|
||||
"6회": "06"
|
||||
}
|
||||
},
|
||||
"FW-00366": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"20㎝": "01",
|
||||
"30㎝": "02",
|
||||
"40㎝": "03"
|
||||
}
|
||||
},
|
||||
"FW-00377": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"∅800mm": "01",
|
||||
"∅1000mm": "02",
|
||||
"∅1200mm": "03"
|
||||
}
|
||||
},
|
||||
"FW-00378": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"∅800mm": "01",
|
||||
"∅1000mm": "02",
|
||||
"∅1200mm": "03"
|
||||
}
|
||||
},
|
||||
"FW-00379": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"∅800mm": "01",
|
||||
"∅1000mm": "02",
|
||||
"∅1200mm": "03"
|
||||
}
|
||||
},
|
||||
"FW-00380": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"콘크리트": "01"
|
||||
}
|
||||
},
|
||||
"FW-00381": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"콘크리트": "01"
|
||||
}
|
||||
},
|
||||
"FW-00383": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"구체콘크리트": "01",
|
||||
"버림콘크리트": "02"
|
||||
}
|
||||
},
|
||||
"FW-00384": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"구체콘크리트": "01",
|
||||
"버림콘크리트": "02"
|
||||
}
|
||||
},
|
||||
"FW-00386": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"무근콘크리트": "01",
|
||||
"철근콘크리트": "02",
|
||||
"설치": "03",
|
||||
"철거": "04"
|
||||
}
|
||||
},
|
||||
"FW-00396": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"뒷채움자재비및운반비별산": "01"
|
||||
}
|
||||
},
|
||||
"FW-00397": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"뒷채움자재비및운반비별산": "01"
|
||||
}
|
||||
},
|
||||
"FW-00420": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"간단": "01",
|
||||
"보통": "02",
|
||||
"복잡": "03"
|
||||
}
|
||||
},
|
||||
"FW-00422": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"간단": "01",
|
||||
"보통": "02",
|
||||
"복잡": "03"
|
||||
}
|
||||
},
|
||||
"FW-00423": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"복잡": "01",
|
||||
"보통": "02",
|
||||
"간단": "03"
|
||||
}
|
||||
},
|
||||
"FW-00428": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"㎡당": "01",
|
||||
"㎥당": "02"
|
||||
}
|
||||
},
|
||||
"FW-00430": {
|
||||
"next_serial": 11,
|
||||
"slots": {
|
||||
"25㎝·㎡당": "01",
|
||||
"35㎝·㎡당": "02",
|
||||
"45㎝·㎡당": "03",
|
||||
"55㎝·㎡당": "04",
|
||||
"60㎝·㎡당": "05",
|
||||
"25㎝·㎥당": "06",
|
||||
"35㎝·㎥당": "07",
|
||||
"45㎝·㎥당": "08",
|
||||
"55㎝·㎥당": "09",
|
||||
"60㎝·㎥당": "10"
|
||||
}
|
||||
},
|
||||
"FW-00431": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"35cm이하": "01",
|
||||
"55cm이하": "02",
|
||||
"75cm이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00432": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"두께3㎝": "01",
|
||||
"두께6㎝": "02",
|
||||
"자갈기초다짐지름1∼3㎝": "03"
|
||||
}
|
||||
},
|
||||
"FW-00435": {
|
||||
"next_serial": 41,
|
||||
"slots": {
|
||||
"깬잡석·골쌓기·뒷길이25㎝": "01",
|
||||
"깬잡석·켜쌓기·뒷길이25㎝": "02",
|
||||
"호박돌및야면석·뒷길이25㎝": "03",
|
||||
"깬돌·골쌓기·뒷길이30㎝": "04",
|
||||
"깬돌·켜쌓기·뒷길이30㎝": "05",
|
||||
"깬잡석·골쌓기·뒷길이30㎝": "06",
|
||||
"깬잡석·켜쌓기·뒷길이30㎝": "07",
|
||||
"호박돌및야면석·뒷길이30㎝": "08",
|
||||
"견치돌·골쌓기·뒷길이35㎝": "09",
|
||||
"견치돌·켜쌓기·뒷길이35㎝": "10",
|
||||
"깬돌·골쌓기·뒷길이35㎝": "11",
|
||||
"깬돌·켜쌓기·뒷길이35㎝": "12",
|
||||
"깬잡석·골쌓기·뒷길이35㎝": "13",
|
||||
"깬잡석·켜쌓기·뒷길이35㎝": "14",
|
||||
"호박돌및야면석·뒷길이35㎝": "15",
|
||||
"견치돌·골쌓기·뒷길이45㎝": "16",
|
||||
"견치돌·켜쌓기·뒷길이45㎝": "17",
|
||||
"깬돌·골쌓기·뒷길이45㎝": "18",
|
||||
"깬돌·켜쌓기·뒷길이45㎝": "19",
|
||||
"깬잡석·골쌓기·뒷길이45㎝": "20",
|
||||
"깬잡석·켜쌓기·뒷길이45㎝": "21",
|
||||
"호박돌및야면석·뒷길이45㎝": "22",
|
||||
"견치돌·골쌓기·뒷길이55㎝": "23",
|
||||
"견치돌·켜쌓기·뒷길이55㎝": "24",
|
||||
"깬돌·골쌓기·뒷길이55㎝": "25",
|
||||
"깬돌·켜쌓기·뒷길이55㎝": "26",
|
||||
"깬잡석·골쌓기·뒷길이55㎝": "27",
|
||||
"깬잡석·켜쌓기·뒷길이55㎝": "28",
|
||||
"호박돌및야면석·뒷길이55㎝": "29",
|
||||
"견치돌·골쌓기·뒷길이60㎝": "30",
|
||||
"견치돌·켜쌓기·뒷길이60㎝": "31",
|
||||
"깬돌·골쌓기·뒷길이60㎝": "32",
|
||||
"깬돌·켜쌓기·뒷길이60㎝": "33",
|
||||
"깬잡석·골쌓기·뒷길이60㎝": "34",
|
||||
"깬잡석·켜쌓기·뒷길이60㎝": "35",
|
||||
"호박돌및야면석·뒷길이60㎝": "36",
|
||||
"깬돌·골쌓기·뒷길이75㎝": "37",
|
||||
"깬돌·켜쌓기·뒷길이75㎝": "38",
|
||||
"깬잡석·골쌓기·뒷길이75㎝": "39",
|
||||
"깬잡석·켜쌓기·뒷길이75㎝": "40"
|
||||
}
|
||||
},
|
||||
"FW-00436": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"35cm이하": "01",
|
||||
"55cm이하": "02",
|
||||
"75cm이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00438": {
|
||||
"next_serial": 41,
|
||||
"slots": {
|
||||
"깬잡석·골쌓기·뒷길이25㎝": "01",
|
||||
"깬잡석·켜쌓기·뒷길이25㎝": "02",
|
||||
"호박돌및야면석·뒷길이25㎝": "03",
|
||||
"깬돌·골쌓기·뒷길이30㎝": "04",
|
||||
"깬돌·켜쌓기·뒷길이30㎝": "05",
|
||||
"깬잡석·골쌓기·뒷길이30㎝": "06",
|
||||
"깬잡석·켜쌓기·뒷길이30㎝": "07",
|
||||
"호박돌및야면석·뒷길이30㎝": "08",
|
||||
"견치돌·골쌓기·뒷길이35㎝": "09",
|
||||
"견치돌·켜쌓기·뒷길이35㎝": "10",
|
||||
"깬돌·골쌓기·뒷길이35㎝": "11",
|
||||
"깬돌·켜쌓기·뒷길이35㎝": "12",
|
||||
"깬잡석·골쌓기·뒷길이35㎝": "13",
|
||||
"깬잡석·켜쌓기·뒷길이35㎝": "14",
|
||||
"호박돌및야면석·뒷길이35㎝": "15",
|
||||
"견치돌·골쌓기·뒷길이45㎝": "16",
|
||||
"견치돌·켜쌓기·뒷길이45㎝": "17",
|
||||
"깬돌·골쌓기·뒷길이45㎝": "18",
|
||||
"깬돌·켜쌓기·뒷길이45㎝": "19",
|
||||
"깬잡석·골쌓기·뒷길이45㎝": "20",
|
||||
"깬잡석·켜쌓기·뒷길이45㎝": "21",
|
||||
"호박돌및야면석·뒷길이45㎝": "22",
|
||||
"견치돌·골쌓기·뒷길이55㎝": "23",
|
||||
"견치돌·켜쌓기·뒷길이55㎝": "24",
|
||||
"깬돌·골쌓기·뒷길이55㎝": "25",
|
||||
"깬돌·켜쌓기·뒷길이55㎝": "26",
|
||||
"깬잡석·골쌓기·뒷길이55㎝": "27",
|
||||
"깬잡석·켜쌓기·뒷길이55㎝": "28",
|
||||
"호박돌및야면석·뒷길이55㎝": "29",
|
||||
"견치돌·골쌓기·뒷길이60㎝": "30",
|
||||
"견치돌·켜쌓기·뒷길이60㎝": "31",
|
||||
"깬돌·골쌓기·뒷길이60㎝": "32",
|
||||
"깬돌·켜쌓기·뒷길이60㎝": "33",
|
||||
"깬잡석·골쌓기·뒷길이60㎝": "34",
|
||||
"깬잡석·켜쌓기·뒷길이60㎝": "35",
|
||||
"호박돌및야면석·뒷길이60㎝": "36",
|
||||
"깬돌·골쌓기·뒷길이75㎝": "37",
|
||||
"깬돌·켜쌓기·뒷길이75㎝": "38",
|
||||
"깬잡석·골쌓기·뒷길이75㎝": "39",
|
||||
"깬잡석·켜쌓기·뒷길이75㎝": "40"
|
||||
}
|
||||
},
|
||||
"FW-00439": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"35cm이하": "01",
|
||||
"55cm이하": "02",
|
||||
"75cm이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00440": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"25㎝": "01",
|
||||
"30㎝": "02",
|
||||
"35㎝": "03"
|
||||
}
|
||||
},
|
||||
"FW-00442": {
|
||||
"next_serial": 41,
|
||||
"slots": {
|
||||
"메붙임·깬돌·뒷길이25㎝": "01",
|
||||
"메붙임·깬돌·뒷길이30㎝": "02",
|
||||
"메붙임·깬돌·뒷길이35㎝": "03",
|
||||
"메붙임·깬돌·뒷길이45㎝": "04",
|
||||
"메붙임·깬돌·뒷길이55㎝": "05",
|
||||
"메붙임·깬돌·뒷길이60㎝": "06",
|
||||
"메붙임·깬돌·뒷길이70㎝": "07",
|
||||
"메붙임·깬잡석·뒷길이25㎝": "08",
|
||||
"메붙임·깬잡석·뒷길이30㎝": "09",
|
||||
"메붙임·깬잡석·뒷길이35㎝": "10",
|
||||
"메붙임·깬잡석·뒷길이45㎝": "11",
|
||||
"메붙임·깬잡석·뒷길이55㎝": "12",
|
||||
"메붙임·깬잡석·뒷길이60㎝": "13",
|
||||
"메붙임·깬잡석·뒷길이70㎝": "14",
|
||||
"메붙임·조약돌및야면석·뒷길이25㎝": "15",
|
||||
"메붙임·조약돌및야면석·뒷길이30㎝": "16",
|
||||
"메붙임·조약돌및야면석·뒷길이35㎝": "17",
|
||||
"메붙임·조약돌및야면석·뒷길이45㎝": "18",
|
||||
"메붙임·조약돌및야면석·뒷길이55㎝": "19",
|
||||
"메붙임·조약돌및야면석·뒷길이60㎝": "20",
|
||||
"찰붙임·깬돌·뒷길이25㎝": "21",
|
||||
"찰붙임·깬돌·뒷길이30㎝": "22",
|
||||
"찰붙임·깬돌·뒷길이35㎝": "23",
|
||||
"찰붙임·깬돌·뒷길이45㎝": "24",
|
||||
"찰붙임·깬돌·뒷길이55㎝": "25",
|
||||
"찰붙임·깬돌·뒷길이60㎝": "26",
|
||||
"찰붙임·깬돌·뒷길이70㎝": "27",
|
||||
"찰붙임·깬잡석·뒷길이25㎝": "28",
|
||||
"찰붙임·깬잡석·뒷길이30㎝": "29",
|
||||
"찰붙임·깬잡석·뒷길이35㎝": "30",
|
||||
"찰붙임·깬잡석·뒷길이45㎝": "31",
|
||||
"찰붙임·깬잡석·뒷길이55㎝": "32",
|
||||
"찰붙임·깬잡석·뒷길이60㎝": "33",
|
||||
"찰붙임·깬잡석·뒷길이70㎝": "34",
|
||||
"찰붙임·호박돌및야면석·뒷길이25㎝": "35",
|
||||
"찰붙임·호박돌및야면석·뒷길이30㎝": "36",
|
||||
"찰붙임·호박돌및야면석·뒷길이35㎝": "37",
|
||||
"찰붙임·호박돌및야면석·뒷길이45㎝": "38",
|
||||
"찰붙임·호박돌및야면석·뒷길이55㎝": "39",
|
||||
"찰붙임·호박돌및야면석·뒷길이60㎝": "40"
|
||||
}
|
||||
},
|
||||
"FW-00443": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"35cm이하": "01",
|
||||
"55cm이하": "02",
|
||||
"75cm이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00445": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"직경40㎝이상∼60㎝미만": "01",
|
||||
"직경60㎝이상∼80㎝미만": "02",
|
||||
"직경80㎝이상∼100㎝이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00446": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"직경40㎝이상∼60㎝미만": "01",
|
||||
"직경60㎝이상∼80㎝미만": "02",
|
||||
"직경80㎝이상∼100㎝이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00447": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"직경40㎝이상∼60㎝미만": "01",
|
||||
"직경60㎝이상∼80㎝미만": "02",
|
||||
"직경80㎝이상∼100㎝이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00449": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"직경40㎝이상∼60㎝미만": "01",
|
||||
"직경60㎝이상∼80㎝미만": "02",
|
||||
"직경80㎝이상∼100㎝이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00450": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"직경40㎝이상∼60㎝미만": "01",
|
||||
"직경60㎝이상∼80㎝미만": "02",
|
||||
"직경80㎝이상∼100㎝이하": "03"
|
||||
}
|
||||
},
|
||||
"FW-00454": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"직경15㎝길이4m": "01"
|
||||
}
|
||||
},
|
||||
"FW-00465": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"중": "01",
|
||||
"상등구조": "02"
|
||||
}
|
||||
},
|
||||
"FW-00466": {
|
||||
"next_serial": 5,
|
||||
"slots": {
|
||||
"식생매트설치": "01",
|
||||
"복토": "02",
|
||||
"간단구조": "03",
|
||||
"보통구조": "04"
|
||||
}
|
||||
},
|
||||
"FW-00467": {
|
||||
"next_serial": 4,
|
||||
"slots": {
|
||||
"단끊기": "01",
|
||||
"흙채우기(마대채우기)": "02",
|
||||
"마대쌓기": "03"
|
||||
}
|
||||
},
|
||||
"FW-00473": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"사면": "01",
|
||||
"연약지반": "02"
|
||||
}
|
||||
},
|
||||
"FW-00474": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"폭1.5m이하": "01",
|
||||
"폭2.0m이하": "02"
|
||||
}
|
||||
},
|
||||
"FW-00476": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"무한궤도": "01",
|
||||
"타이어": "02"
|
||||
}
|
||||
},
|
||||
"FW-00477": {
|
||||
"next_serial": 3,
|
||||
"slots": {
|
||||
"무한궤도": "01",
|
||||
"타이어": "02"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,11 +27,14 @@ from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Keys import ( # noqa: E402
|
||||
assign_keys,
|
||||
axis_role,
|
||||
empty_registry,
|
||||
assign_variant_keys,
|
||||
format_key,
|
||||
general_provision_roots,
|
||||
load_policy,
|
||||
path_names,
|
||||
toc_edition,
|
||||
variant_display,
|
||||
variant_match,
|
||||
toc_slot,
|
||||
)
|
||||
|
||||
@@ -55,6 +58,7 @@ ADDED_FIELDS = (
|
||||
"toc_edition",
|
||||
"path_name",
|
||||
"axis_role",
|
||||
"variants",
|
||||
)
|
||||
|
||||
|
||||
@@ -223,11 +227,15 @@ def test_총칙_범위는_코드가_아니라_자료가_정함() -> None:
|
||||
assert general_provision_roots("forest") == ("FP-01", "FP-02")
|
||||
const = load_policy("const")
|
||||
assert const["key_prefix"] == "CW"
|
||||
assert const["settled"] is False
|
||||
assert const["settled"] is True # 2026-09-17 안티그래비티 조사 · 브레인 확정
|
||||
# 건설 뿌리는 **장 파일 이름**으로 적는다 — 뽑는 코드가 목차 코드로 바꿔 준다(랩탑 메인 `file_place`).
|
||||
# ⚠ 바뀐 코드에는 부문 자리가 들어간다(`CP-01-01`) — 부문마다 장 번호가 1부터 다시 시작해서다.
|
||||
assert const["general_provision_roots"] == ["01_공통부문/제1장_적용기준.md"]
|
||||
assert [p["code"] for p in const["general_provision_pending"]] == ["CP-01-08", "CP-05-01"]
|
||||
assert const["general_provision_roots"] == [
|
||||
"01_공통부문/제1장_적용기준.md",
|
||||
"01_공통부문/제8장_건설기계.md", # 산림 FP-02(소요재료·기계손료)와 짝
|
||||
]
|
||||
# 유지관리 제1장 「공 통」은 총칙이 아니라 **공종** — 미확정 목록이 비었다
|
||||
assert const["general_provision_pending"] == []
|
||||
# 뿌리를 바꿔 주면 구실도 따라 바뀐다 — 잣대가 자료에 있다는 증거
|
||||
assert (
|
||||
axis_role({"work_item_code": "FP-09-03", "tables": []}, has_children=True, roots=("FP-09",))
|
||||
@@ -241,18 +249,63 @@ def test_건설_총칙_뿌리가_실제로_붙음() -> None:
|
||||
(OUT_DIR / "const_work_item_master_2026-01-01.json").read_text(encoding="utf-8")
|
||||
)
|
||||
roles = doc["stats"]["axis_roles"]
|
||||
assert roles["general_provision"] == 37
|
||||
assert roles["general_provision"] == 112 # 적용기준 37 + 건설기계 75
|
||||
assert sum(roles.values()) == len(doc["work_items"]) == 1367
|
||||
under = [
|
||||
it
|
||||
for it in doc["work_items"]
|
||||
if it["work_item_code"] == "CP-01-01" or it["work_item_code"].startswith("CP-01-01-")
|
||||
]
|
||||
assert len(under) == 37
|
||||
assert {it["axis_role"] for it in under} == {"general_provision"}
|
||||
# ⬜ 미확정 둘은 아직 공종·묶음으로 서 있다 — 안티그래비티 답이 오면 뿌리에 더한다
|
||||
기계 = next(it for it in doc["work_items"] if it["work_item_code"] == "CP-01-08")
|
||||
assert 기계["axis_role"] != "general_provision"
|
||||
for root, count in (("CP-01-01", 37), ("CP-01-08", 75)):
|
||||
under = [
|
||||
it
|
||||
for it in doc["work_items"]
|
||||
if it["work_item_code"] == root or it["work_item_code"].startswith(root + "-")
|
||||
]
|
||||
assert len(under) == count
|
||||
assert {it["axis_role"] for it in under} == {"general_provision"}
|
||||
# 유지관리 제1장 「공 통」은 공종으로 남는다(총칙 아님)
|
||||
공통 = next(it for it in doc["work_items"] if it["work_item_code"] == "CP-05-01")
|
||||
assert 공통["axis_role"] != "general_provision"
|
||||
|
||||
|
||||
def test_갈래에도_불변_열쇠가_있다(master: dict) -> None:
|
||||
"""갈래 열쇠는 `FW-00105#01` — **글자가 아니라 번호**다(2026-09-17 브레인).
|
||||
|
||||
글자를 열쇠에 담으면 원문 자간·물결표가 다듬어지는 날 열쇠가 갈린다. 공종 열쇠와 같은 병이다.
|
||||
"""
|
||||
items = master["work_items"]
|
||||
keys, pairs = [], []
|
||||
for it in items:
|
||||
for v in it.get("variants") or []:
|
||||
assert re.fullmatch(r"\d{2}", v["variant_key"]), v
|
||||
keys.append(f"{it['work_item_key']}#{v['variant_key']}")
|
||||
pairs.append((v["name"], v["name_clean"]))
|
||||
assert len(keys) == 332 # 갈래 수 — 헛단위 13-3 갈래 3 뺌(335 → 332 · 2026-09-17 · 장부 번호는 남음)
|
||||
assert len(set(keys)) == len(keys) # 겹침 0
|
||||
# 한 공종 안에서 번호는 1부터 빠짐없이
|
||||
for it in items:
|
||||
got = [v["variant_key"] for v in it.get("variants") or []]
|
||||
assert got == [f"{i + 1:02d}" for i in range(len(got))], it["work_item_key"]
|
||||
# 이름 칸 둘 — 원문은 손대지 않고, 다듬은 것이 따로
|
||||
raw = [it.get("variant_keys") or [] for it in items]
|
||||
assert [n for it in items for n in (it.get("variant_keys") or [])] == [p[0] for p in pairs]
|
||||
assert sum(1 for a, b in pairs if a != b) == 14 # 자간·물결표가 다듬어진 줄
|
||||
assert raw # 원문 목록은 그대로 남아 있다
|
||||
|
||||
|
||||
def test_갈래_열쇠는_글자가_바뀌어도_안_흔들린다() -> None:
|
||||
"""맞대는 꼴이 공백·물결표를 흡수한다 — 이름 다듬기가 들어와도 번호가 그대로다."""
|
||||
reg = empty_registry()
|
||||
node = {
|
||||
"work_item_key": "FW-00105",
|
||||
"sort_order": 1,
|
||||
"variant_keys": ["1.1∼1.5", "간 단"],
|
||||
}
|
||||
assign_variant_keys([node], reg)
|
||||
before = [v["variant_key"] for v in node["variants"]]
|
||||
# 원문을 다듬어도(물결표 바꿈 · 자간 정리) 같은 번호가 나와야 한다
|
||||
node2 = {"work_item_key": "FW-00105", "sort_order": 1, "variant_keys": ["1.1~1.5", "간 단"]}
|
||||
newly = assign_variant_keys([node2], reg)
|
||||
assert [v["variant_key"] for v in node2["variants"]] == before
|
||||
assert newly == [] # 새 번호를 내지 않는다
|
||||
assert variant_match("간 단") == variant_match("간 단") == "간단"
|
||||
assert variant_display("직경 60㎝이상 ~80㎝미만") == "직경 60㎝이상 ∼80㎝미만"
|
||||
|
||||
|
||||
def test_갈래_문자열이_열쇠라_흔들림을_못박음(master: dict) -> None:
|
||||
|
||||
@@ -84,8 +84,8 @@ def test_트리_표_id_와_이름표_표_id_는_양쪽으로_같음(client: Test
|
||||
label_only += [f"{entry['file_id']}::{i}" for i in sorted(label_ids - tree_ids)]
|
||||
assert not_labelled == [], not_labelled
|
||||
assert label_only == [], label_only
|
||||
# 2026-09-17 92 → 100 — 공종 축 산출 일곱을 이름표에 올림.
|
||||
assert sum(len(t) for t in files.values()) == LABELS["counts"]["tables"] == 100
|
||||
# 2026-09-17 92 → 101 — 공종 축 산출 일곱 + 갈래 열쇠 장부 표.
|
||||
assert sum(len(t) for t in files.values()) == LABELS["counts"]["tables"] == 101
|
||||
for entry in LABELS["files"]: # 이름이 실제로 붙음 · 줄 수도 이름표 셈과 같음
|
||||
named = {t["key"]: t for t in entry["tables"]}
|
||||
for t in files[entry["file_id"]]:
|
||||
|
||||
@@ -102,7 +102,9 @@ def test_불변_열쇠가_오면_id_로_씀_자료_파일은_판_id_로_가림(
|
||||
"steps": [{"code": "CP-01-01", "weight": "0.5"}], "steps_basis": "시험", "variant_keys": []},
|
||||
{"work_item_code": "CP-01-01", "work_item_key": "CW-00002", "number": "1-1",
|
||||
"name": "인력", "parent_code": "CP-01", "tables": [{"pum_table_id": "C0001"}],
|
||||
"variant_keys": ["갑", "을"]},
|
||||
"variant_keys": ["갑", "을"],
|
||||
"variants": [{"variant_key": "01", "name": "갑", "name_clean": "갑"},
|
||||
{"variant_key": "02", "name": "을", "name_clean": "을"}]},
|
||||
],
|
||||
} # fmt: skip
|
||||
(folder / "const_work_item_master_2026-01-01.json").write_text(
|
||||
@@ -111,7 +113,8 @@ def test_불변_열쇠가_오면_id_로_씀_자료_파일은_판_id_로_가림(
|
||||
monkeypatch.setattr(work_items, "FOLDER", folder)
|
||||
|
||||
table = _get(client, "work_item_const")
|
||||
assert [r["@id"] for r in table["rows"]] == ["CW-00002#갑", "CW-00002#을"] # 갈래마다 한 줄
|
||||
# 갈래마다 한 줄 · 열쇠는 **글자가 아니라 번호**(2026-09-17 브레인 — 장부가 준다)
|
||||
assert [r["@id"] for r in table["rows"]] == ["CW-00002#01", "CW-00002#02"]
|
||||
assert {r["@key"] for r in table["rows"]} == {"CW-00002"}
|
||||
assert table["rows"][0]["work_item_code"] == "CP-01-01" # 목차 코드는 칸으로 남음
|
||||
assert table["rows"][0]["name"] == "토공 › 인력"
|
||||
@@ -120,7 +123,7 @@ def test_불변_열쇠가_오면_id_로_씀_자료_파일은_판_id_로_가림(
|
||||
assert _get(client, "work_item_forest")["total"] == 0 # 산림 파일은 이 폴더에 없음
|
||||
|
||||
res = client.put(
|
||||
"/api/master-data/base-prices/work_item_const/CW-00002%23갑",
|
||||
"/api/master-data/base-prices/work_item_const/CW-00002%2301",
|
||||
json={"values": {"name": "바꿈"}},
|
||||
)
|
||||
assert res.status_code == 400 and "공종 축 뼈대" in res.json()["detail"]
|
||||
@@ -158,7 +161,10 @@ def test_거르기는_자료에_있는_가름만_서버가_판정(client: TestCl
|
||||
client, "work_item_const", size=500, division="공통부문", axis_role="general_provision"
|
||||
)
|
||||
assert rules["total"] > 0
|
||||
assert all(r["name"].startswith("공통부문 › 적용기준") for r in rules["rows"])
|
||||
# 2026-09-17 건설 총칙 뿌리가 둘 — 적용기준(37) + 건설기계(75 · 산림 FP-02 와 짝)
|
||||
assert all(
|
||||
r["name"].startswith(("공통부문 › 적용기준", "공통부문 › 건설기계")) for r in rules["rows"]
|
||||
)
|
||||
role_names = {o["value"]: o["label"] for o in by_key["axis_role"]["options"]}
|
||||
# 표시 칸 — 이름은 잣대(`list_label` · 「공종 아님 · 규정·기준」) 한 곳
|
||||
assert {r["axis_role"] for r in rules["rows"]} == {role_names["general_provision"]}
|
||||
@@ -214,7 +220,9 @@ def test_갈래마다_한_줄이라_편_하나를_집는다(client: TestClient)
|
||||
"1.0 이하", "1.1∼1.5", "1.6∼2.0", "2.1∼2.5", "2.6∼3.0",
|
||||
"3.1∼3.5", "3.6∼4.0", "4.1∼4.5", "4.6∼5.0",
|
||||
] # fmt: skip
|
||||
assert rows[1]["@id"] == "FW-00105#1.1∼1.5" and rows[1]["@key"] == "FW-00105"
|
||||
# 열쇠에 갈래 **글자**를 담지 않는다 — 원문 물결표·자간이 다듬어지면 열쇠가 갈린다(브레인).
|
||||
assert rows[1]["@id"] == "FW-00105#02" and rows[1]["@key"] == "FW-00105"
|
||||
assert rows[1]["variant"] == "1.1∼1.5" # 글자는 보일 이름 칸으로
|
||||
# 갈래 없는 공종은 한 줄 · 열쇠에 # 없음
|
||||
plain = _get(client, "work_item_forest", q="교목굴취(근원직경)")["rows"]
|
||||
assert [(r["@id"], r["variant"]) for r in plain] == [("FW-00106", None)]
|
||||
|
||||
Reference in New Issue
Block a user