feat(b09): 사람이 가른 표 형태 66표 까닭을 화면에 — 일위대가 상세 회색 한 줄(form_basis_note) · 일위대가 없는 공종은 내역 비고 곁 · 판정표 한 벌(_Forms.FORM_JUDGMENTS)을 읽음(10-A ⑭ · 원문 근거 없는 SW 규칙)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -444,6 +444,8 @@ def _leaf_row(
|
||||
row.add_note(
|
||||
"unit_price_krw", "일위대가가 아직 없습니다 — 금액을 0 으로 때우지 않습니다."
|
||||
)
|
||||
if form_judgment_note(node.code): # 사람이 가른 표 형태 까닭(10-A ⑭)
|
||||
row.add_note("unit_price_krw", form_judgment_note(node.code))
|
||||
reason = "일위대가 없음"
|
||||
# 관경이 표 밖이면 **무엇을 정해야 하는지**까지 가리킨다.
|
||||
diameter_note = pipe_diameter_note(node.code, item.variant_value) if children else ""
|
||||
@@ -595,6 +597,7 @@ _PENDING_FORMULA: dict[str, str] = {}
|
||||
|
||||
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import ( # noqa: E402
|
||||
form_judgment_note,
|
||||
known_gap_note,
|
||||
pipe_diameter_note,
|
||||
)
|
||||
|
||||
@@ -110,6 +110,41 @@ def known_gap_note(code: str | None) -> str:
|
||||
return " / ".join(parts)
|
||||
|
||||
|
||||
#: 표 형태 이름 — 판정 까닭 한 줄에 붙임.
|
||||
_FORM_LABELS = {
|
||||
"reference": "참조표",
|
||||
"coefficient": "계수표",
|
||||
"productivity": "생산량형",
|
||||
"requirement": "소요량형",
|
||||
}
|
||||
|
||||
|
||||
def form_judgment_note(code: str | None) -> str:
|
||||
"""사람이 가른 표 형태 까닭 — 원문 근거 없는 **SW 규칙**이라 화면에 드러냄(10-A ⑭ · 09-14).
|
||||
|
||||
정본은 B08 마스터 빌더의 판정표 한 벌(`_Forms.FORM_JUDGMENTS`) — 여기서 다시 적지 않고 읽음.
|
||||
"""
|
||||
plain = str(code or "").split("#")[0]
|
||||
if not plain:
|
||||
return ""
|
||||
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Forms import FORM_JUDGMENTS
|
||||
from B09_Estimation.B09_Estimation_ResourceAxis import load_work_item_master
|
||||
|
||||
node = next(
|
||||
(n for n in load_work_item_master()["work_items"] if n.get("work_item_code") == plain),
|
||||
{},
|
||||
)
|
||||
parts = []
|
||||
for table in node.get("tables") or []:
|
||||
found = FORM_JUDGMENTS.get(str(table.get("pum_table_id")))
|
||||
if found:
|
||||
_section, form, why = found
|
||||
parts.append(f"{table['pum_table_id']} {_FORM_LABELS.get(form, form)}: {why}")
|
||||
if not parts:
|
||||
return ""
|
||||
return "ⓘ 표 형태는 사람이 가름(원문 근거 없음 · SW 규칙) — " + " / ".join(parts)
|
||||
|
||||
|
||||
#: 관부설 품셈 표가 다루는 관경 — 그 밖은 **표에 없는 것**이지 값이 틀린 것이 아니다.
|
||||
PIPE_TABLE_DIAMETERS_MM = (800, 1000, 1200)
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ function drawDetail(
|
||||
}
|
||||
if (detail.unattached_note) box.append(hint(detail.unattached_note.replace(/\*\*/g, ""), true));
|
||||
if (detail.known_gap_note) box.append(hint(detail.known_gap_note, true));
|
||||
if (detail.form_basis_note) box.append(hint(detail.form_basis_note, true));
|
||||
}
|
||||
|
||||
/** 본표 한 장을 `box` 에 — 자취를 쌓고 서버 본표를 받아 그림. */
|
||||
|
||||
@@ -175,6 +175,8 @@ export interface DetailDto {
|
||||
rows: DetailRowDto[];
|
||||
unattached_note: string;
|
||||
known_gap_note: string;
|
||||
/** 사람이 가른 표 형태 까닭(원문 근거 없는 SW 규칙 · 10-A ⑭). 없으면 빈 문자열. */
|
||||
form_basis_note?: string;
|
||||
/** 구성행·Q 식을 고칠 수 있는 본표(B·D)인가 · 줄 더하기에 쓸 다음 칸 이름. */
|
||||
editable?: boolean;
|
||||
next_add_key?: string;
|
||||
|
||||
@@ -174,7 +174,7 @@ def detail_of(build: UnitPriceBuild, code: str) -> dict:
|
||||
money = build.book.resolve(code)
|
||||
# 코드에서 공종을 도로 뽑는다 — 「B-FP-09-11-01#갈래」의 갈래는 떼고 본다.
|
||||
work_item_code = code[2:].split("#")[0] if code.startswith("B-") else ""
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import known_gap_note
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import form_judgment_note, known_gap_note
|
||||
|
||||
unattached = list(build.unattached.get(work_item_code, []))
|
||||
rows: list[dict] = []
|
||||
@@ -317,6 +317,8 @@ def detail_of(build: UnitPriceBuild, code: str) -> dict:
|
||||
"unattached": unattached,
|
||||
# ⚠ 원문에는 있는데 못 실린 몫 — 이름을 못 찾은 줄과 **다른 갈래**다.
|
||||
"known_gap_note": known_gap_note(work_item_code),
|
||||
# 사람이 가른 표 형태 까닭(SW 규칙 · 10-A ⑭) — 칸 밑 회색 한 줄.
|
||||
"form_basis_note": form_judgment_note(work_item_code),
|
||||
"unattached_note": (
|
||||
f"⚠ 품셈 표에 있는 {len(unattached)}줄이 아직 안 붙었습니다 — "
|
||||
f"{', '.join(unattached[:4])}"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""10-A ⑭ 표 형태 66표 까닭을 화면에 — 2026-09-14 사용자 확정 「SW 규칙 · 화면에 드러낼 것」.
|
||||
|
||||
사람이 가른 표 형태(`_Forms.FORM_JUDGMENTS`)는 원문 근거가 없는 우리 규칙 —
|
||||
마스터엔 있으나 화면에 한 번도 안 닿았음. 모양은 서브 10-A 채움과 같게 **칸 밑 회색 한 줄**:
|
||||
일위대가 상세(`detail_of` → 화면 hint) · 일위대가가 없는 공종은 내역 「일위대가 없음」 비고.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from B09_Estimation.B09_Estimation_KnownGaps import form_judgment_note
|
||||
from B09_Estimation.B09_Estimation_UnitPrice import cached_build, detail_of
|
||||
|
||||
|
||||
def test_판정표가_딸린_일위대가_상세에_까닭_한_줄() -> None:
|
||||
build = cached_build()
|
||||
code = next(c for c in build.book.titles if c.startswith("B-FP-13-04-04"))
|
||||
note = detail_of(build, code)["form_basis_note"]
|
||||
assert "F0412" in note and "참조표" in note and "뒷길이 표준" in note, note
|
||||
assert "SW 규칙" in note
|
||||
|
||||
|
||||
def test_판정표_없는_공종은_빈_칸() -> None:
|
||||
assert form_judgment_note("FP-09-03-02") == ""
|
||||
|
||||
|
||||
def test_일위대가_없는_공종은_내역_비고에_까닭() -> None:
|
||||
from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill
|
||||
|
||||
item = {"work_item_code": "FP-12-38-01", "name": "사용횟수", "spec": "", "unit": "회",
|
||||
"quantity": "1", "in_bill": True} # fmt: skip
|
||||
rows = build_bill({"work_items": [item], "materials": []}).rows
|
||||
line = next(r for r in rows if r.code == "FP-12-38-01")
|
||||
assert "F0392" in line.note and "계수표" in line.note, line.note
|
||||
Reference in New Issue
Block a user