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

Last change on this file since 17016 was 16057, checked in by Henrik Bettermann, 5 years ago

Render proper application slips in all tests.

  • Property svn:keywords set to Id
File size: 9.2 KB
Line 
1## $Id: pdf.py 16057 2020-04-18 08:12:53Z henrik $
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.platypus import Paragraph, Spacer, Table
23from reportlab.lib.units import cm
24from zope.component import getUtility
25from zope.i18n import translate
26from waeup.kofa.applicants.interfaces import IApplicant, IApplicantsUtils
27from waeup.kofa.browser import DEFAULT_PASSPORT_IMAGE_PATH
28from waeup.kofa.browser.interfaces import IPDFCreator
29from waeup.kofa.browser.pdf import SMALL_PARA_STYLE, ENTRY1_STYLE, get_qrcode
30from waeup.kofa.interfaces import IExtFileStore, IPDF, IKofaUtils
31from waeup.kofa.interfaces import MessageFactory as _
32from waeup.kofa.widgets.datewidget import FriendlyDateDisplayWidget
33
34SLIP_STYLE = [
35    ('VALIGN',(0,0),(-1,-1),'TOP'),
36    #('FONT', (0,0), (-1,-1), 'Helvetica', 11),
37    ]
38
39class PDFApplicationSlip(grok.Adapter):
40    """Create a PDF application slip for applicants.
41    """
42    # XXX: Many things in here are reusable. We might want to split
43    # things. Possibly move parts to IPDFCreator?
44    grok.context(IApplicant)
45    grok.implements(IPDF)
46    grok.name('application_slip')
47
48    form_fields =  grok.AutoFields(IApplicant).omit(
49        'locked', 'course_admitted', 'suspended',
50        )
51    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
52    column_two_fields = ('applicant_id', 'reg_number',
53        'firstname', 'middlename', 'lastname')
54    two_columns_design_fields = []
55
56    @property
57    def note(self):
58        note = getattr(self.context.__parent__, 'application_slip_notice', None)
59        if note:
60            return '<br /><br />' + note
61        return
62
63    @property
64    def target(self):
65        return getattr(self.context.__parent__, 'prefix', None)
66
67    @property
68    def title(self):
69        container_title = self.context.__parent__.title
70        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
71        ar_translation = translate(_('Application Record'),
72            'waeup.kofa', target_language=portal_language)
73        return '%s - %s %s' % (container_title,
74            ar_translation, self.context.application_number)
75
76    def _getCourseAdmittedLink(self, view):
77        """Return link, title and code in html format to the certificate
78           admitted.
79        """
80        course_admitted = self.context.course_admitted
81        if course_admitted is not None:
82            if view is None:
83                title = course_admitted.title
84                code = course_admitted.code
85                return '%s - %s' %(code,title)
86            if getattr(course_admitted, '__parent__',None):
87                url = view.url(course_admitted)
88                title = course_admitted.title
89                code = course_admitted.code
90                return '<a href="%s">%s - %s</a>' %(url,code,title)
91        return ''
92
93    def _getDeptAndFaculty(self):
94        """Return long titles of department and faculty.
95
96        Returns a list [department_title, faculty_title]
97
98        If the context applicant has no course admitted or dept. and
99        faculty cannot be determined, ``None`` is returned.
100        """
101        course_admitted = self.context.course_admitted
102        dept = getattr(
103                getattr(course_admitted, '__parent__', None),
104                '__parent__', None)
105        faculty = getattr(dept, '__parent__', None)
106        return [x is not None and x.longtitle or x for x in dept, faculty]
107
108    def _addLoginInformation(self):
109        if self.context.state == 'created':
110            comment = translate(_(
111                '\n Proceed to the login page of the portal' +
112                ' and enter your new credentials:' +
113                ' user name= ${a}, password = ${b}. ' +
114                'Change your password when you have logged in.',
115                mapping = {
116                    'a':self.context.student_id,
117                    'b':self.context.application_number}
118                ))
119            return comment
120        return
121
122    def _getPDFCreator(self):
123        return getUtility(IPDFCreator)
124
125    def __call__(self, view=None, note=None):
126        """Return a PDF representation of the context applicant.
127
128        If no `view` is given, the course admitted field will be an
129        empty string and author will be set as ``'unknown'``.
130
131        If a `view` is given, author will be set as the calling
132        principal.
133        """
134        doc_title = '\n'.join([x.strip() for x in self.title.split(' - ')])
135        data = []
136        topMargin = 1.5
137        if len(self.title.split(' - ')) > 2:
138            topMargin = 1.8
139        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
140        separators = getUtility(IApplicantsUtils).SEPARATORS_DICT
141        creator = self._getPDFCreator()
142
143        # append history
144        data.extend(creator.fromStringList(self.context.history.messages))
145        data.append(Spacer(1, 5))
146
147        if self.context.__parent__.with_picture:
148
149            # create three-column header table
150            # append photograph to the left
151            img_path = getattr(
152                getUtility(IExtFileStore).getFileByContext(self.context),
153                'name', DEFAULT_PASSPORT_IMAGE_PATH)
154            data_left = [[creator.getImage(img_path)]]
155            table_left = Table(data_left,style=SLIP_STYLE)
156
157            # append base data table to the middle
158            fields = [
159                field for field in self.form_fields
160                    if field.__name__ in self.column_two_fields]
161            table_middle = creator.getWidgetsTable(
162                fields, self.context, None, lang=portal_language,
163                separators=None, colWidths=[5*cm, 4.5*cm])
164
165            # append QR code to the right
166            if view is not None:
167                url = view.url(self.context, 'application_slip.pdf')
168                data_right = [[get_qrcode(url, width=70.0)]]
169                table_right = Table(data_right,style=SLIP_STYLE)
170            else:
171                table_right = None
172
173            header_table = Table(
174                [[table_left, table_middle, table_right],],style=SLIP_STYLE)
175            data.append(header_table)
176
177        else:
178            fields = [
179                field for field in self.form_fields
180                    if field.__name__ in self.column_two_fields]
181            data.append(creator.getWidgetsTable(
182                fields, self.context, None, lang=portal_language,
183                separators=None, colWidths=[7*cm, 10*cm]))
184
185        # append widgets except those already added in column two
186        # and those in two_columns_design_fields
187        dept, faculty = self._getDeptAndFaculty()
188        fields = [
189            field for field in self.form_fields
190                if not field.__name__ in self.column_two_fields and
191                not field.__name__ in self.two_columns_design_fields]
192        data.append(creator.getWidgetsTable(
193            fields, self.context, view, lang=portal_language,
194            domain='waeup.kofa', separators=separators,
195            course_label='Admitted Course of Study:',
196            course_link=self._getCourseAdmittedLink(view),
197            dept=dept, faculty=faculty, colWidths=[7*cm, 10*cm]))
198
199        # append two-column table of widgets of those fields defined in
200        # two_columns_design_fields
201        if len(self.two_columns_design_fields):
202            fields = [
203                field for field in self.form_fields
204                    if not field.__name__ in self.column_two_fields and
205                    field.__name__ in self.two_columns_design_fields]
206            if fields:
207                data.append(creator.getWidgetsTable(
208                    fields, self.context, view, lang=portal_language,
209                    domain='waeup.kofa', separators=separators,
210                    twoDataCols=True))
211
212        # append QR Code if without picture
213        if not self.context.__parent__.with_picture and view is not None:
214            data.append(Spacer(1, 5))
215            url = view.url(self.context, 'application_slip.pdf')
216            data_right = [[get_qrcode(url, width=70.0)]]
217            table_right = Table(data_right,style=SLIP_STYLE)
218            data.append(get_qrcode(url, width=70.0))
219
220        # append login information
221        note = None
222        login_information = self._addLoginInformation()
223        if not None in (self.note, login_information):
224            note = self.note + login_information
225        elif self.note:
226            note = self.note
227        elif login_information:
228            note = login_information
229
230        return creator.create_pdf(data, None, doc_title, note=note,
231            topMargin=topMargin)
Note: See TracBrowser for help on using the repository browser.