diff --git a/M01_MasterData/M01_MasterData_Store_Matset.py b/M01_MasterData/M01_MasterData_Store_Matset.py index e3692168..08308fdc 100644 --- a/M01_MasterData/M01_MasterData_Store_Matset.py +++ b/M01_MasterData/M01_MasterData_Store_Matset.py @@ -14,7 +14,7 @@ from M01_MasterData import M01_MasterData_Store as store from M01_MasterData import M01_MasterData_Store_Combo as combos cm = store.cm -msk = cm.msk +msk = cm.mmc # sub4 가 세운 자재 조합 엔진(`scripts/master_material_combo.py`) FILE = msk.FILE OWNERS = msk.OWNERS @@ -63,12 +63,23 @@ def _clean(one: dict, owner: str, key: str | None = None) -> dict: if isinstance(got, list): # 화면이 덤을 실어도 자재 줄은 네 칸만 · 안 준 칸은 빈 글 got = [{c: m.get(c, "") for c in msk.ITEM_COLS} if isinstance(m, dict) else m for m in got] rest = {k: v for k, v in one.items() if k not in ("키", "원문번호", "소유")} + _check_codes(got) row = {**({"키": key} if key else {}), "소유": owner, **rest, "담은자재": got or []} for col in msk.COLS: row.setdefault(col, None) return {k: row[k] for k in msk.COLS if k in row} +def _check_codes(got) -> None: + """담은 자재 코드가 마스터 어느 줄에도 없으면 422 — 틀 검사는 저장 길(`store.save`)이 함.""" + if not isinstance(got, list) or not got: + return + known = {str(r.get("키")) for d in store.loaded()[0].values() for r in d.get("줄") or []} + lost = [str(m.get("코드")) for m in got if isinstance(m, dict) and m.get("코드") not in known] + if lost: + raise store.StoreError(422, {"errors": [f"마스터에 없는 자재 {' · '.join(lost)}"]}) + + def _write(changes: list[dict], version: str | None = None) -> dict: _make_file() return store.save( @@ -79,7 +90,7 @@ def _write(changes: list[dict], version: str | None = None) -> dict: def matsets(q: str = "", owner: str = "") -> list[dict]: """목록 — 찾기(이름 · 키)와 소유로 거름 · 줄마다 자재 수.""" out = [] - for _, row in msk.rows(store.loaded()[0]): + for row in store.loaded()[0].get(FILE, {}).get("줄") or []: if owner and row.get("소유") != owner: continue if not store._hit(row, q): diff --git a/resources/tester/test_m01_matset.py b/resources/tester/test_m01_matset.py index 58ff30cc..7be0f59b 100644 --- a/resources/tester/test_m01_matset.py +++ b/resources/tester/test_m01_matset.py @@ -53,7 +53,7 @@ def _new(client: TestClient, name: str, mats: list[dict], **more) -> dict: def test_정본_자재조합_파일은_틀대로다() -> None: data = json.loads((ROOT / "resources/master_data/자재조합.json").read_text(encoding="utf-8")) assert data["그룹"] == "자재조합" and isinstance(data["줄"], list) - assert store.cm.msk.check_form("자재조합.json", data) == [] + assert store.cm.mmc.check_form("자재조합.json", data) == [] assert '"UM"' in (ROOT / "resources/master_data/_키대장.json").read_text(encoding="utf-8") @@ -63,7 +63,7 @@ def test_새로_만들면_UM_키와_열_한_벌(client) -> None: assert res.status_code == 200, res.text made = res.json() assert made["key"].startswith("UM") and len(made["key"]) == 8 - assert tuple(made["matset"]) == store.cm.msk.COLS + assert tuple(made["matset"]) == store.cm.mmc.COLS assert made["matset"]["담은자재"] == [mat] and made["matset"]["본뜬키"] is None rows = client.get("/api/m01/matsets").json()["matsets"] assert [(r["키"], r["count"]) for r in rows] == [(made["key"], 1)]