diff --git a/caseworker/cases/forms/queries.py b/caseworker/cases/forms/queries.py index 74f584b58d..0cb25da1ce 100644 --- a/caseworker/cases/forms/queries.py +++ b/caseworker/cases/forms/queries.py @@ -8,10 +8,13 @@ class CloseQueryForm(forms.Form): reason_for_closing_query = forms.CharField( label="Why are you closing the query? This will not be visible to the exporter.", widget=forms.Textarea, - required=False, + error_messages={"required": "Enter a reason why you are closing the query"}, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() - self.helper.layout = Layout("reason_for_closing_query", Button("submit", "Submit")) + self.helper.layout = Layout( + "reason_for_closing_query", + Button("submit", "Submit"), + ) diff --git a/caseworker/cases/helpers/case.py b/caseworker/cases/helpers/case.py index aa364909c7..da4ea6ca2e 100644 --- a/caseworker/cases/helpers/case.py +++ b/caseworker/cases/helpers/case.py @@ -239,7 +239,7 @@ def _transform_data(self): for queue_detail in self.case.queue_details: queue_detail["days_on_queue_elapsed"] = (timezone.now() - parse(queue_detail["joined_queue_at"])).days - def get(self, request, **kwargs): + def get(self, request, *args, **kwargs): self.case_id = str(kwargs["pk"]) self.case = get_case(request, self.case_id) self.queue_id = kwargs["queue_pk"] diff --git a/caseworker/cases/views/queries.py b/caseworker/cases/views/queries.py index 61b00a2bba..6522244c5d 100644 --- a/caseworker/cases/views/queries.py +++ b/caseworker/cases/views/queries.py @@ -1,13 +1,16 @@ +from django.http import Http404 from django.urls import reverse from django.views.generic import FormView from caseworker.cases.forms.queries import CloseQueryForm +from caseworker.cases.helpers.ecju_queries import get_ecju_queries from caseworker.cases.services import put_ecju_query from core.auth.views import LoginRequiredMixin class CloseQueryView(LoginRequiredMixin, FormView): form_class = CloseQueryForm + template_name = "case/close-query.html" def dispatch(self, request, *args, **kwargs): self.lite_user = request.lite_user @@ -35,3 +38,22 @@ def get_success_url(self): "tab": "ecju-queries", }, ) + + def get_query(self, open_ecju_queries): + for query in open_ecju_queries: + if query["id"] == str(self.kwargs["query_pk"]): + return query + return None + + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + + open_ecju_queries, _ = get_ecju_queries(self.request, self.kwargs["pk"]) + query = self.get_query(open_ecju_queries) + if not query: + raise Http404 + + context["title"] = "Close query" + context["query"] = query + + return context diff --git a/caseworker/templates/case/close-query.html b/caseworker/templates/case/close-query.html new file mode 100644 index 0000000000..a1092f159e --- /dev/null +++ b/caseworker/templates/case/close-query.html @@ -0,0 +1,35 @@ +{% extends 'layouts/two-pane.html' %} +{% load crispy_forms_tags crispy_forms_gds %} + +{% block title %}{{title}}{% endblock %} +{% block back_link %} + {{ back_link_text|default:"Back" }} +{% endblock %} + +{% block two_thirds %} + +{% if errors %} + {% include "forms-errors.html" %} +{% endif %} + +
+ {% csrf_token %} + + {% error_summary form %} + +
+

+ +

