- [수정] 모달 = Labor_Table(읽기 · 덧칸 표지 · 엑셀 금액) · 줄 = 로직(단가산출 · 일위대가) / 요소(연결됨 · 후보 · 못 이음) · 단가산출 줄 = 가져온 식 SK 수식 탭 모달(Labor_SkEdit) · 서버 hopyo-view(M02_Hopyo_View) - 엑셀 보기 목록 · 칠 = 줄 표지(View.listing) · 단가산출 탭 = 블록 목록 + [가져온 식으로 열기] · [내 단가산출로] - 걷음(요구 703): 판정 체계 785(Judge · Solve · Bind · San_Basis 다섯 · Make.Move · Row 1차 판정 · 화면 Check · CheckRows · Rows · Block · JudgeApi · Picks · Judge.css) · [우리 기초로 바꾸기](to-base) · 근거 기초 제안 · Clause 기초 판정 - 시험 지움: 642_2(Bind · Solve) · 642_3(Row 1차 판정) · 642_5(옮기기 Move) · 642_6(판정 화면) · 786_2(옛 [수정] 모달) · 793_3a(근거 → 기초 제안) — 모두 걷은 기초 판정 길 몫 - 시험 고침: 642_1 · 794_2a2 · 794_2b(근거 제안 부분만 뺌) · 793_2 · 793_3b(기초 바꾸기 기대 → 없음) · 627 · 779_2 · 785_4 · 807_1 · m02_hopyo_excel · grid · stmate(judge 길 → view 길) - 새 시험 test_809_1_import_labor(기초 길 0 · 표지 1,350 줄 · 가져온 식 SK · 모달 = Labor_Table · 금액 = 엑셀) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
160 lines
6.9 KiB
Python
160 lines
6.9 KiB
Python
"""일위대가 실무자료 엑셀꼴 격자(PLAN 329-1 · `M02_Hopyo_Grid` · `GET hopyo-grid/{키}`).
|
|
|
|
북부청 임도 xls — 병합 11 · 15열 · B20 「제3호표」 · `#,##0` · 호표 68 행 범위 안 겹침 ·
|
|
제3호표 [20, 24] · 올리면 격자도 · 200 / 옛 파일 404 · 지우면 격자도 · 역할 · xlsx 값만 ·
|
|
STmate 격자(일위대가표 · 단가산출근거 · 숨은 칸 글 뺌 · 338) ·
|
|
master_data 그대로.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from M02_MasterTemplete import M02_Hopyo_Excel as hx
|
|
from M02_MasterTemplete import M02_Hopyo_Grid as hg
|
|
from M02_MasterTemplete import M02_Hopyo_Store as hs
|
|
from M02_MasterTemplete import M02_Template_Layers as layers
|
|
from resources.tester import test_m02_hopyo_excel as base
|
|
from resources.tester.test_m02_hopyo_excel import (
|
|
NORTH,
|
|
URL,
|
|
_post,
|
|
_xlsx,
|
|
master_hash,
|
|
)
|
|
|
|
client = base.client # 공용 고정물(임시 층)
|
|
GRID = "/api/m02/layers/{}/hopyo-grid/{}"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def north() -> dict:
|
|
data = NORTH.read_bytes()
|
|
return hg.read(NORTH.name, data, hx.read_book(NORTH.name, data))
|
|
|
|
|
|
def _sheet(grid: dict, name: str) -> dict:
|
|
return next(s for s in grid["책"]["시트"] if s["이름"] == name)
|
|
|
|
|
|
def test_격자_모양(north):
|
|
book = north["책"]
|
|
assert (book["종류"], book["판"], book["활성"]) == ("통합문서", 1, "s1")
|
|
assert [s["이름"] for s in book["시트"]] == ["일위대가", "단가산출총괄표", "단가산출"]
|
|
sheet = _sheet(north, "일위대가")
|
|
assert len(sheet["병합"]) == 11 and "B1:O2" in sheet["병합"]
|
|
assert len(sheet["열"]) == 15 and sheet["열"]["C"]["폭"] == round(7208 / 256, 2)
|
|
assert sheet["틀고정"] == {"행": 4}
|
|
assert sheet["칸"]["B20"]["값"] == "제3호표"
|
|
assert sheet["칸"]["H5"]["값"] == 1040052
|
|
styles = book["서식"]
|
|
assert styles[0] == {} and any(s.get("형식") == "#,##0" for s in styles)
|
|
assert any(s.get("테두리") for s in styles)
|
|
assert _sheet(north, "단가산출")["칸"]["B4"]["값"] == "1.유용토운반(무대)[㎥]"
|
|
|
|
|
|
def test_호표_단산_행_범위(north):
|
|
rows = [h["행"] for h in north["호표"]]
|
|
assert len(rows) == 68
|
|
assert all(a[1] < b[0] for a, b in zip(sorted(rows), sorted(rows)[1:], strict=False))
|
|
assert next(h for h in north["호표"] if h["번"] == 3) == {
|
|
"번": 3,
|
|
"이름": "임도표지석",
|
|
"행": [20, 24],
|
|
}
|
|
assert len(north["단산"]) == 95
|
|
assert next(b for b in north["단산"] if b["번"] == 93)["행"] == [4229, 4244]
|
|
|
|
|
|
def test_줄_행(north):
|
|
book = hx.read_book(NORTH.name, NORTH.read_bytes())
|
|
three = next(h for h in book["호표"] if h["번"] == 3)
|
|
assert three["행"] == [20, 24] and [x["행"] for x in three["줄"]] == [21, 22, 23, 24]
|
|
|
|
|
|
def test_올리기_격자_200_404_지우기(client):
|
|
before = master_hash()
|
|
assert _post(client).status_code == 200
|
|
res = client.get(GRID.format("personal", "HP-000001"))
|
|
assert res.status_code == 200, res.text
|
|
got = res.json()
|
|
assert got["책"]["열"] == "HP-000001" and len(got["호표"]) == 68
|
|
folder = layers.personal_dir(7, 42)
|
|
path = folder / hs.DIRNAME / hs.GRID / "HP-000001.json"
|
|
assert path.is_file()
|
|
assert [r["키"] for r in client.get(URL.format("personal")).json()["줄"]] == ["HP-000001"]
|
|
path.unlink() # 옛 파일(324) = 격자 없음
|
|
old = client.get(GRID.format("personal", "HP-000001"))
|
|
assert old.status_code == 404 and old.json()["detail"] == "격자 없음 — 다시 올리면 보임"
|
|
assert client.delete(URL.format("personal") + "/HP-000001").status_code == 200
|
|
assert _post(client).status_code == 200 # 718-1 — 같은 엑셀은 지운 뒤 새 번
|
|
assert client.get(GRID.format("personal", "HP-000002")).status_code == 200
|
|
assert client.delete(URL.format("personal") + "/HP-000002").status_code == 200
|
|
assert not (folder / hs.DIRNAME / hs.GRID / "HP-000002.json").exists()
|
|
assert client.get(GRID.format("personal", "HP-000002")).status_code == 404
|
|
assert client.get(GRID.format("personal", "../x")).status_code == 404
|
|
gone = client.get(URL.format("personal") + "-view/HP-000001/3") # 718-1 지운 뒤 = 없음
|
|
assert gone.status_code == 404 and "없는 실무자료" in gone.json()["detail"]
|
|
assert master_hash() == before
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("role", "layer", "owner", "want"),
|
|
[
|
|
({"role": "USER"}, "personal", None, 200),
|
|
({"role": "USER"}, "personal", "7/43", 403),
|
|
({"role": "USER"}, "company", None, 200),
|
|
({"role": "USER"}, "system", None, 200),
|
|
],
|
|
)
|
|
def test_역할_읽기(client, role, layer, owner, want):
|
|
client.who.update({"role": "SYSTEM_ADMIN"})
|
|
assert _post(client, layer if want == 200 else "personal").status_code == 200
|
|
client.who.update(role)
|
|
params = {"owner": owner} if owner else {}
|
|
assert client.get(GRID.format(layer, "HP-000001"), params=params).status_code == want
|
|
|
|
|
|
@pytest.mark.parametrize("layer", ["company", "system"])
|
|
def test_위_층_격자_읽기(client, layer):
|
|
"""아래 층 사용자가 위 층 목록 키로 위 층 파일 격자를 읽음."""
|
|
client.who.update({"role": "SYSTEM_ADMIN"})
|
|
assert _post(client, layer).status_code == 200
|
|
client.who.update({"role": "USER"})
|
|
rows = client.get(URL.format(layer)).json()[
|
|
"줄"
|
|
] # 위 층 목록(옛 「실무 호표」 고르기 줄 갈음 · 785-7)
|
|
res = client.get(GRID.format(layer, rows[0]["키"]))
|
|
assert res.status_code == 200 and len(res.json()["호표"]) == 68
|
|
|
|
|
|
def test_xlsx_값만():
|
|
data = _xlsx()
|
|
grid = hg.read("a.xlsx", data, hx.read_book("a.xlsx", data))
|
|
sheet = grid["책"]["시트"][0]
|
|
assert sheet["이름"] == "일위대가" and sheet["틀고정"] == {"행": 4}
|
|
assert sheet["칸"]["B5"] == {"값": "제 1 호표"} and sheet["칸"]["E6"] == {"값": 0.5}
|
|
assert "K6" not in sheet["칸"] # 머리 글(앞 4 줄) 마지막 열 J 까지
|
|
assert grid["호표"] == [{"번": 1, "이름": "표지석", "행": [5, 6]}] and grid["단산"] == []
|
|
|
|
|
|
def test_STmate_격자():
|
|
from resources.tester.test_m02_hopyo_stmate import _path
|
|
|
|
path = _path("영월")
|
|
data = path.read_bytes()
|
|
parsed = hx.read_book(path.name, data)
|
|
grid = hg.read(path.name, data, parsed)
|
|
assert [s["이름"] for s in grid["책"]["시트"]] == [
|
|
"일위대가표",
|
|
"단가산출근거목록표",
|
|
"단가산출근거",
|
|
]
|
|
cells = _sheet(grid, "일위대가표")["칸"]
|
|
one = grid["호표"][0]
|
|
assert one == {"번": 1, "이름": "녹생토(종자배합)", "행": [5, 10]}
|
|
assert cells[f"A{one['행'][0]}"]["값"].strip().startswith("제")
|
|
assert cells["A10"]["값"] == "보통인부"
|
|
calc = _sheet(grid, "단가산출근거")["칸"]
|
|
block = next(b for b in grid["단산"] if b["번"] == 2)
|
|
assert calc[f"B{block['행'][0] + 1}"]["값"].startswith("구조물터파기(인력)")
|
|
assert not any(str(c.get("값")).startswith("_x000") for c in {**cells, **calc}.values())
|