source: main/waeup.kofa/trunk/src/waeup/kofa/applicants/pdf.py @ 8084

Last change on this file since 8084 was 8059, checked in by uli, 13 years ago

Improve pdf generation: a global pdf generator, watermarks and more.

  • Property svn:keywords set to Id
File size: 9.3 KB
Line 
1## $Id: pdf.py 8059 2012-04-07 08:15:16Z uli $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Generate PDF docs for applicants.
20"""
21import grok
22from reportlab.lib.styles import getSampleStyleSheet
23from reportlab.lib.units import cm
24from reportlab.platypus import Paragraph, Image, Table, Spacer
25from zope.component import getUtility
26from zope.formlib.form import setUpEditWidgets
27from zope.i18n import translate
28from zope.publisher.browser import TestRequest
29from waeup.kofa.applicants.interfaces import IApplicant, IApplicantsUtils
30from waeup.kofa.browser import DEFAULT_PASSPORT_IMAGE_PATH
31from waeup.kofa.browser.interfaces import IPDFCreator
32from waeup.kofa.interfaces import IExtFileStore, IPDF, IKofaUtils
33from waeup.kofa.interfaces import MessageFactory as _
34from waeup.kofa.widgets.datewidget import FriendlyDateDisplayWidget
35
36class PDFApplicationSlip(grok.Adapter):
37    """Create a PDF application slip for applicants.
38    """
39    # XXX: Many things in here are reusable. We might want to split
40    # things. Possibly move parts to IPDFCreator?
41    grok.context(IApplicant)
42    grok.implements(IPDF)
43    grok.name('application_slip')
44
45    form_fields =  grok.AutoFields(IApplicant).omit(
46        'locked', 'course_admitted')
47    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
48
49    @property
50    def title(self):
51        container_title = self.context.__parent__.title
52        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
53        ar_translation = translate(_('Application Record'),
54            'waeup.kofa', target_language=portal_language)
55        return '%s - %s %s' % (container_title,
56            ar_translation, self.context.application_number)
57
58    def _setUpWidgets(self):
59        """Setup simple display widgets.
60
61        Returns the list of widgets.
62        """
63        request = TestRequest()
64        return setUpEditWidgets(
65            self.form_fields, 'form', self.context, request, {},
66            for_display=True, ignore_request=True
67            )
68
69    def _getCourseAdmittedLink(self, view):
70        """Return link, title and code in html format to the certificate
71           admitted.
72        """
73        course_admitted = self.context.course_admitted
74        if view is not None and getattr(course_admitted, '__parent__',None):
75            url = view.url(course_admitted)
76            title = course_admitted.title
77            code = course_admitted.code
78            return '<a href="%s">%s - %s</a>' %(url,code,title)
79        return ''
80
81    def _addPassportImage(self, data):
82        """Add passport image to data stream.
83
84        If no image exists yet the default image is added.
85        """
86        img = getUtility(IExtFileStore).getFileByContext(self.context)
87        if img is None:
88            img = open(DEFAULT_PASSPORT_IMAGE_PATH, 'rb')
89        doc_img = Image(img.name, width=4*cm, height=3*cm, kind='bound')
90        data.append([doc_img])
91        data.append([Spacer(1, 18)])
92        return data
93
94    def _addDeptAndFaculty(self, data):
95        """If we have a valid course admitted, add dept. and faculty to data
96           stream.
97        """
98        style = getSampleStyleSheet()
99        course_admitted = self.context.course_admitted
100        dept = getattr(
101                getattr(course_admitted, '__parent__', None),
102                '__parent__', None)
103        if dept is None:
104            return data
105        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
106        dp_translation = translate(_('Department:'),
107            'waeup.kofa', target_language=portal_language)
108        f_label = '<font size=12>%s</font>' % dp_translation
109        f_text = '<font size=12>%s</font>' % dept.longtitle()
110        f_label = Paragraph(f_label, style["Normal"])
111        f_text = Paragraph(f_text, style["Normal"])
112        data.append([f_label,f_text])
113
114        faculty = getattr(dept, '__parent__', None)
115        if faculty is None:
116            return data
117        fc_translation = translate(_('Faculty:'),
118            'waeup.kofa', target_language=portal_language)
119        f_label = '<font size=12>%s</font>' % fc_translation
120        f_text = '<font size=12>%s</font>' % faculty.longtitle()
121        f_label = Paragraph(f_label, style["Normal"])
122        f_text = Paragraph(f_text, style["Normal"])
123        data.append([f_label,f_text])
124        return data
125
126    def _getWidgetsTable(self, view):
127        """Return a reportlab table buildt of widgets.
128        """
129        style = getSampleStyleSheet()
130        table_data = []
131        table_style = [('LEFTPADDING', (0,0), (0,-1), 0),
132                       ('VALIGN', (0,0), (-1,-1), 'TOP'),
133                       ]
134        row_num = 0
135        widgets = self._setUpWidgets()
136        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
137        for widget in widgets:
138            separators = getUtility(IApplicantsUtils).SEPARATORS_DICT
139            if separators and separators.get(widget.name):
140                f_headline = ('<font size=12><strong>%s</strong></font>'
141                    % translate(separators[widget.name], 'waeup.kofa',
142                    target_language=portal_language))
143                f_headline = Paragraph(f_headline, style["Normal"])
144                table_data.append([f_headline ])
145                table_style.append(('SPAN', (0,row_num), (-1,row_num)),)
146                table_style.append(
147                    ('TOPPADDING', (0,row_num), (-1,row_num), 12),)
148                row_num += 1
149            f_label = '<font size=12>%s</font>:' % translate(
150                widget.label.strip(), 'waeup.kofa',
151                target_language=portal_language)
152            f_label = Paragraph(f_label, style["Normal"])
153            f_text = '<font size=12>%s</font>' % widget()
154            # Add br tag if widgets contain div tags
155            # which are not supported by reportlab
156            f_text = f_text.replace('</div>', '</div><br />')
157            f_text = f_text.replace('\n', '')
158            f_text = Paragraph(f_text, style["Normal"])
159            table_data.append([f_label,f_text])
160            row_num += 1
161        adm_translation = translate(_('Admitted Course of Study:'),
162                'waeup.kofa', target_language=portal_language)
163        f_label = '<font size=12>%s</font>' % adm_translation
164        f_text = '<font size=12>%s</font>' % (
165            self._getCourseAdmittedLink(view),)
166        f_label = Paragraph(f_label, style["Normal"])
167        f_text = Paragraph(f_text, style["Normal"])
168        table_data.append([f_label,f_text])
169        row_num += 1
170
171        # Add dept. and faculty if applicable
172        table_data = self._addDeptAndFaculty(table_data)
173
174        # Create table
175        table = Table(table_data,style=table_style)
176        table.hAlign = 'LEFT'
177        return table
178
179    def _addComments(self, data):
180        style = getSampleStyleSheet()
181        if self.context.state == 'created':
182            comment1 = _(
183                '<font size=10>Proceed to the login page of the portal' +
184                ' and enter your new credentials:' +
185                ' user name= ${a}, password = ${b}.</font>', mapping = {
186                    'a':self.context.student_id,
187                    'b':self.context.application_number}
188                )
189            comment2 = _(
190                '<font size=10>Change your password when you have ' +
191                ' logged in.</font>'
192                )
193            comment1 = Paragraph(comment1, style["Normal"])
194            comment2 = Paragraph(comment2, style["Normal"])
195            data.extend([Spacer(1, 18), comment1, comment2])
196        return data
197
198    def __call__(self, view=None):
199        """Return a PDF representation of the context applicant.
200
201        If no `view` is given, the course admitted field will be an
202        empty string and author will be set as ``'unknown'``.
203
204        If a `view` is given, author will be set as the calling
205        principal.
206        """
207        doc_title = self.title.replace('-', '\n')
208        style = getSampleStyleSheet()
209        data = []
210
211        # append history
212        for msg in self.context.history.messages:
213            f_msg = '<font face="Courier" size=10>%s</font>' % msg
214            data.append(Paragraph(f_msg, style["Normal"]))
215        data.append(Spacer(1, 20))
216
217        # append photograph
218        img_path = getattr(
219            getUtility(IExtFileStore).getFileByContext(self.context),
220            'name', DEFAULT_PASSPORT_IMAGE_PATH)
221        doc_img = Image(img_path, width=4*cm, height=3*cm, kind='bound')
222        doc_img.hAlign='LEFT'
223        data.append(doc_img)
224
225        # append widgets
226        data.append(self._getWidgetsTable(view))
227
228        # append comments
229        data = self._addComments(data)
230
231        creator = getUtility(IPDFCreator)
232        return creator.create_pdf(data, None, doc_title)
Note: See TracBrowser for help on using the repository browser.