source: main/waeup.sirp/trunk/src/waeup/sirp/students/utils.py @ 7318

Last change on this file since 7318 was 7318, checked in by Henrik Bettermann, 14 years ago

It seems that font attributes can't be defined in Tables if Paragraphs are being used. The latter have to be used to render the widgets properly.

Reorganise slip pages in students section.

Sort course lists by semester and course code.

  • Property svn:keywords set to Id
File size: 12.4 KB
RevLine 
[7191]1## $Id: utils.py 7318 2011-12-09 12:34:30Z 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##
[6651]18"""General helper functions for the student section.
19"""
[7150]20import grok
[6662]21from random import SystemRandom as r
[7256]22from datetime import datetime
[7019]23from reportlab.pdfgen import canvas
[7318]24from reportlab.lib import colors
[7019]25from reportlab.lib.units import cm
[7310]26from reportlab.lib.enums import TA_RIGHT
[7019]27from reportlab.lib.pagesizes import A4
[7310]28from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
[7019]29from reportlab.platypus import (Frame, Paragraph, Image,
30    Table, Spacer)
31from reportlab.platypus.tables import TableStyle
[7310]32from reportlab.platypus.flowables import PageBreak
[7280]33from zope.component import getUtility
[7019]34from zope.formlib.form import setUpEditWidgets
[7280]35from waeup.sirp.interfaces import IExtFileStore
[7150]36from waeup.sirp.students.interfaces import IStudentsUtils
[6651]37
[7318]38SLIP_STYLE = [
39    ('VALIGN',(0,0),(-1,-1),'TOP'),
40    #('FONT', (0,0), (-1,-1), 'Helvetica', 11),
41    ]
[7019]42
[7318]43CONTENT_STYLE = [
44    ('VALIGN',(0,0),(-1,-1),'TOP'),
45    #('FONT', (0,0), (-1,-1), 'Helvetica', 8),
46    #('TEXTCOLOR',(0,0),(-1,0),colors.white),
47    ('BACKGROUND',(0,0),(-1,0),colors.black),
48    ]
[7304]49
[7318]50FONT_SIZE = 10
51FONT_COLOR = 'black'
52
53def formatted_string(color=FONT_COLOR, size=FONT_SIZE):
54    tag1 ='<font color=%s size=%d>' % (color, size)
55    return tag1 + '%s</font>'
56
[6749]57def generate_student_id(students,letter):
[6651]58    if letter == '?':
[6664]59        letter= r().choice('ABCDEFGHKLMNPQRSTUVWXY')
60    sid = u"%c%d" % (letter,r().randint(99999,1000000))
[6749]61    while sid in students.keys():
[6664]62        sid = u"%c%d" % (letter,r().randint(99999,1000000))
[6662]63    return sid
[6742]64
65def set_returning_data(student):
66    student['studycourse'].current_level += 100
67    student['studycourse'].current_session += 1
68    verdict = student['studycourse'].current_verdict
[6804]69    student['studycourse'].current_verdict = '0'
[6742]70    student['studycourse'].previous_verdict = verdict
71    return
[6876]72
[7186]73def set_up_widgets(view, ignore_request=False):
[7019]74    view.adapters = {}
75    view.widgets = setUpEditWidgets(
76        view.form_fields, view.prefix, view.context, view.request,
77        adapters=view.adapters, for_display=True,
78        ignore_request=ignore_request
79        )
80
[7310]81def render_student_data(studentview):
[7318]82    """Render student table for an existing frame.
83    """
84    width, height = A4
[7186]85    set_up_widgets(studentview, ignore_request=True)
[7318]86    data_left = []
87    data_right = []
[7019]88    style = getSampleStyleSheet()
[7280]89    img = getUtility(IExtFileStore).getFileByContext(
90        studentview.context, attr='passport.jpg')
91    if img is None:
92        from waeup.sirp.browser import DEFAULT_PASSPORT_IMAGE_PATH
93        img = open(DEFAULT_PASSPORT_IMAGE_PATH, 'rb')
[7318]94    doc_img = Image(img.name, width=4*cm, height=4*cm, kind='bound')
95    data_left.append([doc_img])
96    #data.append([Spacer(1, 12)])
[7019]97    for widget in studentview.widgets:
98        if widget.name == 'form.adm_code':
99            continue
[7318]100        f_label = formatted_string() % widget.label.strip()
[7019]101        f_label = Paragraph(f_label, style["Normal"])
[7318]102        f_text = formatted_string() % widget()
[7019]103        f_text = Paragraph(f_text, style["Normal"])
[7318]104        data_right.append([f_label,f_text])
105    table_left = Table(data_left,style=SLIP_STYLE)
106    table_right = Table(data_right,style=SLIP_STYLE, colWidths=[4*cm, 10*cm])
107    table = Table([[table_left, table_right],],style=SLIP_STYLE)
[7019]108    return table
109
[7304]110def render_table_data(tableheader,tabledata):
[7318]111    """Render children table for an existing frame.
112    """
[7304]113    data = []
[7318]114    #data.append([Spacer(1, 12)])
[7304]115    line = []
116    style = getSampleStyleSheet()
117    for element in tableheader:
[7318]118        field = formatted_string(color='white') % element[0]
[7310]119        field = Paragraph(field, style["Normal"])
[7304]120        line.append(field)
121    data.append(line)
122    for ticket in tabledata:
123        line = []
124        for element in tableheader:
[7318]125              field = formatted_string() % str(getattr(ticket,element[1],u' '))
126              field = Paragraph(field, style["Normal"])
[7304]127              line.append(field)
128        data.append(line)
[7310]129    table = Table(data,colWidths=[
[7318]130        element[2]*cm for element in tableheader], style=CONTENT_STYLE)
[7304]131    return table
132
[7318]133
134def insert_footer(pdf,width,style,text=None, number_of_pages=1):
135      """Render the whole footer frame.
136      """
137      story = []
138      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
139      timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
140      left_text = '<font size=10>%s</font>' % timestamp
141      story.append(Paragraph(left_text, style["Normal"]))
142      frame_footer.addFromList(story,pdf)
143      story = []
144      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
145      right_text = '<font size=10>%s Page %s of %s</font>' % (
146          text, pdf.getPageNumber(), number_of_pages)
147      story.append(Paragraph(right_text, style["Right"]))
148      frame_footer.addFromList(story,pdf)
149
[7150]150class StudentsUtils(grok.GlobalUtility):
151    """A collection of methods subject to customization.
152    """
153    grok.implements(IStudentsUtils)
[7019]154
[7186]155    def getPaymentDetails(self,category, student):
[7150]156        d = {}
157        d['p_item'] = u''
158        d['amount'] = 0
159        d['error'] = u''
160        d['p_session'] = student['studycourse'].current_session
161        session = str(d['p_session'])
162        try:
163            academic_session = grok.getSite()['configuration'][session]
164        except KeyError:
165            d['error'] = u'Session configuration object is not available.'
166            return d
167        d['surcharge_1'] = academic_session.surcharge_1
168        d['surcharge_2'] = academic_session.surcharge_2
169        d['surcharge_3'] = academic_session.surcharge_3
170        if category == 'schoolfee':
171            d['amount'] = academic_session.school_fee_base
172            d['p_item'] = student['studycourse'].certificate.code
173        elif category == 'clearance':
174            d['p_item'] = student['studycourse'].certificate.code
175            d['amount'] = academic_session.clearance_fee
176        elif category == 'bed_allocation':
[7186]177            d['p_item'] = self.getAccommodationDetails(student)['bt']
[7150]178            d['amount'] = academic_session.booking_fee
179        return d
[7019]180
[7186]181    def getAccommodationDetails(self, student):
[7150]182        d = {}
183        d['error'] = u''
184        site_confoguration = grok.getSite()['configuration']
185        d['booking_session'] = site_confoguration.accommodation_session
186        d['allowed_states'] = site_confoguration.accommodation_states
187        # Determine bed type
188        studycourse = student['studycourse']
189        entry_session = studycourse.entry_session
190        current_level = studycourse.current_level
191        end_level = studycourse.certificate.end_level
192        if entry_session == grok.getSite()['configuration'].accommodation_session:
193            bt = 'fr'
194        elif current_level >= end_level:
195            bt = 'fi'
196        else:
197            bt = 're'
198        if student.sex == 'f':
199            sex = 'female'
200        else:
201            sex = 'male'
202        special_handling = 'regular'
203        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
204        return d
[7019]205
[7150]206    # In the standard configuration we select the first bed found,
207    # but can also randomize the selection if we like.
[7186]208    def selectBed(self, available_beds):
[7150]209        return available_beds[0]
210
[7318]211    def renderPDF(self, view, filename='slip.pdf',
[7304]212        student=None, studentview=None, tableheader=None, tabledata=None):
[7150]213        # (0,0),(-1,-1) = whole table
214        # (0,0),(0,-1) = first column
215        # (-1,0),(-1,-1) = last column
216        # (0,0),(-1,0) = first row
217        # (0,-1),(-1,-1) = last row
218
219        pdf = canvas.Canvas(filename,pagesize=A4)
220        pdf.setTitle(view.label)
[7318]221        pdf.setSubject(view.title)
[7150]222        pdf.setAuthor('%s (%s)' % (view.request.principal.title,
223            view.request.principal.id))
224        pdf.setCreator('WAeUP SIRP')
225        width, height = A4
[7310]226        footer_text = view.label
227        if student is not None:
228            footer_text = "%s - %s - " % (student.student_id, footer_text)
[7150]229        style = getSampleStyleSheet()
[7310]230        style.add(ParagraphStyle(name='Right', alignment=TA_RIGHT))
[7150]231        pdf.line(1*cm,height-(1.8*cm),width-(1*cm),height-(1.8*cm))
232
233        story = []
234        frame_header = Frame(1*cm,1*cm,width-(1.7*cm),height-(1.7*cm))
235        header_title = getattr(grok.getSite(), 'name', u'Sample University')
236        story.append(Paragraph(header_title, style["Heading1"]))
237        frame_header.addFromList(story,pdf)
238
[7318]239        # Insert student data table
[7150]240        story = []
241        frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(3.5*cm))
242        story.append(Paragraph(view.label, style["Heading2"]))
[7310]243        if student is not None:
[7318]244            #story.append(Spacer(1, 12))
245            story.append(Paragraph('Student Base Data', style["Heading3"]))
[7310]246            studenttable = render_student_data(studentview)
[7150]247            story.append(studenttable)
[7304]248
[7318]249        # Insert widgets
250        story.append(Paragraph(view.title, style["Heading3"]))
[7186]251        set_up_widgets(view)
[7150]252        data = []
253        for widget in view.widgets:
[7318]254            f_label = formatted_string() % widget.label.strip()
[7150]255            f_label = Paragraph(f_label, style["Normal"])
[7318]256            f_text = formatted_string() % str(widget())
[7150]257            f_text = Paragraph(f_text, style["Normal"])
258            data.append([f_label,f_text])
[7318]259        table = Table(data,style=SLIP_STYLE, colWidths=[5*cm, 13.5*cm])
260        story.append(table)
261
262        # Import browser components locally
[7280]263        # to avoid circular import
264        from waeup.sirp.students.viewlets import FileManager
265        from waeup.sirp.browser import DEFAULT_IMAGE_PATH
[7318]266        data = []
267        # Collect viewlets
[7280]268        fm = FileManager(view.context, view.request, view)
269        fm.update()
[7318]270        if fm.viewlets:
271            story.append(Paragraph('Scanned Documents', style["Heading3"]))
272            # Insert list of scanned documents
273            for viewlet in fm.viewlets:
274                f_label = formatted_string() % viewlet.label
275                f_label = Paragraph(f_label, style["Normal"])
276                if viewlet.template.__grok_name__ == 'imagedisplay':
277                    # In case we define FileDisplay viewlets with
278                    # an imagedisplay template in the customization package
279                    img = getUtility(IExtFileStore).getFileByContext(
280                        view.context, attr=viewlet.download_name)
281                    if img is None:
282                        img = open(DEFAULT_IMAGE_PATH, 'rb')
283                    doc_img = Image(img.name, width=2*cm, height=1*cm, kind='bound')
284                    data.append([f_label,doc_img])
285                else:
286                    f_text = formatted_string() % viewlet.title
287                    f_text = Paragraph(f_text, style["Normal"])
288                    data.append([f_label,f_text])
289            table = Table(data,style=SLIP_STYLE, colWidths=[5*cm, 13.5*cm])
290            story.append(table)
291
[7280]292        try:
293            frame_body.addFromList(story,pdf)
294        except IOError:
295            view.flash('Error in image file.')
296            return view.redirect(view.url(view.context))
[7318]297
[7304]298        if tabledata and tableheader:
[7318]299            insert_footer(pdf,width,style,footer_text,number_of_pages=2)
300        else:
301            insert_footer(pdf,width,style,footer_text)
302
303        # Insert content table on second page
304        if tabledata and tableheader:
305            pdf.showPage()
306            frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(2*cm))
[7304]307            story = []
[7318]308            story.append(Paragraph(view.content_title, style["Heading3"]))
[7310]309            #story.append(Spacer(1, 12))
[7304]310            contenttable = render_table_data(tableheader,tabledata)
311            story.append(contenttable)
312            frame_body.addFromList(story,pdf)
[7318]313            insert_footer(pdf,width,style,footer_text,number_of_pages=2)
314
[7150]315        view.response.setHeader(
316            'Content-Type', 'application/pdf')
317        return pdf.getpdfdata()
Note: See TracBrowser for help on using the repository browser.