from datetime import datetime from pathlib import Path from types import SimpleNamespace from jinja2 import Environment, FileSystemLoader, select_autoescape from ..summary import YearView from .charts import change_bars, grouped_bars from .i18n import T TEMPLATES = Path(__file__).parent / "templates" env = Environment(loader=FileSystemLoader(TEMPLATES), autoescape=select_autoescape(["html"])) CSS = (TEMPLATES / "report.css").read_text() def _exported() -> str: return datetime.now().strftime("%Y-%m-%d %H:%M") def cost_report_html(view: YearView, lang: str, site: str | None = None, screen: bool = True) -> str: t = T(lang, view.year.year, view.year.department.name) cost_cats = view.with_lines("cost") cats = [] for cv in cost_cats: rows = [(lv.line.name, float(lv.figures.prior), float(lv.figures.adjusted)) for lv in cv.lines] cats.append(SimpleNamespace( name=cv.name(lang), count=len(cv.lines), totals=cv.totals, chart=grouped_bars(rows, t.short_eur, lambda v: t.eur(v, 0)))) overview = grouped_bars([(c.name, float(c.totals.prior), float(c.totals.adjusted)) for c in cats], t.short_eur) ranked = sorted([c for c in cats if c.totals.change_pct is not None], key=lambda c: c.totals.change_pct, reverse=True) change = change_bars([(c.name, float(c.totals.change_pct)) for c in ranked], lambda v: t.pct(v)) return env.get_template("cost_report.html").render( t=t, title=t("cost_report_title"), year=view.year, site=site, cats=cats, costs=view.costs, overview_chart=overview, change_chart=change, exported=_exported(), css=CSS, screen=screen) def budget_html(view: YearView, lang: str, site: str | None = None, include_empty: bool = False) -> str: t = T(lang, view.year.year, view.year.department.name) cats = [SimpleNamespace(name=cv.name(lang), category=cv.category, lines=cv.lines, totals=cv.totals) for cv in view.categories if cv.lines or include_empty] # revenue first, as in the Budget IT sheet cats.sort(key=lambda c: 0 if c.category.section == "revenue" else 1) return env.get_template("budget.html").render( t=t, title=t("budget_title"), year=view.year, site=site, cats=cats, costs=view.costs, exported=_exported(), css=CSS) def to_pdf(html: str) -> bytes: from weasyprint import HTML # imported lazily: it loads system libraries return HTML(string=html).write_pdf()