From 0b23e2b93c4a5343d036889e07a2293d29a66105 Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Sat, 4 Nov 2023 12:54:45 +0530 Subject: [PATCH 1/8] Add paf for review table for paf approvers --- .../dashboard/contracting_dashboard.html | 8 ++++ .../templates/dashboard/dashboard.html | 8 ++++ .../dashboard/finance_dashboard.html | 7 +++ hypha/apply/dashboard/utils.py | 28 +++++++++++ hypha/apply/dashboard/views.py | 48 +++++++++++++++++++ hypha/apply/projects/tables.py | 36 +++++++++++++- 6 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 hypha/apply/dashboard/utils.py diff --git a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html index a382b38822..8ef3ceb4c5 100644 --- a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html @@ -15,6 +15,14 @@ {% endadminbar %}
+ + {% if paf_for_review.count %} +
+

{% trans "PAFs for review" %}

+ {% render_table paf_for_review.table %} +
+ {% endif %} + {% if paf_waiting_for_approval.count %} {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} {% endif %} diff --git a/hypha/apply/dashboard/templates/dashboard/dashboard.html b/hypha/apply/dashboard/templates/dashboard/dashboard.html index 006d7812ef..035b64dc5a 100644 --- a/hypha/apply/dashboard/templates/dashboard/dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/dashboard.html @@ -72,6 +72,13 @@ {% include "funds/includes/round-block.html" with can_export=can_export closed_rounds=rounds.closed open_rounds=rounds.open title="Your rounds and labs" page_type='dashboard' %} {% endif %} + {% if paf_for_review.count %} +
+

{% trans "PAFs for review" %}

+ {% render_table paf_for_review.table %} +
+ {% endif %} + {% if paf_waiting_for_approval.count %} {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} {% endif %} @@ -125,6 +132,7 @@

{% trans "Active Invoices" %}

{% block extra_js %} {{ my_reviewed.filterset.form.media.js }} + diff --git a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html index 2b0e6f9a5d..eacc37277d 100644 --- a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html @@ -84,6 +84,13 @@

{% trans 'Invoices' %} + {% if paf_for_review.count %} +
+

{% trans "PAFs for review" %}

