- 아스콘 규격 괄호 조합 이름 떼기 · 시군 묶음 지역 짝짓기 · 지난번 못 채운 줄 재시도 - 관급 열 채움 3,045 · null 1,507 (보류 394 · 못 채움 1,113) - test_masterdata_procure.py 7건 · 설계 문서에 제조사 선택지 · 로직 일괄 시험 전후 (1,024/327 동일) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
"""관급 단가 짝짓기 — 작은 견본 응답으로 레미콘 지역·규격 · 아스콘 · 값 갈림 보류 · 지역 불일치 미채움 (`resources/master_data/scripts/update_관급단가.py`)."""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "master_data/scripts"))
|
|
|
|
import update_관급단가 as up # noqa: E402
|
|
|
|
|
|
def raw_row(
|
|
spec, region, price, corp="테스트조합", maker="조합공통품목", cond="", bgn="2026-06-01"
|
|
):
|
|
return {
|
|
"prdctSpecNm": spec,
|
|
"prdctSplyRgnNm": region,
|
|
"cntrctPrceAmt": str(price),
|
|
"cntrctCorpNm": corp,
|
|
"prdctMakrNm": maker,
|
|
"prdctDlvryCndtnNm": cond,
|
|
"cntrctBgnDate": bgn,
|
|
"rgstDt": bgn,
|
|
"cntrctMthdNm": "다수 공급자 계약",
|
|
"vatAplDivNm": "포함",
|
|
"prdctUnit": "㎥",
|
|
}
|
|
|
|
|
|
def item(key, name, spec):
|
|
return {"키": key, "이름": name, "규격": spec, "관급": 1, "비고": "조달 26.7"}
|
|
|
|
|
|
RAW = {
|
|
"MASCntrct_레미콘": [
|
|
raw_row("조합공통품목, 25-18-080", "경기도 수원시", 100000),
|
|
raw_row("조합공통품목, 25-18-080", "강원도 원주시", 90000),
|
|
raw_row("조합공통품목, 25-21-080", "경기도 수원시", 105000),
|
|
raw_row("삼표, 25-18-080", "경기도 수원시", 1, maker="삼표"), # 제조사 줄 — 조합공통 아님
|
|
],
|
|
"MASCntrct_아스팔트콘크리트": [
|
|
raw_row("아스팔트콘크리트 조합공통품목, WC-2, 가열, 3등급", "경기도 수원시", 70000),
|
|
raw_row("순환 아스팔트콘크리트 조합공통품목, WC-2, 가열, 3등급", "경기도 수원시", 60000),
|
|
],
|
|
"MASCntrct_봉강": [
|
|
raw_row("SD400, D10", "전지역(제주제외)", 827640, maker="가철강", cond="생산공장 상차도"),
|
|
raw_row("SD400, D10", "전지역(제주제외)", 830000, maker="나철강", cond="생산공장 상차도"),
|
|
],
|
|
}
|
|
|
|
|
|
def fill(x):
|
|
(r,) = up.refill([x], RAW)
|
|
return r, up.decide(x, r, "2026-09-20")
|
|
|
|
|
|
def test_레미콘_지역_규격_짝():
|
|
r, (val, note) = fill(item("a", "레미콘(관급)-경기 수원", "조합공통품목, 25-18-80")) # 80 = 080
|
|
assert val == 100000 and "조달청" in note
|
|
r, (val, _) = fill(item("b", "레미콘(관급)-경기 수원", "조합공통품목, 25-21-080"))
|
|
assert val == 105000
|
|
|
|
|
|
def test_레미콘_지역_불일치는_안_채움():
|
|
r, (val, note) = fill(item("c", "레미콘(관급)-울진", "조합공통품목, 25-18-080"))
|
|
assert val is None and "지역 못 찾음" in note
|
|
|
|
|
|
def test_레미콘_규격_없으면_안_채움():
|
|
r, (val, note) = fill(item("d", "레미콘(관급)-경기 수원", "조합공통품목, 30-24-150"))
|
|
assert val is None and "강도 없음" in note
|
|
|
|
|
|
def test_아스콘_순환_구분():
|
|
_, (val, _) = fill(item("e", "아스콘(관급)-경기 수원", "조합공통품목, WC-2, 가열, 3등급"))
|
|
assert val == 70000
|
|
_, (val, _) = fill(item("f", "순환아스콘(관급)-경기 수원", "조합공통품목, WC-2, 가열, 3등급"))
|
|
assert val == 60000
|
|
|
|
|
|
def test_제조사별_값_갈리면_보류():
|
|
_, (val, note) = fill(item("g", "이형철근(SD400)-관급", "HD=10mm 생산공장 상차도"))
|
|
assert val is None and "갈림" in note
|
|
|
|
|
|
def test_짝_없는_갈래는_안_채움():
|
|
_, (val, note) = fill(item("h", "벤치플륨(관급)", "300"))
|
|
assert val is None and "짝짓기 없음" in note
|
|
|
|
|
|
def test_호출_오류에_키_안_찍힘(monkeypatch):
|
|
def boom(url, **kw):
|
|
raise OSError(f"연결 실패 {url}")
|
|
|
|
monkeypatch.setattr(up.cc, "fetch", boom)
|
|
try:
|
|
up.call("op", "SECRETKEY123", a=1)
|
|
except RuntimeError as e:
|
|
assert "SECRETKEY123" not in str(e) and "***" in str(e)
|
|
else:
|
|
raise AssertionError("예외가 나야 함")
|