source: main/waeup.kofa/branches/uli-py3/src/waeup/kofa/students/reports/session_results_presentation.py

Last change on this file was 14917, checked in by Henrik Bettermann, 7 years ago

Also the length of GPABoundaries() may depend on the parameters.

  • Property svn:keywords set to Id
File size: 13.4 KB
Line 
1## $Id: session_results_presentation.py 14917 2017-11-30 11:19:10Z henrik $
2##
3## Copyright (C) 2013 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##
18import grok
19from zope.i18n import translate
20from zope.catalog.interfaces import ICatalog
21from zope.component import queryUtility, getUtility
22from zope.interface import implementer, Interface, Attribute
23from waeup.kofa.interfaces import (
24    IKofaUtils, GRADUATED,
25    academic_sessions_vocab, registration_states_vocab)
26from waeup.kofa.students.vocabularies import StudyLevelSource
27from waeup.kofa.students.interfaces import IStudentsUtils
28from waeup.kofa.interfaces import MessageFactory as _
29from waeup.kofa.browser.pdf import get_signature_tables
30from waeup.kofa.reports import IReport
31from waeup.kofa.students.reports.level_report import (
32    ILevelReport, LevelReportGeneratorPage)
33from waeup.kofa.students.reports.student_statistics import (
34    StudentStatisticsReportPDFView)
35from reportlab.lib import colors
36from reportlab.lib.styles import getSampleStyleSheet
37from reportlab.lib.units import cm
38from reportlab.platypus import Paragraph, Table, Spacer
39from reportlab.platypus.flowables import Flowable
40from waeup.kofa.reports import IReport, IReportGenerator
41from waeup.kofa.reports import Report
42from waeup.kofa.browser.interfaces import IPDFCreator
43
44STYLE = getSampleStyleSheet()
45
46TABLE_STYLE = [
47    ('FONT', (0,0), (-1,-1), 'Helvetica', 8),
48    ('FONT', (0,0), (-1,0), 'Helvetica-Bold', 8), # 1st row
49    #('ALIGN', (3,1), (-1,-1), 'RIGHT'),
50    #('ALIGN', (1,0), (1,-1), 'LEFT'),
51    #('ALIGN', (2,0), (2,-1), 'LEFT'),
52    #('INNERGRID', (0,1), (-1,-1), 0.25, colors.black),
53    #('BOX', (0,1), (-1,-1), 1, colors.black),
54    ]
55
56SUMMARY_STYLE = [
57    ('ALIGN', (3,1), (-1,-1), 'RIGHT'),
58    ]
59
60class ISessionResultsPresentation(ILevelReport):
61    """ Same interface as for level session results presentation.
62    """
63
64@implementer(ISessionResultsPresentation)
65class SessionResultsPresentation(Report):
66    data = None
67    session = None
68    level = None
69    faccode = None
70    depcode = None
71    certcode = None
72    pdfcreator = ''
73    signatures = None
74    introduction = ''
75
76    @property
77    def title(self):
78        return translate(_('Presentation of Session Results'))
79
80    @property
81    def right_footer(self):
82        return self.title + ' - %s -' % self.session
83
84    note = None
85
86    def _excluded(self, level_obj):
87        """Some universities may add further conditions to exclude
88        students from reports. These conditions can be customized in
89        this function.
90        """
91        return False
92
93    def _get_students(self, faccode, depcode, certcode, session, level=None):
94        """Get students in a certain department, studying a certain programmen
95        who registered courses in a certain session at a certain level.
96
97        Returns a list of lists of student data tuples.
98        """
99        site = grok.getSite()
100        cat = queryUtility(ICatalog, name="students_catalog")
101        if certcode == 'all':
102            certcode = None
103        result = cat.searchResults(
104            depcode = (depcode, depcode), faccode = (faccode, faccode),
105            certcode = (certcode, certcode)
106            )
107        students_utils = getUtility(IStudentsUtils)
108        table = list()
109        for i in range(len(students_utils.GPABoundaries(
110                faccode=faccode, depcode=depcode,
111                certcode=certcode))+1):
112            # The last list is reserved for students with more than one
113            # level in the same session.
114            table.append([])
115        for stud in result:
116            if stud.state == GRADUATED:
117                continue
118            line = (stud.student_id,
119                    stud.matric_number,
120                    stud.display_fullname,
121                    )
122            if level != 0:
123                if not stud['studycourse'].has_key(str(level)):
124                    continue
125                level_obj = stud['studycourse'][str(level)]
126                if level_obj.level_session != session:
127                    continue
128                if self._excluded(level_obj):
129                    continue
130            else:
131                itemcount = 0
132                for item in stud['studycourse'].values():
133                    if item.level_session == session:
134                        level_obj = item
135                        itemcount += 1
136                if itemcount == 0:
137                    # No level registered in this session
138                    continue
139                if itemcount > 1:
140                    # Error: more than one level registered in this session
141                    table[len(students_utils.GPABoundaries(
142                        faccode=faccode, depcode=depcode,
143                        certcode=certcode))].append(line)
144                    continue
145            gpaclass = students_utils.getDegreeClassNumber(level_obj)
146            table[gpaclass].append(line)
147            for i in range(len(students_utils.GPABoundaries(
148                    faccode=faccode, depcode=depcode,
149                    certcode=certcode))+1):
150                if len(table[i]):
151                    table[i] = sorted([value for value in table[i]],
152                        key=lambda value: value[2])
153        return table
154
155    def __init__(self, faccode, depcode, certcode, session, level,
156                 author='System'):
157        super(SessionResultsPresentation, self).__init__(
158            args=[faccode, depcode, certcode, session, level],
159            kwargs={'author':author})
160        site = grok.getSite()
161        self.studylevelsource = StudyLevelSource().factory
162        self.portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
163        self.session = academic_sessions_vocab.getTerm(session).title
164        self.levelcode = level
165        self.sessioncode = session
166        self.faccode = faccode
167        self.depcode = depcode
168        self.certcode = certcode
169        self.factitle = site['faculties'][faccode].longtitle
170        self.deptitle = site['faculties'][faccode][depcode].longtitle
171        if self.certcode == 'all':
172            self.certtitle = translate(
173                _('All Certificates'), 'waeup.kofa',
174                target_language=self.portal_language)
175        else:
176            certificate = site[
177                'faculties'][faccode][depcode].certificates[certcode]
178            self.certtitle = certificate.longtitle
179        if level == 0:
180            self.level = translate(_('all levels'))
181        else:
182            if self.certcode == 'all':
183                self.level = translate(
184                    self.studylevelsource.getTitle(None, int(level)),
185                    'waeup.kofa', target_language=self.portal_language)
186            else:
187                self.level = translate(
188                    self.studylevelsource.getTitle(certificate, int(level)),
189                    'waeup.kofa', target_language=self.portal_language)
190        self.author = author
191        self.creation_dt_string = self.creation_dt.astimezone(
192            getUtility(IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z")
193        self.data = self._get_students(faccode, depcode, certcode, session, level)
194
195    def create_pdf(self, job_id):
196        creator = getUtility(IPDFCreator, name=self.pdfcreator)
197        #col_widths = [2*cm, 4*cm, 5*cm, 0.8*cm, 0.8*cm, 0.8*cm, 6*cm, ]
198        pdf_data = [Paragraph('<b>%s - Report %s</b>'
199                              % (self.creation_dt_string, job_id),
200                              STYLE["Normal"]),
201                    Spacer(1, 12),]
202        if self.introduction:
203            pdf_data += [Paragraph(self.introduction,
204                         STYLE["Normal"]), Spacer(1, 12)]
205        pdf_data += [Paragraph(
206                    translate(
207                        '${a}<br />${b}<br />${c}<br />Session: ${d}<br />'
208                        'Level: ${e}',
209                        mapping = {'a':self.certtitle,
210                                   'b':self.deptitle,
211                                   'c':self.factitle,
212                                   'd':self.session,
213                                   'e':self.level,
214                                   }),
215                    STYLE["Normal"]),
216                    ]
217        students_utils = getUtility(IStudentsUtils)
218        # Print classes in reverse order
219        for gpa_class in range(len(students_utils.GPABoundaries(
220                faccode=self.faccode, depcode=self.depcode,
221                certcode=self.certcode))-1,-1,-1):
222            pdf_data.append(Spacer(1, 20))
223            gpa_class_name = students_utils.GPABoundaries(
224                faccode=self.faccode, depcode=self.depcode,
225                certcode=self.certcode)[gpa_class][1]
226            pdf_data += [Paragraph('<strong>%s</strong>' % gpa_class_name,
227                         STYLE["Normal"])]
228            pdf_data.append(Spacer(1, 6))
229            if len(self.data[gpa_class]):
230                sns = range(len(self.data[gpa_class]))
231                gpa_class_data = [(i+1,) + self.data[gpa_class][i] for i in sns]
232            else:
233                gpa_class_data = [('', '', '- Nil -', '')]
234            table_data = [('S/N', 'Student Id', 'Matric No.',
235                translate(_('Student Name')))] + gpa_class_data
236            pdf_data += [Table(table_data, style=TABLE_STYLE)]    #, colWidths=col_widths)]
237        if self.data[-1]:
238            pdf_data.append(Spacer(1, 20))
239            pdf_data += [
240                Paragraph(
241                    '<strong>Students with erroneous data</strong>', STYLE["Normal"])]
242            pdf_data.append(Spacer(1, 10))
243            table_data = [('Student Id', 'Matric No.', 'Name')] + self.data[-1]
244            pdf_data += [Table(table_data, style=TABLE_STYLE)]
245        pdf_data.append(Spacer(1, 20))
246        pdf_data += [Paragraph('<strong>Summary</strong>', STYLE["Normal"])]
247        pdf_data.append(Spacer(1, 10))
248        total_count = 0
249        table_data = list()
250        for gpa_class in range(len(students_utils.GPABoundaries(
251                faccode=self.faccode, depcode=self.depcode,
252                certcode=self.certcode))-1,-1,-1):
253            gpa_class_name = students_utils.GPABoundaries(
254                faccode=self.faccode, depcode=self.depcode,
255                certcode=self.certcode)[gpa_class][1]
256            gpa_count = len(self.data[gpa_class])
257            total_count += gpa_count
258            table_data += [(gpa_class_name + ':', '%02d' % gpa_count)]
259            #pdf_data += [Paragraph('%s: %s'
260            #             % (gpa_class_name, gpa_count), STYLE["Normal"])]
261            pass
262        #pdf_data += [Paragraph('Total: %s' % (total_count), STYLE["Normal"])]
263        table_data += [('Total:', '%02d' % total_count)]
264        pdf_data += [Table(table_data, style=SUMMARY_STYLE, hAlign='LEFT')]
265
266        pdf_data.append(Spacer(1, 40))
267        if self.signatures:
268            signaturetables = get_signature_tables(self.signatures)
269            pdf_data.append(signaturetables[0])
270
271        pdf = creator.create_pdf(
272            pdf_data, None, self.title, self.author,
273            self.right_footer, note = self.note
274            )
275        return pdf
276
277@implementer(IReportGenerator)
278class SessionResultsPresentationGenerator(grok.GlobalUtility):
279
280    title = _('Session Results Presentation')
281    grok.name('session_results_presentation')
282
283    def generate(self, site, faccode=None, depcode=None, certcode=None,
284                 session=None, level=None, author=None):
285        result = SessionResultsPresentation(faccode=faccode, depcode=depcode,
286                 certcode=certcode, session=session, level=level, author=author)
287        return result
288
289###############################################################
290## Browser related stuff
291##
292## XXX: move to local browser module
293###############################################################
294from waeup.kofa.browser.layout import KofaPage
295from waeup.kofa.interfaces import academic_sessions_vocab
296from waeup.kofa.reports import get_generators
297from waeup.kofa.browser.breadcrumbs import Breadcrumb
298grok.templatedir('browser_templates')
299class SessionResultsPresentationGeneratorPage(LevelReportGeneratorPage):
300
301    grok.context(SessionResultsPresentationGenerator)
302    grok.template('levelreportgeneratorpage')
303    label = _('Create session results presentation')
304
305    def _set_level_values(self):
306        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
307        studylevelsource = StudyLevelSource().factory
308        self.levels = [(u'All levels', 0)]
309        for code in studylevelsource.getValues(None):
310            title = translate(studylevelsource.getTitle(None, code),
311                'waeup.kofa', target_language=portal_language)
312            self.levels.append((title, code))
313        return
314
315class SessionResultsPresentationPDFView(StudentStatisticsReportPDFView):
316
317    grok.context(ISessionResultsPresentation)
318    grok.name('pdf')
319    grok.require('waeup.handleReports')
320
321    def _filename(self):
322        return 'SessionResultsPresentation_rno%s_%s.pdf' % (
323            self.context.__name__,
324            self.context.creation_dt_string)
Note: See TracBrowser for help on using the repository browser.