Skip to content

Commit

Permalink
Merge pull request #2346 from uktrade/LTD-5887-view-f680-caseworker
Browse files Browse the repository at this point in the history
[LTD-5887] Add stub F680 case detail page
  • Loading branch information
currycoder authored Feb 11, 2025
2 parents 8f61fb2 + 29cd8fd commit fd4ef7f
Show file tree
Hide file tree
Showing 14 changed files with 385 additions and 316 deletions.
1 change: 1 addition & 0 deletions caseworker/cases/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
path("good/<uuid:good_pk>/", goods.GoodDetails.as_view(), name="good"),
path("denials/", denials.Denials.as_view(), name="denials"),
path("activities/", include("caseworker.activities.urls")),
path("f680/", include("caseworker.f680.urls")),
# tabs
path("<str:tab>/", main.CaseDetail.as_view(), name="case", kwargs={"disable_queue_lookup": True}),
# Finalisation actions
Expand Down
9 changes: 0 additions & 9 deletions caseworker/cases/views/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,6 @@ def get_gifting_clearance_application(self):

def get_f680_clearance_application(self):
self.tabs = self.get_tabs()
self.tabs.insert(1, Tabs.LICENCES)
self.tabs.append(Tabs.ADVICE)
self.slices = [
Slices.GOODS,
Slices.DESTINATIONS,
Slices.F680_DETAILS,
Slices.END_USE_DETAILS,
Slices.SUPPORTING_DOCUMENTS,
]
self.additional_context = self.get_advice_additional_context()

def get_end_user_advisory_query(self):
Expand Down
Empty file added caseworker/f680/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions caseworker/f680/templates/f680/case/detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% extends 'layouts/case.html' %}
{% block details %}
<section class="govuk-!-margin-top-8">
<h1 class="govuk-visually-hidden">Case Summary</h1>
{% include "f680/case/summary.html" %}
</section>
{% endblock %}
1 change: 1 addition & 0 deletions caseworker/f680/templates/f680/case/summary.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% extends "case/base-case-summary.html" %}
Empty file.
124 changes: 124 additions & 0 deletions caseworker/f680/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import pytest
from datetime import timedelta
from requests.exceptions import HTTPError

from bs4 import BeautifulSoup
from django.urls import reverse
from django.utils import timezone

from core import client


@pytest.fixture(autouse=True)
def setup(
mock_queue,
mock_case,
mock_approval_reason,
mock_denial_reasons,
mock_proviso,
mock_footnote_details,
):
return


@pytest.fixture
def missing_case_id():
return "5eb8f65f-9ce0-4dd6-abde-5c3fc00b802c"


@pytest.fixture
def mock_missing_case(missing_case_id, requests_mock):
url = client._build_absolute_uri(f"/cases/{missing_case_id}/")
return requests_mock.get(url=url, status_code=404)


@pytest.fixture
def f680_case_id():
return "67271217-7e55-4345-9db4-31de1bfe4067"


@pytest.fixture
def f680_reference_code():
return "F680/2025/0000016"


@pytest.fixture
def data_f680_case(f680_case_id, f680_reference_code):
submitted_at = timezone.now() - timedelta(days=7)
return {
"case": {
"advice": [],
"all_flags": [],
"amendment_of": None,
"assigned_users": {},
"case_officer": None,
"case_type": {
"id": "00000000-0000-0000-0000-000000000007",
"reference": {"key": "f680", "value": "MOD F680 Clearance"},
"sub_type": {"key": "f680_clearance", "value": "MOD F680 Clearance"},
"type": {"key": "application", "value": "Application"},
},
"copy_of": None,
"countersign_advice": [],
"data": {
"application": {"some": "json"},
"id": f680_case_id,
"organisation": {
"id": "1363b104-9669-4c53-8602-8fc3717b07cd", # /PS-IGNORE
"name": "Parrish, Crosby and Friedman",
"status": "active",
"type": "commercial",
},
"reference_code": f680_reference_code,
"status": {"id": "00000000-0000-0000-0000-000000000001", "key": "submitted", "value": "Submitted"},
"submitted_at": submitted_at.isoformat(),
"submitted_by": None,
},
"flags": [],
"has_advice": {"final": False, "my_team": False, "my_user": False, "team": False, "user": False},
"id": f680_case_id,
"latest_activity": None,
"licences": [],
"queue_details": [],
"queue_names": [],
"queues": [],
"reference_code": "F680/2025/0000016",
"sla_days": 0,
"sla_remaining_days": None,
"submitted_at": submitted_at.isoformat(),
"superseded_by": None,
}
}


