- 기계.json EQ000656~668 더함 — 발전기 5.5·7·10㎾(손료계수 2362 발전기 계열) · 대형 브레이커 0.18㎥(0.2㎥ 계수·가격) · 에어 호스 1.91㎝ · 모노펌프 5-20㎥/hr · 파워트로웰 3.73㎾ · 콘크리트펌프용 파이프 여섯($ × 환율 FX000001 · 비고에 $ 값) - 원문번호 「자체 이름 규격」 · 출처 가격 = 자체 · 비고 = EST 단가 구성 → 우리 줄 · 가격 갱신 필요 - 계산식 — 손료만 = GC000273 · 발전기 5.5 = GC000268 고르기 끝에 더함(814-1 빌더 · 로직 + 수식 문서) · 파워트로웰 = 새 GC001195(휘발유 + 잡품(주연료 줄 %) + 전력 + 손료) - 발전기 7·10㎾ = 2016 사방품셈(안) 기계경비 가격 · 그 표대로 손료만 - M02_Machine_Hourly 시간당 부름에서 빈칸 든 입력 이름(전력 계약종별) 따옴표 — 파워트로웰 시간당 이음 - 기술정보 기계경비_산정 7 절(표) - 낡은 시험 고침: 812_9 test_no_guess · 815_1 test_alias_machine 이 「에어 호스 · 모노펌프 = 우리 표에 없음」 예로 씀 → 아직 없는 기종(진공흡입기 · 스키드로더)으로 - 기존 수식 문서 1,514 기본 금액 전후 같음 · check_master 전후 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
208 lines
12 KiB
Python
208 lines
12 KiB
Python
"""812-9 지킴 — 가져온 기계 잇기(`M02_Machine_Find` · 요구 718 · 719).
|
||
|
||
(a) 기계표 전체에서 찾음 — 낱말표 밖 기종(로우더 · 공기 압축기 · 램 머 · 라인마커 …) · 후보 여럿이던 것
|
||
(물탱크 · 크레인(무한궤도) · 머캐덤 · 콘크리트 펌프차 …) · 지어 맞추기 없음(3.0Ton = 우리 표에 없음)
|
||
(b) 표기 정규화 · 괄호 낱말(무한궤도 · 타이어 · 일반용 · 표에 없는 낱말 발파 = 안 봄) · 범위 · 복수 규격
|
||
(c) 조합 기계 = 둘(대형브레이카 +굴착기 · 0.7+브레이카 · +부착용집게 · +진동콤팩터 · 덤프트럭(자동덮개))
|
||
(d) 별칭 먼저 — M01 기계 줄 「별칭」 칸(815-1 · 시험 안 임시 별칭) · 이름 + 규격 통째 = 그 EQ · 이름만 =
|
||
그 기종으로 · 후보 여럿 표지(옛 층 장부 쓰기 `learn` = 815-2 장부 걷기로 지움)
|
||
(e) 금액 전후 같음 — 조합 줄 둘(첫 줄 엑셀 값 · 다음 줄 0) · 원파일 저장 금액 그대로
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
HERE = Path(__file__).resolve().parent
|
||
for p in (ROOT, HERE):
|
||
if str(p) not in sys.path:
|
||
sys.path.insert(0, str(p))
|
||
|
||
from M02_MasterTemplete import M02_Elem_Alias as ea # noqa: E402
|
||
from M02_MasterTemplete import M02_Machine_Find as mf # noqa: E402
|
||
from test_815_1_import_link import aliases, no_aliases # noqa: E402 — M01 별칭 칸 임시
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _blank_aliases():
|
||
"""진짜 마스터 기계 별칭 내용 · 수와 무관 — 별칭이 필요한 시험은 스스로 넣음."""
|
||
with no_aliases("EQ"):
|
||
yield
|
||
|
||
|
||
def one(name: str, spec: str = "") -> tuple[str, str, str]:
|
||
got = mf.find(name, spec)
|
||
first = got["후보"][0] if got["후보"] else {}
|
||
return got["판정"], str(first.get("이름") or ""), str(first.get("규격") or "")
|
||
|
||
|
||
LINKED = [ # 낱말 모름 · 후보 여럿이던 예(812-8) → 하나
|
||
("로우더(타이어)", "0.57㎥", "로더(타이어)", "0.57㎥"),
|
||
("로우더(타이어)", "1.72㎥", "로더(타이어)", "1.72㎥"),
|
||
("공기 압축기", "21.0㎥/min", "공기압축기(이동식)", "21.0㎥/min"),
|
||
("공기 압축기", "7.1㎥/min", "공기압축기(이동식)", "7.1㎥/min"),
|
||
("라인마커", "10Km/hr", "라인 마커", "10km/hr"),
|
||
("램 머", "80kg", "래 머", "80㎏"),
|
||
("진동파일해머", "60kW", "진동파일 해머(전동식)", "60㎾"),
|
||
("진동파일해머", "45kW", "진동파일 해머(전동식)", "45㎾"),
|
||
("진동파일해머", "40kW", "진동파일 해머(전동식)", "40㎾"),
|
||
("노면파쇄기", "2.0m", "노면파쇄기", "2.0m"),
|
||
("아스팔트 디스트리뷰터", "3800ℓ", "아스팔트 디스트리뷰터", "3,800ℓ"),
|
||
("고소작업차", "3Ton", "고소작업차", "3ton"),
|
||
("고소작업차", "5Ton", "고소작업차", "5ton"),
|
||
("취부기(녹생토)", "18.65kW", "취부기(녹생토 암절개면 보호식재용)", "18.65㎾"),
|
||
("아스팔트 스프레이어", "400ℓ", "아스팔트 스프레이어", "400ℓ"),
|
||
("커 터", "320~400mm", "커터(콘크리트 및 아스팔트용)", "320~400"),
|
||
("경운기", "1000kg", "경운기", "1,000㎏"),
|
||
("건설용펌프(자흡식)", "50mm", "건설용펌프(자흡식)", "50(1.49×10)"),
|
||
("강연선인장기", "120Ton", "강연선인장기", "120ton"),
|
||
("물탱크", "5500ℓ", "물탱크(살수차)", "5,500ℓ"),
|
||
("물탱크", "16000ℓ", "물탱크(살수차)", "16,000ℓ"),
|
||
("콘크리트 펌프차", "32m,80~95㎥/hr", "콘크리트 펌프차", "32 [80∼95]"),
|
||
("머캐덤 로울러(자주식)", "10~12Ton", "머캐덤 롤러(자주식)", "10∼12"),
|
||
("타이어 로울러(자주식)", "8~15Ton", "타이어 롤러(자주식)", "8∼15"),
|
||
("크레인(무한궤도)", "40Ton", "크레인(무한궤도)", "40 (1.53)"),
|
||
("크레인(무한궤도)", "35Ton", "크레인(무한궤도)", "35 (1.33)"),
|
||
("크로울러 드릴(공기식)", "17㎥/min", "크롤러드릴(공기식)", "17 (120㎜)"),
|
||
("모터 그레이더", "3.6m(일반용)", "모터그레이더(일반용)", "3.6m"),
|
||
("콘크리트 믹서", "0.3㎥", "콘크리트 믹서", "0.30㎥"),
|
||
("진동 로울러(자주식)", "12Ton", "진동롤러(자주식)", "12ton"),
|
||
("굴삭기(무한궤도)", "0.7㎥", "굴착기(무한궤도)", "0.7㎥"),
|
||
("굴착기(타이어형)", "0.6㎥", "굴착기(타이어)", "0.6㎥"),
|
||
("굴착기(무한궤도)", "0.4㎥(발파)", "굴착기(무한궤도)", "0.4㎥"),
|
||
("불도우저(무한궤도)", "32Ton", "불도저(무한궤도)", "32ton"),
|
||
]
|
||
|
||
|
||
@pytest.mark.parametrize("name,spec,our,size", LINKED)
|
||
def test_linked(name: str, spec: str, our: str, size: str) -> None:
|
||
kind, *got = one(name, spec)
|
||
assert kind in (mf.LINKED, mf.ALIAS) and got == [our, size] # 승인 별칭(디젤 엔진) = 별칭
|
||
|
||
|
||
MASTER = [ # 마스터 층 승인 별칭(요구 735-5 · 736) — 이름 별칭 + 규격은 수로 맞댐
|
||
("아스팔트페이버(피니셔)", "3.0m", "EQ000193"),
|
||
("아스팔트페이버(피니셔)", "1.7m", "EQ000192"),
|
||
("디젤 엔진", "11.19kW", "EQ000500"),
|
||
("디젤 엔진", "26.11kW", "EQ000503"),
|
||
("디젤 엔진", "52.22kW", "EQ000504"),
|
||
("워터제트", "96kW", "EQ000400"),
|
||
("버킷준설기", "7.46kW", "EQ000425"),
|
||
("바이브레이트", "봉상후렉시블", "EQ000248"),
|
||
]
|
||
|
||
|
||
# 마스터 기계 별칭 다섯(815-2 가 기계 줄 「별칭」 칸으로 옮김) — 칸이 비었으면 시험 동안만 넣음
|
||
FIVE = {"EQ000193": "아스팔트페이버(피니셔)", "EQ000500": "디젤 엔진", "EQ000400": "워터제트",
|
||
"EQ000425": "버킷준설기", "EQ000248": '"바이브레이트 봉상후렉시블"'} # fmt: skip
|
||
|
||
|
||
@pytest.mark.parametrize("name,spec,eq", MASTER)
|
||
def test_master_alias(name: str, spec: str, eq: str) -> None:
|
||
rows = ea.book()["줄"]["EQ"]
|
||
with aliases("EQ", {k: v for k, v in FIVE.items() if not rows[k].get("별칭")}):
|
||
got = mf.find(name, spec)
|
||
assert got["키"] == eq and got["판정"] in (mf.LINKED, mf.ALIAS)
|
||
|
||
|
||
def test_no_guess() -> None:
|
||
"""우리 표에 없는 규격 = 못 찾음(가까운 규격으로 안 이음) · 기종 모름 = 별칭 몫 · 여럿 = 여럿."""
|
||
got = mf.find("덤프트럭", "3.0Ton")
|
||
assert got["판정"] == mf.NONE and got["까닭"] == "우리 표에 없음(규격)" and got["키"] is None
|
||
assert got["후보"][0]["규격"] == "2.5ton" # 보여주기만 — 가까운 규격 먼저
|
||
for name, spec in (
|
||
("진공흡입기", "5kW"),
|
||
("스키드로더", "0.3㎥"),
|
||
): # 우리 표에 없는 기종 = 별칭 몫
|
||
got = mf.find(name, spec)
|
||
assert (got["판정"], got["까닭"]) == (mf.NONE, "기종 모름 — 별칭")
|
||
got = mf.find("크레인(트럭)", "10Ton") # 「트럭」 = 기계표 괄호에 없는 낱말 → 안 봄
|
||
assert got["판정"] == mf.MANY and got["수"] == 2
|
||
assert mf.mark(got, "크레인(트럭)", "10Ton").startswith("참고 · 기계 후보 2 — 고르기")
|
||
assert "기계 못 찾음" in mf.mark(mf.find("덤프트럭", "3.0Ton"), "덤프트럭", "3.0Ton")
|
||
assert mf.mark(mf.find("물탱크", "5500ℓ"), "물탱크", "5500ℓ") is None
|
||
|
||
|
||
def test_norm_paren_spec() -> None:
|
||
assert mf.norm("로우더") == mf.norm("로더") and mf.norm("로울러") == mf.norm("롤러")
|
||
assert mf.norm("브레이카") == mf.norm("브레이커") and mf.norm("굴삭기") == mf.norm("굴착기")
|
||
assert mf.norm("불도우저") == mf.norm("불도저") and mf.norm("램 머") == mf.norm("래 머")
|
||
assert mf.tokens("10~12Ton") == [(10.0, 12.0, "ton")]
|
||
assert mf.tokens("32m,80~95㎥/hr") == [(32.0, 32.0, "m"), (80.0, 95.0, "m3/hr")]
|
||
assert mf.tokens("5,500ℓ") == [(5500.0, 5500.0, "l")]
|
||
assert mf.spec_fit(mf.tokens("0.7㎥"), mf.tokens("0.6∼0.8")) == "안"
|
||
assert one("굴착기(타이어)", "0.6㎥")[1] == "굴착기(타이어)" # 괄호 낱말이 가름
|
||
assert one("굴착기(무한궤도)", "0.6㎥")[1] == "굴착기(무한궤도)"
|
||
|
||
|
||
COMBO = [ # 조합 기계 = 둘 · 규격 없는 쪽 = 앞 규격
|
||
("굴삭기(무한궤도)", "0.7+브레이카", [("굴착기(무한궤도)", "0.7㎥"), ("대형 브레이커", "0.7㎥")]),
|
||
("대형브레이카", "+굴착기(0.7㎥)", [("대형 브레이커", "0.7㎥"), ("굴착기(무한궤도)", "0.7㎥")]),
|
||
("대형브레이카", "+굴착기(0.4㎥)", [("대형 브레이커", "0.4㎥"), ("굴착기(무한궤도)", "0.4㎥")]),
|
||
("굴삭기+진동콤팩터", "0.7㎥", [("굴착기(무한궤도)", "0.7㎥"),
|
||
("유압식 진동콤팩터(굴착기 부착용)", "0.7㎥")]),
|
||
("굴삭기(무한궤도)", "0.2㎥+부착용집게", [("굴착기(무한궤도)", "0.2㎥"), ("부착용 집게", "0.2㎥")]),
|
||
("굴삭기(무한궤도)", "0.6㎥+부착용집게", [("굴착기(무한궤도)", "0.6㎥"), ("부착용 집게", "0.6∼0.8")]),
|
||
("로우더(타이어)+소형노면파쇄기", "0.95㎥", [("로더(타이어)", "0.95㎥"), ("소형노면파쇄기", "0.95㎥")]),
|
||
("덤프트럭(자동덮개)", "15Ton", [("덤프트럭", "15ton"), ("덤프트럭 자동덮개시설", "15톤용")]),
|
||
("굴삭기(무한궤도)", "0.7㎥,(브레이커조합)", [("굴착기(무한궤도)", "0.7㎥"), ("대형 브레이커", "0.7㎥")]),
|
||
] # fmt: skip
|
||
|
||
|
||
@pytest.mark.parametrize("name,spec,want", COMBO)
|
||
def test_combo_two(name: str, spec: str, want: list) -> None:
|
||
got = mf.find_all(name, spec)
|
||
assert [g["판정"] for g in got] == [mf.LINKED, mf.LINKED]
|
||
assert [(g["후보"][0]["이름"], g["후보"][0]["규격"]) for g in got] == want
|
||
|
||
|
||
def test_combo_many_part() -> None:
|
||
"""대형브레이카 +굴착기(1.0㎥) — 굴착기 무한궤도 · 타이어 둘 다 1.0 = 그 쪽만 후보 여럿(사용자 고름)."""
|
||
got = mf.find_all("대형브레이카", "+굴착기(1.0㎥)")
|
||
assert [g["판정"] for g in got] == [mf.LINKED, mf.MANY]
|
||
assert mf.find_all("덤프트럭", "15Ton") == [{**mf.find("덤프트럭", "15Ton"), "이름": "덤프트럭", "규격": "15Ton"}] # fmt: skip
|
||
|
||
|
||
def test_alias_first_master_column() -> None:
|
||
"""마스터 기계 줄 「별칭」 칸(815-2 옮김) — 이름만 별칭 = 그 기종 → 규격으로 하나 ·
|
||
통째 별칭 · 할증 글 · 후보 여럿 = `test_815_1_import_link.test_alias_machine`."""
|
||
with aliases("EQ", FIVE): # 다섯만 넣음(더 있어도 비워져 있음)
|
||
got = mf.find("아스팔트페이버(피니셔)", "3.0m")
|
||
assert (got["판정"], got["후보"][0]["이름"], got["후보"][0]["규격"]) == (
|
||
mf.ALIAS, "아스팔트 피니셔", "3m") # fmt: skip
|
||
assert mf.find("크레인(트럭)", "10Ton")["판정"] == mf.MANY # 크레인 별칭은 비움 · 여럿
|
||
|
||
|
||
def test_combo_money_same() -> None:
|
||
"""원파일 거창 측구터파기 연암 — 「굴삭기(무한궤도) 0.7+브레이카」 = 줄 둘 · 금액 = 원파일 저장 그대로."""
|
||
from test_810_2_native_doc import doc_and_money, native
|
||
|
||
from M02_MasterTemplete import M02_Doc_FromNative as fn
|
||
|
||
saved = native("EST", "거창")
|
||
blk = fn.numbers(saved)[2]
|
||
sk, doc, money = doc_and_money(fn.emit(saved, 2))
|
||
names = [(m["이름"], m.get("규격")) for m in doc["금액"]]
|
||
assert ("굴삭기(무한궤도)", "0.7") in names and (
|
||
"대형 브레이커",
|
||
"0.7㎥",
|
||
) in names # 첫 줄 규격 = 그 기계(814-1)
|
||
assert float(money["계"]) == pytest.approx(float(blk["저장"]["T"]), abs=1)
|
||
found = {x["원래"]["이름"]: x for x in doc["가져온"]["기계"]}
|
||
assert found["브레이카"]["조합"] is True and found["브레이카"]["찾기어"] == "대형 브레이커"
|
||
assert any("조합 기계 — 경비는 한 덩이" in m for m in doc["가져온"]["표지"])
|
||
from M02_MasterTemplete import M02_Doc_NativeLayout as lay
|
||
|
||
from test_812_3_native_layout import _show
|
||
|
||
groups = [(g[0], g[2]) for g in _show(doc)] # 조합 기계 = 기계마다 항목(요구 738-3)
|
||
assert ("굴착기(무한궤도) 0.7㎥", ["=Q", "굴삭기(무한궤도)"]) in groups
|
||
assert ("대형 브레이커 0.7㎥", ["대형 브레이커"]) in groups
|
||
owned = lay.owned_of(doc) # 못 이은 기계 줄(시간당 자료 없음 = 숫자 묶음)도 기계 = 이름 단추
|
||
at = next(i for i, m in enumerate(doc["금액"]) if m["이름"] == "대형 브레이커")
|
||
assert owned.get(at) == found["브레이카"]["기호"]
|