- 충돌 시험 셋(717-4 · 719-2 · hopyo build) = 740-1 펼침 단언 + 742-1 저장 수량 단언 합침 - 740-2 일위대가표 풍선 줄의 body(742-1 이 걷은 휘발 셈 몸) → cur Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
132 lines
6.7 KiB
Python
132 lines
6.7 KiB
Python
"""719-1 프로젝트 사본 — M02 단가산출(SK) 풀어 굳힘(`M02_Item_Sangeun` · `M02_Item_Source` ·
|
|
`M02_Item_Prices` · `B09_Estimation_Bill_Library`) — 임시 storage(견본 층 · 실제 M01 읽기만).
|
|
|
|
구조물 사본 · B09 서고 사본 셈 = M02 층 SK 셈 · 굳힌 줄은 사본 `단가.json` 로직 줄 · 원본 SK 를
|
|
지워도 같은 값 · 같은 SK = 같은 굳힌 키(다시 복사 · SK 고친 뒤도) · 원본 층 지문 그대로 ·
|
|
서고 manifest 원본판 = SK 바뀌면 다름.
|
|
"""
|
|
|
|
# ruff: noqa: F811 — 임시 층 fixture `world` 를 들여 씀
|
|
import hashlib
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from B09_Estimation import B09_Estimation_Bill_Library as library
|
|
from M02_MasterTemplete import M02_Item_Prices as prices
|
|
from M02_MasterTemplete import M02_Item_Sangeun as sk
|
|
from M02_MasterTemplete import M02_Item_Source as source
|
|
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_715_sangeun_store import PCT, _sk
|
|
from resources.tester.test_m02_labor_ref import MINE, world # noqa: F401 — 같은 임시 층
|
|
|
|
COVER = {"labor:LB000036#0": {"qty": 0.5}}
|
|
ADD = [{"종류": "인력", "요소": "LB000002", "수량": 0.1}]
|
|
|
|
|
|
def _print(folder):
|
|
"""층 폴더 지문 — 파일 이름 · 바이트."""
|
|
out = hashlib.sha256()
|
|
for path in sorted(p for p in folder.rglob("*") if p.is_file()):
|
|
out.update(str(path.relative_to(folder)).encode() + path.read_bytes())
|
|
return out.hexdigest()
|
|
|
|
|
|
def _top(ref, qty=2):
|
|
with store.at(ref["folder"]):
|
|
doc = labor.clean({"열": "rv", "담은로직": [{"참조": ref["ref"], "수량": {"손": qty}}]})
|
|
return doc, labor.calc(doc, {})["줄"][0]
|
|
|
|
|
|
def _mine(world):
|
|
key = _sk(world["personal"], 바탕={"로직": PCT}, 덮개=COVER, 더한줄=ADD)
|
|
return key, {"folder": world["personal"], "ref": {**MINE, "키": key}}
|
|
|
|
|
|
def test_구조물_사본_굳힌_줄_값_같음_원본_지워도(world):
|
|
key, ref = _mine(world)
|
|
doc, live = _top(ref)
|
|
assert not live["까닭"] and live["기준"]["계"] > 0
|
|
before = _print(world["personal"])
|
|
rows = source.labor_doc_rows(doc)
|
|
bundle = source.price_bundle(rows, world["personal"])
|
|
assert _print(world["personal"]) == before # 원본 층 안 건드림
|
|
rid = refs.ref_id(ref["ref"])
|
|
frozen = rows["참조사본"][rid]
|
|
fk = frozen["바탕"]["로직"]
|
|
assert fk == sk.frozen_key(rid, set()) and fk.startswith("GX9")
|
|
assert frozen["덮개"] == {} and frozen["더한줄"] == [] and frozen["뺀줄"] == []
|
|
assert frozen["원본"]["덮개"]["labor:LB000036#0"]["qty"] == 0.5 # 고친 근거
|
|
assert [r["키"] for r in bundle[sk.FILE]["줄"]] == [fk]
|
|
json.dumps(rows["참조사본"], ensure_ascii=False) # 사본 파일로 쓸 수 있는 꼴(Decimal 없음)
|
|
(world["personal"] / "sangeun" / f"{key}.json").unlink() # 원본이 사라져도 사본만 봄
|
|
got = prices.calc(rows, json.loads(json.dumps(bundle, ensure_ascii=False)), {}, {}, None)
|
|
line = got["줄"][0]
|
|
assert not line["까닭"]
|
|
for part in ("노무비", "재료비", "경비", "계"):
|
|
assert line["기준"][part] == pytest.approx(live["기준"][part], rel=1e-9)
|
|
assert line["반영"]["계"] == pytest.approx(live["반영"]["계"], rel=1e-9)
|
|
|
|
|
|
def test_같은_SK_같은_굳힌_키_다른_SK_다른_키(world):
|
|
key, ref = _mine(world)
|
|
doc, _ = _top(ref)
|
|
rid = refs.ref_id(ref["ref"])
|
|
first = source.labor_doc_rows(doc)["참조사본"][rid]["바탕"]["로직"]
|
|
with store.at(world["personal"]): # SK 를 고쳐도 굳힌 키 그대로(B09 덮개 짝 지킴)
|
|
now = store.read("sangeun", key)
|
|
store.write("sangeun", key, now["판"], {**now["문서"], "덮개": {}})
|
|
again = source.labor_doc_rows(doc)["참조사본"][rid]
|
|
assert again["바탕"]["로직"] == first and again["원본"]["덮개"] == {}
|
|
other = refs.ref_id({"층": "company", "주인": "7", "키": key}) # 같은 번호 다른 층
|
|
assert sk.frozen_key(other, set()) != first
|
|
taken = {first}
|
|
assert sk.frozen_key(rid, taken) != first and len(taken) == 2 # 겹치면 다음 번호
|
|
|
|
|
|
def test_B09_서고_사본_값_같음_원본판(world, tmp_path):
|
|
_, ref = _mine(world)
|
|
with store.at(world["personal"]):
|
|
sc = refs.create(
|
|
"precombo",
|
|
{"이름": "조합", "단위": "㎡", "담은로직": [{"참조": ref["ref"], "수량": {"손": 2}}]},
|
|
)["이름"]
|
|
# 742-1 = SC 안 줄 수량(손 2) 저장 → 굳힌 사본 = 저장 2 · 쓰는 쪽 알약 값(2)이 앞섬(층 · 사본 같은 값)
|
|
pill = f"{refs.ref_id({**MINE, '키': sc})}#0"
|
|
with store.at(world["personal"]):
|
|
top = labor.clean(
|
|
{"열": "rv", "담은로직": [{"참조": {**MINE, "키": sc}, "수량": {"손": 1}}]}
|
|
)
|
|
live = labor.calc(top, {pill: 2})["줄"][0]
|
|
area = {"시트": [{"id": "s", "칸": {"A1": {"값": 2}}, "연결": [{"칸": "A1", "키": pill}]}]}
|
|
before = _print(world["personal"])
|
|
root = tmp_path / "proj"
|
|
made = library.import_copy(root, "precombo", "personal", "7/42", sc)
|
|
assert made["만듦"] and _print(world["personal"]) == before
|
|
folder = library.library_dir(root) / made["폴더"]
|
|
read = {p.name: json.loads(p.read_text(encoding="utf-8")) for p in folder.glob("*.json")}
|
|
bare = prices.calc(read[source.LABOR_FILE], read[source.PRICE_FILE], {}, {}, None)["줄"][0]
|
|
assert bare["기준"]["계"] == pytest.approx(
|
|
live["기준"]["계"], rel=1e-9
|
|
) # 이은 값 없음 = 저장 2
|
|
got = prices.calc(read[source.LABOR_FILE], read[source.PRICE_FILE], {}, {}, area)["줄"][0]
|
|
assert not got["까닭"] and not live["까닭"]
|
|
assert got["기준"]["계"] == pytest.approx(live["기준"]["계"], rel=1e-9)
|
|
mark = read["manifest.json"]["원본판"]
|
|
built = library._build("precombo", "personal", "7/42", sc)[0]
|
|
assert library.source_version(built) == mark # 다시 모아도 같은 판
|
|
again = library.import_copy(root, "precombo", "personal", "7/42", sc)
|
|
assert again == {"폴더": made["폴더"], "만듦": False}
|
|
with store.at(world["personal"]): # 740-1 — SK 고쳐도 SC 는 펼친 사본이라 원본판 그대로
|
|
now = store.read("sangeun", ref["ref"]["키"])
|
|
store.write("sangeun", ref["ref"]["키"], now["판"], {**now["문서"], "덮개": {}})
|
|
assert library.source_version(library._build("precombo", "personal", "7/42", sc)[0]) == mark
|
|
|
|
|
|
def test_SK_없는_사본_그대로():
|
|
"""SK 없는 참조사본 = 받은 묶음 그대로(기존 사본 · 공사 금액 전후 같음)."""
|
|
copies = {"x": {"종류": "사전조합", "담은로직": []}}
|
|
assert sk.freeze(copies) is copies and sk.rows(copies) == [] and sk.materials(copies) == []
|