Index: main/waeup.uniben/trunk/src/waeup/uniben/browser/viewlets.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/browser/viewlets.py	(revision 16100)
+++ main/waeup.uniben/trunk/src/waeup/uniben/browser/viewlets.py	(revision 16100)
@@ -0,0 +1,47 @@
+## $Id: viewlets.py 15424 2019-05-24 10:13:52Z henrik $
+##
+## Copyright (C) 2015 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+import grok
+from waeup.kofa.interfaces import IKofaObject, academic_sessions_vocab
+from waeup.kofa.browser.viewlets import (
+    PrimaryNavTab, ManageActionButton, UpdateScoresActionButton,
+    DownloadCSVFileActionButton, DownloadTicketOverviewActionButton)
+from waeup.uniben.interfaces import MessageFactory as _
+
+grok.context(IKofaObject)
+
+class RequestTranscriptTab(PrimaryNavTab):
+    """Request Transcript tab in primary navigation.
+
+    Display tab only for anonymous. 
+    """
+    grok.order(4)
+    grok.require('waeup.Anonymous')
+    tab_title = _(u'Request Transcript')
+    pnav = 6
+
+    # Also zope.manager has role Anonymous.
+    # To avoid displaying this tab, we have to check the principal id too.
+    @property
+    def link_target(self):
+        if self.request.principal.id == 'zope.anybody':
+            #if 'alumni' not in self.view.application_url():
+            #    return
+            return 'https://uniben-alumni.waeup.org/documents/transcript/display'
+        return
+
Index: main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py	(revision 16099)
+++ main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py	(revision 16100)
@@ -465,4 +465,149 @@
         return None
 
+    def renderPDFTranscript(self, view, filename='transcript.pdf',
+                  student=None,
+                  studentview=None,
+                  note=None,
+                  signatures=(),
+                  sigs_in_footer=(),
+                  digital_sigs=(),
+                  show_scans=True, topMargin=1.5,
+                  omit_fields=(),
+                  tableheader=None,
+                  no_passport=False,
+                  save_file=False):
+        """Render pdf slip of a transcripts.
+        """
+        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
+        # XXX: tell what the different parameters mean
+        style = getSampleStyleSheet()
+        creator = self.getPDFCreator(student)
+        data = []
+        doc_title = view.label
+        author = '%s (%s)' % (view.request.principal.title,
+                              view.request.principal.id)
+        footer_text = view.label.split('\n')
+        if len(footer_text) > 2:
+            # We can add a department in first line
+            footer_text = footer_text[1]
+        else:
+            # Only the first line is used for the footer
+            footer_text = footer_text[0]
+        if getattr(student, 'student_id', None) is not None:
+            footer_text = "%s - %s - " % (student.student_id, footer_text)
+
+        # Insert student data table
+        if student is not None:
+            #bd_translation = trans(_('Base Data'), portal_language)
+            #data.append(Paragraph(bd_translation, HEADING_STYLE))
+            data.append(render_student_data(
+                studentview, view.context,
+                omit_fields, lang=portal_language,
+                slipname=filename,
+                no_passport=no_passport))
+
+        transcript_data = view.context.getTranscriptData()
+        levels_data = transcript_data[0]
+
+        contextdata = []
+        f_label = trans(_('Course of Study:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(view.context.certificate.longtitle)
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Faculty:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(
+            view.context.certificate.__parent__.__parent__.__parent__.longtitle)
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Department:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(
+            view.context.certificate.__parent__.__parent__.longtitle)
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Entry Session:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(
+            view.session_dict.get(view.context.entry_session))
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Final Session:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(
+            view.session_dict.get(view.context.current_session))
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Entry Mode:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(view.studymode_dict.get(
+            view.context.entry_mode))
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Final Verdict:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        f_text = formatted_text(view.studymode_dict.get(
+            view.context.current_verdict))
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        f_label = trans(_('Cumulative GPA:'), portal_language)
+        f_label = Paragraph(f_label, ENTRY1_STYLE)
+        format_float = getUtility(IKofaUtils).format_float
+        cgpa = format_float(transcript_data[1], 3)
+        if student.state == GRADUATED:
+            f_text = formatted_text('%s (%s)' % (
+                cgpa, self.getClassFromCGPA(transcript_data[1], student)[1]))
+        else:
+            f_text = formatted_text('%s' % cgpa)
+        f_text = Paragraph(f_text, ENTRY1_STYLE)
+        contextdata.append([f_label,f_text])
+
+        contexttable = Table(contextdata,style=SLIP_STYLE)
+        data.append(contexttable)
+
+        transcripttables = render_transcript_data(
+            view, tableheader, levels_data, lang=portal_language)
+        data.extend(transcripttables)
+
+        # Insert signatures
+        # XXX: We are using only sigs_in_footer in waeup.kofa, so we
+        # do not have a test for the following lines.
+        if signatures and not sigs_in_footer:
+            data.append(Spacer(1, 20))
+            # Render one signature table per signature to
+            # get date and signature in line.
+            for signature in signatures:
+                signaturetables = get_signature_tables(signature)
+                data.append(signaturetables[0])
+
+        # Insert digital signatures
+        if digital_sigs:
+            data.append(Spacer(1, 20))
+            sigs = digital_sigs.split('\n')
+            for sig in sigs:
+                data.append(Paragraph(sig, NOTE_STYLE))
+
+        view.response.setHeader(
+            'Content-Type', 'application/pdf')
+        try:
+            pdf_stream = creator.create_pdf(
+                data, None, doc_title, author=author, footer=footer_text,
+                note=note, sigs_in_footer=sigs_in_footer, topMargin=topMargin)
+        except IOError:
+            view.flash(_('Error in image file.'))
+            return view.redirect(view.url(view.context))
+        if save_file:
+            self._saveTranscriptPDF(student, pdf_stream)
+            return
+        return pdf_stream
+
     #: A tuple containing the names of registration states in which changing of
     #: passport pictures is allowed.
