- 새 master_pick.py — 검색어 찾기(지역 낱말은 차례만) · 고름(호표 줄 차례 → 자재 키) · 같은 성격 단위 환산 · 단위경고 칸 · 기계 목록 밖 원문 분류번호 받기 - Router 몸에 고름 칸 · check_master 검색어 후보 0 · 단위 경고 - 검색어 없는 줄은 옛 길 그대로 — 1,354 자동값 금액 변화 0 - 시험 test_m01_pick 8개 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
115 lines
4.8 KiB
Python
115 lines
4.8 KiB
Python
"""M01 재료 기본 검색어 · 고름 · 단위 환산 · 단위 경고 — PLAN 8-1 · 8-2 계약.
|
||
|
||
검색어 든 견본 로직 줄을 시험 안에서 만들어(`POST /calc` 의 `row` — 저장 안 함) 돌림. 정본 폴더는 읽기만.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from decimal import Decimal
|
||
|
||
import pytest
|
||
from fastapi import FastAPI
|
||
from fastapi.testclient import TestClient
|
||
|
||
from M01_MasterData import M01_MasterData_Router as router_module
|
||
from M01_MasterData import M01_MasterData_Store as store
|
||
|
||
mf = store.cm.mf
|
||
mp = mf.mp
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def client() -> TestClient:
|
||
app = FastAPI()
|
||
app.include_router(router_module.router)
|
||
return TestClient(app)
|
||
|
||
|
||
def _sample(term: str, unit: str, **cond) -> dict:
|
||
"""재료 줄 하나짜리 견본 로직 — 검색어 줄 하나 · 수량 1."""
|
||
return {
|
||
"이름": "검색어 견본",
|
||
"구분": "자체",
|
||
"입력": [],
|
||
"호표": [
|
||
{
|
||
"종류": "재료",
|
||
"요소": {"검색어": term, **cond},
|
||
"이름": "견본 재료",
|
||
"단위": unit,
|
||
"수량": "1",
|
||
"비목": "재료비",
|
||
}
|
||
],
|
||
}
|
||
|
||
|
||
def _line(client: TestClient, row: dict, picks: dict | None = None, path: str = "calc") -> dict:
|
||
body = {"key": "GF999999", "inputs": {}, "row": row, **({"고름": picks} if picks else {})}
|
||
got = client.post(f"/api/m01/{path}", json=body).json()
|
||
assert got.get("ok", True) is True, got
|
||
return got["lines"][0] if path == "calc" else got
|
||
|
||
|
||
def test_검색어로_찾고_지역_낱말이_맞는_줄이_먼저(client) -> None:
|
||
seoul = _line(client, _sample("합판(내수) 12t 서울", "㎡"))
|
||
assert seoul["출처"].startswith("MT000018") and seoul["단가"] == 11354 # 값 열 가운데 낮은 값
|
||
busan = _line(client, _sample("합판(내수) 12t 부산", "㎡"))
|
||
assert busan["출처"].startswith("MT000020") and busan["단가"] == 11488
|
||
assert "단위경고" not in seoul
|
||
|
||
|
||
def test_고름은_그_줄만_그_품목으로_셈(client) -> None:
|
||
row = _sample("합판(내수) 12t 서울", "㎡")
|
||
got = _line(client, row, {"0": "MT000019"})
|
||
assert got["출처"].startswith("MT000019") and got["단가"] == 11556
|
||
assert _line(client, row)["단가"] == 11354 # 요청마다 — 저장 안 함
|
||
text = _line(client, row, {"0": "MT000019"}, "text")
|
||
assert text["ok"] is True # 읽는 식도 같은 몸으로 돎
|
||
|
||
|
||
def test_같은_성격_단위는_줄_단위로_환산(client) -> None:
|
||
got = _line(client, _sample("어닐링철선 서울 4.0mm", "톤")) # 자재 kg → 줄 톤
|
||
assert got["단가"] == 1610000 and "단위경고" not in got
|
||
got = _line(client, _sample("어닐링철선 서울 4.0mm", "g"))
|
||
assert got["단가"] == pytest.approx(1.61)
|
||
|
||
|
||
def test_성격이_다르면_계산은_하고_단위경고(client) -> None:
|
||
got = _line(client, _sample("어닐링철선 서울 4.0mm", "m"))
|
||
assert got["단가"] == 1610 and got["단위경고"] == "줄 m · 자재 kg"
|
||
assert got["금액"] == 1610
|
||
|
||
|
||
def test_검색어_후보가_없으면_그_줄만_비움(client) -> None:
|
||
got = client.post(
|
||
"/api/m01/calc", json={"key": "GF999999", "inputs": {}, "row": _sample("없는물건zzz", "개")}
|
||
).json()
|
||
assert got["ok"] is True and got["lines"][0]["금액"] is None
|
||
assert "후보 없음" in got["lines"][0]["까닭"]
|
||
|
||
|
||
def test_기계_입력은_목록_밖_원문번호도_받음(client) -> None:
|
||
key = "GC000267"
|
||
inputs = {**store.auto(key)["값"], "기계": "0101-0007"} # 고르기 목록 밖 · 기계 마스터엔 있음
|
||
got = client.post("/api/m01/calc", json={"key": key, "inputs": inputs}).json()
|
||
assert got["ok"] is True, got
|
||
bad = client.post("/api/m01/calc", json={"key": key, "inputs": {**inputs, "기계": "9999-9999"}})
|
||
assert bad.json()["ok"] is False # 기계 마스터에 없는 번호는 그대로 막힘
|
||
|
||
|
||
def test_단위_환산_표() -> None:
|
||
assert mp.convert(Decimal(1610), "kg", "톤") == 1610000
|
||
assert mp.convert(Decimal(5), "Ton", "kg") == Decimal("0.005")
|
||
assert mp.convert(Decimal(100), "㎡", "㎠") == Decimal("0.01")
|
||
assert mp.convert(Decimal(7), "kg", "m") == 7 # 성격이 다르면 그대로
|
||
assert mp.same_kind("ℓ", "㎥") and not mp.same_kind("kg", "m")
|
||
|
||
|
||
def test_check_master_검색어_후보0_단위경고(client) -> None:
|
||
whole = store.loaded()[1]
|
||
assert mf.check_pick(whole, "줄", {"검색어": "합판(내수) 12t 서울"}) == []
|
||
assert "후보 0" in mf.check_pick(whole, "줄", {"검색어": "없는물건zzz"})[0]
|
||
assert mf.check_unit(whole, "줄", {"검색어": "어닐링철선 서울 4.0mm"}, "kg") == []
|
||
assert "성격이 다름" in mf.check_unit(whole, "줄", {"검색어": "어닐링철선 서울 4.0mm"}, "m")[0]
|