Files
Aislo/tools/stmate-test/api_report.py

78 lines
2.5 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""보고서 내보내기 끼워 넣기 (api_report.py) — 시트 모형 → 엑셀 · CSV · 조달청 XML 검증.
근거: 지식DB STmate/old/20_분석 19 §3 · 20 §3 · 30(조달청 XSD).
시트 모형은 화면(scr_report.js)이 report_*.js 로 만들어 보냄 — 계산은 브라우저 엔진과 같은 코드.
"""
from __future__ import annotations
import pathlib
import urllib.parse
from fastapi import APIRouter, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from report_xlsx import build_csv, build_report_xlsx
HERE = pathlib.Path(__file__).resolve().parent
XSD = (
HERE.parent.parent
/ "resources/knowledge/original/경쟁사 프로그램/STmate/old/30_원자료/조달청_공사원가호환규정.xsd"
)
router = APIRouter()
class ReportReq(BaseModel):
sheets: list[dict] = []
filename: str = "STMATE_보고서.xlsx"
formulas: bool = False # 엑셀 수식 넣기(Prn_FMLA_INFO)
print: dict = {} # 인쇄 메뉴 옵션 — font · size · orient
class XmlReq(BaseModel):
xml: str
def _disposition(name: str) -> str:
return f"attachment; filename*=UTF-8''{urllib.parse.quote(name)}"
@router.post("/api/report/xlsx")
def api_report_xlsx(req: ReportReq):
if not req.sheets:
raise HTTPException(status_code=400, detail="시트 모형 없음")
return Response(
content=build_report_xlsx(req.sheets, req.formulas, req.print),
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": _disposition(req.filename)},
)
@router.post("/api/report/csv")
def api_report_csv(req: ReportReq):
if not req.sheets:
raise HTTPException(status_code=400, detail="시트 모형 없음")
body = "" + build_csv(req.sheets[0])
name = req.filename if req.filename.endswith(".csv") else req.filename + ".csv"
return Response(
content=body.encode("utf-8"),
media_type="text/csv; charset=utf-8",
headers={"Content-Disposition": _disposition(name)},
)
@router.post("/api/report/validate-pps")
def api_validate_pps(req: XmlReq):
"""조달청 호환규정 XSD(V1.0.5) 검증 — 위반 줄을 돌려줌."""
from lxml import etree
schema = etree.XMLSchema(etree.parse(str(XSD)))
try:
doc = etree.fromstring(req.xml.encode("utf-8"))
except etree.XMLSyntaxError as e:
return {"ok": False, "errors": [str(e)]}
ok = schema.validate(doc)
return {"ok": ok, "errors": [str(e) for e in list(schema.error_log)[:20]]}