edx-enterprise-data 10.16.6__py3-none-any.whl → 10.16.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: edx-enterprise-data
3
- Version: 10.16.6
3
+ Version: 10.16.9
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -1,5 +1,5 @@
1
- edx_enterprise_data-10.16.6.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
2
- enterprise_data/__init__.py,sha256=dZT3Q3ESJQAMbR--mBETUuHta1jjIIigfuOt5mZC_X4,125
1
+ edx_enterprise_data-10.16.9.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
2
+ enterprise_data/__init__.py,sha256=TE8afRufNXv1fzM-rmw0xsaobqx-ZirO7GdcVULfGuw,125
3
3
  enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
4
4
  enterprise_data/clients.py,sha256=glw-fXu3V7rKEpiUBF056gZEdNK4KnWcP9tNYELimRQ,6566
5
5
  enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
@@ -25,7 +25,7 @@ enterprise_data/admin_analytics/database/filters/mixins.py,sha256=FOtOKvcugQC8eo
25
25
  enterprise_data/admin_analytics/database/queries/__init__.py,sha256=IC5TLOr_GnydbrVbl2mWhwO3aUbYeHuDmfPTLmwGhZA,218
26
26
  enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=RejAfiNGr0i3wyNe5bsqFOcdRKCGp-tbqS04ibgLi5I,10393
27
27
  enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=n_RiqraVzYvCsgLaPmpSBUX3cyNEHjSnkNH7n35gC80,10609
28
- enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=ZaJPghTrQvBGsFxfpeR8EE45ujtaYI9R_xkoDDqD2So,4269
28
+ enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=fn45gYBT1gKcBxUf40Tm8Oy6YB2Un8bnmjSgdKnP630,5149
29
29
  enterprise_data/admin_analytics/database/query_filters/__init__.py,sha256=xW9cf5KGpMs33tTlil5gzKq4RxcZVCJZESsrHo2X0E4,182
30
30
  enterprise_data/admin_analytics/database/query_filters/base.py,sha256=XZUC1AIaDPBq0cwh2Xn5wp_DZfsD3HnMMvqFUt7iM2E,2205
31
31
  enterprise_data/admin_analytics/database/query_filters/between.py,sha256=YvAM4WSJSCHb1nCzeJLwku4zkJKHrqnSrEnl7-xMOoA,924
@@ -35,7 +35,7 @@ enterprise_data/admin_analytics/database/tables/__init__.py,sha256=Z-c3P9hqR-dC9
35
35
  enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
36
36
  enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=wAnpNgh1USAQKi86JdEy4KJ_d_IL2fbKKu3ypqi5BCs,15434
37
37
  enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=BwchyH1VJy8Ie-m_ma3bXiKKkNtJhb8A0u37hjocyiU,17049
38
- enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=3xNwSi0wfCyBHcXPd6-9Ujs1NUm8kmZRg_gPrZzp9nQ,3233
38
+ enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=hbxvjrhONXRiR27-NfyM8ldBK0wSU9t7oQuThwaO7UI,5638
39
39
  enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
41
41
  enterprise_data/api/v0/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
@@ -51,7 +51,7 @@ enterprise_data/api/v1/views/analytics_engagements.py,sha256=XHJ_sfGyeamCW4krEaz
51
51
  enterprise_data/api/v1/views/analytics_enrollments.py,sha256=_KBo4RhEmfQXcCOgvowD28WCVJwlc4APuCnRDbAYK9E,6563
52
52
  enterprise_data/api/v1/views/analytics_leaderboard.py,sha256=3dyo7_OhyGEEeibemBrRsUOo0jbM4LbDgV5gw3YnVig,4186
53
53
  enterprise_data/api/v1/views/base.py,sha256=Kkmd5zgEBAhvwS_GoGXSK6lgbDNwSPioYn-QbnizI3w,3416
54
- enterprise_data/api/v1/views/enterprise_admin.py,sha256=3rmFoRxnnQFoOsHDCt8excTJT84NLlhg4QhpdDJLxOM,9129
54
+ enterprise_data/api/v1/views/enterprise_admin.py,sha256=zlufNTdlb_TxBa_zmMqR1911ussXhUxUfqM5bKq1vTI,9717
55
55
  enterprise_data/api/v1/views/enterprise_learner.py,sha256=vRzfaQCEoeq_tEY7KsNZJVzgn7XEWZ1l-n0oUoSVGyU,20093