@pytest.fixture
def mock_f680_case(f680_case_id, requests_mock, data_f680_case):
url = client._build_absolute_uri(f"/cases/{f680_case_id}/")
return requests_mock.get(url=url, json=data_f680_case)


class TestCaseDetailView:

def test_GET_success(
self, authorized_client, data_queue, mock_f680_case, f680_case_id, f680_reference_code, data_f680_case
):
url = reverse("cases:f680:details", kwargs={"queue_pk": data_queue["id"], "pk": f680_case_id})
response = authorized_client.get(url)
assert response.status_code == 200
assert dict(response.context["case"]) == data_f680_case["case"]
soup = BeautifulSoup(response.content, "html.parser")
assert f680_reference_code in soup.find("h1").text

def test_GET_not_logged_in(
self, client, data_queue, mock_f680_case, f680_case_id, f680_reference_code, data_f680_case
):
url = reverse("cases:f680:details", kwargs={"queue_pk": data_queue["id"], "pk": f680_case_id})
expected_redirect_location = reverse("auth:login")
response = client.get(url)
assert response.status_code == 302
assert response.url.startswith(expected_redirect_location)

def test_GET_no_case_404(self, authorized_client, data_queue, missing_case_id, mock_missing_case):
url = reverse("cases:f680:details", kwargs={"queue_pk": data_queue["id"], "pk": missing_case_id})
with pytest.raises(HTTPError, match="404"):
authorized_client.get(url)
14 changes: 14 additions & 0 deletions caseworker/f680/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.urls import path

from caseworker.f680 import views


app_name = "f680"

urlpatterns = [
path(
"",
views.CaseDetailView.as_view(),
name="details",
),
]
24 changes: 24 additions & 0 deletions caseworker/f680/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.views.generic import TemplateView

from core.auth.views import LoginRequiredMixin

from caseworker.cases.services import get_case
from caseworker.cases.helpers.case import CaseworkerMixin
from caseworker.queues.services import get_queue


class CaseDetailView(LoginRequiredMixin, CaseworkerMixin, TemplateView):
template_name = "f680/case/detail.html"

def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)

self.case_id = str(kwargs["pk"])
self.case = get_case(request, self.case_id)
self.queue_id = kwargs["queue_pk"]
self.queue = get_queue(request, self.queue_id)

def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
context_data["case"] = self.case
return context_data
154 changes: 154 additions & 0 deletions caseworker/templates/case/base-case-summary.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
{% load rules %}

{% test_rule 'can_user_change_case' request case as can_user_change_case %}

