Improve document detection by workflow state including initial state.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2017-07-07 13:00:22 -04:00
parent 998af4931f
commit e4c88e575f
8 changed files with 97 additions and 57 deletions

View File

@@ -87,6 +87,7 @@ Other Changes
will be loaded and visible by default when a view loads. will be loaded and visible by default when a view loads.
- Improve usability and appearance on medium and small devices like - Improve usability and appearance on medium and small devices like
tablets and smartphones. tablets and smartphones.
- Improve document detection by initial workflow state.
Removals Removals
-------- --------

View File

@@ -31,7 +31,9 @@ class APIDocumentTypeWorkflowListView(generics.ListAPIView):
""" """
Returns a list of all the document type workflows. Returns a list of all the document type workflows.
""" """
return super(APIDocumentTypeWorkflowListView, self).get(*args, **kwargs) return super(
APIDocumentTypeWorkflowListView, self
).get(*args, **kwargs)
def get_document_type(self): def get_document_type(self):
document_type = get_object_or_404(DocumentType, pk=self.kwargs['pk']) document_type = get_object_or_404(DocumentType, pk=self.kwargs['pk'])
@@ -600,4 +602,6 @@ class APIWorkflowInstanceLogEntryListView(generics.ListCreateAPIView):
Transition a document workflow by creating a new document workflow Transition a document workflow by creating a new document workflow
log entry. log entry.
""" """
return super(APIWorkflowInstanceLogEntryListView, self).post(*args, **kwargs) return super(
APIWorkflowInstanceLogEntryListView, self
).post(*args, **kwargs)

View File

@@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import apps from django.apps import apps
from django.db.models.signals import pre_delete, post_delete, post_save from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from kombu import Exchange, Queue from kombu import Exchange, Queue

View File

@@ -22,8 +22,17 @@ class WorkflowTransitionForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
workflow = kwargs.pop('workflow') workflow = kwargs.pop('workflow')
super(WorkflowTransitionForm, self).__init__(*args, **kwargs) super(WorkflowTransitionForm, self).__init__(*args, **kwargs)
self.fields['origin_state'].queryset = self.fields['origin_state'].queryset.filter(workflow=workflow) self.fields[
self.fields['destination_state'].queryset = self.fields['destination_state'].queryset.filter(workflow=workflow) 'origin_state'
].queryset = self.fields[
'origin_state'
].queryset.filter(workflow=workflow)
self.fields[
'destination_state'
].queryset = self.fields[
'destination_state'
].queryset.filter(workflow=workflow)
class Meta: class Meta:
fields = ('label', 'origin_state', 'destination_state') fields = ('label', 'origin_state', 'destination_state')

View File

@@ -96,7 +96,8 @@ link_workflow_list = Link(
) )
link_workflow_state_document_list = Link( link_workflow_state_document_list = Link(
permissions=(permission_workflow_view,), permissions=(permission_workflow_view,),
text=_('State documents'), view='document_states:workflow_state_document_list', text=_('State documents'),
view='document_states:workflow_state_document_list',
args='resolved_object.pk' args='resolved_object.pk'
) )
link_workflow_state_list = Link( link_workflow_state_list = Link(

View File

@@ -36,14 +36,24 @@ class Migration(migrations.Migration):
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='workflow', name='workflow',
options={'ordering': ('label',), 'verbose_name': 'Workflow', 'verbose_name_plural': 'Workflows'}, options={
'ordering': ('label',),
'verbose_name': 'Workflow', 'verbose_name_plural': 'Workflows'
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='workflowstate', name='workflowstate',
options={'ordering': ('label',), 'verbose_name': 'Workflow state', 'verbose_name_plural': 'Workflow states'}, options={
'ordering': ('label',),
'verbose_name': 'Workflow state',
'verbose_name_plural': 'Workflow states'
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='workflowtransition', name='workflowtransition',
options={'ordering': ('label',), 'verbose_name': 'Workflow transition', 'verbose_name_plural': 'Workflow transitions'}, options={
'ordering': ('label',), 'verbose_name': 'Workflow transition',
'verbose_name_plural': 'Workflow transitions'
},
), ),
] ]

View File

