entities/wfobjs.py
branchstable
changeset 3628 440931181322
parent 3621 1ec4452aa36f
child 3629 559cad62c786
child 3663 c74d8ec4cdb2
equal deleted inserted replaced
3627:70dbba754c11 3628:440931181322
   122                              'WHERE S eid %(s)s, T eid %(t)s',
   122                              'WHERE S eid %(s)s, T eid %(t)s',
   123                              {'s': state, 't': tr.eid}, ('s', 't'))
   123                              {'s': state, 't': tr.eid}, ('s', 't'))
   124         tr.set_transition_permissions(requiredgroups, conditions, reset=False)
   124         tr.set_transition_permissions(requiredgroups, conditions, reset=False)
   125         return tr
   125         return tr
   126 
   126 
   127     def add_transition(self, name, fromstates, tostate,
   127     def add_transition(self, name, fromstates, tostate=None,
   128                        requiredgroups=(), conditions=(), **kwargs):
   128                        requiredgroups=(), conditions=(), **kwargs):
   129         """add a transition to this workflow from some state(s) to another"""
   129         """add a transition to this workflow from some state(s) to another"""
   130         tr = self._add_transition('Transition', name, fromstates,
   130         tr = self._add_transition('Transition', name, fromstates,
   131                                   requiredgroups, conditions, **kwargs)
   131                                   requiredgroups, conditions, **kwargs)
   132         if hasattr(tostate, 'eid'):
   132         if tostate is not None:
   133             tostate = tostate.eid
   133             if hasattr(tostate, 'eid'):
   134         self.req.execute('SET T destination_state S '
   134                 tostate = tostate.eid
   135                          'WHERE S eid %(s)s, T eid %(t)s',
   135             self.req.execute('SET T destination_state S '
   136                          {'t': tr.eid, 's': tostate}, ('s', 't'))
   136                              'WHERE S eid %(s)s, T eid %(t)s',
       
   137                              {'t': tr.eid, 's': tostate}, ('s', 't'))
   137         return tr
   138         return tr
   138 
   139 
   139     def add_wftransition(self, name, subworkflow, fromstates, exitpoints,
   140     def add_wftransition(self, name, subworkflow, fromstates, exitpoints=(),
   140                          requiredgroups=(), conditions=(), **kwargs):
   141                          requiredgroups=(), conditions=(), **kwargs):
   141         """add a workflow transition to this workflow"""
   142         """add a workflow transition to this workflow"""
   142         tr = self._add_transition('WorkflowTransition', name, fromstates,
   143         tr = self._add_transition('WorkflowTransition', name, fromstates,
   143                                   requiredgroups, conditions, **kwargs)
   144                                   requiredgroups, conditions, **kwargs)
   144         if hasattr(subworkflow, 'eid'):
   145         if hasattr(subworkflow, 'eid'):
   255         return self.subwf.initial
   256         return self.subwf.initial
   256 
   257 
   257     def add_exit_point(self, fromstate, tostate):
   258     def add_exit_point(self, fromstate, tostate):
   258         if hasattr(fromstate, 'eid'):
   259         if hasattr(fromstate, 'eid'):
   259             fromstate = fromstate.eid
   260             fromstate = fromstate.eid
   260         if hasattr(tostate, 'eid'):
   261         if tostate is None:
   261             tostate = tostate.eid
   262             self.req.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, '
   262         self.req.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, '
   263                              'X subworkflow_state FS WHERE T eid %(t)s, FS eid %(fs)s',
   263                          'X subworkflow_state FS, X destination_state TS '
   264                              {'t': self.eid, 'fs': fromstate}, ('t', 'fs'))
   264                          'WHERE T eid %(t)s, FS eid %(fs)s, TS eid %(ts)s',
   265         else:
   265                          {'t': self.eid, 'fs': fromstate, 'ts': tostate},
   266             if hasattr(tostate, 'eid'):
   266                          ('t', 'fs', 'ts'))
   267                 tostate = tostate.eid
   267 
   268             self.req.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, '
   268     def get_exit_point(self, state):
   269                              'X subworkflow_state FS, X destination_state TS '
       
   270                              'WHERE T eid %(t)s, FS eid %(fs)s, TS eid %(ts)s',
       
   271                              {'t': self.eid, 'fs': fromstate, 'ts': tostate},
       
   272                              ('t', 'fs', 'ts'))
       
   273 
       
   274     def get_exit_point(self, entity, stateeid):
   269         """if state is an exit point, return its associated destination state"""
   275         """if state is an exit point, return its associated destination state"""
   270         if hasattr(state, 'eid'):
   276         if hasattr(stateeid, 'eid'):
   271             state = state.eid
   277             stateeid = stateeid.eid
   272         stateeid = self.exit_points().get(state)
   278         try:
   273         if stateeid is not None:
   279             tostateeid = self.exit_points()[stateeid]
   274             return self.req.entity_from_eid(stateeid)
   280         except KeyError:
   275         return None
   281             return None
       
   282         if tostateeid is None:
       
   283             # go back to state from which we've entered the subworkflow
       
   284             return entity.subworkflow_input_trinfo().previous_state
       
   285         return self.req.entity_from_eid(tostateeid)
   276 
   286 
   277     @cached
   287     @cached
   278     def exit_points(self):
   288     def exit_points(self):
   279         result = {}
   289         result = {}
   280         for ep in self.subworkflow_exit:
   290         for ep in self.subworkflow_exit:
   281             result[ep.subwf_state.eid] = ep.destination.eid
   291             result[ep.subwf_state.eid] = ep.destination and ep.destination.eid
   282         return result
   292         return result
   283 
   293 
   284     def clear_all_caches(self):
   294     def clear_all_caches(self):
   285         super(WorkflowableMixIn, self).clear_all_caches()
   295         super(WorkflowableMixIn, self).clear_all_caches()
   286         clear_cache(self, 'exit_points')
   296         clear_cache(self, 'exit_points')
   294     def subwf_state(self):
   304     def subwf_state(self):
   295         return self.subworkflow_state[0]
   305         return self.subworkflow_state[0]
   296 
   306 
   297     @property
   307     @property
   298     def destination(self):
   308     def destination(self):
   299         return self.destination_state[0]
   309         return self.destination_state and self.destination_state[0] or None
   300 
   310 
   301 
   311 
   302 class State(AnyEntity):
   312 class State(AnyEntity):
   303     """customized class for State entities"""
   313     """customized class for State entities"""
   304     id = 'State'
   314     id = 'State'
   455         """change the entity's state by firing transition of the given name in
   465         """change the entity's state by firing transition of the given name in
   456         entity's workflow
   466         entity's workflow
   457         """
   467         """
   458         assert self.current_workflow
   468         assert self.current_workflow
   459         if isinstance(tr, basestring):
   469         if isinstance(tr, basestring):
   460             tr = self.current_workflow.transition_by_name(tr)
   470             _tr = self.current_workflow.transition_by_name(tr)
   461         assert tr is not None, 'not a %s transition: %s' % (self.id, tr)
   471             assert _tr is not None, 'not a %s transition: %s' % (self.id, tr)
       
   472             tr = _tr
   462         return self._add_trinfo(comment, commentformat, tr.eid)
   473         return self._add_trinfo(comment, commentformat, tr.eid)
   463 
   474 
   464     def change_state(self, statename, comment=None, commentformat=None, tr=None):
   475     def change_state(self, statename, comment=None, commentformat=None, tr=None):
   465         """change the entity's state to the given state (name or entity) in
   476         """change the entity's state to the given state (name or entity) in
   466         entity's workflow. This method should only by used by manager to fix an
   477         entity's workflow. This method should only by used by manager to fix an
   481                                                                 statename))
   492                                                                 statename))
   482             stateeid = state.eid
   493             stateeid = state.eid
   483         # XXX try to find matching transition?
   494         # XXX try to find matching transition?
   484         return self._add_trinfo(comment, commentformat, tr and tr.eid, stateeid)
   495         return self._add_trinfo(comment, commentformat, tr and tr.eid, stateeid)
   485 
   496 
   486     def subworkflow_input_transition(self):
   497     def subworkflow_input_trinfo(self):
   487         """return the transition which has went through the current sub-workflow
   498         """return the TrInfo which has be recorded when this entity went into
       
   499         the current sub-workflow
   488         """
   500         """
   489         if self.main_workflow.eid == self.current_workflow.eid:
   501         if self.main_workflow.eid == self.current_workflow.eid:
   490             return # doesn't make sense
   502             return # doesn't make sense
   491         subwfentries = []
   503         subwfentries = []
   492         for trinfo in self.workflow_history:
   504         for trinfo in self.workflow_history:
   501                 else:
   513                 else:
   502                     # enter
   514                     # enter
   503                     subwfentries.append(trinfo)
   515                     subwfentries.append(trinfo)
   504         if not subwfentries:
   516         if not subwfentries:
   505             return None
   517             return None
   506         return subwfentries[-1].transition
   518         return subwfentries[-1]
       
   519 
       
   520     def subworkflow_input_transition(self):
       
   521         """return the transition which has went through the current sub-workflow
       
   522         """
       
   523         return getattr(self.subworkflow_input_trinfo(), 'transition', None)
   507 
   524 
   508     def clear_all_caches(self):
   525     def clear_all_caches(self):
   509         super(WorkflowableMixIn, self).clear_all_caches()
   526         super(WorkflowableMixIn, self).clear_all_caches()
   510         clear_cache(self, 'cwetype_workflow')
   527         clear_cache(self, 'cwetype_workflow')
   511 
   528