Source code for fsi.pdf

from datetime import date
from io import BytesIO
from operator import itemgetter
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.units import cm
from sedate import utcnow

from onegov.fsi import _
from onegov.pdf import Pdf, page_fn_footer, page_fn_header_and_footer


from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
    from collections.abc import Callable
    from onegov.fsi.collections.audit import AuditCollection
    from onegov.fsi.collections.subscription import SubscriptionsCollection
    from onegov.fsi.models import CourseSubscription
    from onegov.fsi.layout import DefaultLayout
    from onegov.fsi.layouts.audit import AuditLayout
    from onegov.pdf.templates import Template
    from reportlab.lib.colors import Color
    from reportlab.pdfgen.canvas import Canvas


[docs] class FsiPdf(Pdf):
[docs] previous_level_context: int | None = None
@property
[docs] def page_fn(self) -> 'Callable[[Canvas, Template], None]': return page_fn_footer
@property
[docs] def page_fn_later(self) -> 'Callable[[Canvas, Template], None]': return page_fn_header_and_footer
@property
[docs] def table_style(self) -> list[tuple[Any, ...]]: return [ ('GRID', (0, 0), (-1, -1), 0.5, colors.black), ('ALIGN', (1, 0), (-1, -1), 'CENTER'), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE') ]
@classmethod
[docs] def from_subscriptions( cls, collection: 'SubscriptionsCollection', layout: 'DefaultLayout', title: str ) -> BytesIO: chosen_event = layout.model.course_event translate = layout.request.translate result = BytesIO() pdf = cls( result, title=title, created=f'{date.today():%d.%m.%Y}', ) pdf.init_a4_portrait( page_fn=pdf.page_fn, page_fn_later=pdf.page_fn_later ) pdf.h(title) pdf.p(f"{translate(_('Printed'))} " f"{layout.format_date(utcnow(), 'date')}") pdf.spacer() def get_headers() -> list[str]: headers = ['Attendee', 'Shortcode'] if not chosen_event: headers.append('Course Name') headers.append('Date') headers += ['Course Status', 'Course attended', 'Last info mail'] return [translate(_(h)) for h in headers] def get_row(subscription: 'CourseSubscription') -> list[str]: row = [str(subscription)] att = subscription.attendee row.append(att and att.source_id or '') if not chosen_event: event = subscription.course_event row.append(event.name) row.append( layout.format_date(event.start, 'datetime') ) sent = event.info_template.last_sent else: sent = chosen_event.info_template.last_sent row.append( translate(layout.format_status( chosen_event.status if chosen_event else event.status)) ) row.append('✔' if subscription.event_completed else '-') row.append(layout.format_date(sent, 'date') if sent else '') return row data = sorted( (get_row(subs) for subs in collection.query()), key=itemgetter(0) ) data.insert(0, get_headers()) pdf.table( data, columns='even', style=pdf.table_style, ) pdf.generate() result.seek(0) return result
@classmethod
[docs] def from_audit_collection( cls, collection: 'AuditCollection', layout: 'AuditLayout', title: str ) -> BytesIO: now = utcnow() request = layout.request assert collection.course is not None refresh_interval = collection.course.refresh_interval result = BytesIO() pdf = cls( result, title=title, created=f'{date.today():%d.%m.%Y}', ) pdf.init_a4_portrait( page_fn=pdf.page_fn, page_fn_later=pdf.page_fn_later ) pdf.h(title) filter_str = '' if collection.organisations: orgs = ', '.join(collection.organisations) org_title = request.translate(_('Organisations')) filter_str = f'{org_title}: {orgs}' if collection.letter: letter_title = request.translate(_('Letter')) letter_title += f' {collection.letter}' if filter_str: filter_str += f'{filter_str}, {letter_title}' else: filter_str = letter_title if filter_str: pdf.h3(filter_str) pdf.p(f"{request.translate(_('Printed'))} " f"{layout.format_date(now, 'date')}") pdf.spacer() data: list[list[Any]] = [layout.audit_table_headers] green = HexColor('#1be45b') orange = HexColor('#f4cb71') red = colors.pink style = pdf.table_style def bgcolor(ix: int, row: int, color: 'Color') -> tuple[Any, ...]: return 'BACKGROUND', (row, ix), (row, ix), color next_subscriptions = collection.next_subscriptions(request) for ix, e in enumerate(collection.query()): dt = layout.next_event_date(e.start, refresh_interval) if dt: if now > dt: next_event_hint = dt.year color = red else: not_so_fine = (dt.year == now.year and e.event_completed) color = orange if not_so_fine else green next_event_hint = dt.year else: next_event_hint = now.year color = red style.append(bgcolor(ix + 1, 4, color)) data_line = [ f'{e.last_name}, {e.first_name}', e.source_id, layout.format_date(e.start, 'datetime'), '✔' if next_subscriptions.get(e[0], None) else '-', next_event_hint ] data.append(data_line) pdf.table( data, columns=[None, None, None, 2.5 * cm, 2.5 * cm], style=style, ) pdf.generate() result.seek(0) return result