"""Workflow for applicants. """ import grok from datetime import datetime from hurry.workflow.workflow import ( Transition, Workflow, WorkflowVersions, WorkflowInfo, WorkflowState, NullCondition) from hurry.workflow.interfaces import ( IWorkflow, IWorkflowState, IWorkflowInfo, IWorkflowVersions, InvalidTransitionError, IWorkflowTransitionEvent) from waeup.sirp.applicants.interfaces import IApplicantBaseData INITIALIZED = 'initialized' STARTED = 'started' SUBMITTED = 'submitted' ADMITTED = 'admitted' NOT_ADMITTED = 'not admitted' CREATED = 'created' def create_workflow(): init_transition = Transition( transition_id = 'init', title = 'Initialize application', source = None, condition = NullCondition, destination = INITIALIZED) start_transition = Transition( transition_id = 'start', title = 'Start application', source = INITIALIZED, destination = STARTED) submit_transition = Transition( transition_id = 'submit', title = 'Submit application', source = STARTED, destination = SUBMITTED) admit_transition = Transition( transition_id = 'admit', title = 'Admit applicant', source = SUBMITTED, destination = ADMITTED) refuse1_transition = Transition( transition_id = 'refuse1', title = 'Refuse application', source = SUBMITTED, destination = NOT_ADMITTED) refuse2_transition = Transition( transition_id = 'refuse2', title = 'Refuse application', source = ADMITTED, destination = NOT_ADMITTED) create_transition = Transition( transition_id = 'create', title = 'Create student record', source = ADMITTED, destination = CREATED) reset1_transition = Transition( transition_id = 'reset1', title = 'Reset application', source = SUBMITTED, destination = STARTED) reset2_transition = Transition( transition_id = 'reset2', title = 'Reset application', source = ADMITTED, destination = STARTED) reset3_transition = Transition( transition_id = 'reset3', title = 'Reset application', source = NOT_ADMITTED, destination = STARTED) reset4_transition = Transition( transition_id = 'reset4', title = 'Reset application', source = CREATED, destination = STARTED) return [init_transition, start_transition, submit_transition, admit_transition, create_transition, refuse1_transition, refuse2_transition, reset1_transition, reset2_transition, reset3_transition, reset4_transition] class ApplicationWorkflow(Workflow): """A hurry.workflow Workflow with more appropriate error messages. """ grok.provides(IWorkflow) def __init__(self): super(Workflow, self).__init__() self.refresh(create_workflow()) def getTransition(self, source, transition_id): transition = self._id_transitions[transition_id] if transition.source != source: raise InvalidTransitionError( "Transition '%s' requires '%s' as source state (is: '%s')" % ( transition_id, transition.source, source)) return transition class ApplicationWorkflowNullVersions(WorkflowVersions): """A workflow versions manager that does not handle versions. Sounds odd, but the default implementation of :class:`hurry.workflow.workflow.WorkflowVersions` is a base implementation that raises :exc:`NotImplemented` exceptions for most of the methods defined below. If we want to register a versionless workflow, an utility implementing IWorkflowVersions is looked up nevertheless by WorkflowInfo and WorkflowState components so we **have** to provide workflow versions, even if we do not support versioned workflows. This implementation returns empty result sets for any requests, but does not raise :exc:`NotImplemented`. """ def getVersions(self, state, id): return [] def getVersionsWithAutomaticTransitions(self): return [] def hasVersion(self, id, state): return False def hasVersionId(self, id): return False # Register global utilities for workflows and workflow versions... grok.global_utility(ApplicationWorkflow, IWorkflow) grok.global_utility(ApplicationWorkflowNullVersions, IWorkflowVersions) class ApplicationState(grok.Adapter, WorkflowState): """An adapter to adapt Applicant objects to workflow states. """ grok.context(IApplicantBaseData) grok.provides(IWorkflowState) class ApplicationInfo(grok.Adapter, WorkflowInfo): """Adapter to adapt Applicant objects to workflow info objects. """ grok.context(IApplicantBaseData) grok.provides(IWorkflowInfo) @grok.subscribe(IApplicantBaseData, IWorkflowTransitionEvent) def handle_applicant_transition_event(obj, event): """Append message to applicant when transition happened. """ timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S") comment = event.comment or '(no comment)' # XXX: `messages` is meta data which shouldn't really be part of # the Applicant class. Furthermore we should not store HTML # code but simple messages. This has to be cleaned up # further. For now we replace the redundant code in browser # mod. As we're here: one could use permissions and similar # to finetune transitions instead of doing that manually in # UI stuff. msg = '%s - %s to %s: %s: %s' % ( timestamp, event.source, event.destination, event.transition.title, comment) msgs = getattr(obj, 'messages', None) if msgs != '': msgs += '
' obj.messages += msg return