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

LTD-5856 add initial question and feature flag to start f680 flow #2342

Draft
wants to merge 43 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1355221
add initial question and feature flag to start f680 flow
markj0hnst0n Jan 28, 2025
a7630ca
test amendment and feature flag change
markj0hnst0n Jan 28, 2025
a934d7f
more feature flag changes
markj0hnst0n Jan 28, 2025
c7cd6c3
remove f680 app
markj0hnst0n Jan 28, 2025
263fac9
feature flag var revert
markj0hnst0n Jan 28, 2025
3c5cbef
test update
markj0hnst0n Jan 28, 2025
70e7593
remove view
markj0hnst0n Jan 28, 2025
7c37a4b
add back in
markj0hnst0n Jan 28, 2025
b0badcd
add scaffold
markj0hnst0n Jan 28, 2025
e37589c
add f680 app files and initial question
markj0hnst0n Jan 28, 2025
3fba9fb
Create test_f680s.py
markj0hnst0n Jan 28, 2025
556bd88
more view testing added
markj0hnst0n Jan 29, 2025
d5ff705
more view testing added
markj0hnst0n Jan 29, 2025
0845fc1
set add feature flag test fixture
markj0hnst0n Jan 29, 2025
b2f1428
correct apps
markj0hnst0n Jan 29, 2025
ade61bd
add as pytest fixture
markj0hnst0n Jan 29, 2025
dbfce77
remove breakpoint
markj0hnst0n Jan 29, 2025
8a6c831
add ps ignore
markj0hnst0n Jan 29, 2025
10f2982
update
markj0hnst0n Jan 29, 2025
bd6e634
update env var
markj0hnst0n Jan 29, 2025
8a29723
add env var to exporter explicitly
markj0hnst0n Jan 29, 2025
c8b571c
add feature flag explicitly to CircleCi
markj0hnst0n Jan 29, 2025
89b1bbe
show correct name in template
markj0hnst0n Jan 29, 2025
52eb4d0
add add env var explicitly to test env
markj0hnst0n Jan 29, 2025
eb7b4e9
comment out unused
markj0hnst0n Jan 29, 2025
429dce1
Update test_urls.py
markj0hnst0n Jan 29, 2025
aad09c1
Update test_f680s.py
markj0hnst0n Jan 29, 2025
852d7f7
Update test_f680s.py
markj0hnst0n Jan 29, 2025
fdfb7a1
more tests added
markj0hnst0n Jan 29, 2025
a1c76c5
more tests added
markj0hnst0n Jan 29, 2025
3d215e1
more test info
markj0hnst0n Jan 29, 2025
e985a7d
different test approach
markj0hnst0n Jan 29, 2025
047d2d5
revert
markj0hnst0n Jan 29, 2025
acb4bf4
amendment
markj0hnst0n Jan 29, 2025
b4f82ec
post working with errors
markj0hnst0n Jan 29, 2025
a4df32c
post to summary redirect test added
markj0hnst0n Jan 29, 2025
9444143
more test additions
markj0hnst0n Jan 30, 2025
1c0b3f5
test update
markj0hnst0n Jan 30, 2025
b14066e
add more ps ignore and tidy tests
markj0hnst0n Jan 30, 2025
851b4d0
remove breakpoints
markj0hnst0n Jan 30, 2025
0b5bd52
test consolidation
markj0hnst0n Jan 30, 2025
a25271f
revert
markj0hnst0n Jan 30, 2025
b21ac9f
Update test_f680s.py
markj0hnst0n Jan 30, 2025
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
1 change: 1 addition & 0 deletions conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,4 @@ def show_toolbar(request):
GTM_ID = env.str("GTM_ID", default="")

GIT_COMMIT = env.str("GIT_COMMIT", default="")
FEATURE_FLAG_ALLOW_F680 = env.bool("FEATURE_FLAG_ALLOW_F680", default=False) # PS-IGNORE
1 change: 1 addition & 0 deletions conf/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"exporter.applications",
"exporter.organisation",
"exporter.goods",
"exporter.f680",
]

