feat(795-3): 옛 SK · SC · 일위대가 사본 옮기기 도구 — 전후 금액 대조 · 같음만 씀 · 백업 · 되돌림

- 새 M02_Copy_Migrate — 사본 없는 마스터 · 회사 · 개인 층 문서에 지금 M01 사본 찍어 대조(SK 기준 · SC · 일위대가 기준합 · 반영합)
- 같음 = 사본 칸만 더해 씀 · 다름 · 못 셈 = 안 씀(목록) · 프로젝트 층 일위대가 = 세기 · 대조만(795-4)
- --apply 는 --backup 폴더 필수 · --restore 로 다시 덮음 · 기본 = 보기만(표)
- 실제 storage 보기만 결과 — 다름 0 · 층 문서 같음 41 · 필요없음 6 · 프로젝트 같음 70 · 못셈 14(옛 SP 참조) · 옮기지 않음
- 시험 test_795_3_migrate 3(임시 storage)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 11:32:22 +09:00
co-authored by Claude Opus 5.5
parent cc259d1121
commit 16d7eede50
2 changed files with 255 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀
"""795-3 옛 SK · SC · 일위대가 → 로직 사본 옮기기 — 임시 storage 에서만.
① 보기만 = 안 씀 · 전후 같음 ② 쓰기 = 사본 칸만 더함 · 다른 칸 그대로 · 금액 같음 · 백업 · 되돌림
③ 전후 다르면 안 씀(목록) ④ 프로젝트 층 일위대가 = 세기 · 대조만.
"""
from __future__ import annotations
import copy
import json
from M02_MasterTemplete import M02_Copy_Migrate as mig
from M02_MasterTemplete import M02_Labor_Copy as lc
from M02_MasterTemplete import M02_Labor_Ref as refs
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_Sangeun_Copy as skc
from M02_MasterTemplete import M02_Template_Layers as layers
from resources.tester.test_795_1_sk_copy import _fake, _live
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
PCT, LB = "GC001109", "LB000036"
LINE = {"로직": PCT, "수량": {"손": 1}}
def _old(path):
"""사본 칸 뗀 옛 문서로 되씀 → 옛 내용."""
raw = {k: v for k, v in json.loads(path.read_bytes()).items() if k != skc.KEY}
path.write_text(json.dumps(raw, ensure_ascii=False), encoding="utf-8")
return raw
def _make(me):
with store.at(me):
sk = refs.create(
"sangeun", {"이름": "sub2임시", "단위": "㎡", "바탕": {"로직": PCT}, "더한줄": []}
)["이름"]
sc = refs.create("precombo", {"이름": "sub2임시", "단위": "㎡", "담은로직": [LINE]})["이름"]
store.write("labor", "sub2임시", "", {"열": "sub2임시", "담은로직": [LINE], "자재": []})
paths = [me / "sangeun" / f"{sk}.json", me / "precombo" / f"{sc}.json"]
paths.append(me / "labor" / "sub2임시.json")
return {p: _old(p) for p in paths}
def _mine(rows, olds):
keys = {p.stem for p in olds}
return {r["키"]: r for r in rows if r["어디"].startswith("개인") and r["키"] in keys}
def test_dry_then_apply_then_restore(world, tmp_path):
"""① · ② 보기만 → 쓰기(사본만 더함 · 금액 같음) → 되돌림 = 처음 파일."""
olds = _make(world["personal"])
rows = _mine(mig.migrate(), olds)
assert {r["상태"] for r in rows.values()} == {"같음"} and len(rows) == 3
assert not any(r["씀"] for r in rows.values())
assert all(json.loads(p.read_bytes()) == raw for p, raw in olds.items())
back = tmp_path / "back"
rows = _mine(mig.migrate(True, back), olds)
assert all(r["씀"] for r in rows.values())
for path, raw in olds.items():
now = json.loads(path.read_bytes())
assert skc.has(now) and {k: v for k, v in now.items() if k != skc.KEY} == raw
again = _mine(mig.migrate(), olds) # 다시 돌림 = 이미 있음
assert {r["상태"] for r in again.values()} == {"있음"}
assert {r["전"]["계"] for r in rows.values() if r["종류"] == "sangeun"} == {
r["후"]["계"] for r in rows.values() if r["종류"] == "sangeun"
}
mig.restore(back)
assert all(json.loads(p.read_bytes()) == raw for p, raw in olds.items())
def test_different_amount_not_written(world, monkeypatch, tmp_path):
"""③ 찍은 사본 금액이 지금과 다르면(노임 다른 판) 안 씀 · 까닭."""
olds = _make(world["personal"])
real = lc.stamp
def stale(doc): # 노임 두 배 판으로 찍힌 사본 흉내
with monkeypatch.context() as m:
row = copy.deepcopy(_live().get(LB))
row["값"] = row["값"] * 2
_fake(m, [row])
return real(doc)
monkeypatch.setattr(lc, "stamp", stale)
rows = _mine(mig.migrate(True, tmp_path / "back"), olds)
bad = [r for r in rows.values() if r["종류"] != "sangeun"]
assert {r["상태"] for r in bad} == {"다름"} and not any(r["씀"] for r in bad)
assert all(not skc.has(json.loads(p.read_bytes())) for p in olds if p.parent.name != "sangeun")
def test_project_labor_count_only(world, tmp_path):
"""④ 프로젝트 층 일위대가 = 대조만 · 안 씀."""
folder = layers.storage_root() / "7" / "42" / "p1" / "templates" / "labor"
folder.mkdir(parents=True)
path = folder / "x.json"
raw = {"열": "x", "담은로직": [LINE], "자재": []}
path.write_text(json.dumps(raw, ensure_ascii=False), encoding="utf-8")
rows = [r for r in mig.migrate(True, tmp_path / "back") if r["어디"].startswith("프로젝트")]
assert [(r["키"], r["상태"], r["씀"]) for r in rows] == [("x", "같음", False)]
assert json.loads(path.read_bytes()) == raw
assert mig.table(rows) == {"프로젝트 labor": {"같음": 1}}