Improve document detection by workflow state including initial state.
Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -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
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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'
|
||||||
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user