source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py @ 12259

Last change on this file since 12259 was 12221, checked in by Henrik Bettermann, 10 years ago

Log workflow transitions properly.

  • Property svn:keywords set to Id
File size: 11.2 KB
Line 
1## $Id: workflow.py 12221 2014-12-14 06:14:39Z henrik $
2##
3## Copyright (C) 2014 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"""Workflow for customers.
19"""
20import grok
21from datetime import datetime
22from zope.component import getUtility
23from hurry.workflow.workflow import Transition, WorkflowState, NullCondition
24from hurry.workflow.interfaces import (
25    IWorkflowState, IWorkflowTransitionEvent, InvalidTransitionError)
26from waeup.ikoba.interfaces import (
27    IObjectHistory, IIkobaWorkflowInfo, IIkobaUtils,
28    STARTED, CREATED, REQUESTED, APPROVED,
29    SUBMITTED, VERIFIED, REJECTED, EXPIRED)
30from waeup.ikoba.interfaces import MessageFactory as _
31from waeup.ikoba.workflow import (
32    IkobaWorkflow, IkobaWorkflowInfo)
33from waeup.ikoba.customers.interfaces import (
34    ICustomer, ICustomersUtils,
35    IContract, ICustomerDocument)
36from waeup.ikoba.utils.helpers import get_current_principal
37
38# Customer workflow
39
40IMPORTABLE_REGISTRATION_STATES = (STARTED, REQUESTED, APPROVED)
41
42REGISTRATION_TRANSITIONS = (
43    Transition(
44        transition_id = 'create',
45        title = _('Create customer'),
46        source = None,
47        condition = NullCondition,
48        msg = _('Customer created'),
49        destination = CREATED),
50
51    Transition(
52        transition_id = 'start',
53        title = _('Start registration'),
54        source = CREATED,
55        condition = NullCondition,
56        msg = _('Customer registration started'),
57        destination = STARTED),
58
59    Transition(
60        transition_id = 'request',
61        title = _('Request registration'),
62        msg = _('Customer registration requested'),
63        source = STARTED,
64        destination = REQUESTED),
65
66    Transition(
67        transition_id = 'approve',
68        title = _('Approve customer'),
69        msg = _('Customer registration approved'),
70        source = REQUESTED,
71        destination = APPROVED),
72
73    Transition(
74        transition_id = 'reject',
75        title = _('Reject customer'),
76        msg = _('Customer registration rejected'),
77        source = REQUESTED,
78        destination = STARTED),
79
80    Transition(
81        transition_id = 'reset1',
82        title = _('Reset customer'),
83        msg = _('Reset to initial customer state'),
84        source = APPROVED,
85        destination = STARTED),
86
87    Transition(
88        transition_id = 'reset2',
89        title = _('Reset to requested'),
90        msg = _("Reset to 'requested'"),
91        source = APPROVED,
92        destination = REQUESTED),
93
94    Transition(
95        transition_id = 'reset3',
96        title = _('Reset customer'),
97        msg = _("Reset to initial state"),
98        source = REQUESTED,
99        destination = STARTED),
100
101    )
102
103
104IMPORTABLE_REGISTRATION_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
105
106registration_workflow = IkobaWorkflow(REGISTRATION_TRANSITIONS)
107
108
109class RegistrationWorkflowState(WorkflowState, grok.Adapter):
110    """An adapter to adapt Customer objects to workflow states.
111    """
112    grok.context(ICustomer)
113    grok.provides(IWorkflowState)
114
115    state_key = 'wf.registration.state'
116    state_id = 'wf.registration.id'
117
118
119class RegistrationWorkflowInfo(IkobaWorkflowInfo, grok.Adapter):
120    """Adapter to adapt Customer objects to workflow info objects.
121    """
122    grok.context(ICustomer)
123    grok.provides(IIkobaWorkflowInfo)
124
125    def __init__(self, context):
126        self.context = context
127        self.wf = registration_workflow
128
129
130@grok.subscribe(ICustomer, IWorkflowTransitionEvent)
131def handle_customer_transition_event(obj, event):
132    """Append message to customer history and log file when transition happened.
133    """
134
135    msg = event.transition.user_data['msg']
136    history = IObjectHistory(obj)
137    history.addMessage(msg)
138    try:
139        customers_container = grok.getSite()['customers']
140        customers_container.logger.info('%s - %s' % (obj.customer_id,msg))
141    except (TypeError, AttributeError):
142        pass
143    return
144
145
146# Contract workflow
147
148
149CONTRACT_TRANSITIONS = (
150    Transition(
151        transition_id = 'create',
152        title = _('Create contract'),
153        source = None,
154        condition = NullCondition,
155        msg = _('Contract created'),
156        destination = CREATED),
157
158    Transition(
159        transition_id = 'submit',
160        title = _('Submit for approval'),
161        msg = _('Submitted for approval'),
162        source = CREATED,
163        destination = SUBMITTED),
164
165    Transition(
166        transition_id = 'approve',
167        title = _('Approve'),
168        msg = _('Approved'),
169        source = SUBMITTED,
170        destination = APPROVED),
171
172    Transition(
173        transition_id = 'reject',
174        title = _('Reject'),
175        msg = _('REJECTED'),
176        source = SUBMITTED,
177        destination = REJECTED),
178
179    Transition(
180        transition_id = 'reset1',
181        title = _('Reset to initial state'),
182        msg = _('Reset to initial state'),
183        source = REJECTED,
184        destination = CREATED),
185
186    Transition(
187        transition_id = 'reset2',
188        title = _('Reset to initial state'),
189        msg = _('Reset to initial state'),
190        source = APPROVED,
191        destination = CREATED),
192
193    Transition(
194        transition_id = 'reset3',
195        title = _('Reset to initial state'),
196        msg = _('Reset to initial state'),
197        source = SUBMITTED,
198        destination = CREATED),
199
200    Transition(
201        transition_id = 'expire',
202        title = _('Set to expired'),
203        msg = _('Set to expired'),
204        source = APPROVED,
205        destination = EXPIRED),
206
207    Transition(
208        transition_id = 'reset4',
209        title = _('Reset to initial state'),
210        msg = _('Reset to initial state'),
211        source = EXPIRED,
212        destination = CREATED),
213    )
214
215contract_workflow = IkobaWorkflow(CONTRACT_TRANSITIONS)
216
217
218class ContractWorkflowState(WorkflowState, grok.Adapter):
219    """An adapter to adapt Contract objects to workflow states.
220    """
221    grok.context(IContract)
222    grok.provides(IWorkflowState)
223
224    state_key = 'wf.contract.state'
225    state_id = 'wf.contract.id'
226
227
228class ContractWorkflowInfo(IkobaWorkflowInfo, grok.Adapter):
229    """Adapter to adapt Contract objects to workflow info objects.
230    """
231    grok.context(IContract)
232    grok.provides(IIkobaWorkflowInfo)
233
234    def __init__(self, context):
235        self.context = context
236        self.wf = contract_workflow
237
238@grok.subscribe(IContract, IWorkflowTransitionEvent)
239def handle_contract_transition_event(obj, event):
240    """Append message to contract history and log file.
241
242    Undo the approval of contract and raise an exception if contract
243    does not meet the requirements for approval.
244    """
245    if event.transition.destination == APPROVED:
246        approvable, error = obj.is_approvable
247        if not approvable:
248            # Undo transition and raise an exception.
249            IWorkflowState(obj).setState(event.transition.source)
250            raise InvalidTransitionError(error)
251    msg = event.transition.user_data['msg']
252    history = IObjectHistory(obj)
253    history.addMessage(msg)
254    try:
255        customers_container = grok.getSite()['customers']
256        customers_container.logger.info(
257            '%s - %s - %s' % (obj.customer.customer_id, obj.contract_id, msg))
258    except (TypeError, AttributeError):
259        pass
260    return
261
262# Customer document workflow
263
264VERIFICATION_TRANSITIONS = (
265    Transition(
266        transition_id = 'create',
267        title = _('Create document'),
268        source = None,
269        condition = NullCondition,
270        msg = _('Document created'),
271        destination = CREATED),
272
273    Transition(
274        transition_id = 'submit',
275        title = _('Submit for verification'),
276        msg = _('Submitted for verification'),
277        source = CREATED,
278        destination = SUBMITTED),
279
280    Transition(
281        transition_id = 'verify',
282        title = _('Verify'),
283        msg = _('Verified'),
284        source = SUBMITTED,
285        destination = VERIFIED),
286
287    Transition(
288        transition_id = 'reject',
289        title = _('Reject'),
290        msg = _('REJECTED'),
291        source = SUBMITTED,
292        destination = REJECTED),
293
294    Transition(
295        transition_id = 'reset1',
296        title = _('Reset to initial state'),
297        msg = _('Reset to initial state'),
298        source = REJECTED,
299        destination = CREATED),
300
301    Transition(
302        transition_id = 'reset2',
303        title = _('Reset to initial state'),
304        msg = _('Reset to initial state'),
305        source = VERIFIED,
306        destination = CREATED),
307
308    Transition(
309        transition_id = 'reset3',
310        title = _('Reset to initial state'),
311        msg = _('Reset to initial state'),
312        source = SUBMITTED,
313        destination = CREATED),
314
315    Transition(
316        transition_id = 'expire',
317        title = _('Set to expired'),
318        msg = _('Set to expired'),
319        source = VERIFIED,
320        destination = EXPIRED),
321
322    Transition(
323        transition_id = 'reset4',
324        title = _('Reset to initial state'),
325        msg = _('Reset to initial state'),
326        source = EXPIRED,
327        destination = CREATED),
328    )
329
330verification_workflow = IkobaWorkflow(VERIFICATION_TRANSITIONS)
331
332
333class VerificationWorkflowState(WorkflowState, grok.Adapter):
334    """An adapter to adapt CustomerDocument objects to workflow states.
335    """
336    grok.context(ICustomerDocument)
337    grok.provides(IWorkflowState)
338
339    state_key = 'wf.verification.state'
340    state_id = 'wf.verification.id'
341
342
343class VerificationWorkflowInfo(IkobaWorkflowInfo, grok.Adapter):
344    """Adapter to adapt CustomerDocument objects to workflow info objects.
345    """
346    grok.context(ICustomerDocument)
347    grok.provides(IIkobaWorkflowInfo)
348
349    def __init__(self, context):
350        self.context = context
351        self.wf = verification_workflow
352
353@grok.subscribe(ICustomerDocument, IWorkflowTransitionEvent)
354def handle_customer_document_transition_event(obj, event):
355    """Append message to document history and log file.
356
357    Undo the verification of document and raise an exception if document
358    does not meet the requirements for verification.
359    """
360    if event.transition.destination == VERIFIED:
361        verifiable, error = obj.is_verifiable
362        if not verifiable:
363            # Undo transition and raise an exception.
364            IWorkflowState(obj).setState(event.transition.source)
365            raise InvalidTransitionError(error)
366    if event.transition.transition_id == 'verify':
367        obj.setMD5()
368    msg = event.transition.user_data['msg']
369    history = IObjectHistory(obj)
370    history.addMessage(msg)
371    try:
372        customers_container = grok.getSite()['customers']
373        customers_container.logger.info(
374            '%s - %s - %s' % (obj.customer.customer_id, obj.document_id, msg))
375    except (TypeError, AttributeError):
376        pass
377    return
Note: See TracBrowser for help on using the repository browser.