summaryrefslogtreecommitdiff
path: root/prediction_report_service.py
diff options
context:
space:
mode:
Diffstat (limited to 'prediction_report_service.py')
-rw-r--r--prediction_report_service.py158
1 files changed, 158 insertions, 0 deletions
diff --git a/prediction_report_service.py b/prediction_report_service.py
new file mode 100644
index 0000000..b7e3620
--- /dev/null
+++ b/prediction_report_service.py
@@ -0,0 +1,158 @@
+from datetime import datetime
+from typing import List
+
+from PyQt5.QtGui import QTextDocument
+from PyQt5.QtPrintSupport import QPrinter
+
+from calendar_manager import CalendarManager
+from prediction_controller import PredictionController
+from date_service import DateService
+
+
+class PredictionReportService:
+ """Service to export the current prediction and entries into a PDF report."""
+
+ @staticmethod
+ def export_pdf(calendar_manager: CalendarManager,
+ prediction_controller: PredictionController,
+ out_path: str,
+ dateformat: str = "dd.MM.yyyy") -> bool:
+ try:
+ # Gather data
+ launch_dt = prediction_controller.get_launch_date()
+ duration = prediction_controller.get_duration()
+ prediction_dt = prediction_controller.get_prediction()
+ entries = calendar_manager.list_entries()
+
+ # Format helpers
+ def fmt_date(dt):
+ return DateService.format_date_for_display(dt, dateformat) if dt else ""
+
+ launch_str = fmt_date(launch_dt)
+ duration_str = f"{duration.years} Jahre" if duration and hasattr(duration, 'years') else ""
+ prediction_str = fmt_date(prediction_dt)
+
+ # Sum time_periods (months and days separately)
+ total_months = 0
+ total_days = 0
+ for e in entries:
+ tp = getattr(e, 'time_period', None)
+ if not tp:
+ continue
+ try:
+ parts = tp.split()
+ if len(parts) >= 2:
+ value = int(parts[0])
+ unit = parts[1].lower()
+ if value > 0:
+ if 'monat' in unit:
+ total_months += value
+ elif 'tag' in unit:
+ total_days += value
+ except Exception:
+ # Ignore unparsable time_periods
+ pass
+
+ sum_parts = []
+ if total_months > 0:
+ sum_parts.append(f"{total_months} Monate")
+ if total_days > 0:
+ sum_parts.append(f"{total_days} Tage")
+ sum_str = ", ".join(sum_parts) if sum_parts else "0"
+
+ # Build HTML
+ created_stamp = datetime.now().strftime('%d.%m.%Y %H:%M:%S')
+ html = []
+ html.append("<html><head><meta charset='utf-8'>")
+ html.append("""
+ <style>
+ body { font-family: Arial, sans-serif; color: #222; }
+ h1 { font-size: 20px; margin-bottom: 6px; }
+ .meta { margin-bottom: 12px; }
+ .meta div { margin: 2px 0; }
+ table { border-collapse: collapse; width: 100%; }
+ th, td { border: 1px solid #e1e4ee; padding: 4px 6px; vertical-align: top; font-size: 150px; line-height: 1.3; }
+ th { background: #f5f7fb; text-align: left; }
+ tfoot td { font-weight: bold; }
+ .stamp { margin-top: 16px; font-size: 10px; color: #666; }
+ </style>
+ """)
+ html.append("</head><body>")
+ html.append("<h1>Ausfallzeitenrechner — Bericht</h1>")
+ html.append("<div class='meta'>")
+ html.append(f"<div><strong>Promotionsdatum:</strong> {launch_str}</div>")
+ html.append(f"<div><strong>Bewerbungszeitraum:</strong> {duration_str}</div>")
+ html.append(f"<div><strong>Bewerbungsfrist:</strong> {prediction_str}</div>")
+ html.append("</div>")
+
+ # Table header
+ html.append("<table>")
+ html.append(
+ "<thead><tr>"
+ "<th>Beginn</th>"
+ "<th>Ende</th>"
+ "<th>Art</th>"
+ "<th>Kommentar</th>"
+ "<th>Beginn Anrechnung</th>"
+ "<th>Ende Anrechnung</th>"
+ "<th>Anrechnungszeitraum</th>"
+ "</tr></thead><tbody>"
+ )
+
+ # Rows
+ for e in entries:
+ start_text = fmt_date(e.start_date)
+ end_text = fmt_date(e.end_date)
+ keyword_text = e.keyword
+ commentary_text = getattr(e, 'commentary', '') or ''
+ c_start_text = fmt_date(getattr(e, 'corrected_start_date', None))
+ c_end_text = fmt_date(getattr(e, 'corrected_end_date', None))
+ time_text = getattr(e, 'time_period', '') or ''
+
+ # Escape
+ def esc(s: str) -> str:
+ return (s.replace('&', '&amp;')
+ .replace('<', '&lt;')
+ .replace('>', '&gt;'))
+
+ html.append(
+ f"<tr><td>{esc(start_text)}</td>"
+ f"<td>{esc(end_text)}</td>"
+ f"<td>{esc(keyword_text)}</td>"
+ f"<td>{esc(commentary_text)}</td>"
+ f"<td>{esc(c_start_text)}</td>"
+ f"<td>{esc(c_end_text)}</td>"
+ f"<td>{esc(time_text)}</td></tr>"
+ )
+
+ html.append("</tbody>")
+ html.append(f"<tfoot><tr><td colspan='7'>Summe Anrechnungszeitraum: {sum_str}</td></tr></tfoot>")
+ html.append("</table>")
+
+ html.append(f"<div class='stamp'>Erstellt am: {created_stamp}</div>")
+ html.append("</body></html>")
+
+ # Ensure extension
+ if not out_path.lower().endswith('.pdf'):
+ out_path = out_path + '.pdf'
+
+ # Render HTML to PDF
+ printer = QPrinter(QPrinter.HighResolution)
+ printer.setOutputFormat(QPrinter.PdfFormat)
+ printer.setOutputFileName(out_path)
+ # Try to set margins (not all bindings support Millimeter overload)
+ try:
+ printer.setPageMargins(12, 12, 12, 12, QPrinter.Millimeter)
+ except Exception:
+ pass
+
+ doc = QTextDocument()
+ doc.setHtml("".join(html))
+ doc.print_(printer)
+
+ return True
+ except Exception as e:
+ print(f"Error exporting PDF: {e}")
+ return False
+
+