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

78 lines
2.5 KiB
Python
Raw 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]]}