-
-
Notifications
You must be signed in to change notification settings - Fork 218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Enterprise SMS Report #35437
Add Enterprise SMS Report #35437
Changes from 6 commits
f95ba18
182ed6a
8f45845
72b7bef
4d80d9f
3f58ff3
fc4fccd
8310efd
c181654
1adcaf3
6400bd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import re | ||
from django.db.models import Count | ||
from datetime import datetime, timedelta | ||
|
||
from django.utils.translation import gettext as _ | ||
|
@@ -20,6 +21,7 @@ | |
from corehq.apps.es import forms as form_es | ||
from corehq.apps.es.users import UserES | ||
from corehq.apps.export.dbaccessors import ODataExportFetcher | ||
from corehq.apps.sms.models import SMS, OUTGOING, INCOMING | ||
from corehq.apps.users.dbaccessors import ( | ||
get_all_user_rows, | ||
get_mobile_user_count, | ||
|
@@ -34,6 +36,7 @@ class EnterpriseReport: | |
MOBILE_USERS = 'mobile_users' | ||
FORM_SUBMISSIONS = 'form_submissions' | ||
ODATA_FEEDS = 'odata_feeds' | ||
SMS = 'sms' | ||
|
||
DATE_ROW_FORMAT = '%Y/%m/%d %H:%M:%S' | ||
|
||
|
@@ -67,6 +70,8 @@ def create(cls, slug, account_id, couch_user, **kwargs): | |
report = EnterpriseFormReport(account, couch_user, **kwargs) | ||
elif slug == cls.ODATA_FEEDS: | ||
report = EnterpriseODataReport(account, couch_user, **kwargs) | ||
elif slug == cls.SMS: | ||
report = EnterpriseSMSReport(account, couch_user, **kwargs) | ||
|
||
if report: | ||
report.slug = slug | ||
|
@@ -383,3 +388,59 @@ def _get_individual_export_rows(self, exports, export_line_counts): | |
) | ||
|
||
return rows | ||
|
||
|
||
class EnterpriseSMSReport(EnterpriseReport): | ||
title = gettext_lazy('SMS Sent') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change the title to align with the design doc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in fc4fccd |
||
MAX_DATE_RANGE_DAYS = 90 | ||
|
||
def __init__(self, account, couch_user, start_date=None, end_date=None, num_days=30): | ||
super().__init__(account, couch_user) | ||
|
||
if not end_date: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you make it as a util function so other tiles can reuse it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I did this in the iterators PR, which is still in review. Re-adding it here would cause conflicts, so I'm going to wait until that PR is merged for this functionality |
||
end_date = datetime.utcnow() | ||
elif isinstance(end_date, str): | ||
end_date = datetime.fromisoformat(end_date) | ||
|
||
if start_date: | ||
if isinstance(start_date, str): | ||
start_date = datetime.fromisoformat(start_date) | ||
self.datespan = DateSpan(start_date, end_date) | ||
self.subtitle = _("{} to {}").format( | ||
start_date.date(), | ||
end_date.date(), | ||
) | ||
else: | ||
self.datespan = DateSpan(end_date - timedelta(days=num_days), end_date) | ||
self.subtitle = _("past {} days").format(num_days) | ||
|
||
if self.datespan.enddate - self.datespan.startdate > timedelta(days=self.MAX_DATE_RANGE_DAYS): | ||
raise TooMuchRequestedDataError( | ||
_('Date ranges with more than {} days are not supported').format(self.MAX_DATE_RANGE_DAYS) | ||
) | ||
|
||
def total_for_domain(self, domain_obj): | ||
query = SMS.objects.filter( | ||
domain=domain_obj.name, | ||
direction=OUTGOING, | ||
date__gte=self.datespan.startdate, | ||
date__lt=self.datespan.enddate_adjusted | ||
) | ||
|
||
return query.count() | ||
|
||
@property | ||
def headers(self): | ||
headers = [_('Project Space Name'), _('# Sent'), _('# Received'), _('# Errors')] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simplify the header to be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
return headers | ||
|
||
def rows_for_domain(self, domain_obj): | ||
results = SMS.objects.filter(domain=domain_obj.name) \ | ||
.values('direction', 'error').annotate(direction_count=Count('pk')) | ||
|
||
num_sent = sum([result['direction_count'] for result in results if result['direction'] == OUTGOING]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we only include sms that is succesfully sent and received? If we don't charge them, then we should not include errored sms in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in 1adcaf3 |
||
num_received = sum([result['direction_count'] for result in results if result['direction'] == INCOMING]) | ||
num_errors = sum([result['direction_count'] for result in results if result['error']]) | ||
|
||
return [(domain_obj.name, num_sent, num_received, num_errors), ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
util function for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c181654