- 길 — guess 몸 대상 list | dict · to = 만들 층 - 줄 맞춤 — 섞인 줄 1위 대상에 몫 · 배(고임돌 GF000211 × 0.1) · 장비 품 비교 열쇠 「+」(화면과 같음) · guess 가 사용자 배 그대로 - 화면 — 품 비교 장비 표시 열쇠를 갈래 묶음 이름으로 - 시험 — client 고정물 맞춤셈 캐시 = 임시 폴더 · 뒤 셈 안 돌림(tmp/m02_hopyo 안 남음 · 결과 흔들림 없음) · 끝까지(북부청 올림 → 셈 → 보기 → 화면 몸 → 만들기 → 장부 → 다시 올림 별칭 · 몸 없음 400 · hopyo-memory 404 · 영월 STmate) · 실물 대역 화면 시험 · 이음매 268 줄 맞음 122 · 다른 점 86 · 후보 60 · 후보 1순위 근거 맞음 123 → 9 - 응답 대역 JSON 실물로 다시 뽑음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
159 lines
7.6 KiB
Python
159 lines
7.6 KiB
Python
"""338-4 이음매 — 끝까지(시험 클라이언트 · 임시 층): 북부청 임도 올림 → 셈 끝 → 호표 보기(맞음 ·
|
|
다른 점 ·
|
|
후보) → 화면 도우미(`helper_m02_hopyo_check.cjs` · 실물 응답)가 만든 몸(체크한 줄만) →
|
|
[확인하고 사전조합 만들기] → 사전조합 줄(로직 여럿 같은 별칭 · 배 · 몫) · 별칭 장부 → 다시 올림 =
|
|
별칭 체크 ·
|
|
몸 없는 만들기 400 · 옛 hopyo-memory 404 · STmate 영월 올림 → 상태 · master_data 원본 그대로.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
from M02_MasterTemplete import M02_Hopyo_Fit as fit
|
|
from M02_MasterTemplete import M02_Template_Layers as layers
|
|
from resources.tester.helper_m02_hopyo_golden import FILES
|
|
from resources.tester.test_m02_hopyo_excel import URL, _post, client, master_hash # noqa: F401
|
|
|
|
# ruff: noqa: F811
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
FOLDER = (7, 42) # USER 의 개인 층
|
|
|
|
|
|
def _node(payload: dict) -> dict:
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_m02_hopyo_check.cjs")],
|
|
input=json.dumps(payload, 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 _up(client, key: str, name: str | None = None, data: bytes | None = None) -> None:
|
|
res = _post(client, data=data, **({"name": name} if name else {}))
|
|
assert res.status_code == 200, res.text
|
|
assert res.json()["키"] == key
|
|
fit.run_job(layers.personal_dir(*FOLDER), key) # 셈 끝(뒤 셈 대신 바로)
|
|
|
|
|
|
def _one(client, key: str, no: int) -> dict:
|
|
res = client.get(f"{URL.format('personal')}/{key}/{no}")
|
|
assert res.status_code == 200, res.text
|
|
return res.json()["호표"]
|
|
|
|
|
|
def _find(client, key: str, name: str) -> tuple[int, dict]:
|
|
whole = client.get(f"{URL.format('personal')}/{key}").json()
|
|
assert whole["셈"]["끝"]
|
|
for h in whole["호표"]:
|
|
one = _one(client, key, h["번"])
|
|
if any(x["이름"] == name for x in one["줄"]):
|
|
return h["번"], one
|
|
raise KeyError(name)
|
|
|
|
|
|
def _build(client, key: str, no: int, lines: list, **extra) -> dict:
|
|
body = {"층": "personal", "키": key, "번": no, "줄": lines, **extra}
|
|
res = client.post("/api/m02/layers/personal/hopyo-build", json=body)
|
|
assert res.status_code == 200, res.text
|
|
return res.json()
|
|
|
|
|
|
def _doc(ref: dict) -> dict:
|
|
path = layers.personal_dir(*FOLDER) / "precombo" / f"{ref['키']}.json"
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def test_끝까지_확인한_줄만_별칭(client):
|
|
before = master_hash()
|
|
_up(client, "HP-000001")
|
|
no, hopyo = _find(client, "HP-000001", "레미콘타설(장비사용)")
|
|
by = {x["이름"]: x for x in hopyo["줄"]}
|
|
assert by["레미콘타설(장비사용)"]["맞춤"]["상태"] == "맞음"
|
|
screen = _node({"real": hopyo["줄"]})
|
|
seen = {x["이름"]: x for x in screen["lines"]}
|
|
remicon = seen["레미콘타설(장비사용)"]
|
|
assert remicon["checked"] and remicon["checkable"]
|
|
assert remicon["compare"].startswith("콘크리트공 0.1091 → 0.1091 ✓")
|
|
assert "굴착기 0.29 → 0.2909 ✓" in remicon["compare"]
|
|
assert "소량감률=50(블록)" in remicon["inputs"] and remicon["target"].endswith("[㎥]")
|
|
states = {x["상태"] for x in screen["lines"]}
|
|
assert {"맞음", "다른 점", "후보"} <= states
|
|
body = screen["body"] # 화면이 만든 몸 = 서버 체크 제안 줄만
|
|
suggested = [x["차례"] for x in hopyo["줄"] if x["맞춤"]["체크"]]
|
|
assert [x["차례"] for x in body] == suggested and screen["leftOut"]["확인 안 함"] > 0
|
|
rebar = next(x for x in hopyo["줄"] if x["이름"] == "철근가공조립(현장)")
|
|
two = [{k: p[k] for k in ("로직", "입력값", "배")} for p in rebar["맞춤"]["대상"]]
|
|
assert {p["로직"] for p in two} == {"GC000206", "GC000207"} # 다른 점 → 사용자가 체크
|
|
body = body + [{"차례": rebar["차례"], "대상": two}]
|
|
made = _build(client, "HP-000001", no, body)
|
|
assert made["다시씀"] is False and made["장부"]["씀"] == len(body)
|
|
assert all(m["까닭"] for m in made["빠진줄"]) # 확인 안 함 · % 줄
|
|
doc = _doc(made["참조"])
|
|
logics = [x for x in doc["담은로직"] if x.get("로직")]
|
|
alias = {x["로직"]: x["별칭"] for x in logics}
|
|
assert alias["GC000206"] == alias["GC000207"] == "철근가공조립(현장)" # 로직 여럿 · 같은 별칭
|
|
assert doc["본뜬"]["확인"] and doc["본뜬"]["키"] == f"HP-000001 제{no}호표"
|
|
rows = client.get("/api/m02/layers/personal/hopyo-ledger").json()["줄"]
|
|
keys = {r["열쇠"]: r for r in rows}
|
|
assert {p["로직"] for p in keys[rebar["맞춤"]["열쇠"]]["짝"]} == {"GC000206", "GC000207"}
|
|
# 다시 올림 = 확인한 줄은 별칭 · 체크 · 만든 것이 보임
|
|
_up(client, "HP-000002")
|
|
again = {x["이름"]: x["맞춤"] for x in _one(client, "HP-000002", no)["줄"]}
|
|
assert again["레미콘타설(장비사용)"]["상태"] == "별칭" and again["레미콘타설(장비사용)"]["체크"]
|
|
assert again["철근가공조립(현장)"]["상태"] == "별칭"
|
|
assert again["철근가공조립(현장)"]["대상"][0]["출처"] == {
|
|
k: "별칭" for k in again["철근가공조립(현장)"]["대상"][0]["입력값"]
|
|
}
|
|
first = _one(client, "HP-000001", no)
|
|
assert first["만든"] == {"키": made["참조"]["키"], "확인": True}
|
|
assert master_hash() == before
|
|
|
|
|
|
def test_섞인_줄_몫_배(client):
|
|
_up(client, "HP-000001")
|
|
no, hopyo = _find(client, "HP-000001", "고임돌 채집 및 운반")
|
|
line = next(x for x in hopyo["줄"] if x["이름"] == "고임돌 채집 및 운반")
|
|
part = line["맞춤"]["대상"][0]
|
|
assert (part["로직"], part["몫"], part["배"]) == ("GF000211", 0.1, 0.1)
|
|
screen = _node({"real": [line]})
|
|
assert screen["lines"][0]["checkable"] and not screen["lines"][0]["checked"]
|
|
one = {k: part[k] for k in ("로직", "입력값", "배", "몫")}
|
|
made = _build(client, "HP-000001", no, [{"차례": line["차례"], "대상": [one]}])
|
|
row = next(x for x in _doc(made["참조"])["담은로직"] if x.get("로직") == "GF000211")
|
|
assert row["수량"]["손"] == round(line["수량"] * 0.1, 6)
|
|
|
|
|
|
def test_막는_길(client):
|
|
_up(client, "HP-000001")
|
|
empty = client.post(
|
|
"/api/m02/layers/personal/hopyo-build",
|
|
json={"층": "personal", "키": "HP-000001", "번": 1, "줄": []},
|
|
)
|
|
assert empty.status_code == 400 and "확인한 줄이 없음" in empty.text
|
|
money = client.post(
|
|
"/api/m02/layers/personal/hopyo-build",
|
|
json={"층": "personal", "키": "HP-000001", "번": 1, "줄": [{"차례": 1, "금액": 1}]},
|
|
)
|
|
assert money.status_code in (400, 422)
|
|
gone = client.post("/api/m02/layers/personal/hopyo-memory", json={"줄": {}})
|
|
assert gone.status_code in (404, 405)
|
|
url = f"{URL.format('personal')}/HP-000001/1/guess"
|
|
many = client.post(url, json={"차례": 1, "대상": [{"로직": "GC000198", "입력값": {}}]})
|
|
assert many.status_code == 200 and many.json()["대상"][0]["로직"] == "GC000198"
|
|
|
|
|
|
def test_STmate_영월(client):
|
|
path = FILES["동부청영월"]
|
|
_up(client, "HP-000001", path.name, path.read_bytes())
|
|
whole = client.get(f"{URL.format('personal')}/HP-000001").json()
|
|
assert whole["셈"]["끝"] and len(whole["호표"]) == 23 and whole["맞춤"][0] > 0
|
|
states = set()
|
|
for h in whole["호표"]:
|
|
states |= {x["맞춤"]["상태"] for x in _one(client, "HP-000001", h["번"])["줄"]}
|
|
assert {"맞음", "후보"} <= states
|