Files
Aislo/resources/tester/test_817_1_material_find.py
T
eomsangdonandClaude Opus 5.5 bb243af270 feat(817-1): 불러오기 재료 찾기 — 표기만 다름 자동 이음 · 같은 이름 후보 좁힘 · 별도계상 표지
- 새 M02_Hopyo_MatSame — ㉮ 이름 같은 품목(빈칸 · 괄호 차례 · 등급 · 점 · 소리 표기 넷) + 규격 수 묶음 같음(차례 · 단위 배 · 한쪽 듦) + 규격 낱말 안 부딪힘 + 우리 품목 하나 → 이음 · ㉯ 이름 같은 묶음 = 규격 어근 품은 줄 · 덧말 적은 줄 1 순위 · 규격 수 같은 후보 먼저
- M02_Hopyo_Row 재료 길 = 바탕 이름 유일 짝 뒤 ㉮ › 옛 후보 하나 › ㉯ + 옛 후보
- M02_San_Link — 별도계상 줄 = 요소 잇기 없음 + 표지 「별도계상 · 품목은 프로젝트에서」 · 못 이은 재료 까닭에 1 순위 이름 · 규격
- 전수(원파일 2,220 · 엑셀 1,021) 재료 이음 88.0 → 93.5 % · 새 이음 112 줄 51 종 · 끊긴 이음 0 · 금액 그대로 · 치즐 0.7 이 엉뚱한 0.2 줄에서 0.7 줄로 옮김
- 시험 test_817_1_material_find(과녁 100 줄 · 틀린 이음 막기 · 별도계상 표지)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:24:56 +09:00

