source: main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/workflow.py @ 17367

Last change on this file since 17367 was 15155, checked in by Henrik Bettermann, 6 years ago

Reorganise interfaces.

Transcript processing views and viewlets are now in the context of studycourses. Officers can now validate, sign and release transcripts directly on the transcript page.

  • Property svn:keywords set to Id
File size: 9.9 KB
Line 
1"""Workflow for students.
2"""
3import grok
4from datetime import datetime
5from zope.component import getUtility
6from hurry.workflow.workflow import Transition, WorkflowState, NullCondition
7from hurry.workflow.interfaces import IWorkflowState, IWorkflowTransitionEvent
8from waeup.kofa.interfaces import (
9    IObjectHistory, IKofaWorkflowInfo, IKofaUtils,
10    CREATED, ADMITTED, CLEARANCE, REQUESTED, CLEARED, PAID, RETURNING,
11    REGISTERED, VALIDATED, GRADUATED, TRANSREQ, TRANSVAL, TRANSREL,
12    IExtFileStore)
13from waeup.kofa.interfaces import MessageFactory as _
14from waeup.kofa.workflow import KofaWorkflow, KofaWorkflowInfo
15from waeup.kofa.students.interfaces import IStudent, IStudentsUtils
16from waeup.kofa.utils.helpers import get_current_principal
17
18
19IMPORTABLE_STATES = (ADMITTED, CLEARANCE, REQUESTED, CLEARED, PAID, RETURNING,
20    REGISTERED, VALIDATED, GRADUATED)
21
22FORBIDDEN_POSTGRAD_STATES = (RETURNING, REGISTERED, VALIDATED)
23
24REGISTRATION_TRANSITIONS = (
25    Transition(
26        transition_id = 'create',
27        title = _('Create student'),
28        source = None,
29        condition = NullCondition,
30        msg = _('Record created'),
31        destination = CREATED),
32
33    Transition(
34        transition_id = 'admit',
35        title = _('Admit student'),
36        msg = _('Admitted'),
37        source = CREATED,
38        destination = ADMITTED),
39
40    Transition(
41        transition_id = 'reset1',
42        title = _('Reset student'),
43        msg = _('Reset to initial state'),
44        source = ADMITTED,
45        destination = CREATED),
46
47    Transition(
48        transition_id = 'start_clearance',
49        title = _('Start clearance'),
50        msg = _('Clearance started'),
51        source = ADMITTED,
52        destination = CLEARANCE),
53
54    Transition(
55        transition_id = 'reset2',
56        title = _('Reset to admitted'),
57        msg = _("Reset to 'admitted'"),
58        source = CLEARANCE,
59        destination = ADMITTED),
60
61    Transition(
62        transition_id = 'request_clearance',
63        title = _('Request clearance'),
64        msg = _('Clearance requested'),
65        source = CLEARANCE,
66        destination = REQUESTED),
67
68    Transition(
69        transition_id = 'reset3',
70        title = _('Reset to clearance started'),
71        msg = _("Reset to 'clearance started'"),
72        source = REQUESTED,
73        destination = CLEARANCE),
74
75    Transition(
76        transition_id = 'clear',
77        title = _('Clear student'),
78        msg = _('Cleared'),
79        source = REQUESTED,
80        destination = CLEARED),
81
82    Transition(
83        transition_id = 'reset4',
84        title = _('Reset to clearance started'),
85        msg = _("Reset to 'clearance started'"),
86        source = CLEARED,
87        destination = CLEARANCE),
88
89    Transition(
90        transition_id = 'pay_first_school_fee',
91        title = _('Pay school fee'),
92        msg = _('First school fee payment made'),
93        source = CLEARED,
94        destination = PAID),
95
96    Transition(
97        transition_id = 'approve_first_school_fee',
98        title = _('Approve payment'),
99        msg = _('First school fee payment approved'),
100        source = CLEARED,
101        destination = PAID),
102
103    Transition(
104        transition_id = 'reset5',
105        title = _('Reset to cleared'),
106        msg = _("Reset to 'cleared'"),
107        source = PAID,
108        destination = CLEARED),
109
110    Transition(
111        transition_id = 'pay_school_fee',
112        title = _('Pay school fee'),
113        msg = _('School fee payment made'),
114        source = RETURNING,
115        destination = PAID),
116
117    Transition(
118        transition_id = 'pay_pg_fee',
119        title = _('Pay PG school fee'),
120        msg = _('PG school fee payment made'),
121        source = PAID,
122        destination = PAID),
123
124    Transition(
125        transition_id = 'approve_school_fee',
126        title = _('Approve school fee payment'),
127        msg = _('School fee payment approved'),
128        source = RETURNING,
129        destination = PAID),
130
131    Transition(
132        transition_id = 'approve_pg_fee',
133        title = _('Approve PG school fee payment'),
134        msg = _('PG school fee payment approved'),
135        source = PAID,
136        destination = PAID),
137
138    Transition(
139        transition_id = 'reset6',
140        title = _('Reset to returning'),
141        msg = _("Reset to 'returning'"),
142        source = PAID,
143        destination = RETURNING),
144
145    Transition(
146        transition_id = 'register_courses',
147        title = _('Register courses'),
148        msg = _('Courses registered'),
149        source = PAID,
150        destination = REGISTERED),
151
152    Transition(
153        transition_id = 'reset7',
154        title = _('Unregister courses'),
155        msg = _("Courses unregistered"),
156        source = REGISTERED,
157        destination = PAID),
158
159    Transition(
160        transition_id = 'validate_courses',
161        title = _('Validate courses'),
162        msg = _('Courses validated'),
163        source = REGISTERED,
164        destination = VALIDATED),
165
166    Transition(
167        transition_id = 'bypass_validation',
168        title = _('Return and bypass validation'),
169        msg = _("Course validation bypassed"),
170        source = REGISTERED,
171        destination = RETURNING),
172
173    Transition(
174        transition_id = 'reset8',
175        title = _('Reset to school fee paid'),
176        msg = _("Reset to 'school fee paid'"),
177        source = VALIDATED,
178        destination = PAID),
179
180    Transition(
181        transition_id = 'return',
182        title = _('Return'),
183        msg = _("Returned"),
184        source = VALIDATED,
185        destination = RETURNING),
186
187    Transition(
188        transition_id = 'reset9',
189        title = _('Reset to courses validated'),
190        msg = _("Reset to 'courses validated'"),
191        source = RETURNING,
192        destination = VALIDATED),
193
194    # There is no transition to graduated.
195
196    Transition(
197        transition_id = 'request_transcript',
198        title = _('Request transript'),
199        msg = _("Transcript requested"),
200        source = GRADUATED,
201        destination = TRANSREQ),
202
203    Transition(
204        transition_id = 'reset10',
205        title = _('Reject transcript request'),
206        msg = _("Transcript request rejected"),
207        source = TRANSREQ,
208        destination = GRADUATED),
209
210    Transition(
211        transition_id = 'validate_transcript',
212        title = _('Validate transcript'),
213        msg = _("Transcript validated"),
214        source = TRANSREQ,
215        destination = TRANSVAL),
216
217    Transition(
218        transition_id = 'release_transcript',
219        title = _('Release transcript'),
220        msg = _("Transcript released"),
221        source = TRANSVAL,
222        destination = TRANSREL),
223
224    Transition(
225        transition_id = 'reset11',
226        title = _('Reset to graduated'),
227        msg = _("Transcript process reset"),
228        source = TRANSREL,
229        destination = GRADUATED),
230    )
231
232
233IMPORTABLE_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
234
235FORBIDDEN_POSTGRAD_TRANS = ['reset6', 'register_courses']
236
237registration_workflow = KofaWorkflow(REGISTRATION_TRANSITIONS)
238
239class RegistrationWorkflowState(WorkflowState, grok.Adapter):
240    """An adapter to adapt Student objects to workflow states.
241    """
242    grok.context(IStudent)
243    grok.provides(IWorkflowState)
244
245    state_key = 'wf.registration.state'
246    state_id = 'wf.registration.id'
247
248class RegistrationWorkflowInfo(KofaWorkflowInfo, grok.Adapter):
249    """Adapter to adapt Student objects to workflow info objects.
250    """
251    grok.context(IStudent)
252    grok.provides(IKofaWorkflowInfo)
253
254    def __init__(self, context):
255        self.context = context
256        self.wf = registration_workflow
257
258@grok.subscribe(IStudent, IWorkflowTransitionEvent)
259def handle_student_transition_event(obj, event):
260    """Append message to student history and log file when transition happened.
261
262    Lock and unlock clearance form.
263    Trigger actions after school fee payment.
264    """
265
266    msg = event.transition.user_data['msg']
267    history = IObjectHistory(obj)
268    history.addMessage(msg)
269    # School fee payment of returning students triggers the change of
270    # current session, current level, and current verdict
271    if event.transition.transition_id in (
272        'pay_school_fee', 'approve_school_fee'):
273        getUtility(IStudentsUtils).setReturningData(obj)
274    elif event.transition.transition_id in (
275        'pay_pg_fee', 'approve_pg_fee'):
276        new_session = obj['studycourse'].current_session + 1
277        obj['studycourse'].current_session = new_session
278    elif event.transition.transition_id == 'validate_courses':
279        current_level = obj['studycourse'].current_level
280        level_object = obj['studycourse'].get(str(current_level), None)
281        if level_object is not None:
282            user = get_current_principal()
283            if user is None:
284                usertitle = 'system'
285            else:
286                usertitle = getattr(user, 'public_name', None)
287                if not usertitle:
288                    usertitle = user.title
289            level_object.validated_by = usertitle
290            level_object.validation_date = datetime.utcnow()
291    elif event.transition.transition_id == 'clear':
292        obj.officer_comment = None
293    elif event.transition.transition_id == 'reset8':
294        current_level = obj['studycourse'].current_level
295        level_object = obj['studycourse'].get(str(current_level), None)
296        if level_object is not None:
297            level_object.validated_by = None
298            level_object.validation_date = None
299    elif event.transition.transition_id == 'reset11':
300        transcript_file = getUtility(IExtFileStore).getFileByContext(
301            obj, attr='final_transcript')
302        if transcript_file:
303            getUtility(IExtFileStore).deleteFileByContext(
304                obj, attr='final_transcript')
305        obj['studycourse'].transcript_comment = None
306        obj['studycourse'].transcript_signees = None
307    # In some tests we don't have a students container
308    try:
309        students_container = grok.getSite()['students']
310        students_container.logger.info('%s - %s' % (obj.student_id,msg))
311    except (TypeError, AttributeError):
312        pass
313    return
Note: See TracBrowser for help on using the repository browser.