edx-enterprise-data 9.0.1__py3-none-any.whl → 9.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/METADATA +1 -1
  2. {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/RECORD +22 -23
  3. enterprise_data/__init__.py +1 -1
  4. enterprise_data/admin_analytics/constants.py +0 -16
  5. enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +90 -0
  6. enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +83 -4
  7. enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +116 -0
  8. enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +97 -3
  9. enterprise_data/api/v1/serializers.py +1 -55
  10. enterprise_data/api/v1/urls.py +14 -17
  11. enterprise_data/api/v1/views/analytics_completions.py +150 -0
  12. enterprise_data/api/v1/views/analytics_engagements.py +106 -351
  13. enterprise_data/api/v1/views/analytics_enrollments.py +3 -6
  14. enterprise_data/renderers.py +22 -7
  15. enterprise_data/tests/admin_analytics/mock_analytics_data.py +12 -90
  16. enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -66
  17. enterprise_data/tests/admin_analytics/test_analytics_engagements.py +120 -240
  18. enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +12 -81
  19. enterprise_data/tests/admin_analytics/test_enterprise_completions.py +105 -120
  20. enterprise_data/admin_analytics/completions_utils.py +0 -261
  21. enterprise_data/api/v1/views/enterprise_completions.py +0 -200
  22. {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/LICENSE +0 -0
  23. {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/WHEEL +0 -0
  24. {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edx-enterprise-data
3
- Version: 9.0.1
3
+ Version: 9.1.0
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -1,29 +1,28 @@
1
- enterprise_data/__init__.py,sha256=wEC_qcYuekT4a1fFlvFa8RoVQmkPyucJqib8SX4wwn4,123
1
+ enterprise_data/__init__.py,sha256=iLQWwenZSKPK_Ygv_cROjWWAtH0biPa7Cuvdqy3hrbg,123
2
2
  enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
3
3
  enterprise_data/clients.py,sha256=GvQupy5TVYfO_IKC3yzXSAgNP54r-PtIjidM5ws9Iks,3947
4
4
  enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
5
5
  enterprise_data/filters.py,sha256=D2EiK12MMpBoz6eOUmTpoJEhj_sH7bA93NRRAdvkDVo,6163
6
6
  enterprise_data/models.py,sha256=khGcOh7NWP8KGu84t78Y2zAu3knREeXA_prApmU2NX8,24428
7
7
  enterprise_data/paginators.py,sha256=YPrC5TeXFt-ymenT2H8H2nCbDCnAzJQlH9kFPElRxWE,269
8
- enterprise_data/renderers.py,sha256=VaCymaZUhYEZ6yvryoASEohKeeL6lcPSWhFCnyfzjps,2699
8
+ enterprise_data/renderers.py,sha256=94JNmPj6OuOcoqMfwl_ieTwy-fQPJO7IbYpYQhxvHJY,3022
9
9
  enterprise_data/signals.py,sha256=8eqNPnlvmfsKf19lGWv5xTIuBgQIqR8EZSp9UYzC8Rc,1024
10
10
  enterprise_data/urls.py,sha256=bqtKF5OEWEwrNmHG3os-pZNuNsmjlhxEqp7yM4TbPf4,243
11
11
  enterprise_data/utils.py,sha256=_zK3BErjZSIkP_JNzK8m-DR5pRTnxKylP9I-vURaRcE,3009
12
12
  enterprise_data/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- enterprise_data/admin_analytics/completions_utils.py,sha256=kGmLy7x6aD0coNYgzLa5XzJypLkGTT5clDHLSH_QFDE,9442
14
- enterprise_data/admin_analytics/constants.py,sha256=7WturLuMISekgcHHlgj45PPdPrDTYM-l21lA8-Q_Tfc,1107
13
+ enterprise_data/admin_analytics/constants.py,sha256=bTU05drUaePj9ZjLVxUwFMq_8hibafXqPnVrmrQt4Og,532
15
14
  enterprise_data/admin_analytics/data_loaders.py,sha256=z5OHCmsjQuu1lBw43mSSCbdSQ40fmL_WtodV_Tcnj5U,4791
16
15
  enterprise_data/admin_analytics/utils.py,sha256=DftyBaSKnf0f6E3adH8yVAvGNeQGROywufqnJxZ0W84,6295
17
16
  enterprise_data/admin_analytics/database/__init__.py,sha256=vNSWKf2VV5xMegN7htJJtxtQEb0ASLC6frE2w0ZpYpE,104
18
17
  enterprise_data/admin_analytics/database/utils.py,sha256=5u-d6ZQW95mF_r4bH8Xdi7DgpYAuDFOG_q0P-bjKXHU,1712
19
18
  enterprise_data/admin_analytics/database/queries/__init__.py,sha256=IC5TLOr_GnydbrVbl2mWhwO3aUbYeHuDmfPTLmwGhZA,218
20
- enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=fq01Ni_sKnvSRoiPQfTnJ8TtRePQe5MBLmI5CpVy36o,747
21
- enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=uuhX3OIB5Cp0-5uxN604HNEUuzb3s9nH3VR4CiEXs18,5388
19
+ enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=QNoeuUQ2Fg9IWSxayA8mBbrnRYNPaXVBWhA7-dbquNc,4445
20
+ enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=brRgmgtzPLsOdt1vYrk_EpoQLm2izmOdBapxAxNkXzA,8420
22
21
  enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=PgWwvtVCK5lbiq6z44lH0fwbkdWYukhyXZL9X8lNWCY,4099
23
22
  enterprise_data/admin_analytics/database/tables/__init__.py,sha256=Z-c3P9hqR-dC9uYKe63qHkQG9Nms8cLE2jRN-4jeMM0,289
24
23
  enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
25
- enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=EsG8KgRW84wtA_nJuUknjLYlDtaPSJf_9mWdkO2Bj2I,1293
26
- enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=ix5QvPnrUZMVs_Fdt742i9PAmrQTXuqHlfW3PJhSQWo,7282
24
+ enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=VM-5S1ayJuFaWhBoJd1odTqWaFsWDeLZkoaPixAG2dQ,5544
25
+ enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=q1XB7aDwFzllS5lBQNfS2y7drehqiK7o0J1eiYzqFOk,10854
27
26
  enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=9PqLeVqByrz7R0qumRbwJlr5lzIWn7Fl7WEGM0aJVlw,3131
28
27
  enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
28
  enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
@@ -33,15 +32,15 @@ enterprise_data/api/v0/urls.py,sha256=vzJjqIo_S3AXWs9Us8XTaJc3FnxLbYzAkmLyuDQqum
33
32
  enterprise_data/api/v0/views.py,sha256=4RslZ4NZOU-844bnebEQ71ji2utRY7jEijqC45oQQD0,14380
34
33
  enterprise_data/api/v1/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
35
34
  enterprise_data/api/v1/paginators.py,sha256=f0xsilLaU94jSBltJk46tR1rLEIt7YrqSzMAAVtPXjA,3592
36
- enterprise_data/api/v1/serializers.py,sha256=FEuH-_iTlKFJoxM8ABzEYHDAWHsgSYfdQd2WSPdXoeE,13329
37
- enterprise_data/api/v1/urls.py,sha256=JzaaVsHEAELMLFdhR60_8LRLb9klDeA4zdH1dLxnQEo,4048
35
+ enterprise_data/api/v1/serializers.py,sha256=leVxK1fVAk_25TDnuMLDHKvOw7GvTmU7zSYXiX0nmZU,11620
36
+ enterprise_data/api/v1/urls.py,sha256=zoztENyCI_8TcKpE88Q6pkKSHiWCC9DascjC9ul4arc,3975
38
37
  enterprise_data/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- enterprise_data/api/v1/views/analytics_engagements.py,sha256=8H3Fk-hTqJaU3H5Lpu1kFWq7p7xDp1pjge-sK7osDbg,17553
40
- enterprise_data/api/v1/views/analytics_enrollments.py,sha256=uVc36C0s9y1dPBfbYwFhXLqPlExvQvZeiJ4C45lb4ZQ,6447
38
+ enterprise_data/api/v1/views/analytics_completions.py,sha256=Px-hwNpkgwZN-Kwrl9MEfpY-TNuVglp1pyJEG9QnPFQ,6391
39
+ enterprise_data/api/v1/views/analytics_engagements.py,sha256=yvnHALXVkxQHuX7M8Mom1vNEH-2vvPHZMVlm1SUvTTE,6429
40
+ enterprise_data/api/v1/views/analytics_enrollments.py,sha256=RF-OOSVOPbESIUmrLbSM229lMPQ8RokJ6MqTpWoxIgY,6413
41
41
  enterprise_data/api/v1/views/analytics_leaderboard.py,sha256=2DALqzUIbe4-ZGgHHIkYAKJ5L1ik2ruPtQNYtTdPba4,5974
42
42
  enterprise_data/api/v1/views/base.py,sha256=Kkmd5zgEBAhvwS_GoGXSK6lgbDNwSPioYn-QbnizI3w,3416
43
43
  enterprise_data/api/v1/views/enterprise_admin.py,sha256=DsR1oHFhe6LCIFjIJ4YLLZ7PUChvNlFfdZD-sxHoijY,7388
44
- enterprise_data/api/v1/views/enterprise_completions.py,sha256=bJG2ZtTbLyiBrj64iJHQNHEKLrJCzl9OuJ7nDtw-9aY,8377
45
44
  enterprise_data/api/v1/views/enterprise_learner.py,sha256=yABjJje3CT8I8YOhWr1_tTkdKtnGJom8eu3EFz_-0BU,18517
46
45
  enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
47
46
  enterprise_data/fixtures/enterprise_enrollment.json,sha256=6onPXXR29pMdTdbl_mn81sDi3Re5jkLUZz2TPMB_1IY,5786
@@ -115,13 +114,13 @@ enterprise_data/tests/test_models.py,sha256=MWBY-LY5TPBjZ4GlvpM-h4W-BvRKr2Rml8Bz
115
114
  enterprise_data/tests/test_utils.py,sha256=vbmYM7DMN-lHS2p4yaa0Yd6uSGXd2qoZRDE9X3J4Sec,18385
116
115
  enterprise_data/tests/test_views.py,sha256=UvDRNTxruy5zBK_KgUy2cBMbwlaTW_vkM0-TCXbQZiY,69667
117
116
  enterprise_data/tests/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
- enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=LiuwYQXj44XW_mBIQz9gP3Izy8dwrkX-Yp9s8PA19e4,20866
119
- enterprise_data/tests/admin_analytics/mock_enrollments.py,sha256=LfuMo9Kn-OQD4z42G3BRuM5MXUUXXlaAMhTqfJf46XE,7266
120
- enterprise_data/tests/admin_analytics/test_analytics_engagements.py,sha256=KPXtBPaAOrzfff7W-xERSGx9KtZAJndLbIJx3gopSnE,15689
121
- enterprise_data/tests/admin_analytics/test_analytics_enrollments.py,sha256=GePv5E8BRGRWUHUwGaXvYIsN3dtDpNXUh-yfW5iBTi4,13781
117
+ enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=NYmgPKIZrIK7HqbjxQ_PKqhY5zmafoePM4NcqE5zfpc,17401
118
+ enterprise_data/tests/admin_analytics/mock_enrollments.py,sha256=u61tkqSdVKExURJF7arvBoXvbdkF39CkjxQiTvVMXIE,4467
119
+ enterprise_data/tests/admin_analytics/test_analytics_engagements.py,sha256=gfO6RI2gbDMhOD4p4h7l6sZpisglBreTPtJRqNxIgo8,10440
120
+ enterprise_data/tests/admin_analytics/test_analytics_enrollments.py,sha256=uFa6gnlf-CthctdYTWsw-pLLOxkELGiq8YFq5CyWFbs,10826
122
121
  enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py,sha256=VSEyDAHfWBJvqmx9yzd4NnPAqK3TqaKrMBWswMAdzfU,6206
123
122
  enterprise_data/tests/admin_analytics/test_data_loaders.py,sha256=b4BjN88FX9WjE6XJjkJZnoEvWVB_DovBGJ_wh-HgT9I,3514
124
- enterprise_data/tests/admin_analytics/test_enterprise_completions.py,sha256=afkHQFy4bvqZ0pq5Drl1t2nv8zxbgca2jzOQbihlPG0,7359
123
+ enterprise_data/tests/admin_analytics/test_enterprise_completions.py,sha256=6BsCnaXdTMaQXoqy4SWNxAkGimc75lBCdBHjR2MdOFU,7233
125
124
  enterprise_data/tests/admin_analytics/test_utils.py,sha256=4qL_ZK-sGzbMMqiOrBrPmzdIPno7KohiaIfd7FMehic,5260
126
125
  enterprise_data/tests/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
126
  enterprise_data/tests/api/v0/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -171,8 +170,8 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=WtL-RqGgu2x5PP
171
170
  enterprise_reporting/tests/test_utils.py,sha256=Zt_TA0LVb-B6fQGkUkAKKVlUKKnQh8jnw1US1jKe7g8,9493
172
171
  enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
173
172
  enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
174
- edx_enterprise_data-9.0.1.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
175
- edx_enterprise_data-9.0.1.dist-info/METADATA,sha256=sQyBej1XBqXBR31O1IvBhV4BP1KonVp6JfzuiCgdtYA,1569
176
- edx_enterprise_data-9.0.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
177
- edx_enterprise_data-9.0.1.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
178
- edx_enterprise_data-9.0.1.dist-info/RECORD,,
173
+ edx_enterprise_data-9.1.0.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
174
+ edx_enterprise_data-9.1.0.dist-info/METADATA,sha256=7nemB4hOP7OfCH-uN87q4YINSbTbnicYsTd_P6CLSPE,1569
175
+ edx_enterprise_data-9.1.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
176
+ edx_enterprise_data-9.1.0.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
177
+ edx_enterprise_data-9.1.0.dist-info/RECORD,,
@@ -2,4 +2,4 @@
2
2
  Enterprise data api application. This Django app exposes API endpoints used by enterprises.
3
3
  """
4
4
 
5
- __version__ = "9.0.1"
5
+ __version__ = "9.1.0"
@@ -19,23 +19,7 @@ class Calculation(Enum):
19
19
  MOVING_AVERAGE_7_PERIOD = 'Moving Average (7 Period)'
20
20
 
21
21
 
22
- class EnrollmentChart(Enum):
23
- """CSV choices"""
24
- ENROLLMENTS_OVER_TIME = 'enrollments_over_time'
25
- TOP_COURSES_BY_ENROLLMENTS = 'top_courses_by_enrollments'
26
- TOP_SUBJECTS_BY_ENROLLMENTS = 'top_subjects_by_enrollments'
27
- INDIVIDUAL_ENROLLMENTS = 'individual_enrollments'
28
-
29
-
30
22
  class ResponseType(Enum):
31
23
  """Response type choices"""
32
24
  JSON = 'json'
33
25
  CSV = 'csv'
34
-
35
-
36
- class EngagementChart(Enum):
37
- """Response Choices"""
38
- ENGAGEMENTS_OVER_TIME = 'engagements_over_time'
39
- TOP_COURSES_BY_ENGAGEMENTS = 'top_courses_by_engagements'
40
- TOP_SUBJECTS_BY_ENGAGEMENTS = 'top_subjects_by_engagements'
41
- INDIVIDUAL_ENGAGEMENTS = 'individual_engagements'
@@ -19,3 +19,93 @@ class FactEngagementAdminDashQueries:
19
19
  WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
20
20
  activity_date BETWEEN %(start_date)s AND %(end_date)s;
21
21
  """
22
+
23
+ @staticmethod
24
+ def get_engagement_count_query():
25
+ """
26
+ Get the query to fetch the total number of engagements for an enterprise customer.
27
+ """
28
+ return """
29
+ SELECT count(*)
30
+ FROM fact_enrollment_engagement_day_admin_dash
31
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
32
+ activity_date BETWEEN %(start_date)s AND %(end_date)s;
33
+ """
34
+
35
+ @staticmethod
36
+ def get_all_engagement_query():
37
+ """
38
+ Get the query to fetch all engagement data.
39
+ """
40
+ return """
41
+ SELECT
42
+ email, course_title, course_subject, enroll_type, activity_date,
43
+ learning_time_seconds/3600 as learning_time_hours
44
+ FROM fact_enrollment_engagement_day_admin_dash
45
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
46
+ activity_date BETWEEN %(start_date)s AND %(end_date)s
47
+ ORDER BY activity_date DESC LIMIT %(limit)s OFFSET %(offset)s;
48
+ """
49
+
50
+ @staticmethod
51
+ def get_top_courses_by_engagement_query(record_count=20):
52
+ """
53
+ Get the query to fetch the learning time in hours by courses.
54
+
55
+ Query should fetch the top N courses by user engagement. Where N is the value of record_count.
56
+
57
+ Arguments:
58
+ record_count (int): Number of records to fetch.
59
+
60
+ Returns:
61
+ (str): Query to fetch the learning time in hours by courses for the top courses by user engagement.
62
+ """
63
+ return f"""
64
+ SELECT course_key, course_title, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
65
+ FROM fact_enrollment_engagement_day_admin_dash
66
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
67
+ activity_date BETWEEN %(start_date)s AND %(end_date)s
68
+ GROUP BY course_key, course_title, enroll_type
69
+ ORDER BY learning_time_hours DESC LIMIT {record_count};
70
+ """
71
+
72
+ @staticmethod
73
+ def get_top_subjects_by_engagement_query(record_count=20):
74
+ """
75
+ Get the query to fetch the learning time in hours by subjects.
76
+
77
+ Query should fetch the top N subjects by user engagement. Where N is the value of record_count.
78
+
79
+ Arguments:
80
+ record_count (int): Number of records to fetch.
81
+
82
+ Returns:
83
+ (str): Query to fetch the learning time in hours by subjects for the top subjects by user engagement.
84
+ """
85
+ return f"""
86
+ SELECT course_subject, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
87
+ FROM fact_enrollment_engagement_day_admin_dash
88
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
89
+ activity_date BETWEEN %(start_date)s AND %(end_date)s
90
+ GROUP BY course_subject, enroll_type
91
+ ORDER BY learning_time_hours DESC LIMIT {record_count};
92
+ """
93
+
94
+ @staticmethod
95
+ def get_engagement_time_series_data_query():
96
+ """
97
+ Get the query to fetch the completion time series data.
98
+
99
+ Query should fetch the time series data with daily granularity.
100
+
101
+ Returns:
102
+ (str): Query to fetch the completion time series data.
103
+ """
104
+ return """
105
+ SELECT activity_date, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
106
+ FROM fact_enrollment_engagement_day_admin_dash
107
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
108
+ activity_date BETWEEN %(start_date)s AND %(end_date)s
109
+ GROUP BY activity_date, enroll_type
110
+ ORDER BY activity_date;
111
+ """
@@ -68,6 +68,7 @@ class FactEnrollmentAdminDashQueries:
68
68
  SUM(has_passed) as completions
69
69
  FROM fact_enrollment_admin_dash
70
70
  WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
71
+ has_passed=1 AND
71
72
  passed_date BETWEEN %(start_date)s AND %(end_date)s;
72
73
  """
73
74
 
@@ -85,7 +86,7 @@ class FactEnrollmentAdminDashQueries:
85
86
  """
86
87
 
87
88
  @staticmethod
88
- def get_top_courses_enrollments_query(record_count=20):
89
+ def get_top_courses_by_enrollments_query(record_count=20):
89
90
  """
90
91
  Get the query to fetch the enrollment count by courses.
91
92
 
@@ -94,14 +95,12 @@ class FactEnrollmentAdminDashQueries:
94
95
  Arguments:
95
96
  record_count (int): Number of records to fetch.
96
97
  """
97
- # Some local environments raise error when course_title is added in SELECT without GROUP BY.
98
- # If you face this issue, you can remove course_title from SELECT.
99
98
  return f"""
100
99
  SELECT course_key, course_title , enroll_type, count(course_key) as enrollment_count
101
100
  FROM fact_enrollment_admin_dash
102
101
  WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
103
102
  enterprise_enrollment_date BETWEEN %(start_date)s AND %(end_date)s
104
- GROUP BY course_key, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
103
+ GROUP BY course_key, course_title, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
105
104
  """
106
105
 
107
106
  @staticmethod
@@ -135,3 +134,83 @@ class FactEnrollmentAdminDashQueries:
135
134
  GROUP BY enterprise_enrollment_date, enroll_type
136
135
  ORDER BY enterprise_enrollment_date;
137
136
  """
137
+
138
+ @staticmethod
139
+ def get_all_completions_query():
140
+ """
141
+ Get the query to fetch all completions.
142
+ """
143
+ return """
144
+ SELECT email, course_title, course_subject, enroll_type, passed_date
145
+ FROM fact_enrollment_admin_dash
146
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
147
+ has_passed=1 AND
148
+ passed_date BETWEEN %(start_date)s AND %(end_date)s
149
+ ORDER BY passed_date DESC LIMIT %(limit)s OFFSET %(offset)s
150
+ """
151
+
152
+ @staticmethod
153
+ def get_top_courses_by_completions_query(record_count=20):
154
+ """
155
+ Get the query to fetch the completion count by courses.
156
+
157
+ Query should fetch the top N courses by completion count. Where N is the value of record_count.
158
+
159
+ Arguments:
160
+ record_count (int): Number of records to fetch.
161
+
162
+ Returns:
163
+ (str): Query to fetch the enrollment count by courses for the top courses by enrollment count.
164
+ """
165
+ return f"""
166
+ SELECT course_key, course_title, enroll_type, count(course_key) as completion_count
167
+ FROM fact_enrollment_admin_dash
168
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
169
+ has_passed=1 AND
170
+ passed_date BETWEEN %(start_date)s AND %(end_date)s
171
+ GROUP BY course_key, course_title, enroll_type
172
+ ORDER BY completion_count DESC LIMIT {record_count};
173
+ """
174
+
175
+ @staticmethod
176
+ def get_top_subjects_by_completions_query(record_count=20):
177
+ """
178
+ Get the query to fetch the completion count by subjects.
179
+
180
+ Query should fetch the top N subjects by completion count. Where N is the value of record_count.
181
+
182
+ Arguments:
183
+ record_count (int): Number of records to fetch.
184
+
185
+ Returns:
186
+ (str): Query to fetch the completion count by subjects for the top subjects by completion count.
187
+ """
188
+ return f"""
189
+ SELECT course_subject, enroll_type, count(course_subject) as completion_count
190
+ FROM fact_enrollment_admin_dash
191
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
192
+ has_passed=1 AND
193
+ passed_date BETWEEN %(start_date)s AND %(end_date)s
194
+ GROUP BY course_subject, enroll_type
195
+ ORDER BY completion_count DESC LIMIT {record_count};
196
+ """
197
+
198
+ @staticmethod
199
+ def get_completions_time_series_data_query():
200
+ """
201
+ Get the query to fetch the completion time series data.
202
+
203
+ Query should fetch the time series data with daily granularity.
204
+
205
+ Returns:
206
+ (str): Query to fetch the completion time series data.
207
+ """
208
+ return """
209
+ SELECT passed_date, enroll_type, count(course_key) as completion_count
210
+ FROM fact_enrollment_admin_dash
211
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
212
+ has_passed=1 AND
213
+ passed_date BETWEEN %(start_date)s AND %(end_date)s
214
+ GROUP BY passed_date, enroll_type
215
+ ORDER BY passed_date;
216
+ """
@@ -36,3 +36,119 @@ class FactEngagementAdminDashTable(BaseTable):
36
36
  }
37
37
  )
38
38
  return tuple(results[0])
39
+
40
+ def get_engagement_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
41
+ """
42
+ Get the total number of engagements for the given enterprise customer.
43
+
44
+ Arguments:
45
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
46
+ start_date (date): The start date.
47
+ end_date (date): The end date.
48
+
49
+ Returns:
50
+ int: The total number of engagements.
51
+ """
52
+ results = run_query(
53
+ query=self.queries.get_engagement_count_query(),
54
+ params={
55
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
56
+ 'start_date': start_date,
57
+ 'end_date': end_date,
58
+ }
59
+ )
60
+ return results[0][0]
61
+
62
+ def get_all_engagements(
63
+ self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
64
+ ):
65
+ """
66
+ Get all engagement data for the given enterprise customer.
67
+
68
+ Arguments:
69
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
70
+ start_date (date): The start date.
71
+ end_date (date): The end date.
72
+ limit (int): The maximum number of records to return.
73
+ offset (int): The number of records to skip.
74
+
75
+ Returns:
76
+ list<dict>: A list of dictionaries containing the engagement data.
77
+ """
78
+ return run_query(
79
+ query=self.queries.get_all_engagement_query(),
80
+ params={
81
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
82
+ 'start_date': start_date,
83
+ 'end_date': end_date,
84
+ 'limit': limit,
85
+ 'offset': offset,
86
+ },
87
+ as_dict=True,
88
+ )
89
+
90
+ def get_top_courses_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
91
+ """
92
+ Get the top courses by user engagement for the given enterprise customer.
93
+
94
+ Arguments:
95
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
96
+ start_date (date): The start date.
97
+ end_date (date): The end date.
98
+
99
+ Returns:
100
+ list<dict>: A list of dictionaries containing the course data.
101
+ """
102
+ return run_query(
103
+ query=self.queries.get_top_courses_by_engagement_query(),
104
+ params={
105
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
106
+ 'start_date': start_date,
107
+ 'end_date': end_date,
108
+ },
109
+ as_dict=True,
110
+ )
111
+
112
+ def get_top_subjects_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
113
+ """
114
+ Get the top subjects by user engagement for the given enterprise customer.
115
+
116
+ Arguments:
117
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
118
+ start_date (date): The start date.
119
+ end_date (date): The end date.
120
+
121
+ Returns:
122
+ list<dict>: A list of dictionaries containing the subject data.
123
+ """
124
+ return run_query(
125
+ query=self.queries.get_top_subjects_by_engagement_query(),
126
+ params={
127
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
128
+ 'start_date': start_date,
129
+ 'end_date': end_date,
130
+ },
131
+ as_dict=True,
132
+ )
133
+
134
+ def get_engagement_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
135
+ """
136
+ Get the engagement time series data.
137
+
138
+ Arguments:
139
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
140
+ start_date (date): The start date.
141
+ end_date (date): The end date.
142
+
143
+ Returns:
144
+ list<dict>: A list of dictionaries containing the engagement time series data.
145
+ """
146
+ return run_query(
147
+ query=self.queries.get_engagement_time_series_data_query(),
148
+ params={
149
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
150
+ 'start_date': start_date,
151
+ 'end_date': end_date,
152
+ },
153
+ as_dict=True,
154
+ )
@@ -35,7 +35,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
35
35
  'end_date': end_date,
36
36
  }
37
37
  )
38
- return results[0][0]
38
+ return int(results[0][0] or 0)
39
39
 
40
40
  def get_all_enrollments(
41
41
  self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
@@ -132,7 +132,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
132
132
  'end_date': end_date,
133
133
  }
134
134
  )
135
- return results[0][0]
135
+ return int(results[0][0] or 0)
136
136
 
137
137
  def get_top_courses_by_enrollments(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
138
138
  """
@@ -147,7 +147,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
147
147
  list<dict>: A list of dictionaries containing the course key, course_title and enrollment count.
148
148
  """
149
149
  return run_query(
150
- query=self.queries.get_top_courses_enrollments_query(),
150
+ query=self.queries.get_top_courses_by_enrollments_query(),
151
151
  params={
152
152
  'enterprise_customer_uuid': enterprise_customer_uuid,
153
153
  'start_date': start_date,
@@ -199,3 +199,97 @@ class FactEnrollmentAdminDashTable(BaseTable):
199
199
  },
200
200
  as_dict=True,
201
201
  )
202
+
203
+ def get_all_completions(
204
+ self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
205
+ ):
206
+ """
207
+ Get all completions for the given enterprise customer.
208
+
209
+ Arguments:
210
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
211
+ start_date (date): The start date.
212
+ end_date (date): The end date.
213
+ limit (int): The maximum number of records to return.
214
+ offset (int): The number of records to skip.
215
+
216
+ Returns:
217
+ list<dict>: A list of dictionaries containing the completions data.
218
+ """
219
+ return run_query(
220
+ query=self.queries.get_all_completions_query(),
221
+ params={
222
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
223
+ 'start_date': start_date,
224
+ 'end_date': end_date,
225
+ 'limit': limit,
226
+ 'offset': offset,
227
+ },
228
+ as_dict=True,
229
+ )
230
+
231
+ def get_top_courses_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
232
+ """
233
+ Get the top courses by completion for the given enterprise customer.
234
+
235
+ Arguments:
236
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
237
+ start_date (date): The start date.
238
+ end_date (date): The end date.
239
+
240
+ Returns:
241
+ list<dict>: A list of dictionaries containing the course key, course_title and completion count.
242
+ """
243
+ return run_query(
244
+ query=self.queries.get_top_courses_by_completions_query(),
245
+ params={
246
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
247
+ 'start_date': start_date,
248
+ 'end_date': end_date,
249
+ },
250
+ as_dict=True,
251
+ )
252
+
253
+ def get_top_subjects_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
254
+ """
255
+ Get the top subjects by completions for the given enterprise customer.
256
+
257
+ Arguments:
258
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
259
+ start_date (date): The start date.
260
+ end_date (date): The end date.
261
+
262
+ Returns:
263
+ list<dict>: A list of dictionaries containing the subject and completion count.
264
+ """
265
+ return run_query(
266
+ query=self.queries.get_top_subjects_by_completions_query(),
267
+ params={
268
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
269
+ 'start_date': start_date,
270
+ 'end_date': end_date,
271
+ },
272
+ as_dict=True,
273
+ )
274
+
275
+ def get_completions_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
276
+ """
277
+ Get the completions time series data for the given enterprise customer.
278
+
279
+ Arguments:
280
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
281
+ start_date (date): The start date.
282
+ end_date (date): The end date.
283
+
284
+ Returns:
285
+ list<dict>: A list of dictionaries containing the date and completion count.
286
+ """
287
+ return run_query(
288
+ query=self.queries.get_completions_time_series_data_query(),
289
+ params={
290
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
291
+ 'start_date': start_date,
292
+ 'end_date': end_date,
293
+ },
294
+ as_dict=True,
295
+ )
@@ -5,13 +5,7 @@ from uuid import UUID
5
5
 
6
6
  from rest_framework import serializers
7
7
 
8
- from enterprise_data.admin_analytics.constants import (
9
- Calculation,
10
- EngagementChart,
11
- EnrollmentChart,
12
- Granularity,
13
- ResponseType,
14
- )
8
+ from enterprise_data.admin_analytics.constants import Calculation, Granularity, ResponseType
15
9
  from enterprise_data.models import (
16
10
  EnterpriseAdminLearnerProgress,
17
11
  EnterpriseAdminSummarizeInsights,
@@ -315,51 +309,3 @@ class AdvanceAnalyticsQueryParamSerializer(serializers.Serializer): # pylint: d
315
309
  if value not in self.CALCULATION_CHOICES:
316
310
  raise serializers.ValidationError(f"Calculation must be one of {self.CALCULATION_CHOICES}")
317
311
  return value
318
-
319
-
320
- class AdvanceAnalyticsEnrollmentStatsSerializer(
321
- AdvanceAnalyticsQueryParamSerializer
322
- ): # pylint: disable=abstract-method
323
- """Serializer for validating Advance Analytics Enrollments Stats API"""
324
- CHART_TYPES = [
325
- EnrollmentChart.ENROLLMENTS_OVER_TIME.value,
326
- EnrollmentChart.TOP_COURSES_BY_ENROLLMENTS.value,
327
- EnrollmentChart.TOP_SUBJECTS_BY_ENROLLMENTS.value
328
- ]
329
-
330
- chart_type = serializers.CharField(required=False)
331
-
332
- def validate_chart_type(self, value):
333
- """
334
- Validate the chart_type value.
335
-
336
- Raises:
337
- serializers.ValidationError: If chart_type is not one of the valid choices
338
- """
339
- if value not in self.CHART_TYPES:
340
- raise serializers.ValidationError(f"chart_type must be one of {self.CHART_TYPES}")
341
- return value
342
-
343
-
344
- class AdvanceAnalyticsEngagementStatsSerializer(
345
- AdvanceAnalyticsQueryParamSerializer
346
- ): # pylint: disable=abstract-method
347
- """Serializer for validating Advance Analytics Engagements Stats API"""
348
- CHART_TYPES = [
349
- EngagementChart.ENGAGEMENTS_OVER_TIME.value,
350
- EngagementChart.TOP_COURSES_BY_ENGAGEMENTS.value,
351
- EngagementChart.TOP_SUBJECTS_BY_ENGAGEMENTS.value
352
- ]
353
-
354
- chart_type = serializers.CharField(required=False)
355
-
356
- def validate_chart_type(self, value):
357
- """
358
- Validate the chart_type value.
359
-
360
- Raises:
361
- serializers.ValidationError: If chart_type is not one of the valid choices
362
- """
363
- if value not in self.CHART_TYPES:
364
- raise serializers.ValidationError(f"chart_type must be one of {self.CHART_TYPES}")
365
- return value