71 lines
2.1 KiB
Python
71 lines
2.1 KiB
Python
"""Shared authoritative PDF-report service for Flask and MCP adapters."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from pdf_report import (
|
|
report_from_calculation_result,
|
|
render_roll_report,
|
|
safe_report_filename,
|
|
)
|
|
from roll_calculation import calculate_roll
|
|
|
|
|
|
UNKNOWN_BUILD_INFO = {
|
|
"version": "unknown",
|
|
"branch": "unknown",
|
|
"commit": "unknown",
|
|
"timestamp": "unknown",
|
|
}
|
|
|
|
|
|
def create_roll_calculation_pdf(
|
|
calculation_request: Any,
|
|
*,
|
|
build_info: dict[str, str],
|
|
) -> tuple[bytes, str, dict[str, Any]]:
|
|
"""Recalculate one request and render the established RollCalc PDF."""
|
|
result = calculate_roll(calculation_request, build_info=build_info)
|
|
pdf, filename = create_roll_calculation_pdf_from_result(
|
|
result,
|
|
build_info=build_info,
|
|
)
|
|
return pdf, filename, result
|
|
|
|
|
|
def create_roll_calculation_pdf_from_result(
|
|
result: dict[str, Any],
|
|
*,
|
|
build_info: dict[str, str],
|
|
) -> tuple[bytes, str]:
|
|
"""Render an already-authoritative calculation result using the shared path."""
|
|
report = report_from_calculation_result(result)
|
|
generated_at = datetime.now().astimezone()
|
|
pdf = render_roll_report(
|
|
report,
|
|
generated_at=generated_at,
|
|
build_info=build_info,
|
|
)
|
|
article_number = report["article"]["number"] if report["article"] else None
|
|
return pdf, safe_report_filename(article_number, generated_at)
|
|
|
|
|
|
def load_report_build_info(path: str = "build_info.json") -> dict[str, str]:
|
|
"""Load the same optional build metadata shown by Flask-generated reports."""
|
|
try:
|
|
raw = json.loads(Path(path).read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError):
|
|
return UNKNOWN_BUILD_INFO.copy()
|
|
if not isinstance(raw, dict):
|
|
return UNKNOWN_BUILD_INFO.copy()
|
|
build_info = UNKNOWN_BUILD_INFO.copy()
|
|
for key in build_info:
|
|
value = raw.get(key)
|
|
if isinstance(value, str) and value.strip():
|
|
build_info[key] = value.strip()
|
|
return build_info
|