Removed transitions and move to a Node based workflow element

This commit is contained in:
Roberto Rosario
2012-03-30 03:23:04 -04:00
parent 0717f346b0
commit a5280870c2
8 changed files with 559 additions and 75 deletions

View File

@@ -9,11 +9,9 @@ from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW,
PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT,
PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW,
PERMISSION_STATE_SETUP_CREATE, PERMISSION_STATE_SETUP_EDIT,
PERMISSION_STATE_SETUP_DELETE, PERMISSION_TRANSITION_SETUP_VIEW,
PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT,
PERMISSION_TRANSITION_SETUP_DELETE)
from .models import (Workflow, State, Transition, WorkflowState,
WorkflowStateTransition)
PERMISSION_STATE_SETUP_DELETE)
from .models import (Workflow, State, WorkflowState, WorkflowNode)
setup_workflow_list_link = Link(text=_(u'workflow list'), view='setup_workflow_list', sprite='chart_organisation', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW])
setup_workflow_create_link = Link(text=_(u'create new workflow'), view='setup_workflow_create', sprite='chart_organisation_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE])
@@ -33,34 +31,38 @@ setup_state_create_link = Link(text=_(u'create new state'), view='setup_state_cr
setup_state_edit_link = Link(text=_(u'edit'), view='setup_state_edit', args='object.pk', sprite='transmit_edit', permissions=[PERMISSION_STATE_SETUP_EDIT])
setup_state_delete_link = Link(text=_(u'delete'), view='setup_state_delete', args='object.pk', sprite='transmit_delete', permissions=[PERMISSION_STATE_SETUP_DELETE])
setup_transition_list_link = Link(text=_(u'transition list'), view='setup_transition_list', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_VIEW])
setup_transition_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_TRANSITION_SETUP_CREATE])
setup_transition_edit_link = Link(text=_(u'edit'), view='setup_transition_edit', args='transition.pk', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_EDIT])
setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_TRANSITION_SETUP_DELETE])
setup_workflow_node_list_link = Link(text=_(u'node list'), view='setup_workflow_node_list', args='workflow.pk', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT])
#setup_workflow_node_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_TRANSITION_SETUP_CREATE])
setup_workflow_node_edit_link = Link(text=_(u'edit'), view='setup_workflow_node_edit', args='workflow_node.pk', sprite='chart_line_edit', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT])
#setup_workflow_node_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_TRANSITION_SETUP_DELETE])
bind_links(
[
Workflow, State, Transition, WorkflowStateTransition,
Workflow, State,
'setup_workflow_list', 'setup_workflow_create',
'setup_state_list', 'setup_state_create',
'setup_transition_list', 'setup_transition_create',
#'setup_transition_list', 'setup_transition_create',
'setup_transition_create',
], [
setup_workflow_list_link, setup_state_list_link, setup_transition_list_link
setup_workflow_list_link, setup_state_list_link#, setup_transition_list_link
], menu_name=u'form_header')
bind_links([Workflow], [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link])
bind_links([Workflow], [setup_workflow_node_list_link, setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link])
bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu')
bind_links([WorkflowState, 'setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar')
bind_links([State], [setup_state_edit_link, setup_state_delete_link])
bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu')
bind_links([Transition], [setup_transition_edit_link, setup_transition_delete_link])
bind_links([Transition, 'setup_transition_list', 'setup_transition_create'], [setup_transition_create_link], menu_name=u'secondary_menu')
#bind_links([Transition], [setup_transition_edit_link, setup_transition_delete_link])
#bind_links([Transition, 'setup_transition_list', 'setup_transition_create'], [setup_transition_create_link], menu_name=u'secondary_menu')
bind_links([WorkflowState], [setup_workflow_state_transitions_list_link, setup_workflow_states_edit_link, setup_workflow_states_remove_link])
bind_links([WorkflowState], [setup_workflow_state_transition_add_link], menu_name=u'sidebar')
#bind_links([WorkflowState], [setup_workflow_state_transitions_list_link, setup_workflow_states_edit_link, setup_workflow_states_remove_link])
bind_links([WorkflowState], [setup_workflow_states_edit_link, setup_workflow_states_remove_link])
bind_links([WorkflowStateTransition], [setup_workflow_state_transition_edit_link])#, setup_transition_delete_link])
#bind_links([WorkflowState], [setup_workflow_state_transition_add_link], menu_name=u'sidebar')
#bind_links([WorkflowNode], [setup_workflow_state_transition_add_link], menu_name=u'sidebar')
bind_links([WorkflowNode], [setup_workflow_node_edit_link])#, setup_transition_delete_link])
register_setup(Link(text=_(u'workflows'), view='setup_workflow_list', icon='chart_organisation.png', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW]))

