source: main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py @ 8059

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

Remove all ApplicantsContainerProvider? components. Experience has shown that we only need one type of ApplicantsContainers? and one type of Applicants but with different interfaces for form generation.

  • Property svn:keywords set to Id
File size: 6.6 KB
Line 
1## $Id: batching.py 8008 2012-03-30 10:23:32Z henrik $
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##
18"""Batch processing for applicants.
19"""
20import csv
21import grok
22from zope.schema import getFields
23from zope.interface import Interface
24from zope.component import queryUtility
25from zope.catalog.interfaces import ICatalog
26from waeup.kofa.interfaces import (
27    IBatchProcessor, IObjectConverter, FatalCSVError)
28from waeup.kofa.utils.batching import BatchProcessor
29from waeup.kofa.applicants.interfaces import (
30    IApplicantsContainer, IApplicant, IApplicantUpdateByRegNo)
31
32class ApplicantsContainerProcessor(BatchProcessor):
33    """A processor for applicants containers.
34    """
35    grok.implements(IBatchProcessor)
36    grok.provides(IBatchProcessor)
37    grok.context(Interface)
38    util_name = 'applicants container processor'
39    grok.name(util_name)
40
41    name = u'Applicants Container Processor'
42    mode = u'create'
43    iface = IApplicantsContainer
44
45    location_fields = ['code',]
46    factory_name = 'waeup.ApplicantsContainer'
47
48    def parentsExist(self, row, site):
49        return 'applicants' in site.keys()
50
51    def entryExists(self, row, site):
52        return row['code'] in site['applicants'].keys()
53
54    def getParent(self, row, site):
55        return site['applicants']
56
57    def getEntry(self, row, site):
58        if not self.entryExists(row, site):
59            return None
60        parent = self.getParent(row, site)
61        return parent.get(row['code'])
62
63    def addEntry(self, obj, row, site):
64        parent = self.getParent(row, site)
65        parent[row['code']] = obj
66        return
67
68    def delEntry(self, row, site):
69        parent = self.getParent(row, site)
70        del parent[row['code']]
71        return
72
73class ApplicantProcessor(BatchProcessor):
74    """A batch processor for IApplicant objects.
75    """
76    grok.implements(IBatchProcessor)
77    grok.provides(IBatchProcessor)
78    grok.context(Interface)
79    util_name = 'applicantprocessor'
80    grok.name(util_name)
81    name = u'Applicant Processor'
82    iface = IApplicant
83    location_fields = ['container_code']
84    factory_name = 'waeup.Applicant'
85
86    mode = None
87
88    @property
89    def available_fields(self):
90        return sorted(list(set(
91            ['application_number','reg_number','container_code'] + getFields(
92                self.iface).keys())))
93
94    def checkHeaders(self, headerfields, mode='create'):
95        if not 'reg_number' in headerfields and not 'application_number' \
96            in headerfields:
97            raise FatalCSVError(
98                "Need at least columns application_number or reg_number ")
99        if mode == 'create':
100            for field in self.required_fields:
101                if not field in headerfields:
102                    raise FatalCSVError(
103                        "Need at least columns %s for import!" %
104                        ', '.join(["'%s'" % x for x in self.required_fields]))
105        # Check for fields to be ignored...
106        not_ignored_fields = [x for x in headerfields
107                              if not x.startswith('--')]
108        if len(set(not_ignored_fields)) < len(not_ignored_fields):
109            raise FatalCSVError(
110                "Double headers: each column name may only appear once.")
111        return True
112
113    def getLocator(self, row):
114        #if 'application_number' in row.keys() and row['application_number']:
115        if row.get('application_number',None):
116            return 'application_number'
117        elif 'reg_number' in row.keys() and row['reg_number']:
118            return 'reg_number'
119        else:
120            return None
121
122    def getParent(self, row, site):
123        if not 'applicants' in site.keys():
124            return False
125        return site['applicants'][row['container_code']]
126
127    def parentsExist(self, row, site):
128        return self.getParent(row, site) is not None
129
130    def getEntry(self, row, site):
131        if not self.parentsExist(row, site):
132            return None
133        parent = self.getParent(row, site)
134        if self.getLocator(row) == 'application_number':
135            if row['application_number'] in parent:
136                applicant = parent[row['application_number']]
137                return applicant
138        elif self.getLocator(row) == 'reg_number':
139            reg_number = row['reg_number']
140            cat = queryUtility(ICatalog, name='applicants_catalog')
141            results = list(
142                cat.searchResults(reg_number=(reg_number, reg_number)))
143            if results:
144                return results[0]
145        return None
146
147    def entryExists(self, row, site):
148        return self.getEntry(row, site) is not None
149
150    def addEntry(self, obj, row, site):
151        parent = self.getParent(row, site)
152        parent.addApplicant(obj)
153        return
154
155    def delEntry(self, row, site):
156        applicant = self.getEntry(row, site)
157        if applicant is not None:
158            parent = self.getParent(row, site)
159            del parent[applicant.application_number]
160        pass
161
162    def getMapping(self, path, headerfields, mode):
163        """Get a mapping from CSV file headerfields to actually used fieldnames.
164        """
165        result = dict()
166        reader = csv.reader(open(path, 'rb'))
167        raw_header = reader.next()
168        for num, field in enumerate(headerfields):
169            if field not in ['container_code',
170                'application_number', 'reg_number'] and mode == 'remove':
171                continue
172            if field == u'--IGNORE--':
173                # Skip ignored columns in failed and finished data files.
174                continue
175            result[raw_header[num]] = field
176        return result
177
178    def checkConversion(self, row, mode='create'):
179        """Validates all values in row.
180        """
181        if mode in ['update', 'remove']:
182            if self.getLocator(row) == 'reg_number':
183                iface = IApplicantUpdateByRegNo
184        else:
185            iface = self.iface
186        converter = IObjectConverter(iface)
187        errs, inv_errs, conv_dict =  converter.fromStringDict(
188            row, self.factory_name)
189        return errs, inv_errs, conv_dict
Note: See TracBrowser for help on using the repository browser.