56
56
  enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
57
57
  enterprise_data/cache/__init__.py,sha256=fiBUploll1kmDy2vCmnNpeZVTD4ewsgtRF14vVs0Rb4,1850
@@ -133,7 +133,7 @@ enterprise_data/tests/test_models.py,sha256=rRFrzjMnnUh1YpVvQMyA1OhFmX6BOCRt28SN
133
133
  enterprise_data/tests/test_utils.py,sha256=3sM3YWEoihHupgwhh0NiI66CbcQPLY4I_W0xjbLG0zg,19694
134
134
  enterprise_data/tests/test_views.py,sha256=UvDRNTxruy5zBK_KgUy2cBMbwlaTW_vkM0-TCXbQZiY,69667
135
135
  enterprise_data/tests/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=qN73YxoD1kAtKsQo94avR0DGMCsJClrpqFxxYC6reqE,15248
136
+ enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=sKduLQq3cJhmxBdg2OCJduYNs46krpdARImRD0yg6qw,15541
137
137
  enterprise_data/tests/admin_analytics/mock_enrollments.py,sha256=n67vb0dQVbNaI1PvEPlo8ljkrlQ5RvnHpR2kVuOk1go,4632
138
138
  enterprise_data/tests/admin_analytics/test_analytics_engagements.py,sha256=gfO6RI2gbDMhOD4p4h7l6sZpisglBreTPtJRqNxIgo8,10440
139
139
  enterprise_data/tests/admin_analytics/test_analytics_enrollments.py,sha256=uFa6gnlf-CthctdYTWsw-pLLOxkELGiq8YFq5CyWFbs,10826
@@ -147,7 +147,7 @@ enterprise_data/tests/api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
147
147
  enterprise_data/tests/api/v1/test_serializers.py,sha256=DwgEHcyOP3oqNUPB2O-NkJGeO_cYs9XJiq7791vJLZE,3682
148
148
  enterprise_data/tests/api/v1/test_views.py,sha256=rLqUHfar0HdBNtz33hQxd_0qUUgr7Ku3KwQSQ1B4Ypg,15213
149
149
  enterprise_data/tests/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
- enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=6SXw7LcMaE-M2VSX8PHaWmOHDGXlqbI2ahNHqyBuPOk,11161
150
+ enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=_bDr9o5OWhe-VvhjTa9gMxSlrDXj-jSVYo5yr8fEUZk,11899
151
151
  enterprise_data_roles/__init__.py,sha256=toCpbypm2uDoWVw29_em9gPFNly8vNUS__C0b4TCqEg,112
152
152
  enterprise_data_roles/admin.py,sha256=QNP0VeWE092vZzpyxOA5UJK1nNGl5e71B1J0RCwo_nU,998
153
153
  enterprise_data_roles/apps.py,sha256=nKi8TyuQ5Q6WGtKs5QeXvUTc3N-YQjKhyBnm2EM3Bng,260
@@ -189,7 +189,7 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=zBj7sDvRLJQbRs
189
189
  enterprise_reporting/tests/test_utils.py,sha256=y4t6w9aKra-ftqtUeHvPwOhje-1npz7auV5o74ya8fE,9523
190
190
  enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
191
191
  enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
192
- edx_enterprise_data-10.16.6.dist-info/METADATA,sha256=RTQfpbQ_R4r9tnEoCAf6JPPvBzXw3v1_vldc9iJ4hwg,1746
193
- edx_enterprise_data-10.16.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
194
- edx_enterprise_data-10.16.6.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
195
- edx_enterprise_data-10.16.6.dist-info/RECORD,,
192
+ edx_enterprise_data-10.16.9.dist-info/METADATA,sha256=dL-d09NGDXjh4ghxY1KkZNZ07jBPeMcC52Q3fF8458k,1746
193
+ edx_enterprise_data-10.16.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
194
+ edx_enterprise_data-10.16.9.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
195
+ edx_enterprise_data-10.16.9.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__ = "10.16.6"
5
+ __version__ = "10.16.9"
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Module containing queries for the skills_daily_rollup_admin_dash table.
3
3
  """
4
+ from ..query_filters import QueryFilters
4
5
 
5
6
 
6
7
  class SkillsDailyRollupAdminDashQueries:
@@ -118,3 +119,31 @@ class SkillsDailyRollupAdminDashQueries:
118
119
  ORDER BY
119
120
  total_completion_count DESC;
120
121
  """
