feat(B09): 오른쪽 재료 창고 · 지난 공사 일위대가 가져오기(PLAN 703-1)
- 설계내역서 표 오른쪽 서랍(공용 side_panels · 접고 펴기 · 좁은 화면 = 아래) — 찾기 하나 + 출처 탭 이 공사 · 내 것 · 회사 · 품셈(704-1 기준 목록 · 우클릭 계산서 보기) · 지난 공사 - 두 번 누름 · Enter = 고른 내역 줄에 단가연결 · 끌어 놓기 = 놓은 줄 · 연결 = 단가연결 모달과 같은 길(702-3 즉시 금액) - 품셈 = 넣을 값 창에 계산서 입력 전부(목록 바꿈은 기본과 다른 것만 — 석축헐기 뒷길이 60 이 0 으로 열리던 것) - 서버 B09_Estimation_Past + GET/POST /estimation/past — 같은 회사 다른 공사 구조물 사본 · 서고 사본 → 이 공사 서고 사본(폴더 통째 · 가져온곳 · 덮개째 · 단가 = 이 공사 책) · 남의 회사 403 - 표 높이 셈(spaceBelow)이 뒤 형제만 보므로 서랍 = DOM 앞 · CSS order 로 오른쪽 - 시험 test_703_1 6 · 셸 꼴 글 시험 200-2 · 202-1 = 표 칸 + 서랍 꼴로 고침(낡은 글) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,12 @@
|
||||
「내 자료집에 저장」(703-2) — 펼친 일위대가 → 개인 층 사전조합
|
||||
(`B09_Estimation_Daega_Personal`) · user = 화면 캐시 덮개 ·
|
||||
같은 이름 = 409 {같은이름} → 덮어쓰기(overwrite = 키) · 새 이름
|
||||
GET /api/projects/{id}/estimation/past
|
||||
재료 창고 「지난 공사」(703-1) — 같은 회사 다른 공사의 일위대가 목록(`B09_Estimation_Past`)
|
||||
POST /api/projects/{id}/estimation/past {project_id, cover}
|
||||
지난 공사 일위대가 → 이 공사 서고 사본(덮개째) → {폴더, 만듦, key, cover, 덮개, payload} ·
|
||||
덮개 = 그 공사 저장 칸(화면 캐시 cover 가 비었을 때만 얹음 · 같은 꼴 블록이 먼저 있으면 빈 것) ·
|
||||
같은 회사만(남의 회사 403)
|
||||
운반 사본 연결 = 셈 때마다 거리로 사본 다시 고름(`Bill_Library.resolve_hauls` · `fix_keys`).
|
||||
|
||||
저장 자리 = 프로젝트 안 `B09_Estimation/v1/`(`B09_Estimation_Store`) ·
|
||||
@@ -66,6 +72,7 @@ from B08_Quantity.B08_Quantity_Router_Milestone import read_data as read_milesto
|
||||
from B08_Quantity.B08_Quantity_Router_Milestone import site_info
|
||||
from B09_Estimation import B09_Estimation_Bill_Library as library
|
||||
from B09_Estimation import B09_Estimation_Daega_Personal as personal
|
||||
from B09_Estimation import B09_Estimation_Past as past
|
||||
from B09_Estimation import B09_Estimation_Prices as prices
|
||||
from B09_Estimation import B09_Estimation_Refresh as refresh
|
||||
from B09_Estimation import B09_Estimation_Sangeun as sangeun
|
||||
@@ -82,10 +89,12 @@ 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 common_util.common_util_project_settings import reset_section
|
||||
from common_util.common_util_storage import resolve_stored_project_path
|
||||
from common_util.common_util_workflow_state import mark_stage
|
||||
from M02_MasterTemplete import M02_Layer_Access as access
|
||||
from M02_MasterTemplete.M02_Item_Snapshot import importer
|
||||
from M02_MasterTemplete.M02_MasterTemplete_Router_Items import _call, _root
|
||||
from M02_MasterTemplete.M02_MasterTemplete_Router_Layers import _company_projects, _project
|
||||
|
||||
try: # 252 공기 초안(draft 폴더 · 지우면 공기 탭 원천 없이)
|
||||
from B09_Estimation.draft import B09_Draft_Schedule_Source as schedule_draft
|
||||
@@ -488,6 +497,63 @@ async def save_personal(
|
||||
}
|
||||
|
||||
|
||||
def _past_rows(projects: list[dict[str, Any]], here: str) -> list[dict[str, Any]]:
|
||||
out = []
|
||||
for other in projects:
|
||||
if other["project_id"] == here or not other.get("storage_path"):
|
||||
continue
|
||||
try:
|
||||
rows = past.rows_of(Path(resolve_stored_project_path(other["storage_path"])))
|
||||
except (ValueError, OSError): # 못 읽는 공사 = 건너뜀
|
||||
continue
|
||||
ref = {"project_id": other["project_id"], "project": other["name"]}
|
||||
out += [{**ref, **row} for row in rows]
|
||||
return out
|
||||
|
||||
|
||||
@router.get("/{project_id}/estimation/past")
|
||||
async def past_list(
|
||||
project_id: UUID, session: dict[str, Any] = Depends(verify_session)
|
||||
) -> dict[str, Any]:
|
||||
here = await _project(session, str(project_id))
|
||||
projects = await _company_projects(int(here["company_id"]))
|
||||
return {"rows": await asyncio.to_thread(_past_rows, projects, str(project_id))}
|
||||
|
||||
|
||||
class PastBody(BaseModel):
|
||||
project_id: str = Field(min_length=1, max_length=64)
|
||||
cover: str = Field(min_length=3, max_length=200)
|
||||
|
||||
|
||||
@router.post("/{project_id}/estimation/past")
|
||||
async def past_import(
|
||||
project_id: UUID, body: PastBody, session: dict[str, Any] = Depends(verify_session)
|
||||
) -> dict[str, Any]:
|
||||
here = await _project(session, str(project_id))
|
||||
if body.project_id == str(project_id):
|
||||
raise HTTPException(status_code=400, detail="이 공사 것은 「이 공사」 탭에서 고름")
|
||||
other = await _project(session, body.project_id)
|
||||
if other["company_id"] != here["company_id"]:
|
||||
raise HTTPException(status_code=403, detail="같은 회사 공사에서만 가져옴")
|
||||
ref = {"project_id": body.project_id, "프로젝트": other.get("name")}
|
||||
try:
|
||||
made = await asyncio.to_thread(
|
||||
past.import_past, here["root"], other["root"], ref, body.cover, 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, here["root"])
|
||||
daega = out["inputs"].get("daega") or {}
|
||||
key = (daega.get("libs") or {}).get(made["폴더"])
|
||||
# 같은 꼴 블록이 이 공사에 먼저 있으면 그 블록(다른 cover) — 덮개 안 옮김(그 블록 덮개 그대로)
|
||||
cover = next((b["cover"] for b in daega.get("blocks") or [] if b["id"] == key), None)
|
||||
if cover != made.pop("덮개자리"):
|
||||
made["덮개"] = {}
|
||||
return {**made, "key": key, "cover": cover, "payload": out}
|
||||
|
||||
|
||||
# 166-4 견적서 파일 길 — 같은 머리 · 같은 권한
|
||||
router.include_router(quotes_router)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user