Files
Aislo/resources/tester/test_778_5_sk_pick_screen.py
T
eomsangdonandClaude Opus 5.5 8a5689c400 feat(780-2): 엑셀 보기 단가산출 탭 오른쪽 = 단가산출 목록 — 판 바꾸기 · 거르기 · 목록 ↔ 시트 · 두 벌 맞춤(요구 627)
- 새 Hopyo_SheetSk: 탭(역할) 따라 오른쪽 판 바꿈 · 일위대가표 = 호표 목록 그대로 · 단가산출표 · 상세 = 마법사 단가산출 칸 좁은 꼴 한 벌(처음 올 때 지음 · 다른 층 · 권한 없음 = 보기만) · 시트 칸 → 목록 강조 · 목록 줄 → 지금 탭 블록 자리
- WizardSk: 좁은 꼴 옵션 · 부름 칸(일위대가 n 곳 · 일위대가 밖) · 거르기(전체 · 안 · 밖 · 고를 줄 있음) · 같은 캐시 두 벌 맞춤 알림 · 옮김 뒤 HOPYO_BUILT(열린 엑셀 보기 칠 다시)
- SkPick: 줄 0 블록 = 「줄 없음」 확인 막음 · 거르기 · 끝내기 글 재료에 일위대가 밖 수
- SheetNav: role · blockAt · spotOf 내보냄 · SheetMap: 판정 없음 글 → 「일위대가 밖」
- Wizard [끝내기]: 막지 않음 · 물음창에 안 옮긴 단가산출 n(일위대가 밖 m)
- 시험: 새 test_627_sheet_sk(판 바꿈 · 목록 지음 · 줄 0 막음 · 캐시 공유) · test_778_5 끝내기 재료 꼴에 밖 칸 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 18:01:06 +09:00

133 lines
5.8 KiB
Python

