Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1109] Feature/update plan list view #462

Merged
merged 7 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/open_inwoner/plans/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from datetime import date
from uuid import uuid4

from django.db import models
from django.db.models import Q
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _

from filer.fields.file import FilerFileField

from open_inwoner.accounts.choices import TypeChoices
from open_inwoner.accounts.choices import StatusChoices, TypeChoices

from .managers import PlanQuerySet

Expand Down Expand Up @@ -131,11 +133,6 @@ def __str__(self):
def get_absolute_url(self):
return reverse("plans:plan_detail", kwargs={"uuid": self.uuid})

def contactperson_list(self):
return ", ".join(
[contact.get_full_name() for contact in self.plan_contacts.all()]
)

def get_latest_file(self):
file = self.documents.order_by("-created_on").first()
if file:
Expand All @@ -158,3 +155,19 @@ def get_other_users(self, user=None):
from open_inwoner.accounts.models import User

return User.objects.filter(id__in=user_ids)

def get_other_users_full_names(self, user):
other_users = self.get_other_users(user)
return ", ".join([user.get_full_name() for user in other_users])

def get_status(self):
vaszig marked this conversation as resolved.
Show resolved Hide resolved
if self.end_date > date.today():
return _("Open")
else:
return _("Afgerond")

def open_actions(self):
return self.actions.filter(
Q(status=StatusChoices.open) | Q(status=StatusChoices.approval),
is_deleted=False,
)
112 changes: 111 additions & 1 deletion src/open_inwoner/plans/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from datetime import date

from django.contrib.messages import get_messages
from django.core import mail
from django.urls import reverse
from django.utils.translation import ugettext as _

from django_webtest import WebTest
from freezegun import freeze_time
from webtest import Upload

from open_inwoner.accounts.choices import StatusChoices
from open_inwoner.accounts.choices import ContactTypeChoices, StatusChoices
from open_inwoner.accounts.models import Action
from open_inwoner.accounts.tests.factories import ActionFactory, UserFactory
from open_inwoner.accounts.tests.test_action_views import ActionsPlaywrightTests
Expand Down Expand Up @@ -561,6 +564,113 @@ def test_plan_action_status_not_your_action(self):
)
self.assertEqual(response.status_code, 404)

@freeze_time("2022-01-01")
def test_plan_list_renders_expected_data_when_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.plan.end_date = date(2022, 1, 20)
self.plan.save()

response = self.app.get(self.list_url, user=self.user)
rendered_plan_title = response.pyquery("tbody .table__header")[0].text
rendered_contact = response.pyquery("tbody .table__item")[0].text
rendered_end_date = response.pyquery("tbody .table__item")[1].text
rendered_plan_status = response.pyquery("tbody .table__item")[2].text
rendered_actions_num = response.pyquery("tbody .table__item")[3].text
vaszig marked this conversation as resolved.
Show resolved Hide resolved
rendered_action_required = response.pyquery(
"tbody .table__item--notification-danger"
)[0].text

self.assertEqual(rendered_plan_title, self.plan.title)
self.assertEqual(rendered_contact, self.contact.get_full_name())
self.assertEqual(rendered_end_date, "20-01-2022")
self.assertEqual(rendered_plan_status, _("Open"))
self.assertEqual(rendered_actions_num, "1")
self.assertEqual(rendered_action_required, _("Actie vereist"))

@freeze_time("2022-01-01")
def test_plan_list_renders_expected_data_for_expired_plan_when_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.plan.end_date = date(2022, 1, 1)
self.plan.save()

response = self.app.get(self.list_url, user=self.user)
rendered_end_date = response.pyquery("tbody .table__item")[1].text
vaszig marked this conversation as resolved.
Show resolved Hide resolved
rendered_plan_status = response.pyquery("tbody .table__item")[2].text

self.assertEqual(rendered_end_date, "01-01-2022")
self.assertEqual(rendered_plan_status, _("Afgerond"))

@freeze_time("2022-01-01")
def test_plan_list_renders_expected_data_for_approval_actions_when_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.action.status = StatusChoices.approval
self.action.save()

response = self.app.get(self.list_url, user=self.user)
rendered_actions_num = response.pyquery("tbody .table__item")[3].text
rendered_action_required = response.pyquery(
"tbody .table__item--notification-danger"
)[0].text

self.assertEqual(rendered_actions_num, "1")
self.assertEqual(rendered_action_required, _("Actie vereist"))

@freeze_time("2022-01-01")
def test_plan_list_renders_expected_data_for_closed_actions_when_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.action.status = StatusChoices.closed
self.action.save()

response = self.app.get(self.list_url, user=self.user)
rendered_actions_num = response.pyquery("tbody .table__item")[3].text
rendered_action_required = response.pyquery(
"tbody .table__item--notification-danger"
)

self.assertEqual(rendered_actions_num, "0")
self.assertEqual(rendered_action_required, [])

def test_plan_list_doesnt_add_deleted_action_to_total_when_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.action.is_deleted = True
self.action.save()

response = self.app.get(self.list_url, user=self.user)
rendered_actions_num = response.pyquery("tbody .table__item")[3].text
rendered_action_required = response.pyquery(
"tbody .table__item--notification-danger"
)

self.assertEqual(rendered_actions_num, "0")
self.assertEqual(rendered_action_required, [])

@freeze_time("2022-01-01")
def test_plan_list_renders_template_for_regular_user(self):
self.plan.end_date = date(2022, 1, 20)
self.plan.save()