<dl class="app-case__summary-list">
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.EXPORTER_REFERENCE' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.data.name }}
</dd>
</div>
{% if case.copy_of %}
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.COPY_OF' %}
</dt>
<dd class="app-case__summary-list__value">
<a class="govuk-link govuk-link--no-visited-state" id="link-case-copy-of" href="{% url 'cases:case' queue.id case.copy_of.id %}">{{ case.copy_of.reference_code }}</a>
</dd>
</div>
{% endif %}
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.SUBMITTED_AT' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.data.submitted_at|str_date }}
</dd>
</div>
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.SUBMITTED_BY' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.data.submitted_by }}
</dd>
</div>
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.STATUS' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.data.status.value }}
</dd>
<dd class="app-case__summary-list__actions">
{% if permissible_statuses %}
{% if not is_terminal or 'REOPEN_CLOSED_CASES' in permissions %}
{% if can_user_change_case %}
<a id="link-change-status" class="govuk-link govuk-link--no-visited-state" href="{% url 'cases:change_status' queue.id case.id %}">
{% lcs 'generic.CHANGE' %}
</a>
{% endif %}
{% endif %}
{% endif %}
</dd>
</div>
<div class="app-case__summary-list__row" id="case-sub-status">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.SUB_STATUS' %}
</dt>
<dd class="app-case__summary-list__value">
{% if case.data.sub_status %}
{{ case.data.sub_status.name }}
{% else %}
<span class="govuk-hint govuk-!-margin-0">No sub-status set</span>
{% endif %}
</dd>
{% test_rule 'can_user_change_sub_status' request case as can_user_change_sub_status %}
{% if can_user_change_sub_status %}
<dd class="app-case__summary-list__actions">
<a id="link-case-sub-status-change" class="govuk-link govuk-link--no-visited-state" href="{% url 'cases:change_sub_status' queue.id case.id %}">Change</a>
</dd>
{% endif %}
</div>
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.ASSIGNED_QUEUES' %}
</dt>
<dd class="app-case__summary-list__value">
{% if case.queue_names %}
<ol id="assigned-queues" class="govuk-list govuk-!-margin-0">
{% for queue_name in case.queue_names %}
<li>{{ queue_name }}</li>
{% endfor %}
</ol>
{% else %}
<span class="govuk-hint govuk-!-margin-0">
{% lcs 'cases.CasePage.DetailsTab.NO_QUEUES_ASSIGNED' %}
</span>
{% endif %}
</dd>
<dd class="app-case__summary-list__actions">
{% if can_user_change_case %}
<a id="link-change-queues" class="govuk-link govuk-link--no-visited-state" href="{% url 'cases:move' queue.id case.id %}">
{% lcs 'generic.CHANGE' %}
</a>
{% endif %}
</dd>
</div>
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.TYPE' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.case_type.reference.value }}
</dd>
</div>
{% if case.data.updated_at %}
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.LAST_UPDATED' %}
</dt>
<dd class="app-case__summary-list__value">
{{ case.data.updated_at|str_date }}
</dd>
</div>
{% endif %}
<div class="app-case__summary-list__row">
<dt class="app-case__summary-list__key">
{% lcs 'cases.CasePage.DetailsTab.ASSIGNED_USERS' %}
</dt>
<dd id="assigned-users" class="app-case__summary-list__value">
{% for queue_name, users in case.assigned_users.items %}
<span class="govuk-label">{{ queue_name }}</span>
<ol class="govuk-list govuk-!-margin-0">
{% for user in users %}
<li>
<div class="app-case__summary-list__value__fullwidth">
<a href="{% url 'users:user' user.id %}?return_to={{ CURRENT_PATH|urlencode }}&return_to_text={{ case.reference_code }}" class="govuk-link govuk-link--no-visited-state">{{ user|username }}</a>
<a href="{% url 'cases:remove-case-assignment' queue.id case.id %}?assignment_id={{user.assignment_id}}" class="govuk-link govuk-link--no-visited-state app-case__summary-list__value__item-action">Remove</a>
</div>
</li>
{% endfor %}
</ol>
{% empty %}
<span class="govuk-hint govuk-!-margin-0">
{% lcs 'cases.CasePage.DetailsTab.NO_USERS_ASSIGNED' %}
</span>
{% endfor %}
{% test_rule 'can_user_allocate_case' request case as can_user_allocate_case %}
{% if can_user_allocate_case %}
<div class="app-case__summary-list__value__actions">
<a id="link-change-assigned-users" class="govuk-link govuk-link--no-visited-state" href="{% url 'queues:case_assignments_assign_user' queue.id %}?cases={{case.id}}&return_to={{CURRENT_PATH|urlencode}}">
{% lcs 'cases.CasePage.DetailsTab.ADD_ASSIGNED_USER' %}
</a>
</div>
{% endif %}
</dd>
</div>
{% block additional_summary %}
{% endblock %}
</dl>
Loading

0 comments on commit fd4ef7f

Please sign in to comment.