feat(B09): 공구손료·잡재료 칸 — 기본은 빔, 넣으면 주재료비의 %로 붙음
사용자 확정 5차 작은 것 1 「지금은 안 넣되 숫자 넣으면 되게 열어 둘 것」. 근거는 산림품셈 1-2-6 — 주재료비(할증수량 제외)의 2~5%까지, 산정 근거 명시. - 기초자료 탭 「산출 조건」에 칸 하나 + [적용]. 비면 줄 자체가 안 섬(지금 상태 그대로). - 밑수는 **자재 줄만** — 노무·경비, 하위 일위대가 재료비는 안 듦(층마다 거듭 세지 않음). - 상한 5% 초과는 거절(400) — 조용히 깎아 넣지 않음. - ⚠ 지금은 일위대가에 주재료비가 선 공종이 0개라 붙을 밑수가 없음 — 그 사실을 칸 밑에 띄움. - 곁다리: 비율 줄(제잡비·공구손료)이 저장했다 읽으면 사라지던 것을 고침. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -152,6 +152,12 @@ class PriceDetail:
|
||||
#: ⚠ `percent_of_parent` 와 다르다: 밑수가 3분할 전체가 아니라 **노무비만**이고,
|
||||
#: 결과는 **경비(J)** 로만 들어간다. 「상한」이라 설계자가 낮출 수 있는 값이다.
|
||||
percent_of_labor: Decimal | None = None
|
||||
#: **주재료비**의 %로 붙는 재료비 줄 — 공구손료·잡재료(산림품셈 1-2-6).
|
||||
#: ⚠ 밑수는 **자재 카탈로그(M)에서 온 재료비만**이다. 하위 일위대가가 품고 온 재료비는
|
||||
#: 그 일위대가에서 이미 한 번 셌으므로 여기서 또 세지 않는다.
|
||||
#: ⚠ 원문이 「재료비의 **할증수량 제외**」라 밑수가 **할증 전** 값이어야 하는데, 일위대가
|
||||
#: 층의 재료비가 곧 할증 전 값이다(할증은 자재총괄에서 한 번만 — PLAN 8-7 ㉠).
|
||||
percent_of_material: Decimal | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -200,6 +206,8 @@ class PriceBook:
|
||||
# 제잡비 밑수로 쓸 **사람 품(직접노무비)** — 기계 줄 안의 조종원 노임은 안 센다.
|
||||
# 근거는 아래 `percent_of_labor` 자리 주석의 인용 셋.
|
||||
direct_labor = Decimal(0)
|
||||
# 공구손료·잡재료 밑수로 쓸 **주재료비** — 자재 카탈로그에서 바로 온 재료비만 센다.
|
||||
direct_material = Decimal(0)
|
||||
for row in rows:
|
||||
# ⚠ 비율 줄은 **참조를 풀기 전에** 처리한다 — 자기 자신을 가리키므로
|
||||
# 먼저 풀면 순환으로 잡힌다(제잡비 줄이 그렇다).
|
||||
@@ -236,6 +244,20 @@ class PriceBook:
|
||||
total = total + Money3(expense=direct_labor * row.percent_of_labor / Decimal(100))
|
||||
continue
|
||||
|
||||
if row.percent_of_material is not None:
|
||||
# 공구손료·잡재료 — **주재료비**의 %가 **재료비**로 붙는다(산림품셈 1-2-6
|
||||
# 「각 항목에 명시되어 있지 않는 잡재료 및 소모재료 … 주재료비(재료비의
|
||||
# 할증수량 제외)의 2~5%까지 별도 계상하되 산정 근거를 명시하여야 한다」).
|
||||
# ⚠ **기본은 빈 칸이라 이 줄 자체가 안 선다**(사용자 확정 5차 작은 것 1
|
||||
# 「지금은 안 넣되 숫자 넣으면 되게 열어 둘 것」). 몇 %인지는 사용자 몫이다.
|
||||
# ⚠ 밑수가 **명시된 잡재료를 뺀 주재료비**여야 하는데, 품셈이 명시한 잡재료는
|
||||
# 이미 자원 줄로 서 있어 이 밑수에 함께 든다 — 그 공종에 잡재료가 명시돼
|
||||
# 있으면 1-2-6 이 애초에 안 걸리는 자리이므로 **칸을 비워 두는 것이 맞다.**
|
||||
total = total + Money3(
|
||||
material=direct_material * row.percent_of_material / Decimal(100)
|
||||
)
|
||||
continue
|
||||
|
||||
child = self.resolve(row.ref_code, (*_seen, code))
|
||||
if row.percent_of_parent is not None:
|
||||
# 비율 행 — 지금까지 쌓인 값의 %로 붙는다(공구손료 등).
|
||||
@@ -244,9 +266,29 @@ class PriceBook:
|
||||
scaled = child.scaled(row.quantity)
|
||||
if self.titles[row.ref_code].kind is PriceKind.LABOR:
|
||||
direct_labor = direct_labor + scaled.labor
|
||||
if self.titles[row.ref_code].kind is PriceKind.MATERIAL:
|
||||
direct_material = direct_material + scaled.material
|
||||
total = total + scaled
|
||||
return total
|
||||
|
||||
def material_base(self, code: str) -> Decimal:
|
||||
"""공구손료·잡재료(산림품셈 1-2-6)의 **밑수** — 그 항목에 바로 붙은 자재 줄의 합.
|
||||
|
||||
`resolve` 안의 `direct_material` 과 같은 규칙이다. 화면이 「넣을 데가 있는가」를
|
||||
미리 물어볼 수 있게 따로 낸다 — 지금은 사급 단가가 미결이라 대부분 0 이고,
|
||||
그 사실을 숨기면 사용자가 값을 넣고도 왜 안 붙는지 모른다.
|
||||
"""
|
||||
base = _ZERO
|
||||
for row in self.details.get(code, []):
|
||||
if row.percent_of_material is not None or row.percent_of_labor is not None:
|
||||
continue
|
||||
if row.percent_of_parent is not None or row.ref_code == code:
|
||||
continue
|
||||
title = self.titles.get(row.ref_code)
|
||||
if title is not None and title.kind is PriceKind.MATERIAL:
|
||||
base = base + title.catalog_money().material * row.quantity
|
||||
return base
|
||||
|
||||
def unmatched_codes(self) -> list[str]:
|
||||
"""상세가 가리키는데 제목이 없는 코드 — **빈칸으로 두지 않고 목록으로 낸다**.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user