Ross, I like the on-the-fly ability.
Each step in your template changes the state of the item. Each one of those states should have a title. There are two other states to account for, new and done. Workflows sometimes have more than one path to completion. I see an entity called a workflow_item that has the ability to determine its current state and all possible states to which it could transition. It also knows who can cause it to transition to one of those states as well as which of its attributes should be hidden, visible or editable in any given state, and who should be able to see or edit those attributes while in that state. On Tuesday, May 1, 2012 12:00:42 PM UTC-4, Ross Peoples wrote: > > In reference to: > https://groups.google.com/forum/#!searchin/web2py/workflow/web2py/osEmmtu9hlg/2MHi_ZCeMBMJ > > Has anyone done any work on this yet? I was thinking about making a > web2py-based workflow engine. > > I mentioned previously that I built one of these for an application I > wrote several years ago, but it was built specifically for that app. This > will be my first attempt at making a general-use workflow engine, so let me > know if you find any problems with my design: > > Make a contrib module that is initialized like the Auth module: > from gluon.contrib.workflow_engine import WorkflowEngine, Step > workflow_engine = WorkflowEngine() > workflow_engine.define_tables() > > > I will use the example that I know best, which is passing around a sales > order throughout a company's departments. This first example would define a > workflow template because every sales order will have the same workflow: > workflow_engine.add_template('Sales Order', > Step(group_id=2, hours=4), # Engineering gets 4 hours to complete > their step > Step(user_id=7, hours=0), # The engineering manager (user) has no > time limit > Step(group_id=3, hours=2), # Quality department gets 2 hours to > inspect the order > Step(group_id=8, hours=6.5), # Shipping department gets 6.5 hours to > ship order > ) > > > You would start this workflow like this: > workflow_id = workflow_engine.load_template('Sales Order', item_type= > 'document', item_id=1) > workflow_id = workflow_engine. > workflow_engine.start(workflow_id) > > > Optionally, a workflow can be created on the fly (if the workflow will > only be used once): > workflow_id = workflow_engine.create_workflow('One-time Workflow', > 'document', 1 # same as item_type and item_id used in load_template() > Step(group_id=2, hours=4) > Step(group_id=3, due_date=request.now + datetime.timedelta(days=1)) # > set time limit to an exact datetime > ) > > workflow_engine.start(workflow_id) # start the workflow we just created > > > We assume that we are going to associate this workflow with another > object. In this case, we will assume there is a table called "document" and > that the document we want to pass around has an id of 1. The "item_type" > argument allows you to pass around any type of database object. In this > case, we will call it the same thing as our table: "document". > > These are some common operations that could be done: > workflow_engine.active_workflows() # returns a list of all active > workflows > workflow_engine.active_workflows(user_id=1) # all active workflows for > the user_id > workflow_engine.active_workflows(user_id=1, include_groups=True) # same > as above, but includes groups the user is a member of > workflow_engine.active_workflows(group_id=2) # all active workflows for > the group_id > workflow_engine.late_workflows() # returns a list of all late/overdue > workflows > workflow_engine.step_complete(workflow_id, notes='General info about > completed task') # moves workflow to the next step > workflow_engine.step_reject(workflow_id, to_step=2, notes='Why step was > rejected') # moves workflow back to step 2 incase there was a problem > with one of the previously completed steps > > > Workflow triggers: > workflow_engine.before_start = function(workflow, step) > workflow_engine.after_start = function(workflow, step) > workflow_engine.before_step_complete = function(workflow, step) > workflow_engine.after_step_complete = function(workflow, step) > workflow_engine.before_step_reject = function(workflow, step) > workflow_engine.after_step_reject = function(workflow, step) > workflow_engine.before_finish = function(workflow, step) > workflow_engine.after_finish = function(workflow, step) > > > Finally, (and I MIGHT do this) since we are using time limits in hours, we > should set some time ranges where users are available. For example, if the > company is only open from 8 AM to 5 PM, you wouldn't want something to be > late at 7 PM. You would want to roll over the extra 2 hours so that it > becomes late at 10 AM the next business day. A list of time ranges would be > created, and a user would be assigned to one of the time ranges. This would > accommodate users in different time zones or with different "work" hours. > Again, this last part I MIGHT do if I have enough time. I've done it > before, but I'm sure you can imagine how complicated this part is. > > > So any questions, comments, improvements? Thanks! >