@@ -6,6 +6,7 @@ from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import IntegrityError, models from django.db import IntegrityError, models
from django.db.models import F, Max, Q
from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -106,6 +107,12 @@ class WorkflowState(models.Model):
), verbose_name=_('Completion') ), verbose_name=_('Completion')
) )
class Meta:
ordering = ('label',)
unique_together = ('workflow', 'label')
verbose_name = _('Workflow state')
verbose_name_plural = _('Workflow states')
def __str__(self): def __str__(self):
return self.label return self.label
@@ -114,11 +121,30 @@ class WorkflowState(models.Model):
self.workflow.states.all().update(initial=False) self.workflow.states.all().update(initial=False)
return super(WorkflowState, self).save(*args, **kwargs) return super(WorkflowState, self).save(*args, **kwargs)
class Meta: def get_documents(self):
ordering = ('label',) latest_entries = WorkflowInstanceLogEntry.objects.annotate(
unique_together = ('workflow', 'label') max_datetime=Max(
verbose_name = _('Workflow state') 'workflow_instance__log_entries__datetime'
verbose_name_plural = _('Workflow states') )
).filter(
datetime=F('max_datetime')
)
state_latest_entries = latest_entries.filter(
transition__destination_state=self
)
return Document.objects.filter(
Q(
workflows__pk__in=state_latest_entries.values_list(
'workflow_instance', flat=True
)
) | Q(
workflows__log_entries__isnull=True,
workflows__workflow__states=self,
workflows__workflow__states__initial=True
)
).distinct()
@python_2_unicode_compatible @python_2_unicode_compatible

View File

@@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse, reverse_lazy from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import F, Max
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@@ -21,8 +20,8 @@ from .forms import (
WorkflowTransitionForm WorkflowTransitionForm
) )
from .models import ( from .models import (
Workflow, WorkflowInstance, WorkflowInstanceLogEntry, WorkflowState, Workflow, WorkflowInstance, WorkflowState, WorkflowTransition,
WorkflowTransition, WorkflowRuntimeProxy, WorkflowStateRuntimeProxy WorkflowRuntimeProxy, WorkflowStateRuntimeProxy
) )
from .permissions import ( from .permissions import (
permission_workflow_create, permission_workflow_delete, permission_workflow_create, permission_workflow_delete,
@@ -97,6 +96,11 @@ class WorkflowInstanceTransitionView(FormView):
comment=form.cleaned_data['comment'], comment=form.cleaned_data['comment'],
transition=form.cleaned_data['transition'], user=self.request.user transition=form.cleaned_data['transition'], user=self.request.user
) )
messages.success(
self.request, _(
'Document "%s" transitioned successfully'
) % self.get_workflow_instance().document
)
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
def get_extra_context(self): def get_extra_context(self):
@@ -405,7 +409,7 @@ class WorkflowListView(SingleObjectListView):
def get_extra_context(self): def get_extra_context(self):
return { return {
'hide_link': True, 'hide_object': True,
'title': _('Workflows') 'title': _('Workflows')
} }
@@ -437,51 +441,36 @@ class WorkflowDocumentListView(DocumentListView):
class WorkflowStateDocumentListView(DocumentListView): class WorkflowStateDocumentListView(DocumentListView):
def dispatch(self, request, *args, **kwargs): def get_document_queryset(self):
self.workflow_state = get_object_or_404( return self.get_workflow_state().get_documents()
def get_extra_context(self):
workflow_state = self.get_workflow_state()
return {
'hide_links': True,
'object': workflow_state,
'navigation_object_list': ('object', 'workflow'),
'workflow': WorkflowRuntimeProxy.objects.get(
pk=workflow_state.workflow.pk
),
'title': _(
'Documents in the workflow "%s", state "%s"'
) % (
workflow_state.workflow, workflow_state
)
}
def get_workflow_state(self):
workflow_state = get_object_or_404(
WorkflowStateRuntimeProxy, pk=self.kwargs['pk'] WorkflowStateRuntimeProxy, pk=self.kwargs['pk']
) )
AccessControlList.objects.check_access( AccessControlList.objects.check_access(
permissions=permission_workflow_view, user=request.user, permissions=permission_workflow_view, user=self.request.user,
obj=self.workflow_state.workflow obj=workflow_state.workflow
) )
return super( return workflow_state
WorkflowStateDocumentListView, self
).dispatch(request, *args, **kwargs)
def get_document_queryset(self):
latest_entries = WorkflowInstanceLogEntry.objects.annotate(
max_datetime=Max(
'workflow_instance__log_entries__datetime'
)
).filter(
datetime=F('max_datetime')
)
state_latest_entries = latest_entries.filter(
transition__destination_state=self.workflow_state
)
return Document.objects.filter(
workflows__pk__in=state_latest_entries.values_list(
'workflow_instance', flat=True
)
)
def get_extra_context(self):
return {
'hide_links': True,
'object': self.workflow_state,
'navigation_object_list': ('object', 'workflow'),
'workflow': WorkflowRuntimeProxy.objects.get(
pk=self.workflow_state.workflow.pk
),
'title': _(
'Documents in the workflow "%s", state "%s"'
) % (self.workflow_state.workflow, self.workflow_state)
}
class WorkflowStateListView(SingleObjectListView): class WorkflowStateListView(SingleObjectListView):