Skip to content
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

Added Enterprise Data Exports Report #35462

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions corehq/apps/enterprise/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
MobileUserResource,
ODataFeedResource,
WebUserResource,
DataExportReportResource
)

v1_api = Api(api_name='v1')
Expand All @@ -14,3 +15,4 @@
v1_api.register(MobileUserResource())
v1_api.register(FormSubmissionResource())
v1_api.register(ODataFeedResource())
v1_api.register(DataExportReportResource())
30 changes: 30 additions & 0 deletions corehq/apps/enterprise/api/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,33 @@ def dehydrate(self, bundle):

def get_primary_keys(self):
return ('form_id', 'submitted',)


class DataExportReportResource(ODataEnterpriseReportResource):
domain = fields.CharField()
name = fields.CharField()
export_type = fields.CharField()
export_subtype = fields.CharField()
owner = fields.CharField()

REPORT_SLUG = EnterpriseReport.DATA_EXPORTS

def get_report_task(self, request):
account = BillingAccount.get_account_by_domain(request.domain)
return generate_enterprise_report.s(
self.REPORT_SLUG,
account.id,
request.couch_user.username
)

def dehydrate(self, bundle):
bundle.data['domain'] = bundle.obj[0]
bundle.data['name'] = bundle.obj[1]
bundle.data['export_type'] = bundle.obj[2]
bundle.data['export_subtype'] = bundle.obj[3]
bundle.data['owner'] = bundle.obj[4]

return bundle

def get_primary_keys(self):
return ('domain', 'export_type', 'export_subtype', 'name')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested on staging, I can have two export in same domain, with same export_type, export_subtype and name. In this case, adding owner won't be helpful. Should we add some other attribute like export_id?

75 changes: 75 additions & 0 deletions corehq/apps/enterprise/enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
from couchforms.analytics import get_last_form_submission_received
from dimagi.utils.dates import DateSpan

from corehq.apps.users.models import WebUser
from corehq.apps.export.dbaccessors import (
get_brief_exports,
is_standard,
is_daily_saved_export,
is_excel_integration
)
from corehq.apps.enterprise.exceptions import EnterpriseReportError, TooMuchRequestedDataError
from corehq.apps.enterprise.iterators import raise_after_max_elements
from corehq.apps.accounting.models import BillingAccount
Expand All @@ -34,6 +41,7 @@ class EnterpriseReport:
MOBILE_USERS = 'mobile_users'
FORM_SUBMISSIONS = 'form_submissions'
ODATA_FEEDS = 'odata_feeds'
DATA_EXPORTS = 'data_exports'

DATE_ROW_FORMAT = '%Y/%m/%d %H:%M:%S'

Expand Down Expand Up @@ -67,6 +75,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.DATA_EXPORTS:
report = EnterpriseDataExportReport(account, couch_user, **kwargs)

if report:
report.slug = slug
Expand Down Expand Up @@ -383,3 +393,68 @@ def _get_individual_export_rows(self, exports, export_line_counts):
)

return rows


class EnterpriseDataExportReport(EnterpriseReport):
title = gettext_lazy('Data Exports')

def __init__(self, account, couch_user):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tada! Got you! Same issue as mine when you reviewed my PR lol.

super().__init__(account, couch_user)

@property
def headers(self):
return [
_('Project Space'),
_('Name'),
_('Type'),
_('SubType'),
_('Created By'),
]

def type_lookup(self, doc_type):
from corehq.apps.export.models.new import FormExportInstance, CaseExportInstance
if doc_type == FormExportInstance.__name__:
return _('Form')
elif doc_type == CaseExportInstance.__name__:
return _('Case')
else:
return _('Unknown')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what case it will be unknown?


SUBTYPE_MAP = {
is_standard: gettext_lazy('Standard'),
is_daily_saved_export: gettext_lazy('Daily Saved Export'),
is_excel_integration: gettext_lazy('Excel Integration'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we don't support PowerBi/tableau integration?

}

def subtype_lookup(self, export):
for (is_subtype_fn, subtype) in self.SUBTYPE_MAP.items():
if is_subtype_fn(export):
return subtype

return _('Unknown')

def user_lookup(self, owner_id):
if not owner_id:
return _('Unknown')

owner = WebUser.get_by_user_id(owner_id)
return owner.username

def get_exports(self, domain_obj):
valid_subtypes = self.SUBTYPE_MAP.values()
return [
export for export in get_brief_exports(domain_obj.name)
if self.subtype_lookup(export) in valid_subtypes
]

def rows_for_domain(self, domain_obj):
return [[
domain_obj.name,
export['name'],
self.type_lookup(export['doc_type']),
self.subtype_lookup(export),
self.user_lookup(export['owner_id']),
] for export in self.get_exports(domain_obj)]

def total_for_domain(self, domain_obj):
return len(self.get_exports(domain_obj))
1 change: 1 addition & 0 deletions corehq/apps/enterprise/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def enterprise_dashboard(request, domain):
EnterpriseReport.MOBILE_USERS,
EnterpriseReport.FORM_SUBMISSIONS,
EnterpriseReport.ODATA_FEEDS,
EnterpriseReport.DATA_EXPORTS,
)],
'current_page': {
'page_name': _('Enterprise Dashboard'),
Expand Down
23 changes: 22 additions & 1 deletion corehq/apps/export/dbaccessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,27 @@ def delete_all_export_instances():
safe_delete(db, doc_id)


def is_standard(export):
return (not export['is_daily_saved_export']
and not export['is_odata_config'])


def is_daily_saved_export(export):
return (export['is_daily_saved_export']
and not export['export_format'] == "html"
and not export['is_odata_config'])


def is_excel_integration(export):
return (export['is_daily_saved_export']
and export['export_format'] == "html"
and not export['is_odata_config'])


def is_odata_export(export):
return export['is_odata_config']


class ODataExportFetcher:
def get_export_count(self, domain):
return len(self._get_odata_exports(domain))
Expand All @@ -220,4 +241,4 @@ def get_exports(self, domain):

def _get_odata_exports(self, domain):
all_domain_exports = get_brief_exports(domain)
return [export for export in all_domain_exports if export['is_odata_config']]
return [export for export in all_domain_exports if is_odata_export(export)]
Loading