Merge remote-tracking branch 'origin/main_desktop_1' into sub_laptop_1

# Conflicts:
#	B08_Quantity/B08_Quantity_Engine_UnitQuantity.py
This commit is contained in:
2026-09-09 12:10:38 +09:00
4 changed files with 58 additions and 27 deletions
@@ -582,7 +582,15 @@ def _preparation_rows(preparation_table: dict[str, Any]) -> list[dict[str, Any]]
"station_from": None,
"station_to": None,
"excavation_method": None,
"spec_detail": str(row.get("group") or ""),
# ⚠ **값이 서는 줄에도 근거를 싣는다**(2026-09-09) — 종전에는 대분류 이름만
# 실어, 값이 서는 순간 **왜 그 값인지가 사라졌다**(제근이 면적 축으로 확정돼
# 값이 서자 「교차 참조: 건설품셈 3-9-2」가 화면에서 사라진 자리).
# 못 서는 줄은 종전대로 `blocked_reason` 이 따로 든다.
"spec_detail": " · ".join(
part
for part in (str(row.get("group") or ""), str(row.get("reason") or ""))
if part
),
"composite_parts": None,
"structure_kind": None,
# ⚠ 못 서는 까닭을 그대로 넘긴다 — 받는 쪽이 「만들어야 할 것」 목록에 얹는다.
+33 -19
View File
@@ -192,9 +192,13 @@ TOPSOIL_HAUL_LAW = (
#: 적혀 있는데 9-21 표에는 그 표기가 없다. 등급을 넣어도 **무엇당 값인지 모르면 못 센다.**
#: 지어내지 않고 그 사실을 사유로 낸다(원문 확인이 필요한 자리).
STAND_VOLUME_CLASSES = ("소림", "중림", "밀림")
ROOT_REMOVAL_BASIS_UNKNOWN = (
"품셈 9-21 표에 **밑수 단위가 없음** — 9-20 은 「10주당」이라 적혀 있으나 9-21 에는"
" 그 표기가 없어 「무엇당 값」인지 원문으로 확인해야 함. 등급을 넣어도 그 전에는 못 셈"
#: ⭐ 2026-09-09 **사용자 확정 5차 6번** — 제근 밑수를 **면적 축**으로 확정.
#: 산림품셈 9-21 표에 밑수 표기가 없어, **건설공사 표준품셈 3-9-2 「1,000㎡당」**을 빌려 쓴다.
#: ⚠ **교차 참조 표시 필수**(CLAUDE.md 3장 — 다른 품셈을 빌려 쓸 때의 규칙).
#: ⇒ 이 확정으로 **제근·뿌리 적재·뿌리 운반·지장목제거 넷이 같은 면적 밑수**로 선다.
ROOT_REMOVAL_BASIS = (
"밑수는 **면적 축**(사용자 확정 5차 6번) — 산림품셈 9-21 에 밑수 표기가 없어"
" ⚠ **교차 참조**: 건설공사 표준품셈 **3-9-2 뿌리뽑기 「1,000㎡당」**을 빌려 씀"
)
ROOT_REMOVAL_CLASS_MISSING = (
"임목축적 등급이 아직 입력되지 않았습니다 — 품셈 9-21 [주]① 이 소림(30~60㎥/㏊)·"
@@ -210,18 +214,20 @@ def _root_removal_row(slope: dict[str, float], stand_volume_class: str | None) -
"""
area = float(slope.get("tree_removal_fill", 0.0)) + float(slope.get("tree_removal_cut", 0.0))
picked = str(stand_volume_class or "").strip()
reasons = [ROOT_REMOVAL_BASIS_UNKNOWN]
reasons = [ROOT_REMOVAL_BASIS, "대상 면적은 지장목제거와 같은 자리(벌개제근 연동)"]
if picked in STAND_VOLUME_CLASSES:
reasons.append(f"등급{picked}로 정해져 있음")
reasons.append(f"임목축적 등급 「{picked} — 품셈 9-21 [주]① 이 품을 그 축으로 가름")
else:
reasons.append(ROOT_REMOVAL_CLASS_MISSING)
# ⚠ 등급은 **품(단가) 갈래**이지 물량 밑수가 아니다 — 면적이 서면 물량은 선다.
# 등급이 비면 값은 서되 **단가를 못 고른다**는 사실만 사유로 남는다.
return {
"group": "준비공",
"item": "제근·뿌리다듬기",
"unit": "",
"amount": None,
"status": STATUS_PENDING,
"reason": " · ".join(reasons) + f" (대상 면적 {area:,.1f}㎡ — 벌개제근 연동)",
"unit": "",
"amount": area if area > 0 else None,
"status": STATUS_READY if area > 0 else STATUS_PENDING,
"reason": " · ".join(reasons),
"reference_amount": area,
"work_item_code": "FP-09-21",
}
@@ -243,34 +249,42 @@ ROOT_STEPS_NOTE = (
def _root_steps_rows(
slope: dict[str, float], stand_volume_class: str | None
) -> list[dict[str, Any]]:
"""뿌리 적재·운반 — **제근과 한 벌로 가는 뒤 단계**. 밑수가 서면 함께 선다."""
"""뿌리 적재·운반 — **제근과 한 벌로 가는 뒤 단계**. 제근이 서면 함께 선다."""
area = float(slope.get("tree_removal_fill", 0.0)) + float(slope.get("tree_removal_cut", 0.0))
return [
{
"group": "준비공",
"item": "뿌리 적재",
"unit": "",
"amount": None,
"status": STATUS_PENDING,
"unit": "",
"amount": area if area > 0 else None,
"status": STATUS_READY if area > 0 else STATUS_PENDING,
"reason": (
f"{ROOT_STEPS_NOTE} · 품셈 9-20-2 「(단위: 10주당)」 — **본수가 서야 셈**"
f" (대상 면적 {area:,.1f}㎡ · 제근과 같은 밑수)"
f"{ROOT_STEPS_NOTE} · {ROOT_REMOVAL_BASIS}"
" · ⚠ **품셈 9-20-2 는 「10주당」이라 밑수 축이 다름** — 면적 축으로 내고"
" 그 사실을 적음(본수가 서면 그 축으로 옮길 것)"
),
"reference_amount": area,
"work_item_code": "FP-09-20-02",
},
{
# ⭐ 2026-09-09 **확정 5차 4번** — 뿌리 운반은 **덤프**로 잡는다.
# ⚠ 사용자 관찰 「실제 운반품이 적용 안 되는 듯함. 나중엔 적용될 가능성도 있음」
# ⇒ 코드는 붙이되 **품이 안 붙으면 그대로 두고 사유**를 낸다. 억지로 안 붙인다.
# ⚠ 물량 축이 다르다 — 운반은 **부피(㎥)** 인데 우리가 든 것은 **면적**뿐이라
# ㎥ 를 지어내지 않고 면적을 참고로만 싣는다.
"group": "준비공",
"item": "뿌리 운반",
"unit": "",
"unit": "",
"amount": None,
"status": STATUS_PENDING,
"reason": (
f"{ROOT_STEPS_NOTE} · ⚠ **9-20 장에 운반 공종이 없음** — 10장 계열 어디에"
" 붙는지 원문이 말하지 않아 공종코드를 못 붙임"
f"{ROOT_STEPS_NOTE} · 사용자 확정 5차 4번 「**덤프**로 잡음」 —"
" ⚠ 운반 밑수는 **부피(㎥)** 인데 뿌리 부피를 든 곳이 없어 물량이 안 섬"
" (대상 면적만 있음). ⚠ 실무에서 **운반품이 안 붙는 경우가 있음**(사용자 관찰) —"
" 안 붙으면 그대로 두고 이 사유가 남음"
),
"reference_amount": area,
"work_item_code": None,
"work_item_code": "FP-10-12",
},
]
@@ -197,12 +197,13 @@ def stone_coefficients(options: dict[str, Any], back_cm: int) -> tuple[dict[str,
# 돌쌓기 전개식의 상수 — 실무 수식에 박혀 있던 값을 뺀 것.
#: ⚠⚠ **기슭막이 계열(돌쌓기 찰·메) 전용이다. 다른 구조물로 넓히지 말 것**(2026-09-09).
#: 골막이는 **두께식부터 다르다** — 소광리 숨김탭 「골막이(찰)(치수조서연결)」 C26:
#: 평균두께 = {(3 + 0.1×H) + (3 + 0.4×H)} ÷ 2
#: ⚠ 앞서 이 식을 「0.45 + 0.1H」로 적어 두었으나 **0.45 는 상수가 아니라 뒷길이 ℓ3**
#: 이다(C26 이 `P6/100` 을 읽고 P6 = 45㎝). ⇒ 두 식 다 뒷길이 기반이고 **더하는 몫만**
#: 다르다. 우리가 확정 ② 로 버린 옛 식이 뒷길이를 안 보던 것과는 그 점이 다르다.
#: ⚠ 상수만 보고 골막이에 가져다 쓰면 **값이 나오므로 아무 시험도 안 잡는다.**
#: 골막이는 **더하는 몫이 다르다** — 소광리 숨김탭 「골막이(찰)(치수조서연결)」 C26:
#: 골막이 평균두께 = {(3 + 0.1×H) + (3 + 0.4×H)} ÷ 2
#: 기슭막이 상부 = ℓ3 + 0.30 · 하부 = 상부 + 0.30(H 1)
#: ⚠⚠ **둘 다 뒷길이(ℓ3) 기반이다** — C26 의 「0.45」는 상수가 아니라 `P6/100`(뒷길이 45㎝)을
#: 읽은 값이었다(2026-09-09 랩탑 보조가 셀 참조로 확인). 앞서 여기 「0.45 + 0.1H」로 적어
#: **상수처럼 보이게** 두었는데, 그렇게 굳으면 **뒷길이를 바꿔도 골막이 값이 안 움직이는**
#: 결함이 조용히 남는다.#: ⚠ 상수만 보고 골막이에 가져다 쓰면 **값이 나오므로 아무 시험도 안 잡는다.**
#: ⚠ 골막이는 그 밖에도 셋이 더 다르다 — 밑수가 **돌쌓기 + 돌붙임**(기슭막이는 돌쌓기만) ·
#: 단위가 **개소당**(기슭막이는 m당) · 정면적이 **사다리꼴**.
STONE_MASONRY = {