From 96efe6735dcb846ae5cb0c49ae89657b8946e653 Mon Sep 17 00:00:00 2001
From: sandeepsajan0 <sandeepsajan0@gmail.com>
Date: Mon, 29 Aug 2022 18:37:33 +0530
Subject: [PATCH] Fix editable issue and update tests accordingly

---
 hypha/apply/dashboard/tests/test_views.py     |  6 +--
 hypha/apply/dashboard/views.py                |  2 +-
 hypha/apply/projects/forms/project.py         |  7 ---
 hypha/apply/projects/models/project.py        | 46 +++++++++----------
 .../project_admin_detail.html                 |  2 +-
 hypha/apply/projects/tests/test_views.py      |  4 +-
 hypha/apply/projects/views/project.py         |  5 +-
 7 files changed, 31 insertions(+), 41 deletions(-)

diff --git a/hypha/apply/dashboard/tests/test_views.py b/hypha/apply/dashboard/tests/test_views.py
index 4f1fc1ae0..a4e160acb 100644
--- a/hypha/apply/dashboard/tests/test_views.py
+++ b/hypha/apply/dashboard/tests/test_views.py
@@ -10,7 +10,7 @@ from hypha.apply.projects.models.payment import (
     RESUBMITTED,
     SUBMITTED,
 )
-from hypha.apply.projects.models.project import COMMITTED
+from hypha.apply.projects.models.project import WAITING_FOR_APPROVAL
 from hypha.apply.projects.tests.factories import InvoiceFactory, ProjectFactory
 from hypha.apply.review.tests.factories import ReviewFactory, ReviewOpinionFactory
 from hypha.apply.users.groups import APPROVER_GROUP_NAME
@@ -135,13 +135,13 @@ class TestStaffDashboard(BaseViewTestCase):
         self.assertNotContains(response, "Active Invoices")
 
     def test_non_project_approver_cannot_see_projects_awaiting_review_stats_or_table(self):
-        ProjectFactory(is_locked=True, status=COMMITTED)
+        ProjectFactory(is_locked=False, status=WAITING_FOR_APPROVAL)
 
         response = self.get_page()
         self.assertNotContains(response, "Projects awaiting approval")
 
     def test_project_approver_can_see_projects_awaiting_review_stats_or_table(self):
-        ProjectFactory(is_locked=True, status=COMMITTED)
+        ProjectFactory(is_locked=False, status=WAITING_FOR_APPROVAL)
 
         user = StaffFactory()
         user.groups.add(GroupFactory(name=APPROVER_GROUP_NAME))
diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py
index bfc9d8150..9ac43c32d 100644
--- a/hypha/apply/dashboard/views.py
+++ b/hypha/apply/dashboard/views.py
@@ -122,7 +122,7 @@ class AdminDashboardView(MyFlaggedMixin, TemplateView):
                 'table': None,
             }
 