response = self.app.get(self.list_url, user=self.user)
extended = response.pyquery(".plans-extended")

self.assertEqual(len(extended), 0)

@freeze_time("2022-01-01")
def test_plan_list_renders_template_for_begeleider(self):
self.user.contact_type = ContactTypeChoices.begeleider
self.user.save()
self.plan.end_date = date(2022, 1, 20)
self.plan.save()

response = self.app.get(self.list_url, user=self.user)
extended = response.pyquery(".plans-extended")

self.assertEqual(len(extended), 1)


@multi_browser()
class PlanActionStatusPlaywrightTests(ActionsPlaywrightTests):
Expand Down
28 changes: 28 additions & 0 deletions src/open_inwoner/plans/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from view_breadcrumbs import BaseBreadcrumbMixin

from open_inwoner.accounts.choices import ContactTypeChoices
from open_inwoner.accounts.forms import ActionListForm, DocumentForm
from open_inwoner.accounts.views.actions import (
ActionCreateView,
Expand Down Expand Up @@ -42,6 +43,7 @@ class PlanListView(
):
template_name = "pages/plans/list.html"
model = Plan
paginate_by = 10

@cached_property
def crumbs(self):
Expand All @@ -54,6 +56,25 @@ def get_queryset(self):
"plan_contacts"
)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = self.request.user

plans = self.get_queryset()
paginator, page, queryset, is_paginated = self.paginate_queryset(plans, 10)
context["paginator"] = paginator
context["page_obj"] = page
context["is_paginated"] = is_paginated
context["plans"] = queryset

if user.contact_type == ContactTypeChoices.begeleider:
plans = {}
for plan in queryset:
plans[plan] = plan.get_other_users_full_names(user=user)

context["extended_plans"] = plans
return context


class PlanDetailView(
PlansEnabledMixin,
Expand Down Expand Up @@ -424,3 +445,10 @@ class PlanExportView(

def get_queryset(self):
return Plan.objects.connected(self.request.user).prefetch_related("actions")

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
plan = self.get_object()

context["plan_contacts"] = plan.get_other_users_full_names(self.request.user)
return context
8 changes: 8 additions & 0 deletions src/open_inwoner/scss/components/Table/Table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@
&--top {
vertical-align: top;
}

&--notification-danger {
background-color: var(--color-danger-lightest);
color: var(--color-danger-darker);
text-align: center;
border-radius: var(--border-radius);
padding: var(--spacing-small) 0;
}
}

&__header {
Expand Down
4 changes: 2 additions & 2 deletions src/open_inwoner/templates/export/plans/plan_export.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% extends 'base_pdf.html' %}
{% load i18n link_tags file_tags %}
{% load i18n link_tags file_tags helpers %}

{% block content %}

Expand All @@ -20,7 +20,7 @@ <h1 class="h1">{% trans "Plan" %} {{ object.title }}</h1>
</tr>
<tr>
<th class="table__header">{% trans "Contacts" %}</th>
<td class="table__item">{{ object.contactperson_list }}</td>
<td class="table__item">{{ plan_contacts }}</td>
</tr>
<tr>
<th class="table__header">{% trans "Created by" %}</th>
Expand Down
44 changes: 42 additions & 2 deletions src/open_inwoner/templates/pages/plans/list.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
{% extends 'master.html' %}
{% load i18n button_tags card_tags map_tags utils string_tags %}
{% load i18n button_tags string_tags pagination_tags helpers card_tags %}

{% block content %}
<h1 class="h1">
{% trans "Samenwerken" %}
{% button href="plans:plan_create" text=_("Start nieuwe samenwerking") primary=True icon="group" icon_outlined=True %}
</h1>
{% optional_paragraph configurable_text.plans_page.plans_intro %}
{% card_container plans=object_list columns=2 %}

vaszig marked this conversation as resolved.
Show resolved Hide resolved
{% if extended_plans %}
<table class="table plans-extended">
<thead class="table__heading">
<tr>
<td class="table__item">{% trans "Samenwerking" %}</td>
<td class="table__item">{% trans "Contactpersoon" %}</td>
<td class="table__item">{% trans "Einddatum" %}</td>
<td class="table__item">{% trans "Status" %}</td>
<td class="table__item" colspan="2">{% trans "Openstaande acties" %}&nbsp;</td>
<td class="table__item">&nbsp;</td>
</tr>
</thead>
<tbody>
{% for plan, plan_participants in extended_plans.items %}
<tr>
<th class="table__header">{{plan.title}}</th>
<td class="table__item">{{plan_participants|truncatechars:30}}</td>
<td class="table__item table__item--no-lb">{{plan.end_date|date:"d-m-Y"}}</td>
<td class="table__item">{{plan.get_status}}</td>
<td class="table__item">{{plan.open_actions.count}}</td>
<td class="table__item">
{% if plan.open_actions.exists %}
<div class="table__item--notification-danger">{% trans "Actie vereist" %}</div>
{% endif %}
</td>
<td class="table__item">{% button text="" href=plan.get_absolute_url icon="arrow_forward" icon_outlined=True transparent=True %}</td>
</tr>
{% empty %}
<tr>
<td class="table__item" colspan="7" >{% trans "There are no plans yet." %}</td>
</tr>
{% endfor %}
</tbody>
</table>

{% else %}
{% card_container plans=plans columns=2 %}
{% endif %}

{% pagination page_obj=page_obj paginator=paginator request=request %}
{% endblock %}