diff --git a/caseworker/queues/views/forms.py b/caseworker/queues/views/forms.py
index c48380119d..ab82849574 100644
--- a/caseworker/queues/views/forms.py
+++ b/caseworker/queues/views/forms.py
@@ -172,18 +172,16 @@ def __init__(self, queue, filters_data, all_flags, all_cles, all_regimes, countr
flag_url = reverse("flags:flags")
self.fields["flags"] = forms.MultipleChoiceField(
- label="Flags",
+ label="Show only cases with these flags",
choices=flags_choices,
required=False,
- help_text=f'Flag information (open in a new window)',
# setting id for javascript to use
widget=forms.SelectMultiple(attrs={"id": "flags"}),
)
self.fields["exclude_flags"] = forms.MultipleChoiceField(
- label="Exclude flags",
+ label="Do not show cases with these flags",
choices=flags_choices,
required=False,
- help_text=f'Flag information (open in a new window)',
# setting id for javascript to use
widget=forms.SelectMultiple(attrs={"id": "exclude_flags"}),
)
@@ -229,6 +227,11 @@ def __init__(self, queue, filters_data, all_flags, all_cles, all_regimes, countr
"submitted_to",
Field("flags", css_class="multi-select-filter"),
Field("exclude_flags", css_class="multi-select-filter"),
+ HTML(
+ '
"
+ ),
"finalised_from",
"finalised_to",
]
diff --git a/core/builtins/custom_tags.py b/core/builtins/custom_tags.py
index 4cac4e3adf..8ca4783fe7 100644
--- a/core/builtins/custom_tags.py
+++ b/core/builtins/custom_tags.py
@@ -178,13 +178,12 @@ def str_date_only(value):
return localtime(parse(value)).strftime("%-d %B %Y")
-@register.simple_tag
-@mark_safe # noqa: S308
+@register.inclusion_tag("inclusion_tags/hidden-field.html")
def hidden_field(key, value):
"""
Generates a hidden field from the given key and value
"""
- return f''
+ return {"key": key, "value": value}
@register.filter()
diff --git a/core/templates/inclusion_tags/hidden-field.html b/core/templates/inclusion_tags/hidden-field.html
new file mode 100644
index 0000000000..44db06f0ff
--- /dev/null
+++ b/core/templates/inclusion_tags/hidden-field.html
@@ -0,0 +1 @@
+
diff --git a/lite_content/lite_internal_frontend/strings.py b/lite_content/lite_internal_frontend/strings.py
index 7f77a92975..76631d6e34 100644
--- a/lite_content/lite_internal_frontend/strings.py
+++ b/lite_content/lite_internal_frontend/strings.py
@@ -13,6 +13,7 @@
queues, # noqa
picklists, # noqa
routing_rules, # noqa
+ tests, # noqa
) # noqa
# Buttons
diff --git a/lite_content/lite_internal_frontend/tests.py b/lite_content/lite_internal_frontend/tests.py
new file mode 100644
index 0000000000..8bb74bbb60
--- /dev/null
+++ b/lite_content/lite_internal_frontend/tests.py
@@ -0,0 +1,2 @@
+class TestPage:
+ BUTTON = "Test Button"
diff --git a/lite_forms/templates/govuk-link-button.html b/lite_forms/templates/govuk-link-button.html
new file mode 100644
index 0000000000..400a4c017a
--- /dev/null
+++ b/lite_forms/templates/govuk-link-button.html
@@ -0,0 +1,8 @@
+
+ {% lcs text %}
+ {% if show_chevron %}
+
+ {% endif %}
+
diff --git a/lite_forms/templatetags/custom_tags.py b/lite_forms/templatetags/custom_tags.py
index 97857f37d8..0276747954 100644
--- a/lite_forms/templatetags/custom_tags.py
+++ b/lite_forms/templatetags/custom_tags.py
@@ -6,7 +6,6 @@
from django.urls import reverse
from django.utils.safestring import mark_safe
-from core.builtins.custom_tags import get_const_string
from lite_forms.helpers import flatten_data
@@ -199,27 +198,25 @@ def item_with_rating_exists(items, rating):
return True
-@register.simple_tag
-@mark_safe # noqa: S308
+@register.inclusion_tag("govuk-link-button.html")
def govuk_link_button(text, url, url_param=None, id="", classes="", query_params="", show_chevron=False, hidden=False):
- text = get_const_string(text)
+ if not url_param:
+ url_param = []
+
if isinstance(url_param, str):
url_param = [url_param]
- url = reverse(url, args=url_param if url_param else [])
- id = f'id="button-{id}"' if id else ""
- chevron = ""
- if show_chevron:
- chevron = (
- ''
- )
- hidden = 'style="display: none;"' if hidden else ""
-
- return (
- f'{text}{chevron}'
- )
+
+ url = reverse(url, args=url_param)
+
+ return {
+ "text": text,
+ "url": url,
+ "id": id,
+ "classes": classes,
+ "show_chevron": show_chevron,
+ "hidden": hidden,
+ "query_params": query_params,
+ }
@register.filter()
diff --git a/ui_tests/caseworker/features/give_advice/lu_consolidate_advice.feature b/ui_tests/caseworker/features/give_advice/lu_consolidate_advice.feature
index 8a54e2a4da..25b69321fc 100644
--- a/ui_tests/caseworker/features/give_advice/lu_consolidate_advice.feature
+++ b/ui_tests/caseworker/features/give_advice/lu_consolidate_advice.feature
@@ -52,3 +52,102 @@ Feature: I want to record my user advice and any comments and conditions relatin
And I click on "Details" tab
Then I see the case status is now "Finalised"
And I see the case is not assigned to any queues
+
+ @lu_consolidate_advice_ogd_licence_conditions
+ Scenario: LU consolidate advice with OGD licence conditions
+ Given I sign in as Test UAT user
+ And I create standard application or standard application has been previously created
+ # LR
+ When I switch to "Licensing Reception" with queue "Licensing Reception SIEL applications" and I submit the case
+ Then I see the case status is now "Initial checks"
+ And I see the case is assigned to queues "Enforcement Unit Cases to Review, Technical Assessment Unit SIELs to Review"
+ # EU
+ When I switch to "Enforcement Unit" with queue "Enforcement Unit Cases to Review" and I submit the case
+ Then I see the case status is now "Initial checks"
+ And I see the case is assigned to queues "Technical Assessment Unit SIELs to Review"
+ And I see the case is not assigned to queues "Enforcement Unit Cases to Review"
+ # TAU
+ When I go to my profile page
+ And I change my team to "Technical Assessment Unit" and default queue to "Technical Assessment Unit SIELs to Review"
+ And I go to my case list
+ Then I see previously created application
+ When I click on the application previously created
+ And I assign myself to the case
+ Then I click on Product assessment
+ And I select good
+ And I select the CLE "ML1a"
+ And I select "components for" / "microwave components" as report summary prefix / subject and regime to none and submit
+ When I click move case forward
+ Then I don't see previously created application
+ # LU
+ When I switch to "Licensing Unit" with queue "Licensing Unit Pre-circulation Cases to Review" and I submit the case
+ Then I see the case status is now "OGD Advice"
+ And I see the case is assigned to queues "MOD-DI Indirect cases to review, MOD-CapProt cases to review, FCDO Cases to Review"
+ # MOD-DI
+ When I switch to "MOD-DI" with queue "MOD-DI Indirect cases to review" and I submit the case
+ Then I see the case status is now "OGD Advice"
+ And I see the case is assigned to queues "MOD-CapProt cases to review, FCDO Cases to Review"
+
+ ##### MOD Sub-advisor to give advice #####
+ When I go to my profile page
+ And I change my team to "MOD-CapProt" and default queue to "MOD-CapProt cases to review"
+ And I go to my case list
+ Then I should see my case in the cases list
+ When I click the application previously created
+ And I assign myself to the case
+ And I click the recommendations and decision tab
+ And I click make recommendation
+ And I click approve all
+ And I click continue
+ And I enter "reason for approving" as the reasons for approving
+ And I click the text "Add a licence condition, instruction to exporter or footnote"
+ And I enter "MOD licence condition" as the licence condition
+ And I enter "instruction for exporter" as the instructions for the exporter
+ And I enter "reporting footnote" as the reporting footnote
+ And I click submit recommendation
+ Then I see "reason for approving" as the reasons for approving
+ And I see "MOD licence condition" as the licence condition
+ And I see "instruction for exporter" as the instructions for the exporter
+ And I see "reporting footnote" as the reporting footnote
+
+ ##### FCDO Sub-advisor to give advice #####
+ When I go to my profile page
+ And I change my team to "FCDO" and default queue to "FCDO Cases to Review"
+ And I go to my case list
+ Then I should see my case in the cases list
+ When I click the application previously created
+ And I assign myself to the case
+ And I click the recommendations and decision tab
+ And I click make recommendation
+ And I click approve all
+ And I click continue
+ And I select countries "GB, UA"
+ And I enter "reason for approving" as the reasons for approving
+ And I click the text "Add a licence condition, instruction to exporter or footnote"
+ And I enter "FCDO licence condition" as the licence condition
+ And I enter "instruction for exporter" as the instructions for the exporter
+ And I enter "reporting footnote" as the reporting footnote
+ And I click submit recommendation
+ Then I see "reason for approving" as the reasons for approving
+ And I see "FCDO licence condition" as the licence condition
+ And I see "instruction for exporter" as the instructions for the exporter
+ And I see "reporting footnote" as the reporting footnote
+
+ When I logout
+ Given I sign in as Licensing Unit Officer
+ And I prepare the application for final review
+ When I go to my case list
+ And I go to my case list
+ And I click the application previously created
+ And I assign myself as case officer to the case
+ And I go to my case list
+ And I click the application previously created
+ And I click the recommendations and decision tab
+ And I click "Review and combine"
+ And I enter "reason for approving" as the reasons for approving
+ And I click "Add licence condition"
+ And I click submit recommendation
+ Then I see "reason for approving" as the reasons for approving
+ And I see "MOD licence condition" in the licence condition
+ And I see "FCDO licence condition" in the licence condition
+ And I see "serial numbers" in the licence condition
diff --git a/ui_tests/caseworker/pages/advice.py b/ui_tests/caseworker/pages/advice.py
index 7cf2de31fa..47d685c6d6 100644
--- a/ui_tests/caseworker/pages/advice.py
+++ b/ui_tests/caseworker/pages/advice.py
@@ -165,8 +165,8 @@ def get_refusal_note(self):
def get_licence_condition(self):
return self.driver.find_element(
- by=By.XPATH,
- value="//p[preceding-sibling::*[self::h2 or self::h3][contains(text(), 'Licence condition')]][2]",
+ by=By.CLASS_NAME,
+ value="licence-condition",
).text
def get_instructions_for_exporter(self):
diff --git a/ui_tests/caseworker/step_defs/test_give_advice/conftest.py b/ui_tests/caseworker/step_defs/test_give_advice/conftest.py
index ab9dc74ee8..d22b7034ea 100644
--- a/ui_tests/caseworker/step_defs/test_give_advice/conftest.py
+++ b/ui_tests/caseworker/step_defs/test_give_advice/conftest.py
@@ -133,6 +133,11 @@ def should_see_licence_condition(driver, licence_condition, context): # noqa
assert RecommendationsAndDecisionPage(driver).get_licence_condition() == licence_condition
+@then(parsers.parse('I see "{licence_condition}" in the licence condition'))
+def should_see_licence_condition(driver, licence_condition, context): # noqa
+ assert licence_condition in RecommendationsAndDecisionPage(driver).get_licence_condition()
+
+
@then(parsers.parse('I see "{instructions}" as the instructions for the exporter'))
def should_see_instructions_for_exporter(driver, instructions, context): # noqa
assert RecommendationsAndDecisionPage(driver).get_instructions_for_exporter() == instructions
diff --git a/unit_tests/caseworker/cases/views/test_case_bookmarks.py b/unit_tests/caseworker/cases/views/test_case_bookmarks.py
index eb977ad07f..e8a21beb76 100644
--- a/unit_tests/caseworker/cases/views/test_case_bookmarks.py
+++ b/unit_tests/caseworker/cases/views/test_case_bookmarks.py
@@ -72,6 +72,6 @@ def test_bookmarks_present(
assert third["filter_json"] == {
"flags": ["64cbcf98-9beb-41ad-8f5d-276dee768990", "8f02e308-9861-4284-a7f0-f05495efce31"]
}
- assert third["description"] == "Flags: AG Biological, AG Chemical"
+ assert third["description"] == "Show only cases with these flags: AG Biological, AG Chemical"
assert "flags=64cbcf98-9beb-41ad-8f5d-276dee768990" in third["url"]
assert "flags=8f02e308-9861-4284-a7f0-f05495efce31" in third["url"]
diff --git a/unit_tests/caseworker/test_template_tags.py b/unit_tests/caseworker/test_template_tags.py
index c3d227f2a9..f008957fd0 100644
--- a/unit_tests/caseworker/test_template_tags.py
+++ b/unit_tests/caseworker/test_template_tags.py
@@ -1,6 +1,7 @@
from core.builtins import custom_tags
from caseworker.core.constants import SLA_CIRCUMFERENCE
+from caseworker.letter_templates.templatetags.variable_highlight import variable_highlight
import pytest
@@ -60,3 +61,20 @@ def test_sla_colour(remaining, unit, colour):
def test_sla_colour_missing_unit():
with pytest.raises(ValueError):
custom_tags.sla_colour(10, "")
+
+
+@pytest.mark.parametrize(
+ "input, expected",
+ (
+ ("just text", "just text"),
+ ("with {{ variable }}", 'with {{ variable }}'),
+ (
+ "with {% another_variable %}",
+ 'with {% another_variable %}',
+ ),
+ ("Link", "Link"),
+ ("", "<script>alert()</script>"),
+ ),
+)
+def test_variable_highlight(input, expected):
+ assert variable_highlight(input) == expected
diff --git a/unit_tests/conftest.py b/unit_tests/conftest.py
index a7dcddb6ab..0f8dca8f0a 100644
--- a/unit_tests/conftest.py
+++ b/unit_tests/conftest.py
@@ -2602,12 +2602,29 @@ def _create_files(*files):
return _create_files
-@pytest.fixture
+@pytest.fixture()
+def authorized_client(client):
+ return client
+
+
+@pytest.fixture()
def mock_request(rf, authorized_client):
request = rf.get("/")
request.session = authorized_client.session
request.requests_session = requests.Session()
- yield request
+ return request
+
+
+@pytest.fixture()
+def render_template_string(mock_request):
+ def _render_template_string(template_string, context=None):
+ if not context:
+ context = {}
+ template = Template(template_string)
+ context = RequestContext(mock_request, context)
+ return template.render(context)
+
+ return _render_template_string
@pytest.fixture()
diff --git a/unit_tests/core/builtins/test_custom_tags.py b/unit_tests/core/builtins/test_custom_tags.py
index 388b8c7c6b..22542a42fc 100644
--- a/unit_tests/core/builtins/test_custom_tags.py
+++ b/unit_tests/core/builtins/test_custom_tags.py
@@ -1,6 +1,8 @@
import datetime
import pytest
+from pytest_django.asserts import assertHTMLEqual
+
from decimal import Decimal
from core.builtins import custom_tags
@@ -426,3 +428,33 @@ def test_pagination_params(url, page, expected):
def test_pagination():
with pytest.raises(ValueError):
custom_tags.pagination({}, link_type="madeup")
+
+
+@pytest.mark.parametrize(
+ "input, context, expected",
+ [
+ (
+ "{% hidden_field 'test-key' 'test-value' %}",
+ {},
+ '',
+ ),
+ (
+ "{% hidden_field key value %}",
+ {
+ "key": "test-key",
+ "value": "test-value",
+ },
+ '',
+ ),
+ (
+ "{% hidden_field key value %}",
+ {
+ "key": '">',
+ ),
+ ],
+)
+def test_hidden_field(render_template_string, input, context, expected):
+ assertHTMLEqual(render_template_string(input, context), expected)
diff --git a/unit_tests/exporter/goods/forms/test_forms.py b/unit_tests/exporter/goods/forms/test_forms.py
index 1cd864af95..e1e7e30dcf 100644
--- a/unit_tests/exporter/goods/forms/test_forms.py
+++ b/unit_tests/exporter/goods/forms/test_forms.py
@@ -1,3 +1,5 @@
+import datetime
+
from unittest.mock import patch
import pytest
@@ -590,25 +592,28 @@ def test_registered_firearms_dealer_form(data, valid, error_field, error_message
assert form.errors[error_field][0] == error_message
+FUTURE_YEAR = datetime.date.today().year + 1
+
+
@pytest.mark.parametrize(
"data, files, valid, error_field, error_message",
(
(
- {"reference_code": "ref_code", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": 2025},
+ {"reference_code": "ref_code", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": FUTURE_YEAR},
{"file": SimpleUploadedFile("test", b"test_content")},
True,
None,
None,
),
(
- {"reference_code": "ref_code", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": 2025},
+ {"reference_code": "ref_code", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": FUTURE_YEAR},
{"file": ""},
False,
"file",
"Select certificate file to upload",
),
(
- {"reference_code": "", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": 2025},
+ {"reference_code": "", "expiry_date_0": 1, "expiry_date_1": 1, "expiry_date_2": FUTURE_YEAR},
{"file": SimpleUploadedFile("test", b"test_content")},
False,
"reference_code",
@@ -638,7 +643,7 @@ def test_attach_fiream_dealer_certificate_form(data, files, valid, error_field,
if valid:
assert form.cleaned_data["expiry_date_day"] == "1"
assert form.cleaned_data["expiry_date_month"] == "1"
- assert form.cleaned_data["expiry_date_year"] == "2025"
+ assert form.cleaned_data["expiry_date_year"] == str(FUTURE_YEAR)
else:
assert form.errors[error_field][0] == error_message
diff --git a/unit_tests/lite_forms/templatetags/test_custom_tags.py b/unit_tests/lite_forms/templatetags/test_custom_tags.py
index 3932438a69..45ddf72036 100644
--- a/unit_tests/lite_forms/templatetags/test_custom_tags.py
+++ b/unit_tests/lite_forms/templatetags/test_custom_tags.py
@@ -1,5 +1,7 @@
import pytest
+from pytest_django.asserts import assertHTMLEqual
+
from lite_forms.templatetags import custom_tags
@@ -12,3 +14,42 @@
)
def test_file_type(filename, expected):
assert expected == custom_tags.file_type(filename)
+
+
+@pytest.mark.parametrize(
+ "input, context, expected",
+ [
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' %}",
+ {},
+ 'Test Button',
+ ),
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' id='test-id' classes='govuk-button--secondary' %}",
+ {},
+ 'Test Button',
+ ),
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' show_chevron=True %}",
+ {},
+ 'Test Button',
+ ),
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' query_params='?foo=bar' %}",
+ {},
+ 'Test Button',
+ ),
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' hidden=True %}",
+ {},
+ 'Test Button',
+ ),
+ (
+ "{% govuk_link_button text='tests.TestPage.BUTTON' url='core:index' query_params=html_content %}",
+ {"html_content": '">fooTest Button',
+ ),
+ ],
+)
+def test_govuk_link_button(render_template_string, input, context, expected):
+ assertHTMLEqual(render_template_string(input, context), expected)