diff --git a/app/__init__.py b/app/__init__.py index 527495702..2ff39d8e4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,6 +3,7 @@ import os import urllib from datetime import datetime, timedelta, timezone from functools import partial +from numbers import Number from time import monotonic import ago @@ -345,6 +346,14 @@ def format_delta(date): ) +def format_thousands(value): + if isinstance(value, Number): + return '{:,.0f}'.format(value) + if value is None: + return '' + return value + + def valid_phone_number(phone_number): try: validate_phone_number(phone_number) @@ -688,6 +697,7 @@ def add_template_filters(application): formatted_list, nl2br, format_phone_number_human_readable, + format_thousands, id_safe, ]: application.add_template_filter(fn) diff --git a/app/main/forms.py b/app/main/forms.py index 6ab4e1035..2017b6433 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -34,6 +34,7 @@ from wtforms.fields.html5 import EmailField, SearchField, TelField from wtforms.validators import URL, DataRequired, Length, Optional, Regexp from wtforms.widgets import CheckboxInput, ListWidget +from app import format_thousands from app.main.validators import ( Blacklist, CsvFileValidator, @@ -209,9 +210,9 @@ class ForgivingIntegerField(StringField): error = None try: if int(self.data) > self.POSTGRES_MAX_INT: - error = 'Number of {} must be {:,.0f} or less'.format( + error = 'Number of {} must be {} or less'.format( self.things, - self.POSTGRES_MAX_INT, + format_thousands(self.POSTGRES_MAX_INT), ) except ValueError: error = 'Enter the number of {} {}'.format( @@ -234,7 +235,7 @@ class ForgivingIntegerField(StringField): try: value = int(self.data) - value = '{:,.0f}'.format(value) + value = format_thousands(value) except (ValueError, TypeError): value = self.data if self.data is not None else '' diff --git a/app/main/views/choose_account.py b/app/main/views/choose_account.py index febecaeea..3626a66e6 100644 --- a/app/main/views/choose_account.py +++ b/app/main/views/choose_account.py @@ -1,7 +1,9 @@ from flask import redirect, render_template, session, url_for from flask_login import current_user +from app import status_api_client from app.main import main +from app.models.organisation import Organisations from app.utils import PermanentRedirect, user_is_logged_in @@ -18,9 +20,17 @@ def services_or_dashboard(): @main.route("/accounts") @user_is_logged_in def choose_account(): + org_count, live_service_count = None, None + if current_user.platform_admin: + org_count, live_service_count = ( + len(Organisations()), + status_api_client.get_count_of_live_services_and_organisations()['services'], + ) return render_template( 'views/choose-account.html', can_add_service=current_user.is_gov_user, + org_count=org_count, + live_service_count=live_service_count, ) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index acb1a4346..8d1bc5b48 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -25,6 +25,7 @@ from notifications_utils.template import Template, WithSubjectTemplate from app import ( current_service, format_datetime_short, + format_thousands, job_api_client, notification_api_client, service_api_client, @@ -186,8 +187,8 @@ def cancel_letter_job(service_id, job_id): except HTTPError as e: flash(e.message, 'dangerous') return redirect(url_for('main.view_job', service_id=service_id, job_id=job_id)) - flash("Cancelled {:,.0f} letters from {}".format( - number_of_letters, job['original_file_name'] + flash("Cancelled {} letters from {}".format( + format_thousands(number_of_letters), job['original_file_name'] ), 'default_with_tick') return redirect(url_for('main.service_dashboard', service_id=service_id)) diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 9a50c48df..807b17147 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -19,6 +19,7 @@ from app import ( billing_api_client, current_service, email_branding_client, + format_thousands, inbound_number_client, letter_branding_client, notification_api_client, @@ -212,9 +213,9 @@ def submit_request_to_go_live(service_id): service_dashboard=url_for('main.service_dashboard', service_id=current_service.id, _external=True), organisation_type=str(current_service.organisation_type).title(), agreement=current_service.organisation.as_human_readable(current_user.email_domain), - volume_email_formatted=format_if_number(current_service.volume_email), - volume_sms_formatted=format_if_number(current_service.volume_sms), - volume_letter_formatted=format_if_number(current_service.volume_letter), + volume_email_formatted=format_thousands(current_service.volume_email), + volume_sms_formatted=format_thousands(current_service.volume_sms), + volume_letter_formatted=format_thousands(current_service.volume_letter), research_consent='Yes' if current_service.consent_to_research else 'No', existing_live='Yes' if current_user.live_services else 'No', email_address=current_user.email_address, @@ -262,7 +263,7 @@ def service_switch_count_as_live(service_id): ) if form.validate_on_submit(): - current_service.update(count_as_live=form.enabled.data) + current_service.update_count_as_live(form.enabled.data) return redirect(url_for('.service_settings', service_id=service_id)) return render_template( @@ -1121,7 +1122,3 @@ def check_contact_details_type(contact_details): return 'email_address' else: return 'phone_number' - - -def format_if_number(value): - return '{:,.0f}'.format(value) if isinstance(value, int) else '' diff --git a/app/models/service.py b/app/models/service.py index 3a45f6a17..7b09ca5e5 100644 --- a/app/models/service.py +++ b/app/models/service.py @@ -65,6 +65,9 @@ class Service(JSONModel): def update(self, **kwargs): return service_api_client.update_service(self.id, **kwargs) + def update_count_as_live(self, count_as_live): + return service_api_client.update_count_as_live(self.id, count_as_live=count_as_live) + def update_status(self, live): return service_api_client.update_status(self.id, live=live) diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index aa6086c6a..8adbee048 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -114,6 +114,13 @@ class ServiceAPIClient(NotifyAdminAPIClient): go_live_at=str(datetime.utcnow()) if live else None ) + @cache.delete('live-service-and-organisation-counts') + def update_count_as_live(self, service_id, count_as_live): + return self.update_service( + service_id, + count_as_live=count_as_live, + ) + # This method is not cached because it calls through to one which is def update_service_with_properties(self, service_id, properties): return self.update_service(service_id, **properties) diff --git a/app/templates/views/choose-account.html b/app/templates/views/choose-account.html index 9457f520e..62924ed19 100644 --- a/app/templates/views/choose-account.html +++ b/app/templates/views/choose-account.html @@ -69,6 +69,9 @@
+ {{ org_count|format_thousands }} organisations, {{ live_service_count|format_thousands }} live services +