- 새 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>
133 lines
5.8 KiB
Python
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) # 순수
|