Merge remote-tracking branch 'origin/sub_desktop_1' into sub_laptop_1
This commit is contained in:
@@ -222,6 +222,10 @@ def _leaf_row(
|
||||
if children:
|
||||
names = ", ".join(f"{c[2:]} {unit_prices.book.title(c).name}" for c in children)
|
||||
row.note = f"이 공종엔 일위대가가 없고 한 층 아래에 있습니다 — 후보: {names}"
|
||||
# 관경이 표 밖이면 **무엇을 정해야 하는지**까지 가리킨다.
|
||||
diameter_note = pipe_diameter_note(node.code, item.variant_value)
|
||||
if diameter_note:
|
||||
row.note = f"{row.note} / {diameter_note}"
|
||||
reason = f"일위대가가 하위 공종에 있음(후보 {len(children)}건)"
|
||||
else:
|
||||
# ⚠ 「아직 안 만든 것」과 「성분이 빠져 못 세운 것」은 **할 일이 다르다**.
|
||||
@@ -362,7 +366,10 @@ def _leaf_row(
|
||||
_PENDING_FORMULA: dict[str, str] = {}
|
||||
|
||||
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import known_gap_note # noqa: E402
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import ( # noqa: E402
|
||||
known_gap_note,
|
||||
pipe_diameter_note,
|
||||
)
|
||||
|
||||
|
||||
def pending_formula_note(code: str | None) -> str:
|
||||
|
||||
@@ -36,6 +36,14 @@ KNOWN_GAPS: dict[str, tuple[str, str]] = {
|
||||
"(2026-09-09 각재·판재·못이 자재 축에 섰음. 다만 관급·사급이 안 갈려 아직 금액 0). "
|
||||
"재료가 금액으로 서면 손율이 함께 걸립니다 — 품셈 [주]③ 「목재의 손율은 1개소 사용당 80%」.",
|
||||
),
|
||||
"FP-12-11-03": (
|
||||
"인력 품만",
|
||||
"⚠ 이 값은 **인력 품만**입니다 — 파형강관·커플링밴드·크레인(5ton)·모래부설이 아직 "
|
||||
"안 붙었습니다. 관·모래는 원문이 「별산」·「설계수량」이라 한 자리이고, 크레인은 "
|
||||
"기계 카탈로그에 없어서입니다. "
|
||||
"ⓘ 커플링밴드는 값이 표에 없지만 [주]① 이 「**1EA/6m**」를 줍니다 — 자재가 서면 "
|
||||
"m 당 1/6 EA 로 셀 수 있습니다(다만 「필요시 별도 산정」이라 조건이 하나 더 붙습니다).",
|
||||
),
|
||||
"FP-12-25": (
|
||||
"운반거리 미정",
|
||||
"⚠ 이 값에는 **운반 몫이 빠져 있습니다** — 품셈 12-25 는 「운반 | 덤프트럭(15ton)」 줄을 "
|
||||
@@ -67,3 +75,38 @@ def known_gap_note(code: str | None) -> str:
|
||||
if plain.startswith(prefix):
|
||||
parts.append(note)
|
||||
return " / ".join(parts)
|
||||
|
||||
|
||||
#: 관부설 품셈 표가 다루는 관경 — 그 밖은 **표에 없는 것**이지 값이 틀린 것이 아니다.
|
||||
PIPE_TABLE_DIAMETERS_MM = (800, 1000, 1200)
|
||||
|
||||
#: 교본이 큰 관을 넘기는 자리 — **교본 기준이지 법령·행정규칙이 아니다.**
|
||||
#: `횡단배수관_암거.md §5`(교본 3장) 「BOX암거 적용 — 수리계산상 배수관 **Ø1,500㎜ 이상**
|
||||
#: 적용 유역 · 계곡 횡단경사 40% 이내 · 구체 수평 설치 원칙」.
|
||||
#: ⚠ 그래서 「Ø1,500 이면 반드시 암거」라고 **단정하지 않는다** — 프로젝트 규칙이
|
||||
#: 「기본값은 현행 법령·행정규칙, 교본은 과거 참조」이기 때문이다. **가리키기만** 한다.
|
||||
CULVERT_HINT_MM = 1500
|
||||
|
||||
|
||||
def pipe_diameter_note(code: str | None, variant_value: object) -> str:
|
||||
"""관경이 품셈 표 밖일 때 **어디를 봐야 하는지**를 가리킨다.
|
||||
|
||||
⚠ 「품셈 표에 그 관경이 없음」만 적으면 사용자가 **엉뚱한 것을 정하러 간다** —
|
||||
정할 것은 단가가 아니라 **시설 선택**일 수 있다.
|
||||
"""
|
||||
if not code or not str(code).startswith("FP-12-11"):
|
||||
return ""
|
||||
try:
|
||||
diameter = int(float(str(variant_value)))
|
||||
except (TypeError, ValueError):
|
||||
return ""
|
||||
if diameter in PIPE_TABLE_DIAMETERS_MM:
|
||||
return ""
|
||||
note = f"⚠ 품셈 관부설 표는 ∅800·∅1000·∅1200 까지만 있습니다 — Ø{diameter} 는 표 밖입니다."
|
||||
if diameter >= CULVERT_HINT_MM:
|
||||
note += (
|
||||
" ⓘ 임도기술교본 3장은 **Ø1,500㎜ 이상을 BOX암거 적용 유역**으로 봅니다"
|
||||
"(`횡단배수관_암거 §5`). 관으로 놓을 자리가 아닐 수 있으니 **단가가 아니라"
|
||||
" 시설 선택**을 먼저 볼 것. ⚠ 교본 기준이라 법령·행정규칙은 아닙니다."
|
||||
)
|
||||
return note
|
||||
|
||||
@@ -155,6 +155,12 @@ def match_choose_one_machine_table(
|
||||
form = str(table.get("pum_form", ""))
|
||||
unit = table.get("basis_unit") or ""
|
||||
|
||||
# ⚠ **빌려 온 밑수의 배수를 여기서 나눈다** — 「1,000㎡당」 표를 ㎡당으로 싣는다.
|
||||
# 안 나누면 금액이 **천 배**로 선다(2026-09-09 확정 5차 6번, 제근).
|
||||
from B09_Estimation.B09_Estimation_WorkItemUnit import borrowed_basis_per
|
||||
|
||||
per = Decimal(borrowed_basis_per(str(node.get("work_item_code", ""))))
|
||||
|
||||
made = 0
|
||||
for block in blocks:
|
||||
machine = block["entry"]
|
||||
@@ -174,7 +180,7 @@ def match_choose_one_machine_table(
|
||||
resource_code=entry.code,
|
||||
resource_name=entry.name,
|
||||
resource_spec=entry.spec,
|
||||
amount=amount,
|
||||
amount=amount / per,
|
||||
amount_unit=unit,
|
||||
raw_row_index=0,
|
||||
variant=variant,
|
||||
|
||||
@@ -136,8 +136,63 @@ def section_of(work_item_code: str) -> str:
|
||||
return "-".join(numbers)
|
||||
|
||||
|
||||
#: **다른 품셈에서 빌려 온 밑수** — 산림품셈이 안 적은 자리를 사용자가 정해 준 것.
|
||||
#:
|
||||
#: ⚠ **임도 전용 품이 있는데 건설품셈을 쓰는 것**이라 화면이 그 사실을 밝혀야 한다
|
||||
#: (교차 참조 표시 — 프로젝트 규칙). 그래서 값만 두지 않고 **근거 문구를 함께** 든다.
|
||||
#: ⚠ 여기 적는 것은 **사용자가 정한 것뿐**이다. 우리가 골라 채우는 자리가 아니다.
|
||||
#: 빌려 온 밑수가 **몇 단위당**인가 — 「1,000㎡당」이면 1000.
|
||||
#: ⚠ **이 나눗셈을 빠뜨리면 1,000 배 틀린다.** 단위만 「㎡」로 바꿔 달고 값을 그대로 두면
|
||||
#: 금액이 천 배로 선다. 그래서 단위와 배수를 **한 자리에** 둔다.
|
||||
BORROWED_BASIS_PER: dict[str, int] = {"FP-09-21": 1000}
|
||||
|
||||
BORROWED_UNITS: dict[str, tuple[str, str]] = {
|
||||
# 2026-09-09 사용자 확정 5차 6번 — 제근 밑수를 면적 축으로.
|
||||
"FP-09-21": (
|
||||
"㎡",
|
||||
"밑수는 **건설공사 표준품셈 3-9-2 뿌리뽑기 「1,000㎡당」**에서 빌려 왔습니다"
|
||||
"(2026-09-09 사용자 확정) — ⚠ **교차 참조**입니다. 산림품셈 9-21 은 표 머리·제목·[주] "
|
||||
"어디에도 밑수를 안 적었고(앞 절 9-20-1 「10주당」·9-20-2 「단위: 10주당」과 대비), "
|
||||
"실무도 ㎡(영월)와 ㎥(교본 예시)로 갈려 있었습니다. "
|
||||
"⚠ 그 표가 **1,000㎡당**이라 **㎡당으로 환산(÷1,000)**해 싣습니다. "
|
||||
"⚠ **자릿수가 견준 값과 어긋납니다** — 이대로면 굴착기 0.7㎥·소림 기준 55.4원/㎡ "
|
||||
"(대상 17,873.8㎡ 이면 약 99만원)인데, 실무 영월 「뿌리뽑기」는 475원/㎡ 이고 "
|
||||
"빌려 온 건설품셈 3-9-2 는 같은 1,000㎡당에 굴착기(0.2㎥) 3.76hr 로 산림품셈 "
|
||||
"9-21 의 0.80hr 보다 4.7배 큽니다. **100㎡당으로 보면 실무와 자릿수가 맞습니다.** "
|
||||
"값은 확정대로 두되 이 어긋남을 함께 보입니다 — 다시 볼 자리입니다.",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def borrowed_basis_per(work_item_code: str) -> int:
|
||||
"""빌려 온 밑수의 배수 — 「1,000㎡당」이면 1000. 아니면 1."""
|
||||
plain = str(work_item_code or "").split("#")[0]
|
||||
for code, per in BORROWED_BASIS_PER.items():
|
||||
if plain.startswith(code):
|
||||
return per
|
||||
return 1
|
||||
|
||||
|
||||
def borrowed_unit_note(work_item_code: str) -> str:
|
||||
"""빌려 온 밑수라면 그 근거 한 줄. 아니면 빈 문자열."""
|
||||
plain = str(work_item_code or "").split("#")[0]
|
||||
for code, (_unit, note) in BORROWED_UNITS.items():
|
||||
if plain.startswith(code):
|
||||
return note
|
||||
return ""
|
||||
|
||||
|
||||
def unit_of(work_item_code: str) -> str | None:
|
||||
"""그 공종 단가의 기준 단위. **원문에 없으면 `None`** — 짐작으로 채우지 않는다."""
|
||||
"""그 공종 단가의 기준 단위. **원문에 없으면 `None`** — 짐작으로 채우지 않는다.
|
||||
|
||||
⚠ 예외는 **사용자가 다른 품셈에서 빌려 오라고 정한 자리**뿐이다(`BORROWED_UNITS`).
|
||||
그때도 화면이 **어디서 빌렸는지**를 함께 보인다.
|
||||
"""
|
||||
plain = str(work_item_code or "").split("#")[0]
|
||||
for code, (unit, _note) in BORROWED_UNITS.items():
|
||||
if plain.startswith(code):
|
||||
return unit
|
||||
|
||||
section = section_of(work_item_code)
|
||||
if not section:
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user