diff --git a/_infra/helm/response-operations-ui/Chart.yaml b/_infra/helm/response-operations-ui/Chart.yaml index 2057b194f..a8fca436c 100644 --- a/_infra/helm/response-operations-ui/Chart.yaml +++ b/_infra/helm/response-operations-ui/Chart.yaml @@ -14,8 +14,8 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. -version: 3.1.53 +version: 3.1.54 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. -appVersion: 3.1.53 +appVersion: 3.1.54 diff --git a/response_operations_ui/contexts/case.py b/response_operations_ui/contexts/case.py new file mode 100644 index 000000000..b42a373e3 --- /dev/null +++ b/response_operations_ui/contexts/case.py @@ -0,0 +1,35 @@ +from flask import url_for + + +def build_response_status_context( + ru_ref: str, + survey_short_name: str, + case_group_id: str, + ce_period: str, + allowed_transitions_for_case: dict, + survey_id: str, + has_reporting_unit_permission: bool, +) -> dict: + if has_reporting_unit_permission: + change_response_status = { + "url": url_for( + "case_bp.update_response_status", + ru_ref=ru_ref, + survey=survey_short_name, + case_group_id=case_group_id, + period=ce_period, + ), + "radios": _generate_radios(allowed_transitions_for_case), + "cancel_link": url_for("reporting_unit_bp.view_reporting_unit_survey", ru_ref=ru_ref, survey_id=survey_id), + } + else: + change_response_status = {} + return {"change_response_status": change_response_status} + + +def _generate_radios(allowed_transitions_for_case: dict) -> list: + radios = [ + {"id": f"state-{index + 1}", "label": {"text": status}, "value": event} + for index, (event, status) in enumerate(allowed_transitions_for_case.items()) + ] + return radios diff --git a/response_operations_ui/contexts/reporting_units.py b/response_operations_ui/contexts/reporting_units.py new file mode 100644 index 000000000..688f0f3db --- /dev/null +++ b/response_operations_ui/contexts/reporting_units.py @@ -0,0 +1,207 @@ +from flask import url_for + +CE_STATUS_CLASS = { + "Not started": "ons-status--info", + "In progress": "ons-status--pending", + "Completed": "ons-status--success", + "Completed by phone": "ons-status--success", + "No longer required": "ons-status--dead", +} + +ENROLMENT_ENABLED = "ENABLED" +ENROLMENT_PENDING = "PENDING" + + +def build_reporting_units_context( + collection_exercises: list, ru: dict, survey: dict, respondents: list, case, unused_iac: str, permissions: dict +) -> dict: + collection_exercise_section = _build_collection_exercise_section( + collection_exercises, ru["sampleUnitRef"], survey["shortName"], permissions["reporting_unit_edit"] + ) + respondents_section = _build_respondents_section( + respondents, + case["id"], + collection_exercises, + ru, + survey, + unused_iac, + permissions, + ) + + return {"collection_exercise_section": collection_exercise_section, "respondents_section": respondents_section} + + +def _build_collection_exercise_section( + collection_exercises: list, sample_unit_ref: str, survey_short_name: str, reporting_unit_permission: bool +) -> list: + table = [ + { + "status_class": (CE_STATUS_CLASS.get(ce["responseStatus"], "ons-status--error")), + "hyperlink": url_for( + "case_bp.get_response_statuses", + ru_ref=sample_unit_ref, + survey=survey_short_name, + period=ce["exerciseRef"], + ), + "hyperlink_text": "Change" if reporting_unit_permission else "View", + "period": ce["exerciseRef"], + "reporting_unit_name": ce["companyName"], + "trading_as": ce["tradingAs"], + "region": ce["companyRegion"], + "response_status": ce["responseStatus"], + "status": _build_ce_status( + sample_unit_ref, + survey_short_name, + ce["exerciseRef"], + ce["responseStatus"], + reporting_unit_permission, + ), + } + for ce in collection_exercises + ] + return table + + +def _build_ce_status(ru_ref: str, survey: str, period: str, response_status: str, ru_permission: bool) -> dict: + ce_status = { + "hyperlink": url_for( + "case_bp.get_response_statuses", + ru_ref=ru_ref, + survey=survey, + period=period, + ), + "hyperlink_text": "Change" if ru_permission else "View", + "status_class": ( + CE_STATUS_CLASS[response_status] if response_status in CE_STATUS_CLASS.keys() else "ons-status--error" + ), + "response_status": response_status, + } + return ce_status + + +def _build_respondents_section( + respondents: list, + case_id: str, + collection_exercises: list, + ru: dict, + survey: dict, + unused_iac: str, + permissions: dict, +) -> list: + table = [] + for respondent in respondents: + row = {} + if permissions["reporting_unit_edit"]: + if unused_iac: + row["enrolment_code"] = unused_iac + else: + row["enrolment_code_hyperlink"] = url_for( + "reporting_unit_bp.generate_new_enrolment_code", + case_id=case_id, + collection_exercise_id=collection_exercises[0]["id"], + ru_name=ru["name"], + ru_ref=ru["sampleUnitRef"], + trading_as=collection_exercises[0]["tradingAs"], + survey_ref=survey["surveyRef"], + survey_name=survey["shortName"], + ) + row["enrolment_code_hyperlink_text"] = "Generate new enrollment code" + else: + row["enrolment_code"] = "" + row["contact_details"] = { + "name": f"{respondent['firstName']} {respondent['lastName']}", + "email": respondent["emailAddress"], + "tel": respondent["telephone"], + } + row["account_status_class"] = ( + "ons-status--error" if respondent["status"] == "SUSPENDED" else "ons-status--success" + ) + row["account_status"] = respondent["status"].capitalize() + row["enrolment_status"] = respondent["enrolmentStatus"].capitalize() + ( + row["enrolment_status_hyperlink"], + row["enrolment_status_hyperlink_text"], + row["enrolment_status_class"], + ) = _build_enrollment_status_hyperlink( + respondent, + ru, + collection_exercises[0]["tradingAs"], + survey["id"], + survey["surveyRef"], + permissions["reporting_unit_edit"], + ) + if permissions["messages_edit"]: + row["message"] = [ + {"name": "ru_ref", "value": ru["sampleUnitRef"]}, + {"name": "business_id", "value": ru["id"]}, + {"name": "business", "value": ru["name"]}, + {"name": "survey", "value": survey["shortName"]}, + {"name": "survey_id", "value": survey["id"]}, + {"name": "msg_to_name", "value": row["contact_details"]["name"]}, + {"name": "msg_to", "value": respondent["id"]}, + ] + table.append(row) + + return table + + +def _build_enrollment_status_hyperlink( + respondent: dict, + ru: dict, + trading_as: str, + survey_id: str, + survey_short_name: str, + ru_permission: bool, +) -> tuple[str | None, str, str]: + if respondent["enrolmentStatus"] == ENROLMENT_ENABLED: + status_class = "ons-status--success" + hyperlink = ( + url_for( + "reporting_unit_bp.confirm_change_enrolment_status", + ru_ref=ru["sampleUnitRef"], + ru_name=ru["name"], + survey_id=survey_id, + survey_name=survey_short_name, + respondent_id=respondent["id"], + respondent_first_name=respondent["firstName"], + respondent_last_name=respondent["lastName"], + business_id=ru["id"], + trading_as=trading_as, + change_flag="DISABLED", + tab="reporting_units", + ) + if ru_permission + else None + ) + hyperlink_text = "Disable" + elif respondent["enrolmentStatus"] == ENROLMENT_PENDING: + status_class = "ons-status--info" + hyperlink = ( + url_for("reporting_unit_bp.view_resend_verification", ru_ref=ru["sampleUnitRef"], party_id=respondent["id"]) + if ru_permission + else None + ) + hyperlink_text = "Re-send verification email" + else: + status_class = "ons-status--dead" + hyperlink = ( + url_for( + "reporting_unit_bp.confirm_change_enrolment_status", + ru_ref=ru["sampleUnitRef"], + ru_name=ru["name"], + survey_id=survey_id, + survey_name=survey_short_name, + respondent_id=respondent["id"], + respondent_first_name=respondent["firstName"], + respondent_last_name=respondent["lastName"], + business_id=ru["id"], + trading_as=trading_as, + change_flag="ENABLED", + tab="reporting_units", + ) + if ru_permission + else None + ) + hyperlink_text = "Re-enable" + + return hyperlink, hyperlink_text, status_class diff --git a/response_operations_ui/templates/reporting-unit-survey.html b/response_operations_ui/templates/reporting-unit-survey.html index c792cea7e..0c9181f78 100644 --- a/response_operations_ui/templates/reporting-unit-survey.html +++ b/response_operations_ui/templates/reporting-unit-survey.html @@ -51,55 +51,16 @@

