feat(m02): 사전조합 자재를 사전조합 값 · B08 참조 재료 · B09 겹 대가 · 사본 단가 묶음에 셈 (175-2)
- 사전조합 1 단위 값(Expand._combo) = 안 줄 + 자재 기준단가 × 손 · 빈칸 = 안 셈 · 단가 없음 = 까닭 · 안 줄에 자재 줄 - B08 _ref_mats 가 사전조합 자재(손 × 겹 손)를 품목 코드로 더함 · 사용자 자재는 연료 거름 안 함 - B09 겹 대가 블록에 자재 줄(조합 자재 줄과 한 꼴 _material) - 사본 단가 묶음: 굳힌 사전조합 자재 · 고름 코드(frozen_materials) · 개인 자재 묶음도 - 화면 하위 행: 안 줄 자재 코드 표시 - 시험: test_175_precombo_mats 네 개 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
This commit is contained in:
@@ -2,13 +2,18 @@
|
||||
|
||||
175-1 화면 · 저장 — 서고 모드 자재목록 · 로직 자재 세 칸 막힘 풂 · 저장 `_combo_lines` 가
|
||||
고름 · 자재표시 남김 · 문서 `자재`(일위대가 자재 검사 · 로직 자재와 같은 품목 400).
|
||||
175-2 셈 — 담은 자재(손 · 빈칸 = 안 셈)가 사전조합 1 단위 값(`Expand._combo` · 안 줄) · B08 참조 줄
|
||||
재료(`_ref_mats`) · B09 겹 대가 자재 줄 · 프로젝트 사본 단가 묶음(`frozen_materials`)에 들어감.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M02_MasterTemplete import M02_Labor_Doc as labor
|
||||
from M02_MasterTemplete import M02_Labor_Ref as refs
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 임시 층 fixture
|
||||
@@ -19,6 +24,8 @@ NET = "GC000337" # 낙석방지망 — 재료 줄 3 · 4 · 5(철망 · 결속
|
||||
NET_ITEM = "MT006697"
|
||||
WIRE = "MT000194"
|
||||
MAT = "MT000008" # 자재품목 · 물가정보 83000
|
||||
STONE = "GF000219" # 원/㎡
|
||||
SYS = {"층": "system", "주인": None}
|
||||
|
||||
|
||||
def _save(folder, doc):
|
||||
@@ -58,3 +65,85 @@ def test_로직_자재와_같은_품목_400_없는_자재_400(world): # noqa: F
|
||||
with pytest.raises(store.StoreError) as e:
|
||||
_save(world["system"], {"담은로직": [], "자재": [{"코드": "MT999999"}]})
|
||||
assert e.value.status == 400
|
||||
|
||||
|
||||
# ── 175-2 셈 ──────────────────────────────────────────────────────────
|
||||
def _price(code):
|
||||
whole = m01.loaded()[1]
|
||||
return Decimal(str(labor.material_price(whole, code, None)["기준단가"]))
|
||||
|
||||
|
||||
def _world_combo(world): # noqa: F811
|
||||
"""STONE 1 + MAT 손 2 + WIRE 빈칸(안 셈) · NET 고름 4 = NET_ITEM — (키, 손셈 1 단위 값)."""
|
||||
lines = [
|
||||
{"로직": STONE, "수량": {"손": 1}},
|
||||
{"로직": NET, "수량": {"손": 0}, "고름": {"4": NET_ITEM}},
|
||||
]
|
||||
mats = [{"코드": MAT, "수량": {"손": 2}}, {"코드": WIRE, "수량": None}]
|
||||
with store.at(world["system"]):
|
||||
key = refs.create("precombo", {"이름": "자재 조합", "담은로직": lines, "자재": mats})[
|
||||
"이름"
|
||||
]
|
||||
stone = Decimal(str(labor.run_line(m01.loaded()[1], STONE, {})["기준"]["계"]))
|
||||
return key, stone + _price(MAT) * 2
|
||||
|
||||
|
||||
def test_사전조합_값에_자재_금액_빈칸은_안_셈_안_줄에_자재(world): # noqa: F811
|
||||
key, want = _world_combo(world)
|
||||
with store.at(world["system"]):
|
||||
doc = labor.clean(
|
||||
{"열": "rv", "담은로직": [{"참조": {**SYS, "키": key}, "수량": {"손": 3}}]}
|
||||
)
|
||||
one = labor.calc(doc, {})["줄"][0]
|
||||
assert one["기준"]["계"] == pytest.approx(float(want))
|
||||
assert one["반영"]["계"] == pytest.approx(float(want * 3))
|
||||
mats = [x for x in one["안"] if x.get("자재")]
|
||||
assert [(x["자재"], x["수량"]) for x in mats] == [(MAT, 2)] # WIRE 빈칸 = 안 셈
|
||||
assert mats[0]["기준"]["재료비"] == pytest.approx(float(_price(MAT)))
|
||||
# 목록 기준금액(51-4)도 같은 펼침
|
||||
rows = [{"종류": "precombo", "이름": key}]
|
||||
refs.summaries(world["system"], rows)
|
||||
assert rows[0]["기준금액"] == pytest.approx(float(want))
|
||||
|
||||
|
||||
def test_B08_참조_줄_재료에_사전조합_자재_손_곱(world): # noqa: F811
|
||||
from B08_Quantity.B08_Quantity_Router_Material import _ref_mats
|
||||
|
||||
key, _ = _world_combo(world)
|
||||
with store.at(world["system"]):
|
||||
outer = refs.create(
|
||||
"precombo",
|
||||
{"이름": "겹", "담은로직": [{"참조": {**SYS, "키": key}, "수량": {"손": 3}}]},
|
||||
)["이름"]
|
||||
got = _ref_mats(m01.loaded()[1], refs.read_ref, {**SYS, "키": outer})
|
||||
mats = [(m["품목"]["키"], q) for m, q in got if m.get("자재")]
|
||||
assert mats == [(MAT, pytest.approx(6.0))] # 2 × 겹 손 3 · WIRE 빈칸 없음
|
||||
|
||||
|
||||
def test_B09_겹_대가에_자재_줄(world): # noqa: F811
|
||||
from B09_Estimation.B09_Estimation_Labor_Source import Builder
|
||||
|
||||
key, _ = _world_combo(world)
|
||||
ref = {**SYS, "키": key}
|
||||
build = Builder()
|
||||
bid = build.precombo(m01.loaded()[1], ref, refs.read_ref(ref), {})
|
||||
mats = [x for x in build.blocks[bid]["lines"] if x["kind"] == "material"]
|
||||
assert [(x["key"], x["qty"]) for x in mats] == [(MAT, 2.0), (WIRE, None)]
|
||||
assert mats[0]["name"] and mats[0]["unit"]
|
||||
|
||||
|
||||
def test_사본_단가_묶음에_사전조합_자재_고름_사본_값_같음(world): # noqa: F811
|
||||
from M02_MasterTemplete import M02_Item_Prices as prices
|
||||
from M02_MasterTemplete import M02_Item_Source as source
|
||||
|
||||
key, want = _world_combo(world)
|
||||
doc = {"열": "rv", "담은로직": [{"참조": {**SYS, "키": key}, "수량": {"손": 1}}], "자재": []}
|
||||
with store.at(world["system"]):
|
||||
rows = source.labor_doc_rows(labor.clean(doc))
|
||||
mats = refs.frozen_materials(rows["참조사본"])
|
||||
assert {MAT, WIRE, NET_ITEM} <= set(mats)
|
||||
assert "refs.frozen_materials(" in open(source.__file__, encoding="utf-8").read()
|
||||
bundle = prices.to_json(prices.collect(refs.frozen_logics(rows["참조사본"]), mats))
|
||||
(world["system"] / "precombo" / f"{key}.json").unlink() # 원본이 사라져도 굳힌 사본
|
||||
got = prices.calc(rows, bundle, {}, {}, None)["줄"][0]
|
||||
assert got["기준"]["계"] == pytest.approx(float(want), rel=1e-9)
|
||||
|
||||
Reference in New Issue
Block a user