193 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""817-1 불러오기 재료 찾기 — 표기만 다름 ㉮ 이음 · ㉯ 후보 좁힘 · 틀린 이음 막기 · 별도계상 표지(요구 773-5 · 774).
과녁 = 사용자 시트 「수동연결(자재)」 100 줄(브레인 과녁 `_과녁_773_자재표기.tsv` 를 우리 자재표로 다시 확인한 결과).
「후보」 줄 키 = 1 순위를 굳힌 줄만(종자 · 그레이팅 · 표기만 다름인데 수 묶음 · 이름이 안 맞아 ㉯ 로 둔 줄) · None = 이음만 안 됨.
"""
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path[:0] = [str(ROOT), str(ROOT / "resources" / "master_data" / "scripts")]
from M02_MasterTemplete import M02_Hopyo_MatSame as ms # noqa: E402
from M02_MasterTemplete import M02_Hopyo_Row as hrow # noqa: E402
from M02_MasterTemplete import M02_San_Link as sl # noqa: E402
TABLE = [
("접착제", "", "후보", None), # 1
("패널(유로폼)", "600*1200mm", "이음", "MT000467"), # 2
("각재", "외송", "후보", "MT000393"), # 3
("요소", "", "후보", "MT006763"), # 4
("내부코너패널(유로폼)", "(100x200)x1200mm", "이음", "MT000470"), # 5
("결속선(철선)", "#20 , 0.9M/M", "후보", None), # 6
("각재 (외송)", "", "후보", "MT000393"), # 7
("파형강관", "별도계상", "후보", None), # 8
("금강사", "", "없음", None), # 9
("고무테이프", "0.5mm×19mm×10m", "이음", "MT009202"), # 10
("낙석방지책", "H2500×W2000(표준)", "후보", None), # 11
("낙석방지책", "H2500×W2000(단부)", "후보", None), # 12
("종자", "초본류", "후보", "MT006646"), # 13
("종자", "목본류", "후보", "MT006648"), # 14
("어닐링철선(결속선)", "#20 0.9mm 200.4m/kg", "이음", "MT000209"), # 15
("내수합판1급", "12mmx1220x2440", "이음", "MT000018"), # 16
("어닐링철선(결속선)", "#20 0.9M/M", "이음", "MT000209"), # 17
("유로폼(패널)", "600*1200", "이음", "MT000467"), # 18
("내부코너패널", "(200+200)*1200", "이음", "MT000472"), # 19
("합판(내수)", "12×1220×2440", "이음", "MT000018"), # 20
("조임철물", "(직교자재)", "이음", "MT000499"), # 21
("에폭시수지", "YD-128", "후보", None), # 22
("종자", "생태복원형,초본류", "후보", "MT006646"), # 23
("종자", "생태복원형,목본류", "후보", "MT006648"), # 24
("내부코너패널(유로폼)", "(100+200)*1200mm", "이음", "MT000470"), # 25
("유로폼(패널)", "600×1200", "이음", "MT000467"), # 26
("콘테이너하우스", "창고용(3.0m×6.0m×2.6m)", "이음", "MT007111"), # 27
("전기뇌관(MS)", "3.5m×500개(하이데토)", "이음", "MT005677"), # 28
("BUTTON BIT", "Ø38×76㎜", "후보", None), # 29
("유압드릴샹크", "T38×CM470", "후보", None), # 30
("유압식드릴스리브", "T38×190mm", "후보", "MT005687"), # 31
("미송(판재)", "", "후보", None), # 32
("산림종자", "참싸리(박피)", "이음", "MT006664"), # 33
("유기질퇴비", "", "후보", None), # 34
("PVC지수판", "200x5T KSM3805", "이음", "MT006544"), # 35
("PVC용접봉", "Ø3.2 (국산)", "후보", None), # 36
("PVC파이프(일반용VG2)", "50㎜ × 4m", "이음", "MT002926"), # 37
("혼합골재", "영월", "후보", None), # 38
("이형철근", "별도계상", "후보", None), # 39
("안전표지판", "삼각,D=900", "후보", "MT003202"), # 40
("표지판지주", "D=76.3mm, 3.5M", "후보", None), # 41
("블레이드(커터)", 'd=320 400mm 14"xt3.2', "이음", "MT005749"), # 42
("떼", "", "없음", None), # 43
("강관비계", "φ48.6m/m×2.3mm", "이음", "MT000481"), # 44
("철물", "", "후보", None), # 45
("각재(말뚝)", "Φ60", "후보", None), # 46
("강관써포트", "V4 2600-4000mm 14.3kg", "후보", None), # 47
("안고초", "", "이음", "MT006667"), # 48
("비수리", "", "이음", "MT006665"), # 49
("내수합판1급", "12m/m 1220×2440", "이음", "MT000018"), # 50
("각재(외송)", "3.6×3.0×3.0", "이음", "MT000393"), # 51
("내수합판1급", "12mm 1220×2440", "이음", "MT000018"), # 52
("각재(거푸집용,외송)", "3.6×3.0×3.0", "이음", "MT000393"), # 53
("다이아몬드톱날", 'Ø14"×3.2t(콘크리트용)', "후보", None), # 54
("아세틸렌", "용접용", "후보", "MT003163"), # 55
("산소", "고압가스", "이음", "MT003166"), # 56
("신나", "KSM6060 2종(조합페인트류)", "이음", "MT003398"), # 57
("초류종자(국내산)", "참싸리,비수리,낭아초등", "후보", None), # 58
("종 자", "초본형", "후보", "MT006646"), # 59
("소나무우드칩(멀칭재)", "", "후보", None), # 60
("3단코어비트", '5"(125mm)', "후보", None), # 61
("P V C PIPE", "Φ50M/M,VG1", "이음", "MT002861"), # 62
("콘테이너(창 고)", "3×6×2.6", "이음", "MT007111"), # 63
("강관비계", "48.6mm×2.3mm×6m", "후보", None), # 64
("철물", "직교자재", "이음", "MT000499"), # 65
("문양거푸집(ABS코팅품)", "600×1200", "이음", "MT000453"), # 66
("와이어매쉬", "#6 100×100", "이음", "MT007136"), # 67
("지수판", "T5×200", "이음", "MT006544"), # 68
("용접봉(연강용)", "3.2m/m", "후보", None), # 69
("어닐링철선 (결속선)", "#6 4.0mm 10.1m/kg", "후보", None), # 70
("구역화물자동차(4.5Ton)", "80km이내", "이음", "MT023493"), # 71
("구역화물자동차(4.5Ton)", "60km이내", "이음", "MT023491"), # 72
("산소(6000ℓ)", "99%,120kg/㎠", "이음", "MT003165"), # 73
("아세칠렌", "AC 98%,용접용", "이음", "MT003163"), # 74
("서비스볼트(고장력볼트)", "M20×60", "이음", "MT002536"), # 75
("보조강재(열연강판)", "T=9-12", "후보", None), # 76
("구역화물자동차(8Ton)", "10km이내", "이음", "MT023654"), # 77
("구역화물자동차(8Ton)", "20km이내", "이음", "MT023655"), # 78
("참싸리(박피)", "", "없음", None), # 79
("부산물비료", "20kg/포", "후보", None), # 80
("참싸리", "박피", "없음", None), # 81
("복합비료", "21-17-17 20kg/포", "이음", "MT006490"), # 82
("퇴비(천연부엽토)", "20㎏/포", "후보", None), # 83
("문양거푸집(ABS코팅폼)", "600×1200×20~30mm", "이음", "MT000453"), # 84
("P.V.C PIPE", "VG1(50mm)", "이음", "MT002861"), # 85
("다웰바(DOWEL BAR)", "Ø32×1,000", "이음", "MT006540"), # 86
("P.V.C PIPE", "VG1(35mm)", "이음", "MT002859"), # 87
("휠라", "T=15mm,1000×1000mm", "없음", None), # 88
("측구수로관", "300×300×2000×120,앵글포함", "이음", "MT015883"), # 89
("중하중그레이팅", "395×995×52", "후보", "MT007025"), # 90
("측구수로관", "500×500×2000×150,앵글포함", "이음", "MT015887"), # 91
("중하중그레이팅", "595×995×67", "후보", "MT007032"), # 92
("잔디", "0.18×0.18×0.01", "이음", "MT006796"), # 93
("강관비계", "4000×48.6mm×2.3mm", "이음", "MT000481"), # 94
("삼각표지판", "삼각,900mm", "후보", None), # 95
("표지판지주", "D=76.3mm×3.0m", "이음", "MT003241"), # 96
("공사안내표지판", "300×1500", "후보", None), # 97
("공사안전PE드럼", "500×800", "후보", "MT003311"), # 98
("윙카호스", "10cm", "후보", None), # 99
("조합페인트", "KSM6020 2급,백색", "이음", "MT003372"), # 100
]
def _link(name, spec):
key, mark = sl.m01("재료", {"이름": name, "규격": spec, "단위": "", "갈래": "재료"})
return key, mark, hrow.m01_picks("재료", {"이름": name, "규격": spec, "단위": ""})
@pytest.mark.parametrize("name,spec,want,key", TABLE)
def test_target_rows(name, spec, want, key):
got, _mark, picks = _link(name, spec)
if want == "이음":
assert got == key
else:
assert got is None
assert bool(picks) == (want == "후보")
if key:
assert picks[0]["키"] == key
def test_counts():
linked = sum(1 for *_x, w, _k in TABLE if w == "이음")
assert linked == 51
@pytest.mark.parametrize(
"name,spec,bad",
[
("용접봉(연강용)", "3.2m/m", "MT003195"), # 연강용 ↔ 주철용
("PVC용접봉", "Ø3.2 (국산)", "MT003195"), # PVC 용접봉 ↔ 용접봉
("어닐링철선 (결속선)", "#6 4.0mm 10.1m/kg", "MT000199"), # #6 ↔ #8
("잔디", "0.18×0.18×0.01", "MT019017"), # 0.01 ↔ 0.03
("표지판지주", "D=76.3mm, 3.5M", "MT003241"), # 3.5M ↔ 3000
("신나", "KSM6060 2종(조합페인트류)", "MT018835"), # 신나 ↔ 신나무
("강관비계", "48.6mm×2.3mm×6m", "MT000481"), # 6m ↔ 4.0m
],
)
def test_no_wrong_link(name, spec, bad):
got, _mark, picks = _link(name, spec)
assert got != bad
if name == "신나":
assert got == "MT003398" # 신너(조합페인트용)
def test_seed_narrow():
assert [x["자재"] for x in ms.narrow({"이름": "종자", "규격": "초본류"})][:3] == [
"MT006646",
"MT006647",
"MT006649",
]
def test_spec_forms():
assert ms.num_fit(ms._bag("3.6×3.0×3.0"), ms._bag("30×30×3600mm"))[0] == 2
assert ms.num_fit(ms._bag("T5×200"), ms._bag("200×5T"))[0] == 3
assert ms.num_fit(ms._bag("Ø32×1,000"), ms._bag("Φ32*1000"))[0] == 3
assert ms._item("PVC지수판", "200x5T KSM3805")["bag"] == ms._item("PVC지수판", "200×5T")["bag"]
assert ms._item("유로폼(패널)", "")["chars"] == ms._item("유로폼패널", "")["chars"]
assert ms._item("P.V.C PIPE", "")["core"] == ms._item("PVC파이프(일반관),서울", "")["core"]
assert ms._item("아세칠렌", "")["core"] == "아세틸렌"
def test_apart_mark():
key, mark, _ = _link("파형강관", "별도계상")
assert key is None and mark == f"{sl.NOTE}{sl.APART}"
assert (
sl.why({"자원": {"갈래": "재료", "이름": "철근(별도계상)", "규격": "별도계상"}}) == sl.APART
)
def test_why_shows_first():
got = sl.why({"자원": {"갈래": "재료", "이름": "종자", "규격": "초본류"}})
assert got == "자재 후보 여럿 — 고름 · 1 순위 종 자 초본위주형"