if MOCK_SSO_ACTIVATE_ENDPOINTS:
Expand Down
19 changes: 10 additions & 9 deletions exporter/apply_for_a_licence/forms/triage_questions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ def opening_question():
"before you provide access to controlled technology, software or data."
),
),
Option(
key="f680", # PS-IGNORE
value="Security Approval",
description=(
"Select if you need approval to give classified products or information to non-UK organisations, "
"governments and individuals. This includes F680 approval. You should apply for security approval" # PS-IGNORE
" before you apply for a licence."
),
disabled=not settings.FEATURE_FLAG_ALLOW_F680, # PS-IGNORE
),
Option(
key="transhipment",
value="Transhipment licence",
Expand All @@ -52,15 +62,6 @@ def opening_question():
),
disabled=settings.FEATURE_FLAG_ONLY_ALLOW_SIEL,
),
Option(
key="mod",
value="MOD clearance",
description=(
"Select if you need to share information (an F680) or to go to an exhibition, or if you're gifting "
"surplus products."
),
disabled=settings.FEATURE_FLAG_ONLY_ALLOW_SIEL,
),
]
if settings.FEATURE_FLAG_ONLY_ALLOW_SIEL:
description = render_to_string("applications/use-spire-triage.html")
Expand Down
7 changes: 6 additions & 1 deletion exporter/apply_for_a_licence/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
if not settings.FEATURE_FLAG_ONLY_ALLOW_SIEL:
urlpatterns += [
path("transhipment/", views.TranshipmentQuestions.as_view(), name="transhipment_questions"),
path("mod/", views.MODClearanceQuestions.as_view(), name="mod_questions"),
# path("mod/", views.MODClearanceQuestions.as_view(), name="mod_questions"),
path("<str:ogl>/", views.OpenGeneralLicenceQuestions.as_view(), name="ogl_questions"),
path("<str:ogl>/<uuid:pk>/", views.OpenGeneralLicenceSubmit.as_view(), name="ogl_submit"),
]

if settings.FEATURE_FLAG_ALLOW_F680: # /PS-IGNORE
urlpatterns += [
path("f680/", views.F680Questions.as_view(), name="f680_questions"), # /PS-IGNORE
]
25 changes: 15 additions & 10 deletions exporter/apply_for_a_licence/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from exporter.core.services import post_open_general_licence_cases
from lite_forms.views import SingleFormView, MultiFormView

from core.auth.views import LoginRequiredMixin
from core.auth.views import LoginRequiredMixin, RedirectView


class LicenceType(LoginRequiredMixin, SingleFormView):
Expand Down Expand Up @@ -69,17 +69,17 @@ def get_success_url(self):
return reverse_lazy("applications:task_list", kwargs={"pk": pk})


class MODClearanceQuestions(LoginRequiredMixin, MultiFormView):
def init(self, request, **kwargs):
self.forms = MOD_questions(None)
self.action = post_applications
# class MODClearanceQuestions(LoginRequiredMixin, MultiFormView):
# def init(self, request, **kwargs):
# self.forms = MOD_questions(None)
# self.action = post_applications

def on_submission(self, request, **kwargs):
self.forms = MOD_questions(request.POST.copy().get("application_type"))
# def on_submission(self, request, **kwargs):
# self.forms = MOD_questions(request.POST.copy().get("application_type"))

def get_success_url(self):
pk = self.get_validated_data()["id"]
return reverse_lazy("applications:task_list", kwargs={"pk": pk})
# def get_success_url(self):
# pk = self.get_validated_data()["id"]
# return reverse_lazy("applications:task_list", kwargs={"pk": pk})


class OpenGeneralLicenceQuestions(LoginRequiredMixin, MultiFormView):
Expand All @@ -101,3 +101,8 @@ def get_success_url(self):
class OpenGeneralLicenceSubmit(LoginRequiredMixin, TemplateView):
def get(self, request, *args, **kwargs):
return open_general_licence_submit_success_page(request, **kwargs)


class F680Questions(LoginRequiredMixin, RedirectView): # /PS-IGNORE
def get_redirect_url(self, *args, **kwargs):
return reverse("f680:apply") # /PS-IGNORE
Empty file added exporter/f680/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions exporter/f680/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ApplicationFormSteps:
APPLICATION_NAME = "APPLICATION_NAME"
27 changes: 27 additions & 0 deletions exporter/f680/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django import forms

from core.common.forms import BaseForm


class ApplicationNameForm(BaseForm):
class Layout:
TITLE = "Name of the application"
TITLE_AS_LABEL_FOR = "name"
SUBMIT_BUTTON_TEXT = "Continue"

name = forms.CharField(
label="",
help_text="Give the application a reference name so you can refer back to it when needed",
)

def get_layout_fields(self):
return ("name",)


class ApplicationSubmissionForm(BaseForm):
class Layout:
TITLE = ""
SUBMIT_BUTTON_TEXT = "Submit"

def get_layout_fields(self):
return []
13 changes: 13 additions & 0 deletions exporter/f680/payloads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from core.wizard.payloads import MergingPayloadBuilder
from exporter.applications.views.goods.common.payloads import get_cleaned_data
from .constants import ApplicationFormSteps # /PS-IGNORE


class F680CreatePayloadBuilder(MergingPayloadBuilder): # /PS-IGNORE
payload_dict = {
ApplicationFormSteps.APPLICATION_NAME: get_cleaned_data, # /PS-IGNORE
}

def build(self, form_dict):
payload = super().build(form_dict)
return {"application": payload}
11 changes: 11 additions & 0 deletions exporter/f680/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from core import client


def post_f680_application(request, json):
data = client.post(request, "/exporter/f680/application/", json)
return data.json(), data.status_code


def get_f680_application(request, application_id):
data = client.get(request, f"/exporter/f680/application/{application_id}/")
return data.json()
11 changes: 11 additions & 0 deletions exporter/f680/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.urls import path

from . import views


app_name = "f680"

