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

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

Export course registration slip on two pages.
Set columns width of each column.
Show semester on all course registration view.

ToDo?: Sort course tickets by semester on course registration slip.

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