Collection exercises

] } %} - + {% set collectionExerciseTableDataRows = [] %} - - {% for ce in collection_exercises %} - {% if ce.responseStatus == 'Not started' %} - {% set status_class = 'ons-status--info' %} - {% elif ce.responseStatus == 'In progress' %} - {% set status_class = 'ons-status--pending' %} - {% elif ce.responseStatus == 'Completed' or ce.responseStatus == 'Completed by phone' %} - {% set status_class = 'ons-status--success' %} - {% elif ce.responseStatus == 'No longer required' %} - {% set status_class = 'ons-status--dead' %} - {% else %} - {% set status_class = 'ons-status--error' %} - {% endif %} - - {% if ce.responseStatus in ['Not started', 'In progress'] and isReportingUnitPermission %} - {% set survey_link = '  Change' %} - {% elif ce.responseStatus in ['Completed', 'Completed by phone', 'No longer required'] and isReportingUnitPermission %} - {% set survey_link = '  View' %} - {% else %} - {% set survey_link = '' %} - {% endif %} - {% do collectionExerciseTableDataRows.append( - { - "tds": [ - { - "value": ce.exerciseRef, - "data": "Period" - }, - { - "value": ce.companyName, - "data": "Reporting unit name" - }, - { - "value": ce.tradingAs, - "data": "Trading as" - }, - { - "value": ce.companyRegion, - "data": "Region" - }, - { - "value": '' + ce.responseStatus + '' + survey_link, - "data": "Status" - }, - ] - } - ) %} + {% for ce in context["collection_exercise_section"] %} + {% set ceTds = [{"value": ce.period, "data": "Period"}, + {"value": ce.reporting_unit_name, "data": "Reporting unit name"}, + {"value": ce.trading_as, "data": "Trading as"}, + {"value": ce.region, "data": "Region"}, + {"value": '' + ce.response_status + '' + '  '+ ce.hyperlink_text +'', "data": "Status"},] + %} + {% do collectionExerciseTableDataRows.append({"tds": ceTds}) %} {% endfor %} {% do collectionExerciseTableData | setAttribute("trs", collectionExerciseTableDataRows) %} @@ -115,14 +76,10 @@

Respondents