+ {% render_table paf_for_review.table %} +
+ {% endif %} + {% if paf_waiting_for_approval.count %} {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} {% endif %} diff --git a/hypha/apply/dashboard/utils.py b/hypha/apply/dashboard/utils.py new file mode 100644 index 0000000000..b1e20e410b --- /dev/null +++ b/hypha/apply/dashboard/utils.py @@ -0,0 +1,28 @@ +from django.db.models import Count + +from hypha.apply.projects.models import PAFApprovals + + +def get_paf_for_review(user, project_settings): + # Return a list of paf approvals ready for user's review + + paf_approvals = PAFApprovals.objects.annotate( + roles_count=Count("paf_reviewer_role__user_roles") + ).filter( + roles_count=len(list(user.groups.all())), + approved=False, + ) + + for role in user.groups.all(): + paf_approvals = paf_approvals.filter(paf_reviewer_role__user_roles__id=role.id) + + if project_settings.paf_approval_sequential: + all_matched_paf_approvals = list(paf_approvals) + for matched_paf_approval in all_matched_paf_approvals: + if matched_paf_approval.project.paf_approvals.filter( + paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, + approved=False, + ).exists(): + paf_approvals = paf_approvals.exclude(id=matched_paf_approval.id) + + return paf_approvals diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 41823412a5..f85ac89846 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -27,11 +27,14 @@ from hypha.apply.projects.permissions import has_permission from hypha.apply.projects.tables import ( InvoiceDashboardTable, + PAFForReviewDashboardTable, ProjectsAssigneeDashboardTable, ProjectsDashboardTable, ) from hypha.apply.utils.views import ViewDispatcher +from .utils import get_paf_for_review + class MySubmissionContextMixin: def get_context_data(self, **kwargs): @@ -95,11 +98,26 @@ def get_context_data(self, **kwargs): "rounds": self.rounds(), "my_flagged": self.my_flagged(submissions), "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context + def paf_for_review(self): + if not self.request.user.is_apply_staff: + return {"count": None, "table": None} + project_settings = ProjectSettings.for_request(self.request) + + paf_approvals = get_paf_for_review( + user=self.request.user, project_settings=project_settings + ) + + return { + "count": paf_approvals.count(), + "table": PAFForReviewDashboardTable(paf_approvals), + } + def awaiting_reviews(self, submissions): submissions = submissions.in_review_for(self.request.user).order_by( "-submit_time" @@ -291,11 +309,26 @@ def get_context_data(self, **kwargs): "invoices_to_convert": self.invoices_to_convert(), "paf_waiting_for_approval": self.paf_waiting_for_approval(), "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context + def paf_for_review(self): + if not self.request.user.is_finance: + return {"count": None, "table": None} + project_settings = ProjectSettings.for_request(self.request) + + paf_approvals = get_paf_for_review( + user=self.request.user, project_settings=project_settings + ) + + return { + "count": paf_approvals.count(), + "table": PAFForReviewDashboardTable(paf_approvals), + } + def active_invoices(self): if self.request.user.is_finance_level_2: invoices = Invoice.objects.for_finance_2() @@ -586,11 +619,26 @@ def get_context_data(self, **kwargs): "paf_waiting_for_approval": self.paf_waiting_for_approval(), "projects_in_contracting": self.projects_in_contracting(), "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context + def paf_for_review(self): + if not self.request.user.is_contracting: + return {"count": None, "table": None} + project_settings = ProjectSettings.for_request(self.request) + + paf_approvals = get_paf_for_review( + user=self.request.user, project_settings=project_settings + ) + + return { + "count": paf_approvals.count(), + "table": PAFForReviewDashboardTable(paf_approvals), + } + def paf_waiting_for_approval(self): if ( not self.request.user.is_contracting diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index 117d6db83b..f9eb93f7b6 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -4,7 +4,7 @@ from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ -from .models import Invoice, Project, Report +from .models import Invoice, PAFApprovals, Project, Report class BaseInvoiceTable(tables.Table): @@ -124,6 +124,40 @@ class Meta: attrs = {"class": "projects-table"} +class PAFForReviewDashboardTable(tables.Table): + date_requested = tables.DateColumn( + verbose_name=_("Date requested"), accessor="updated_at" + ) + title = tables.LinkColumn( + "funds:projects:detail", + text=lambda r: textwrap.shorten(r.project.title, width=30, placeholder="..."), + accessor="project__title", + args=[tables.utils.A("project__pk")], + ) + status = tables.Column( + verbose_name=_("Status"), + accessor="project__get_status_display", + order_by=("status",), + ) + fund = tables.Column(verbose_name=_("Fund"), accessor="project__submission__page") + + assignee = tables.Column(verbose_name=_("Assignee"), accessor="user") + + class Meta: + fields = ["date_requested", "title", "status", "fund", "assignee"] + model = PAFApprovals + orderable = True + order_by = ("date_requested",) + attrs = {"class": "projects-table"} + + def order_date_requested(self, qs, is_descending): + direction = "-" if is_descending else "" + + qs = qs.order_by(f"{direction}updated_at") + + return qs, True + + class ProjectsListTable(BaseProjectsTable): class Meta: fields = [ From e3f879a73871d623808916aea475dc8e99a834d4 Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Sat, 4 Nov 2023 16:57:23 +0530 Subject: [PATCH 2/8] Update status values --- hypha/apply/projects/tables.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index f9eb93f7b6..c3fb728a81 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -134,17 +134,13 @@ class PAFForReviewDashboardTable(tables.Table): accessor="project__title", args=[tables.utils.A("project__pk")], ) - status = tables.Column( - verbose_name=_("Status"), - accessor="project__get_status_display", - order_by=("status",), - ) + status = tables.Column(verbose_name=_("Status"), accessor="pk") fund = tables.Column(verbose_name=_("Fund"), accessor="project__submission__page") assignee = tables.Column(verbose_name=_("Assignee"), accessor="user") class Meta: - fields = ["date_requested", "title", "status", "fund", "assignee"] + fields = ["date_requested", "title", "fund", "status", "assignee"] model = PAFApprovals orderable = True order_by = ("date_requested",) @@ -157,6 +153,12 @@ def order_date_requested(self, qs, is_descending): return qs, True + def render_status(self, record): + if record.user: + return _("Waiting for approval") + else: + return _("Waiting for assignee") + class ProjectsListTable(BaseProjectsTable): class Meta: From ecd141f612d52b979762de518c15a62202577336 Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Tue, 7 Nov 2023 17:48:36 +0530 Subject: [PATCH 3/8] Use submit_date instead of updated date for date_requested --- hypha/apply/projects/tables.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index c3fb728a81..056ca4d001 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -126,7 +126,7 @@ class Meta: class PAFForReviewDashboardTable(tables.Table): date_requested = tables.DateColumn( - verbose_name=_("Date requested"), accessor="updated_at" + verbose_name=_("Date requested"), accessor="created_at" ) title = tables.LinkColumn( "funds:projects:detail", @@ -149,7 +149,7 @@ class Meta: def order_date_requested(self, qs, is_descending): direction = "-" if is_descending else "" - qs = qs.order_by(f"{direction}updated_at") + qs = qs.order_by(f"{direction}created_at") return qs, True From 21d571b248a87f43920a9d43f21f4e30e590c72b Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Wed, 8 Nov 2023 11:52:22 +0530 Subject: [PATCH 4/8] Move utils code to services and pass settings' values instead of setting itself --- hypha/apply/dashboard/{utils.py => services.py} | 6 +++--- hypha/apply/dashboard/views.py | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) rename hypha/apply/dashboard/{utils.py => services.py} (84%) diff --git a/hypha/apply/dashboard/utils.py b/hypha/apply/dashboard/services.py similarity index 84% rename from hypha/apply/dashboard/utils.py rename to hypha/apply/dashboard/services.py index b1e20e410b..7f9ad5bfca 100644 --- a/hypha/apply/dashboard/utils.py +++ b/hypha/apply/dashboard/services.py @@ -3,8 +3,8 @@ from hypha.apply.projects.models import PAFApprovals -def get_paf_for_review(user, project_settings): - # Return a list of paf approvals ready for user's review +def get_paf_for_review(user, is_paf_approval_sequential): + """Return a list of paf approvals ready for user's review""" paf_approvals = PAFApprovals.objects.annotate( roles_count=Count("paf_reviewer_role__user_roles") @@ -16,7 +16,7 @@ def get_paf_for_review(user, project_settings): for role in user.groups.all(): paf_approvals = paf_approvals.filter(paf_reviewer_role__user_roles__id=role.id) - if project_settings.paf_approval_sequential: + if is_paf_approval_sequential: all_matched_paf_approvals = list(paf_approvals) for matched_paf_approval in all_matched_paf_approvals: if matched_paf_approval.project.paf_approvals.filter( diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index f85ac89846..82dee479ef 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -33,7 +33,7 @@ ) from hypha.apply.utils.views import ViewDispatcher -from .utils import get_paf_for_review +from .services import get_paf_for_review class MySubmissionContextMixin: @@ -110,7 +110,8 @@ def paf_for_review(self): project_settings = ProjectSettings.for_request(self.request) paf_approvals = get_paf_for_review( - user=self.request.user, project_settings=project_settings + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, ) return { @@ -321,7 +322,8 @@ def paf_for_review(self): project_settings = ProjectSettings.for_request(self.request) paf_approvals = get_paf_for_review( - user=self.request.user, project_settings=project_settings + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, ) return { @@ -631,7 +633,8 @@ def paf_for_review(self): project_settings = ProjectSettings.for_request(self.request) paf_approvals = get_paf_for_review( - user=self.request.user, project_settings=project_settings + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, ) return { From ce2046892c67bfbdbb32940f7aac5bda3a1f560a Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Wed, 8 Nov 2023 12:47:46 +0530 Subject: [PATCH 5/8] Remove old PAF waiting for assignee and PAF waiting for approval tables --- .../dashboard/contracting_dashboard.html | 11 - .../templates/dashboard/dashboard.html | 20 - .../dashboard/finance_dashboard.html | 10 - .../includes/paf_waiting_for_approval.html | 48 --- .../dashboard/reviewer_dashboard.html | 9 - hypha/apply/dashboard/views.py | 347 +----------------- 6 files changed, 1 insertion(+), 444 deletions(-) delete mode 100644 hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html diff --git a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html index 8ef3ceb4c5..4de5c99286 100644 --- a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html @@ -23,17 +23,6 @@

