source: main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/applicants/export.py @ 17937

Last change on this file since 17937 was 13968, checked in by Henrik Bettermann, 9 years ago

Make provision against storing other objects than applicant payments in applicant containers.

  • Property svn:keywords set to Id
File size: 9.2 KB
Line 
1## $Id: export.py 13968 2016-06-22 04:39:50Z henrik $
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##
18"""Exporters for applicant-related stuff.
19"""
20import grok
21from zope.catalog.interfaces import ICatalog
22from zope.component import queryUtility
23from waeup.kofa.applicants.interfaces import (
24    IApplicantBaseData, IApplicantsContainer, IApplicantOnlinePayment)
25from waeup.kofa.interfaces import ICSVExporter
26from waeup.kofa.interfaces import MessageFactory as _
27from waeup.kofa.utils.batching import ExporterBase
28from waeup.kofa.utils.helpers import iface_names
29
30class ApplicantsContainerExporter(grok.GlobalUtility, ExporterBase):
31    """The Applicants Container Exporter exports container data. It does not
32    export applicants (application records) inside the container.
33    """
34    grok.implements(ICSVExporter)
35    grok.name('applicantscontainers')
36
37    fields = tuple(sorted(iface_names(IApplicantsContainer)))
38    title = _(u'Applicants Containers')
39
40    def mangle_value(self, value, name, context=None):
41        return super(
42            ApplicantsContainerExporter, self).mangle_value(
43            value, name, context=context)
44
45    def export(self, containers, filepath=None):
46        """Export `containers`, an iterable, as CSV file.
47
48        If `filepath` is ``None``, a raw string with CSV data is returned.
49        """
50        writer, outfile = self.get_csv_writer(filepath)
51        for container in containers:
52            self.write_item(container, writer)
53        return self.close_outfile(filepath, outfile)
54
55    def export_all(self, site, filepath=None):
56        """Export applicantscontainer into filepath as CSV data.
57
58        If `filepath` is ``None``, a raw string with CSV data is returned.
59        """
60        writer, outfile = self.get_csv_writer(filepath)
61        containers = site.get('applicants', {})
62        return self.export(containers.values(), filepath)
63
64
65class ApplicantExporter(grok.GlobalUtility, ExporterBase):
66    """The Applicant Exporter exports application records (= applicants)
67    stored in the database. In contrast to the exporters in the academic
68    section this exporter does not iterate over the items of containers
69    but searches the :class:`ApplicantsCatalog` instead.
70
71    The exporter exports all applicants if started in the Data Center
72    which means in the context of the `DataCenter` object. The exporter can also
73    be started 'locally' which means in the context of an `ApplicantsContainer`
74    container. Then the :meth:`export_filtered()` instead of the
75    :meth:`export_all()` method is applied which searches for applicants
76    in the respective container.
77    """
78    grok.implements(ICSVExporter)
79    grok.name('applicants')
80
81    fields = tuple(sorted(iface_names(IApplicantBaseData))) + (
82        'password', 'state', 'history', 'container_code', 'application_number',
83        'display_fullname', 'application_date')
84    title = _(u'Applicants')
85
86    def mangle_value(self, value, name, context=None):
87        """The mangler determines the codes of the atributes `course1`,
88        `course2` and `course_admitted`. It furthermore prepares the
89        history messages and adds a hash symbol at the end of the phone number
90        to avoid annoying automatic number transformation by Excel or Calc.
91        """
92        if name.startswith('course') and value is not None:
93            value = value.code
94        #elif name == 'school_grades':
95        #    value = [eval(entry.to_string()) for entry in value]
96        elif name == 'history':
97            value = value.messages
98        elif name == 'phone' and value is not None:
99            # Append hash '#' to phone numbers to circumvent
100            # unwanted excel automatic
101            value = str('%s#' % value)
102        elif name == 'container_code':
103            value = value.strip('+')
104        return super(
105            ApplicantExporter, self).mangle_value(
106            value, name, context=context)
107
108    def export(self, applicants, filepath=None):
109        """Export `applicants`, an iterable, as CSV file.
110        If `filepath` is ``None``, a raw string with CSV data is returned.
111        """
112        writer, outfile = self.get_csv_writer(filepath)
113        for applicant in applicants:
114            self.write_item(applicant, writer)
115        return self.close_outfile(filepath, outfile)
116
117    def export_all(self, site, filepath=None):
118        """Export all applicants into filepath as CSV data.
119        If `filepath` is ``None``, a raw string with CSV data is returned.
120        Only used records are being exported.
121        """
122        catalog = queryUtility(
123            ICatalog, context=site, name='applicants_catalog', default=None)
124        if catalog is None:
125            return self.export([], filepath)
126        applicants = catalog.searchResults(
127            # reg_num might not be set and then would not be found.
128            # We therefore search for applicant_id.
129            applicant_id=(None, None))
130        used = [value for value in applicants
131                if value.container_code.endswith('+')]
132        return self.export(used, filepath=filepath)
133
134    def export_filtered(self, site, filepath=None, **kw):
135        """Export filtered applicants in container denoted by keywords (`kw`).
136        If `filepath` is ``None``, a raw string with CSV data should
137        be returned. Only used records are being exported.
138        """
139        container = grok.getSite()['applicants'][kw['container']]
140        container_values = container.values()
141        used = [value for value in container_values
142                if value.container_code.endswith('+')]
143        return self.export(used, filepath=filepath)
144
145
146class ApplicantPaymentExporter(grok.GlobalUtility, ExporterBase):
147    """The Applicant Payments Exporter exports all payments made by applicants.
148    In other words, it exports payment tickets in state 'paid'. The exporter
149    searches :class:`ApplicantsCatalog` and iterates over all payment tickets
150    which are stored in an applicant (container).
151
152    The exporter exports all applicant payments if started in the Data Center
153    which means in the context of the `DataCenter` object. The exporter can also
154    be started 'locally' which means in the context of an
155    `ApplicantsContainer` container, see `ApplicantExporter` above.
156    """
157    grok.implements(ICSVExporter)
158    grok.name('applicantpayments')
159
160    fields = tuple(sorted(iface_names(
161        IApplicantOnlinePayment,
162        exclude_attribs=False,
163        omit=['display_item']))) + (
164              'applicant_id',
165              'reg_number',
166              'display_fullname',)
167    title = _(u'Applicant Payments')
168
169    def mangle_value(self, value, name, context=None):
170        """The mangler determines the applicant's id.
171        """
172        if name in ('applicant_id', 'reg_number',
173            'display_fullname',) and context is not None:
174            applicant = context.__parent__
175            value = getattr(applicant, name, None)
176        return super(
177            ApplicantPaymentExporter, self).mangle_value(
178            value, name, context=context)
179
180    def export(self, payments, filepath=None):
181        """
182        """
183        writer, outfile = self.get_csv_writer(filepath)
184        for payment in payments:
185            self.write_item(payment, writer)
186        return self.close_outfile(filepath, outfile)
187
188    def export_all(self, site, filepath=None):
189        """
190        """
191        catalog = queryUtility(
192            ICatalog, context=site, name='applicants_catalog', default=None)
193        if catalog is None:
194            return self.export([], filepath)
195        applicants = catalog.searchResults(
196            # reg_num might not be set and then would not be found.
197            # We therefore search for applicant_id.
198            applicant_id=(None, None))
199        used = [value for value in applicants
200                if value.container_code.endswith('+')]
201        payments = []
202        for applicant in used:
203            for payment in applicant.payments:
204                if payment.p_state == 'paid':
205                    payments.append(payment)
206        return self.export(payments, filepath=filepath)
207
208    def export_filtered(self, site, filepath=None, **kw):
209        """
210        """
211        container = grok.getSite()['applicants'][kw['container']]
212        container_values = container.values()
213        used = [value for value in container_values
214                if value.container_code.endswith('+')]
215        payments = []
216        for applicant in used:
217            for payment in applicant.payments:
218                if payment.p_state == 'paid':
219                    payments.append(payment)
220        return self.export(payments, filepath=filepath)
Note: See TracBrowser for help on using the repository browser.