122
+
123
+ @staticmethod
124
+ def get_skills_by_learning_hours(query_filters: QueryFilters, record_count: int = 25):
125
+ """
126
+ Get the query to fetch skills by learning hours for an enterprise customer.
127
+ """
128
+ return f"""
129
+ WITH filtered_data AS (
130
+ SELECT
131
+ skill_name,
132
+ total_learning_time_hours
133
+ FROM
134
+ skills_daily_rollup_admin_dash
135
+ WHERE
136
+ {query_filters.to_sql()}
137
+ )
138
+
139
+ SELECT
140
+ skill_name,
141
+ SUM(total_learning_time_hours) AS learning_hours
142
+ FROM
143
+ filtered_data
144
+ GROUP BY
145
+ skill_name
146
+ ORDER BY
147
+ learning_hours DESC
148
+ LIMIT {record_count};
149
+ """
@@ -4,15 +4,19 @@ Module for interacting with the skills_daily_rollup_admin_dash table.
4
4
  from datetime import date
5
5
  from uuid import UUID
6
6
 
7
+ from enterprise_data.admin_analytics.database.filters.mixins import CommonFiltersMixin
7
8
  from enterprise_data.admin_analytics.database.queries.skills_daily_rollup_admin_dash import (
8
9
  SkillsDailyRollupAdminDashQueries,
9
10
  )
11
+ from enterprise_data.admin_analytics.database.query_filters import EqualQueryFilter
10
12
  from enterprise_data.admin_analytics.database.tables.base import BaseTable
11
13
  from enterprise_data.admin_analytics.database.utils import run_query
12
14
  from enterprise_data.cache.decorators import cache_it
13
15
 
16
+ from ..query_filters import QueryFilters
14
17
 
15
- class SkillsDailyRollupAdminDashTable(BaseTable):
18
+
19
+ class SkillsDailyRollupAdminDashTable(CommonFiltersMixin, BaseTable):
16
20
  """
17
21
  Class for communicating with the skills_daily_rollup_admin_dash table.
18
22
  """
@@ -96,3 +100,68 @@ class SkillsDailyRollupAdminDashTable(BaseTable):
96
100
  },
97
101
  as_dict=True,
98
102
  )
103
+
104
+ def get_skills_by_learning_hours(
105
+ self,
106
+ enterprise_customer_uuid: UUID,
107
+ start_date: date,
108
+ end_date: date,
109
+ course_key: str = None,
110
+ course_type: str = None,
111
+ ):
112
+ """
113
+ Get the skills by learning hours for the given enterprise customer.
114
+
115
+ Arguments:
116
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
117
+ start_date (date): The start date.
118
+ end_date (date): The end date.
119
+ course_key (str): The course key to filter by (optional).
120
+ course_type (str): The course type (OCM or Executive Education) to filter by (optional).
121
+
122
+ Returns:
123
+ list<dict>: A list of dictionaries containing the skill_name, subject_name, count.
124
+ """
125
+ optional_params = {}
126
+ course_key_filter = None
127
+ course_type_filter = None
128
+
129
+ default_params = {
130
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
131
+ 'start_date': start_date,
132
+ 'end_date': end_date,
133
+ }
134
+ query_filters = QueryFilters([
135
+ self.enterprise_customer_uuid_filter('enterprise_customer_uuid'),
136
+ self.date_range_filter(
137
+ column='date',
138
+ start_date_params_key='start_date',
139
+ end_date_params_key='end_date',
140
+ ),
141
+ ])
142
+
143
+ if course_key:
144
+ course_key_filter = EqualQueryFilter(
145
+ column='course_key',
146
+ value_placeholder='course_key',
147
+ )
148
+
149
+ optional_params['course_key'] = course_key
150
+ query_filters.append(course_key_filter)
151
+
152
+ if course_type:
153
+ course_type_filter = EqualQueryFilter(
154
+ column='course_product_line',
155
+ value_placeholder='course_type',
156
+ )
157
+
158
+ optional_params['course_type'] = course_type
159
+ query_filters.append(course_type_filter)
160
+
161
+ params = {**default_params, **optional_params}
162
+
163
+ return run_query(
164
+ query=self.queries.get_skills_by_learning_hours(query_filters),
165
+ params=params,
166
+ as_dict=True,
167
+ )
@@ -180,10 +180,24 @@ class EnterpriseAdminAnalyticsSkillsView(APIView):
180
180
  end_date
