179 lines
9.3 KiB
Python
179 lines
9.3 KiB
Python
# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀
|
||
"""821-1 내 기계(개인 층 기계 줄) — M01 기계처럼: 만들 때 사본에 복사 · 고쳐도 금액 그대로 + 「단가새값」 ·
|
||
[단가 갱신] 으로 반영 · 지워도 마지막 값(임시 storage · M01 정본 안 고침).
|
||
|
||
① 세 꼴(바로 · 품셈 · 직접) 저장 · 키 · 원문번호 M01 과 안 겹침 ② 시간당 = M01 같은 값 기계와 같음
|
||
③ 찾기 · 남의 층 안 보임 ④ SK 사본에 박힘 · 고친 뒤 그대로 + 새값 · 갱신 뒤 반영 · 지운 뒤 마지막 값 ·
|
||
층 사이 복사 ⑤ M01 만 쓰는 SK 금액 그대로 ⑥ 권한.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
|
||
import pytest
|
||
from fastapi import HTTPException
|
||
|
||
from M01_MasterData import M01_MasterData_Store as m01
|
||
from M02_MasterTemplete import M02_Labor_Ref as refs
|
||
from M02_MasterTemplete import M02_Machine_Find as mfind
|
||
from M02_MasterTemplete import M02_Machine_Hourly as mh
|
||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||
from M02_MasterTemplete import M02_MyMachine as mym
|
||
from M02_MasterTemplete import M02_MyMachine_Router as route
|
||
from M02_MasterTemplete import M02_Sangeun_Calc as calc
|
||
from M02_MasterTemplete import M02_Sangeun_Copy as skc
|
||
from M02_MasterTemplete import M02_Template_Layers as layers
|
||
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
|
||
|
||
DIG = "EQ000022" # 굴착기(무한궤도) 1.0㎥ — 연료 · 조종원 있음
|
||
PCT = "GC001109" # M01 만 쓰는 SK 바탕
|
||
NAME = "서브셋임시기계" # 찾기 기종 글(수 = 규격으로 읽음 · 창 표시는 글로)
|
||
|
||
|
||
def _at(folder, fn, *args):
|
||
with store.at(folder):
|
||
return fn(*args)
|
||
|
||
|
||
def _easy(**vals):
|
||
base = {"가격": 1000, "손료계수": 2000, "주연료": 2, "주연료종류": "경유", "잡재료율": 10,
|
||
"조종원": 1, "조종원직종": "1048"} # fmt: skip
|
||
return {"이름": NAME, "규격": "1㎾", "방식": "바로", "값": base | vals}
|
||
|
||
|
||
def _sk(folder, machine_no):
|
||
line = {"종류": "로직", "로직": "GC000268", "입력값": {"기계": machine_no, "지역": "전국평균"},
|
||
"수량": "1"} # fmt: skip
|
||
body = {"이름": "sub3임시 내기계", "단위": "시간", "더한줄": [line]}
|
||
return _at(folder, lambda: refs.create("sangeun", body)["이름"])
|
||
|
||
|
||
def _doc(folder, key):
|
||
return _at(folder, lambda: store.read("sangeun", key)["문서"])
|
||
|
||
|
||
def _calc(folder, doc):
|
||
return _at(folder, calc.calc_doc, doc, None, False)
|
||
|
||
|
||
def _sum(folder, key):
|
||
return _calc(folder, _doc(folder, key))["기준"]["계"]
|
||
|
||
|
||
def test_three_shapes_and_keys(world):
|
||
"""① 바로 · 품셈 · 직접 — 키 EQP{사용자}-#### · 원문번호 「개인 …」 · M01 과 안 겹침 · 날."""
|
||
me = world["personal"]
|
||
easy = _at(me, mym.create, _easy())["줄"]
|
||
assert easy["키"] == "EQP42-0001" and easy["원문번호"] == "개인 EQP42-0001"
|
||
assert set(easy["값"]) >= {"가격", "손료계수"} and "상각비계수" not in easy["값"]
|
||
assert easy["넣은날"] == easy["고친날"] and easy["출처"]["가격"] == "개인"
|
||
book = _at(me, mym.create, {"방식": "품셈"}, DIG)["줄"] # M01 기계 복사해 만들기(비율 → 계수)
|
||
m01_row = m01.loaded()[1].get(DIG)["값"]
|
||
for k in ("상각비계수", "정비비계수", "관리비계수", "손료계수"):
|
||
assert float(book["값"][k]) == float(m01_row[k]), k
|
||
direct = _at(me, mym.create, {"이름": NAME, "규격": "1㎾", "방식": "직접",
|
||
"시간당": {"노무비": 10, "재료비": 20, "경비": 30}}) # fmt: skip
|
||
assert direct["시간당"]["계"] == 60 and direct["시간당"]["직접"] is True
|
||
m01_eq = m01.loaded()[1]
|
||
for row in _at(me, mym.rows):
|
||
assert row["키"] not in m01_eq.index["EQ"] and row["원문번호"] not in m01_eq.numbers["EQ"]
|
||
assert [r["키"] for r in _at(me, mym.rows)] == ["EQP42-0001", "EQP42-0002", "EQP42-0003"]
|
||
assert {x["키"] for x in direct["같은이름"]} == {"EQP42-0001"} # 같은 이름 · 규격 알림
|
||
for bad in ({"이름": ""}, {**_easy(), "값": {"가격": 1}}, {**_easy(가격=-1)},
|
||
{**_easy(주연료종류="물")}, {**_easy(조종원직종="없음")}): # fmt: skip
|
||
with pytest.raises(store.StoreError):
|
||
_at(me, mym.create, bad)
|
||
|
||
|
||
def test_hourly_same_as_m01(world):
|
||
"""② 굴착기 1.0㎥ 값을 내 기계로(바로 · 품셈) → 시간당 = M01 기계 · 식은 채운 칸으로."""
|
||
me = world["personal"]
|
||
want = mh.hourly(DIG)
|
||
for how in ("바로", "품셈"):
|
||
got = _at(me, mym.create, {"방식": how}, DIG)
|
||
hour = _at(me, mh.hourly, got["줄"]["키"])
|
||
assert hour["ok"] and hour["로직"] == "GC000268", how
|
||
for k in ("노무비", "재료비", "경비", "계"):
|
||
assert hour[k] == want[k], (how, k)
|
||
loss = _at(me, mym.create, _easy(주연료=0, 조종원=0))["시간당"]
|
||
assert loss["로직"] == "GC000273" and loss["계"] == loss["경비"] == 200 # 1000×1000×2000/10⁷
|
||
assert _at(me, mym.create, _easy(조종원=0))["시간당"]["로직"] == "GC000272"
|
||
assert _at(me, mym.create, _easy(주연료=0))["시간당"]["로직"] == "GC000276"
|
||
|
||
|
||
def test_find_and_other_layer_hidden(world):
|
||
"""③ 기계 찾기 = 그 층 내 기계도 · 남의 층 · 층 모르는 길 = M01 만."""
|
||
me, other = world["personal"], layers.personal_dir(7, 43)
|
||
key = _at(me, mym.create, _easy())["줄"]["키"]
|
||
got = _at(me, mfind.find, NAME, "1㎾")
|
||
assert got["판정"] == mfind.LINKED and got["키"] == key
|
||
assert _at(other, mfind.find, NAME, "1㎾")["판정"] == mfind.NONE
|
||
assert _at(other, mh.hourly, key)["ok"] is False
|
||
assert mh.hourly(key)["ok"] is False # 층 모르는 길
|
||
assert key not in _at(other, skc.whole_).index["EQ"]
|
||
|
||
|
||
def test_sk_copy_edit_refresh_delete(world):
|
||
"""④ 만들 때 사본에 박힘 → 고쳐도 그대로 + 새값 → [단가 갱신] 반영 → 지워도 마지막 값 · 층 복사."""
|
||
me = world["personal"]
|
||
made = _at(me, mym.create, _easy())
|
||
key, no = made["줄"]["키"], made["줄"]["원문번호"]
|
||
sk = _sk(me, no)
|
||
copy = _doc(me, sk)["사본"]
|
||
assert key in {r["키"] for r in copy["단가"]}
|
||
was = _sum(me, sk)
|
||
assert float(was) == made["시간당"]["계"]
|
||
assert _at(me, mym.one, key)["쓰는곳"] == [{"키": sk, "이름": "sub3임시 내기계"}]
|
||
_at(me, mym.update, key, _easy(가격=3000)) # 고침
|
||
now = _calc(me, _doc(me, sk))
|
||
assert now["기준"]["계"] == was and now["사본"]["단가새값"] is True
|
||
assert now["사본"]["지운키"] == []
|
||
new = _at(me, mh.hourly, key)["계"]
|
||
look = _at(me, skc.preview, _doc(me, sk), skc.PRICE)
|
||
assert float(look["전"]["계"]) == float(was) and float(look["후"]["계"]) == new
|
||
assert [x["키"] for x in look["바뀐자원"]] == [key]
|
||
with store.at(me): # [저장] = 할일 적용
|
||
store.write("sangeun", sk, store.read("sangeun", sk)["판"], look["문서"])
|
||
assert float(_sum(me, sk)) == new
|
||
assert _calc(me, _doc(me, sk))["사본"]["단가새값"] is False
|
||
# 층 사이 복사 — 사본이 따라감(받은 층에 그 내 기계 없음 · 마지막 값)
|
||
other = layers.personal_dir(7, 43)
|
||
moved = _at(other, skc.settle, {**_doc(me, sk), "키": "SK-999999"})
|
||
assert float(_calc(other, moved)["기준"]["계"]) == new
|
||
gone = _at(me, mym.delete, key)
|
||
assert gone["쓰는곳"] == [{"키": sk, "이름": "sub3임시 내기계"}]
|
||
after = _calc(me, _doc(me, sk))
|
||
assert float(after["기준"]["계"]) == new and after["사본"]["지운키"] == [key]
|
||
look = _at(me, skc.preview, _doc(me, sk), skc.PRICE)
|
||
assert look["바뀐자원"] == [{"키": key, "이름": NAME, "지워짐": True}]
|
||
assert float(look["후"]["계"]) == new
|
||
|
||
|
||
def test_m01_only_sk_same(world):
|
||
"""⑤ 내 기계가 있는 층에서도 M01 만 쓰는 SK 금액 · 사본 같음 · 사본 모으기에 내 기계 안 낌."""
|
||
me, other = world["personal"], layers.personal_dir(7, 43)
|
||
base = {"이름": "sub3임시 M01", "단위": "㎡", "바탕": {"로직": PCT}, "더한줄": []}
|
||
plain = _at(other, lambda: refs.create("sangeun", base)["이름"])
|
||
_at(me, mym.create, _easy())
|
||
mine = _at(me, lambda: refs.create("sangeun", base)["이름"])
|
||
a, b = _doc(other, plain)["사본"], _doc(me, mine)["사본"]
|
||
assert json.dumps(a["단가"], sort_keys=True) == json.dumps(b["단가"], sort_keys=True)
|
||
assert a["판"] == b["판"] and _sum(other, plain) == _sum(me, mine)
|
||
|
||
|
||
def test_rights(world):
|
||
"""⑥ 남의 개인 층 = 403(일반) · 회사 관리자 = 됨 · 개인 층 밖 = 404."""
|
||
user = {"role": "USER", "company_id": 7, "user_id": 42}
|
||
boss = {"role": "ADMIN", "company_id": 7, "user_id": 1}
|
||
with pytest.raises(HTTPException) as e:
|
||
route._folder(user, "personal", "7/43", True)
|
||
assert e.value.status_code == 403
|
||
with pytest.raises(HTTPException) as e:
|
||
route._folder(user, "company", None, True)
|
||
assert e.value.status_code == 404
|
||
assert route._folder(user, "personal", None, True) == world["personal"]
|
||
assert route._folder(boss, "personal", "7/42") == world["personal"] # 맡은 회사 관리자 읽기
|
||
with pytest.raises(store.StoreError): # 개인 층 아닌 자리에서 만들기
|
||
_at(world["company"], mym.create, _easy())
|