{{ iac }} {% else %} - Generate new enrolment code {% endif %} {% endif %} - {% set tblHeaders = [ { @@ -155,72 +112,60 @@

Respondents

{% set respondentTableDataRows = [] %} - {% for respondent in respondents %} - {% if respondent.status == 'SUSPENDED' %} - {% set account_status_class = 'ons-status--error' %} + {% for respondent in context["respondents_section"] %} + + {% set contactDetailsCell = { + "value": '
+
+ Name: +
+
+ ' + respondent.contact_details["name"] + ' +
+
+ Email: +
+
+ ' + respondent.contact_details["email"] + ' +
+
+ Tel: +
+
+ ' + respondent.contact_details["tel"] + ' +
+
', + "data": "Contact details", + "name": "tbl-respondents-contact-details" + } %} + + {% if respondent.enrolment_status_hyperlink %} + {% set enrolment_status_hyperlink = '' + respondent.enrolment_status_hyperlink_text + '' %} {% else %} - {% set account_status_class = 'ons-status--success' %} + {% set enrolment_status_hyperlink = '' %} {% endif %} - - {% if respondent.enrolmentStatus == 'ENABLED' %} - {% set enrolment_status_class = 'ons-status--success' %} - {% set change_status_link = 'Disable' %} - {% elif respondent.enrolmentStatus == 'PENDING' %} - {% set enrolment_status_class = 'ons-status--info' %} - {% set change_status_link = 'Re-send verification email' %} - {% else %} - {% set enrolment_status_class = 'ons-status--dead' %} - {% set change_status_link = 'Re-enable' %} - {% endif %} - {% if not isReportingUnitPermission %} - {% set change_status_link = '' %} - {% endif %} - - {% set tableColumns = - [ - { - "value": '
-
- Name: -
-
- ' + respondent.firstName + ' ' + respondent.lastName + ' -
-
- Email: -
-
- ' + respondent.emailAddress + ' -
-
- Tel: -
-
- ' + respondent.telephone + ' -
-
', - "data": "Contact details", - "name": "tbl-respondents-contact-details" - }, - { - "value": '' + respondent.status|title + '', - "data": "Account status", - "name": "tbl-respondents-account-status" - }, - { - "value": '' + respondent.enrolmentStatus|title + '
' + change_status_link, - "data": "Enrolment status", - "name": "tbl-respondents-enrolment-status" - } - ] - %} - - {% if isMessageEditPermission %} - + + {% set tableColumns = + [ + contactDetailsCell, + { + "value": '' + respondent.account_status + '', + "data": "Account status", + "name": "tbl-respondents-account-status" + }, + { + "value": '' + respondent.enrolment_status + '
' + enrolment_status_hyperlink, + "data": "Enrolment status", + "name": "tbl-respondents-enrolment-status" + } + ] + %} + + {% if isMessageEditPermission %} + + {% set formField = respondent["message"] %} + {% do formField.append({"name": "csrf_token", "value": csrf_token()}) %} + {% set formData = { "action": url_for('messages_bp.create_message'), "button": { @@ -230,47 +175,16 @@

Respondents

"value": 'create-message-view', "name": 'create-message' }, - "hiddenFormField": [ - { - "name": "ru_ref", - "value": ru.sampleUnitRef - }, - { - "name": "business_id", - "value": ru.id - }, - { - "name": "business", - "value": ru.name - }, - { - "name": "survey", - "value": survey.shortName - }, - { - "name": "survey_id", - "value": survey.id - }, - { - "name": "msg_to_name", - "value": respondent.firstName + ' ' + respondent.lastName - }, - { - "name": "msg_to", - "value": respondent.id - }, - { - "name": "csrf_token", - "value": csrf_token() - } - ] + "hiddenFormField": formField } %} + {% do tableColumns.append( { "form": formData } ) %} - {% endif %} + + {% endif %} {% do respondentTableDataRows.append( { @@ -280,6 +194,7 @@

Respondents

{% endfor %} {% do respondentTableData | setAttribute("trs", respondentTableDataRows) %} + {{ onsTable(respondentTableData) }} diff --git a/response_operations_ui/templates/response-status.html b/response_operations_ui/templates/response-status.html index f04a3cbd1..f396aeec8 100755 --- a/response_operations_ui/templates/response-status.html +++ b/response_operations_ui/templates/response-status.html @@ -10,11 +10,7 @@
- {% if is_case_complete %} -

Response status

- {% else %} -

Change response status

- {% endif %} +

Change response status

{{ onsMetadata({ "termCol": "3", @@ -92,30 +88,15 @@

Change response status

] }) }} - {% if is_case_complete %} - Close - {% else %} -
+ {% if context['change_response_status'] %} + {% set radioComponent = { "legend": "Change response status", "name": "event" } %} - {% set radios = [] %} - {% for event, status in allowed_transitions_for_case.items() %} - {% do radios.append( - { - "id": 'state-' ~ loop.index, - "label": { - "text": status - }, - "value": event - } - ) %} - {% endfor %} - - {% do radioComponent | setAttribute("radios", radios) %} + {% do radioComponent | setAttribute("radios", context["change_response_status"]["radios"]) %} {{ onsRadios(radioComponent) }} @@ -128,7 +109,7 @@

Change response status

}) }}

- Cancel + Cancel

