- 새 Hopyo_Check(모달 껍데기 · 머리 = 호표 · 엑셀 단가 · 제안 n / 줄 m · 확인 n · 만든 일위대가 ·
[호표 제안 모두 확인](새) · [일위대가 생성] = 옮기기 길 이 호표만 · [구조물 조합으로] · [엑셀 보기])
- 새 Hopyo_CheckRows(로직 표 + 자재 표 = 구조물 조합 상세 꼴 · Labor_Rows moneyCell · PRICE_SLOTS ·
Labor_MatMarks 빌려 씀 · 칸마다 엑셀 / 우리 단가 · 품 비교 · [고르기] · [원문 보기] · [옵션] · 추가 / 로직없음)
- 새 Hopyo_ToItem(구조물 조합 나무 add-item → 그 일위대가 문서에 SC 참조 한 줄 · 옮겨진 뒤만 켬)
- Hopyo_Rows: 시트 아래 줄 판 몸 걷음 → 줄 칸 부품 createRowKit(판정 · 고름 칩 · 블록 풀이 · 단위 환산 · [확인]) ·
옮기기 한 번 runMove(오른쪽 [옮기기] · 모달 [일위대가 생성] 한 벌)
- Router: POST /hopyo/{키}/price 우리 금액 미리 셈(저장 없음 · Make.Move.pick · Lines.picks → Labor_Doc.calc 재사용)
- Sheet: [수정] = openHopyoCheck · 시트 아래 자리는 단가산출 블록 판(SheetSk) 몫으로 남김
- 안 살림: 맞음·별칭 일괄 체크 · 품셈으로 바꾸기 · 모두 고정으로(지운 서버 길 몫) · 사용안함(새 옮기기 길에 뺌 없음)
- 시험: 새 test_786_2_check_modal(우리 금액 예시 1 = 94,227 · 예시 3 입력 필요 → 0 · 쓰기 0 · 모달 · 새 배지 ·
공용 import 만 · 날 button/input 0) · test_642_6 단언 = 줄 판 createJudgeRows → 모달 openHopyoCheck(까닭: 줄 판 몸 걷음)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
124 lines
6.0 KiB
Python
124 lines
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""786-2 불러오기 [수정] 모달 지킴 — 「확인 — 제N호표」 옛 꼴 되살림 + 새 기능 「새」 표지
|
|
(요구 644 · 645).
|
|
|
|
- 우리 금액 길(`/hopyo/{키}/price` · 저장 없음) — 옮기기와 같은 길로 한 줄 문서 →
|
|
`Labor_Doc.calc`: 예시 1 야면석소운반(단산10 · GC001140 · 입력 필요 0 · 엑셀 1 단위 94,227) ·
|
|
예시 3 합판거푸집(GC000211 · 높이감률 · 구멍땜 입력 필요 → 0 넣으면 노무 38,291) ·
|
|
쓰기 0(SC · SK 수 그대로)
|
|
- 화면 소스 — [수정] = 모달(`openHopyoCheck` · 부품 상자 모달) · 시트 아래 호표 줄 판 몸 없음 ·
|
|
「새」 배지 · 구조물 조합 공용 부품(`Labor_Rows` · `Labor_MatMarks` · `Labor_Input` ·
|
|
`Labor_Pick`)은 import 만 · 날 button · input · select 0 · 700 줄
|
|
임시 storage(`client` 마당) · M01 원본 그대로.
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from M02_MasterTemplete import M02_Hopyo_Judge as judge
|
|
from M02_MasterTemplete import M02_Template_Layers as layers
|
|
|
|
# ruff: noqa: F811
|
|
from resources.tester.test_m02_hopyo_excel import _post, client, master_hash # noqa: F401
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
M02 = ROOT / "M02_MasterTemplete"
|
|
API = "/api/m02/layers/personal"
|
|
KEY = "HP-000001"
|
|
MINE = ("Check", "CheckRows", "ToItem", "Rows")
|
|
SHARED = ("Labor_Rows", "Labor_MatMarks", "Labor_Input", "Labor_Pick", "Labor_Detail", "Structure")
|
|
|
|
|
|
def _src(name: str) -> str:
|
|
return (M02 / f"M02_MasterTemplete_{name}.ts").read_text(encoding="utf-8")
|
|
|
|
|
|
def _at(unit, no):
|
|
return next(r for r in unit["줄"] if r.get("번") == no and "단가산출" in r["갈래"])
|
|
|
|
|
|
def _base(row):
|
|
part = row["풀이"]["절"][0]
|
|
cand = next(c for c in part["후보"] if c["키"] == part["고름"])
|
|
return {"갈래": "기초", "키": cand["키"], "입력값": cand["바인딩"]["입력값"]}
|
|
|
|
|
|
def _count(kind):
|
|
folder = layers.personal_dir(7, 42) / kind
|
|
return len(list(folder.glob("*.json"))) if folder.exists() else 0
|
|
|
|
|
|
def test_우리금액_옮기기와_같은_길_저장없음(client):
|
|
before = master_hash()
|
|
assert _post(client).status_code == 200
|
|
judge.solve_all(layers.personal_dir(7, 42), KEY)
|
|
made = (_count("precombo"), _count("sangeun"))
|
|
url = f"{API}/hopyo/{KEY}/price"
|
|
|
|
two = client.get(f"{API}/hopyo-judge/{KEY}/2").json()
|
|
ten = _at(two, 10) # 예시 1 야면석소운반
|
|
got = client.post(
|
|
url, json={"층": "personal", "호표": 2, "줄": {str(ten["차례"]): [_base(ten)]}}
|
|
)
|
|
assert got.status_code == 200, got.text
|
|
line = got.json()["줄"][str(ten["차례"])]
|
|
assert line["까닭"] == [] and line["칸"] == []
|
|
assert int(line["금액"]["계"] / ten["수량"]["엑셀"]) == 94227 == ten["단가"]["계"]
|
|
|
|
one = client.get(f"{API}/hopyo-judge/{KEY}/1").json()
|
|
form = _at(one, 24) # 예시 3 합판거푸집
|
|
ex3 = _base(form)
|
|
need = client.post(url, json={"층": "personal", "호표": 1, "줄": {str(form["차례"]): [ex3]}})
|
|
stuck = need.json()["줄"][str(form["차례"])]
|
|
assert stuck["금액"] is None and stuck["칸"] == ["높이감률", "구멍땜"]
|
|
ex3["입력값"] = {**ex3["입력값"], "높이감률": 0, "구멍땜": 0}
|
|
ok = client.post(url, json={"층": "personal", "호표": 1, "줄": {str(form["차례"]): [ex3]}})
|
|
money = ok.json()["줄"][str(form["차례"])]["금액"]
|
|
assert abs(money["노무비"] / form["수량"]["엑셀"] - 38291) <= 2 # 엑셀 노무 38,291(줄 0.1 원 끝수)
|
|
|
|
bad = client.post(
|
|
url, json={"층": "personal", "호표": 2, "줄": {"0": [{**_base(ten), "금액": 1}]}}
|
|
)
|
|
assert bad.status_code == 422 # 금액 칸 = 서버가 셈
|
|
assert (_count("precombo"), _count("sangeun")) == made # 쓰기 0
|
|
assert master_hash() == before
|
|
|
|
|
|
def test_수정은_모달_줄판몸_없음():
|
|
sheet = _src("Hopyo_Sheet")
|
|
edit = sheet.split("const editButton")[1].split("function paintList")[0]
|
|
assert "openHopyoCheck({" in edit and "openLines" not in edit
|
|
assert "createJudgeRows" not in sheet + _src("Hopyo_Rows")
|
|
check = _src("Hopyo_Check")
|
|
assert 'from "@ui/ui_template_modal"' in check and "openModal({" in check
|
|
assert 'L("M02_CheckTitle")' in check and "confirmSuggested(" in check # [호표 제안 모두 확인]
|
|
assert "runMove(" in check and "[String(no)]: mine" in check # [사전조합 생성] = 이 호표만
|
|
assert "h.만든" in check.split("const item = ")[1].split(";")[0] # 옮겨진 뒤만
|
|
locale = (ROOT / "ui_template/ui_template_locale_m2_judge.ts").read_text(encoding="utf-8")
|
|
assert 'M02_CheckTitle: ["확인 — 제{n}호표"' in locale and 'M02_CheckNew: ["새"' in locale
|
|
|
|
|
|
def test_새_배지_옛_표_꼴():
|
|
rows = _src("Hopyo_CheckRows")
|
|
assert "createBadge(" in rows and "newBadge()" in rows and "dataset.checkNew" in rows
|
|
assert "newBadge()" in _src("Hopyo_Check")
|
|
for part in ("moneyCell(", "PRICE_SLOTS", "markCells(", "markHeads()", '"logic"', '"mat"'):
|
|
assert part in rows, part
|
|
assert "M02_CheckApart" in _src("Hopyo_Rows") # 별도계상 줄 = 고름 칩 없이 글
|
|
|
|
|
|
def test_공용파일_import_만_부품상자만_700줄():
|
|
texts = {n: _src(f"Hopyo_{n}") for n in MINE}
|
|
joined = "\n".join(texts.values())
|
|
for name in ("Labor_Rows", "Labor_MatMarks", "Labor_Input", "Labor_Pick"):
|
|
assert f'from "./M02_MasterTemplete_{name}"' in joined, name
|
|
for name in SHARED: # 공용 쪽은 새 모달을 모름(거꾸로 이음 없음)
|
|
assert "Hopyo_Check" not in _src(name) and "Hopyo_ToItem" not in _src(name), name
|
|
for name, text in texts.items():
|
|
assert len(text.splitlines()) <= 700, name
|
|
assert not re.search(r"""\bel\(\s*["'](button|input|select)["']""", text), name
|
|
assert not re.search(r"""createElement\(\s*["'](button|input|select)["']""", text), name
|
|
assert "<button" not in text and "<input" not in text, name
|
|
assert not re.search(r"#[0-9a-fA-F]{3,6}\b|rgba?\(", text), name
|
|
assert len(_src("Hopyo_Sheet").splitlines()) <= 402 # 늘리지 않음
|