From e9f0e08de5fec9596ebbe3d3c3ae2d5fb1bc8549 Mon Sep 17 00:00:00 2001 From: Shiv K Sah Date: Mon, 3 Jul 2017 19:24:48 +0530 Subject: [PATCH 1/2] Waterfall repots- - Activation summary - Loader - Reload Amount - Reload Transactions --- cloud/endagaweb/stats_app/stats_client.py | 83 +++- cloud/endagaweb/stats_app/views.py | 7 +- .../templates/dashboard/report/billing.html | 390 ++++++++++++++++++ .../templates/dashboard/report/waterfall.html | 21 + 4 files changed, 499 insertions(+), 2 deletions(-) create mode 100644 cloud/endagaweb/templates/dashboard/report/billing.html create mode 100644 cloud/endagaweb/templates/dashboard/report/waterfall.html diff --git a/cloud/endagaweb/stats_app/stats_client.py b/cloud/endagaweb/stats_app/stats_client.py index 5ebe043f..1676eec0 100644 --- a/cloud/endagaweb/stats_app/stats_client.py +++ b/cloud/endagaweb/stats_app/stats_client.py @@ -25,7 +25,9 @@ SMS_KINDS = [ 'local_sms', 'local_recv_sms', 'outside_sms', 'incoming_sms', 'free_sms', 'error_sms'] -USAGE_EVENT_KINDS = CALL_KINDS + SMS_KINDS + ['gprs'] +WATERFALL_KINDS = ['loader', 'reload_rate', 'reload_amount', + 'reload_transaction', 'average_frequency'] +USAGE_EVENT_KINDS = CALL_KINDS + SMS_KINDS + ['gprs'] + WATERFALL_KINDS TIMESERIES_STAT_KEYS = [ 'ccch_sdcch4_load', 'tch_f_max', 'tch_f_load', 'sdcch8_max', 'tch_f_pdch_load', 'tch_f_pdch_max', 'tch_h_load', 'tch_h_max', 'sdcch8_load', 'ccch_sdcch4_max', 'sdcch_load', 'sdcch_available', 'tchf_load', 'tchf_available', @@ -369,3 +371,82 @@ def timeseries(self, key=None, **kwargs): if 'aggregation' not in kwargs: kwargs['aggregation'] = 'average_value' return self.aggregate_timeseries(key, **kwargs) + + +class WaterfallStatsClient(StatsClientBase): + """ waterfall reports data """ + + def __init__(self, *args, **kwargs): + super(WaterfallStatsClient, self).__init__(*args, **kwargs) + + def timeseries(self, kind=None, **kwargs): + # Get report data in timeseries format + start_time_epoch = kwargs.pop('start_time_epoch', 0) + end_time_epoch = kwargs.pop('end_time_epoch', -1) + + start = datetime.fromtimestamp(start_time_epoch, pytz.utc) + if end_time_epoch != -1: + end = datetime.fromtimestamp(end_time_epoch, pytz.utc) + else: + end = datetime.fromtimestamp(time.time(), pytz.utc) + + response = {'header': [{'label': "Months", 'name': 'month', + 'frozen': 'true'}, + {'label': "Activation", 'name': 'activation', + 'frozen': 'true', 'align': 'center'}], + 'data': []}; + + months = rrule(MONTHLY, dtstart=start, until=end) + for mnth in months: + key = mnth.strftime("%b") + "-" + mnth.strftime("%Y") + response['header'].append({'label': key, + 'name': key, + 'align': 'center'}) + + # Get last/first date of month from selected month + next_month = mnth.replace(day=28) + timedelta(days=4) + stats_end_dt = next_month - timedelta(days=next_month.day) + stats_start_dt = mnth + + kwargs['start_time_epoch'] = int(stats_start_dt.strftime("%s")) + kwargs['end_time_epoch'] = int(stats_end_dt.strftime("%s")) + kwargs['query'] = Q(subscriber__role='retailer') + kind_key = 'provisioned' + kwargs['report_view'] = 'value' + subscribers = self.aggregate_timeseries(kind_key, **kwargs) + + month_row = {'month': key, 'activation': len(subscribers)} + for col_mnth in months: + col_key = col_mnth.strftime("%b") + "-" + col_mnth.strftime("%Y") + month_start_dt = col_mnth + # Get last date of month from selected month + next_month = col_mnth.replace(day=28) + timedelta(days=4) + month_end_dt = next_month - timedelta(days=next_month.day) + + kwargs['start_time_epoch'] = int(month_start_dt.strftime("%s")) + kwargs['end_time_epoch'] = int(month_end_dt.strftime("%s")) + if kind == 'loader': + kwargs['aggregation'] = 'loader' + kwargs['report_view'] = 'value' + elif kind == 'reload_transaction': + kwargs['aggregation'] = 'count' + kwargs['report_view'] = 'summary' + elif kind == 'reload_amount': + kwargs['aggregation'] = 'transaction_sum' + kwargs['report_view'] = 'summary' + elif kind == 'reload_rate': + kwargs['aggregation'] = 'transaction_sum' + kwargs['report_view'] = 'summary' + elif kind == 'average_frequency': + kwargs['aggregation'] = 'transaction_sum' + kwargs['report_view'] = 'summary' + kwargs['query'] = Q(subscriber_id__in=subscribers) + kind_row = 'transfer' + result = self.aggregate_timeseries(kind_row, **kwargs) + + if isinstance(result, (list, tuple)): + month_row.update({col_key: len(result)}) + else: + month_row.update({col_key: result}) + response['data'].append(month_row) + return response diff --git a/cloud/endagaweb/stats_app/views.py b/cloud/endagaweb/stats_app/views.py index df6c88df..00b47c68 100644 --- a/cloud/endagaweb/stats_app/views.py +++ b/cloud/endagaweb/stats_app/views.py @@ -26,7 +26,10 @@ CALL_KINDS = stats_client.CALL_KINDS + ['call'] GPRS_KINDS = ['total_data', 'uploaded_data', 'downloaded_data'] TIMESERIES_STAT_KEYS = stats_client.TIMESERIES_STAT_KEYS -VALID_STATS = SMS_KINDS + CALL_KINDS + GPRS_KINDS + TIMESERIES_STAT_KEYS +WATERFALL_KINDS = ['loader', 'reload_rate', 'reload_amount', + 'reload_transaction', 'average_frequency'] +VALID_STATS = SMS_KINDS + CALL_KINDS + GPRS_KINDS + TIMESERIES_STAT_KEYS + WATERFALL_KINDS + # Set valid intervals. INTERVALS = ['years', 'months', 'weeks', 'days', 'hours', 'minutes'] # Set valid aggregation types. @@ -135,6 +138,8 @@ def get(self, request, infrastructure_level): client_type = stats_client.GPRSStatsClient elif stat_type in TIMESERIES_STAT_KEYS: client_type = stats_client.TimeseriesStatsClient + elif stat_type in WATERFALL_KINDS: + client_type = stats_client.WaterfallStatsClient # Instantiate the client at an infrastructure level. if infrastructure_level == 'global': client = client_type('global') diff --git a/cloud/endagaweb/templates/dashboard/report/billing.html b/cloud/endagaweb/templates/dashboard/report/billing.html new file mode 100644 index 00000000..2c87568c --- /dev/null +++ b/cloud/endagaweb/templates/dashboard/report/billing.html @@ -0,0 +1,390 @@ +{% extends "dashboard/layout.html" %} +{% comment %} +Copyright (c) 2016-present, Facebook, Inc. +All rights reserved. + +This source code is licensed under the BSD-style license found in the +LICENSE file in the root directory of this source tree. An additional grant +of patent rights can be found in the PATENTS file in the same directory. +{% endcomment %} +{% load apptags %} +{% load humanize %} +{% load crispy_forms_tags %} + + +{% block title %} + {% tmpl_const "SITENAME" %} | Report + {% if report_summary %} + | "{{ report_summary }}" + {% endif %} +{% endblock %} + +{% block pagestyle %} + + + + + + + +{% endblock %} + +{% block content %} + {% include "dashboard/report/header.html" with header='Billing' %} + +
+ + {% include "dashboard/report/nav.html" with active_tab='billing_reports' %} +
+ {% include "dashboard/report/filter.html" with action_url='/dashboard/reports/billing' %} + {% if network_has_activity %} +
+
+
+
+
+ {% if 'Loader' in reports %} +
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Loader" id="waterfall_loader" %} +
+
+ {% endif %} + {% if 'Reload Rate' in reports %} +
 
+
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Rate" id="waterfall_reload_rate" %} +
+
+ {% endif %} + {% if 'Reload Amount' in reports %} +
 
+
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Amount" id="waterfall_reload_amount" %} +
+
+ {% endif %} + {% if 'Reload Transaction' in reports %} +
 
+
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Transaction" id="waterfall_reload_transaction" %} +
+
+ {% endif %} + {% if 'Average Frequency' in reports %} +
 
+
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Average Frequency" id="waterfall_average_frequency" %} +
+
+ {% endif %} +
+
+
+
+
+
+ +
+
+ +
+ + {% else %} +

There is no network activity to display.

+ {% endif %} +
+ {% include 'dashboard/timezone-notice.html' %} +
+ +
+
+{% endblock %} + +{% block js %} +{% if network_has_activity %} + + + + + + + + + + + + + + + + + + +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/cloud/endagaweb/templates/dashboard/report/waterfall.html b/cloud/endagaweb/templates/dashboard/report/waterfall.html new file mode 100644 index 00000000..b6eb4e4d --- /dev/null +++ b/cloud/endagaweb/templates/dashboard/report/waterfall.html @@ -0,0 +1,21 @@ +

{{ title }}

+ + + + + + + + + + + + + + + +
\ No newline at end of file From 98ee56758eecb7c439e4fedbfb3a29aa5f478147 Mon Sep 17 00:00:00 2001 From: Shiv K Sah Date: Thu, 3 Aug 2017 21:22:50 +0530 Subject: [PATCH 2/2] update waterfall reports --- cloud/endagaweb/stats_app/stats_client.py | 119 ++++++++++--- cloud/endagaweb/stats_app/views.py | 7 +- .../templates/dashboard/report/billing.html | 159 ++++++++++++++---- .../templates/dashboard/report/waterfall.html | 5 +- 4 files changed, 227 insertions(+), 63 deletions(-) diff --git a/cloud/endagaweb/stats_app/stats_client.py b/cloud/endagaweb/stats_app/stats_client.py index 1676eec0..5dbdc930 100644 --- a/cloud/endagaweb/stats_app/stats_client.py +++ b/cloud/endagaweb/stats_app/stats_client.py @@ -25,9 +25,7 @@ SMS_KINDS = [ 'local_sms', 'local_recv_sms', 'outside_sms', 'incoming_sms', 'free_sms', 'error_sms'] -WATERFALL_KINDS = ['loader', 'reload_rate', 'reload_amount', - 'reload_transaction', 'average_frequency'] -USAGE_EVENT_KINDS = CALL_KINDS + SMS_KINDS + ['gprs'] + WATERFALL_KINDS +USAGE_EVENT_KINDS = CALL_KINDS + SMS_KINDS + ['gprs'] TIMESERIES_STAT_KEYS = [ 'ccch_sdcch4_load', 'tch_f_max', 'tch_f_load', 'sdcch8_max', 'tch_f_pdch_load', 'tch_f_pdch_max', 'tch_h_load', 'tch_h_max', 'sdcch8_load', 'ccch_sdcch4_max', 'sdcch_load', 'sdcch_available', 'tchf_load', 'tchf_available', @@ -391,17 +389,15 @@ def timeseries(self, kind=None, **kwargs): end = datetime.fromtimestamp(time.time(), pytz.utc) response = {'header': [{'label': "Months", 'name': 'month', - 'frozen': 'true'}, - {'label': "Activation", 'name': 'activation', - 'frozen': 'true', 'align': 'center'}], + 'frozen': True}, + {'label': "Subscriber Activation", + 'name': 'activation', 'frozen': True}], 'data': []}; months = rrule(MONTHLY, dtstart=start, until=end) for mnth in months: key = mnth.strftime("%b") + "-" + mnth.strftime("%Y") - response['header'].append({'label': key, - 'name': key, - 'align': 'center'}) + response['header'].append({'label': key, 'name': key}) # Get last/first date of month from selected month next_month = mnth.replace(day=28) + timedelta(days=4) @@ -410,8 +406,8 @@ def timeseries(self, kind=None, **kwargs): kwargs['start_time_epoch'] = int(stats_start_dt.strftime("%s")) kwargs['end_time_epoch'] = int(stats_end_dt.strftime("%s")) - kwargs['query'] = Q(subscriber__role='retailer') - kind_key = 'provisioned' + kwargs['query'] = Q(subscriber__role='subscriber') + kind_key = 'Provisioned' kwargs['report_view'] = 'value' subscribers = self.aggregate_timeseries(kind_key, **kwargs) @@ -425,28 +421,97 @@ def timeseries(self, kind=None, **kwargs): kwargs['start_time_epoch'] = int(month_start_dt.strftime("%s")) kwargs['end_time_epoch'] = int(month_end_dt.strftime("%s")) - if kind == 'loader': + kwargs['query'] = Q(subscriber_id__in=subscribers) + if kind in ['loader', 'reload_rate']: kwargs['aggregation'] = 'loader' kwargs['report_view'] = 'value' - elif kind == 'reload_transaction': + elif kind in ['reload_transaction', 'average_frequency']: kwargs['aggregation'] = 'count' kwargs['report_view'] = 'summary' - elif kind == 'reload_amount': - kwargs['aggregation'] = 'transaction_sum' - kwargs['report_view'] = 'summary' - elif kind == 'reload_rate': - kwargs['aggregation'] = 'transaction_sum' + elif kind in ['reload_amount', 'average_load']: + kwargs['aggregation'] = 'reload_transcation_sum' kwargs['report_view'] = 'summary' - elif kind == 'average_frequency': - kwargs['aggregation'] = 'transaction_sum' - kwargs['report_view'] = 'summary' - kwargs['query'] = Q(subscriber_id__in=subscribers) - kind_row = 'transfer' - result = self.aggregate_timeseries(kind_row, **kwargs) + result = self.aggregate_timeseries('transfer', **kwargs) if isinstance(result, (list, tuple)): - month_row.update({col_key: len(result)}) - else: - month_row.update({col_key: result}) + result = len(result) + + if kind == 'reload_rate': + try: + pers = round(float(result) / len(subscribers), 2) * 100 + except: + pers = 0 + result = str(pers) + " %" + elif kind in ['average_load', 'average_frequency']: + kwargs['aggregation'] = 'loader' + kwargs['report_view'] = 'value' + loader = self.aggregate_timeseries('transfer', **kwargs) + if isinstance(loader, (list, tuple)): + loader = len(loader) + try: + result = round(float(result) / float(loader), 2) + except: + result = 0 + month_row.update({col_key: result}) + response['data'].append(month_row) + return response + + +class NonLoaderStatsClient(StatsClientBase): + """ waterfall reports data """ + + def __init__(self, *args, **kwargs): + super(NonLoaderStatsClient, self).__init__(*args, **kwargs) + + def timeseries(self, kind=None, **kwargs): + # Get report data in timeseries format + # Oldest subscriber provision date + start_time_epoch = 1406680050 + last_month = datetime.fromtimestamp(time.time(), + pytz.utc) - timedelta(days=30) + end_epoch = last_month.replace(day=calendar.monthrange( + last_month.year, last_month.month)[1]) + start_epoch = end_epoch - timedelta(6 * 365 / 12) + + response = {'header': [{'label': "Months", 'name': 'month', + 'frozen': True}, + # {'label': "Activation", 'name': 'activation', + # 'frozen': True}, + {'label': "Non Loader", 'name': 'nonloader', + 'frozen': True}], + 'data': []}; + + months = list(rrule(MONTHLY, dtstart=start_epoch, until=end_epoch)) + months.sort(reverse=True) + kwargs2 = kwargs + + counter = 1 + + for mnth in months: + key = mnth.strftime("%b") + "-" + mnth.strftime("%Y") + + # Get last/first date of month from selected month + next_month = mnth.replace(day=28) + timedelta(days=4) + stats_end_dt = next_month - timedelta(days=next_month.day) + stats_start_dt = mnth.replace(day=1) + + kwargs[ + 'start_time_epoch'] = start_time_epoch # int(stats_start_dt.strftime("%s")) + kwargs['end_time_epoch'] = int(stats_end_dt.strftime("%s")) + kwargs['query'] = Q(subscriber__role='retailer') + kwargs['report_view'] = 'value' + subscribers = self.aggregate_timeseries('Provisioned', **kwargs) + + kwargs2['start_time_epoch'] = int(stats_start_dt.strftime("%s")) + kwargs2['end_time_epoch'] = int(end_epoch.strftime("%s")) + kwargs2['query'] = Q(subscriber__role='retailer') + kwargs2['aggregation'] = 'count' + kwargs2['report_view'] = 'summary' + + result = self.aggregate_timeseries('transfer', **kwargs2) + month_row = {'month': "%d months" % (counter), + # 'activation': len(subscribers), + 'nonloader': result - len(subscribers)} response['data'].append(month_row) + counter += 1 return response diff --git a/cloud/endagaweb/stats_app/views.py b/cloud/endagaweb/stats_app/views.py index 00b47c68..df6c88df 100644 --- a/cloud/endagaweb/stats_app/views.py +++ b/cloud/endagaweb/stats_app/views.py @@ -26,10 +26,7 @@ CALL_KINDS = stats_client.CALL_KINDS + ['call'] GPRS_KINDS = ['total_data', 'uploaded_data', 'downloaded_data'] TIMESERIES_STAT_KEYS = stats_client.TIMESERIES_STAT_KEYS -WATERFALL_KINDS = ['loader', 'reload_rate', 'reload_amount', - 'reload_transaction', 'average_frequency'] -VALID_STATS = SMS_KINDS + CALL_KINDS + GPRS_KINDS + TIMESERIES_STAT_KEYS + WATERFALL_KINDS - +VALID_STATS = SMS_KINDS + CALL_KINDS + GPRS_KINDS + TIMESERIES_STAT_KEYS # Set valid intervals. INTERVALS = ['years', 'months', 'weeks', 'days', 'hours', 'minutes'] # Set valid aggregation types. @@ -138,8 +135,6 @@ def get(self, request, infrastructure_level): client_type = stats_client.GPRSStatsClient elif stat_type in TIMESERIES_STAT_KEYS: client_type = stats_client.TimeseriesStatsClient - elif stat_type in WATERFALL_KINDS: - client_type = stats_client.WaterfallStatsClient # Instantiate the client at an infrastructure level. if infrastructure_level == 'global': client = client_type('global') diff --git a/cloud/endagaweb/templates/dashboard/report/billing.html b/cloud/endagaweb/templates/dashboard/report/billing.html index 2c87568c..6ca41407 100644 --- a/cloud/endagaweb/templates/dashboard/report/billing.html +++ b/cloud/endagaweb/templates/dashboard/report/billing.html @@ -10,7 +10,7 @@ {% load apptags %} {% load humanize %} {% load crispy_forms_tags %} - +{% load guardian_tags %} {% block title %} {% tmpl_const "SITENAME" %} | Report @@ -20,6 +20,7 @@ {% endblock %} {% block pagestyle %} + @@ -34,10 +35,12 @@ {% block content %} {% include "dashboard/report/header.html" with header='Billing' %} + {% get_obj_perms request.user for network as 'user_permission' %}
{% include "dashboard/report/nav.html" with active_tab='billing_reports' %} + {% if 'view_graph' in user_permission %}
{% include "dashboard/report/filter.html" with action_url='/dashboard/reports/billing' %} {% if network_has_activity %} @@ -49,7 +52,7 @@ {% if 'Loader' in reports %}
- {% include "dashboard/report/waterfall.html" with title="Waterfall - Loader" id="waterfall_loader" %} + {% include "dashboard/report/waterfall.html" with title="Waterfall - Loader" info="This report shows count of subscribers who did top-up in assessing month. So, total count of such subscribers will get updated against their provisioned month." id="waterfall_loader" %}
{% endif %} @@ -57,7 +60,7 @@
 
