edx-enterprise-data 10.7.7__py3-none-any.whl → 10.8.1__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.
- {edx_enterprise_data-10.7.7.dist-info → edx_enterprise_data-10.8.1.dist-info}/METADATA +1 -1
- {edx_enterprise_data-10.7.7.dist-info → edx_enterprise_data-10.8.1.dist-info}/RECORD +14 -13
- enterprise_data/__init__.py +1 -1
- enterprise_data/api/v1/serializers.py +14 -0
- enterprise_data/migrations/0047_enterpriseexecedlcmoduleperformance_avg_after_lo_score_and_more.py +28 -0
- enterprise_data/models.py +3 -0
- enterprise_data/utils.py +19 -0
- enterprise_reporting/send_enterprise_reports.py +13 -3
- enterprise_reporting/tests/test_send_enterprise_reports.py +1 -1
- enterprise_reporting/tests/test_utils.py +1 -0
- enterprise_reporting/utils.py +2 -5
- {edx_enterprise_data-10.7.7.dist-info → edx_enterprise_data-10.8.1.dist-info}/LICENSE +0 -0
- {edx_enterprise_data-10.7.7.dist-info → edx_enterprise_data-10.8.1.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-10.7.7.dist-info → edx_enterprise_data-10.8.1.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,14 @@
|
|
1
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
enterprise_data/__init__.py,sha256=pPBujM0IVxjUhz1lnPdSHkkELYKz27-OefUZyDB8Nu4,124
|
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
|
-
enterprise_data/models.py,sha256=
|
6
|
+
enterprise_data/models.py,sha256=6_rtrxVX-eW7IjJLLFDK712ih-tFqHWzlsPwwTk7XL0,26555
|
7
7
|
enterprise_data/paginators.py,sha256=YPrC5TeXFt-ymenT2H8H2nCbDCnAzJQlH9kFPElRxWE,269
|
8
8
|
enterprise_data/renderers.py,sha256=qggCLZklL9ohVcLHLO1pSecPJSDCCR7e_-PVobl9Lj8,3063
|
9
9
|
enterprise_data/signals.py,sha256=8eqNPnlvmfsKf19lGWv5xTIuBgQIqR8EZSp9UYzC8Rc,1024
|
10
10
|
enterprise_data/urls.py,sha256=bqtKF5OEWEwrNmHG3os-pZNuNsmjlhxEqp7yM4TbPf4,243
|
11
|
-
enterprise_data/utils.py,sha256=
|
11
|
+
enterprise_data/utils.py,sha256=djGuQUnvT8HJMMV60CzcD5BWerPIwiK9uG26bhkpWMg,3518
|
12
12
|
enterprise_data/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
enterprise_data/admin_analytics/constants.py,sha256=-6uLAq5DUeA_rv5eUb9SeqlG3iVWV30qUS8asbK4430,160
|
14
14
|
enterprise_data/admin_analytics/data_loaders.py,sha256=b6RjEIxCol8ETQMY7QfwhqN9eEAvrUN_UldIG7rgsSY,736
|
@@ -30,7 +30,7 @@ enterprise_data/api/v0/serializers.py,sha256=dngZTk6DhRxApchQKCMp1B_c8aVnQtH0NCq
|
|
30
30
|
enterprise_data/api/v0/urls.py,sha256=vzJjqIo_S3AXWs9Us8XTaJc3FnxLbYzAkmLyuDQqum0,699
|
31
31
|
enterprise_data/api/v0/views.py,sha256=4RslZ4NZOU-844bnebEQ71ji2utRY7jEijqC45oQQD0,14380
|
32
32
|
enterprise_data/api/v1/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
|
33
|
-
enterprise_data/api/v1/serializers.py,sha256=
|
33
|
+
enterprise_data/api/v1/serializers.py,sha256=DUhk8cP-JFQmbLR_JNGmmwis9Un5dyvd01kRdmxn8Lk,11866
|
34
34
|
enterprise_data/api/v1/urls.py,sha256=Wl1xLboPg-Lq1ZvjAWf51JKYkHlmx02Kpq1nwfDyS8s,4372
|
35
35
|
enterprise_data/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
36
|
enterprise_data/api/v1/views/analytics_completions.py,sha256=esFbJ5q8ssnm2Mfbc3rZXtiGHF-MeM4KQ4Ft3N7wwHU,6260
|
@@ -106,6 +106,7 @@ enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpris
|
|
106
106
|
enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py,sha256=1aJ0wIu9K2cT3AJdBIHuNCUpJysPWmq_37Ucp5ntEO8,6122
|
107
107
|
enterprise_data/migrations/0045_alter_enterpriseexecedlcmoduleperformance_options_and_more.py,sha256=HJkY2OvuE39ciWgaEescd--ixQhTVrwzbL0_bvNofSo,876
|
108
108
|
enterprise_data/migrations/0046_enterprisegroupmembership.py,sha256=38qfi3EySDLrpP3gDuO_oUl_7rphGPZIrPsCuBhQ_dk,1766
|
109
|
+
enterprise_data/migrations/0047_enterpriseexecedlcmoduleperformance_avg_after_lo_score_and_more.py,sha256=_lHmsJozjV_JEWyUfHDKleOhd53594fOaRhz7M0z-nY,897
|
109
110
|
enterprise_data/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
110
111
|
enterprise_data/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
111
112
|
enterprise_data/settings/test.py,sha256=4-flfrlf81AthGx9wTaT5PscyoOWyhsDDqbzBl-z7Eg,4191
|
@@ -154,8 +155,8 @@ enterprise_reporting/__init__.py,sha256=yQO9ureIxFnl-1a_34H53elDwuAzXrSmhLlzqqD2
|
|
154
155
|
enterprise_reporting/delivery_method.py,sha256=bG-JCGhrK3nuC3P6D88zBRSwDJCbaDxN35nNlXzvoRM,4813
|
155
156
|
enterprise_reporting/external_resource_link_report.py,sha256=jQ6RS0yec0IhAz4wErQ3q8Yn206R7aQbgcR2c803BLA,8066
|
156
157
|
enterprise_reporting/reporter.py,sha256=3wI46qH-CNCUC5r9-Eme1mQdMjwEsFk9myRb-ajzJkM,13807
|
157
|
-
enterprise_reporting/send_enterprise_reports.py,sha256=
|
158
|
-
enterprise_reporting/utils.py,sha256=
|
158
|
+
enterprise_reporting/send_enterprise_reports.py,sha256=W9xc7hu3ZP4zmoIndITc3hdXDbd4A3QEWQN0_ZO1E1A,5270
|
159
|
+
enterprise_reporting/utils.py,sha256=L_ENZYE-UgTy3sHRJSXjN-Hb3qkT-VLAIIqzIu9fpDQ,13745
|
159
160
|
enterprise_reporting/clients/__init__.py,sha256=9xW-Nj1A3JWb9rOWVFdFaDzcyremAS-whVB8DRW_wCY,5121
|
160
161
|
enterprise_reporting/clients/enterprise.py,sha256=-ZKoQTyDLYPLDfC7hWKhJZxVOorWt0kYmFAiOUJkyNM,9853
|
161
162
|
enterprise_reporting/clients/s3.py,sha256=CZ9FgwOGKo-lQmZ4cw8oIqoVmhEtwBb6jfhFqoNHgh4,559
|
@@ -169,12 +170,12 @@ enterprise_reporting/tests/test_delivery_method.py,sha256=Zy169SrKz5zWjysI_RhGuj
|
|
169
170
|
enterprise_reporting/tests/test_enterprise_client.py,sha256=lpWm0muvA3alRjmlRAezE5901C9DU3WiySH4D5-U3qE,1058
|
170
171
|
enterprise_reporting/tests/test_external_link_report.py,sha256=zdnVOD1qtAp9c5EbIPnD9jcoLtW4iKs7gSVklgBK328,7029
|
171
172
|
enterprise_reporting/tests/test_reporter.py,sha256=PTmkGvPjGEjxiyizL88LAKnaWdvZDgOBjL4QStfOdyw,4057
|
172
|
-
enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=
|
173
|
-
enterprise_reporting/tests/test_utils.py,sha256=
|
173
|
+
enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=zBj7sDvRLJQbRsOHwYeOzTGrKx7t7JUq5dLNGASiq7o,1052
|
174
|
+
enterprise_reporting/tests/test_utils.py,sha256=y4t6w9aKra-ftqtUeHvPwOhje-1npz7auV5o74ya8fE,9523
|
174
175
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
175
176
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
176
|
-
edx_enterprise_data-10.
|
177
|
-
edx_enterprise_data-10.
|
178
|
-
edx_enterprise_data-10.
|
179
|
-
edx_enterprise_data-10.
|
180
|
-
edx_enterprise_data-10.
|
177
|
+
edx_enterprise_data-10.8.1.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
178
|
+
edx_enterprise_data-10.8.1.dist-info/METADATA,sha256=PETAn5Cls0D4pVyyxTW0flv7OFqFjBNV6RA44cbivOU,1684
|
179
|
+
edx_enterprise_data-10.8.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
180
|
+
edx_enterprise_data-10.8.1.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
181
|
+
edx_enterprise_data-10.8.1.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -16,6 +16,7 @@ from enterprise_data.models import (
|
|
16
16
|
EnterpriseOffer,
|
17
17
|
EnterpriseSubsidyBudget,
|
18
18
|
)
|
19
|
+
from enterprise_data.utils import calculate_percentage_difference
|
19
20
|
|
20
21
|
|
21
22
|
class EnterpriseLearnerEnrollmentSerializer(serializers.ModelSerializer):
|
@@ -231,6 +232,7 @@ class EnterpriseExecEdLCModulePerformanceSerializer(serializers.ModelSerializer)
|
|
231
232
|
Serializer for EnterpriseExecEdLCModulePerformance model.
|
232
233
|
"""
|
233
234
|
extensions_requested = serializers.SerializerMethodField()
|
235
|
+
avg_lo_percentage_difference = serializers.SerializerMethodField()
|
234
236
|
|
235
237
|
class Meta:
|
236
238
|
model = EnterpriseExecEdLCModulePerformance
|
@@ -240,6 +242,18 @@ class EnterpriseExecEdLCModulePerformanceSerializer(serializers.ModelSerializer)
|
|
240
242
|
"""Return extensions_requested if not None, otherwise return 0"""
|
241
243
|
return obj.extensions_requested if obj.extensions_requested is not None else 0
|
242
244
|
|
245
|
+
def get_avg_lo_percentage_difference(self, obj):
|
246
|
+
"""
|
247
|
+
Return percentage difference between `avg_before_lo_score` and `avg_after_lo_score` if not None,
|
248
|
+
otherwise return None
|
249
|
+
"""
|
250
|
+
if obj.avg_before_lo_score is None or obj.avg_after_lo_score is None:
|
251
|
+
return None
|
252
|
+
return round(
|
253
|
+
calculate_percentage_difference(obj.avg_before_lo_score, obj.avg_after_lo_score),
|
254
|
+
2
|
255
|
+
)
|
256
|
+
|
243
257
|
|
244
258
|
class EnterpriseBudgetSerializer(serializers.ModelSerializer):
|
245
259
|
"""
|
enterprise_data/migrations/0047_enterpriseexecedlcmoduleperformance_avg_after_lo_score_and_more.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Generated by Django 4.2.15 on 2025-02-20 08:08
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('enterprise_data', '0046_enterprisegroupmembership'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AddField(
|
14
|
+
model_name='enterpriseexecedlcmoduleperformance',
|
15
|
+
name='avg_after_lo_score',
|
16
|
+
field=models.DecimalField(decimal_places=6, max_digits=38, null=True),
|
17
|
+
),
|
18
|
+
migrations.AddField(
|
19
|
+
model_name='enterpriseexecedlcmoduleperformance',
|
20
|
+
name='avg_before_lo_score',
|
21
|
+
field=models.DecimalField(decimal_places=6, max_digits=38, null=True),
|
22
|
+
),
|
23
|
+
migrations.AddField(
|
24
|
+
model_name='enterpriseexecedlcmoduleperformance',
|
25
|
+
name='question_name',
|
26
|
+
field=models.CharField(max_length=500, null=True),
|
27
|
+
),
|
28
|
+
]
|
enterprise_data/models.py
CHANGED
@@ -558,6 +558,9 @@ class EnterpriseExecEdLCModulePerformance(models.Model):
|
|
558
558
|
discussion_forum_activities_completed_count = models.PositiveIntegerField(null=True)
|
559
559
|
discussion_forum_activities_total_count = models.PositiveIntegerField(null=True)
|
560
560
|
pass_grade = models.DecimalField(max_digits=38, decimal_places=2, null=True)
|
561
|
+
question_name = models.CharField(max_length=500, null=True)
|
562
|
+
avg_before_lo_score = models.DecimalField(max_digits=38, decimal_places=6, null=True)
|
563
|
+
avg_after_lo_score = models.DecimalField(max_digits=38, decimal_places=6, null=True)
|
561
564
|
|
562
565
|
def __str__(self):
|
563
566
|
"""
|
enterprise_data/utils.py
CHANGED
@@ -114,3 +114,22 @@ def find_first(iterable, condition):
|
|
114
114
|
return next(item for item in iterable if condition(item))
|
115
115
|
except StopIteration:
|
116
116
|
return None
|
117
|
+
|
118
|
+
|
119
|
+
def calculate_percentage_difference(first, second):
|
120
|
+
"""
|
121
|
+
Calculate the percentage difference between two numbers.
|
122
|
+
|
123
|
+
It will calculate the percentage difference between the two numbers using the formula:
|
124
|
+
((second - first) / (first + second)/2) * 100
|
125
|
+
|
126
|
+
Arguments:
|
127
|
+
first (float): The first number.
|
128
|
+
second (float): The second number.
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
float: The percentage difference between the two numbers.
|
132
|
+
"""
|
133
|
+
if first == 0 and second == 0:
|
134
|
+
return 0
|
135
|
+
return ((second - first) / ((first + second) / 2)) * 100
|
@@ -4,13 +4,15 @@ Sends an Enterprise Customer's data file to a configured destination.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
|
7
|
-
|
8
7
|
import argparse
|
8
|
+
import datetime
|
9
9
|
import logging
|
10
10
|
import os
|
11
11
|
import re
|
12
12
|
import sys
|
13
13
|
|
14
|
+
import pytz
|
15
|
+
|
14
16
|
from enterprise_reporting.clients.enterprise import EnterpriseAPIClient
|
15
17
|
from enterprise_reporting.reporter import EnterpriseReportSender
|
16
18
|
from enterprise_reporting.utils import is_current_time_in_schedule
|
@@ -55,11 +57,13 @@ def cleanup_files(enterprise_id):
|
|
55
57
|
os.remove(os.path.join(directory, f))
|
56
58
|
|
57
59
|
|
58
|
-
def should_deliver_report(args, reporting_config):
|
60
|
+
def should_deliver_report(args, reporting_config, current_est_time):
|
59
61
|
"""Given CLI arguments and the reporting configuration, determine if delivery should happen."""
|
60
62
|
valid_data_type = reporting_config['data_type'] in (args.data_type or DATA_TYPES)
|
61
63
|
enterprise_customer_specified = bool(args.enterprise_customer)
|
64
|
+
|
62
65
|
meets_schedule_requirement = is_current_time_in_schedule(
|
66
|
+
current_est_time,
|
63
67
|
reporting_config['frequency'],
|
64
68
|
reporting_config['hour_of_day'],
|
65
69
|
reporting_config['day_of_month'],
|
@@ -101,6 +105,12 @@ def process_reports():
|
|
101
105
|
LOGGER.error(f'The enterprise {args.enterprise_customer} does not have a reporting configuration.')
|
102
106
|
sys.exit(1)
|
103
107
|
|
108
|
+
# We are defining the current est time globally because we want the current time for a job
|
109
|
+
# to remain same thoughout the job. This ensures that a single report is not processed multiple times.
|
110
|
+
# See this comment for more details: https://2u-internal.atlassian.net/browse/ENT-9954?focusedCommentId=5356815
|
111
|
+
est_timezone = pytz.timezone('US/Eastern')
|
112
|
+
current_est_time = datetime.datetime.now(est_timezone)
|
113
|
+
|
104
114
|
error_raised = False
|
105
115
|
for reporting_config in reporting_configs['results']:
|
106
116
|
LOGGER.info('Checking if {}\'s reporting config for {} data in {} format is ready for processing'.format(
|
@@ -109,7 +119,7 @@ def process_reports():
|
|
109
119
|
reporting_config['report_type'],
|
110
120
|
))
|
111
121
|
|
112
|
-
if should_deliver_report(args, reporting_config):
|
122
|
+
if should_deliver_report(args, reporting_config, current_est_time):
|
113
123
|
if send_data(reporting_config):
|
114
124
|
error_raised = True
|
115
125
|
else:
|
@@ -33,4 +33,4 @@ class TestSendEnterpriseReports(unittest.TestCase):
|
|
33
33
|
Command = namedtuple("Command", "data_type enterprise_customer")
|
34
34
|
args = Command('', '')
|
35
35
|
|
36
|
-
assert should_deliver_report(args, reporting_config)
|
36
|
+
assert should_deliver_report(args, reporting_config, current_est_time)
|
@@ -165,6 +165,7 @@ class TestUtilities(unittest.TestCase):
|
|
165
165
|
est_timezone = pytz.timezone('US/Eastern')
|
166
166
|
current_est_time = datetime.datetime.now(est_timezone)
|
167
167
|
assert utils.is_current_time_in_schedule(
|
168
|
+
current_est_time,
|
168
169
|
utils.FREQUENCY_TYPE_DAILY,
|
169
170
|
current_est_time.hour,
|
170
171
|
current_est_time.day,
|
enterprise_reporting/utils.py
CHANGED
@@ -3,7 +3,6 @@ Utility functions for Enterprise Reporting.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
|
6
|
-
import datetime
|
7
6
|
import logging
|
8
7
|
import os
|
9
8
|
import re
|
@@ -16,7 +15,6 @@ from urllib.parse import parse_qs, urlparse
|
|
16
15
|
import boto3
|
17
16
|
import pgpy
|
18
17
|
import pyminizip
|
19
|
-
import pytz
|
20
18
|
from cryptography.fernet import Fernet
|
21
19
|
from fernet_fields.hkdf import derive_fernet_key
|
22
20
|
|
@@ -149,12 +147,11 @@ def send_email_with_attachment(subject, body, from_email, to_email, attachment_d
|
|
149
147
|
LOGGER.debug(result)
|
150
148
|
|
151
149
|
|
152
|
-
def is_current_time_in_schedule(frequency, hour_of_day, day_of_month=None, day_of_week=None):
|
150
|
+
def is_current_time_in_schedule(current_est_time, frequency, hour_of_day, day_of_month=None, day_of_week=None):
|
153
151
|
"""
|
154
152
|
Determine if the current time is in the range specified by this configuration's schedule.
|
155
153
|
"""
|
156
|
-
|
157
|
-
current_est_time = datetime.datetime.now(est_timezone)
|
154
|
+
|
158
155
|
current_hour_of_day = current_est_time.hour
|
159
156
|
current_day_of_week = current_est_time.weekday()
|
160
157
|
current_day_of_month = current_est_time.day
|
File without changes
|
File without changes
|
File without changes
|