feat(B09): 263-2 사전조합 · 구조물 조합 운반 = 담은 로직 입력 + 거리 값 사본
- 모달 = 담은 로직 이름별 입력(library-inputs) · 거리 칸 거리에서 · 손 값(own) 이김
- 사본 폴더 = 종류@층@주인@키~값해시8 · 같은 값 = 같은 사본 · 다른 거리 = 따로 · 옛 이름 읽힘
- 셈 때 서버가 거리로 사본 다시 고름(resolve_hauls · fix_keys) · [저장] = 바뀐 연결 저장 값에도 · prune
- 연결 {tab dg, key, lib, given, own} 저장 꼴 · 원본 읽기 전 모양 검사
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
This commit is contained in:
@@ -12,7 +12,12 @@
|
||||
POST /api/projects/{id}/estimation/library {kind, layer, owner, key}
|
||||
설계내역서 연결 고르기(204-2) — 서고 구조물조합 · 사전조합을 프로젝트 사본으로
|
||||
(있으면 그대로) → {폴더, 만듦, key = 대가 블록 id, payload} ·
|
||||
층 읽기 권한 = `M02_Layer_Access` · 줄 연결은 화면 캐시 → [저장] 때 안 쓰는 사본 지움(`Bill_Library.prune`)
|
||||
층 읽기 권한 = `M02_Layer_Access` · 줄 연결은 화면 캐시 →
|
||||
[저장] 때 안 쓰는 사본 지움(`Bill_Library.prune`) ·
|
||||
운반공 줄 = {given, own, dist} 같이 → 거리 값 사본(263-2 · 폴더 `~값 해시`)
|
||||
POST /api/projects/{id}/estimation/library-inputs {kind, layer, owner, key, lib?}
|
||||
「운반 단가」 모달(263-2) — 담은 로직 줄 입력 · 값(읽기만 · 권한 = library 길과 같음)
|
||||
운반 사본 연결 = 셈 때마다 거리로 사본 다시 고름(`Bill_Library.resolve_hauls` · `fix_keys`).
|
||||
|
||||
저장 자리 = 프로젝트 안 `B09_Estimation/v1/`(`B09_Estimation_Store`) ·
|
||||
단가 = `B09_Estimation_Prices` ·
|
||||
@@ -134,15 +139,17 @@ def haul_user(rows: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
|
||||
|
||||
def calc_user(root: Path) -> dict[str, Any]:
|
||||
"""셈 · 수요 · 사본 정리용 사용자 값 — 저장 값 + 거리이정표 운반 연결 · 거리(화면엔 안 보냄)."""
|
||||
return {**store.read_user(root), **haul_user(haul_routes(root))}
|
||||
"""셈 · 수요 · 사본 정리용 사용자 값 — 저장 값 + 거리이정표 운반 연결 · 거리(화면엔 안 보냄) ·
|
||||
운반 사본 연결 = 지금 거리의 사본(263-2)."""
|
||||
user = {**store.read_user(root), **haul_user(haul_routes(root))}
|
||||
return library.resolve_hauls(root, user)
|
||||
|
||||
|
||||
async def _demand(root: Path) -> list[str]:
|
||||
"""단가 수요 키 — 연결된 사본 + 설계내역서 손 줄 로직(166-2) +
|
||||
거리이정표 운반 연결(251-5)."""
|
||||
user = await asyncio.to_thread(calc_user, root) # 운반 값 사본 먼저(263-2)
|
||||
keys = await asyncio.to_thread(linked_resource_keys, root)
|
||||
user = await asyncio.to_thread(calc_user, root)
|
||||
hand = await asyncio.to_thread(sangeun.hand_resource_keys, user)
|
||||
return [*keys, *(k for k in hand if k not in keys)]
|
||||
|
||||
@@ -158,11 +165,12 @@ async def payload(project_id: UUID, root: Path) -> dict[str, Any]:
|
||||
book = await asyncio.to_thread(store.read_book, root)
|
||||
inputs = await asyncio.to_thread(prices.build_inputs, book, keys, b08["materials"])
|
||||
hauls = await asyncio.to_thread(haul_routes, root)
|
||||
inputs["bill"] = bill_items({**b08, **haul_user(hauls), "haul_routes": hauls})
|
||||
user = await asyncio.to_thread(store.read_user, root)
|
||||
calc = await asyncio.to_thread(library.resolve_hauls, root, {**user, **haul_user(hauls)})
|
||||
inputs["bill"] = bill_items({**b08, **calc, "haul_routes": hauls})
|
||||
inputs["hopyo"] = hopyo_prices(root)
|
||||
inputs["daega"] = await asyncio.to_thread(daega_inputs, root)
|
||||
user = await asyncio.to_thread(store.read_user, root)
|
||||
calc = {**user, **haul_user(hauls)}
|
||||
library.fix_keys(calc, inputs["daega"].get("libs") or {}) # 263-2 바뀐 사본 = 그 블록
|
||||
sheets, summary = await asyncio.to_thread(compute_twice, root, inputs, calc)
|
||||
if schedule_draft:
|
||||
schedule_draft.attach(inputs, sheets, user)
|
||||
@@ -191,7 +199,11 @@ async def estimation(project_id: UUID) -> dict[str, Any]:
|
||||
async def save_estimation(project_id: UUID, body: dict[str, Any] = Body(...)) -> dict[str, Any]:
|
||||
root = await _project_root(project_id)
|
||||
user = await asyncio.to_thread(store.write_user, root, body.get("user"))
|
||||
calc = {**user, **haul_user(await asyncio.to_thread(haul_routes, root))}
|
||||
calc = await asyncio.to_thread(calc_user, root) # 263-2 운반 값 사본 = 지금 거리
|
||||
if (rows := calc["bill"].get("rows")) != ((user.get("bill") or {}).get("rows") or []):
|
||||
# 바뀐 사본 연결 = 저장 값에도(응답 user → 화면 캐시 · 다음 [저장]이 옛 lib 안 씀)
|
||||
bill = {**user["bill"], "rows": rows}
|
||||
await asyncio.to_thread(store.write_user, root, {**user, "bill": bill})
|
||||
await asyncio.to_thread(library.prune, root, calc) # 204-2 줄이 안 잇는 서고 사본
|
||||
keys = await _demand(root)
|
||||
book = await asyncio.to_thread(store.read_book, root)
|
||||
@@ -251,6 +263,11 @@ class LibraryBody(BaseModel):
|
||||
layer: str
|
||||
owner: str | None = None
|
||||
key: str
|
||||
# 263-2 운반공 줄 — 손 값 {줄 id: {입력: 값}} · 덮은 칸 · 그 행 거리 · 있는 사본
|
||||
given: dict[str, Any] | None = None
|
||||
own: list[str] | None = None
|
||||
dist: dict[str, Any] | None = None
|
||||
lib: str | None = None
|
||||
|
||||
|
||||
@router.post("/{project_id}/estimation/library")
|
||||
@@ -261,7 +278,14 @@ async def import_library(
|
||||
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)
|
||||
library.import_copy,
|
||||
root,
|
||||
body.kind,
|
||||
got.layer,
|
||||
got.owner,
|
||||
body.key,
|
||||
importer(session),
|
||||
{"given": body.given, "own": body.own, "dist": body.dist, "lib": body.lib},
|
||||
)
|
||||
except LookupError as error:
|
||||
raise HTTPException(status_code=404, detail=str(error)) from error
|
||||
@@ -272,5 +296,22 @@ async def import_library(
|
||||
return {**made, "key": key, "payload": out}
|
||||
|
||||
|
||||
@router.post("/{project_id}/estimation/library-inputs")
|
||||
async def library_inputs(
|
||||
project_id: UUID, body: LibraryBody, session: dict[str, Any] = Depends(verify_session)
|
||||
) -> dict[str, Any]:
|
||||
got = access.grant(session, body.layer, body.owner)
|
||||
root = await _project_root(project_id)
|
||||
try:
|
||||
lines = await asyncio.to_thread(
|
||||
library.library_inputs, root, body.kind, got.layer, got.owner, body.key, body.lib
|
||||
)
|
||||
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
|
||||
return {"lines": lines}
|
||||
|
||||
|
||||
# 166-4 견적서 파일 길 — 같은 머리 · 같은 권한
|
||||
router.include_router(quotes_router)
|
||||
|
||||
Reference in New Issue
Block a user