- {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Rate" id="waterfall_reload_rate" %} + {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Rate" info='This report shows average number of time top-up done by all the subscribers in assessing month against the number of subscriber provisioned in that particular month' id="waterfall_reload_rate" %}
{% endif %} @@ -65,7 +68,7 @@
 
- {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Amount" id="waterfall_reload_amount" %} + {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Amount" info="This report shows total top-up done by all the subscribers through retailer in assessing month. so, sum of top-up amount done by all the subscriber will get updated against their provisioned month" id="waterfall_reload_amount" %}
{% endif %} @@ -73,7 +76,15 @@
 
- {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Transaction" id="waterfall_reload_transaction" %} + {% include "dashboard/report/waterfall.html" with title="Waterfall - Reload Transaction" info="This report shows number of transaction done by all the subscribers in assessing month. So, number of transaction done by all the subscribers will get updated against their provisioned month" id="waterfall_reload_transaction" %} +
+
+ {% endif %} + {% if 'Average Load' in reports %} +
 
+
+
+ {% include "dashboard/report/waterfall.html" with title="Waterfall - Average Load" info="This report shows average top-up done by each subscriber in assessing month. So, average amount per subscriber will get updated against their provisioned month" id="waterfall_average_load" %}
{% endif %} @@ -81,20 +92,27 @@
 
- {% include "dashboard/report/waterfall.html" with title="Waterfall - Average Frequency" id="waterfall_average_frequency" %} + {% include "dashboard/report/waterfall.html" with title="Waterfall - Average Frequency" info="This report shows average number of time top-up done by each subscriber in assessing month. So, average frequency per subscriber will get updated against their provisioned month" id="waterfall_average_frequency" %}
{% endif %} + + {% if 'Total Base' in reports %} +
+
+

Non Loader Report - Total Base

+
+
+
+
+ {% endif %} +
- -
-
-
{% else %} @@ -105,6 +123,9 @@
+ {% else %} + {% include 'dashboard/permission_denied.html' %} + {% endif %} {% endblock %} @@ -117,6 +138,7 @@ }, 800); }); + @@ -124,12 +146,11 @@ - + + - - {% endif %} diff --git a/cloud/endagaweb/templates/dashboard/report/waterfall.html b/cloud/endagaweb/templates/dashboard/report/waterfall.html index b6eb4e4d..62a86849 100644 --- a/cloud/endagaweb/templates/dashboard/report/waterfall.html +++ b/cloud/endagaweb/templates/dashboard/report/waterfall.html @@ -1,4 +1,7 @@ -

{{ title }}

+

+ {{ title }}   + +