+
+
+ {{ query.question }} +
+
+ {% crispy form %} +
+
+ +{% endblock %} diff --git a/unit_tests/caseworker/cases/forms/test_ecju_queries.py b/unit_tests/caseworker/cases/forms/test_ecju_queries.py new file mode 100644 index 0000000000..cc17ffae2a --- /dev/null +++ b/unit_tests/caseworker/cases/forms/test_ecju_queries.py @@ -0,0 +1,22 @@ +import pytest + + +from caseworker.cases.forms.queries import CloseQueryForm + + +@pytest.mark.parametrize( + "data, is_valid, errors", + ( + ({}, False, {"reason_for_closing_query": ["Enter a reason why you are closing the query"]}), + ( + {"reason_for_closing_query": ""}, + False, + {"reason_for_closing_query": ["Enter a reason why you are closing the query"]}, + ), + ({"reason_for_closing_query": "closing response"}, True, {}), + ), +) +def test_ecju_queries_close_query_form(data, is_valid, errors): + form = CloseQueryForm(data=data) + assert form.is_valid() == is_valid + assert form.errors == errors diff --git a/unit_tests/caseworker/cases/test_views.py b/unit_tests/caseworker/cases/test_views.py index c60e95e856..ec0fe9d40f 100644 --- a/unit_tests/caseworker/cases/test_views.py +++ b/unit_tests/caseworker/cases/test_views.py @@ -505,9 +505,6 @@ def mock_get_queries(requests_mock, standard_case_pk, data_ecju_queries_gov_seri ) -@pytest.mark.parametrize( - ("reason_for_closing_query", "expected_status"), [("closing this query because xyz", 302), ("", 302)] -) def test_close_query_view_post_success( authorized_client, requests_mock, @@ -516,8 +513,6 @@ def test_close_query_view_post_success( data_ecju_queries_gov_serializer, data_query_closed_by_caseworker, mock_get_queries, - reason_for_closing_query, - expected_status, ): # see that the query is in the open queries section url = reverse("cases:case", kwargs={"queue_pk": queue_pk, "pk": standard_case_pk, "tab": "ecju-queries"}) @@ -533,9 +528,60 @@ def test_close_query_view_post_success( "cases:close_query", kwargs={"queue_pk": queue_pk, "pk": standard_case_pk, "query_pk": query_pk} ) response = authorized_client.post( - cases_close_query_url, data={f"{query_pk}-reason_for_closing_query": reason_for_closing_query} + cases_close_query_url, + data={ + f"{query_pk}-reason_for_closing_query": "Exporter clarified, closing this query", + }, ) - assert response.status_code == expected_status + assert response.status_code == 302 + + +def test_close_query_without_response_gives_error( + authorized_client, + requests_mock, + queue_pk, + standard_case_pk, + data_ecju_queries_gov_serializer, + data_query_closed_by_caseworker, + mock_get_queries, +): + # see that the query is in the open queries section + url = reverse("cases:case", kwargs={"queue_pk": queue_pk, "pk": standard_case_pk, "tab": "ecju-queries"}) + response = authorized_client.get(url) + soup = BeautifulSoup(response.content, "html.parser") + open_queries = soup.find(id="open-queries") + assert data_ecju_queries_gov_serializer["ecju_queries"][0]["question"] in str(open_queries) + + # close the query + query_pk = data_ecju_queries_gov_serializer["ecju_queries"][0]["id"] + requests_mock.put(client._build_absolute_uri(f"/cases/{standard_case_pk}/ecju-queries/{query_pk}/"), json={}) + cases_close_query_url = reverse( + "cases:close_query", kwargs={"queue_pk": queue_pk, "pk": standard_case_pk, "query_pk": query_pk} + ) + response = authorized_client.post( + cases_close_query_url, + data={ + f"{query_pk}-reason_for_closing_query": "", + }, + ) + assert response.status_code == 200 + + error_message = "Enter a reason why you are closing the query" + assert error_message in response.content.decode("utf-8") + assert response.context["form"].errors["reason_for_closing_query"] == [error_message] + + +def test_close_invalid_query_raises_error( + authorized_client, + queue_pk, + standard_case_pk, + mock_get_queries, +): + # try to close query with invalid id + query_pk = str(uuid.uuid4()) + url = reverse("cases:close_query", kwargs={"queue_pk": queue_pk, "pk": standard_case_pk, "query_pk": query_pk}) + response = authorized_client.post(url, data={f"{query_pk}-reason_for_closing_query": ""}) + assert response.status_code == 404 def test_close_query_view_show_closed_queries_on_page(