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

Last change on this file since 7323 was 7319, checked in by Henrik Bettermann, 13 years ago

Label colons should be rendered by pagetemplates and not by label attributes.

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