diff --git a/app/main/views/organizations.py b/app/main/views/organizations.py index 3b1569f65..52acc144d 100644 --- a/app/main/views/organizations.py +++ b/app/main/views/organizations.py @@ -62,6 +62,20 @@ def add_organization(): return render_template("views/organizations/add-organization.html", form=form) +def get_organization_message_allowance(org_id): + try: + message_usage = organizations_client.get_organization_message_usage(org_id) + except Exception as e: + current_app.logger.error(f"Error fetching organization message usage: {e}") + message_usage = {} + + return { + "messages_sent": message_usage.get("messages_sent", 0), + "messages_remaining": message_usage.get("messages_remaining", 0), + "total_message_limit": message_usage.get("total_message_limit", 0), + } + + @main.route("/organizations/", methods=["GET"]) @user_has_permissions() def organization_dashboard(org_id): @@ -70,10 +84,16 @@ def organization_dashboard(org_id): year = requested_and_current_financial_year(request)[0] - # TODO: total message allowance + message_allowance = get_organization_message_allowance(org_id) + return render_template( "views/organizations/organization/index.html", selected_year=year, + live_services=len(current_organization.live_services), + trial_services=len(current_organization.trial_services), + suspended_services=len(current_organization.suspended_services), + total_services=len(current_organization.services), + **message_allowance, ) diff --git a/app/models/organization.py b/app/models/organization.py index f2dc1bf07..33f5f3ec4 100644 --- a/app/models/organization.py +++ b/app/models/organization.py @@ -103,7 +103,11 @@ class Organization(JSONModel, SortByNameMixin): @property def trial_services(self): - return [s for s in self.services if not s["active"] or s["restricted"]] + return [s for s in self.services if s["active"] and s["restricted"]] + + @property + def suspended_services(self): + return [s for s in self.services if not s["active"]] @cached_property def invited_users(self): diff --git a/app/notify_client/organizations_api_client.py b/app/notify_client/organizations_api_client.py index 10d121a41..e7cca58ef 100644 --- a/app/notify_client/organizations_api_client.py +++ b/app/notify_client/organizations_api_client.py @@ -78,5 +78,10 @@ class OrganizationsClient(NotifyAdminAPIClient): params={"year": str(year)}, ) + def get_organization_message_usage(self, org_id): + return self.get( + url="/organizations/{}/message-allowance".format(org_id), + ) + organizations_client = OrganizationsClient() diff --git a/app/templates/views/organizations/organization/index.html b/app/templates/views/organizations/organization/index.html index 8ffce38d5..88a2d2433 100644 --- a/app/templates/views/organizations/organization/index.html +++ b/app/templates/views/organizations/organization/index.html @@ -9,7 +9,56 @@ {{ page_header('Organization Dashboard', size='large') }} -
+
+
+

Overall {{ selected_year }} Total Message Allowance

+ +
+ +
+
+
+
+
+
+
+
+
+
+
Total Services
+
{{ total_services }}
+
+
+ {{ live_services }} Live + {{ trial_services }} Trial + {{ suspended_services }} Suspended +
+
+
+
+
+
+
+
+
+
+
Agreement Period
+
Jan 1 - Dec 31
+
+
+
+
+
+ +

What is a service?

When you join Notify, you're added to a service. This is your organization's workspace for sending text messages and emails. Within your service, you can: diff --git a/tests/app/main/views/organizations/test_organizations.py b/tests/app/main/views/organizations/test_organizations.py index bca1bf2f8..3dc7e74d8 100644 --- a/tests/app/main/views/organizations/test_organizations.py +++ b/tests/app/main/views/organizations/test_organizations.py @@ -655,16 +655,12 @@ def test_organization_trial_mode_services_shows_all_non_live_services( ) services = page.select(".browse-list-item") - assert len(services) == 2 + assert len(services) == 1 assert normalize_spaces(services[0].text) == "2" - assert normalize_spaces(services[1].text) == "3" assert services[0].find("a")["href"] == url_for( "main.service_dashboard", service_id="2" ) - assert services[1].find("a")["href"] == url_for( - "main.service_dashboard", service_id="3" - ) def test_organization_trial_mode_services_doesnt_work_if_not_platform_admin( @@ -1522,3 +1518,77 @@ def test_organization_billing_page_not_accessible_if_not_platform_admin( client_request.get( ".organization_billing", org_id=ORGANISATION_ID, _expected_status=403 ) + + +def test_organization_dashboard_shows_message_usage( + client_request, + mock_get_organization, + mocker, + active_user_with_permissions, +): + mock_message_usage = mocker.patch( + "app.organizations_client.get_organization_message_usage", + return_value={ + "messages_sent": 1000, + "messages_remaining": 2000, + "total_message_limit": 3000, + }, + ) + mocker.patch( + "app.organizations_client.get_organization_services", + return_value=[], + ) + client_request.login(active_user_with_permissions) + page = client_request.get( + ".organization_dashboard", + org_id=ORGANISATION_ID, + ) + + mock_message_usage.assert_called_once_with(ORGANISATION_ID) + + assert normalize_spaces(page.select_one("h1").text) == "Organization Dashboard" + + chart_container = page.select_one("#totalMessageChartContainer") + assert chart_container["data-messages-sent"] == "1000" + assert chart_container["data-messages-remaining"] == "2000" + assert chart_container["data-total-message-limit"] == "3000" + + +def test_organization_dashboard_shows_service_counts( + client_request, + mock_get_organization, + mocker, + active_user_with_permissions, +): + mocker.patch( + "app.organizations_client.get_organization_message_usage", + return_value={ + "messages_sent": 0, + "messages_remaining": 0, + "total_message_limit": 0, + }, + ) + mocker.patch( + "app.organizations_client.get_organization_services", + return_value=[ + service_json(id_="1", name="Live Service", restricted=False, active=True), + service_json(id_="2", name="Trial Service", restricted=True, active=True), + service_json(id_="3", name="Suspended", restricted=False, active=False), + ], + ) + + client_request.login(active_user_with_permissions) + page = client_request.get( + ".organization_dashboard", + org_id=ORGANISATION_ID, + ) + + summary_boxes = page.select(".usa-summary-box") + assert len(summary_boxes) == 2 + + service_box = summary_boxes[0] + assert "Total Services" in normalize_spaces(service_box.text) + assert "3" in normalize_spaces(service_box.text) + assert "1 Live" in normalize_spaces(service_box.text) + assert "1 Trial" in normalize_spaces(service_box.text) + assert "1 Suspended" in normalize_spaces(service_box.text)