feat(B09): 설계내역서 연결 고르기 서고 구조물조합 · 일위대가 사전조합 — 프로젝트 사본 들여와 새 호표 · 같은 것 재사용 · 저장 때 안 쓰는 사본 정리 (204-2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
This commit is contained in:
2026-10-10 14:39:12 +09:00
co-authored by Claude Opus 5.5
parent 694ca5fee3
commit 49b3e79c2a
10 changed files with 558 additions and 31 deletions
+38 -2
View File
@@ -6,6 +6,10 @@
[저장] — 사용자 값 · 책에 없는 새 단가 줄만 굳힘 → 서버가 정본으로 다시 셈
POST /api/projects/{id}/estimation/prices
[단가 갱신] — 수요 단가 전부를 지금 M01 값으로 새로 굳힘
POST /api/projects/{id}/estimation/library {kind, layer, owner, key}
설계내역서 연결 고르기(204-2) — 서고 구조물조합 · 사전조합을 프로젝트 사본으로
(있으면 그대로) → {폴더, 만듦, key = 대가 블록 id, payload} ·
층 읽기 권한 = `M02_Layer_Access` · 줄 연결은 화면 캐시 → [저장] 때 안 쓰는 사본 지움(`Bill_Library.prune`)
저장 자리 = 프로젝트 안 `B09_Estimation/v1/`(`B09_Estimation_Store`) ·
단가 = `B09_Estimation_Prices` ·
@@ -20,11 +24,13 @@ from pathlib import Path
from typing import Any
from uuid import UUID
from fastapi import APIRouter, Body
from fastapi import APIRouter, Body, Depends, HTTPException
from pydantic import BaseModel
from B08_Quantity.B08_Quantity_Router_Earthwork import earthwork_table
from B08_Quantity.B08_Quantity_Router_Hydro import _project_root
from B08_Quantity.B08_Quantity_Router_Material import material_sheets
from B09_Estimation import B09_Estimation_Bill_Library as library
from B09_Estimation import B09_Estimation_Prices as prices
from B09_Estimation import B09_Estimation_Sangeun as sangeun
from B09_Estimation import B09_Estimation_Store as store
@@ -38,6 +44,9 @@ from B09_Estimation.B09_Estimation_Linked import linked_resource_keys
from B09_Estimation.B09_Estimation_Rates import rate_candidates, rate_table
from B09_Estimation.B09_Estimation_Router_Quotes import router as quotes_router
from B09_Estimation.B09_Estimation_Summary import compute_summary, hopyo_lines, used_materials
from common_util.common_util_auth import verify_session
from M02_MasterTemplete import M02_Layer_Access as access
from M02_MasterTemplete.M02_Item_Snapshot import importer
router = APIRouter(prefix="/api/projects", tags=["B09 Estimation"])
@@ -139,7 +148,8 @@ async def estimation(project_id: UUID) -> dict[str, Any]:
@router.put("/{project_id}/estimation")
async def save_estimation(project_id: UUID, body: dict[str, Any] = Body(...)) -> dict[str, Any]:
root = await _project_root(project_id)
await asyncio.to_thread(store.write_user, root, body.get("user"))
user = await asyncio.to_thread(store.write_user, root, body.get("user"))
await asyncio.to_thread(library.prune, root, user) # 204-2 줄이 안 잇는 서고 사본
keys = await _demand(root)
book = await asyncio.to_thread(store.read_book, root)
book = await asyncio.to_thread(prices.extend_book, book, keys)
@@ -156,5 +166,31 @@ async def refresh_prices(project_id: UUID) -> dict[str, Any]:
return await payload(project_id, root)
class LibraryBody(BaseModel):
kind: str
layer: str
owner: str | None = None
key: str
@router.post("/{project_id}/estimation/library")
async def import_library(
project_id: UUID, body: LibraryBody, session: dict[str, Any] = Depends(verify_session)
) -> dict[str, Any]:
got = access.grant(session, body.layer, body.owner) # 못 읽는 층 = 403 · 회사 없음 = 409
root = await _project_root(project_id)
try:
made = await asyncio.to_thread(
library.import_copy, root, body.kind, got.layer, got.owner, body.key, importer(session)
)
except LookupError as error:
raise HTTPException(status_code=404, detail=str(error)) from error
except ValueError as error:
raise HTTPException(status_code=400, detail=str(error)) from error
out = await payload(project_id, root)
key = ((out["inputs"].get("daega") or {}).get("libs") or {}).get(made["폴더"])
return {**made, "key": key, "payload": out}
# 166-4 견적서 파일 길 — 같은 머리 · 같은 권한
router.include_router(quotes_router)