From ccec5758ec4d88f12271859ab75b2dbcc79ca63a Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 21 Oct 2025 14:06:54 -0700 Subject: [PATCH 1/4] get service usage --- app/dao/fact_billing_dao.py | 16 +++++++++++++--- app/organization/rest.py | 4 +++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index bcb685c52..18df6c1d2 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -18,7 +18,7 @@ from app.models import ( Rate, Service, ) -from app.utils import get_midnight_in_utc, utc_now +from app.utils import DATETIME_FORMAT, get_midnight_in_utc, utc_now def fetch_sms_free_allowance_remainder_until_date(end_date): @@ -695,10 +695,15 @@ def query_organization_sms_usage_for_year(organization_id, year): ) -def fetch_usage_year_for_organization(organization_id, year): +def fetch_usage_year_for_organization(organization_id, year, include_all_services=False): year_start, year_end = get_calendar_year_dates(year) today = utc_now().date() - services = dao_get_organization_live_services(organization_id) + + if include_all_services: + from app.dao.organization_dao import dao_get_organization_services + services = dao_get_organization_services(organization_id) + else: + services = dao_get_organization_live_services(organization_id) # if year end date is less than today, we are calculating for data in the past and have no need for deltas. if year_end >= today: @@ -719,12 +724,15 @@ def fetch_usage_year_for_organization(organization_id, year): "sms_cost": 0.0, "emails_sent": 0, "active": service.active, + "restricted": service.restricted, + "created_at": service.created_at.strftime(DATETIME_FORMAT), } sms_usages = fetch_sms_billing_for_organization(organization_id, year) email_usages = fetch_email_usage_for_organization( organization_id, year_start, year_end ) for usage in sms_usages: + service = next(s for s in services if s.id == usage.service_id) service_with_usage[str(usage.service_id)] = { "service_id": usage.service_id, "service_name": usage.service_name, @@ -735,6 +743,8 @@ def fetch_usage_year_for_organization(organization_id, year): "sms_cost": float(usage.sms_cost), "emails_sent": 0, "active": usage.active, + "restricted": service.restricted, + "created_at": service.created_at.strftime(DATETIME_FORMAT), } for email_usage in email_usages: service_with_usage[str(email_usage.service_id)][ diff --git a/app/organization/rest.py b/app/organization/rest.py index cd963197d..3296ff48f 100644 --- a/app/organization/rest.py +++ b/app/organization/rest.py @@ -151,7 +151,9 @@ def get_organization_services_usage(organization_id): year = int(request.args.get("year", "none")) except ValueError: return jsonify(result="error", message="No valid year provided"), 400 - services = fetch_usage_year_for_organization(organization_id, year) + include_all = request.args.get("include_all_services", "false").lower() == "true" + + services = fetch_usage_year_for_organization(organization_id, year, include_all_services=include_all) list_services = services.values() sorted_services = sorted( list_services, key=lambda s: (-s["active"], s["service_name"].lower()) From 0267c52098f9a3ec1bbf6cba6ec13326c2bedaaa Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 21 Oct 2025 14:42:19 -0700 Subject: [PATCH 2/4] updating imports --- app/dao/fact_billing_dao.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index 18df6c1d2..8e72d6ad3 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -7,7 +7,10 @@ from sqlalchemy.sql.expression import case, literal from app import db from app.dao.date_util import get_calendar_year_dates, get_calendar_year_for_datetime -from app.dao.organization_dao import dao_get_organization_live_services +from app.dao.organization_dao import ( + dao_get_organization_live_services, + dao_get_organization_services, +) from app.enums import KeyType, NotificationStatus, NotificationType from app.models import ( AnnualBilling, @@ -700,7 +703,6 @@ def fetch_usage_year_for_organization(organization_id, year, include_all_service today = utc_now().date() if include_all_services: - from app.dao.organization_dao import dao_get_organization_services services = dao_get_organization_services(organization_id) else: services = dao_get_organization_live_services(organization_id) From 09907cc4afd7ef8810719132b73fc38224bcc8c4 Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 21 Oct 2025 14:50:30 -0700 Subject: [PATCH 3/4] removed the next() lookup --- app/dao/fact_billing_dao.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index 8e72d6ad3..36e65b887 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -616,6 +616,8 @@ def fetch_sms_billing_for_organization(organization_id, financial_year): func.coalesce(chargeable_sms, 0).label("chargeable_billable_sms"), func.coalesce(sms_cost, 0).label("sms_cost"), Service.active, + Service.restricted, + Service.created_at, ) .select_from(Service) .outerjoin( @@ -734,7 +736,6 @@ def fetch_usage_year_for_organization(organization_id, year, include_all_service organization_id, year_start, year_end ) for usage in sms_usages: - service = next(s for s in services if s.id == usage.service_id) service_with_usage[str(usage.service_id)] = { "service_id": usage.service_id, "service_name": usage.service_name, @@ -745,8 +746,8 @@ def fetch_usage_year_for_organization(organization_id, year, include_all_service "sms_cost": float(usage.sms_cost), "emails_sent": 0, "active": usage.active, - "restricted": service.restricted, - "created_at": service.created_at.strftime(DATETIME_FORMAT), + "restricted": usage.restricted, + "created_at": usage.created_at.strftime(DATETIME_FORMAT), } for email_usage in email_usages: service_with_usage[str(email_usage.service_id)][ From 3a82ef7fd370c476ca500a11a11dc7cf02df9bca Mon Sep 17 00:00:00 2001 From: Beverly Nguyen Date: Tue, 21 Oct 2025 15:32:18 -0700 Subject: [PATCH 4/4] we don't need created_at here --- app/dao/fact_billing_dao.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index 36e65b887..dcc9e1f76 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -21,7 +21,7 @@ from app.models import ( Rate, Service, ) -from app.utils import DATETIME_FORMAT, get_midnight_in_utc, utc_now +from app.utils import get_midnight_in_utc, utc_now def fetch_sms_free_allowance_remainder_until_date(end_date): @@ -617,7 +617,6 @@ def fetch_sms_billing_for_organization(organization_id, financial_year): func.coalesce(sms_cost, 0).label("sms_cost"), Service.active, Service.restricted, - Service.created_at, ) .select_from(Service) .outerjoin( @@ -729,7 +728,6 @@ def fetch_usage_year_for_organization(organization_id, year, include_all_service "emails_sent": 0, "active": service.active, "restricted": service.restricted, - "created_at": service.created_at.strftime(DATETIME_FORMAT), } sms_usages = fetch_sms_billing_for_organization(organization_id, year) email_usages = fetch_email_usage_for_organization( @@ -747,7 +745,6 @@ def fetch_usage_year_for_organization(organization_id, year, include_all_service "emails_sent": 0, "active": usage.active, "restricted": usage.restricted, - "created_at": usage.created_at.strftime(DATETIME_FORMAT), } for email_usage in email_usages: service_with_usage[str(email_usage.service_id)][