urlpatterns = [
path("apply/", views.F680ApplicationCreateView.as_view(), name="apply"), # PS-IGNORE
path("<uuid:pk>/apply/", views.F680ApplicationSummaryView.as_view(), name="summary"), # PS-IGNORE
]
77 changes: 77 additions & 0 deletions exporter/f680/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from http import HTTPStatus

from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic import FormView

from core.auth.views import LoginRequiredMixin
from core.decorators import expect_status
from core.wizard.views import BaseSessionWizardView

from .constants import (
ApplicationFormSteps,
)
from .forms import (
ApplicationNameForm,
ApplicationSubmissionForm,
)
from .payloads import (
F680CreatePayloadBuilder, # PS-IGNORE
)
from .services import (
post_f680_application, # PS-IGNORE
get_f680_application, # PS-IGNORE
)


class F680ApplicationCreateView(LoginRequiredMixin, BaseSessionWizardView): # PS-IGNORE
form_list = [
(ApplicationFormSteps.APPLICATION_NAME, ApplicationNameForm),
]

@expect_status(
HTTPStatus.CREATED,
"Error creating F680 application", # PS-IGNORE
"Unexpected error creating F680 application", # PS-IGNORE
)
def post_f680_application(self, data): # PS-IGNORE
return post_f680_application(self.request, data) # PS-IGNORE

def get_success_url(self, application_id):
return reverse(
"f680:summary", # PS-IGNORE
kwargs={
"pk": application_id,
},
)

def get_payload(self, form_dict):
return F680CreatePayloadBuilder().build(form_dict) # /PS-IGNORE

def done(self, form_list, form_dict, **kwargs):
data = self.get_payload(form_dict)

response_data, _ = self.post_f680_application(data) # PS-IGNORE

return redirect(self.get_success_url(response_data["id"]))


class F680ApplicationSummaryView(LoginRequiredMixin, FormView): # PS-IGNORE
form_class = ApplicationSubmissionForm
template_name = "f680/summary.html" # PS-IGNORE

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

self.application = get_f680_application(request, kwargs["pk"])

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["application"] = self.application

return context

# This method currently just redirects back to the app summary but this will eventually
# submit the clearnace application.
def get_success_url(self):
return reverse("f680:summary", kwargs={"pk": self.application["id"]}) # PS-IGNORE
37 changes: 37 additions & 0 deletions exporter/templates/f680/summary.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% extends "layouts/base.html" %}

{% load crispy_forms_tags %}

{% block title %}Apply for an F680 Application{% endblock%}

{% block body %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l govuk-!-margin-bottom-2">F680 Application</h1>
<ol class="lite-task-list">
<li>
<h2 class="lite-task-list__section">
<span class="lite-task-list__section-number">1. </span>
Create Application
</h2>
<ul class="lite-task-list__items">
<li class="lite-task-list__item">
<div class="lite-task-list__item-header">
Your reference
<div class="lite-tag lite-tag--blue">
Saved
</div>
</div>
<div class="lite-task-list__item-details govuk-caption-m">
{{ application.application.name }}
</div>
</li>
</ul>
</li>
</ol>
<div class="app-submit-bar">
{% crispy form %}
</div>
</div>
</div>
{% endblock %}
5 changes: 5 additions & 0 deletions exporter/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@
urlpatterns = [
path("__debug__/", include(debug_toolbar.urls)),
] + urlpatterns

if settings.FEATURE_FLAG_ALLOW_F680:
urlpatterns += [
path("f680/", include("exporter.f680.urls")),
]
1 change: 1 addition & 0 deletions tests.caseworker.env
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ NOTIFY_FEEDBACK_EMAIL="feedback@lite"
FILE_UPLOAD_HANDLERS="django.core.files.uploadhandler.MemoryFileUploadHandler,django.core.files.uploadhandler.TemporaryFileUploadHandler"

SESSION_COOKIE_NAME=caseworker
FEATURE_FLAG_ALLOW_F680=True # PS-IGNORE
1 change: 1 addition & 0 deletions tests.exporter.env
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ NOTIFY_FEEDBACK_EMAIL="feedback@lite"
FILE_UPLOAD_HANDLERS="django.core.files.uploadhandler.MemoryFileUploadHandler,django.core.files.uploadhandler.TemporaryFileUploadHandler"

SESSION_COOKIE_NAME=exporter
FEATURE_FLAG_ALLOW_F680=True # PS-IGNORE
17 changes: 17 additions & 0 deletions unit_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,23 @@ def data_open_case():
}


@pytest.fixture
def data_f680_case(data_organisation):
return {
"id": "6cf7b401-62dc-4577-ad1d-4282f2aabc96",
"application": {"name": "F680 Test 1"},
"reference_code": None,
"organisation": {
"id": "3913ff20-5a2b-468a-bf5d-427228459b06",
"name": "Archway Communications",
"type": "commercial",
"status": "active",
},
"submitted_at": None,
"submitted_by": None,
}


@pytest.fixture
def data_standard_case(
data_organisation,
Expand Down
Loading