feat(reports): include workspace thumbnail in pdf exports

This commit is contained in:
2026-04-28 11:38:43 +03:30
parent 315f2ca728
commit c8a118788b
2 changed files with 41 additions and 5 deletions

View File

@@ -418,7 +418,11 @@ def _scope_payload(filters: ReportFilters) -> dict:
} }
return { return {
"workspace": {"id": str(filters.workspace.id), "name": filters.workspace.name}, "workspace": {
"id": str(filters.workspace.id),
"name": filters.workspace.name,
"thumbnail_path": filters.workspace.thumbnail.path if getattr(filters.workspace, "thumbnail", None) else None,
},
"period": filters.period, "period": filters.period,
"from_date": filters.from_date.isoformat(), "from_date": filters.from_date.isoformat(),
"to_date": filters.to_date.isoformat(), "to_date": filters.to_date.isoformat(),

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import io import io
import os
from datetime import datetime from datetime import datetime
from openpyxl import Workbook from openpyxl import Workbook
@@ -12,6 +13,7 @@ from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import mm from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import Image as RLImage
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
from apps.reports.services.export_i18n import ExportLocale, safe_sheet_title, user_label from apps.reports.services.export_i18n import ExportLocale, safe_sheet_title, user_label
@@ -229,6 +231,11 @@ def _paragraph(text: str, style: ParagraphStyle, locale: ExportLocale) -> Paragr
return Paragraph(locale.shape(text), style) return Paragraph(locale.shape(text), style)
def _workspace_initial(name: str) -> str:
stripped = (name or "").strip()
return stripped[0].upper() if stripped else "W"
def _styled_table(data: list[list[str]], *, locale: ExportLocale, column_widths: list[float]) -> Table: def _styled_table(data: list[list[str]], *, locale: ExportLocale, column_widths: list[float]) -> Table:
shaped_data = [ shaped_data = [
[locale.shape(cell) if cell is not None else "" for cell in row] [locale.shape(cell) if cell is not None else "" for cell in row]
@@ -318,10 +325,35 @@ def build_pdf_report(*, report_data: dict, locale: ExportLocale) -> bytes:
scope = report_data["scope"] scope = report_data["scope"]
summary = report_data["summary"] summary = report_data["summary"]
story = [ workspace_name = scope["workspace"]["name"]
_paragraph(f"{locale.t('report_title')} - {scope['workspace']['name']}", title_style, locale), workspace_thumbnail_path = scope["workspace"].get("thumbnail_path")
Spacer(1, 6 * mm), title_text = f"{locale.t('report_title')} - {workspace_name}"
]
title_cell = _paragraph(title_text, title_style, locale)
badge_cell = _paragraph(_workspace_initial(workspace_name), title_style, locale)
if workspace_thumbnail_path and os.path.exists(workspace_thumbnail_path):
try:
badge_cell = RLImage(workspace_thumbnail_path, width=14 * mm, height=14 * mm)
except Exception: # noqa: BLE001
badge_cell = _paragraph(_workspace_initial(workspace_name), title_style, locale)
header_row = [badge_cell, title_cell] if locale.is_rtl else [title_cell, badge_cell]
header_col_widths = [doc.width * 0.08, doc.width * 0.92] if locale.is_rtl else [doc.width * 0.92, doc.width * 0.08]
header_table = Table([header_row], colWidths=header_col_widths)
header_table.setStyle(
TableStyle(
[
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("ALIGN", (0, 0), (-1, -1), "RIGHT" if locale.is_rtl else "LEFT"),
("LEFTPADDING", (0, 0), (-1, -1), 0),
("RIGHTPADDING", (0, 0), (-1, -1), 0),
("TOPPADDING", (0, 0), (-1, -1), 0),
("BOTTOMPADDING", (0, 0), (-1, -1), 0),
]
)
)
story = [header_table, Spacer(1, 6 * mm)]
meta_rows = [ meta_rows = [
[locale.t("workspace"), scope["workspace"]["name"]], [locale.t("workspace"), scope["workspace"]["name"]],