feat(733-2): 사람 길 만들 때 같은 내용 409 물음 · 복사 딸림 재사용
- 새 M02_Library_Ask — 같은 층 같은 내용(733-1 지문) = 409 {같은것: [{키, 이름, 층, 주인}], 까닭} · 몸 새로 = 그래도 새로 · 씀 = 그 키(새 문서 0 · 같은 내용 아닌 키 = 다시 409)
- 길 = 새로 만들기(빈 문서 · 같은 층 복사 = 안 물음) · [단가산출로 저장] from-line · B09 내 자료집(같은이름 409 와 한 몸 · 하위 호표 지문 = 굳힌 문서) · 공유 요청 승인(일위대가 · 씀 = 사본 키) · 실무 호표 [구조물 조합으로](구조물 조합 지문 = 줄 수량 넣음)
- 복사 딸림 carry — 받는 층에 같은 원본 + 같은 내용 사본이 있으면 그 키 재사용(refs.copied_from) · B09 하위 호표 재사용 목록 = 실무자료 한정 → 모든 사본 원본
- 낡은 시험 고침: test_703 자료집 같은 이름 물음 — 새 이름이라도 같은 내용이면 409(정함 3장 3) → new=True 로 새로 · 씀 확인 더함
- 새 시험 test_733_2_library_ask(새로 · from-line · 승인 · carry) · test_705_2 구조물 조합으로 409
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,6 @@ from B09_Estimation import B09_Estimation_Bill_Library as library
|
||||
from B09_Estimation import B09_Estimation_Sangeun as sg
|
||||
from B09_Estimation.B09_Estimation_Calc_Labor import COPY, COVER_KEYS, with_copies
|
||||
from B09_Estimation.B09_Estimation_Labor_Source import AREA_FILE, daega_inputs
|
||||
from M02_MasterTemplete import M02_Hopyo_Build as hopyo_build
|
||||
from M02_MasterTemplete import M02_Item_Prices as item_prices
|
||||
from M02_MasterTemplete import M02_Labor_Ref as refs
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
@@ -261,11 +260,11 @@ def _subs(root: Path, lines: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
||||
def _carry(lines: list[Any], subs: dict[str, dict[str, Any]], done: dict[str, Any]) -> list[Any]:
|
||||
"""불러온 하위 참조 → 지금 층 새 키(하위 먼저 · 같은 것 한 번 · 앞서 옮긴 것 = 그 키)."""
|
||||
here = refs.here()
|
||||
have = {
|
||||
refs.ref_id(got["복사원본"]): key
|
||||
for key, got, _raw in hopyo_build._origins(store.root())
|
||||
if isinstance(got.get("복사원본"), dict)
|
||||
}
|
||||
have: dict[str, str] = {} # 733-2 — 실무자료뿐 아니라 모든 사본 원본(`copied_from`)
|
||||
for path in sorted((store.root() / KIND).glob(f"{refs.PREFIX[KIND]}-*.json")):
|
||||
got = refs.copied_from(read_json(path))
|
||||
if got is not None:
|
||||
have.setdefault(refs.ref_id(got), path.stem)
|
||||
out = []
|
||||
for one in lines:
|
||||
ref = one.get("참조") if isinstance(one, dict) else None
|
||||
@@ -284,8 +283,32 @@ def _carry(lines: list[Any], subs: dict[str, dict[str, Any]], done: dict[str, An
|
||||
return out
|
||||
|
||||
|
||||
def write(doc: dict[str, Any], overwrite: str | None = None) -> dict[str, Any]:
|
||||
"""지금 층(`store.at` 안)에 씀 — 같은 이름이면 409 · `overwrite` = 같은 이름 그 키를 덮음."""
|
||||
def _ask(kind: str, doc: dict[str, Any], subs: dict, new: bool, use: str | None) -> str | None:
|
||||
"""같은 층 같은 내용(733-2 · `M02_Library_Ask`) — 하위 호표(층 밖 참조) 지문은 굳힌 문서로."""
|
||||
from M02_MasterTemplete import M02_Library_Ask as ask
|
||||
from M02_MasterTemplete.M02_Library_Same import Same
|
||||
|
||||
s = Same()
|
||||
|
||||
def fill(rid: str) -> None:
|
||||
if rid in s.memo or rid not in subs:
|
||||
return
|
||||
sub = {k: v for k, v in subs[rid].items() if k not in ("키", "알약")}
|
||||
for ref in _own(sub.get("담은로직")):
|
||||
fill(refs.ref_id(ref))
|
||||
s.memo[rid] = s.finger(KIND, sub) or f"없음:{rid}"
|
||||
|
||||
for rid in subs:
|
||||
fill(rid)
|
||||
return ask.ask(kind, doc, new, use, s)
|
||||
|
||||
|
||||
def write(
|
||||
doc: dict[str, Any], overwrite: str | None = None, new: bool = False, use: str | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""지금 층(`store.at` 안)에 씀 — 같은 이름이면 409 · `overwrite` = 같은 이름 그 키를 덮음 ·
|
||||
같은 내용(733-2) = 409 `{같은것, 까닭}`(같은 이름도 있으면 `같은이름 · 이름` 함께) →
|
||||
`new` 그래도 새로 · `use` 그 키(새로 안 만듦 · 답 `씀`)."""
|
||||
subs = doc.get(SUBS) or {}
|
||||
doc = {k: v for k, v in doc.items() if k != SUBS}
|
||||
kind = SK_KIND if doc.get("종류") == refs.TITLE[SK_KIND] else KIND
|
||||
@@ -296,8 +319,16 @@ def write(doc: dict[str, Any], overwrite: str | None = None) -> dict[str, Any]:
|
||||
]
|
||||
if overwrite and overwrite not in same:
|
||||
raise store.StoreError(409, f"덮어쓸 「{doc['이름']}」 이 없음 — 다시 누름")
|
||||
if same and not overwrite:
|
||||
raise store.StoreError(409, {"같은이름": same[0], "이름": doc["이름"]})
|
||||
if not overwrite:
|
||||
named = {"같은이름": same[0], "이름": doc["이름"]} if same else {}
|
||||
try:
|
||||
got = _ask(kind, doc, subs, new, use)
|
||||
except store.StoreError as e:
|
||||
raise store.StoreError(e.status, {**e.detail, **named}) from e
|
||||
if got:
|
||||
return {"이름": got, "씀": True}
|
||||
if same:
|
||||
raise store.StoreError(409, named)
|
||||
if subs:
|
||||
doc = {**doc, "담은로직": _carry(doc["담은로직"], subs, {})}
|
||||
if overwrite:
|
||||
|
||||
@@ -511,6 +511,8 @@ class PersonalBody(BaseModel):
|
||||
name: str | None = Field(None, max_length=200)
|
||||
overwrite: str | None = Field(None, max_length=20)
|
||||
user: dict[str, Any] | None = None
|
||||
새로: bool = False # 같은 내용 409 뒤 — 그래도 새로(733-2)
|
||||
씀: str | None = Field(None, max_length=20) # 같은 내용 409 뒤 — 그 키 씀
|
||||
|
||||
|
||||
@router.post("/{project_id}/estimation/daega/personal")
|
||||
@@ -529,7 +531,8 @@ async def save_personal(
|
||||
if not made["문서"]["이름"]:
|
||||
raise HTTPException(status_code=400, detail="이름이 빔")
|
||||
folder = await asyncio.to_thread(_root, session, "personal", None, True)
|
||||
got = await asyncio.to_thread(_call, folder, personal.write, made["문서"], body.overwrite)
|
||||
args = (made["문서"], body.overwrite, body.새로, body.씀)
|
||||
got = await asyncio.to_thread(_call, folder, personal.write, *args)
|
||||
return {
|
||||
"키": got["이름"],
|
||||
"이름": made["문서"]["이름"],
|
||||
|
||||
Reference in New Issue
Block a user