"""M02 담을 로직 읽기 API — `/api/m02/logic-lib/…`(로그인만). ⚠ 등록은 `main.py`(로그인만). 조합 목록 · 키 하나 · 통째 지우기 길은 없앰(732-1). 담을 로직 고르기 · 일위대가 입력 모달이 읽는 단가산출 로직(M01 길은 시스템 관리자 전용)은 `/api/m02/logic-lib/…` 읽기만(로그인) — 모양은 M01 길과 같음. 85-4 — 원문 패널 읽기(`/logic-lib/source` · M01 길과 같은 몸) · 원문 pdf 통째 (`/logic-lib/source-pdf` · 책 이름만 받음 · 경로 안 받음)도 로그인만. 704 — 기준 목록(`/logic-lib/standard`) · 계산서(`/logic-lib/sheet`) 로그인만(`M02_Logic_Standard`). """ from __future__ import annotations import sys from typing import Any from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import Response from pydantic import BaseModel from common_util.common_util_auth import verify_session from common_util.common_util_http_cache import cached_file_response from M01_MasterData import M01_MasterData_Store as m01 from M01_MasterData import M01_MasterData_Store_Make as make from M02_MasterTemplete import M02_Labor_Inputs as labor_inputs from M02_MasterTemplete import M02_Logic_Standard as standard router = APIRouter(prefix="/api/m02", tags=["M02 MasterTemplete Combos"]) if "pytest" not in sys.modules: # 기준 목록을 뒤에서 한 번 셈(저장본이 있으면 읽기만) standard.warm() # ── 담을 로직(읽기만) — M01 `/logics` · `/subs?group=로직` · `/logic` · `/logic/auto` 모양 ── def _read(fn, *args): try: return fn(*args) except m01.StoreError as e: raise HTTPException(status_code=e.status, detail=e.detail) from e @router.get("/logic-lib/logics", dependencies=[Depends(verify_session)]) def get_logics() -> dict: return {"logics": _read(m01.logics, "", "", "", None)} @router.get("/logic-lib/subs", dependencies=[Depends(verify_session)]) def get_logic_subs() -> dict: return _read(m01.subs, "", "로직") @router.get("/logic-lib/logic", dependencies=[Depends(verify_session)]) def get_logic(key: str) -> dict: return _read(m01.logic, key) @router.get("/logic-lib/auto", dependencies=[Depends(verify_session)]) def get_logic_auto(key: str) -> dict: """견본 입력 — 미리 보기용 자동값.""" return _read(m01.auto, key) @router.get("/logic-lib/inputs", dependencies=[Depends(verify_session)]) def get_logic_inputs(keys: str = "") -> dict: """일위대가 입력 모달 — 로직 키들(쉼표)의 입력 목록 + 자동값(`M02_Labor_Inputs`).""" return _read(labor_inputs.logic_inputs, keys.split(",")) @router.get("/logic-lib/standard", dependencies=[Depends(verify_session)]) def get_standard() -> dict: """기준 목록 `{판, 공종, 줄}` — 대표 규격 펼침 · 금액 = M01 엔진(704-1).""" return _read(standard.listing) class SheetBody(BaseModel): key: str 바꿈: dict[str, Any] = {} @router.post("/logic-lib/sheet", dependencies=[Depends(verify_session)]) def post_sheet(body: SheetBody) -> dict: """계산서 한 장 — 노임 × 품 = 금액 줄 · 비목 소계 · 계(704-2 · 저장 안 함).""" return _read(standard.sheet, body.key, body.바꿈) #: 원문 pdf(85-4) — 책 이름 → 파일(쪽 자르기 없음) SOURCE_PDF = { "건설": make.BODY / "건설공사_표준품셈" / "2026년_건설공사_표준품셈.pdf", "산림": make.BODY / "산림_표준품셈" / "첨부" / "(산림청고시 제2025-82호) 산림사업 표준품셈.pdf", } @router.get("/logic-lib/source", dependencies=[Depends(verify_session)]) def get_logic_source(src: str) -> dict: """원문 패널 — 출처 글로 찾은 품셈 본문 절(M01 `/logic/source` 와 같은 몸 · 로그인만).""" return _read(make.source, src) @router.get("/logic-lib/source-pdf", dependencies=[Depends(verify_session)]) def get_source_pdf(request: Request, book: str) -> Response: """원문 pdf 통째 내려받기 — `book` = 건설 | 산림(그 밖 400).""" path = SOURCE_PDF.get(book) if path is None: raise HTTPException(status_code=400, detail="책은 건설 · 산림 중 하나") if not path.is_file(): raise HTTPException(status_code=404, detail="원문 pdf 없음") return cached_file_response(request, path, "application/pdf", filename=path.name)