-        to_approve = Project.objects.in_approval().for_table()
+        to_approve = Project.objects.waiting_for_approval().for_table()
 
         return {
             'count': to_approve.count(),
diff --git a/hypha/apply/projects/forms/project.py b/hypha/apply/projects/forms/project.py
index 7d20ee35a..b967c9802 100644
--- a/hypha/apply/projects/forms/project.py
+++ b/hypha/apply/projects/forms/project.py
@@ -151,15 +151,8 @@ class SetPendingForm(forms.ModelForm):
         if self.instance.status != COMMITTED:
             raise forms.ValidationError(_('A Project can only be sent for Approval when Committed.'))
 
-        if self.instance.is_locked:
-            raise forms.ValidationError(_('A Project can only be sent for Approval once'))
-
         super().clean()
 
-    def save(self, *args, **kwargs):
-        self.instance.is_locked = True
-        return super().save(*args, **kwargs)
-
 
 class UploadContractForm(forms.ModelForm):
     class Meta:
diff --git a/hypha/apply/projects/models/project.py b/hypha/apply/projects/models/project.py
index 907b55021..594392f62 100644
--- a/hypha/apply/projects/models/project.py
+++ b/hypha/apply/projects/models/project.py
@@ -80,13 +80,6 @@ class ProjectQuerySet(models.QuerySet):
     def complete(self):
         return self.filter(status=COMPLETE)
 
-    def in_approval(self):
-        return self.filter(
-            is_locked=True,
-            status=COMMITTED,
-            approvals__isnull=True,
-        )
-
     def waiting_for_approval(self):
         return self.filter(
             status=WAITING_FOR_APPROVAL,
@@ -259,10 +252,12 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
     def end_date(self):
         # Aiming for the proposed end date as the last day of the project
         # If still ongoing assume today is the end
-        return max(
-            self.proposed_end.date(),
-            timezone.now().date(),
-        )
+        if self.proposed_end:
+            return max(
+                self.proposed_end.date(),
+                timezone.now().date(),
+            )
+        return timezone.now().date()
 
     def paid_value(self):
         return self.invoices.paid_value()
@@ -295,24 +290,27 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
 
     def editable_by(self, user):
         if self.editable:
-            return True
+            # Approver can edit it when they are approving
+            if self.can_make_approval:
+                if user.is_finance or user.is_approver or user.is_contracting:
+                    return True
+
+            # Lead can make changes to the project
+            if user == self.lead:
+                return True
 
-        # Approver can edit it when they are approving
-        if self.can_make_approval:
-            if user.is_finance or user.is_approver or user.is_contracting:
+            # Staff can edit project
+            if user.is_apply_staff:
                 return True
+        return False
 
     @property
     def editable(self):
-        if self.status not in (CONTRACTING, WAITING_FOR_APPROVAL, COMMITTED):
-            return True
-
-        # Someone has approved the project - consider it locked while with contracting
-        if self.approvals.exists():
+        if self.is_locked:
             return False
-
-        # Someone must lead the project to make changes
-        return self.lead and not self.is_locked
+        elif self.status in (COMMITTED, WAITING_FOR_APPROVAL):  # locked condition is enough,it is just for double check
+            return True
+        return False
 
     def get_absolute_url(self):
         if settings.PROJECTS_ENABLED:
@@ -321,7 +319,7 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
 
     @property
     def can_make_approval(self):
-        return self.is_locked and self.status == WAITING_FOR_APPROVAL
+        return self.status == WAITING_FOR_APPROVAL
 
     @property
     def can_make_final_approval(self):
diff --git a/hypha/apply/projects/templates/application_projects/project_admin_detail.html b/hypha/apply/projects/templates/application_projects/project_admin_detail.html
index 120b6cdeb..19d215cc1 100644
--- a/hypha/apply/projects/templates/application_projects/project_admin_detail.html
+++ b/hypha/apply/projects/templates/application_projects/project_admin_detail.html
@@ -57,7 +57,7 @@
                     {% trans "A lead must be assigned" %}
                 {% elif not object.user_has_updated_details %}
                     {% trans "Project approval form must be completed" %}
-                {% elif object.is_locked %}
+                {% elif object.can_make_approval or object.can_make_final_approval %}
                     {% trans "Currently awaiting approval" %}
                 {% endif %}"
         {% endif %}
diff --git a/hypha/apply/projects/tests/test_views.py b/hypha/apply/projects/tests/test_views.py
index 6d49b8bb0..163fd6d4a 100644
--- a/hypha/apply/projects/tests/test_views.py
+++ b/hypha/apply/projects/tests/test_views.py
@@ -110,7 +110,7 @@ class TestSendForApprovalView(BaseViewTestCase):
 
         project.refresh_from_db()
 
-        self.assertTrue(project.is_locked)
+        self.assertFalse(project.is_locked)
         self.assertEqual(project.status, WAITING_FOR_APPROVAL)
 
 
@@ -241,7 +241,7 @@ class TestFinalApprovalView(BaseViewTestCase):
         self.assertEqual(response.status_code, 200)
 
         project.refresh_from_db()
-        self.assertFalse(project.is_locked)
+        self.assertTrue(project.is_locked)
         self.assertEqual(project.status, CONTRACTING)
 
     def test_final_rejection(self):
diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py
index 34d8bb4cf..0f4f800fe 100644
--- a/hypha/apply/projects/views/project.py
+++ b/hypha/apply/projects/views/project.py
@@ -176,7 +176,7 @@ class FinalApprovalView(DelegatedViewMixin, UpdateView):
             source=project,
         )
 
-        project.is_locked = False
+        project.is_locked = True
         project.status = CONTRACTING
         project.save(update_fields=['is_locked', 'status'])
 
@@ -488,8 +488,7 @@ class ChangePAFStatusView(DelegatedViewMixin, UpdateView):
 
         if paf_status == REQUEST_CHANGE:
             self.object.status = COMMITTED
-            self.object.is_locked = False
-            self.object.save(update_fields=['status', 'is_locked'])
+            self.object.save(update_fields=['status'])
 
             messenger(
                 MESSAGES.REQUEST_PROJECT_CHANGE,
-- 
GitLab