{% trans "PAFs for review" %}

{% endif %} - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - - {% if paf_waiting_for_assignment.count %} -
-

{% trans "PAF waiting for assignee" %}

- {% render_table paf_waiting_for_assignment.table %} -
- {% endif %} - {% if projects_in_contracting.count %} {% include "dashboard/includes/projects_in_contracting.html" with projects_in_contracting=projects_in_contracting %} {% endif %} diff --git a/hypha/apply/dashboard/templates/dashboard/dashboard.html b/hypha/apply/dashboard/templates/dashboard/dashboard.html index 035b64dc5a..ebabadbccb 100644 --- a/hypha/apply/dashboard/templates/dashboard/dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/dashboard.html @@ -39,15 +39,6 @@
{% trans "View" %}
{% endif %} - {% if not paf_waiting_for_approval.count is None%} - -

{{ paf_waiting_for_approval.count }}

-

{% trans "Projects awaiting approval" %}

- {% if paf_waiting_for_approval.count %} -
{% trans "View" %}
- {% endif %} -
- {% endif %}

{{ active_invoices.count }}

{% trans "Requests for invoices requiring your attention" %}

@@ -79,17 +70,6 @@

{% trans "PAFs for review" %}

{% endif %} - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - - {% if paf_waiting_for_assignment.count %} -
-