"""778-5 D-5 지킴 — 마법사 단가산출 줄 고름(제안 · 확인 뒤 옮김 · 요구 621 · 622 · 623 · 624).
서버 없이 잡음: 줄 고름 캐시가 서버 상태를 덮음(「내가 고름」) · [확인] = 고를 줄 0 일 때만 · 몸 = 이음 줄
`{확인: [{번, 고름?: {차례: 고름}}]}`(확인한 블록만) · 자동 확인 없음(빈 캐시 = 빈 몸 · 「모두 확인」 단추 없음) ·
화면 = 부품 상자만 · 700 줄.
"""
import json
import os
import re
import subprocess
from pathlib import Path
HERE = os.path.dirname(__file__)
M02 = Path(__file__).resolve().parents[2] / "M02_MasterTemplete"
def _line(at, kind, state, **more):
row = {"차례": at, "행": 100 + at, "묶음": kind, "이름": f"줄{at}", "규격": "", "매개값": {}}
row |= {"엑셀금액": 1000.0, "상태": state, "방법": "", "단위": None, "후보": [], "꼬리표": []}
return {**row, "글": "", "우리금액": None, "차": None, **more}
def _block(no, lines, made=None):
head = {"번": no, "이름": f"블록{no}", "단위": "㎥", "판정": "", "고를줄": 0, "우리금액": None}
return head | {"엑셀금액": 5000.0, "근거": None, "만든": made, "줄": lines}
BOSS = ["기본 — 건설업 작업반장"]
BLOCKS = [
_block(
2,
[
_line(0, "L", "이어짐", 매개값={"품": 0.2}),
_line(1, "L", "이어짐", 꼬리표=BOSS, 후보=[{"키": "LB000099"}]),
_line(2, "M", "고를 것", 후보=[{"자재": "MT000123"}]),
_line(3, "M", "못 이음"),
_line(4, "R", "밖"),
],
),
_block(5, [_line(0, "X", "이어짐"), _line(1, "R", "이어짐")]),
_block(7, [_line(0, "S", "못 이음")], made=None),
]
def _run() -> dict:
proc = subprocess.run(
["node", os.path.join(HERE, "helper_778_5_sk_pick.cjs")],
input=json.dumps({"blocks": BLOCKS}, ensure_ascii=False),
capture_output=True,
text=True,
encoding="utf-8",
check=False,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_판정_확인_켜짐_조건():
got = _run()
assert got["start"] == [
{"번": 2, "판정": "고를 줄 2", "확인켜짐": False},
{"번": 5, "판정": "옮길 수 있음", "확인켜짐": True},
{"번": 7, "판정": "고를 줄 1", "확인켜짐": False},
]
assert got["sureBlocked"] == [] # 고를 줄 남은 블록 = [확인] 안 켜짐
assert got["half"] == {"판정": "고를 줄 2", "켜짐": False} # 이어진 줄 바꿈은 고를 줄 안 줄임
assert got["full"] == {"판정": "옮길 수 있음", "켜짐": True}
assert got["sure"] == [2, 5] # 하위 못 이음 블록 7 = 안 켜짐
def test_줄_표_꼴_내가_고름이_덮음():
view = _run()["view"]
assert view[0] == {"상태": "이어짐", "꼬리표": [], "글": "", "mine": False}
assert view[1] == {"상태": "이어짐", "꼬리표": ["내가 고름"], "글": "LB000099", "mine": True}
assert view[2]["상태"] == "이어짐" and view[2]["글"] == "MT000123"
assert view[3] == {
"상태": "뺌",
"꼬리표": ["내가 고름"],
"글": "뺌 · 우리에 없음",
"mine": True,
}
assert view[4]["상태"] == "밖"
def test_몸_꼴_이음_줄_자동_확인_없음():
got = _run()
assert got["emptyBody"] == [] # 누른 것 없음 = 몸 비움
picks = {"1": {"노임": "LB000099"}, "2": {"자재": "MT000123"}, "3": {"뺌": "우리에 없음"}}
assert got["body"] == [{"번": 2, "고름": picks}, {"번": 5}]
first, second = got["calls"]
assert first["method"] == "POST" and first["body"] == {"확인": []} # 판정만
assert first["url"].endswith("/layers/personal/hopyo/HP-000001/sangeun")
assert second["body"] == {"확인": got["body"]}
assert got["wait"] == {
"블록": 3,
"밖": 0,
"줄": 1,
} # 안 옮긴 블록 셋 · 블록 7 하위 줄 · 옛 서버 = 밖 없음
assert got["tidy"] == [5] # 고름 지우면 그 블록 확인 빠짐
assert got["round"]["확인"] == [2, 5] and got["bad"] == {"고름": {}, "확인": []}
def test_후보_고름_꼴():
cand = _run()["cand"]
assert cand["L"] == {"노임": "LB000001"} and cand["X"] == {"기계": "EQ000019"}
assert cand["M"] == {"자재": "MT000001"} and cand["R"] == {"기준": "노무비", "비목": "경비"}
assert cand["Mbad"] is None and cand["text"] == "합판 12mm [장]"
def _src(name: str) -> str:
return (M02 / f"M02_MasterTemplete_Hopyo_{name}.ts").read_text(encoding="utf-8")
def test_화면_자동_없음_부품_상자만():
wiz = _src("WizardSk")
assert "judgeSangeun(scope, key)" in wiz # 열 때 = 판정만
assert "judgeSangeun(scope, key, body)" in wiz and "sureBody(load(), got.판정)" in wiz
assert "모두" not in wiz.split("*/", 1)[1] and "setSure(" in wiz # 확인은 블록마다만
assert 'kind: "chip"' in wiz and "disabled: !ok" in wiz # [확인] 칩 · 고를 줄 0 일 때만
assert "단산행: 행" in wiz # 엑셀 보기 뛰기
lines = _src("SkLines")
assert "lineFind(" in lines and "unitTone(" in lines # 찾기 창 · 엑셀 칠과 한 규칙
wizard = _src("Wizard")
assert 'L("M02_SkLeft")' in wizard and "sk?.count()" in wizard # [끝내기] 막힘 글
for name in ("WizardSk", "SkLines", "SkApi", "Lost", "Compare"):
src = _src(name)
assert len(src.splitlines()) <= 700, name
assert not re.search(r'el\("(button|input|select)"|<button|<input', src), name
assert not re.search(r"#[0-9a-fA-F]{3,6}\b|rgb\(", src), name
logic = (M02 / "logic" / "M02_MasterTemplete_Hopyo_SkPick.ts").read_text(encoding="utf-8")
assert not re.search(r"sessionStorage\.|fetch\(|document\.", logic) # 순수