View File

@@ -3,11 +3,26 @@ from __future__ import absolute_import
from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import Workflow, State, Transition, WorkflowState, WorkflowStateTransition
from .models import Workflow, State, WorkflowState, WorkflowNode
class NodeForm(forms.Form):
def __init__(self, *args, **kwargs):
#workflow = kwargs.pop('workflow')
super(WorkflowStateSetupForm, self).__init__(*args, **kwargs)
#self.fields['workflow'].initial = workflow
#self.fields['workflow'].widget = forms.widgets.HiddenInput()
print self.instance
#def choices(self, workflow):
# return {
## 'next_node': workflow.nodes.all()
# }
class WorkflowSetupForm(forms.ModelForm):
class Meta:
exclude = ('initial_node,')
model = Workflow
@@ -27,19 +42,29 @@ class WorkflowStateSetupForm(forms.ModelForm):
model = WorkflowState
class TransitionSetupForm(forms.ModelForm):
class Meta:
model = Transition
class WorkflowStateTransitionSetupForm(forms.ModelForm):
class WorkflowNodeSetupForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
workflow_state = kwargs.pop('workflow_state')
super(WorkflowStateTransitionSetupForm, self).__init__(*args, **kwargs)
self.fields['workflow_state_source'].initial = workflow_state
self.fields['workflow_state_source'].widget = forms.widgets.HiddenInput()
workflow = kwargs.pop('workflow')
super(WorkflowNodeSetupForm, self).__init__(*args, **kwargs)
self.fields['workflow'].initial = workflow
self.fields['workflow'].widget = forms.widgets.HiddenInput()
class Meta:
model = WorkflowStateTransition
model = WorkflowNode
#class TransitionSetupForm(forms.ModelForm):
# class Meta:
# model = Transition
#class WorkflowStateTransitionSetupForm(forms.ModelForm):
# def __init__(self, *args, **kwargs):
# workflow_state = kwargs.pop('workflow_state')
# super(WorkflowStateTransitionSetupForm, self).__init__(*args, **kwargs)
# self.fields['workflow_state_source'].initial = workflow_state
# self.fields['workflow_state_source'].widget = forms.widgets.HiddenInput()
#
# class Meta:
# model = WorkflowStateTransition

View File

@@ -7,3 +7,13 @@ OPERAND_CHOICES = (
(OPERAND_OR, _(u'or')),
(OPERAND_AND, _(u'and'))
)
NODE_TYPE_TASK = 'task'
NODE_TYPE_START = 'start'
NODE_TYPE_END = 'end'
NODE_TYPE_CHOICES = (
(NODE_TYPE_TASK, _(u'Simple task')),
(NODE_TYPE_START, _(u'Start')),
(NODE_TYPE_END, _(u'End')),
)

View File

