mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-04-13 13:51:22 -04:00
Merge pull request #3004 from GSA/2967-calculate-an-organizations-message-usage-for-current-agreement-period
2967 calculate an organization's message usage for current agreement period
This commit is contained in:
@@ -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/<uuid:org_id>", 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,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -9,7 +9,56 @@
|
||||
|
||||
{{ page_header('Organization Dashboard', size='large') }}
|
||||
|
||||
<div class="margin-top-5 margin-bottom-5">
|
||||
<div id="totalMessageChartContainer" data-messages-sent="{{ messages_sent|default(0) }}" data-messages-remaining="{{ messages_remaining|default(0) }}" data-total-message-limit="{{ total_message_limit|default(0) }}">
|
||||
<div class="grid-row flex-align-center">
|
||||
<h2 id="chartTitle" class="margin-right-1 margin-y-0">Overall {{ selected_year }} Total Message Allowance</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="usa-tooltip usa-tooltip__information margin-right-0"
|
||||
data-position="top"
|
||||
title="Combined totals across all services in {{ current_org.name }}: pending, failed, or delivered"
|
||||
>
|
||||
<span class="usa-sr-only">More information</span>
|
||||
i
|
||||
</button>
|
||||
</div>
|
||||
<svg id="totalMessageChart"></svg>
|
||||
<div id="message"></div>
|
||||
</div>
|
||||
<div id="totalMessageTable" class="margin-bottom-3"></div>
|
||||
<div class="grid-row margin-bottom-3 maxw-tablet">
|
||||
<div class="grid-col-12 tablet:grid-col-6 margin-bottom-2 tablet:margin-bottom-0 tablet:padding-right-1">
|
||||
<div class="usa-summary-box height-full" role="region">
|
||||
<div class="usa-summary-box__body">
|
||||
<div class="usa-summary-box__text">
|
||||
<div class="display-flex flex-align-end">
|
||||
<div class="flex-1">
|
||||
<div class="text-base-dark text-uppercase font-sans-3xs text-ls-1 margin-bottom-05">Total Services</div>
|
||||
<div class="font-sans-xl text-primary-darker line-height-sans-1">{{ total_services }}</div>
|
||||
</div>
|
||||
<div class="text-base-dark font-body-2xs line-height-sans-3">
|
||||
<span class="text-success-dark text-bold">{{ live_services }}</span> Live
|
||||
<span class="margin-left-1 text-warning-dark text-bold">{{ trial_services }}</span> Trial
|
||||
<span class="margin-left-1 text-base-dark text-bold">{{ suspended_services }}</span> Suspended
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-col-12 tablet:grid-col-6 tablet:padding-left-1">
|
||||
<div class="usa-summary-box height-full" role="region">
|
||||
<div class="usa-summary-box__body">
|
||||
<div class="usa-summary-box__text">
|
||||
<div class="text-base-dark text-uppercase font-sans-3xs text-ls-1 margin-bottom-05">Agreement Period</div>
|
||||
<div class="font-sans-xl text-primary-darker">Jan 1 - Dec 31</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="margin-bottom-5">
|
||||
<h2 class="font-heading-lg">What is a service?</h2>
|
||||
<p class="usa-body">
|
||||
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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user