source: main/waeup.kofa/trunk/src/waeup/kofa/students/export.py @ 9798

Last change on this file since 9798 was 9797, checked in by uli, 12 years ago

Local exports for departments.

  • Property svn:keywords set to Id
File size: 15.8 KB
RevLine 
[8057]1## $Id: export.py 9797 2012-12-13 15:39:31Z uli $
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##
[7944]18"""Exporters for student related stuff.
19"""
20import grok
[9574]21from datetime import datetime
[7944]22from waeup.kofa.interfaces import MessageFactory as _
[9787]23from waeup.kofa.students.catalog import StudentsQuery
[8015]24from waeup.kofa.students.interfaces import (
[8371]25    IStudent, IStudentStudyCourse, IStudentStudyLevel, ICourseTicket,
[9427]26    IStudentOnlinePayment, ICSVStudentExporter, IBedTicket)
[9787]27from waeup.kofa.students.vocabularies import study_levels
[7944]28from waeup.kofa.utils.batching import ExporterBase
29from waeup.kofa.utils.helpers import iface_names
30
[8400]31#: A tuple containing all exporter names referring to students or
32#: subobjects thereof.
33EXPORTER_NAMES = ('students', 'studentstudycourses', 'studentstudylevels',
34                  'coursetickets', 'studentpayments')
35
[9797]36def ident(x):
37    return x
38    #for item in x:
39    #    yield item
40
[9787]41def get_students(site, stud_filter=StudentsQuery()):
[8414]42    """Get all students registered in catalog in `site`.
[7944]43    """
[9787]44    return stud_filter.query()
[8414]45
46def get_studycourses(students):
47    """Get studycourses of `students`.
48    """
49    return [x.get('studycourse', None) for x in students
50            if x is not None]
51
52def get_levels(students):
53    """Get all studylevels of `students`.
54    """
55    levels = []
56    for course in get_studycourses(students):
57        for level in course.values():
58            levels.append(level)
59    return levels
60
61def get_tickets(students):
62    """Get all course tickets of `students`.
63    """
64    tickets = []
65    for level in get_levels(students):
66        for ticket in level.values():
67            tickets.append(ticket)
68    return tickets
69
70def get_payments(students):
71    """Get all payments of `students`.
72    """
73    payments = []
74    for student in students:
75        for payment in student.get('payments', {}).values():
76            payments.append(payment)
77    return payments
78
[9427]79def get_bedtickets(students):
80    """Get all bedtickets of `students`.
81    """
82    tickets = []
83    for student in students:
84        for ticket in student.get('accommodation', {}).values():
85            tickets.append(ticket)
86    return tickets
[8414]87
88class StudentExporterBase(ExporterBase):
89    """Exporter for students or related objects.
90
91    This is a baseclass.
92    """
93    grok.baseclass()
[8411]94    grok.implements(ICSVStudentExporter)
95    grok.provides(ICSVStudentExporter)
[8414]96
[9797]97    def filter_func(self, x):
98        return get_students(x)
99
100    def get_filtered(self, site, current_session=None,
101                     current_level=None, faccode=None, depcode=None, ):
102        query = StudentsQuery(
103            current_session=current_session,
104            current_level=current_level,
105            faccode=faccode, depcode=depcode)
106        return query.query()
107
[8414]108    def export(self, values, filepath=None):
109        """Export `values`, an iterable, as CSV file.
110
111        If `filepath` is ``None``, a raw string with CSV data is returned.
112        """
113        writer, outfile = self.get_csv_writer(filepath)
114        for value in values:
115            self.write_item(value, writer)
116        return self.close_outfile(filepath, outfile)
117
[9797]118    def export_all(self, site, filepath=None):
119        """Export students into filepath as CSV data.
120
121        If `filepath` is ``None``, a raw string with CSV data is returned.
[9763]122        """
[9797]123        return self.export(self.filter_func(site), filepath)
[8414]124
[9797]125    def export_student(self, student, filepath=None):
126        return self.export(self.filter_func([student]), filepath=filepath)
[9734]127
[9797]128
[8414]129class StudentsExporter(grok.GlobalUtility, StudentExporterBase):
130    """Exporter for Students.
131    """
[7944]132    grok.name('students')
133
134    #: Fieldnames considered by this exporter
[8493]135    fields = tuple(sorted(iface_names(
136        IStudent, omit=['loggerInfo']))) + (
[9253]137        'password', 'state', 'history', 'certcode', 'is_postgrad',
138        'current_level', 'current_session')
[7944]139
140    #: The title under which this exporter will be displayed
141    title = _(u'Students')
142
[8493]143    def mangle_value(self, value, name, context=None):
144        if name == 'history':
145            value = value.messages
[8971]146        if name == 'phone' and value is not None:
147            # Append hash '#' to phone numbers to circumvent
148            # unwanted excel automatic
[8947]149            value = str('%s#' % value)
[8493]150        return super(
151            StudentsExporter, self).mangle_value(
152            value, name, context=context)
153
[7944]154    def export_all(self, site, filepath=None):
155        """Export students into filepath as CSV data.
156
157        If `filepath` is ``None``, a raw string with CSV data is returned.
158        """
[8414]159        return self.export(get_students(site), filepath)
[7994]160
[8411]161    def export_student(self, student, filepath=None):
162        return self.export([student], filepath=filepath)
163
[8414]164class StudentStudyCourseExporter(grok.GlobalUtility, StudentExporterBase):
[7994]165    """Exporter for StudentStudyCourses.
166    """
167    grok.name('studentstudycourses')
168
169    #: Fieldnames considered by this exporter
[8493]170    fields = tuple(sorted(iface_names(IStudentStudyCourse))) + ('student_id',)
[7994]171
172    #: The title under which this exporter will be displayed
173    title = _(u'Student Study Courses')
174
[9797]175    def filter_func(self, x):
176        return get_studycourses(x)
177
[7994]178    def mangle_value(self, value, name, context=None):
[8493]179        """Treat location values special.
[7994]180        """
181        if name == 'certificate' and value is not None:
182            # XXX: hopefully cert codes are unique site-wide
183            value = value.code
[8493]184        if name == 'student_id' and context is not None:
[8736]185            student = context.student
[8493]186            value = getattr(student, name, None)
[7994]187        return super(
188            StudentStudyCourseExporter, self).mangle_value(
189            value, name, context=context)
190
191    def export_all(self, site, filepath=None):
192        """Export study courses into filepath as CSV data.
193
194        If `filepath` is ``None``, a raw string with CSV data is returned.
195        """
[8414]196        return self.export(get_studycourses(get_students(site)), filepath)
[8015]197
[8411]198    def export_student(self, student, filepath=None):
[8414]199        """Export studycourse of a single student object.
200        """
201        return self.export(get_studycourses([student]), filepath)
[8411]202
[9797]203    def export_filtered(self, site, filepath=None, **kw):
204        """Export items denoted by `args` and `kw`.
[8411]205
[9797]206        If `filepath` is ``None``, a raw string with CSV data should
207        be returned.
208        """
209        data = self.get_filtered(site, **kw)
210        return self.export(get_studycourses(data), filepath=filepath)
211
212
[8414]213class StudentStudyLevelExporter(grok.GlobalUtility, StudentExporterBase):
[8015]214    """Exporter for StudentStudyLevels.
215    """
216    grok.name('studentstudylevels')
217
218    #: Fieldnames considered by this exporter
[8493]219    fields = tuple(sorted(iface_names(
[9253]220        IStudentStudyLevel) + ['level'])) + (
221        'student_id', 'number_of_tickets','certcode')
[8015]222
223    #: The title under which this exporter will be displayed
224    title = _(u'Student Study Levels')
225
226    def mangle_value(self, value, name, context=None):
[8493]227        """Treat location values special.
[8015]228        """
[8493]229        if name == 'student_id' and context is not None:
[8736]230            student = context.student
[8493]231            value = getattr(student, name, None)
[8015]232        return super(
233            StudentStudyLevelExporter, self).mangle_value(
234            value, name, context=context)
235
236    def export_all(self, site, filepath=None):
237        """Export study levels into filepath as CSV data.
238
239        If `filepath` is ``None``, a raw string with CSV data is returned.
240        """
[8414]241        return self.export(get_levels(get_students(site)), filepath)
[8342]242
[8411]243    def export_student(self, student, filepath=None):
[8414]244        return self.export(get_levels([student]), filepath)
[8411]245
[9797]246    def export_filtered(self, site, filepath=None, **kw):
247        """Export items denoted by `args` and `kw`.
248
249        If `filepath` is ``None``, a raw string with CSV data should
250        be returned.
251        """
252        data = self.get_filtered(site, **kw)
253        return self.export(get_levels(data), filepath=filepath)
254
[8414]255class CourseTicketExporter(grok.GlobalUtility, StudentExporterBase):
[8342]256    """Exporter for CourseTickets.
257    """
258    grok.name('coursetickets')
259
260    #: Fieldnames considered by this exporter
[8493]261    fields = tuple(sorted(iface_names(ICourseTicket) +
[9420]262        ['level', 'code'])) + ('student_id', 'certcode')
[8342]263
264    #: The title under which this exporter will be displayed
265    title = _(u'Course Tickets')
266
267    def mangle_value(self, value, name, context=None):
268        """Treat location values special.
269        """
270        if context is not None:
[8736]271            student = context.student
[8493]272            if name == 'student_id' and student is not None:
[8342]273                value = getattr(student, name, None)
274            if name == 'level':
[8393]275                value = getattr(context, 'getLevel', lambda: None)()
[8342]276        return super(
277            CourseTicketExporter, self).mangle_value(
278            value, name, context=context)
279
280    def export_all(self, site, filepath=None):
281        """Export course tickets into filepath as CSV data.
282
283        If `filepath` is ``None``, a raw string with CSV data is returned.
284        """
[8414]285        return self.export(get_tickets(get_students(site)), filepath)
[8342]286
[8411]287    def export_student(self, student, filepath=None):
[8414]288        return self.export(get_tickets([student]), filepath)
[8411]289
[9797]290    def export_filtered(self, site, filepath=None, **kw):
291        """Export items denoted by `args` and `kw`.
[8414]292
[9797]293        If `filepath` is ``None``, a raw string with CSV data should
294        be returned.
295        """
296        data = self.get_filtered(site, **kw)
297        return self.export(get_tickets(data), filepath=filepath)
298
299
[8414]300class PaymentsExporter(grok.GlobalUtility, StudentExporterBase):
[8371]301    """Exporter for OnlinePayment instances.
302    """
303    grok.name('studentpayments')
304
305    #: Fieldnames considered by this exporter
306    fields = tuple(
[8493]307        sorted(iface_names(
[9258]308            IStudentOnlinePayment, exclude_attribs=False))) + (
[9278]309                'student_id','student_state','current_session')
[8371]310
311    #: The title under which this exporter will be displayed
[8576]312    title = _(u'Student Payments')
[8371]313
314    def mangle_value(self, value, name, context=None):
315        """Treat location values special.
316        """
317        if context is not None:
[8736]318            student = context.student
[8493]319            if name in ['student_id'] and student is not None:
[8371]320                value = getattr(student, name, None)
321        return super(
322            PaymentsExporter, self).mangle_value(
323            value, name, context=context)
324
325    def export_all(self, site, filepath=None):
326        """Export payments into filepath as CSV data.
327
328        If `filepath` is ``None``, a raw string with CSV data is returned.
329        """
[8414]330        return self.export(get_payments(get_students(site)), filepath)
[8411]331
332    def export_student(self, student, filepath=None):
[8414]333        return self.export(get_payments([student]), filepath)
[9427]334
[9797]335    def export_filtered(self, site, filepath=None, **kw):
336        """Export items denoted by `args` and `kw`.
337
338        If `filepath` is ``None``, a raw string with CSV data should
339        be returned.
340        """
341        data = self.get_filtered(site, **kw)
342        return self.export(get_payments(data), filepath=filepath)
343
[9427]344class BedTicketsExporter(grok.GlobalUtility, StudentExporterBase):
345    """Exporter for BedTicket instances.
346    """
347    grok.name('bedtickets')
348
349    #: Fieldnames considered by this exporter
350    fields = tuple(
351        sorted(iface_names(
352            IBedTicket, exclude_attribs=False))) + (
353                'student_id', 'actual_bed_type')
354
355    #: The title under which this exporter will be displayed
356    title = _(u'Bed Tickets')
357
358    def mangle_value(self, value, name, context=None):
359        """Treat location values and others special.
360        """
361        if context is not None:
362            student = context.student
363            if name in ['student_id'] and student is not None:
364                value = getattr(student, name, None)
365        if name == 'bed' and value is not None:
366            value = getattr(value, 'bed_id', None)
367        if name == 'actual_bed_type':
368            value = getattr(getattr(context, 'bed', None), 'bed_type')
369        return super(
370            BedTicketsExporter, self).mangle_value(
371            value, name, context=context)
372
373    def export_all(self, site, filepath=None):
374        """Export payments into filepath as CSV data.
375
376        If `filepath` is ``None``, a raw string with CSV data is returned.
377        """
378        return self.export(get_bedtickets(get_students(site)), filepath)
379
380    def export_student(self, student, filepath=None):
381        return self.export(get_bedtickets([student]), filepath)
[9574]382
[9797]383    def export_filtered(self, site, filepath=None, **kw):
384        """Export items denoted by `args` and `kw`.
385
386        If `filepath` is ``None``, a raw string with CSV data should
387        be returned.
388        """
389        data = self.get_filtered(site, **kw)
390        return self.export(get_bedtickets(data), filepath=filepath)
391
[9574]392class StudentPaymentsOverviewExporter(StudentsExporter):
393    """Exporter for students with payment overview.
394    """
395    grok.name('paymentsoverview')
396
397    curr_year = datetime.now().year
398    year_range = range(curr_year - 9, curr_year + 1)
399    year_range_tuple = tuple([str(year) for year in year_range])
400
401    #: Fieldnames considered by this exporter
402    fields = ('student_id', ) + (
403        'state', 'certcode', 'faccode', 'depcode', 'is_postgrad',
404        'current_level', 'current_session',
405        ) + year_range_tuple
406
407    #: The title under which this exporter will be displayed
408    title = _(u'Student Payments Overview')
409
410    def mangle_value(self, value, name, context=None):
411        if name in self.year_range_tuple and context is not None:
412            value = ''
413            for ticket in context['payments'].values():
414                if ticket.p_state == 'paid' and \
415                    ticket.p_category == 'schoolfee' and \
416                    ticket.p_session == int(name):
417                    value = ticket.amount_auth
418                    break
419        return super(
420            StudentsExporter, self).mangle_value(
[9734]421            value, name, context=context)
[9744]422
423class StudentStudyLevelsOverviewExporter(StudentsExporter):
424    """Exporter for students with study level overview.
425    """
426    grok.name('studylevelsoverview')
427
[9787]428    avail_levels = tuple([str(x) for x in study_levels(None)])
[9744]429
430    #: Fieldnames considered by this exporter
431    fields = ('student_id', ) + (
432        'state', 'certcode', 'faccode', 'depcode', 'is_postgrad',
[9761]433        'entry_session', 'current_level', 'current_session',
[9787]434        ) + avail_levels
[9744]435
436    #: The title under which this exporter will be displayed
437    title = _(u'Student Study Levels Overview')
438
439    def mangle_value(self, value, name, context=None):
[9787]440        if name in self.avail_levels and context is not None:
[9744]441            value = ''
442            for level in context['studycourse'].values():
443                if level.level == int(name):
[9761]444                    #value = '%s|%s|%s|%s' % (
445                    #    level.level_session,
446                    #    len(level),
447                    #    level.validated_by,
448                    #    level.level_verdict)
449                    value = '%s' % level.level_session
[9744]450                    break
451        return super(
452            StudentsExporter, self).mangle_value(
453            value, name, context=context)
Note: See TracBrowser for help on using the repository browser.