diff --git a/app/main/views/agreement.py b/app/main/views/agreement.py index ce0851d30..91bc6f001 100644 --- a/app/main/views/agreement.py +++ b/app/main/views/agreement.py @@ -13,6 +13,12 @@ from app.utils import user_has_permissions @main.route('/services//agreement') @user_has_permissions('manage_service') def service_agreement(service_id): + if ( + current_service.organisation_type == 'nhs_gp' and not current_service.organisation + ): + return redirect( + url_for('main.add_organisation_from_gp_service', service_id=current_service.id) + ) if current_service.organisation.crown is None: return render_template('views/agreement/service-agreement-choose.html') if current_service.organisation.agreement_signed: diff --git a/app/main/views/organisations.py b/app/main/views/organisations.py index 6e94d3a0f..c9b790ed5 100644 --- a/app/main/views/organisations.py +++ b/app/main/views/organisations.py @@ -7,6 +7,7 @@ from werkzeug.exceptions import abort from app import ( current_organisation, + current_service, email_branding_client, letter_branding_client, org_invite_api_client, @@ -63,6 +64,36 @@ def add_organisation(): ) +@main.route('/services//add-gp-organisation', methods=['GET', 'POST']) +@user_has_permissions('manage_service') +def add_organisation_from_gp_service(service_id): + print(current_service.organisation_type) + print(current_service.organisation) + if (not current_service.organisation_type == 'nhs_gp') or current_service.organisation: + abort(403) + + form = RenameOrganisationForm() + + if form.validate_on_submit(): + Organisation.create( + form.name.data, + crown=False, + organisation_type='nhs_gp', + agreement_signed=False, + ).associate_service( + service_id + ) + return redirect(url_for( + '.service_agreement', + service_id=service_id, + )) + + return render_template( + 'views/organisations/add-gp-organisation.html', + form=form + ) + + @main.route("/organisations/", methods=['GET']) @user_has_permissions() def organisation_dashboard(org_id): diff --git a/app/models/organisation.py b/app/models/organisation.py index e617e295a..22b0635ca 100644 --- a/app/models/organisation.py +++ b/app/models/organisation.py @@ -152,6 +152,12 @@ class Organisation(JSONModel): response = organisations_client.update_organisation(self.id, **kwargs) self.__init__(response) + def associate_service(self, service_id): + organisations_client.update_service_organisation( + str(service_id), + self.id + ) + class Organisations(ModelList): client = organisations_client.get_organisations diff --git a/app/navigation.py b/app/navigation.py index d04a43998..a4cf5ff30 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -123,6 +123,7 @@ class HeaderNavigation(Navigation): 'action_blocked', 'add_data_retention', 'add_organisation', + 'add_organisation_from_gp_service', 'add_service', 'add_service_template', 'api_callbacks', @@ -379,6 +380,7 @@ class MainNavigation(Navigation): 'usage', }, 'settings': { + 'add_organisation_from_gp_service', 'branding_request', 'estimate_usage', 'link_service_to_organisation', @@ -633,6 +635,7 @@ class CaseworkNavigation(Navigation): 'action_blocked', 'add_data_retention', 'add_organisation', + 'add_organisation_from_gp_service', 'add_service', 'add_service_template', 'api_callbacks', @@ -926,6 +929,7 @@ class OrgNavigation(Navigation): 'action_blocked', 'add_data_retention', 'add_organisation', + 'add_organisation_from_gp_service', 'add_service', 'add_service_template', 'api_callbacks', diff --git a/app/templates/views/organisations/add-gp-organisation.html b/app/templates/views/organisations/add-gp-organisation.html new file mode 100644 index 000000000..d1b713719 --- /dev/null +++ b/app/templates/views/organisations/add-gp-organisation.html @@ -0,0 +1,18 @@ +{% extends "withnav_template.html" %} +{% from "components/page-header.html" import page_header %} +{% from "components/page-footer.html" import page_footer %} +{% from "components/textbox.html" import textbox %} +{% from "components/radios.html" import radios %} +{% from "components/form.html" import form_wrapper %} + +{% block per_page_title %} + What is the name of your organisation? +{% endblock %} + +{% block maincolumn_content %} + {{ page_header('What is the name of your organisation?') }} + {% call form_wrapper() %} + {{textbox(form.name)}} + {{ page_footer('Continue') }} + {% endcall %} +{% endblock %} diff --git a/tests/app/main/views/organisations/test_organisation.py b/tests/app/main/views/organisations/test_organisation.py index 7e3ae2de9..b9fc159ad 100644 --- a/tests/app/main/views/organisations/test_organisation.py +++ b/tests/app/main/views/organisations/test_organisation.py @@ -160,6 +160,75 @@ def test_create_new_organisation_validates( assert mock_create_organisation.called is False +@pytest.mark.parametrize('organisation_type, organisation, expected_status', ( + ('nhs_gp', None, 200), + ('central', None, 403), + ('nhs_gp', organisation_json(organisation_type='nhs_gp'), 403), +)) +def test_only_gps_can_create_own_organisations( + client_request, + mocker, + service_one, + organisation_type, + organisation, + expected_status, +): + mocker.patch('app.organisations_client.get_service_organisation', return_value=organisation) + service_one['organisation_type'] = organisation_type + + page = client_request.get( + '.add_organisation_from_gp_service', + service_id=SERVICE_ONE_ID, + _expected_status=expected_status, + ) + + if expected_status == 403: + return + + assert page.select_one('input[type=text]')['name'] == 'name' + assert normalize_spaces( + page.select_one('label[for=name]').text + ) == ( + 'What’s your practice called?' + ) + + +def test_gps_can_name_their_organisation( + client_request, + mocker, + service_one, + mock_update_service_organisation, +): + mocker.patch('app.organisations_client.get_service_organisation', return_value=None) + service_one['organisation_type'] = 'nhs_gp' + mock_create_organisation = mocker.patch( + 'app.organisations_client.create_organisation', + return_value=organisation_json(ORGANISATION_ID), + ) + + client_request.post( + '.add_organisation_from_gp_service', + service_id=SERVICE_ONE_ID, + _data={ + 'name': 'Dr. Example', + }, + _expected_status=302, + _expected_redirect=url_for( + 'main.service_agreement', + service_id=SERVICE_ONE_ID, + _external=True, + ) + ) + + mock_create_organisation.assert_called_once_with( + name='Dr. Example', + organisation_type='nhs_gp', + agreement_signed=False, + crown=False, + ) + mock_update_service_organisation.assert_called_once_with(SERVICE_ONE_ID, ORGANISATION_ID) + + def test_organisation_services_shows_live_services_only( client_request, mock_get_organisation, diff --git a/tests/app/main/views/test_agreement.py b/tests/app/main/views/test_agreement.py index 0206e73e1..5d487c31e 100644 --- a/tests/app/main/views/test_agreement.py +++ b/tests/app/main/views/test_agreement.py @@ -108,6 +108,28 @@ def test_show_agreement_page( assert link['href'] == url() +def test_unknown_gps_are_redirected( + client_request, + mocker, + fake_uuid, + mock_has_jobs, + service_one, +): + mocker.patch('app.organisations_client.get_service_organisation', return_value=None) + service_one['organisation_id'] = None + service_one['organisation_type'] = 'nhs_gp' + client_request.get( + 'main.service_agreement', + service_id=SERVICE_ONE_ID, + _expected_status=302, + _expected_redirect=url_for( + 'main.add_organisation_from_gp_service', + service_id=SERVICE_ONE_ID, + _external=True, + ), + ) + + @pytest.mark.parametrize('crown, expected_status, expected_file_fetched, expected_file_served', ( ( True, 200, 'crown.pdf',