@@ -0,0 +1,231 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'WorkflowInstance', fields ['object_id', 'content_type', 'workflow']
db.delete_unique('workflows_workflowinstance', ['object_id', 'content_type_id', 'workflow_id'])
# Deleting model 'WorkflowStateAbilityGrant'
db.delete_table('workflows_workflowstateabilitygrant')
# Deleting model 'WorkflowStateTransition'
db.delete_table('workflows_workflowstatetransition')
# Deleting model 'WorkflowStateTransitionAbility'
db.delete_table('workflows_workflowstatetransitionability')
# Deleting model 'Transition'
db.delete_table('workflows_transition')
# Adding model 'WorkflowInstanceActiveState'
db.create_table('workflows_workflowinstanceactivestate', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('workflow_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowInstance'])),
('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.State'], null=True)),
))
db.send_create_signal('workflows', ['WorkflowInstanceActiveState'])
# Adding unique constraint on 'WorkflowInstanceActiveState', fields ['workflow_instance', 'state']
db.create_unique('workflows_workflowinstanceactivestate', ['workflow_instance_id', 'state_id'])
# Adding model 'End'
db.create_table('workflows_end', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('label', self.gf('django.db.models.fields.CharField')(max_length=128)),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
))
db.send_create_signal('workflows', ['End'])
# Adding model 'WorkflowInstanceActiveNode'
db.create_table('workflows_workflowinstanceactivenode', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('workflow_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowInstance'])),
('workflow_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowNode'])),
))
db.send_create_signal('workflows', ['WorkflowInstanceActiveNode'])
# Adding model 'Start'
db.create_table('workflows_start', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('label', self.gf('django.db.models.fields.CharField')(max_length=128)),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'], null=True)),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)),
))
db.send_create_signal('workflows', ['Start'])
# Adding model 'WorkflowNode'
db.create_table('workflows_workflownode', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('workflow', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.Workflow'])),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
))
db.send_create_signal('workflows', ['WorkflowNode'])
# Adding field 'Workflow.initial_node'
db.add_column('workflows_workflow', 'initial_node', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='workflow_initial_node', null=True, to=orm['workflows.WorkflowNode']), keep_default=False)
# Deleting field 'WorkflowInstance.workflow_state'
db.delete_column('workflows_workflowinstance', 'workflow_state_id')
# Adding unique constraint on 'WorkflowState', fields ['state', 'workflow']
db.create_unique('workflows_workflowstate', ['state_id', 'workflow_id'])
def backwards(self, orm):
# Removing unique constraint on 'WorkflowState', fields ['state', 'workflow']
db.delete_unique('workflows_workflowstate', ['state_id', 'workflow_id'])
# Removing unique constraint on 'WorkflowInstanceActiveState', fields ['workflow_instance', 'state']
db.delete_unique('workflows_workflowinstanceactivestate', ['workflow_instance_id', 'state_id'])
# Adding model 'WorkflowStateAbilityGrant'
db.create_table('workflows_workflowstateabilitygrant', (
('workflow_state', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability', to=orm['workflows.WorkflowState'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability_object', to=orm['contenttypes.ContentType'])),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
))
db.send_create_signal('workflows', ['WorkflowStateAbilityGrant'])
# Adding model 'WorkflowStateTransition'
db.create_table('workflows_workflowstatetransition', (
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
('workflow_state_source', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_source', to=orm['workflows.WorkflowState'])),
('transition', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition', to=orm['workflows.Transition'])),
('workflow_state_destination', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_destination', to=orm['workflows.WorkflowState'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('workflows', ['WorkflowStateTransition'])
# Adding model 'WorkflowStateTransitionAbility'
db.create_table('workflows_workflowstatetransitionability', (
('ability', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_ability', to=orm['workflows.Ability'])),
('attribute_comparison_operand', self.gf('django.db.models.fields.CharField')(default='and', max_length=8)),
('negate', self.gf('django.db.models.fields.BooleanField')(default=False)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
))
db.send_create_signal('workflows', ['WorkflowStateTransitionAbility'])
# Adding model 'Transition'
db.create_table('workflows_transition', (
('label', self.gf('django.db.models.fields.CharField')(max_length=128)),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('workflows', ['Transition'])
# Deleting model 'WorkflowInstanceActiveState'
db.delete_table('workflows_workflowinstanceactivestate')
# Deleting model 'End'
db.delete_table('workflows_end')
# Deleting model 'WorkflowInstanceActiveNode'
db.delete_table('workflows_workflowinstanceactivenode')
# Deleting model 'Start'
db.delete_table('workflows_start')
# Deleting model 'WorkflowNode'
db.delete_table('workflows_workflownode')
# Deleting field 'Workflow.initial_node'
db.delete_column('workflows_workflow', 'initial_node_id')
# User chose to not deal with backwards NULL issues for 'WorkflowInstance.workflow_state'
raise RuntimeError("Cannot reverse this migration. 'WorkflowInstance.workflow_state' and its values cannot be restored.")
# Adding unique constraint on 'WorkflowInstance', fields ['object_id', 'content_type', 'workflow']
db.create_unique('workflows_workflowinstance', ['object_id', 'content_type_id', 'workflow_id'])
models = {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'workflows.ability': {
'Meta': {'object_name': 'Ability'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
},
'workflows.end': {
'Meta': {'object_name': 'End'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
'workflows.start': {
'Meta': {'object_name': 'Start'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'})
},
'workflows.state': {
'Meta': {'object_name': 'State'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
'workflows.workflow': {
'Meta': {'object_name': 'Workflow'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_initial_node'", 'null': 'True', 'to': "orm['workflows.WorkflowNode']"}),
'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_initial_state'", 'null': 'True', 'to': "orm['workflows.WorkflowState']"}),
'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
},
'workflows.workflowinstance': {
'Meta': {'object_name': 'WorkflowInstance'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_instance_object'", 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"})
},
'workflows.workflowinstanceactivenode': {
'Meta': {'object_name': 'WorkflowInstanceActiveNode'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'workflow_instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowInstance']"}),
'workflow_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowNode']"})
},
'workflows.workflowinstanceactivestate': {
'Meta': {'unique_together': "(('workflow_instance', 'state'),)", 'object_name': 'WorkflowInstanceActiveState'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']", 'null': 'True'}),
'workflow_instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowInstance']"})
},
'workflows.workflownode': {
'Meta': {'object_name': 'WorkflowNode'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"})
},
'workflows.workflowstate': {
'Meta': {'unique_together': "(('workflow', 'state'),)", 'object_name': 'WorkflowState'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"}),
'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"})
}
}
complete_apps = ['workflows']

View File

@@ -4,11 +4,14 @@ from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from permissions.models import StoredPermission
from .literals import OPERAND_CHOICES, OPERAND_AND
#from .literals import NODE_TYPE_TASK, NODE_TYPE_START, NODE_TYPE_END
#NODE_TYPE_CHOICES
class Ability(models.Model):
label = models.CharField(max_length=128, unique=True, verbose_name = _(u'label'))
@@ -24,44 +27,149 @@ class Ability(models.Model):
class Workflow(models.Model):
label = models.CharField(max_length=128, unique=True, verbose_name = _(u'label'))
initial_node = models.ForeignKey('WorkflowNode', related_name='workflow_initial_node', blank=True, null=True, verbose_name=_(u'initial node'))
initial_state = models.ForeignKey('WorkflowState', related_name='workflow_initial_state', blank=True, null=True, verbose_name=_(u'initial state'))
description = models.TextField(blank=True, verbose_name=_(u'description'))
def __unicode__(self):
return self.label
@property
def workflow_nodes(self):
return self.workflownode_set
def get_nodes(self):
return [workflow_node.node for workflow_node in self.workflownode_set.all()]
def add_node(self, node):
workflow_node = WorkflowNode(
workflow=self,
node=node)
workflow_node.save()
return workflow_node
def save(self, *args, **kwargs):
is_new = not self.pk
result = super(Workflow, self).save(*args, **kwargs)
if is_new:
# Instanciate a new start node
start_node = Start()
start_node.save()
# Set the start node a
workflow_node = self.add_node(node=start_node)
self.initial_node = workflow_node
self.save()
return result
class Meta:
verbose_name = _(u'workflow')
verbose_name_plural = _(u'workflows')
class Node(models.Model):
"""
Must provide:
possible_next_nodes()
Arguments: None
Returns:
List of possible nodes after this one executes
choices()
Arguments: workflow
Returns:
{
'next_node': workflow.nodes.all()
}
execute()
Arguments: workflow_instance
Returns: next_node
"""
label = models.CharField(max_length=128, verbose_name=_(u'label'))
description = models.TextField(blank=True, verbose_name=_(u'description'))
def __unicode__(self):
return self.label
class Meta:
verbose_name = _(u'state')
verbose_name_plural = _(u'states')
abstract = True
class Start(Node):
"""
The node with which all workflows start
"""
content_type = models.ForeignKey(ContentType, null=True)
object_id = models.PositiveIntegerField(null=True)
next_node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id')
def __unicode__(self):
return ugettext(u'Start')
def possible_next_nodes(self):
return self.next_node
def choices(self, workflow):
return {
'next_node': workflow.nodes.all()
}
def execute(self, workflow_instance):
return self.next_node
class Meta(Node.Meta):
verbose_name = _(u'start')
verbose_name_plural = _(u'starts')
class End(Node):
class Meta(Node.Meta):
verbose_name = _(u'start')
verbose_name_plural = _(u'starts')
'''
class Sequence(Node):
"""
A node that is enabled after the completion of a preceding node in the same workflow
"""
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
next_node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id')
#node_type = NODE_TYPE_TASK
def execute(self):
return self.next_node
class Meta(Node.Meta):
verbose_name = _(u'task')
verbose_name_plural = _(u'tasks')
'''
class State(models.Model):
label = models.CharField(max_length=128, verbose_name=_(u'label'))
description = models.TextField(blank=True, verbose_name=_(u'description'))
def __unicode__(self):
#return '%s (%s)' % (self.name, self.workflow.name)
return self.label
class Meta:
verbose_name = _(u'state')
verbose_name_plural = _(u'states')
class Transition(models.Model):
label = models.CharField(max_length=128, verbose_name=_(u'label'))
description = models.TextField(blank=True, verbose_name=_(u'description'))
def __unicode__(self):
#return '%s (%s)' % (self.name, self.workflow.name)
return self.label
class Meta:
verbose_name = _(u'transition')
verbose_name_plural = _(u'transitions')
ordering = ('label',)
class WorkflowState(models.Model):
"""
List of possible states the object of this worflow could be in
"""
workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow'))
state = models.ForeignKey(State, verbose_name=_(u'state'))
description = models.TextField(blank=True, verbose_name=_(u'description'))
@@ -69,17 +177,33 @@ class WorkflowState(models.Model):
def __unicode__(self):
return unicode(self.state)
@property
def transitions(self):
return self.workflowstatetransition_set
class Meta:
#unique_together = ('workflow', 'state')
unique_together = ('workflow', 'state')
verbose_name = _(u'workflow state')
verbose_name_plural = _(u'workflows states')
# TODO: Reduntant - remove
class WorkflowNode(models.Model):
workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow'))
content_type = models.ForeignKey(ContentType)#, limit_choices_to={'model__in': ('model1', 'model2')})#, related_name='workflow_state_ability_object')#, blank=True, null=True)
object_id = models.PositiveIntegerField()#blank=True, null=True)
node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id')
description = models.TextField(blank=True, verbose_name=_(u'description'))
class WorkflowStateAbilityGrant(models.Model):
def __unicode__(self):
return unicode(self.node)
#def save(self, *args, **kwargs):
# if not issubclass(
# return super(WorkflowNode, self).save(*args, **kwargs)
class Meta:
#unique_together = ('workflow', 'state')
verbose_name = _(u'workflow node')
verbose_name_plural = _(u'workflows nodes')
"""
class WorkflowTaskAbilityGrant(models.Model):
workflow_state = models.ForeignKey(WorkflowState, related_name='workflow_state_ability', verbose_name=_(u'workflow state'))
content_type = models.ForeignKey(ContentType, related_name='workflow_state_ability_object')#, blank=True, null=True)
object_id = models.PositiveIntegerField()#blank=True, null=True)
@@ -133,16 +257,69 @@ class WorkflowStateTransitionAbility(models.Model):
verbose_name = _(u'transition')
verbose_name_plural = _(u'transitions')
"""
class WorkflowInstance(models.Model):
workflow = models.ForeignKey(Workflow, verbose_name = _(u'workflow'))
workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow'))
content_type = models.ForeignKey(ContentType, verbose_name=_(u'Content type'), related_name='workflow_instance_object')#, blank=True, null=True)
object_id = models.PositiveIntegerField()#blank=True, null=True)
content_object = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id')
workflow_state = models.ForeignKey(WorkflowState, related_name='workflow_instance_state', verbose_name=_(u'state'))
def __unicode__(self):
return unicode(self.content_object)
@property
def active_nodes(self):
return self.workflowinstanceactivenode_set
def set_active_state(self, state):
active_state = self.get_active_state()
if active_state:
active_state.delete()
# Trigger an exception if the state argument if not allowed for this workflow
state = WorkflowState.objects.get(workflow=self.workflow, state=state).state
self.workflowinstanceactivestate_set.create(
workflow_instance = self,
state = state
)
def get_active_state(self):
try:
return self.workflowinstanceactivestate_set.get().state
except WorkflowInstanceActiveState.DoesNotExist:
return None
active_state = property(get_active_state, set_active_state)
class Meta:
unique_together = ('content_type', 'object_id', 'workflow')
verbose_name = _(u'workflow instance')
verbose_name_plural = _(u'workflow instances')
# unique_together = ('content_type', 'object_id', 'workflow')
class WorkflowInstanceActiveNode(models.Model):
workflow_instance = models.ForeignKey(WorkflowInstance, verbose_name=_(u'workflow instance'))
workflow_node = models.ForeignKey(WorkflowNode, verbose_name=_(u'workflow node'))
class Meta:
verbose_name = _(u'workflow instance active node')
verbose_name_plural = _(u'workflow instances active nodes')
class WorkflowInstanceActiveState(models.Model):
"""
This class holds the active state for the workflow instance
"""
workflow_instance = models.ForeignKey(WorkflowInstance, verbose_name=_(u'workflow instance'))
state = models.ForeignKey(State, null=True, verbose_name=_(u'state'))
class Meta:
unique_together = ('workflow_instance', 'state')
verbose_name = _(u'workflow instance active state')
verbose_name_plural = _(u'workflow instances active states')
# TODO: WorkflowInstanceActiveNodeHistory
# TODO: WorkflowInstanceActiveStateHistory

View File

@@ -16,8 +16,8 @@ PERMISSION_STATE_SETUP_CREATE = Permission.objects.register(namespace, 'state_se
PERMISSION_STATE_SETUP_EDIT = Permission.objects.register(namespace, 'state_setup_edit', _(u'Edit existing state templates'))
PERMISSION_STATE_SETUP_DELETE = Permission.objects.register(namespace, 'state_setup_delete', _(u'Delete existing state templates'))
PERMISSION_TRANSITION_SETUP_VIEW = Permission.objects.register(namespace, 'transition_setup_view', _(u'View existing transition templates'))
PERMISSION_TRANSITION_SETUP_CREATE = Permission.objects.register(namespace, 'transition_setup_create', _(u'Create new transition templates'))
PERMISSION_TRANSITION_SETUP_EDIT = Permission.objects.register(namespace, 'transition_setup_edit', _(u'Edit existing transition templates'))
PERMISSION_TRANSITION_SETUP_DELETE = Permission.objects.register(namespace, 'transition_setup_delete', _(u'Delete existing transition templates'))
#PERMISSION_TRANSITION_SETUP_VIEW = Permission.objects.register(namespace, 'transition_setup_view', _(u'View existing transition templates'))
#PERMISSION_TRANSITION_SETUP_CREATE = Permission.objects.register(namespace, 'transition_setup_create', _(u'Create new transition templates'))
#PERMISSION_TRANSITION_SETUP_EDIT = Permission.objects.register(namespace, 'transition_setup_edit', _(u'Edit existing transition templates'))
#PERMISSION_TRANSITION_SETUP_DELETE = Permission.objects.register(namespace, 'transition_setup_delete', _(u'Delete existing transition templates'))

View File

@@ -11,17 +11,11 @@ urlpatterns = patterns('workflows.views',
url(r'^setup/workflow/state/(?P<workflow_state_pk>\d+)/edit/$', 'setup_workflow_state_edit', (), 'setup_workflow_state_edit'),
url(r'^setup/workflow/state/(?P<workflow_state_pk>\d+)/remove/$', 'setup_workflow_state_remove', (), 'setup_workflow_state_remove'),
url(r'^setup/workflow/state/(?P<workflow_state_pk>\d+)/transition/list/$', 'setup_workflow_state_transitions_list', (), 'setup_workflow_state_transitions_list'),
url(r'^setup/workflow/state/(?P<workflow_state_pk>\d+)/transition/add/$', 'setup_workflow_state_transition_add', (), 'setup_workflow_state_transition_add'),
url(r'^setup/workflow/state/transition/(?P<workflow_state_transition_pk>\d+)/edit/$', 'setup_workflow_state_transition_edit', (), 'setup_workflow_state_transition_edit'),
url(r'^setup/state/list/$', 'setup_state_list', (), 'setup_state_list'),
url(r'^setup/state/create/$', 'setup_state_create', (), 'setup_state_create'),
url(r'^setup/state/(?P<state_pk>\d+)/edit/$', 'setup_state_edit', (), 'setup_state_edit'),
url(r'^setup/state/(?P<state_pk>\d+)/delete/$', 'setup_state_delete', (), 'setup_state_delete'),
url(r'^setup/transition/list/$', 'setup_transition_list', (), 'setup_transition_list'),
url(r'^setup/transition/create/$', 'setup_transition_create', (), 'setup_transition_create'),
url(r'^setup/transition/(?P<transition_pk>\d+)/edit/$', 'setup_transition_edit', (), 'setup_transition_edit'),
url(r'^setup/transition/(?P<transition_pk>\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_delete'),
url(r'^setup/workflow/(?P<workflow_pk>\d+)/node/list/$', 'setup_workflow_node_list', (), 'setup_workflow_node_list'),
url(r'^setup/workflow/node/(?P<workflow_node_pk>\d+)/edit/$', 'setup_workflow_node_edit', (), 'setup_workflow_node_edit'),
)

View File

@@ -18,18 +18,14 @@ from common.utils import encapsulate
#from common.widgets import two_state_template
#from acls.models import AccessEntry
from .models import Workflow, State, Transition, WorkflowState
from .models import Workflow, State, WorkflowState, WorkflowNode
from .forms import (WorkflowSetupForm, StateSetupForm,
WorkflowStateSetupForm, TransitionSetupForm,
WorkflowStateTransitionSetupForm)
WorkflowStateSetupForm, WorkflowNodeSetupForm)
from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW,
PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT,
PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW,
PERMISSION_STATE_SETUP_CREATE, PERMISSION_STATE_SETUP_EDIT,
PERMISSION_STATE_SETUP_DELETE, PERMISSION_TRANSITION_SETUP_VIEW,
PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT,
PERMISSION_TRANSITION_SETUP_DELETE)
PERMISSION_STATE_SETUP_DELETE)
logger = logging.getLogger(__name__)
@@ -207,7 +203,7 @@ def setup_workflow_state_edit(request, workflow_state_pk):
form = WorkflowStateSetupForm(workflow=workflow_state.workflow, instance=workflow_state)
return render_to_response('generic_form.html', {
'title': _(u'edit worflow state'),
'title': _(u'edit worflow state: %s') % workflow_state,
'form': form,
'workflow': workflow_state.workflow,
'workflow_state': workflow_state,
@@ -272,6 +268,54 @@ def setup_workflow_state_remove(request, workflow_state_pk=None, workflow_state_
context_instance=RequestContext(request))
# Nodes
def setup_workflow_node_list(request, workflow_pk):
Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT])
workflow = get_object_or_404(Workflow, pk=workflow_pk)
context = {
'object_list': workflow.workflow_nodes.all(),
'extra_columns': [
{'name': _(u'Posible next nodes'), 'attribute': encapsulate(lambda workflow_node: workflow_node.node.possible_next_nodes() or _(u'None'))},
],
'title': _(u'nodes of workflow: %s') % workflow,
'hide_link': True,
'workflow': workflow,
'navigation_object_list': [
{'object': 'workflow', 'name': _(u'workflow')},
],
'list_object_variable_name': 'workflow_node',
}
return render_to_response('generic_list.html', context,
context_instance=RequestContext(request))
def setup_workflow_node_edit(request, workflow_node_pk):
Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT])
workflow_node = get_object_or_404(WorkflowNode, pk=workflow_node_pk)
redirect_url = reverse('setup_workflow_node_list', args=[workflow_node.workflow.pk])
if request.method == 'POST':
form = WorkflowNodeSetupForm(workflow=workflow_node.workflow, instance=workflow_node, data=request.POST)
if form.is_valid():
state = form.save()
messages.success(request, _(u'worflow node edited succesfully.'))
return HttpResponseRedirect(redirect_url)
else:
form = WorkflowNodeSetupForm(workflow=workflow_node.workflow, instance=workflow_node)
return render_to_response('generic_form.html', {
'title': _(u'edit worflow node: %s') % workflow_node,
'form': form,
'workflow': workflow_node.workflow,
'workflow_node': workflow_node,
'navigation_object_list': [
{'object': 'workflow', 'name': _(u'workflow')},
{'object': 'workflow_node', 'name': _(u'workflow node')}
],
}, context_instance=RequestContext(request))
"""
def setup_workflow_transition_list(request, state_workflow_pk):
Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT])
workflow = get_object_or_404(Workflow, pk=workflow_pk)
@@ -289,6 +333,7 @@ def setup_workflow_transition_list(request, state_workflow_pk):
return render_to_response('generic_list.html', context,
context_instance=RequestContext(request))
"""
# States
def setup_state_list(request):
Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_VIEW])
@@ -395,7 +440,7 @@ def setup_state_delete(request, state_pk=None, state_pk_list=None):
return render_to_response('generic_confirm.html', context,
context_instance=RequestContext(request))
"""
# Transitions
def setup_transition_list(request):
Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_VIEW])
@@ -507,8 +552,8 @@ def setup_transition_delete(request, transition_pk=None, transition_pk_list=None
return render_to_response('generic_confirm.html', context,
context_instance=RequestContext(request))
"""
"""
# State transitions
def setup_workflow_state_transitions_list(request, workflow_state_pk):
Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT])
@@ -587,7 +632,7 @@ def setup_workflow_state_transition_edit(request, work_state_transition_pk):
],
'list_object_variable_name': 'workflow_state_transition',
}, context_instance=RequestContext(request))
"""
"""
def setup_state_transition_remove(request, state_transition_pk=None, state_transition_pk_list=None):
post_action_redirect = None