{% trans "PAF waiting for assignee" %}

- {% render_table paf_waiting_for_assignment.table %} -
- {% endif %} - {% if projects.table.data %}
{% trans "Your projects" as project_heading %} diff --git a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html index eacc37277d..bf0d29a73a 100644 --- a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html @@ -91,16 +91,6 @@

{% trans "PAFs for review" %}

{% endif %} - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - - {% if paf_waiting_for_assignment.count %} -
-

{% trans "PAF waiting for assignee" %}

- {% render_table paf_waiting_for_assignment.table %} -
- {% endif %} {% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html b/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html deleted file mode 100644 index 0fdfcaa1a5..0000000000 --- a/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html +++ /dev/null @@ -1,48 +0,0 @@ -{% load render_table from django_tables2 %} -{% load i18n %} - -
-
-

- {% trans 'PAF waiting for internal approval' %} -

-
-
- -
- {% if paf_waiting_for_approval.awaiting_your_approval.count %} - {% render_table paf_waiting_for_approval.awaiting_your_approval.table %} - {% else %} -
- {% trans "You have approved all PAFs, no PAF is waiting for your Approval " %} -
- {% endif %} -
-
- {% if paf_waiting_for_approval.approved_by_you.count %} - {% render_table paf_waiting_for_approval.approved_by_you.table %} - {% else %} -
- {% trans "No PAF is approved by you yet " %} -
- {% endif %} -
- -
diff --git a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html index 1d6d0c05b6..444531c537 100644 --- a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html @@ -69,15 +69,6 @@
{% trans " {% endif %} - {% if paf_waiting_for_assignment.count %} -
-

- {% trans "PAF waiting for assignee" %} -

- {% render_table paf_waiting_for_assignment.table %} -
- {% endif %} - {% if my_inactive_submissions.data %}

diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 82dee479ef..258a598cc3 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -1,5 +1,4 @@ from django.conf import settings -from django.db.models import Count from django.http import HttpResponseForbidden, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy @@ -21,14 +20,11 @@ review_filter_for_user, ) from hypha.apply.projects.filters import ProjectListFilter -from hypha.apply.projects.models import Invoice, PAFApprovals, Project, ProjectSettings +from hypha.apply.projects.models import Invoice, Project, ProjectSettings from hypha.apply.projects.models.payment import DECLINED, PAID -from hypha.apply.projects.models.project import INTERNAL_APPROVAL -from hypha.apply.projects.permissions import has_permission from hypha.apply.projects.tables import ( InvoiceDashboardTable, PAFForReviewDashboardTable, - ProjectsAssigneeDashboardTable, ProjectsDashboardTable, ) from hypha.apply.utils.views import ViewDispatcher @@ -94,10 +90,8 @@ def get_context_data(self, **kwargs): "can_export": can_export_submissions(self.request.user), "my_reviewed": self.my_reviewed(submissions), "projects": self.projects(), - "paf_waiting_for_approval": self.paf_waiting_for_approval(), "rounds": self.rounds(), "my_flagged": self.my_flagged(submissions), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), "paf_for_review": self.paf_for_review(), } ) @@ -165,104 +159,6 @@ def projects(self): "url": reverse("apply:projects:all"), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_apply_staff - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - def my_reviewed(self, submissions): """Staff reviewer's reviewed submissions for 'Previous reviews' block""" submissions = submissions.reviewed_by(self.request.user).order_by( @@ -308,8 +204,6 @@ def get_context_data(self, **kwargs): "active_invoices": self.active_invoices(), "invoices_for_approval": self.invoices_for_approval(), "invoices_to_convert": self.invoices_to_convert(), - "paf_waiting_for_approval": self.paf_waiting_for_approval(), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), "paf_for_review": self.paf_for_review(), } ) @@ -342,46 +236,6 @@ def active_invoices(self): "table": InvoiceDashboardTable(invoices), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - def invoices_for_approval(self): if self.request.user.is_finance_level_2: invoices = Invoice.objects.approved_by_finance_1() @@ -402,64 +256,6 @@ def invoices_to_convert(self): "table": InvoiceDashboardTable(invoices), } - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_finance - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - class ReviewerDashboardView(MyFlaggedMixin, MySubmissionContextMixin, TemplateView): template_name = "dashboard/reviewer_dashboard.html" @@ -499,7 +295,6 @@ def get_context_data(self, **kwargs): "awaiting_reviews": self.awaiting_reviews(submissions), "my_reviewed": self.my_reviewed(submissions), "my_flagged": self.my_flagged(submissions), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), } ) @@ -522,46 +317,6 @@ def awaiting_reviews(self, submissions): "table": ReviewerSubmissionsTable(submissions[:limit], prefix="my-review-"), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - def my_reviewed(self, submissions): """Staff reviewer's reviewed submissions for 'Previous reviews' block""" submissions = submissions.reviewed_by(self.request.user).order_by( @@ -618,9 +373,7 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update( { - "paf_waiting_for_approval": self.paf_waiting_for_approval(), "projects_in_contracting": self.projects_in_contracting(), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), "paf_for_review": self.paf_for_review(), } ) @@ -642,104 +395,6 @@ def paf_for_review(self): "table": PAFForReviewDashboardTable(paf_approvals), } - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_contracting - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - def projects_in_contracting(self): if not self.request.user.is_contracting: return { From 4d25eefe77ba2afac14bd6c3115b981a8802879d Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Wed, 29 Nov 2023 11:19:54 +0530 Subject: [PATCH 6/8] Fix sorting issue, aligned arrow --- hypha/apply/dashboard/views.py | 7 ++++- hypha/apply/projects/tables.py | 19 +++++++----- .../apply/components/_dashboard-table.scss | 30 +++++++++++++++++++ hypha/static_src/src/sass/apply/main.scss | 1 + .../static_src/src/sass/apply/styleguide.scss | 1 + 5 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 hypha/static_src/src/sass/apply/components/_dashboard-table.scss diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 258a598cc3..4d427b39da 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -3,6 +3,7 @@ from django.shortcuts import render from django.urls import reverse, reverse_lazy from django.views.generic import TemplateView +from django_tables2 import RequestConfig from hypha.apply.funds.models import ( ApplicationSubmission, @@ -107,10 +108,14 @@ def paf_for_review(self): user=self.request.user, is_paf_approval_sequential=project_settings.paf_approval_sequential, ) + paf_table = PAFForReviewDashboardTable( + paf_approvals, prefix="paf-review-", order_by="-date_requested" + ) + RequestConfig(self.request).configure(paf_table) return { "count": paf_approvals.count(), - "table": PAFForReviewDashboardTable(paf_approvals), + "table": paf_table, } def awaiting_reviews(self, submissions): diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index 056ca4d001..af4eb1510f 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -126,25 +126,30 @@ class Meta: class PAFForReviewDashboardTable(tables.Table): date_requested = tables.DateColumn( - verbose_name=_("Date requested"), accessor="created_at" + verbose_name=_("Date requested"), + accessor="created_at", + orderable=True, ) title = tables.LinkColumn( "funds:projects:detail", text=lambda r: textwrap.shorten(r.project.title, width=30, placeholder="..."), accessor="project__title", args=[tables.utils.A("project__pk")], + orderable=False, + ) + status = tables.Column(verbose_name=_("Status"), accessor="pk", orderable=False) + fund = tables.Column( + verbose_name=_("Fund"), accessor="project__submission__page", orderable=False ) - status = tables.Column(verbose_name=_("Status"), accessor="pk") - fund = tables.Column(verbose_name=_("Fund"), accessor="project__submission__page") - assignee = tables.Column(verbose_name=_("Assignee"), accessor="user") + assignee = tables.Column( + verbose_name=_("Assignee"), accessor="user", orderable=False + ) class Meta: fields = ["date_requested", "title", "fund", "status", "assignee"] model = PAFApprovals - orderable = True - order_by = ("date_requested",) - attrs = {"class": "projects-table"} + attrs = {"class": "paf-review-table"} def order_date_requested(self, qs, is_descending): direction = "-" if is_descending else "" diff --git a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss new file mode 100644 index 0000000000..8afef2f795 --- /dev/null +++ b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss @@ -0,0 +1,30 @@ +.paf-review-table { + @include table-ordering-styles; + + thead { + th { + // ordering - adjust alignment + &.desc { + position: relative; + color: $color--dark-grey; + + &::after { + position: absolute; + top: 40%; + margin-left: 5px; + } + } + + &.asc { + position: relative; + color: $color--dark-grey; + + &::after { + position: absolute; + top: 50%; + margin-left: 5px; + } + } + } + } +} diff --git a/hypha/static_src/src/sass/apply/main.scss b/hypha/static_src/src/sass/apply/main.scss index 40ed6f1c79..ab9dae30ed 100644 --- a/hypha/static_src/src/sass/apply/main.scss +++ b/hypha/static_src/src/sass/apply/main.scss @@ -71,6 +71,7 @@ @import "components/activity-notifications"; @import "components/dropdown"; @import "components/banner"; +@import "components/dashboard-table"; // Layout @import "layout/header"; diff --git a/hypha/static_src/src/sass/apply/styleguide.scss b/hypha/static_src/src/sass/apply/styleguide.scss index 6667c9202f..5499fb5d17 100644 --- a/hypha/static_src/src/sass/apply/styleguide.scss +++ b/hypha/static_src/src/sass/apply/styleguide.scss @@ -65,6 +65,7 @@ @import "components/two-factor"; @import "components/determination"; @import "components/dropdown"; +@import "components/dashboard-table"; // Layout @import "layout/header"; From acb00bc5ee8eab5a08b512782d622d6b4d0ade0b Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Wed, 6 Dec 2023 13:05:57 +0530 Subject: [PATCH 7/8] Fix table head and headings for tablet or smaller size screen --- hypha/apply/dashboard/views.py | 2 +- hypha/apply/projects/tables.py | 3 +++ .../apply/components/_dashboard-table.scss | 20 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 4d427b39da..ed90d5547d 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -111,7 +111,7 @@ def paf_for_review(self): paf_table = PAFForReviewDashboardTable( paf_approvals, prefix="paf-review-", order_by="-date_requested" ) - RequestConfig(self.request).configure(paf_table) + RequestConfig(self.request, paginate=False).configure(paf_table) return { "count": paf_approvals.count(), diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index af4eb1510f..6865c163b1 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -149,6 +149,9 @@ class PAFForReviewDashboardTable(tables.Table): class Meta: fields = ["date_requested", "title", "fund", "status", "assignee"] model = PAFApprovals + template_name = ( + "funds/tables/table.html" # todo: update it with Project table template + ) attrs = {"class": "paf-review-table"} def order_date_requested(self, qs, is_descending): diff --git a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss index 8afef2f795..a18f1e7c75 100644 --- a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss +++ b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss @@ -2,6 +2,12 @@ @include table-ordering-styles; thead { + display: none; + + @include media-query($table-breakpoint) { + display: table-header-group; + } + th { // ordering - adjust alignment &.desc { @@ -27,4 +33,18 @@ } } } + + tbody { + td { + // stylelint-disable-next-line force-element-nesting + > span.mobile-label { + display: inline-block; + width: 90px; + + @include media-query($table-breakpoint) { + display: none; + } + } + } + } } From 9957aea9101db107d4c81f8b3a1d4dfc19342d50 Mon Sep 17 00:00:00 2001 From: sandeepsajan0 Date: Wed, 6 Dec 2023 13:12:29 +0530 Subject: [PATCH 8/8] Fix sass lint issues --- .../static_src/src/sass/apply/components/_dashboard-table.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss index a18f1e7c75..1a63c5334f 100644 --- a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss +++ b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss @@ -1,3 +1,5 @@ +// stylelint-disable selector-max-compound-selectors + .paf-review-table { @include table-ordering-styles;