source: main/waeup.kofa/trunk/src/waeup/kofa/accesscodes/batching.py @ 9544

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

Fix typo.

  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1## $Id: batching.py 9269 2012-10-02 07:42:27Z 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 components for accesscodes.
19
20"""
21import grok
22from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
23from zope.interface import Interface
24from waeup.kofa.interfaces import (
25    IBatchProcessor, IGNORE_MARKER, IObjectHistory, IObjectConverter)
26from waeup.kofa.utils.batching import BatchProcessor
27from waeup.kofa.accesscodes.interfaces import IAccessCodeBatch, IAccessCode
28from waeup.kofa.accesscodes.workflow import INITIALIZED, USED, DISABLED
29
30IMPORTABLE_TRANSITIONS = (
31    'init', 'use', 'disable_used', 'disable_unused', 'reeanble')
32
33IMPORTABLE_STATES = (INITIALIZED, USED, DISABLED)
34
35class AccessCodeBatchProcessor(BatchProcessor):
36    """A batch processor for IAccessCodeBatch objects.
37    """
38    grok.implements(IBatchProcessor)
39    grok.provides(IBatchProcessor)
40    grok.context(Interface)
41    util_name = 'accesscodebatchprocessor'
42    grok.name(util_name)
43
44    name = u'AccessCodeBatch Processor'
45    iface = IAccessCodeBatch
46
47    location_fields = ['batch_id',]
48    factory_name = 'waeup.AccessCodeBatch'
49
50    mode = None
51
52    def parentsExist(self, row, site):
53        return 'accesscodes' in site.keys()
54
55    def entryExists(self, row, site):
56        return row['batch_id'] in site['accesscodes'].keys()
57
58    def getParent(self, row, site):
59        return site['accesscodes']
60
61    def getEntry(self, row, site):
62        if not self.entryExists(row, site):
63            return None
64        parent = self.getParent(row, site)
65        return parent.get(row['batch_id'])
66
67    def addEntry(self, obj, row, site):
68        parent = self.getParent(row, site)
69        parent.addBatchByImport(obj, row['batch_id'])
70        return
71
72    def updateEntry(self, obj, row, site):
73        """Update obj to the values given in row.
74
75        Returns a string describing the fields changed.
76        """
77        items_changed = super(AccessCodeBatchProcessor, self).updateEntry(
78            obj, row, site)
79        # Log actions...
80        location_field = self.location_fields[0]
81        grok.getSite()['accesscodes'].logger.info('%s - %s - Batch updated: %s'
82            % (self.name, row[location_field], items_changed))
83        return
84
85class AccessCodeProcessor(BatchProcessor):
86    """A batch processor for IAccessCode objects.
87    """
88    grok.implements(IBatchProcessor)
89    grok.provides(IBatchProcessor)
90    grok.context(Interface)
91    util_name = 'accesscodeprocessor'
92    grok.name(util_name)
93
94    name = u'AccessCode Processor'
95    iface = IAccessCode
96
97    location_fields = ['representation', 'batch_prefix', 'batch_num']
98    factory_name = 'waeup.AccessCode'
99
100    mode = None
101
102    @property
103    def available_fields(self):
104        return sorted(list(set(
105                    self.location_fields + [
106                        'random_num', 'owner', 'cost',
107                        'state', 'transition', 'batch_serial',]
108                    )))
109
110    @property
111    def required_fields(self):
112        return ['random_num', 'batch_serial', 'history',]
113
114    def parentsExist(self, row, site):
115        return self.getParent(row,site) is not None
116
117    def entryExists(self, row, site):
118        parent = self.getParent(row, site)
119        if parent is None:
120            return False
121        return row['representation'] in parent.keys()
122
123    def getParent(self, row, site):
124        if not 'accesscodes' in site.keys():
125            return None
126        batch_id = '%s-%s' % (row['batch_prefix'], row['batch_num'])
127        return site['accesscodes'].get(batch_id, None)
128
129    def getEntry(self, row, site):
130        if not self.entryExists(row, site):
131            return None
132        parent = self.getParent(row, site)
133        return parent.get(row['representation'], None)
134
135    def addEntry(self, obj, row, site):
136        parent = self.getParent(row, site)
137        obj.batch_serial = row['batch_serial']
138        obj.random_num = row['random_num']
139        parent[row['representation']] = obj
140        return
141
142    def checkConversion(self, row, mode='create'):
143        """Validates all values in row.
144        """
145        converter = IObjectConverter(self.iface)
146        errs, inv_errs, conv_dict =  converter.fromStringDict(
147            row, self.factory_name, mode=mode)
148        if row.has_key('transition') and row.has_key('state'):
149            if row['transition'] not in (IGNORE_MARKER, '') and \
150                row['state'] not in (IGNORE_MARKER, ''):
151                errs.append(('workflow','not allowed'))
152                return errs, inv_errs, conv_dict
153        if row.has_key('transition'):
154            if row['transition'] not in IMPORTABLE_TRANSITIONS:
155                if row['transition'] not in (IGNORE_MARKER, ''):
156                    errs.append(('transition','not allowed'))
157        if row.has_key('state'):
158            if row['state'] not in IMPORTABLE_STATES:
159                if row['state'] not in (IGNORE_MARKER, ''):
160                    errs.append(('state','not allowed'))
161                else:
162                    # State is an attribute of AccessCode and must not
163                    # be changed if empty.
164                    conv_dict['state'] = IGNORE_MARKER
165        return errs, inv_errs, conv_dict
166
167    def checkUpdateRequirements(self, obj, row, site):
168        """Checks requirements the object must fulfill when being updated.
169
170        This method is not used in case of deleting or adding objects.
171
172        Returns error messages as strings in case of requirement
173        problems.
174        """
175        transition = row.get('transition', IGNORE_MARKER)
176        if transition not in (IGNORE_MARKER, ''):
177            allowed_transitions = IWorkflowInfo(obj).getManualTransitionIds()
178            if transition not in allowed_transitions:
179                return 'Transition not allowed.'
180        return None
181
182    def updateEntry(self, obj, row, site):
183        """Update obj to the values given in row.
184
185        Returns a string describing the fields changed.
186        """
187        items_changed = ''
188        # Update state
189        # Attention: When importing states the counters remain unchanged.
190        if row.has_key('state'):
191            state = row.get('state', IGNORE_MARKER)
192            if state not in (IGNORE_MARKER, ''):
193                value = row['state']
194                IWorkflowState(obj).setState(value)
195                items_changed += ('%s=%s, ' % ('state', state))
196                msg = "state '%s' set" % state
197                IObjectHistory(obj).addMessage(msg)
198            row.pop('state')
199        # Trigger transition. Counters are properly changed.
200        if row.has_key('transition'):
201            transition = row.get('transition', IGNORE_MARKER)
202            if transition not in (IGNORE_MARKER, ''):
203                value = row['transition']
204                IWorkflowInfo(obj).fireTransition(value)
205                items_changed += ('%s=%s, ' % ('transition', transition))
206            row.pop('transition')
207
208        # In import files we can use the hash symbol at the end of a
209        # random_num string to avoid annoying automatic number transformation
210        # by Excel or Calc
211        if row.has_key('random_num'):
212            random_num = row.get('random_num', IGNORE_MARKER)
213            if random_num not in (IGNORE_MARKER, ''):
214                row['random_num'] = random_num.strip('#')
215
216        items_changed += super(AccessCodeProcessor, self).updateEntry(
217            obj, row, site)
218
219        # Log actions...
220        grok.getSite()['accesscodes'].logger.info('%s - %s - AC updated: %s'
221            % (self.name, row['representation'], items_changed))
222        return
Note: See TracBrowser for help on using the repository browser.