source: main/waeup.kofa/trunk/src/waeup/kofa/applicants/export.py @ 17958

Last change on this file since 17958 was 17760, checked in by Henrik Bettermann, 6 months ago

Mangle referees and school grades.

  • Property svn:keywords set to Id
File size: 12.1 KB
RevLine 
[7865]1## $Id: export.py 17760 2024-05-11 07:45:54Z 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
[7914]21from zope.catalog.interfaces import ICatalog
22from zope.component import queryUtility
[8724]23from waeup.kofa.applicants.interfaces import (
[16064]24    IApplicantBaseData, IApplicantsContainer, IApplicantOnlinePayment,
[17760]25    IApplicantRefereeReport, IApplicant)
[7865]26from waeup.kofa.interfaces import ICSVExporter
[7906]27from waeup.kofa.interfaces import MessageFactory as _
[7865]28from waeup.kofa.utils.batching import ExporterBase
[8724]29from waeup.kofa.utils.helpers import iface_names
[7865]30
31class ApplicantsContainerExporter(grok.GlobalUtility, ExporterBase):
[12859]32    """The Applicants Container Exporter exports container data. It does not
33    export applicants (application records) inside the container.
[7865]34    """
35    grok.implements(ICSVExporter)
36    grok.name('applicantscontainers')
37
[8724]38    fields = tuple(sorted(iface_names(IApplicantsContainer)))
[12180]39    title = _(u'Applicants Containers')
[7906]40
41    def mangle_value(self, value, name, context=None):
42        return super(
43            ApplicantsContainerExporter, self).mangle_value(
44            value, name, context=context)
45
[7865]46    def export(self, containers, filepath=None):
47        """Export `containers`, an iterable, as CSV file.
48
49        If `filepath` is ``None``, a raw string with CSV data is returned.
50        """
51        writer, outfile = self.get_csv_writer(filepath)
52        for container in containers:
53            self.write_item(container, writer)
54        return self.close_outfile(filepath, outfile)
55
56    def export_all(self, site, filepath=None):
57        """Export applicantscontainer into filepath as CSV data.
58
59        If `filepath` is ``None``, a raw string with CSV data is returned.
60        """
61        writer, outfile = self.get_csv_writer(filepath)
62        containers = site.get('applicants', {})
63        return self.export(containers.values(), filepath)
[7914]64
[12859]65
[12079]66class ApplicantExporter(grok.GlobalUtility, ExporterBase):
[12861]67    """The Applicant Exporter exports application records (= applicants)
[12862]68    stored in the database. In contrast to the exporters in the academic
[12859]69    section this exporter does not iterate over the items of containers
[12861]70    but searches the :class:`ApplicantsCatalog` instead.
71
72    The exporter exports all applicants if started in the Data Center
73    which means in the context of the `DataCenter` object. The exporter can also
74    be started 'locally' which means in the context of an `ApplicantsContainer`
75    container. Then the :meth:`export_filtered()` instead of the
76    :meth:`export_all()` method is applied which searches for applicants
77    in the respective container.
[7914]78    """
79    grok.implements(ICSVExporter)
80    grok.name('applicants')
81
[17760]82    fields = tuple(sorted(iface_names(IApplicant))) + (
[13080]83        'password', 'state', 'history', 'container_code', 'application_number',
84        'display_fullname', 'application_date')
[7914]85    title = _(u'Applicants')
86
[7924]87    def mangle_value(self, value, name, context=None):
[12865]88        """The mangler determines the codes of the atributes `course1`,
[12859]89        `course2` and `course_admitted`. It furthermore prepares the
90        history messages and adds a hash symbol at the end of the phone number
91        to avoid annoying automatic number transformation by Excel or Calc.
92        """
[13542]93        if name.startswith('course') and value is not None:
[7924]94            value = value.code
[17760]95        elif name == 'school_grades' and value is not None:
96            value = [eval(entry.to_string()) for entry in value]
97        elif name == 'referees' and value is not None:
98            value = [eval(entry.to_string()) for entry in value]
[8052]99        elif name == 'history':
[15156]100            value = getattr(value, 'messages', None)
[9117]101        elif name == 'phone' and value is not None:
102            # Append hash '#' to phone numbers to circumvent
103            # unwanted excel automatic
104            value = str('%s#' % value)
[13216]105        elif name == 'container_code':
106            value = value.strip('+')
[7914]107        return super(
[12079]108            ApplicantExporter, self).mangle_value(
[7914]109            value, name, context=context)
110
111    def export(self, applicants, filepath=None):
112        """Export `applicants`, an iterable, as CSV file.
113        If `filepath` is ``None``, a raw string with CSV data is returned.
114        """
115        writer, outfile = self.get_csv_writer(filepath)
116        for applicant in applicants:
117            self.write_item(applicant, writer)
118        return self.close_outfile(filepath, outfile)
119
120    def export_all(self, site, filepath=None):
[12861]121        """Export all applicants into filepath as CSV data.
[7914]122        If `filepath` is ``None``, a raw string with CSV data is returned.
[13216]123        Only used records are being exported.
[7914]124        """
125        catalog = queryUtility(
126            ICatalog, context=site, name='applicants_catalog', default=None)
127        if catalog is None:
128            return self.export([], filepath)
129        applicants = catalog.searchResults(
[7924]130            # reg_num might not be set and then would not be found.
131            # We therefore search for applicant_id.
132            applicant_id=(None, None))
[13949]133        used = [value for value in applicants
134                if value.container_code.endswith('+')]
[13216]135        return self.export(used, filepath=filepath)
[10653]136
137    def export_filtered(self, site, filepath=None, **kw):
[12861]138        """Export filtered applicants in container denoted by keywords (`kw`).
[10653]139        If `filepath` is ``None``, a raw string with CSV data should
[13216]140        be returned. Only used records are being exported.
[10653]141        """
[10654]142        container = grok.getSite()['applicants'][kw['container']]
[13216]143        container_values = container.values()
[13949]144        used = [value for value in container_values
145                if value.container_code.endswith('+')]
[13216]146        return self.export(used, filepath=filepath)
[13949]147
148
149class ApplicantPaymentExporter(grok.GlobalUtility, ExporterBase):
[16064]150    """The Applicant Payment Exporter exports all payments made by applicants.
[13949]151    In other words, it exports payment tickets in state 'paid'. The exporter
152    searches :class:`ApplicantsCatalog` and iterates over all payment tickets
153    which are stored in an applicant (container).
154
155    The exporter exports all applicant payments if started in the Data Center
156    which means in the context of the `DataCenter` object. The exporter can also
157    be started 'locally' which means in the context of an
158    `ApplicantsContainer` container, see `ApplicantExporter` above.
159    """
160    grok.implements(ICSVExporter)
161    grok.name('applicantpayments')
162
163    fields = tuple(sorted(iface_names(
164        IApplicantOnlinePayment,
165        exclude_attribs=False,
[16431]166        omit=['display_item', 'p_option']))) + (
[13952]167              'applicant_id',
168              'reg_number',
169              'display_fullname',)
[13949]170    title = _(u'Applicant Payments')
171
172    def mangle_value(self, value, name, context=None):
173        """The mangler determines the applicant's id.
174        """
[13952]175        if name in ('applicant_id', 'reg_number',
176            'display_fullname',) and context is not None:
[13949]177            applicant = context.__parent__
178            value = getattr(applicant, name, None)
179        return super(
180            ApplicantPaymentExporter, self).mangle_value(
181            value, name, context=context)
182
183    def export(self, payments, filepath=None):
184        """
185        """
186        writer, outfile = self.get_csv_writer(filepath)
187        for payment in payments:
188            self.write_item(payment, writer)
189        return self.close_outfile(filepath, outfile)
190
191    def export_all(self, site, filepath=None):
192        """
193        """
194        catalog = queryUtility(
195            ICatalog, context=site, name='applicants_catalog', default=None)
196        if catalog is None:
197            return self.export([], filepath)
198        applicants = catalog.searchResults(
199            # reg_num might not be set and then would not be found.
200            # We therefore search for applicant_id.
201            applicant_id=(None, None))
202        used = [value for value in applicants
203                if value.container_code.endswith('+')]
204        payments = []
205        for applicant in used:
[13968]206            for payment in applicant.payments:
[13949]207                if payment.p_state == 'paid':
208                    payments.append(payment)
209        return self.export(payments, filepath=filepath)
210
211    def export_filtered(self, site, filepath=None, **kw):
212        """
213        """
214        container = grok.getSite()['applicants'][kw['container']]
215        container_values = container.values()
216        used = [value for value in container_values
217                if value.container_code.endswith('+')]
218        payments = []
219        for applicant in used:
[13968]220            for payment in applicant.payments:
[13949]221                if payment.p_state == 'paid':
222                    payments.append(payment)
[16064]223        return self.export(payments, filepath=filepath)
224
225class ApplicantRefereeReportExporter(grok.GlobalUtility, ExporterBase):
226    """The Applicant Referee Report Exporter exports all referee reports.
227    The exportersearches :class:`ApplicantsCatalog` and iterates over all
228    referee reports which are stored in an applicant (container).
229
230    The exporter exports all referee reports if started in the Data Center
231    which means in the context of the `DataCenter` object. The exporter can also
232    be started 'locally' which means in the context of an
233    `ApplicantsContainer` container, see `ApplicantExporter` above.
234    """
235    grok.implements(ICSVExporter)
236    grok.name('applicantrefereereports')
237
238    fields = tuple(sorted(iface_names(
239        IApplicantRefereeReport,
[16066]240        exclude_attribs=False))) + (
[16064]241              'applicant_id',
242              'reg_number',
243              'display_fullname',)
244    title = _(u'Applicant Referee Reports')
245
246    def mangle_value(self, value, name, context=None):
247        """The mangler determines the applicant's id.
248        """
249        if name in ('applicant_id', 'reg_number',
250            'display_fullname',) and context is not None:
251            applicant = context.__parent__
252            value = getattr(applicant, name, None)
253        return super(
254            ApplicantRefereeReportExporter, self).mangle_value(
255            value, name, context=context)
256
[16065]257    def export(self, refereereports, filepath=None):
[16064]258        """
259        """
260        writer, outfile = self.get_csv_writer(filepath)
[16065]261        for refereereport in refereereports:
262            self.write_item(refereereport, writer)
[16064]263        return self.close_outfile(filepath, outfile)
264
265    def export_all(self, site, filepath=None):
266        """
267        """
268        catalog = queryUtility(
269            ICatalog, context=site, name='applicants_catalog', default=None)
270        if catalog is None:
271            return self.export([], filepath)
272        applicants = catalog.searchResults(
273            # reg_num might not be set and then would not be found.
274            # We therefore search for applicant_id.
275            applicant_id=(None, None))
276        refereereports = []
277        for applicant in applicants:
278            for refereereport in applicant.refereereports:
279                refereereports.append(refereereport)
[16069]280        return self.export(refereereports, filepath=filepath)
[16064]281
282    def export_filtered(self, site, filepath=None, **kw):
283        """
284        """
285        container = grok.getSite()['applicants'][kw['container']]
286        container_values = container.values()
287        refereereports = []
288        for applicant in container_values:
289            for refereereport in applicant.refereereports:
290                refereereports.append(refereereport)
291        return self.export(refereereports, filepath=filepath)
Note: See TracBrowser for help on using the repository browser.