181
181
  )
182
182
 
183
+ # TODO: Handle course_key and course_type when they are provided in the request.
184
+ # We have separate tickets to handle this implementation.
185
+ course_key = None
186
+ course_type = None
187
+ with timer('skills_by_learning_hours'):
188
+ skills_by_learning_hours = SkillsDailyRollupAdminDashTable().get_skills_by_learning_hours(
189
+ enterprise_id,
190
+ start_date,
191
+ end_date,
192
+ course_key,
193
+ course_type,
194
+ )
195
+
183
196
  response_data = {
184
197
  "top_skills": skills,
185
198
  "top_skills_by_enrollments": top_skills_by_enrollments,
186
199
  "top_skills_by_completions": top_skills_by_completions,
200
+ "skills_by_learning_hours": skills_by_learning_hours,
187
201
  }
188
202
 
189
203
  return Response(data=response_data, status=HTTP_200_OK)
@@ -470,3 +470,17 @@ TOP_SKILLS_BY_COMPLETIONS = [
470
470
  "count": 15.0
471
471
  },
472
472
  ]
473
+ SKILLS_BY_LEARNING_HOURS = [
474
+ {
475
+ "skill_name": "Python (Programming Language)",
476
+ "learning_hours": 100.0
477
+ },
478
+ {
479
+ "skill_name": "Data Science",
480
+ "learning_hours": 80.0
481
+ },
482
+ {
483
+ "skill_name": "Algorithms",
484
+ "learning_hours": 60.0
485
+ },
486
+ ]
@@ -16,6 +16,7 @@ from enterprise_data.admin_analytics.database.queries import (
16
16
  FactEnrollmentAdminDashQueries,
17
17
  )
18
18
  from enterprise_data.tests.admin_analytics.mock_analytics_data import (
19
+ SKILLS_BY_LEARNING_HOURS,
19
20
  TOP_SKILLS,
20
21
  TOP_SKILLS_BY_COMPLETIONS,
21
22
  TOP_SKILLS_BY_ENROLLMENTS,
@@ -137,8 +138,10 @@ class TestSkillsStatsAPI(JWTTestMixin, APITransactionTestCase):
137
138
  @patch('enterprise_data.api.v1.views.enterprise_admin.SkillsDailyRollupAdminDashTable.get_top_skills')
138
139
  @patch('enterprise_data.api.v1.views.enterprise_admin.SkillsDailyRollupAdminDashTable.get_top_skills_by_enrollment')
139
140
  @patch('enterprise_data.api.v1.views.enterprise_admin.SkillsDailyRollupAdminDashTable.get_top_skills_by_completion')
141
+ @patch('enterprise_data.api.v1.views.enterprise_admin.SkillsDailyRollupAdminDashTable.get_skills_by_learning_hours')
140
142
  def test_get(
141
143
  self,
144
+ mock_get_skills_by_learning_hours,
142
145
  mock_get_top_skills_by_completion,
143
146
  mock_get_top_skills_by_enrollment,
144
147
  mock_get_top_skills,
@@ -151,6 +154,7 @@ class TestSkillsStatsAPI(JWTTestMixin, APITransactionTestCase):
151
154
  mock_get_top_skills.return_value = TOP_SKILLS
152
155
  mock_get_top_skills_by_enrollment.return_value = TOP_SKILLS_BY_ENROLLMENTS
153
156
  mock_get_top_skills_by_completion.return_value = TOP_SKILLS_BY_COMPLETIONS
157
+ mock_get_skills_by_learning_hours.return_value = SKILLS_BY_LEARNING_HOURS
154
158
 
155
159
  response = self.client.get(self.url)
156
160
  assert response.status_code == status.HTTP_200_OK
@@ -210,6 +214,20 @@ class TestSkillsStatsAPI(JWTTestMixin, APITransactionTestCase):
210
214
  "count": 15.0,
211
215
  },
212
216
  ],
217
+ "skills_by_learning_hours": [
218
+ {
219
+ "skill_name": "Python (Programming Language)",
220
+ "learning_hours": 100.0
221
+ },
222
+ {
223
+ "skill_name": "Data Science",
224
+ "learning_hours": 80.0
225
+ },
226
+ {
227
+ "skill_name": "Algorithms",
228
+ "learning_hours": 60.0
229
+ },
230
+ ]
213
231
  }
214
232
 
215
233
  @ddt.data(