diff --git a/hypha/apply/funds/models/submissions.py b/hypha/apply/funds/models/submissions.py index bd92c6b5b89172d68b951da3e0c199ff4cd7118e..3cc70395bd7a15582b47a6c20360c2a76100ed08 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 ce24879d7374300df10d94293f86cf175d0fa293..4584d969e3ab93af3c12fc0a7619ab7ee73d92e8 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 cd30eb9d727dc09f0e9c1c3d21c07e12a042eae9..b219e16a89c36f5efcaedd2e7d67c392b720b870 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