From 0959f287177eaa96cd370850a3eb0b28ccf60d42 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 31 Oct 2026 17:29:04 +0900 Subject: [PATCH] =?UTF-8?q?feat(B09=20=EC=84=A4=EA=B3=84=EB=82=B4=EC=97=AD?= =?UTF-8?q?=EC=84=9C):=20=EC=9D=B4=20=EC=A7=9D=20=EC=9E=8A=EA=B8=B0=20=3D?= =?UTF-8?q?=20=EC=9E=8A=EC=9D=8C=20=ED=91=9C=EC=8B=9C=EB=A5=BC=20=EA=B8=B0?= =?UTF-8?q?=EC=96=B5=EC=97=90=20=EB=82=A8=EA=B9=80=20=E2=80=94=20=EB=8A=90?= =?UTF-8?q?=EC=8A=A8=ED=95=9C=20=EA=B8=B0=EC=96=B5(=ED=92=88=EB=AA=85=20?= =?UTF-8?q?=C2=B7=20=EB=8B=A8=EC=9C=84=20=EA=B0=99=EC=9D=8C)=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=EB=8F=84=20=EB=8B=A4=EC=8B=9C=20=EC=A0=9C=EC=95=88=20?= =?UTF-8?q?=EC=95=88=20=EB=90=A8=20=C2=B7=20=EB=8B=A4=EC=8B=9C=20=EC=9D=B4?= =?UTF-8?q?=EC=9C=BC=EB=A9=B4=20=ED=92=80=EB=A6=BC=20(PLAN=20707-4=20?= =?UTF-8?q?=EB=8D=A7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- B09_Estimation/B09_Estimation_Bill_Link.py | 11 +++++--- B09_Estimation/B09_Estimation_Router_Link.py | 7 ++--- resources/tester/test_707_4_bill_link.py | 27 +++++++++++++++++--- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/B09_Estimation/B09_Estimation_Bill_Link.py b/B09_Estimation/B09_Estimation_Bill_Link.py index 0732de6f8..456cc062c 100644 --- a/B09_Estimation/B09_Estimation_Bill_Link.py +++ b/B09_Estimation/B09_Estimation_Bill_Link.py @@ -33,6 +33,7 @@ from M02_MasterTemplete.M02_Hopyo_Match import line_key MEMORY = "내역맞춤" TABLE, RECALL = "짝 표", "지난번 이음" +FORGOT = "잊음" # 기억 칸 {잊음: True} = 이 짝 잊기 표시 — 느슨한 기억에서도 안 불러옴 · 다시 이으면 덮임 HEADS = ("earth", "st", "haul") _TAIL = re.compile(r"^(.+?)\((.*)\)$") ROCK = ("절토(연암)", "암발파") @@ -97,11 +98,15 @@ def _loose(key: str) -> str: def recall(memory: dict[str, dict[str, Any]], row: dict[str, Any]) -> dict[str, Any] | None: - """기억 한 칸 — 같은 열쇠 · 없으면 품명 · 단위 같고 짝이 하나인 것.""" + """기억 한 칸 — 같은 열쇠 · 없으면 품명 · 단위 같고 짝이 하나인 것(잊은 칸 = 없음).""" key = key_of(row) if isinstance(memory.get(key), dict): - return memory[key] - loose = [v for k, v in memory.items() if isinstance(v, dict) and _loose(k) == _loose(key)] + return None if memory[key].get(FORGOT) else memory[key] + loose = [ + v + for k, v in memory.items() + if isinstance(v, dict) and not v.get(FORGOT) and _loose(k) == _loose(key) + ] return loose[0] if len({v.get("확정") for v in loose}) == 1 else None diff --git a/B09_Estimation/B09_Estimation_Router_Link.py b/B09_Estimation/B09_Estimation_Router_Link.py index d7f27a368..3f8f05ebf 100644 --- a/B09_Estimation/B09_Estimation_Router_Link.py +++ b/B09_Estimation/B09_Estimation_Router_Link.py @@ -10,7 +10,8 @@ 이은 짝 = 맞춤 기억에 씀(회사 층 = 회사 관리자 · 아니면 개인 층) POST …/link/undo {target, user?} → {user, 알림, payload} — 잇기 풀기(맞춤 기억 그대로) POST …/link/forget {key, user?} → {잊음, 기억층, 남음} — 이 짝 잊기(불러온 줄 · 이은 줄 키 → - 맞춤 열쇠 · 쓸 수 있는 층에서 지움 · 남음 = 못 지운 위 층 기억) + 맞춤 열쇠 · 쓸 수 있는 층에 잊음 표시 `{잊음: True}` — 느슨한 기억도 안 불러옴 · + 개인 층 표시가 회사 기억을 덮음 · 남음 = 그래도 살아 있는 기억) 맞춤 기억 = 층 `실무자료/내역맞춤.json`(실무자료 맞춤 꼴) · 읽기 = 회사 + 개인(개인이 이김). 끼워 넣기 = `B09_Estimation_Router`(같은 머리 · 같은 권한) · 화면 = `B09_Estimation_UI_Link`. """ @@ -175,6 +176,6 @@ async def forget( memo = memo or next((r["memo"] for r in board["이은"] if r["key"] == body.key), None) if not memo: raise HTTPException(status_code=400, detail="불러온 줄 · 이은 줄이 아님") - layer = await asyncio.to_thread(keep, session, {memo: None}) - left = memo in await asyncio.to_thread(recalled, session) + layer = await asyncio.to_thread(keep, session, {memo: {linker.FORGOT: True}}) + left = bool((await asyncio.to_thread(recalled, session)).get(memo, {}).get("확정")) return {"잊음": memo, "기억층": layer, "남음": left} diff --git a/resources/tester/test_707_4_bill_link.py b/resources/tester/test_707_4_bill_link.py index 13b342a39..4be04925b 100644 --- a/resources/tester/test_707_4_bill_link.py +++ b/resources/tester/test_707_4_bill_link.py @@ -274,9 +274,28 @@ def test_줄마다_갈래_판(geo): def test_이_짝_잊기(tmp_path, monkeypatch): monkeypatch.setattr(route.access, "folder", lambda got, create=False: tmp_path / got.layer) user = {"company_id": 7, "user_id": 3, "role": "USER"} + gone = {lk.FORGOT: True} route.keep(user, {"a||": {"확정": "earth:4"}, "b||": {"확정": "earth:5"}}) hopyo_store.remember(tmp_path / "company", {"c||": {"확정": "x"}}, lk.MEMORY) - assert route.keep(user, {"a||": None}) == "personal" - assert set(route.recalled(user)) == {"b||", "c||"} - route.keep(user, {"c||": None}) - assert "c||" in route.recalled(user) # 일반 = 회사 기억 못 지움(남음) + assert route.keep(user, {"a||": gone}) == "personal" + assert route.recalled(user)["a||"] == gone and route.recalled(user)["b||"]["확정"] == "earth:5" + route.keep(user, {"c||": gone}) # 일반 = 회사 기억을 개인 층 표시로 덮음 + assert route.recalled(user)["c||"] == gone + + +def test_잊은_짝_느슨한_기억에도_안_나옴(tmp_path, monkeypatch): + monkeypatch.setattr(route.access, "folder", lambda got, create=False: tmp_path / got.layer) + user = {"company_id": 7, "user_id": 3, "role": "USER"} + row = {"name": "토사절취", "spec": "A", "unit": "m3"} + other = {"name": "토사절취", "spec": "B", "unit": "m3"} + live = {"확정": "earth:4", "이름": "절토(토사)"} + route.keep(user, {lk.key_of(other): live}) + assert ( + lk.recall(route.recalled(user), row) == live + ) # 규격 달라도 품명 · 단위 같음 = 느슨한 기억 + route.keep(user, {lk.key_of(row): {lk.FORGOT: True}}) + memory = route.recalled(user) + assert lk.recall(memory, row) is None # 잊음 = 느슨한 기억도 끊김 + assert lk.recall(memory, other) == live # 다른 줄은 그대로 + route.keep(user, {lk.key_of(row): live}) # 다시 이음 = 풀림 + assert lk.recall(route.recalled(user), row) == live