From 7d3aa0774b92b901a05540af62da9e5a305a2c7f Mon Sep 17 00:00:00 2001
From: Todd Dembrey <todd.dembrey@torchbox.com>
Date: Wed, 13 Jun 2018 11:42:35 +0100
Subject: [PATCH] Move the state change to use a signal across all status
 changes

---
 opentech/apply/activity/models.py             | 17 ++++++++++
 opentech/apply/funds/forms.py                 |  4 +--
 opentech/apply/funds/models.py                |  2 +-
 .../funds/applicationsubmission_form.html     |  4 ++-
 opentech/apply/funds/views.py                 | 33 +++++++++++++++----
 5 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/opentech/apply/activity/models.py b/opentech/apply/activity/models.py
index 643ca3cae..d17c46c11 100644
--- a/opentech/apply/activity/models.py
+++ b/opentech/apply/activity/models.py
@@ -3,6 +3,8 @@ from django.db import models
 from django.db.models.signals import post_save
 from django.dispatch import receiver
 
+from django_fsm.signals import post_transition
+
 from opentech.apply.funds.models import ApplicationSubmission
 
 COMMENT = 'comment'
@@ -112,3 +114,18 @@ def log_submission_activity(sender, **kwargs):
             submission=submission,
             message=f'Submitted {submission.title} for {submission.page.title}'
         )
+
+
+@receiver(post_transition, sender=ApplicationSubmission)
+def log_status_update(sender, **kwargs):
+    instance = kwargs['instance']
+    old_phase = instance.workflow[kwargs['source']].display_name
+    new_phase = instance.workflow[kwargs['target']].display_name
+
+    by = kwargs['method_kwargs']['by']
+
+    Activity.actions.create(
+        user=by,
+        submission=instance,
+        message=f'Progressed from {old_phase} to {new_phase}'
+    )
diff --git a/opentech/apply/funds/forms.py b/opentech/apply/funds/forms.py
index 3f150b64f..8f6855338 100644
--- a/opentech/apply/funds/forms.py
+++ b/opentech/apply/funds/forms.py
@@ -15,7 +15,7 @@ class ProgressSubmissionForm(forms.ModelForm):
         fields: list = []
 
     def __init__(self, *args, **kwargs):
-        kwargs.pop('user')
+        self.user = kwargs.pop('user')
         super().__init__(*args, **kwargs)
         choices = [(name, action) for name, action in self.instance.phase.transitions.items()]
         action_field = self.fields['action']
@@ -32,7 +32,7 @@ class ProgressSubmissionForm(forms.ModelForm):
         return action_name
 
     def save(self, *args, **kwargs):
-        self.transition()
+        self.transition(by=self.user)
         return super().save(*args, **kwargs)
 
 
diff --git a/opentech/apply/funds/models.py b/opentech/apply/funds/models.py
index fad44572d..e5f72cdfb 100644
--- a/opentech/apply/funds/models.py
+++ b/opentech/apply/funds/models.py
@@ -501,7 +501,7 @@ class AddTransitions(models.base.ModelBase):
                 for transition_name, action in data.all_transitions.items():
                     method = data.transition_methods.get(transition_name)
                     # Get the method defined on the parent or default to a NOOP
-                    transition_state = attrs.get(method, lambda self: None)
+                    transition_state = attrs.get(method, lambda *args, **kwargs: None)
                     # Provide a neat name for graph viz display
                     transition_state.__name__ = slugify(action)
                     # Wrap with transition decorator
diff --git a/opentech/apply/funds/templates/funds/applicationsubmission_form.html b/opentech/apply/funds/templates/funds/applicationsubmission_form.html
index d7911104f..da02a2a9f 100644
--- a/opentech/apply/funds/templates/funds/applicationsubmission_form.html
+++ b/opentech/apply/funds/templates/funds/applicationsubmission_form.html
@@ -19,7 +19,9 @@
             {{ field }}
             {% endif %}
         {% endfor %}
-        <input class="button button--primary" type="submit" value="Submit" />
+        {% for button_name, button_value in buttons %}
+            <input class="button button--primary" type="submit" name="{{ button_name }}" value="{{ button_value }}" />
+        {% endfor %}
     </form>
 </div>
 {% endblock %}
diff --git a/opentech/apply/funds/views.py b/opentech/apply/funds/views.py
index f1f16005e..78d05fa3b 100644
--- a/opentech/apply/funds/views.py
+++ b/opentech/apply/funds/views.py
@@ -70,14 +70,7 @@ class ProgressSubmissionView(DelegatedViewMixin, UpdateView):
     context_name = 'progress_form'
 
     def form_valid(self, form):
-        old_phase = form.instance.phase.display_name
         response = super().form_valid(form)
-        new_phase = form.instance.phase.display_name
-        Activity.actions.create(
-            user=self.request.user,
-            submission=self.kwargs['submission'],
-            message=f'Progressed from {old_phase} to {new_phase}'
-        )
         return self.progress_stage(form.instance) or response
 
     def progress_stage(self, instance):
@@ -197,6 +190,18 @@ class SubmissionEditView(UpdateView):
             raise PermissionDenied
         return super().dispatch(request, *args, **kwargs)
 
+    @property
+    def transitions(self):
+        transitions =  self.object.get_available_user_status_transitions(self.request.user)
+        return {
+            transition.name: transition
+            for transition in transitions
+        }
+
+    def buttons(self):
+        yield ('save', 'Save')
+        yield from ((transition, transition.title) for transition in self.transitions)
+
     def get_form_kwargs(self):
         kwargs = super().get_form_kwargs()
         instance = kwargs.pop('instance')
@@ -215,10 +220,24 @@ class SubmissionEditView(UpdateView):
         kwargs['initial'] = form_data
         return kwargs
 
+    def get_context_data(self, **kwargs):
+        return super().get_context_data(buttons=self.buttons(), **kwargs)
+
     def get_form_class(self):
         return self.object.get_form_class()
 
     def form_valid(self, form):
         self.object.form_data = form.cleaned_data
         self.object.save()
+
+        if 'save' in self.request.POST:
+            return self.form_invalid(form)
+
+        transition = set(self.request.POST.keys()) & set(self.transitions.keys())
+
+        if transition:
+            transition_object =self.transitions[transition.pop()]
+            self.object.get_transition(transition_object.target)(by=self.request.user)
+            self.object.save()
+
         return HttpResponseRedirect(self.get_success_url())
-- 
GitLab