source: main/waeup.kofa/trunk/src/waeup/kofa/students/reports.py @ 9658

Last change on this file since 9658 was 9657, checked in by Henrik Bettermann, 12 years ago

Display report creation date.

Adjust margin between headline and body.

File size: 8.8 KB
Line 
1## $Id$
2##
3## Copyright (C) 2012 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.catalog.interfaces import ICatalog
20from zope.component import queryUtility, getUtility
21from zope.interface import implementer, Interface
22from waeup.kofa.interfaces import (
23    IKofaUtils,
24    academic_sessions_vocab, registration_states_vocab)
25from waeup.kofa.interfaces import MessageFactory as _
26from waeup.kofa.reports import IReport
27
28class IStudentsReport(IReport):
29    pass
30
31def get_students_by(session, mode):
32    """Get students in a certain session and study mode.
33
34    Returns a table ordered by faculty code (one per row) and
35    registration state (cols). The result is a 3-tuple representing
36    ((<FACULTY_CODES>), (<STATES>), (<NUM_OF_STUDENTS>)). The
37    (<NUM_OF_STUDENTS>) is an n-tuple with each entry containing the
38    number of students found in that faculty and with the respective
39    state.
40
41    Sample result:
42
43      >>> ((u'FAC1', u'FAC2'),
44      ...  ('created', 'accepted', 'registered'),
45      ...  ((12, 10, 1), (0, 5, 25)))
46
47    This result means: there are 5 students in FAC2 in state
48    'accepted' while 12 students in 'FAC1' are in state 'created'.
49    """
50    site = grok.getSite()
51    states = tuple([x.value for x in registration_states_vocab])
52    states = states + (u'Total',)
53    fac_codes = tuple(sorted([x for x in site['faculties'].keys()],
54                             key=lambda x: x.lower()))
55    fac_codes = fac_codes + (u'Total',)
56    # XXX: Here we do _one_ query and then examine the single
57    #   students. One could also do multiple queries and just look for
58    #   the result length (not introspecting the delivered students
59    #   further).
60    cat = queryUtility(ICatalog, name="students_catalog")
61    result = cat.searchResults(current_session=(session, session))
62    table = [[0 for x in xrange(len(states))] for y in xrange(len(fac_codes))]
63    mode_groups = getUtility(IKofaUtils).MODE_GROUPS
64    for stud in result:
65        if mode != 'All' and stud.current_mode not in mode_groups[mode]:
66            continue
67        row = fac_codes.index(stud.faccode)
68        col = states.index(stud.state)
69        table[row][col] += 1
70        table[-1][col] += 1
71        table[row][-1] += 1
72        table[-1][-1] += 1
73    # turn lists into tuples
74    table = tuple([tuple(row) for row in table])
75    return (fac_codes, states, table)
76
77from reportlab.lib import colors
78from reportlab.lib.styles import getSampleStyleSheet
79from reportlab.lib.units import cm
80from reportlab.platypus import Paragraph, Table, Spacer
81from waeup.kofa.reports import IReport, IReportGenerator
82from waeup.kofa.reports import Report
83from waeup.kofa.browser.interfaces import IPDFCreator
84
85STYLE = getSampleStyleSheet()
86
87def tbl_data_to_table(row_names, col_names, data):
88    result = []
89    new_col_names = []
90    for name in col_names:
91        new_col_names.append(name.replace(' ', '\n'))
92    head = [''] + list(new_col_names)
93    result = [head]
94    for idx, row_name in enumerate(row_names):
95        row = [row_name] + list(data[idx])
96        result.append(row)
97    return result
98
99TABLE_STYLE = [
100    ('FONT', (0,0), (-1,-1), 'Helvetica', 8),
101    ('FONT', (0,0), (0,-1), 'Helvetica-Bold', 8),
102    ('FONT', (0,0), (-1,0), 'Helvetica-Bold', 8),
103    ('FONT', (0,-1), (-1,-1), 'Helvetica-Bold', 8),
104    ('FONT', (-1,0), (-1,-1), 'Helvetica-Bold', 8),
105    ('ALIGN', (1,1), (-1,-1), 'RIGHT'),
106    ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
107    ('LINEBELOW', (0,-1), (-1,-1), 0.25, colors.black),
108    ('LINEAFTER', (-1,0), (-1,-1), 0.25, colors.black),
109    ('LINEBEFORE', (-1,0), (-1,-1), 1.0, colors.black),
110    ('LINEABOVE', (0,-1), (-1,-1), 1.0, colors.black),
111    ('LINEABOVE', (0,0), (-1,0), 0.25, colors.black),
112    ]
113
114@implementer(IStudentsReport)
115class StudentsReport(Report):
116    data = None
117    session = None
118    mode = None
119
120    def __init__(self, session, mode, author='System'):
121        super(StudentsReport, self).__init__(
122            args=[session, mode], kwargs={'author':author})
123        self.session = academic_sessions_vocab.getTerm(session).title
124        self.mode = mode
125        self.author = author
126        self.data = get_students_by(session, mode)
127
128    def __repr__(self):
129        return 'StudentsReport (session=%s, mode=%s)' % (
130            self.session, self.mode)
131
132    #def get_data(self):
133    #    self.data = get_students_by(self.session, self.mode)
134
135    def create_pdf(self):
136        creator = getUtility(IPDFCreator)
137        table_data = tbl_data_to_table(*self.data)
138        col_widths = [None,] + [1.6*cm] * len(self.data[1]) + [None,]
139        creation_dt = self.creation_dt.astimezone(getUtility(IKofaUtils).tzinfo)
140        creation_dt = creation_dt.strftime("%Y-%m-%d %H:%M:%S %Z")
141        pdf_data = [Paragraph('<b>%s</b>' % creation_dt,
142                              STYLE["Normal"]),
143                    Spacer(1, 12),]
144        pdf_data += [
145            Table(table_data, style=TABLE_STYLE, colWidths=col_widths)]
146        doc_title = '%s Students in Session %s' % (self.mode, self.session)
147        pdf = creator.create_pdf(
148            pdf_data, None, doc_title, self.author,
149            'Students in Session %s' % self.session)
150        open('/tmp/result.pdf', 'wb').write(pdf)
151        return pdf
152
153@implementer(IReportGenerator)
154class StudentsReportGenerator(grok.GlobalUtility):
155
156    title = _('Students')
157    grok.name('students_by')
158
159    @property
160    def description(self):
161        return self.title
162
163    def generate(self, site, session=None, mode=None, author=None):
164        result = StudentsReport(session=session, mode=mode, author=author)
165        return result
166
167###############################################################
168## Browser related stuff
169##
170## XXX: move to local browser module
171###############################################################
172from waeup.kofa.browser.layout import KofaPage
173from waeup.kofa.interfaces import academic_sessions_vocab
174from waeup.kofa.reports import get_generators
175grok.templatedir('browser_templates')
176class StudentsReportGeneratorPage(KofaPage):
177
178    grok.context(StudentsReportGenerator)
179    grok.name('index.html')
180    grok.require('waeup.manageReports')
181
182    label = _('Create students report')
183
184    @property
185    def generator_name(self):
186        for name, gen in get_generators():
187            if gen == self.context:
188                return name
189        return None
190
191    def update(self, CREATE=None, session=None, mode=None):
192        self.parent_url = self.url(self.context.__parent__)
193        self._set_session_values()
194        self._set_mode_values()
195        if CREATE and session:
196            # create a new report job for students by session
197            container = self.context.__parent__
198            user_id = self.request.principal.id
199            kw = dict(
200                session=int(session),
201                mode=mode)
202            self.flash(_('New report is being created in background'))
203            container.start_report_job(
204                self.generator_name, user_id, kw=kw)
205            ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
206            grok.getSite().logger.info(
207                '%s - created: %s (session=%s, mode=%s)' % (
208                ob_class, self.context.title, session, mode))
209            self.redirect(self.parent_url)
210            return
211        return
212
213    def _set_session_values(self):
214        vocab_terms = academic_sessions_vocab.by_value.values()
215        self.sessions = [(x.title, x.token) for x in vocab_terms]
216        return
217
218    def _set_mode_values(self):
219        mode_groups = getUtility(IKofaUtils).MODE_GROUPS
220        self.modes = sorted([(key, key) for key in mode_groups.keys()])
221        return
222
223class StudentsReportPDFView(grok.View):
224
225    grok.context(IStudentsReport)
226    grok.name('pdf')
227    grok.require('waeup.Public')
228
229    def render(self):
230        filename = "%s.pdf" % (self.context.__repr__())
231        self.response.setHeader(
232            'Content-Type', 'application/pdf')
233        self.response.setHeader(
234            'Content-Disposition:', 'attachment; filename="%s' % filename)
235        pdf_stream = self.context.create_pdf()
236        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
237        grok.getSite().logger.info('%s - downloaded: %s' % (ob_class, filename))
238        return pdf_stream
Note: See TracBrowser for help on using the repository browser.