{% endif %} diff --git a/response_operations_ui/views/case.py b/response_operations_ui/views/case.py index fcea91573..1dec2aa7f 100644 --- a/response_operations_ui/views/case.py +++ b/response_operations_ui/views/case.py @@ -10,6 +10,7 @@ format_short_name, map_ce_response_status, ) +from response_operations_ui.contexts.case import build_response_status_context from response_operations_ui.controllers import ( case_controller, collection_exercise_controllers, @@ -23,6 +24,7 @@ from response_operations_ui.controllers.party_controller import ( get_respondent_by_party_id, ) +from response_operations_ui.controllers.uaa_controller import user_has_permission from response_operations_ui.forms import ChangeGroupStatusForm ALLOWED_TRANSITIONS = ["COMPLETEDBYPHONE", "NOLONGERREQUIRED", "NOTSTARTED"] @@ -74,6 +76,17 @@ def get_response_statuses(ru_ref, error=None): if status in allowed_transitions_filtered } + has_reporting_unit_permission = user_has_permission("reportingunits.edit") + context = build_response_status_context( + ru_ref, + format_short_name(survey["shortName"]), + case_group["id"], + period, + allowed_transitions_for_case, + survey["id"], + has_reporting_unit_permission, + ) + return render_template( "response-status.html", ru_ref=ru_ref, @@ -90,6 +103,7 @@ def get_response_statuses(ru_ref, error=None): is_case_complete=is_case_complete, completed_timestamp=completed_timestamp, completed_respondent=completed_respondent, + context=context, ) diff --git a/response_operations_ui/views/reporting_units.py b/response_operations_ui/views/reporting_units.py index e5e642ff5..f3860227e 100644 --- a/response_operations_ui/views/reporting_units.py +++ b/response_operations_ui/views/reporting_units.py @@ -10,6 +10,9 @@ from response_operations_ui.common.mappers import map_ce_response_status, map_region from response_operations_ui.common.pagination_processor import pagination_processor +from response_operations_ui.contexts.reporting_units import ( + build_reporting_units_context, +) from response_operations_ui.controllers import ( case_controller, iac_controller, @@ -22,6 +25,7 @@ get_collection_exercise_by_id, ) from response_operations_ui.controllers.survey_controllers import get_survey_by_id +from response_operations_ui.controllers.uaa_controller import user_has_permission from response_operations_ui.exceptions.exceptions import ApiError from response_operations_ui.forms import EditContactDetailsForm, RuSearchForm @@ -211,6 +215,20 @@ def view_reporting_unit_survey(ru_ref, survey_id): logger.info("Successfully gathered data to view reporting unit survey data", ru_ref=ru_ref, survey_id=survey_id) + permissions = { + "reporting_unit_edit": user_has_permission("reportingunits.edit"), + "messages_edit": user_has_permission("messages.edit"), + } + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + unused_iac, + permissions, + ) + return render_template( "reporting-unit-survey.html", ru=reporting_unit, @@ -219,6 +237,7 @@ def view_reporting_unit_survey(ru_ref, survey_id): collection_exercises=collection_exercises_with_details, iac=unused_iac, case=case, + context=context, ) diff --git a/tests/context/conftest.py b/tests/context/conftest.py index a1e9f4e2b..967fda9c5 100644 --- a/tests/context/conftest.py +++ b/tests/context/conftest.py @@ -242,3 +242,328 @@ def ce_details_dynamic_event_deleted(ce_details_dynamic_event): ce_details_dynamic_event_deleted = ce_details_dynamic_event.copy() del ce_details_dynamic_event_deleted["events"]["reminder2"] return ce_details_dynamic_event_deleted + + +@pytest.fixture() +def collection_exercises_with_details(ce_details): + collection_exercises_with_details = ce_details["collection_exercise"].copy() + collection_exercises_with_details["responseStatus"] = "Not started" + collection_exercises_with_details["companyName"] = "RUNAME1_COMPANY1 RUNNAME2_COMPANY1 " + collection_exercises_with_details["companyRegion"] = "GB" + collection_exercises_with_details["tradingAs"] = "TOTAL UK ACTIVITY " + return [collection_exercises_with_details] + + +@pytest.fixture +def in_progress_collection_exercise_with_details(collection_exercises_with_details): + in_progress_collection_exercise = collection_exercises_with_details.copy() + in_progress_collection_exercise[0]["responseStatus"] = "In progress" + return in_progress_collection_exercise + + +@pytest.fixture +def completed_collection_exercise_with_details(collection_exercises_with_details): + completed_progress_collection_exercise = collection_exercises_with_details.copy() + completed_progress_collection_exercise[0]["responseStatus"] = "Completed" + return completed_progress_collection_exercise + + +@pytest.fixture +def no_longer_required_collection_exercise_with_details(collection_exercises_with_details): + no_longer_required_collection_exercise = collection_exercises_with_details.copy() + no_longer_required_collection_exercise[0]["responseStatus"] = "No longer required" + return no_longer_required_collection_exercise + + +@pytest.fixture +def error_collection_exercise_with_details(collection_exercises_with_details): + error_collection_exercise_with_details = collection_exercises_with_details.copy() + error_collection_exercise_with_details[0]["responseStatus"] = "Error" + return error_collection_exercise_with_details + + +@pytest.fixture +def multiple_collection_exercises_with_details(collection_exercises_with_details): + multiple_collection_exercises_with_details = collection_exercises_with_details.copy() + multiple_collection_exercises_with_details.append(collection_exercises_with_details[0].copy()) + multiple_collection_exercises_with_details[1]["responseStatus"] = "In progress" + return multiple_collection_exercises_with_details + + +@pytest.fixture() +def reporting_unit(): + return { + "associations": [ + { + "businessRespondentStatus": "ACTIVE", + "enrolments": [{"enrolmentStatus": "ENABLED", "surveyId": "02b9c366-7397-42f7-942a-76dc5876d86d"}], + "partyId": "bf19a18f-fe15-4005-b698-fdd36f35f940", + } + ], + "id": "a5348157-feb4-4bad-9614-fc76e2bfea94", + "name": "RUNAME1_COMPANY1 RUNNAME2_COMPANY1", + "sampleSummaryId": "d646f19b-827f-4934-a71a-43ba458045b6", + "sampleUnitRef": "49900000001", + "sampleUnitType": "B", + "trading_as": "TOTAL UK ACTIVITY", + } + + +@pytest.fixture +def multiple_reporting_units(reporting_unit): + multiple_reporting_units = reporting_unit.copy() + multiple_reporting_units["associations"].append( + { + "businessRespondentStatus": "ACTIVE", + "enrolments": [{"enrolmentStatus": "ENABLED", "surveyId": "02b9c366-7397-42f7-942a-76dc5876d86d"}], + "partyId": "985bf97e-4f03-4898-92ef-dd7aac23ab08", + }, + ) + return multiple_reporting_units + + +@pytest.fixture() +def survey_details(ce_details): + survey_details = ce_details["survey"].copy() + return survey_details + + +@pytest.fixture() +def survey_respondents(): + return [ + { + "associations": [ + { + "businessRespondentStatus": "ACTIVE", + "enrolments": [{"enrolmentStatus": "ENABLED", "surveyId": "02b9c366-7397-42f7-942a-76dc5876d86d"}], + "partyId": "a5348157-feb4-4bad-9614-fc76e2bfea94", + "sampleUnitRef": "49900000001", + } + ], + "emailAddress": "example@example.com", + "firstName": "john", + "id": "bf19a18f-fe15-4005-b698-fdd36f35f940", + "lastName": "doe", + "sampleUnitType": "BI", + "status": "ACTIVE", + "telephone": "07772257772", + "enrolmentStatus": "ENABLED", + } + ] + + +@pytest.fixture +def multiple_survey_respondents(survey_respondents): + multiple_survey_respondents = survey_respondents.copy() + multiple_survey_respondents.append(survey_respondents[0].copy()) + return multiple_survey_respondents + + +@pytest.fixture +def suspended_survey_respondents(survey_respondents): + suspended_survey_respondents = survey_respondents.copy() + suspended_survey_respondents[0]["status"] = "SUSPENDED" + return suspended_survey_respondents + + +@pytest.fixture +def pending_enrolment_survey_respondents(survey_respondents): + pending_enrolment_survey_respondents = survey_respondents.copy() + pending_enrolment_survey_respondents[0]["enrolmentStatus"] = "PENDING" + return pending_enrolment_survey_respondents + + +@pytest.fixture +def disabled_enrolment_survey_respondents(survey_respondents): + disabled_enrolment_survey_respondents = survey_respondents.copy() + disabled_enrolment_survey_respondents[0]["enrolmentStatus"] = "DISABLED" + return disabled_enrolment_survey_respondents + + +@pytest.fixture() +def case(): + return { + "state": "ACTIONABLE", + "id": "f4056be6-2581-4308-b7cd-88118325e81d", + "actionPlanId": None, + "activeEnrolment": True, + "collectionInstrumentId": "e726f50c-504c-4958-be96-9d77520746b9", + "partyId": "a5348157-feb4-4bad-9614-fc76e2bfea94", + "sampleUnitId": "d8579750-8817-4a58-8fa5-867f1447e1cc", + "iac": "t7jk7l29hymx", + "caseRef": "1000000000000003", + "createdBy": "SYSTEM", + "sampleUnitType": "B", + "createdDateTime": "2024-02-08T11:39:58.199Z", + "caseGroup": { + "collectionExerciseId": "1012f36c-b352-431c-b0c9-e7f435cbdd0c", + "id": "39c7e488-3f06-4ea9-82fb-3c619f362cb6", + "partyId": "a5348157-feb4-4bad-9614-fc76e2bfea94", + "sampleUnitRef": "49900000001", + "sampleUnitType": "B", + "caseGroupStatus": "NOTSTARTED", + "surveyId": "02b9c366-7397-42f7-942a-76dc5876d86d", + }, + "caseEvents": None, + } + + +@pytest.fixture() +def unused_iac(): + return "p79j76f4pwfg" + + +@pytest.fixture +def expected_ru_context_with_all_permissions(): + return { + "collection_exercise_section": [ + { + "hyperlink": "/case/49900000001/response-status?survey=MWSS&period=021123", + "hyperlink_text": "Change", + "period": "021123", + "region": "GB", + "reporting_unit_name": "RUNAME1_COMPANY1 " "RUNNAME2_COMPANY1 ", + "response_status": "Not started", + "status": { + "hyperlink": "/case/49900000001/response-status?survey=MWSS&period=021123", + "hyperlink_text": "Change", + "response_status": "Not started", + "status_class": "ons-status--info", + }, + "status_class": "ons-status--info", + "trading_as": "TOTAL UK ACTIVITY ", + } + ], + "respondents_section": [ + { + "account_status": "Active", + "account_status_class": "ons-status--success", + "contact_details": {"email": "example@example.com", "name": "john doe", "tel": "07772257772"}, + "enrolment_code_hyperlink": "/reporting-units/49900000001/new_enrolment_code?" + + "case_id=f4056be6-2581-4308-b7cd-88118325e81d&" + + "collection_exercise_id=7702d7fd-f998-499d-a972-e2906b19e6cf&" + + "ru_name=RUNAME1_COMPANY1+RUNNAME2_COMPANY1&" + + "trading_as=TOTAL+UK+ACTIVITY++&survey_ref=134&survey_name=MWSS", + "enrolment_code_hyperlink_text": "Generate new " "enrollment code", + "enrolment_status": "Enabled", + "enrolment_status_class": "ons-status--success", + "enrolment_status_hyperlink": "/reporting-units/49900000001/change-enrolment-status?" + + "ru_name=RUNAME1_COMPANY1+RUNNAME2_COMPANY1&" + + "survey_id=c23bb1c1-5202-43bb-8357-7a07c844308f&survey_name=134&" + + "respondent_id=bf19a18f-fe15-4005-b698-fdd36f35f940&" + + "respondent_first_name=john&respondent_last_name=doe&" + + "business_id=a5348157-feb4-4bad-9614-fc76e2bfea94&" + + "trading_as=TOTAL+UK+ACTIVITY++&" + + "change_flag=DISABLED&tab=reporting_units", + "enrolment_status_hyperlink_text": "Disable", + "message": [ + {"name": "ru_ref", "value": "49900000001"}, + {"name": "business_id", "value": "a5348157-feb4-4bad-9614-fc76e2bfea94"}, + {"name": "business", "value": "RUNAME1_COMPANY1 " "RUNNAME2_COMPANY1"}, + {"name": "survey", "value": "MWSS"}, + {"name": "survey_id", "value": "c23bb1c1-5202-43bb-8357-7a07c844308f"}, + {"name": "msg_to_name", "value": "john doe"}, + {"name": "msg_to", "value": "bf19a18f-fe15-4005-b698-fdd36f35f940"}, + ], + } + ], + } + + +@pytest.fixture +def expected_ru_context_with_multiple_ces_and_respondents(expected_ru_context_with_all_permissions): + expected_ru_context_with_multiple_ces_and_respondents = expected_ru_context_with_all_permissions.copy() + expected_ru_context_with_multiple_ces_and_respondents["collection_exercise_section"].append( + { + "hyperlink": "/case/49900000001/response-status?survey=MWSS&period=021123", + "hyperlink_text": "Change", + "period": "021123", + "region": "GB", + "reporting_unit_name": "RUNAME1_COMPANY1 " "RUNNAME2_COMPANY1 ", + "response_status": "In progress", + "status": { + "hyperlink": "/case/49900000001/response-status?survey=MWSS&period=021123", + "hyperlink_text": "Change", + "response_status": "In progress", + "status_class": "ons-status--pending", + }, + "status_class": "ons-status--pending", + "trading_as": "TOTAL UK ACTIVITY ", + } + ) + expected_ru_context_with_multiple_ces_and_respondents["respondents_section"].append( + expected_ru_context_with_all_permissions["respondents_section"][0] + ) + expected_ru_context_with_multiple_ces_and_respondents["respondents_section"][0].pop("enrolment_code_hyperlink") + expected_ru_context_with_multiple_ces_and_respondents["respondents_section"][0].pop("enrolment_code_hyperlink_text") + expected_ru_context_with_multiple_ces_and_respondents["respondents_section"][0]["enrolment_code"] = "99yk5r3yjycn" + return expected_ru_context_with_multiple_ces_and_respondents + + +@pytest.fixture +def expected_response_status_context_for_complete_case_with_all_permissions(): + return { + "change_response_status": { + "cancel_link": "/reporting-units/49900000001/surveys/02b9c366-7397-42f7-942a-76dc5876d86d", + "radios": [{"id": "state-1", "label": {"text": "Not started"}, "value": "COMPLETED_TO_NOTSTARTED"}], + "url": "/case/49900000001/response-status?survey=QBS&" + + "case_group_id=6fef0397-f07b-4d65-8988-931cec23057f&period=1912", + } + } + + +@pytest.fixture +def expected_response_status_context_with_no_permissions(): + return {"change_response_status": {}} + + +@pytest.fixture +def expected_response_status_context_transitions_for_incomplete_case( + expected_response_status_context_for_complete_case_with_all_permissions, +): + expected_case_context_transitions_from_not_started = ( + expected_response_status_context_for_complete_case_with_all_permissions.copy() + ) + expected_case_context_transitions_from_not_started["change_response_status"]["radios"] = [ + {"id": "state-1", "label": {"text": "Completed by phone"}, "value": "COMPLETED_BY_PHONE"}, + {"id": "state-2", "label": {"text": "No longer required"}, "value": "NO_LONGER_REQUIRED"}, + ] + return expected_case_context_transitions_from_not_started + + +@pytest.fixture +def transitions_for_complete_case(): + return {"COMPLETED_TO_NOTSTARTED": "Not started"} + + +@pytest.fixture +def transitions_for_incomplete_case(): + return { + "COMPLETED_BY_PHONE": "Completed by phone", + "NO_LONGER_REQUIRED": "No longer required", + } + + +@pytest.fixture +def ru_ref(): + return "49900000001" + + +@pytest.fixture +def survey_short_name(): + return "QBS" + + +@pytest.fixture +def case_group_id(): + return "6fef0397-f07b-4d65-8988-931cec23057f" + + +@pytest.fixture +def ce_period(): + return "1912" + + +@pytest.fixture +def survey_id(): + return "02b9c366-7397-42f7-942a-76dc5876d86d" diff --git a/tests/context/test_case_context.py b/tests/context/test_case_context.py new file mode 100644 index 000000000..e94ffb8ca --- /dev/null +++ b/tests/context/test_case_context.py @@ -0,0 +1,189 @@ +from response_operations_ui.contexts.case import build_response_status_context + + +def test_response_status_context_with_permissions( + app, + transitions_for_complete_case, + expected_response_status_context_for_complete_case_with_all_permissions, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_complete_case, + survey_id, + True, + ) + assert context == expected_response_status_context_for_complete_case_with_all_permissions + + +def test_response_status_context_without_permissions( + app, + transitions_for_complete_case, + expected_response_status_context_with_no_permissions, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_complete_case, + survey_id, + False, + ) + assert context == expected_response_status_context_with_no_permissions + + +def test_transitions_from_not_started( + app, + transitions_for_incomplete_case, + expected_response_status_context_transitions_for_incomplete_case, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_incomplete_case, + survey_id, + True, + ) + radios = get_response_status_context(context, "change_response_status", "radios") + + assert ( + expected_response_status_context_transitions_for_incomplete_case["change_response_status"]["radios"] == radios + ) + + +def test_transitions_from_completed_by_phone( + app, + transitions_for_complete_case, + expected_response_status_context_for_complete_case_with_all_permissions, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_complete_case, + survey_id, + True, + ) + radios = get_response_status_context(context, "change_response_status", "radios") + + assert ( + expected_response_status_context_for_complete_case_with_all_permissions["change_response_status"]["radios"] + == radios + ) + + +def test_transitions_from_no_longer_required( + app, + transitions_for_complete_case, + expected_response_status_context_for_complete_case_with_all_permissions, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_complete_case, + survey_id, + True, + ) + radios = get_response_status_context(context, "change_response_status", "radios") + + assert ( + expected_response_status_context_for_complete_case_with_all_permissions["change_response_status"]["radios"] + == radios + ) + + +def test_transitions_from_in_progress( + app, + transitions_for_incomplete_case, + expected_response_status_context_transitions_for_incomplete_case, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_incomplete_case, + survey_id, + True, + ) + radios = get_response_status_context(context, "change_response_status", "radios") + + assert ( + expected_response_status_context_transitions_for_incomplete_case["change_response_status"]["radios"] == radios + ) + + +def test_transitions_from_complete( + app, + transitions_for_complete_case, + expected_response_status_context_for_complete_case_with_all_permissions, + ru_ref, + survey_short_name, + case_group_id, + ce_period, + survey_id, +): + with app.test_request_context(): + context = build_response_status_context( + ru_ref, + survey_short_name, + case_group_id, + ce_period, + transitions_for_complete_case, + survey_id, + True, + ) + radios = get_response_status_context(context, "change_response_status", "radios") + + assert ( + expected_response_status_context_for_complete_case_with_all_permissions["change_response_status"]["radios"] + == radios + ) + + +def get_response_status_context(context, section, element): + return context[section][element] diff --git a/tests/context/test_reporting_units_context.py b/tests/context/test_reporting_units_context.py new file mode 100644 index 000000000..b88345b80 --- /dev/null +++ b/tests/context/test_reporting_units_context.py @@ -0,0 +1,295 @@ +from response_operations_ui.contexts.reporting_units import ( + build_reporting_units_context, +) + + +def test_has_both_edit_permission( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + hyperlink = get_ru_context(context, "collection_exercise_section", 0, "status")["hyperlink_text"] + message = get_ru_context(context, "respondents_section", 0, "message") + + assert context == expected_ru_context_with_all_permissions + assert "Change" in hyperlink + assert message[0]["value"] == "49900000001" + + +def test_no_reporting_units_edit_permission( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": False, "messages_edit": True}, + ) + hyperlink = get_ru_context(context, "collection_exercise_section", 0, "status")["hyperlink_text"] + + assert "Change" not in hyperlink + assert "View" in hyperlink + + +def test_no_messages_edit_permission( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": False}, + ) + + assert "message" not in context["respondents_section"][0].keys() + + +def test_collection_exercise_in_progress( + app, in_progress_collection_exercise_with_details, reporting_unit, survey_details, survey_respondents, case +): + with app.test_request_context(): + context = build_reporting_units_context( + in_progress_collection_exercise_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + collection_exercise_status = get_ru_context(context, "collection_exercise_section", 0, "status_class") + + assert "ons-status--pending" in collection_exercise_status + + +def test_collection_exercise_completed( + app, completed_collection_exercise_with_details, reporting_unit, survey_details, survey_respondents, case +): + with app.test_request_context(): + context = build_reporting_units_context( + completed_collection_exercise_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + collection_exercise_status = get_ru_context(context, "collection_exercise_section", 0, "status_class") + + assert "ons-status--success" in collection_exercise_status + + +def test_collection_exercise_no_longer_required( + app, no_longer_required_collection_exercise_with_details, reporting_unit, survey_details, survey_respondents, case +): + with app.test_request_context(): + context = build_reporting_units_context( + no_longer_required_collection_exercise_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + collection_exercise_status = get_ru_context(context, "collection_exercise_section", 0, "status_class") + + assert "ons-status--dead" in collection_exercise_status + + +def test_collection_exercise_error( + app, error_collection_exercise_with_details, reporting_unit, survey_details, survey_respondents, case +): + with app.test_request_context(): + context = build_reporting_units_context( + error_collection_exercise_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + collection_exercise_status = get_ru_context(context, "collection_exercise_section", 0, "status_class") + + assert "ons-status--error" in collection_exercise_status + + +def test_respondent_active( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + respondent_status = get_ru_context(context, "respondents_section", 0, "account_status_class") + + assert "ons-status--success" in respondent_status + + +def test_respondent_suspended( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + suspended_survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + suspended_survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + respondent_status = get_ru_context(context, "respondents_section", 0, "account_status_class") + + assert "ons-status--error" in respondent_status + + +def test_respondent_enrolment_enabled( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + enrolment_status = get_ru_context(context, "respondents_section", 0, "enrolment_status_class") + + assert "ons-status--success" in enrolment_status + + +def test_respondent_enrolment_pending( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + pending_enrolment_survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + pending_enrolment_survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + enrolment_status = get_ru_context(context, "respondents_section", 0, "enrolment_status_class") + + assert "ons-status--info" in enrolment_status + + +def test_respondent_enrolment_disabled( + app, + collection_exercises_with_details, + reporting_unit, + survey_details, + disabled_enrolment_survey_respondents, + case, + expected_ru_context_with_all_permissions, +): + with app.test_request_context(): + context = build_reporting_units_context( + collection_exercises_with_details, + reporting_unit, + survey_details, + disabled_enrolment_survey_respondents, + case, + "", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + enrolment_status = get_ru_context(context, "respondents_section", 0, "enrolment_status_class") + + assert "ons-status--dead" in enrolment_status + + +def test_multiple_collection_exercises_and_respondents( + app, + multiple_collection_exercises_with_details, + multiple_reporting_units, + survey_details, + multiple_survey_respondents, + case, + expected_ru_context_with_multiple_ces_and_respondents, +): + with app.test_request_context(): + context = build_reporting_units_context( + multiple_collection_exercises_with_details, + multiple_reporting_units, + survey_details, + multiple_survey_respondents, + case, + "99yk5r3yjycn", + {"reporting_unit_edit": True, "messages_edit": True}, + ) + + assert context == expected_ru_context_with_multiple_ces_and_respondents + + +def get_ru_context(context, section, index, cell): + return context[section][index][cell] diff --git a/tests/views/test_change_response_status.py b/tests/views/test_change_response_status.py index e31989849..e06b3e510 100644 --- a/tests/views/test_change_response_status.py +++ b/tests/views/test_change_response_status.py @@ -3,10 +3,12 @@ from unittest import TestCase import fakeredis +import jwt import requests_mock from config import TestingConfig from response_operations_ui import create_app +from tests.views.test_sign_in import url_sign_in_data short_name = "BLOCKS" survey_id = "cb0711c3-0ac8-41d3-ae0e-567e5ea1ef87" @@ -32,8 +34,9 @@ url_get_case_by_case_group_id = f"{TestingConfig.CASE_URL}/cases/casegroupid/{case_group_id}" url_get_case_events = f"{TestingConfig.CASE_URL}/cases/{case_id}/events" get_respondent_by_id_url = f"{TestingConfig.PARTY_URL}/party-api/v1/respondents/id/{party_id}" -project_root = os.path.dirname(os.path.dirname(__file__)) +url_permission_url = f"{TestingConfig.UAA_SERVICE_URL}/Users/test-id" +project_root = os.path.dirname(os.path.dirname(__file__)) with open(f"{project_root}/test_data/survey/single_survey.json") as fp: survey = json.load(fp) @@ -60,12 +63,24 @@ with open(f"{project_root}/test_data/case/case_groups_list_no_longer_required.json") as fp: case_groups_no_longer_required = json.load(fp) +user_permission_reporting_unit_edit_json = { + "id": "5902656c-c41c-4b38-a294-0359e6aabe59", + "groups": [{"value": "f385f89e-928f-4a0f-96a0-4c48d9007cc3", "display": "reportingunits.edit", "type": "DIRECT"}], +} + +user_permission_admin_json = { + "id": "5902656c-c41c-4b38-a294-0359e6aabe59", + "groups": [{"value": "f385f89e-928f-4a0f-96a0-4c48d9007cc3", "display": "users.admin", "type": "DIRECT"}], +} + class TestChangeResponseStatus(TestCase): def setUp(self): self.app = create_app("TestingConfig") + payload = {"user_id": "test-id", "aud": "response_operations"} self.client = self.app.test_client() self.setup_data() + self.access_token = jwt.encode(payload, TestingConfig.UAA_PRIVATE_KEY, algorithm="RS256") self.app.config["SESSION_REDIS"] = fakeredis.FakeStrictRedis( host=self.app.config["REDIS_HOST"], port=self.app.config["FAKE_REDIS_PORT"], db=self.app.config["REDIS_DB"] ) @@ -83,7 +98,10 @@ def setup_data(self): @requests_mock.mock() def test_get_available_status(self, mock_request): + mock_request.post(url_sign_in_data, json={"access_token": self.access_token}, status_code=201) mock_request.get(url_get_survey_by_short_name, json=survey) + mock_request.get(url_permission_url, json=user_permission_reporting_unit_edit_json, status_code=200) + self.client.post("/sign-in", follow_redirects=True, data={"username": "user", "password": "pass"}) mock_request.get(url_get_collection_exercises_by_survey, json=collection_exercise_list) mock_request.get(url_get_business_by_ru_ref, json=business_reporting_unit) mock_request.get(url_get_available_case_group_statuses, json=self.statuses) @@ -300,13 +318,17 @@ def test_respondent_name_not_in_metadata_for_completed_case_event(self, mock_req @requests_mock.mock() def test_not_started_status_is_present_for_completed_by_phone(self, mock_request): + mock_request.post(url_sign_in_data, json={"access_token": self.access_token}, status_code=201) mock_request.get(url_get_survey_by_short_name, json=survey) + mock_request.get(url_permission_url, json=user_permission_reporting_unit_edit_json, status_code=200) + self.client.post("/sign-in", follow_redirects=True, data={"username": "user", "password": "pass"}) mock_request.get(url_get_collection_exercises_by_survey, json=collection_exercise_list) mock_request.get(url_get_business_by_ru_ref, json=business_reporting_unit) mock_request.get(url_get_available_case_group_statuses, json=self.statuses) mock_request.get(url_get_case_groups_by_business_party_id, json=case_groups_completed_by_phone) mock_request.get(url_get_case_events, json=case_events) mock_request.get(url_get_case_by_case_group_id, json=[case]) + mock_request.get(url_permission_url, json=user_permission_reporting_unit_edit_json, status_code=200) response = self.client.get(f"/case/{ru_ref}/response-status?survey={short_name}&period={period}") @@ -317,7 +339,10 @@ def test_not_started_status_is_present_for_completed_by_phone(self, mock_request @requests_mock.mock() def test_not_started_status_is_present_for_no_longer_required(self, mock_request): + mock_request.post(url_sign_in_data, json={"access_token": self.access_token}, status_code=201) mock_request.get(url_get_survey_by_short_name, json=survey) + mock_request.get(url_permission_url, json=user_permission_reporting_unit_edit_json, status_code=200) + self.client.post("/sign-in", follow_redirects=True, data={"username": "user", "password": "pass"}) mock_request.get(url_get_collection_exercises_by_survey, json=collection_exercise_list) mock_request.get(url_get_business_by_ru_ref, json=business_reporting_unit) mock_request.get(url_get_available_case_group_statuses, json=self.statuses) @@ -331,3 +356,24 @@ def test_not_started_status_is_present_for_no_longer_required(self, mock_request self.assertEqual(response.status_code, 200) self.assertIn(b"No longer required", data) self.assertIn(b"Not started", data) + + @requests_mock.mock() + def test_not_started_status_is_present_for_completed(self, mock_request): + mock_request.post(url_sign_in_data, json={"access_token": self.access_token}, status_code=201) + mock_request.get(url_get_survey_by_short_name, json=survey) + mock_request.get(url_permission_url, json=user_permission_reporting_unit_edit_json, status_code=200) + self.client.post("/sign-in", follow_redirects=True, data={"username": "user", "password": "pass"}) + mock_request.get(url_get_collection_exercises_by_survey, json=collection_exercise_list) + mock_request.get(url_get_business_by_ru_ref, json=business_reporting_unit) + mock_request.get(url_get_available_case_group_statuses, json=self.statuses) + mock_request.get(url_get_case_groups_by_business_party_id, json=case_groups_completed) + mock_request.get(url_get_case_by_case_group_id, json=[case]) + mock_request.get(url_get_case_events, json=case_events) + mock_request.get(get_respondent_by_id_url, json=respondent) + + response = self.client.get(f"/case/{ru_ref}/response-status?survey={short_name}&period={period}") + + data = response.data + self.assertEqual(response.status_code, 200) + self.assertIn(b"Completed", data) + self.assertIn(b"Not started", data)