Files
Aislo/resources/tester/test_572_hopyo_same.py
T
eomsangdonandClaude Opus 5.5 4cdb41f80b feat(778-5): 블록 = 줄 판정 모음 · 확인한 블록만 단위 SK(바탕 없음 · 근거 꼬리표) · 확인 목록 받는 길(D-3 · 요구 623 · 624)
- 새 M02_Hopyo_SkUnit: 줄 판정(Units 잇기 + 매개값 · 사용자 고름 {차례: 노임|기계|자재|기준|뺌} · 꼬리표 「내가 고름」) · 단가 = M01 지금 값으로 다시 셈(우리금액) · 엑셀 금액 차 = 참고 · 블록 판정 「옮길 수 있음」 | 「고를 줄 n」 · 단위 SK 더한줄 = 인력 · 기계경비 로직 줄 · 재료(손료율 든 수량 · 별도계상) · 율 줄(778-4 꼴 · 줄 목록 = 그 행 add:#k) · 하위 참조 · 값 고정 줄 · 저장 꼴로 다듬어 같은 내용 SK 지문 같음
- Sangeun: 기초 · SK · 고름 대기 갈림(SkPatch.plan) 걷고 단위 SK 하나 · 확인 [{번, 고름?}] 에 든 블록만 만듦 · 하위 단산 먼저 · 고를 줄 남으면 못만듦 · 일위대가 만들기가 부르는 Maker.plan(번) = 「확인 전」 고름 대기(자동 없음) · 별칭 제안 걷음(바탕 기초 없음)
- Router: sangeun 몸 바탕 → 확인(줄 수 그대로)
- 시험 새 뜻: test_729(기초 · SK · 고름 대기 · 계수 · 못옮김 잇기 · 729-5 차이 SK 바탕 길 = 바탕 없는 단위 SK 로 사라짐 → 확인 블록 단위 SK · 줄 고름 · 뺌으로 갈음) · test_718_1 · test_572 · test_779_2 · test_m02_hopyo_flow(확인 목록을 보내야 SK 생김 · 같은 파일 안 같은 내용 단위 SK 없을 수 있음 · 바탕 없는 SK = SC 에 참조 그대로)
- 새 test_778_5: 작업반장 = 건설업 · 규격 차례 무관 · 글자 규격 = 후보 · 손료율 · 설치비 · 제경비 율 줄 · 여덟 파일 줄 연결 표 · 확인 안 한 블록 안 만듦 · 고름 · 400 · 404 · 다시 올림 같은 SK 재사용 · 일위대가 확인 전 못 이음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 14:16:12 +09:00

117 lines
5.9 KiB
Python

"""불러오기 [단가산출 만들기] 같은 내용 SK 씀(PLAN 733-1b · 요구서_572 3장 2).
북부청 임도(실물)를 임시 층에 → 같은 파일 안 같은 내용 SK 한 벌 · 바이트만 다른 사본 다시 = 새 SK 0 ·
뒤 출처 = `본뜬.또` · 다시 = 그대로 · 위 층(회사) 같은 것 = `위층같음` 알림 ·
출처마다 못옮김 · 다른 출처가 쓰는 SK 내용은 안 바꿈(떼어 냄 · 넘겨줌).
"""
import io
import json
import zipfile
from M02_MasterTemplete import M02_Hopyo_Fit as fit
from M02_MasterTemplete import M02_Hopyo_Sangeun as sangeun
from M02_MasterTemplete import M02_Library_Same as same
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_Template_Layers as layers
from resources.tester.test_572_library_same import _put
from resources.tester.test_m02_hopyo_excel import NORTH, URL, _post, client # noqa: F401
def _rezip(data: bytes) -> bytes:
"""내용 같고 바이트 다른 사본 — xlsx = 다시 묶음 · xls = 끝에 빈 칸 한 벌(512 바이트)."""
if not zipfile.is_zipfile(io.BytesIO(data)):
return data + bytes(512)
src, buf = zipfile.ZipFile(io.BytesIO(data)), io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED, compresslevel=1) as z:
for info in src.infolist():
z.writestr(
zipfile.ZipInfo(info.filename, (2026, 1, 1, 0, 0, 0)), src.read(info.filename)
)
return buf.getvalue()
def _sks(folder) -> dict[str, dict]:
paths = sorted((folder / "sangeun").glob("SK-*.json"))
return {p.stem: json.loads(p.read_bytes()) for p in paths}
def _make(client, folder, data, name):
res = _post(client, data=data, name=name)
assert res.status_code == 200, res.text
key = res.json()["키"]
fit.run_job(folder, key)
url = f"{URL.format('personal')}/{key}/sangeun"
rows = client.post(url).json()["판정"] # 778-5 — 확인한 블록만(옮길 수 있음 모두 확인)
got = client.post(url, json={"확인": [{"번": r["번"]} for r in rows if not r["고를줄"]]})
assert got.status_code == 200, got.text
return key, got.json()
def test_불러오기_같은내용_SK_씀_바이트만_다른_사본_새_SK_0(client):
folder = layers.personal_dir(7, 42)
data = NORTH.read_bytes()
hp1, one = _make(client, folder, data, NORTH.name)
docs = _sks(folder)
fingers = [same.finger("sangeun", d) for d in docs.values()]
assert len(fingers) == len(set(fingers)) # 같은 내용 SK 한 벌
assert one["만듦"] and len(docs) + len(one["같은것씀"]) == len(one["만듦"])
assert one["위층같음"] == []
again = client.post(f"{URL.format('personal')}/{hp1}/sangeun").json()
assert again["만듦"] == [] and again["그대로"] == len(one["만듦"])
# 위 층(회사)에 같은 것 = 알림만
firm = layers.company_dir(7)
first = next(iter(docs))
_put(firm, "sangeun", "SK-000001", docs[first])
# 바이트만 다른 사본 = 새 HP · 새 SK 0 · 뒤 출처 = 본뜬.또
hp2, two = _make(client, folder, _rezip(data), "사본_" + NORTH.name)
assert hp2 != hp1 and _sks(folder).keys() == docs.keys()
assert len(two["만듦"]) == len(one["만듦"]) == len(two["같은것씀"])
assert {"층": "company", "주인": "7", "키": "SK-000001"} in [
{k: x[k] for k in ("층", "주인", "키")} for x in two["위층같음"]
]
also = {x["키"].split(" ")[0] for d in _sks(folder).values() for x in d["본뜬"].get("또", [])}
assert also == (
{hp1, hp2} if one["같은것씀"] else {hp2}
) # 778-5 단위 SK = 파일 안 겹침 없을 수 있음
again = client.post(f"{URL.format('personal')}/{hp2}/sangeun").json()
assert again["만듦"] == [] and again["그대로"] == len(one["만듦"])
def _maker(hp: str) -> sangeun.Maker:
"""블록 하나짜리 만들기(파일 · 맞춤셈 없이) — 쓰기 규칙만 봄."""
m = object.__new__(sangeun.Maker)
m.first, m.blocks = {1: {"이름": "줄", "단위": "㎥"}}, {1: {"이름": "블록"}}
m.hp, m.sure = {"키": hp, "파일": f"{hp}.xls"}, {"원본": ["personal", "7/42"]}
m.same, m.reused, m.above = same.Same(), [], []
return m
def _plan(code: str, lost: list) -> dict:
keep = {"갈래": "기초", "엑셀품": {}, "못옮김": lost, "바탕": {"로직": code}, "입력값": {}}
return {**keep, "자재표시": {}, "덮개": {}, "더한줄": [], "뺀줄": []}
def test_같은내용_SK_출처마다_못옮김_떼어냄_넘겨줌(client):
folder, at = layers.personal_dir(7, 42), ("personal", "7/42")
one, two = _maker("HP-000001"), _maker("HP-000002")
with store.at(folder):
key = one.write(1, _plan("GF000113", []), None)
assert two.write(1, _plan("GF000113", [{"id": "x"}]), None) == key # 같은 것 씀
assert two.reused == [{"번": 1, "키": key}]
doc = _sks(folder)[key]
assert sangeun.origin_of(doc, "HP-000002 단산1", at)["못옮김"] == [{"id": "x"}]
assert sangeun.origin_of(doc, "HP-000001 단산1", at)["못옮김"] == []
assert sangeun.made(folder, "HP-000002", at) == {"HP-000002 단산1": key}
# 뒤 출처가 바탕을 바꿈 = 떼어 냄 · 남의 SK 내용 그대로
moved = _maker("HP-000002").write(1, _plan("GF000114", []), key)
assert moved != key and "또" not in _sks(folder)[key]["본뜬"]
assert _sks(folder)[key]["바탕"]["로직"] == "GF000113"
# 앞 출처가 바탕을 바꿈 = 뒤 출처에게 넘겨줌
assert _maker("HP-000003").write(1, _plan("GF000113", []), None) == key
back = _maker("HP-000001").write(1, _plan("GF000114", []), key)
assert back == moved # 바꾼 내용 = 이미 있는 같은 것
left = _sks(folder)[key]
assert left["바탕"]["로직"] == "GF000113" and left["본뜬"]["키"] == "HP-000003 단산1"
assert "또" not in left["본뜬"] and len(_sks(folder)) == 2