diff --git a/app/dao/services_dao.py b/app/dao/services_dao.py index 5c1da4d68..e72e359e2 100644 --- a/app/dao/services_dao.py +++ b/app/dao/services_dao.py @@ -2,7 +2,7 @@ import uuid from datetime import date, datetime, timedelta from notifications_utils.statsd_decorators import statsd -from sqlalchemy import asc, func +from sqlalchemy import asc, func, case from sqlalchemy.orm import joinedload from flask import current_app @@ -21,11 +21,13 @@ from app.dao.template_folder_dao import dao_get_valid_template_folders_by_id from app.models import ( AnnualBilling, ApiKey, + FactBilling, InboundNumber, InvitedUser, Job, Notification, NotificationHistory, + Organisation, Permission, Service, ServicePermission, @@ -72,6 +74,84 @@ def dao_count_live_services(): ).count() +def dao_fetch_live_services_data(): + data = db.session.query( + Service.id, + Organisation.name.label("organisation_name"), + Service.name.label("service_name"), + Service.consent_to_research, + Service.go_live_user_id, + User.name.label('user_name'), + User.email_address, + User.mobile_number, + Service.go_live_at.label("live_date"), + Service.volume_sms, + Service.volume_email, + Service.volume_letter, + case([ + (FactBilling.notification_type == 'email', func.sum(FactBilling.notifications_sent)) + ], else_=0).label("email_totals"), + case([ + (FactBilling.notification_type == 'sms', func.sum(FactBilling.notifications_sent)) + ], else_=0).label("sms_totals"), + case([ + (FactBilling.notification_type == 'letter', func.sum(FactBilling.notifications_sent)) + ], else_=0).label("letter_totals"), + ).outerjoin( + Service.organisation + ).outerjoin( + FactBilling, Service.id == FactBilling.service_id + ).outerjoin( + User, Service.go_live_user_id == User.id + ).group_by( + Service.id, + Organisation.name, + Service.name, + Service.consent_to_research, + Service.go_live_user_id, + User.name, + User.email_address, + User.mobile_number, + Service.go_live_at, + Service.volume_sms, + Service.volume_email, + Service.volume_letter, + FactBilling.notification_type + ).all() + results = [] + for row in data: + is_service_in_list = None + i = 0 + while i < len(results): + if results[i]["service_id"] == row.id: + is_service_in_list = i + break + else: + i += 1 + if is_service_in_list is not None: + results[is_service_in_list]["email_totals"] += row.email_totals + results[is_service_in_list]["sms_totals"] += row.sms_totals + results[is_service_in_list]["letter_totals"] += row.letter_totals + else: + results.append({ + "service_id": row.id, + "service_name": row.service_name, + "organisation_name": row.organisation_name, + "consent_to_research": row.consent_to_research, + "contact_name": row.user_name, + "contact_email": row.email_address, + "contact_mobile": row.mobile_number, + "live_date": row.live_date, + "sms_volume_intent": row.volume_sms, + "email_volume_intent": row.volume_email, + "letter_volume_intent": row.volume_letter, + "sms_totals": row.sms_totals, + "email_totals": row.email_totals, + "letter_totals": row.letter_totals, + }) + return results + + def dao_fetch_service_by_id(service_id, only_active=False): query = Service.query.filter_by( id=service_id diff --git a/app/service/rest.py b/app/service/rest.py index 828dcfdaa..8b2be1818 100644 --- a/app/service/rest.py +++ b/app/service/rest.py @@ -49,6 +49,7 @@ from app.dao.services_dao import ( dao_create_service, dao_fetch_all_services, dao_fetch_all_services_by_user, + dao_fetch_live_services_data, dao_fetch_service_by_id, dao_fetch_todays_stats_for_service, dao_fetch_todays_stats_for_all_services, @@ -158,6 +159,12 @@ def get_services(): return jsonify(data=data) +@service_blueprint.route('/live-services-data', methods=['GET']) +def get_live_services_data(): + data = dao_fetch_live_services_data() + return jsonify(data=data) + + @service_blueprint.route('/', methods=['GET']) def get_service_by_id(service_id): if request.args.get('detailed') == 'True': diff --git a/tests/app/dao/test_services_dao.py b/tests/app/dao/test_services_dao.py index e00b7ebd0..70fd265dc 100644 --- a/tests/app/dao/test_services_dao.py +++ b/tests/app/dao/test_services_dao.py @@ -12,12 +12,14 @@ from app.dao.inbound_numbers_dao import ( dao_get_available_inbound_numbers, dao_set_inbound_number_active_flag ) +from app.dao.organisation_dao import dao_add_service_to_organisation from app.dao.service_permissions_dao import dao_add_service_permission, dao_remove_service_permission from app.dao.services_dao import ( dao_create_service, dao_add_user_to_service, dao_remove_user_from_service, dao_fetch_all_services, + dao_fetch_live_services_data, dao_fetch_service_by_id, dao_fetch_all_services_by_user, dao_update_service, @@ -57,7 +59,9 @@ from app.models import ( user_folder_permissions, ) from tests.app.db import ( + create_ft_billing, create_inbound_number, + create_organisation, create_user, create_service, create_service_with_inbound_number, @@ -380,6 +384,31 @@ def test_get_all_user_services_should_return_empty_list_if_no_services_for_user( assert len(dao_fetch_all_services_by_user(user.id)) == 0 +def test_dao_fetch_live_services_data(sample_user, mock): + org = create_organisation() + service = create_service(go_live_user=sample_user) + template = create_template(service=service) + create_service(service_name='second', go_live_user=sample_user) + template2 = create_template(service=service, template_type='email') + dao_add_service_to_organisation(service=service, organisation_id=org.id) + create_ft_billing(bst_date='2019-04-20', notification_type='sms', template=template, service=service) + create_ft_billing(bst_date='2019-04-20', notification_type='email', template=template2, + service=service) + + results = dao_fetch_live_services_data() + assert len(results) == 2 + assert {'service_id': mock.ANY, 'service_name': 'Sample service', 'organisation_name': 'test_org_1', + 'consent_to_research': None, 'contact_name': 'Test User', + 'contact_email': 'notify@digital.cabinet-office.gov.uk', 'contact_mobile': '+447700900986', + 'live_date': None, 'sms_volume_intent': None, 'email_volume_intent': None, + 'letter_volume_intent': None, 'sms_totals': 1, 'email_totals': 1, 'letter_totals': 0} in results + assert {'service_id': mock.ANY, 'service_name': 'second', 'organisation_name': None, 'consent_to_research': None, + 'contact_name': 'Test User', 'contact_email': 'notify@digital.cabinet-office.gov.uk', + 'contact_mobile': '+447700900986', 'live_date': None, 'sms_volume_intent': None, + 'email_volume_intent': None, 'letter_volume_intent': None, + 'sms_totals': 0, 'email_totals': 0, 'letter_totals': 0} in results + + def test_get_service_by_id_returns_none_if_no_service(notify_db): with pytest.raises(NoResultFound) as e: dao_fetch_service_by_id(str(uuid.uuid4())) diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index d447ee559..446445ffb 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -136,6 +136,10 @@ def test_get_service_list_should_return_empty_list_if_no_services(admin_request) assert len(json_resp['data']) == 0 +def test_get_live_services_data(): + pass + + def test_get_service_by_id(admin_request, sample_service): json_resp = admin_request.get('service.get_service_by_id', service_id=sample_service.id) assert json_resp['data']['name'] == sample_service.name