"""721 M02 찾아 넣기 창 — 단추 이름 · 자리 · 부르는 곳 · 인력 · 재료 줄 꼴(요구서_내역16 1장 5~7 · 2장 1 · 2 · 8). - 721-1 단가산출 상세 = 둘째 줄 [항목 추가](727-2 [기본 로직 선택] 걷음 — 첫 기초가 바탕) - 721-2 M02 두 곳(항목 추가 · 일위대가 [로직 추가])만 새 창 · B09 · 불러오기는 옛 창 - M01 전체 = 로직 · 인력(job) · 재료(price) · 기계 · 실무 호표 없음 - 고른 인력 · 재료 = 단가산출 더한줄 `{종류, 요소}` · 일위대가 고정 줄(705-1 이음 꼴) — 둘 다 서버가 받아 노임 · 자재 값으로 셈 """ from __future__ import annotations from pathlib import Path import pytest from M02_MasterTemplete import M02_Labor_Doc as labor from M02_MasterTemplete import M02_Sangeun_Calc as calc ROOT = Path(__file__).resolve().parents[2] M02 = ROOT / "M02_MasterTemplete" LB, MT = "LB000033", "MT000018" # 석공 · 합판(내수) — M01 에 있음 def _text(path: Path) -> str: return path.read_text(encoding="utf-8") def test_721_1_단추_이름과_자리(): detail = _text(M02 / "M02_MasterTemplete_Sangeun_Detail.ts") assert "children: [views.root, addButton]" in detail # 750-2 「시험 계산 = 바탕」 안내 걷음 assert "M02_SangeunPickBase" not in detail # 727-2 단추 걷음 locale = _text(ROOT / "ui_template" / "ui_template_locale_m2.ts") assert "M02_SangeunPickBase" not in locale assert 'M02_SangeunAddLine: ["항목 추가"' in locale def test_721_2_부르는_곳_셋만_새_창(): find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") labor_pick = _text(M02 / "M02_MasterTemplete_Labor_Pick.ts") assert 'if (lib?.sangeun && lib.layer !== "project")' in labor_pick assert "return openFindPicker({" in labor_pick assert "findSangeun" not in labor_pick # 옛 창의 단가산출 탭 걷음 assert "logicOnly" not in _text(M02 / "M02_MasterTemplete_Sangeun_Detail.ts") # 727-2 assert "logicOnly" not in find assert "openFindPicker({" in _text(M02 / "M02_MasterTemplete_Sangeun_Pick.ts") assert "sangeun: true," in _text(M02 / "M02_MasterTemplete_Hopyo_Pick.ts") # 일위대가 # 옛 창 그대로 — B09 단가 연결은 sangeun 없이 부름(736-1 불러오기 · 별칭 장부는 찾아 넣기 창으로) for f in ( ROOT / "B09_Estimation" / "B09_Estimation_UI_Link.ts", ROOT / "B09_Estimation" / "B09_Estimation_UI_Tabs_Bill_Link.ts", ): text = _text(f) assert "openLogicPicker(" in text and "sangeun:" not in text, f.name for f in ("Hopyo_Choose", "Hopyo_Ledger"): text = _text(M02 / f"M02_MasterTemplete_{f}.ts") assert "openFindPicker({" in text and "openLogicPicker" not in text.split("*/", 1)[1], f # 탭 셋 · 찾기 칸 하나 · 거름 고르기 없음 · M01 = 로직 · 인력 · 재료(기계 · 호표 없음) for key in ('key: "m01"', 'key: "sk"', 'key: "pre"'): assert key in find assert "createSelectField" not in find and "Hopyo" not in find assert '(kind: "job" | "price")' in find and "/elements" in find # 736-2 기계(EQ) 묶음 def test_721_2_고정_줄_꼴(): find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") assert "이음: { 노임: labor ? e.코드 : null, 자재: labor ? null : e.코드, 기계: null }" in find assert "take(() => put(e))" in find and "!put" in find assert "dim: !put," in find # 받는 쪽 없으면 회색 막힘 def _fx(name: str, unit: str, code: str) -> dict: """`fixedOf` 꼴 — 인력 = 노임 이음 · 재료 = 자재 이음 · 단가 = 고를 때 값(셈은 단가 책)""" labor_ = code.startswith("LB") return { "이름": name, "규격": "", "단위": unit, "단가": {"노무비": 1 if labor_ else 0, "재료비": 0 if labor_ else 1, "경비": 0}, "이음": {"노임": code if labor_ else None, "자재": None if labor_ else code, "기계": None}, } def test_721_2_인력_재료_서버가_받아_셈(): whole = labor.m01.loaded()[1] wage = whole.get(LB)["값"] sk = calc.calc_doc( { "키": "SK-000001", "이름": "시험", "단위": "㎡", "바탕": None, "더한줄": [ {"종류": "인력", "요소": LB, "이름": "석공", "단위": "인", "수량": 1}, {"종류": "재료", "요소": MT, "이름": "합판", "단위": "㎡", "수량": 1}, ], } )["1단위"] doc = labor.clean( { "담은로직": [ {"로직": "", "고정": _fx("석공", "인", LB), "수량": {"손": 1}}, {"로직": "", "고정": _fx("합판", "㎡", MT), "수량": {"손": 1}}, ] } ) got = labor.calc(doc, {}) assert sk["노무비"] == pytest.approx(wage) and sk["재료비"] > 0 assert got["반영합"]["계"] == pytest.approx(sk["계"]) assert [ln["이은"] for ln in got["줄"]] == [["노무비"], ["재료비"]] def test_736_1_항목_추가_찾기_창_하나(): """736-1 — [로직 추가] → [항목 추가] · [자재 추가] 걷음 · 재료 = 자재 목록 · 자리마다 탭 막음.""" locale = _text(ROOT / "ui_template" / "ui_template_locale_m2.ts") assert "[로직 추가]" not in locale and "기초는 [항목 추가]로" in locale assert 'AddLogic: ["항목 추가", "Add item"]' in _text(M02 / "M02_MasterTemplete_Labor_Text.ts") table = _text(M02 / "M02_MasterTemplete_Labor_Table.ts") detail = _text(M02 / "M02_MasterTemplete_Labor_Detail.ts") for text in (table, detail): assert "addMaterialButton" not in text and "addMat" not in text assert "material: (m: {" in text # 재료 고름 → 「자재 목록」 assert '"Labor_InLogicMat"' in text and '"Labor_AlreadyMat"' in text # 중복 검사 그대로 pick = _text(M02 / "M02_MasterTemplete_Labor_Pick.ts") assert "material: lib.material," in pick find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") assert 'kind === "재료" && opt.material' in find and "? opt.material" in find assert '"logic" | "labor" | "material" | "machine" | "sk" | "pre"' in find # 불러오기 엑셀 연결 = 기초(자재 아닌 줄) · 재료(자재 · 재료비 줄) · 별칭 장부 = 기초 · 재료 둘 choose = _text(M02 / "M02_MasterTemplete_Hopyo_Choose.ts") assert "다른 로직 검색" not in choose and "다른 자재 검색" not in choose assert 'MATERIAL.has(line.갈래) ? [] : (["logic"] as const)' in choose assert 'canPickMaterial(line) ? (["material"] as const) : []' in choose assert 'kinds: ["logic", "material"],' in _text(M02 / "M02_MasterTemplete_Hopyo_Ledger.ts") def test_736_2_빠진_길_둘_신규_자재_기계_탭(): """736-2 — 개인 층 재료 고름 머리 [신규 자재] · 엑셀 연결 = 줄 갈래대로 탭(노임 인력 · 기계 기계 · 자재 재료).""" find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") assert 'opt.layer === "personal" && !!opt.material && ok("material")' in find assert "openNewMaterial(opt.owner" in find and "actions: [newMat]" in find assert "machine?: (e: M01Element) => void;" in find assert 'opt.machine && ok("machine")' in find pick = _text(M02 / "M02_Material_Pick.ts") assert "export function openNewMaterial(" in pick and "{ owner }," in pick choose = _text(M02 / "M02_MasterTemplete_Hopyo_Choose.ts") assert 'line.갈래 === "노임"' in choose and '["labor"]' in choose and '["machine"]' in choose assert "element: (e) => opt.done([{ 노임: e.코드, 배: 1 }])," in choose assert "machine: (e) => opt.done([{ 기계: e.코드, 배: 1 }])," in choose left = _text(M02 / "M02_MasterTemplete_Hopyo_Left.ts") assert "kinds: kindsOf(line)" in left and "pickMachine" not in left lost = _text(M02 / "M02_MasterTemplete_Hopyo_Lost.ts") assert '"machine"' in lost and "pickMachine" not in lost unlinked = _text(M02 / "M02_MasterTemplete_Labor_Unlinked.ts") assert 'machine: (e) => done("기계", e.코드)' in unlinked and "pickMachine" not in unlinked def test_736_3_기계_고정_줄_금액(): """736-3 — [항목 추가] 기계(EQ) = 고정 줄(이음 기계 · 단가 = 한 시간 노 · 재 · 경) — 단가산출 · 일위대가가 같은 금액.""" from M02_MasterTemplete import M02_Machine_Hourly as machine EQ = "EQ000019" # 굴착기(무한궤도) 0.6㎥ got = machine.hourly(EQ) assert got["ok"] and got["계"] > 0 assert got["계"] == pytest.approx(got["노무비"] + got["재료비"] + got["경비"]) assert not machine.hourly(LB)["ok"] and not machine.hourly("EQ999999")["ok"] fx = { "이름": got["이름"], "규격": got["규격"], "단위": "시간", "단가": {k: got[k] for k in ("노무비", "재료비", "경비")}, "이음": {"노임": None, "자재": None, "기계": EQ}, } sk = calc.calc_doc( { "키": "SK-000001", "이름": "시험", "단위": "시간", "바탕": None, "더한줄": [{"고정": fx, "이름": got["이름"], "단위": "시간", "수량": 1}], } )["1단위"] doc = labor.clean({"담은로직": [{"로직": "", "고정": fx, "수량": {"손": 1}}]}) assert sk["계"] == pytest.approx(got["계"]) assert labor.calc(doc, {})["반영합"]["계"] == pytest.approx(got["계"]) find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") assert ( "/logic-lib/machine-hourly?key=" in find and "이음: { 노임: null, 자재: null, 기계: e.코드 }" in find ) assert "machine: fixed &&" in _text(M02 / "M02_MasterTemplete_Labor_Pick.ts") assert "machine: (e) => done({ 고정: fixedOf(e)" in _text( M02 / "M02_MasterTemplete_Sangeun_Pick.ts" )