feat(M02 실무자료): 358-1 후보 묶음 — 이름후보(옛 324 다섯) · 뜻겹침 · 출처 같음 · 책 표시 · 고르기 창 묶음 · 검색 칸 = 품명 낱말 · 일괄 적용(N)
- 서버 줄 맞춤에 이름후보(옛 데스크탑 판과 같음 · 600줄 대조 0 다름) · 후보마다 뜻겹침 · 출처같음(조항 ≥ 0.9) · 책 — 차례 · 무게 · 상태 그대로 - 고르기 창 = 1위 / 출처 같음 / 이름 닮은 로직 / 숫자만 닮음(접힘 · 뜻 안 겹치는 후보 회색 끝) · 같은 이름 책 표시 - 버튼 명사형 — 일괄 적용(N) · 엑셀 보기 · 다른 로직 검색 · 재료비 있는 줄은 다른 자재 검색도 - 시험: match 이름후보 다섯 · 되메우기 · 다웰바 · golden 다섯 안 ∪ 이름후보 · screen 묶음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
This commit is contained in:
@@ -159,6 +159,42 @@ let out0 = null;
|
||||
word: [choose.builtWord({ 다시씀: false }), choose.builtWord({ 다시씀: true })],
|
||||
qty: choose.qtyText(lines[1].맞춤.품.엑셀),
|
||||
target: choose.targetText({ 호표: 46, 단위: "㎡" }),
|
||||
// 358-1 후보 묶음 — 1위 / 출처 같음 / 이름 닮은 로직 / 숫자만 닮음(약한 후보 끝) · 같은 이름 책
|
||||
groups: (() => {
|
||||
const m = {
|
||||
후보: [
|
||||
{ 로직: "A", 이름: "되메우기", 판정: "맞음", 뜻겹침: true, 책: "산림품셈" },
|
||||
{ 로직: "B", 이름: "야면석 채집", 판정: "후보", 뜻겹침: false },
|
||||
{
|
||||
로직: "C",
|
||||
이름: "되메우기",
|
||||
판정: "후보",
|
||||
뜻겹침: true,
|
||||
출처같음: true,
|
||||
책: "건설품셈",
|
||||
},
|
||||
{ 로직: "D", 이름: "표토펴기", 판정: "다른 점", 뜻겹침: false },
|
||||
],
|
||||
이름후보: [
|
||||
{ 로직: "A", 이름: "되메우기" },
|
||||
{ 로직: "E", 이름: "되메우기(노상재)" },
|
||||
],
|
||||
};
|
||||
const g = choose.candGroups(m);
|
||||
const twins = choose.sameNames(g);
|
||||
return {
|
||||
groups: g.map((x) => [x.제목, x.접힘, x.후보.map((c) => c.로직)]),
|
||||
text: g.flatMap((x) => x.후보).map((c) => choose.candText(c, twins)),
|
||||
material: choose
|
||||
.candGroups({ 후보: [{ 자재: "M1" }, { 자재: "M2" }] }, true)
|
||||
.map((x) => x.제목),
|
||||
pick: [
|
||||
choose.canPickMaterial({ 갈래: "단가산출", 단가: { 재료비: 10 } }),
|
||||
choose.canPickMaterial({ 갈래: "단가산출", 단가: { 재료비: null } }),
|
||||
choose.canPickMaterial({ 갈래: "별도계상", 단가: {} }),
|
||||
],
|
||||
};
|
||||
})(),
|
||||
},
|
||||
ledger: (() => {
|
||||
const rows = input.ledger;
|
||||
|
||||
@@ -80,3 +80,18 @@ def test_씨앗_끔_1순위(no_seeds):
|
||||
def test_원본_그대로_셈_무게(run):
|
||||
assert master_hash() == run["원본"]
|
||||
assert run["결과"]["시간"]["북부청임도"] <= 300 # 북부청 임도 맞춤 셈 ≤ 5 분
|
||||
|
||||
|
||||
def test_이름후보_묶음_덧(run):
|
||||
"""358-1 — 이름후보(옛 324 다섯) = 묶음 덧 · 숫자 차례 그대로 → 다섯 안 ∪ 이름후보 ≥ 다섯 안."""
|
||||
have = [
|
||||
r for r in run["결과"]["줄"].values() if r["lab"]["무리"] == "사람" and r["lab"]["정답"]
|
||||
]
|
||||
got = hm.targets()
|
||||
five = [set(r["셈"]["차례"][:5]) for r in have]
|
||||
named = [{c["로직"] for c in hm.name_cands(r["lab"], got)} for r in have]
|
||||
near = sum(bool(f & set(r["lab"]["정답"])) for f, r in zip(five, have, strict=True))
|
||||
both = sum(
|
||||
bool((f | n) & set(r["lab"]["정답"])) for f, n, r in zip(five, named, have, strict=True)
|
||||
)
|
||||
assert both >= near >= 122
|
||||
|
||||
@@ -245,3 +245,26 @@ def test_뜻_낱말이_안_겹치면_후보_아님():
|
||||
assert got["상태"] == "없음" and got["top"] == []
|
||||
fill = {"이름": "구조물되메우기(인력100%)", "규격": "", "단위": "㎥", "갈래": "단가산출"}
|
||||
assert hm.candidates(fill, "로직")[0]["이름"] == "되메우기" # 한쪽 낱말에 듦 = 겹침
|
||||
|
||||
|
||||
# ── 이름 닮은 로직(358-1 · 옛 324 데스크탑 다섯 그대로) ─────────────────────
|
||||
def test_이름후보_옛_데스크탑_다섯():
|
||||
fill = {"이름": "구조물되메우기(인력100%)", "규격": "", "단위": "㎥", "갈래": "단가산출"}
|
||||
got = [c["로직"] for c in hm.name_cands(fill)]
|
||||
assert got == ["GF000113", "GF000194", "GC000108", "GC000109", "GC000451"] # 되메우기 다섯
|
||||
dowel = {"이름": "다웰바설치", "규격": "Φ32×1000", "단위": "EA", "갈래": "단가산출"}
|
||||
assert [c["로직"] for c in hm.name_cands(dowel)][:3] == ["GC000226", "GF000201", "GF000202"]
|
||||
soil = {"이름": "잔토처리(인력100%)", "규격": "", "단위": "㎥", "갈래": "단가산출"}
|
||||
assert hm.name_cands(soil) == [] # 뜻 낱말 안 겹치면 후보 아님 그대로
|
||||
same = {"이름": "되메우기", "규격": "", "단위": "㎥", "갈래": "단가산출"}
|
||||
assert hm.name_cands(same)[0] == {**hm.name_cands(same)[0], "로직": "GF000113", "점수": 9}
|
||||
|
||||
|
||||
def test_이름후보_뜻겹침_출처_표시(client):
|
||||
_ready(client)
|
||||
dig = _hopyo(client, 3)["구조물터파기(인력100%)"]
|
||||
assert dig["이름후보"] and all({"뜻겹침", "출처같음", "책"} <= set(c) for c in dig["이름후보"])
|
||||
assert dig["후보"][0]["출처같음"] is True and dig["후보"][0]["책"] == "건설품셈" # 3-2-1
|
||||
assert [c["로직"] for c in dig["후보"]][0] == "GC000083" # 차례 · 판정 그대로(표시만)
|
||||
mat = _hopyo(client, 1)["레미콘(25-21-120)"]
|
||||
assert "이름후보" not in mat # 자재 줄은 로직 이름후보 없음
|
||||
|
||||
@@ -136,7 +136,16 @@ def test_확인_창_체크한_줄만_몸():
|
||||
|
||||
def test_고르기_창_도우미():
|
||||
got = _check()["choose"]
|
||||
assert got["hint"] == ["6-1-1", "고임돌"] # 인용 조항 번호 → 없으면 품명 첫 뜻 낱말
|
||||
assert got["hint"] == ["레미콘타설", "고임돌"] # 품명 첫 뜻 낱말(358-1 · 조항 번호 아님)
|
||||
assert got["groups"]["groups"] == [
|
||||
["1위", False, ["A"]],
|
||||
["출처 같음", False, ["C"]],
|
||||
["이름 닮은 로직", False, ["E"]],
|
||||
["숫자만 닮음", True, ["D", "B"]], # 뜻 낱말 안 겹치는 「후보」 = 끝
|
||||
]
|
||||
assert got["groups"]["text"][:2] == ["되메우기 · A · 산림", "되메우기 · C · 건설"]
|
||||
assert got["groups"]["material"] == ["1위", "그 밖 후보"]
|
||||
assert got["groups"]["pick"] == [True, False, True] # 재료비 있는 단가산출 줄도 자재 검색
|
||||
assert got["picked"] == [
|
||||
{"로직": "GC000206", "입력값": {}, "배": 1, "몫": None},
|
||||
{"로직": "GF000211", "입력값": {}, "배": 0.1, "몫": 0.1},
|
||||
|
||||
Reference in New Issue
Block a user