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

Last change on this file since 9674 was 9673, checked in by uli, 12 years ago

Remove useless report title.

File size: 8.7 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._creation_dt_string = self.creation_dt.astimezone(
127            getUtility(IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z")
128        self.data = get_students_by(session, mode)
129
130    def create_pdf(self):
131        creator = getUtility(IPDFCreator)
132        table_data = tbl_data_to_table(*self.data)
133        col_widths = [None,] + [1.6*cm] * len(self.data[1]) + [None,]
134        pdf_data = [Paragraph('<b>%s</b>' % self._creation_dt_string,
135                              STYLE["Normal"]),
136                    Spacer(1, 12),]
137        pdf_data += [
138            Table(table_data, style=TABLE_STYLE, colWidths=col_widths)]
139        doc_title = '%s Students in Session %s' % (self.mode, self.session)
140        pdf = creator.create_pdf(
141            pdf_data, None, doc_title, self.author,
142            'Students in Session %s' % self.session)
143        return pdf
144
145@implementer(IReportGenerator)
146class StudentsReportGenerator(grok.GlobalUtility):
147
148    title = _('Students')
149    grok.name('students_by')
150
151    def generate(self, site, session=None, mode=None, author=None):
152        result = StudentsReport(session=session, mode=mode, author=author)
153        return result
154
155###############################################################
156## Browser related stuff
157##
158## XXX: move to local browser module
159###############################################################
160from waeup.kofa.browser.layout import KofaPage
161from waeup.kofa.interfaces import academic_sessions_vocab
162from waeup.kofa.reports import get_generators
163grok.templatedir('browser_templates')
164class StudentsReportGeneratorPage(KofaPage):
165
166    grok.context(StudentsReportGenerator)
167    grok.name('index.html')
168    grok.require('waeup.manageReports')
169
170    label = _('Create students report')
171
172    @property
173    def generator_name(self):
174        for name, gen in get_generators():
175            if gen == self.context:
176                return name
177        return None
178
179    def update(self, CREATE=None, session=None, mode=None):
180        self.parent_url = self.url(self.context.__parent__)
181        self._set_session_values()
182        self._set_mode_values()
183        if CREATE and session:
184            # create a new report job for students by session
185            container = self.context.__parent__
186            user_id = self.request.principal.id
187            kw = dict(
188                session=int(session),
189                mode=mode)
190            self.flash(_('New report is being created in background'))
191            container.start_report_job(
192                self.generator_name, user_id, kw=kw)
193            ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
194            grok.getSite().logger.info(
195                '%s - created: %s (session=%s, mode=%s)' % (
196                ob_class, self.context.title, session, mode))
197            self.redirect(self.parent_url)
198            return
199        return
200
201    def _set_session_values(self):
202        vocab_terms = academic_sessions_vocab.by_value.values()
203        self.sessions = [(x.title, x.token) for x in vocab_terms]
204        return
205
206    def _set_mode_values(self):
207        mode_groups = getUtility(IKofaUtils).MODE_GROUPS
208        self.modes = sorted([(key, key) for key in mode_groups.keys()])
209        return
210
211class StudentsReportPDFView(grok.View):
212
213    grok.context(IStudentsReport)
214    grok.name('pdf')
215    grok.require('waeup.Public')
216
217    def render(self):
218        filename = 'StudentsReport_%s_%s_%s.pdf' % (
219            self.context.session, self.context.mode,
220            self._creation_dt_string)
221        filename = filename.replace(
222            '/', '_').replace(' ','_').replace(':', '-')
223        self.response.setHeader(
224            'Content-Type', 'application/pdf')
225        self.response.setHeader(
226            'Content-Disposition:', 'attachment; filename="%s' % filename)
227        pdf_stream = self.context.create_pdf()
228        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
229        grok.getSite().logger.info('%s - downloaded: %s' % (ob_class, filename))
230        return pdf_stream
Note: See TracBrowser for help on using the repository browser.