From 19136693feae9641669c5338ebb9237daa0685e8 Mon Sep 17 00:00:00 2001
From: Pete Andrew <peter.andrew@torchbox.com>
Date: Mon, 27 Apr 2020 16:05:37 +0100
Subject: [PATCH] Ref 1904: Improve display of Assign Reviewers action

- Added 'Assign Reviewers' primary action
- Only display action when in internal review and all reviewer roles haven't been assigned or when in external review
---
 hypha/apply/funds/models/submissions.py       |  5 +
 .../funds/includes/admin_primary_actions.html |  4 +
 hypha/apply/funds/tests/test_views.py         | 95 +++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/hypha/apply/funds/models/submissions.py b/hypha/apply/funds/models/submissions.py
index bd92c6b5b..3cc70395b 100644
--- a/hypha/apply/funds/models/submissions.py
+++ b/hypha/apply/funds/models/submissions.py
@@ -53,6 +53,7 @@ from ..workflow import (
     review_statuses,
 )
 from .mixins import AccessFormData
+from .reviewer_role import ReviewerRole
 from .utils import (
     COMMUNITY_REVIEWER_GROUP_NAME,
     LIMIT_TO_PARTNERS,
@@ -632,6 +633,10 @@ class ApplicationSubmission(
             self.draft_revision = first_revision
             self.save()
 
+    @property
+    def has_all_reviewer_roles_assigned(self):
+        return self.assigned.with_roles().count() == ReviewerRole.objects.count()
+
     @property
     def community_review(self):
         return self.status in COMMUNITY_REVIEW_PHASES
diff --git a/hypha/apply/funds/templates/funds/includes/admin_primary_actions.html b/hypha/apply/funds/templates/funds/includes/admin_primary_actions.html
index ce24879d7..4584d969e 100644
--- a/hypha/apply/funds/templates/funds/includes/admin_primary_actions.html
+++ b/hypha/apply/funds/templates/funds/includes/admin_primary_actions.html
@@ -22,6 +22,10 @@
 
 {% if object.in_internal_review_phase or object.in_external_review_phase %}
     {% include 'review/includes/review_button.html' with submission=object class="button--full-width button--bottom-space" draft_text="Complete draft review" %}
+
+    {% if object.in_external_review_phase or not object.has_all_reviewer_roles_assigned %}
+        <a data-fancybox data-src="#update-reviewers" class="button button--bottom-space button--primary button--full-width" href="#">Assign reviewers</a>
+    {% endif %}
 {% endif %}
 
 <a data-fancybox data-src="#update-status" class="button button--primary button--full-width {% if progress_form.should_show %}is-not-disabled{% else %}is-disabled{% endif %}" href="#">Update status</a>
diff --git a/hypha/apply/funds/tests/test_views.py b/hypha/apply/funds/tests/test_views.py
index cd30eb9d7..b219e16a8 100644
--- a/hypha/apply/funds/tests/test_views.py
+++ b/hypha/apply/funds/tests/test_views.py
@@ -328,6 +328,74 @@ class TestStaffSubmissionView(BaseSubmissionViewTestCase):
         assert_create_review_not_displayed(submission, 'Add a review')
         assert_create_review_not_displayed(submission, 'Complete draft review')
 
+    def test_can_see_assign_reviewers_primary_action(self):
+        def assert_assign_reviewers_displayed(submission):
+            response = self.get_page(submission)
+            buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--primary', text='Assign reviewers')
+            self.assertEqual(len(buttons), 1)
+
+        submission = ApplicationSubmissionFactory(status='internal_review')
+        reviewer_role_a = ReviewerRoleFactory()
+        reviewer_role_b = ReviewerRoleFactory()
+
+        # Phase: internal_review - no reviewers assigned
+        # Assign reviewers should be displayed
+        assert_assign_reviewers_displayed(submission)
+
+        # Phase: internal_review - not all reviewer types assigned
+        # Assign reviewers should be displayed
+        AssignedReviewersFactory(submission=submission, reviewer=ReviewerFactory(), role=reviewer_role_a)
+        assert_assign_reviewers_displayed(submission)
+
+        # Phase: external_review - no reviewers assigned
+        # Assign reviewers should be displayed
+        submission = ApplicationSubmissionFactory(with_external_review=True, status='ext_external_review')
+        assert_assign_reviewers_displayed(submission)
+
+        # Phase: external_review - all reviewers types assigned
+        # Assign reviewers should still be displayed
+        AssignedReviewersFactory(submission=submission, reviewer=ReviewerFactory(), role=reviewer_role_a)
+        AssignedReviewersFactory(submission=submission, reviewer=ReviewerFactory(), role=reviewer_role_b)
+        assert_assign_reviewers_displayed(submission)
+
+    def test_cant_see_assign_reviewers_primary_action(self):
+        def assert_assign_reviewers_not_displayed(submission):
+            response = self.get_page(submission)
+            buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--primary', text='Assign reviewers')
+            self.assertEqual(len(buttons), 0)
+
+        submission = ApplicationSubmissionFactory()
+        reviewer_role = ReviewerRoleFactory()
+
+        # Phase: received / in_discussion
+        # Assign reviewers should not be displayed
+        assert_assign_reviewers_not_displayed(submission)
+
+        # Phase: internal_review - all reviewer types assigned
+        # Assign reviewers should not be displayed
+        AssignedReviewersFactory(submission=submission, reviewer=ReviewerFactory(), role=reviewer_role)
+        assert_assign_reviewers_not_displayed(submission)
+
+    def test_can_see_assign_reviewers_secondary_action(self):
+        def assert_assign_reviewers_secondary_displayed(submission):
+            response = self.get_page(submission)
+            buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--white', text='Reviewers')
+            self.assertEqual(len(buttons), 1)
+
+        submission = ApplicationSubmissionFactory()
+        reviewer_role = ReviewerRoleFactory()
+
+        # Phase: received / in_discussion
+        assert_assign_reviewers_secondary_displayed(submission)
+
+        # Phase: internal_review - no reviewers assigned
+        submission.perform_transition('internal_review', self.user)
+        assert_assign_reviewers_secondary_displayed(submission)
+
+        # Phase: internal_review - all reviewer types assigned
+        AssignedReviewersFactory(submission=submission, reviewer=ReviewerFactory(), role=reviewer_role)
+        assert_assign_reviewers_secondary_displayed(submission)
+
 
 class TestReviewersUpdateView(BaseSubmissionViewTestCase):
     user_factory = StaffFactory
@@ -463,6 +531,7 @@ class TestReviewerSubmissionView(BaseSubmissionViewTestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.applicant = ApplicantFactory()
+        cls.reviewer_role = ReviewerRoleFactory()
 
     def test_cant_see_add_determination_primary_action(self):
         def assert_add_determination_not_displayed(submission, button_text):
@@ -540,6 +609,18 @@ class TestReviewerSubmissionView(BaseSubmissionViewTestCase):
         assert_create_review_not_displayed(submission, 'Add a review')
         assert_create_review_not_displayed(submission, 'Complete draft review')
 
+    def test_cant_see_assign_reviewers_primary_action(self):
+        submission = ApplicationSubmissionFactory(status='internal_review', user=self.applicant, reviewers=[self.user])
+        response = self.get_page(submission)
+        buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--primary', text='Assign reviewers')
+        self.assertEqual(len(buttons), 0)
+
+    def test_cant_see_assign_reviewers_secondary_action(self):
+        submission = ApplicationSubmissionFactory(status='internal_review', user=self.applicant, reviewers=[self.user])
+        response = self.get_page(submission)
+        buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--white', text='Reviewers')
+        self.assertEqual(len(buttons), 0)
+
 
 class TestApplicantSubmissionView(BaseSubmissionViewTestCase):
     user_factory = ApplicantFactory
@@ -677,6 +758,20 @@ class TestApplicantSubmissionView(BaseSubmissionViewTestCase):
         submission.perform_transition('internal_review', staff_user)
         assert_create_review_not_displayed(submission)
 
+    def test_cant_see_assign_reviewers_primary_action(self):
+        submission = ApplicationSubmissionFactory(status='internal_review', user=self.user)
+        ReviewerRoleFactory()
+        response = self.get_page(submission)
+        buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--primary', text='Assign reviewers')
+        self.assertEqual(len(buttons), 0)
+
+    def test_cant_see_assign_reviewers_secondary_action(self):
+        submission = ApplicationSubmissionFactory(status='internal_review', user=self.user)
+        ReviewerRoleFactory()
+        response = self.get_page(submission)
+        buttons = BeautifulSoup(response.content, 'html5lib').find(class_='sidebar').find_all('a', class_='button--white', text='Reviewers')
+        self.assertEqual(len(buttons), 0)
+
 
 class TestRevisionsView(BaseSubmissionViewTestCase):
     user_factory = ApplicantFactory
-- 
GitLab