"""가져온 식 SK ↔ 우리 M01 기초 — 연결 찾기 기록 · 「확정」 때만 우리 기초 사본으로 바꾸기 · 되돌리기 (PLAN 810-4 · 요구 707 · 708 · 709 · 703) — 서버 단독. 찾기(`find`) = 가져온 식 문서(우리 단가로 셈) → `M02_Doc_Match.match` → SK `가져온.원본.연결후보` 에 적음. 바꾸기(`swap`) = 서버가 다시 찾아 「확정」 일 때만 — 같은 SK 키에 M01 사본 SK(바탕 = 그 기초 · 입력값 = 찾은 옵션 · 802-4a 꼴 · 수식 사본은 저장 때 서버가 찍음)를 씀 · 원래 가져온 식 SK 몸은 `가져온보관` 칸에 그대로 둠 · 일위대가 줄 참조 = 키 그대로(SK 내용만 바뀜 → 금액 다시 셈). 되돌리기(`back`) = `가져온보관` 몸을 그 키에 다시 씀(가져온 식 금액 그대로). 우리 M01 기초는 어느 갈래에서도 안 바뀜(708) · 근접 · 없음 = 바꾸기 409(703). """ from __future__ import annotations from typing import Any from common_util.common_util_time import utc_now_text from M02_MasterTemplete import M02_Doc_Copy as dc from M02_MasterTemplete import M02_Doc_Import as dim from M02_MasterTemplete import M02_Doc_Match as dm from M02_MasterTemplete import M02_MasterTemplete_Store as store from M02_MasterTemplete import M02_Sangeun_Doc as sd from M02_MasterTemplete import M02_Sangeun_Imported as imp KEEP = "가져온보관" # 바꾼 SK 의 원래 가져온 식 몸(되돌리기) _INDEX: dict[str, Any] = {"문서": None, "색인": None} def _bad(why: str, status: int = 400) -> store.StoreError: return store.StoreError(status, why) def index() -> dm.Index: """M01 수식 문서 색인 — 폴더가 바뀌면(M01 관리자 고침) 다시.""" docs = dc.folder() if _INDEX["문서"] is not docs: _INDEX["문서"], _INDEX["색인"] = docs, dm.Index(docs) return _INDEX["색인"] def _read(key: str) -> dict[str, Any]: if not sd.KEY.match(str(key or "")): raise _bad("키(SK-######)") return store.read(sd.KIND, key) def judge(sk: dict) -> dict[str, Any]: """가져온 식 SK → 연결후보(저장 없음).""" whole = imp._whole() links_imp = dim.Links(whole, "우리") doc = dim.of(sk) links_imp.learn(doc) got = dm.match(doc, links_imp, index(), dm.ml.Links(whole, dc.folder())) return {**got, "때": utc_now_text()} def find(key: str, version: str) -> dict[str, Any]: """연결 찾기 → SK `가져온.원본.연결후보` 에 적음 → {연결후보, 판}.""" got = _read(key) sk = got["문서"] if not dim.is_imported(sk): raise _bad("가져온 식 단가산출만 연결을 찾음") found = judge(sk) meta = sk[imp.KEY] new = {**sk, imp.KEY: {**meta, "원본": {**(meta.get("원본") or {}), dm.KEY: found}}} info = store.write(sd.KIND, key, version or got["판"], new) return {dm.KEY: found, "판": info.get("판")} def copy_body(sk: dict, found: dict) -> dict[str, Any]: """M01 사본 SK 몸(이름 · 단위 · 구분 그대로 · 바탕 = 찾은 기초 · 입력값 = 찾은 옵션).""" keep = {k: sk.get(k) for k in ("키", "이름", "단위", "구분", "상세구분") if sk.get(k)} old = {k: v for k, v in sk.items() if k not in ("키", "종류", KEEP)} body = { "덮개": {}, "뺀줄": [], "더한줄": [], "고름": {}, "자재표시": {}, } # M01 그대로(고침 없음) base = {"바탕": {"로직": found["키"]}, "입력값": dict(found.get("옵션") or {})} return {**keep, **body, **base, KEEP: old} def swap(key: str, version: str) -> dict[str, Any]: """「확정」 일 때만 우리 기초 사본으로 — 서버가 다시 찾음(화면 판정을 믿지 않음).""" got = _read(key) sk = got["문서"] if not dim.is_imported(sk): raise _bad("가져온 식 단가산출만 바꿈") found = judge(sk) if found.get("판정") != dm.SURE: raise _bad(f"우리 기초와 「확정」 일치가 아님({found.get('판정')}) — 바꾸지 않음", 409) info = store.write(sd.KIND, key, version or got["판"], copy_body(sk, found)) return {dm.KEY: found, "판": info.get("판")} def back(key: str, version: str) -> dict[str, Any]: """우리 기초 사본 → 원래 가져온 식(보관 몸 그대로).""" got = _read(key) old = got["문서"].get(KEEP) if not isinstance(old, dict) or not old.get(imp.KEY): raise _bad("되돌릴 가져온 식 없음") info = store.write(sd.KIND, key, version or got["판"], {**old, "키": key}) return {"판": info.get("판")}