Merge remote-tracking branch 'origin/sub_laptop_2' into sub_laptop_3
# Conflicts: # resources/master_data/재료_품셈재료.json # resources/tester/test_masterdata_check.py
This commit is contained in:
@@ -220,9 +220,10 @@
|
||||
}
|
||||
```
|
||||
|
||||
- 조건 칸 = `구분`(반드시) · `상세구분` · `규격` · `대표` · 그 밖의 칸은 두지 않음. `종류` 는 「재료」만.
|
||||
- 조건 칸 = `구분`(반드시) · `상세구분` · `이름` · `규격` · `대표` · 그 밖의 칸은 두지 않음. `종류` 는 「재료」만.
|
||||
- 구분·상세구분 = 자재품목 줄의 같은 이름 칸과 똑같이 적음(묶음 목록은 `ref/_묶음_자재품목.md`).
|
||||
- 규격 조건 = 원문이 규격을 밝힌 것만 좁힘 — 낱말이 **모두** 든 줄이 후보(「D300」 · 「D300 B종」) · 대소문자·빈칸·`φ` 는 안 가림. 원문이 규격을 안 밝히면 칸을 두지 않음.
|
||||
- 이름 조건 = 구분·상세구분·규격이 같아도 품명이 갈리는 자재품목을 가를 때만 둠(예: 파형강관 커플링밴드 vs 접속티 — 둘 다 관경만 규격에 있어 규격 조건으로는 안 갈림). 규격과 같은 방식(낱말이 **모두** 이름에 든 줄) — 대소문자·빈칸은 안 가림.
|
||||
- 대표 줄 = 관리자가 고른 자재품목 키 — 시험 계산이 그 줄의 값을 씀. 조건 밖 키는 검사가 잡음.
|
||||
- 후보는 **호표 줄 단위와 같은 자재품목 줄만** — 단위가 다르면 다른 물건(우드칩 ㎥ · 원목후로링 ㎡). 조건 안 줄이 모두 다른 단위면 `check_master 단위` 가 알림.
|
||||
- 조건 값에 `{입력}` 을 넣을 수 있음 — `"규격": "{관경}"` 은 계산 때 입력값으로 채워짐(검사에서는 그 칸을 뺌).
|
||||
|
||||
@@ -16,7 +16,7 @@ LINKED = "MP" # 품셈재료 테이블ID
|
||||
MARKET = "MT" # 자재품목 테이블ID
|
||||
PRICED = "MO" # 유가전력 테이블ID — 값 한 칸
|
||||
SLOTS = ("물가자료", "유통물가", "물가정보", "거래가격", "관급") # 자재품목 값 열
|
||||
PICK_KEYS = ("구분", "상세구분", "규격", "대표") # 재료 고르기 조건 칸 (`_틀.md` 7장)
|
||||
PICK_KEYS = ("구분", "상세구분", "이름", "규격", "대표") # 재료 고르기 조건 칸 (`_틀.md` 7장)
|
||||
REGION = "자재지역" # 로직 입력 — 「지역」 은 유가 고르기가 씀
|
||||
TARIFF = "전력 계약종별" # 로직 입력 — 품셈·계약예규에 계약종별 규정 없음
|
||||
_UNITS = {"ea": "개", "ton": "톤", "t": "톤", "l": "ℓ", "리터": "ℓ", "set": "조", "세트": "조"}
|
||||
@@ -131,16 +131,18 @@ def by_class(master: mf.Master) -> dict[str, dict]:
|
||||
def candidates(
|
||||
master: mf.Master, cond: dict, env: dict | None = None, unit: str | None = None
|
||||
) -> list[str]:
|
||||
"""고르기 조건 안 자재품목 키 — 구분 · 상세구분 · 규격 낱말이 모두 든 줄 · 파일 차례대로.
|
||||
"""고르기 조건 안 자재품목 키 — 구분 · 상세구분 · 이름 · 규격 낱말이 모두 든 줄 · 파일 차례대로.
|
||||
`unit` 을 주면 그 단위(호표 줄 단위)와 같은 줄만 — 단위가 다르면 다른 물건.
|
||||
입력 `자재지역` 이 있으면 이름에 그 지역이 든 줄만(그런 줄이 없으면 조건 안 전부)."""
|
||||
want = [plain_spec(w) for w in str(cond.get("규격") or "").split()]
|
||||
want_name = [plain(w) for w in str(cond.get("이름") or "").split()]
|
||||
detail = cond.get("상세구분")
|
||||
need = plain_unit(unit) if unit else ""
|
||||
hits = [
|
||||
key
|
||||
for key, row in by_class(master).get(cond.get("구분"), {}).items()
|
||||
if (not detail or row.get("상세구분") == detail)
|
||||
and all(w in plain(row.get("이름")) for w in want_name)
|
||||
and all(w in plain_spec(row.get("규격")) for w in want)
|
||||
and (not need or plain_unit(row.get("단위")) == need)
|
||||
]
|
||||
|
||||
@@ -2485,7 +2485,12 @@
|
||||
},
|
||||
{
|
||||
"종류": "재료",
|
||||
"요소": "MP:커플링밴드 ∅{관경}㎜",
|
||||
"요소": {
|
||||
"구분": "관·이음관",
|
||||
"상세구분": "파형강관",
|
||||
"이름": "파형강관 커플링밴드(관급)",
|
||||
"규격": "Φ{관경}mm"
|
||||
},
|
||||
"이름": "커플링밴드",
|
||||
"단위": "EA",
|
||||
"수량": "만약(커플링밴드 == '필요', 1 / 6, 0)",
|
||||
|
||||
@@ -35,17 +35,17 @@
|
||||
{ "키": "MP000024", "원문번호": "고무링 ∅800㎜", "이름": "고무링(VR관)", "규격": "∅800㎜", "단위": "개", "요구절": ["산림품셈 12-11-1"], "연결": "MT009721", "고르기": null, "비고": "연결: VR관고무링 D800 이름·규격 같음" },
|
||||
{ "키": "MP000025", "원문번호": "흄관 ∅800㎜", "이름": "흄관", "규격": "∅800㎜", "단위": "m", "요구절": ["산림품셈 12-11-2-1"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "흄관", "규격": "Φ800mm", "대표": "MT014981"}, "비고": "A·B형 갈림 · 값은 「본」 — m 아님" },
|
||||
{ "키": "MP000026", "원문번호": "파형강관 ∅800㎜", "이름": "파형강관", "규격": "∅800㎜", "단위": "m", "요구절": ["산림품셈 12-11-3"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관"}, "비고": "두께 1.6·2.0·2.7T 갈림 — 원문 없음" },
|
||||
{ "키": "MP000027", "원문번호": "커플링밴드 ∅800㎜", "이름": "커플링밴드(파형강관)", "규격": "∅800㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": "MT015309", "고르기": null, "비고": "연결: 파형강관 커플링밴드 Φ800 관급 줄" },
|
||||
{ "키": "MP000027", "원문번호": "커플링밴드 ∅800㎜", "이름": "커플링밴드(파형강관)", "규격": "∅800㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관", "이름": "파형강관 커플링밴드(관급)", "규격": "Φ800mm", "대표": "MT015309"}, "비고": "일감35 — 규격(관경)만으론 접속티와 안 갈려 이름 조건을 더함" },
|
||||
{ "키": "MP000028", "원문번호": "VR관 ∅1000㎜", "이름": "VR관(소켓식)", "규격": "∅1000㎜", "단위": "m", "요구절": ["산림품셈 12-11-1"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "PVC관"}, "비고": "VR관 값은 「본」 — m 환산 안 함" },
|
||||
{ "키": "MP000029", "원문번호": "고무링 ∅1000㎜", "이름": "고무링(VR관)", "규격": "∅1000㎜", "단위": "개", "요구절": ["산림품셈 12-11-1"], "연결": "MT009723", "고르기": null, "비고": "연결: VR관고무링 D1000 이름·규격 같음" },
|
||||
{ "키": "MP000030", "원문번호": "흄관 ∅1000㎜", "이름": "흄관", "규격": "∅1000㎜", "단위": "m", "요구절": ["산림품셈 12-11-2-1"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "흄관", "규격": "Φ1000mm", "대표": "MT014983"}, "비고": "A·B형 갈림 · 값은 「본」 — m 아님" },
|
||||
{ "키": "MP000031", "원문번호": "파형강관 ∅1000㎜", "이름": "파형강관", "규격": "∅1000㎜", "단위": "m", "요구절": ["산림품셈 12-11-3"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관"}, "비고": "두께 1.6·2.0·2.7T 갈림 — 원문 없음" },
|
||||
{ "키": "MP000032", "원문번호": "커플링밴드 ∅1000㎜", "이름": "커플링밴드(파형강관)", "규격": "∅1000㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": "MT015311", "고르기": null, "비고": "연결: 파형강관 커플링밴드 Φ1000 관급 줄" },
|
||||
{ "키": "MP000032", "원문번호": "커플링밴드 ∅1000㎜", "이름": "커플링밴드(파형강관)", "규격": "∅1000㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관", "이름": "파형강관 커플링밴드(관급)", "규격": "Φ1000mm", "대표": "MT015311"}, "비고": "일감35 — 규격(관경)만으론 접속티와 안 갈려 이름 조건을 더함" },
|
||||
{ "키": "MP000033", "원문번호": "VR관 ∅1200㎜", "이름": "VR관(소켓식)", "규격": "∅1200㎜", "단위": "m", "요구절": ["산림품셈 12-11-1"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "PVC관"}, "비고": "VR관 값은 「본」 — m 환산 안 함" },
|
||||
{ "키": "MP000034", "원문번호": "고무링 ∅1200㎜", "이름": "고무링(VR관)", "규격": "∅1200㎜", "단위": "개", "요구절": ["산림품셈 12-11-1"], "연결": "MT009725", "고르기": null, "비고": "연결: VR관고무링 D1200 이름·규격 같음" },
|
||||
{ "키": "MP000035", "원문번호": "흄관 ∅1200㎜", "이름": "흄관", "규격": "∅1200㎜", "단위": "m", "요구절": ["산림품셈 12-11-2-1"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "흄관", "규격": "Φ1200mm", "대표": "MT014985"}, "비고": "A·B형 갈림 · 값은 「본」 — m 아님" },
|
||||
{ "키": "MP000036", "원문번호": "파형강관 ∅1200㎜", "이름": "파형강관", "규격": "∅1200㎜", "단위": "m", "요구절": ["산림품셈 12-11-3"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관"}, "비고": "두께 1.6·2.0·2.7T 갈림 — 원문 없음" },
|
||||
{ "키": "MP000037", "원문번호": "커플링밴드 ∅1200㎜", "이름": "커플링밴드(파형강관)", "규격": "∅1200㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": "MT015313", "고르기": null, "비고": "연결: 파형강관 커플링밴드 Φ1200 관급 줄" },
|
||||
{ "키": "MP000037", "원문번호": "커플링밴드 ∅1200㎜", "이름": "커플링밴드(파형강관)", "규격": "∅1200㎜", "단위": "EA", "요구절": ["산림품셈 12-11-3 주①"], "연결": null, "고르기": {"구분": "관·이음관", "상세구분": "파형강관", "이름": "파형강관 커플링밴드(관급)", "규격": "Φ1200mm", "대표": "MT015313"}, "비고": "일감35 — 규격(관경)만으론 접속티와 안 갈려 이름 조건을 더함" },
|
||||
{ "키": "MP000038", "원문번호": "지수활제", "이름": "지수활제", "규격": "", "단위": "g", "요구절": ["산림품셈 12-11-1"], "연결": "MT030601", "고르기": null, "비고": "PLAN 7-4b: 자재품목 새 줄(MT030601)로 이음 · 값 미확보" },
|
||||
{ "키": "MP000039", "원문번호": "모르타르 1:2", "이름": "접합몰탈", "규격": "1:2", "단위": "㎥", "요구절": ["산림품셈 12-11-2-1", "건설품셈 건축 2-1-4", "건설품셈 건축 3-2-2"], "연결": null, "고르기": {"구분": "시멘트·골재", "상세구분": "모르타르", "규격": "1:2"}, "비고": "자재품목에 같은 품명 없음" },
|
||||
{ "키": "MP000040", "원문번호": "스틸그레이팅", "이름": "집수정 뚜껑", "규격": "스틸그레이팅", "단위": "개", "요구절": ["산림품셈 12-15"], "연결": null, "고르기": null, "비고": "자재품목에 같은 품명 없음 · 고르기 없음(자재품목 그 묶음에 같은 단위·이름 줄이 없음)" },
|
||||
|
||||
@@ -824,6 +824,40 @@ def test_재료_고르기_조건이_후보를_좁힘():
|
||||
assert mm.candidates(whole, {"구분": "없는구분"}) == []
|
||||
|
||||
|
||||
def test_재료_고르기_이름_조건이_같은_규격_다른_품명을_가름():
|
||||
"""일감35 — 규격(관경)만 같고 품명이 다른 줄(커플링밴드 vs 접속티)이 이름 칸으로 갈림."""
|
||||
files = {
|
||||
"재료_자재품목.json": {
|
||||
"줄": [
|
||||
{
|
||||
"키": "MT900010",
|
||||
"구분": "관·이음관",
|
||||
"상세구분": "파형강관",
|
||||
"이름": "파형강관 커플링밴드(관급)",
|
||||
"규격": "Φ800mm",
|
||||
"단위": "개",
|
||||
"물가자료": None,
|
||||
"관급": Decimal(19030),
|
||||
},
|
||||
{
|
||||
"키": "MT900011",
|
||||
"구분": "관·이음관",
|
||||
"상세구분": "파형강관",
|
||||
"이름": "파형강관이음관(관급)-거양",
|
||||
"규격": "접속티, Φ800mm, 아연도금",
|
||||
"단위": "개",
|
||||
"물가자료": None,
|
||||
"관급": Decimal(216770),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
whole = mf.Master(files)
|
||||
cond = {"구분": "관·이음관", "상세구분": "파형강관", "규격": "Φ800mm"}
|
||||
assert sorted(mm.candidates(whole, cond)) == ["MT900010", "MT900011"] # 이름 없으면 둘 다 걸림
|
||||
assert mm.candidates(whole, {**cond, "이름": "파형강관 커플링밴드(관급)"}) == ["MT900010"]
|
||||
|
||||
|
||||
def test_재료_고르기_시험계산은_대표_줄_없으면_값_있는_첫_줄():
|
||||
whole = _pipes()
|
||||
cond = {"구분": "관·수로", "상세구분": "흄관", "규격": "D300"}
|
||||
@@ -917,8 +951,8 @@ def test_품셈재료_고르기_칸_검사():
|
||||
|
||||
def test_고르기_조건_글자_열쇠():
|
||||
"""화면 단가 미리보기가 조건 줄을 찾는 이름 — 빈 칸은 빈 글자."""
|
||||
assert mm.cond_text({"구분": "관·수로", "상세구분": "흄관"}) == "관·수로|흄관||"
|
||||
assert mm.cond_text({"구분": "레미콘", "대표": "MT900002"}) == "레미콘|||MT900002"
|
||||
assert mm.cond_text({"구분": "관·수로", "상세구분": "흄관"}) == "관·수로|흄관|||"
|
||||
assert mm.cond_text({"구분": "레미콘", "대표": "MT900002"}) == "레미콘||||MT900002"
|
||||
|
||||
|
||||
def test_품셈재료_고르기_칸이_실파일에_있음():
|
||||
@@ -1068,9 +1102,9 @@ def test_고르기_조건의_모르는_변수를_잡음(whole):
|
||||
|
||||
|
||||
def test_변수_참조_줄은_고르기_조건으로_바뀜(whole):
|
||||
"""일감24 — `MT:{철선}` 꼴 옛 참조 19줄을 고르기 조건으로 옮김.
|
||||
VR관(GF000173)은 PLAN 7-4b 뒤 절반에서 1본=2.5m 환산으로 마저 옮김 — 남은 1줄은
|
||||
커플링밴드(GF000176, 접속티와 안 갈리는 문제 — sub2 가 이름 칸을 더하는 중)뿐."""
|
||||
"""일감24 — `MT:{철선}` 꼴 옛 참조 19줄을 고르기 조건으로 옮김. VR관(GF000173)은
|
||||
PLAN 7-4b 뒤 절반에서 1본=2.5m 환산으로, 커플링밴드(GF000176)는 일감35 에서
|
||||
「이름」 조건으로 마저 옮겨 남은 줄 없음."""
|
||||
남음 = [
|
||||
(str(row["키"]), item["요소"])
|
||||
for data in cm.load().values()
|
||||
@@ -1081,6 +1115,4 @@ def test_변수_참조_줄은_고르기_조건으로_바뀜(whole):
|
||||
and item["요소"][:2] in ("MP", "MT")
|
||||
and "{" in item["요소"]
|
||||
]
|
||||
assert sorted(남음) == [
|
||||
("GF000176", "MP:커플링밴드 ∅{관경}㎜"),
|
||||
]
|
||||
assert sorted(남음) == []
|
||||
|
||||
Reference in New Issue
Block a user