Skip to content

Commit 87d23e0

Browse files
committed
Delegate out processing of licence type questions to separate apps
1 parent ad625ff commit 87d23e0

File tree

12 files changed

+106
-126
lines changed

12 files changed

+106
-126
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.shortcuts import redirect
2+
3+
4+
class ExportLicenceLicenceTypeProcessor:
5+
def __init__(self, request):
6+
self.request = request
7+
8+
def process(self):
9+
return redirect("apply_for_a_licence:export_licence_questions")

exporter/apply_for_a_licence/enums.py

+7
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,10 @@ def as_options(cls):
3737
@classmethod
3838
def get_by_acronym(cls, acronym):
3939
return next(ogl for ogl in cls.all() if ogl.acronym.lower() == acronym.lower())
40+
41+
42+
class LicenceType:
43+
EXPORT_LICENCE = "export_licence"
44+
F680 = "f680"
45+
TRANSHIPMENT = "transhipment"
46+
TRADE_CONTROL_LICENCE = "trade_control_licence"

exporter/apply_for_a_licence/forms/triage_questions.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from core.constants import GoodsTypeCategory
1414
from core.forms.layouts import RenderTemplate
1515
from exporter.applications.forms.edit import firearms_form, reference_name_form, told_by_an_official_form
16+
from exporter.apply_for_a_licence.enums import LicenceType
1617
from exporter.core.constants import CaseTypes
1718
from lite_content.lite_exporter_frontend import generic
1819
from lite_content.lite_exporter_frontend.applications import (
@@ -38,27 +39,27 @@ class Layout:
3839
licence_type = forms.ChoiceField(
3940
choices=(
4041
Choice(
41-
"export_licence",
42+
LicenceType.EXPORT_LICENCE,
4243
"Export licence",
4344
hint="Select if you’re sending products from the UK to another country. You need an export licence "
4445
"before you provide access to controlled technology, software or data.",
4546
),
4647
Choice(
47-
"f680",
48+
LicenceType.F680,
4849
"Security Approval",
4950
hint="Select if you need approval to give classified products or information to non-UK organisations, "
5051
"governments and individuals. This includes F680 approval. You should apply for security approval "
5152
"before you apply for a licence.",
5253
),
5354
Choice(
54-
"transhipment",
55+
LicenceType.TRANSHIPMENT,
5556
"Transhipment licence",
5657
disabled=True,
5758
hint="Select if you're shipping something from overseas through the UK on to another country. If the "
5859
"products will be in the UK for 30 days or more, apply for an export licence.",
5960
),
6061
Choice(
61-
"trade_control_licence",
62+
LicenceType.TRADE_CONTROL_LICENCE,
6263
"Trade control licence",
6364
disabled=True,
6465
hint="Select if you’re arranging or brokering the sale or movement of controlled military products "

exporter/apply_for_a_licence/urls.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
app_name = "apply_for_a_licence"
88

99
urlpatterns = [
10-
path("", views.LicenceType.as_view(), name="start"),
10+
path("", views.LicenceTypeView.as_view(), name="start"),
1111
path("export/", views.ExportLicenceQuestions.as_view(), name="export_licence_questions"),
12-
path("f680/", views.F680Questions.as_view(), name="f680_questions"),
1312
]
1413

1514
if not settings.FEATURE_FLAG_ONLY_ALLOW_SIEL:

exporter/apply_for_a_licence/views.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
TemplateView,
55
)
66

7+
from lite_forms.views import MultiFormView
8+
79
from exporter.applications.services import post_applications, post_open_general_licences_applications
10+
from exporter.applications.licence_type_processors import ExportLicenceLicenceTypeProcessor
811
from exporter.apply_for_a_licence.forms.open_general_licences import (
912
open_general_licence_forms,
1013
open_general_licence_submit_success_page,
1114
)
12-
15+
from exporter.apply_for_a_licence.enums import LicenceType
1316
from exporter.apply_for_a_licence.forms.triage_questions import (
1417
LicenceTypeForm,
1518
export_licence_questions,
@@ -18,13 +21,12 @@
1821
from exporter.apply_for_a_licence.validators import validate_open_general_licences
1922
from exporter.core.constants import PERMANENT, CaseTypes
2023
from exporter.core.services import post_open_general_licence_cases
21-
from lite_forms.views import MultiFormView
24+
from exporter.f680.licence_type_processors import F680LicenceLicenceTypeProcessor
2225

23-
from core.auth.views import LoginRequiredMixin, RedirectView
24-
from exporter.f680.views import F680FeatureRequiredMixin
26+
from core.auth.views import LoginRequiredMixin
2527

2628

27-
class LicenceType(LoginRequiredMixin, FormView):
29+
class LicenceTypeView(LoginRequiredMixin, FormView):
2830
form_class = LicenceTypeForm
2931
template_name = "core/form.html"
3032

@@ -34,11 +36,16 @@ def get_form_kwargs(self):
3436
return kwargs
3537

3638
def form_valid(self, form):
37-
self.licence_type = form.cleaned_data["licence_type"]
38-
return super().form_valid(form)
39+
licence_type = form.cleaned_data["licence_type"]
3940

40-
def get_success_url(self):
41-
return reverse(f"apply_for_a_licence:{self.licence_type}_questions")
41+
LicenceTypeProcessor = {
42+
LicenceType.EXPORT_LICENCE: ExportLicenceLicenceTypeProcessor,
43+
LicenceType.F680: F680LicenceLicenceTypeProcessor,
44+
}[licence_type]
45+
46+
licence_type_processor = LicenceTypeProcessor(self.request)
47+
48+
return licence_type_processor.process()
4249

4350
def get_context_data(self, *args, **kwargs):
4451
ctx = super().get_context_data(*args, **kwargs)
@@ -72,11 +79,6 @@ def get_success_url(self):
7279
return reverse_lazy("applications:task_list", kwargs={"pk": pk})
7380

7481

75-
class F680Questions(LoginRequiredMixin, RedirectView, F680FeatureRequiredMixin):
76-
def get_redirect_url(self, *args, **kwargs):
77-
return reverse("f680:apply")
78-
79-
8082
class TranshipmentQuestions(LoginRequiredMixin, MultiFormView):
8183
def init(self, request, **kwargs):
8284
self.forms = transhipment_questions(request)
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.shortcuts import redirect
2+
3+
from http import HTTPStatus
4+
5+
from core.decorators import expect_status
6+
7+
from exporter.f680.services import post_f680_application
8+
9+
10+
class F680LicenceLicenceTypeProcessor:
11+
def __init__(self, request):
12+
self.request = request
13+
14+
@expect_status(
15+
HTTPStatus.CREATED,
16+
"Error creating F680 application",
17+
"Unexpected error creating F680 application",
18+
)
19+
def post_f680_application(self, data):
20+
return post_f680_application(self.request, data)
21+
22+
def process(self):
23+
data = {"application": {}}
24+
response_data, _ = self.post_f680_application(data)
25+
return redirect("f680:summary", pk=response_data["id"])

exporter/f680/tests/test_views.py

+6-55
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def authorized_client(authorized_client_factory, mock_exporter_user):
2020

2121

2222
@pytest.fixture
23-
def f680_apply_url():
24-
return reverse("f680:apply")
23+
def apply_for_a_licence_url():
24+
return reverse("apply_for_a_licence:start")
2525

2626

2727
@pytest.fixture
@@ -129,69 +129,20 @@ def set_f680_allowed_organisation(settings, organisation_pk):
129129
settings.FEATURE_FLAG_ALLOW_F680 = False
130130

131131

132-
class TestApplyForLicenceQuestionsClass:
133-
def test_triage_f680_apply_redirect_success(self, authorized_client, f680_apply_url):
134-
response = authorized_client.post(reverse("apply_for_a_licence:f680_questions"))
135-
assert response.status_code == 302
136-
assert response.url == f680_apply_url
137-
138-
139-
class TestF680ApplicationCreateView:
140-
def test_get_create_f680_view_success(
141-
self,
142-
authorized_client,
143-
f680_apply_url,
144-
f680_summary_url_with_application,
145-
mock_application_post,
146-
):
147-
response = authorized_client.get(f680_apply_url)
148-
assert response.status_code == 302
149-
assert response.url == f680_summary_url_with_application
150-
assert mock_application_post.called_once
151-
assert mock_application_post.last_request.json() == {"application": {}}
152-
153-
def test_get_create_f680_view_success_allowed_organisation(
132+
class TestF680ApplyForALicence:
133+
def test_POST_apply_for_a_licence_success(
154134
self,
155135
authorized_client,
156-
f680_apply_url,
136+
apply_for_a_licence_url,
157137
f680_summary_url_with_application,
158138
mock_application_post,
159-
set_f680_allowed_organisation,
160139
):
161-
response = authorized_client.get(f680_apply_url)
140+
response = authorized_client.post(apply_for_a_licence_url, data={"licence_type": "f680"})
162141
assert response.status_code == 302
163142
assert response.url == f680_summary_url_with_application
164143
assert mock_application_post.called_once
165144
assert mock_application_post.last_request.json() == {"application": {}}
166145

167-
def test_get_create_f680_view_fail_with_feature_flag_off(
168-
self,
169-
authorized_client,
170-
f680_apply_url,
171-
mock_f680_application_get,
172-
unset_f680_feature_flag,
173-
):
174-
response = authorized_client.get(f680_apply_url)
175-
assert response.context[0].get("title") == "Forbidden"
176-
assert (
177-
"You are not authorised to use the F680 Security Clearance application feature"
178-
in response.context[0].get("description").args
179-
)
180-
181-
def test_get_create_f680_view_fail_with_feature_organidation_not_allowed(
182-
self,
183-
authorized_client,
184-
f680_apply_url,
185-
mock_f680_application_get,
186-
unset_f680_allowed_organisation,
187-
):
188-
response = authorized_client.get(f680_apply_url)
189-
assert response.context[0].get("title") == "Forbidden"
190-
assert (
191-
"You are not authorised to use the F680 Security Clearance application feature"
192-
in response.context[0].get("description").args
193-
)
194-
195146

196147
class TestF680ApplicationSummaryView:
197148
def test_get_f680_summary_view_success(

exporter/f680/urls.py

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
app_name = "f680"
77

88
urlpatterns = [
9-
path("apply/", views.F680ApplicationCreateView.as_view(), name="apply"),
109
path("<uuid:pk>/apply/", views.F680ApplicationSummaryView.as_view(), name="summary"),
1110
path(
1211
"<uuid:pk>/general-application-details/",

exporter/f680/views.py

+1-29
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@
22
import rules
33

44
from django.contrib.auth.mixins import AccessMixin
5-
from django.shortcuts import redirect
65
from django.urls import reverse
7-
from django.views.generic import FormView, RedirectView
6+
from django.views.generic import FormView
87

98
from core.auth.views import LoginRequiredMixin
109
from core.decorators import expect_status
1110

1211
from .forms import ApplicationSubmissionForm
1312

1413
from .services import (
15-
post_f680_application,
1614
get_f680_application,
1715
submit_f680_application,
1816
)
@@ -29,32 +27,6 @@ def dispatch(self, request, *args, **kwargs):
2927
return super().dispatch(request, *args, **kwargs)
3028

3129

32-
class F680ApplicationCreateView(LoginRequiredMixin, F680FeatureRequiredMixin, RedirectView):
33-
34-
@expect_status(
35-
HTTPStatus.CREATED,
36-
"Error creating F680 application",
37-
"Unexpected error creating F680 application",
38-
)
39-
def post_f680_application(self, data):
40-
return post_f680_application(self.request, data)
41-
42-
def get_success_url(self, application_id):
43-
return reverse(
44-
"f680:summary",
45-
kwargs={
46-
"pk": application_id,
47-
},
48-
)
49-
50-
def get(self, request, *args, **kwargs):
51-
super().get(request, *args, **kwargs)
52-
# Data required to create a base application
53-
data = {"application": {}}
54-
response_data, _ = self.post_f680_application(data)
55-
return redirect(self.get_success_url(response_data["id"]))
56-
57-
5830
class F680ApplicationSummaryView(LoginRequiredMixin, F680FeatureRequiredMixin, FormView):
5931
form_class = ApplicationSubmissionForm
6032
template_name = "f680/summary.html"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pytest
2+
3+
from django.urls import reverse
4+
5+
6+
@pytest.fixture()
7+
def apply_for_a_licence_url():
8+
return reverse("apply_for_a_licence:start")
9+
10+
11+
def test_POST_apply_for_a_licence_redirects(
12+
authorized_client,
13+
apply_for_a_licence_url,
14+
):
15+
response = authorized_client.post(apply_for_a_licence_url, data={"licence_type": "export_licence"})
16+
assert response.status_code == 302
17+
assert response.url == reverse("apply_for_a_licence:export_licence_questions")

unit_tests/exporter/apply_for_a_licence/test_urls.py

-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ def test_url_respects_siel_only_feature_flag_off(settings):
1818
# then SIEL and start url are found
1919
reverse("apply_for_a_licence:start")
2020
reverse("apply_for_a_licence:export_licence_questions")
21-
reverse("apply_for_a_licence:f680_questions")
2221

2322
# but non SIEL urls are not found
2423
with pytest.raises(NoReverseMatch):
@@ -37,7 +36,6 @@ def test_url_respects_siel_only_feature_flag_on(settings):
3736
# then SIEL and start url are found
3837
reverse("apply_for_a_licence:start")
3938
reverse("apply_for_a_licence:export_licence_questions")
40-
reverse("apply_for_a_licence:f680_questions")
4139

4240
# and non SIEL urls are found
4341
reverse("apply_for_a_licence:transhipment_questions")

0 commit comments

Comments
 (0)