edx-enterprise-data 10.11.0__tar.gz → 10.12.0__tar.gz

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 (215) hide show
  1. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/CHANGELOG.rst +8 -0
  2. {edx_enterprise_data-10.11.0/edx_enterprise_data.egg-info → edx_enterprise_data-10.12.0}/PKG-INFO +1 -1
  3. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0/edx_enterprise_data.egg-info}/PKG-INFO +1 -1
  4. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/edx_enterprise_data.egg-info/SOURCES.txt +1 -0
  5. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/__init__.py +1 -1
  6. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/filters/__init__.py +1 -0
  7. edx_enterprise_data-10.12.0/enterprise_data/admin_analytics/database/filters/fact_completion_admin_dash.py +36 -0
  8. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +20 -24
  9. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +92 -36
  10. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/serializers.py +1 -0
  11. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/analytics_completions.py +11 -5
  12. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/enterprise_admin.py +2 -1
  13. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/pre_warm_analytics_cache.py +6 -0
  14. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v1/views/test_enterprise_admin.py +5 -4
  15. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_delivery_method.py +1 -1
  16. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/LICENSE +0 -0
  17. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/MANIFEST.in +0 -0
  18. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/README.md +0 -0
  19. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/edx_enterprise_data.egg-info/dependency_links.txt +0 -0
  20. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/edx_enterprise_data.egg-info/not-zip-safe +0 -0
  21. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/edx_enterprise_data.egg-info/requires.txt +0 -0
  22. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/edx_enterprise_data.egg-info/top_level.txt +0 -0
  23. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/__init__.py +0 -0
  24. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/constants.py +0 -0
  25. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/data_loaders.py +0 -0
  26. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/__init__.py +0 -0
  27. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/filters/base.py +0 -0
  28. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/filters/fact_enrollment_admin_dash.py +0 -0
  29. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/queries/__init__.py +0 -0
  30. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +0 -0
  31. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py +0 -0
  32. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/query_filters/__init__.py +0 -0
  33. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/query_filters/base.py +0 -0
  34. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/query_filters/between.py +0 -0
  35. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/query_filters/equal.py +0 -0
  36. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/query_filters/in_.py +0 -0
  37. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/tables/__init__.py +0 -0
  38. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/tables/base.py +0 -0
  39. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +0 -0
  40. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py +0 -0
  41. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/admin_analytics/database/utils.py +0 -0
  42. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/__init__.py +0 -0
  43. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/urls.py +0 -0
  44. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v0/__init__.py +0 -0
  45. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v0/serializers.py +0 -0
  46. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v0/urls.py +0 -0
  47. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v0/views.py +0 -0
  48. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/__init__.py +0 -0
  49. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/urls.py +0 -0
  50. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/__init__.py +0 -0
  51. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/analytics_engagements.py +0 -0
  52. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/analytics_enrollments.py +0 -0
  53. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/analytics_leaderboard.py +0 -0
  54. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/base.py +0 -0
  55. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/enterprise_learner.py +0 -0
  56. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/api/v1/views/enterprise_offers.py +0 -0
  57. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/apps.py +0 -0
  58. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/cache/__init__.py +0 -0
  59. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/cache/decorators.py +0 -0
  60. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/clients.py +0 -0
  61. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/constants.py +0 -0
  62. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/exceptions.py +0 -0
  63. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/filters.py +0 -0
  64. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/fixtures/enterprise_enrollment.json +0 -0
  65. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/fixtures/enterprise_user.json +0 -0
  66. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/__init__.py +0 -0
  67. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/__init__.py +0 -0
  68. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_dummy_data.py +0 -0
  69. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_dummy_data_lpr_v1.py +0 -0
  70. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_enterprise_enrollment.py +0 -0
  71. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  72. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py +0 -0
  73. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_enterprise_offer.py +0 -0
  74. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/create_enterprise_user.py +0 -0
  75. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/__init__.py +0 -0
  76. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py +0 -0
  77. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py +0 -0
  78. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  79. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_create_enterprise_learner_lpr_v1.py +0 -0
  80. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_create_enterprise_user.py +0 -0
  81. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/management/commands/tests/test_pre_warm_analytics_cache.py +0 -0
  82. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0001_initial.py +0 -0
  83. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0002_auto_20180430_1358.py +0 -0
  84. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0003_auto_20180501_0603.py +0 -0
  85. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0004_auto_20180501_0928.py +0 -0
  86. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0004_auto_20180508_1652.py +0 -0
  87. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0005_auto_20180524_2204.py +0 -0
  88. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0006_auto_20180612_0336.py +0 -0
  89. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0007_auto_20180612_0534.py +0 -0
  90. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0008_auto_20180614_0108.py +0 -0
  91. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0009_auto_20180628_1152.py +0 -0
  92. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0010_enterpriseenrollment_created.py +0 -0
  93. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0011_enterpriseuser.py +0 -0
  94. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0012_auto_20180831_1930.py +0 -0
  95. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0013_auto_20180831_1931.py +0 -0
  96. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0014_enterpriseuser_created.py +0 -0
  97. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0015_auto_20180907_1757.py +0 -0
  98. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0016_auto_20180924_2138.py +0 -0
  99. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0017_enterpriseenrollment_unenrollment_timestamp.py +0 -0
  100. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0018_enterprisedatafeaturerole_enterprisedataroleassignment.py +0 -0
  101. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0019_add_enterprise_data_feature_roles.py +0 -0
  102. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0020_add_role_based_access_control_switch.py +0 -0
  103. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0021_auto_20190329_1241.py +0 -0
  104. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0022_remove_role_based_access_control_switch.py +0 -0
  105. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0023_enterpriselearner_enterpriselearnerenrollment.py +0 -0
  106. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0024_auto_20210602_1811.py +0 -0
  107. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0025_auto_20210703_1854.py +0 -0
  108. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0026_auto_20210916_0414.py +0 -0
  109. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0027_enterpriselearnerenrollment_total_learning_time_seconds.py +0 -0
  110. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0028_enterpriselearnerenrollment_offer_id.py +0 -0
  111. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0029_enterpriseoffer.py +0 -0
  112. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0030_auto_20230609_1353.py +0 -0
  113. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0031_auto_20230615_0705.py +0 -0
  114. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0032_auto_20230704_0818.py +0 -0
  115. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0033_enterpriseadminlearnerprogress_enterpriseadminsummarizeinsights.py +0 -0
  116. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0034_auto_20230907_0834.py +0 -0
  117. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0035_auto_20230907_1154.py +0 -0
  118. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0036_enterprisesubsidybudget_subsidy_access_policy_display_name.py +0 -0
  119. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0037_alter_enterpriseenrollment_consent_granted.py +0 -0
  120. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0038_enterpriseoffer_export_timestamp.py +0 -0
  121. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0039_auto_20240212_1403.py +0 -0
  122. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpriselearnerenrollment_enterprise_enrollment_id.py +0 -0
  123. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py +0 -0
  124. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0045_alter_enterpriseexecedlcmoduleperformance_options_and_more.py +0 -0
  125. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0046_enterprisegroupmembership.py +0 -0
  126. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0047_enterpriseexecedlcmoduleperformance_avg_after_lo_score_and_more.py +0 -0
  127. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/0048_alter_enterpriseexecedlcmoduleperformance_avg_after_lo_score_and_more.py +0 -0
  128. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/migrations/__init__.py +0 -0
  129. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/models.py +0 -0
  130. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/paginators.py +0 -0
  131. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/renderers.py +0 -0
  132. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/settings/__init__.py +0 -0
  133. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/settings/test.py +0 -0
  134. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/signals.py +0 -0
  135. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/__init__.py +0 -0
  136. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/__init__.py +0 -0
  137. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/mock_analytics_data.py +0 -0
  138. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -0
  139. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/test_analytics_engagements.py +0 -0
  140. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +0 -0
  141. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py +0 -0
  142. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/test_data_loaders.py +0 -0
  143. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/admin_analytics/test_enterprise_completions.py +0 -0
  144. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/__init__.py +0 -0
  145. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v0/__init__.py +0 -0
  146. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v0/test_serializers.py +0 -0
  147. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v1/__init__.py +0 -0
  148. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v1/test_serializers.py +0 -0
  149. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v1/test_views.py +0 -0
  150. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/api/v1/views/__init__.py +0 -0
  151. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/factories.py +0 -0
  152. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/mixins.py +0 -0
  153. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/test_clients.py +0 -0
  154. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/test_filters.py +0 -0
  155. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/test_models.py +0 -0
  156. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/test_utils.py +0 -0
  157. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/tests/test_views.py +0 -0
  158. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/urls.py +0 -0
  159. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data/utils.py +0 -0
  160. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/__init__.py +0 -0
  161. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/admin.py +0 -0
  162. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/apps.py +0 -0
  163. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/constants.py +0 -0
  164. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0001_initial.py +0 -0
  165. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0002_add_enterprise_data_feature_roles.py +0 -0
  166. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0003_add_role_based_access_control_switch.py +0 -0
  167. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0004_enterprisedataroleassignment_enterprise_id.py +0 -0
  168. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0005_turn_on_role_based_access_control_switch.py +0 -0
  169. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0006_remove_role_based_access_control_switch.py +0 -0
  170. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/0007_enterprisedataroleassignment_applies_to_all_contexts.py +0 -0
  171. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/migrations/__init__.py +0 -0
  172. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/models.py +0 -0
  173. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/rules.py +0 -0
  174. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/tests/__init__.py +0 -0
  175. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/tests/factories.py +0 -0
  176. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_data_roles/tests/test_models.py +0 -0
  177. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/__init__.py +0 -0
  178. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/clients/__init__.py +0 -0
  179. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/clients/enterprise.py +0 -0
  180. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/clients/s3.py +0 -0
  181. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/clients/snowflake.py +0 -0
  182. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/clients/vertica.py +0 -0
  183. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/constants.py +0 -0
  184. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/delivery_method.py +0 -0
  185. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/external_resource_link_report.py +0 -0
  186. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/fixtures/__init__.py +0 -0
  187. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/fixtures/enterprise_customer_reporting.json +0 -0
  188. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/reporter.py +0 -0
  189. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/send_enterprise_reports.py +0 -0
  190. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/__init__.py +0 -0
  191. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_clients.py +0 -0
  192. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_enterprise_client.py +0 -0
  193. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_external_link_report.py +0 -0
  194. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_reporter.py +0 -0
  195. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_send_enterprise_reports.py +0 -0
  196. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_utils.py +0 -0
  197. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/test_vertica_client.py +0 -0
  198. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/tests/utils.py +0 -0
  199. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/enterprise_reporting/utils.py +0 -0
  200. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/base.in +0 -0
  201. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/base.txt +0 -0
  202. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/ci.txt +0 -0
  203. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/common_constraints.txt +0 -0
  204. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/constraints.txt +0 -0
  205. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/dev.txt +0 -0
  206. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/django.txt +0 -0
  207. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/pip.txt +0 -0
  208. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/pip_tools.txt +0 -0
  209. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/quality.txt +0 -0
  210. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/reporting.in +0 -0
  211. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/test-master.txt +0 -0
  212. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/test-reporting.txt +0 -0
  213. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/requirements/test.txt +0 -0
  214. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/setup.cfg +0 -0
  215. {edx_enterprise_data-10.11.0 → edx_enterprise_data-10.12.0}/setup.py +0 -0
@@ -15,6 +15,14 @@ Unreleased
15
15
  ----------
16
16
 
17
17
  =========================
18
+ [10.12.0] - 2025-04-09
19
+ ---------------------
20
+ * feat: Added the ability to filter enrollments by group_uuid in the enterprise completions API
21
+
22
+ [10.11.1] - 2025-04-08
23
+ ---------------------
24
+ * fix: Fixed a bug in group_uuid based filtering.
25
+
18
26
  [10.11.0] - 2025-03-25
19
27
  ---------------------
20
28
  * feat: Added the ability to filter enrollments by group_uuid in the enterprise enrollments API.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: edx-enterprise-data
3
- Version: 10.11.0
3
+ Version: 10.12.0
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: edx-enterprise-data
3
- Version: 10.11.0
3
+ Version: 10.12.0
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -28,6 +28,7 @@ enterprise_data/admin_analytics/database/__init__.py
28
28
  enterprise_data/admin_analytics/database/utils.py
29
29
  enterprise_data/admin_analytics/database/filters/__init__.py
30
30
  enterprise_data/admin_analytics/database/filters/base.py
31
+ enterprise_data/admin_analytics/database/filters/fact_completion_admin_dash.py
31
32
  enterprise_data/admin_analytics/database/filters/fact_enrollment_admin_dash.py
32
33
  enterprise_data/admin_analytics/database/queries/__init__.py
33
34
  enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py
@@ -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.11.0"
5
+ __version__ = "10.12.0"
@@ -2,4 +2,5 @@
2
2
  Query Filters for database tables.
3
3
  """
4
4
 
5
+ from .fact_completion_admin_dash import FactCompletionAdminDashFilters
5
6
  from .fact_enrollment_admin_dash import FactEnrollmentAdminDashFilters
@@ -0,0 +1,36 @@
1
+ """
2
+ Query filters for enrollments table.
3
+ """
4
+ from enterprise_data.admin_analytics.database.filters.base import BaseFilter
5
+ from enterprise_data.admin_analytics.database.query_filters import BetweenQueryFilter, EqualQueryFilter
6
+
7
+
8
+ class FactCompletionAdminDashFilters(BaseFilter):
9
+ """
10
+ Query filters for completions data in enrollments table.
11
+ """
12
+ @staticmethod
13
+ def passed_date_range_filter(
14
+ start_date_params_key: str, end_date_params_key: str
15
+ ) -> BetweenQueryFilter:
16
+ """
17
+ Filter by passed date to be in the given range.
18
+
19
+ Arguments:
20
+ start_date_params_key (str): The start date key against which value will be passed in the query.
21
+ end_date_params_key (str): The end date key against which value will be passed in the query.
22
+ """
23
+ return BetweenQueryFilter(
24
+ column='passed_date',
25
+ range_placeholders=(start_date_params_key, end_date_params_key),
26
+ )
27
+
28
+ @staticmethod
29
+ def has_passed_filter() -> EqualQueryFilter:
30
+ """
31
+ Filter by has passed with fixed value 1.
32
+ """
33
+ return EqualQueryFilter(
34
+ column='has_passed',
35
+ value=1
36
+ )
@@ -70,17 +70,15 @@ class FactEnrollmentAdminDashQueries:
70
70
  """
71
71
 
72
72
  @staticmethod
73
- def get_completion_count_query():
73
+ def get_completion_count_query(query_filters: QueryFilters) -> str:
74
74
  """
75
75
  Get the query to fetch the completion count.
76
76
  """
77
- return """
77
+ return f"""
78
78
  SELECT
79
79
  SUM(has_passed) as completions
80
80
  FROM fact_enrollment_admin_dash
81
- WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
82
- has_passed=1 AND
83
- passed_date BETWEEN %(start_date)s AND %(end_date)s;
81
+ WHERE {query_filters.to_sql()};
84
82
  """
85
83
 
86
84
  @staticmethod
@@ -94,7 +92,7 @@ class FactEnrollmentAdminDashQueries:
94
92
  FROM fact_engagement_admin_dash
95
93
  WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
96
94
  activity_date BETWEEN %(start_date)s AND %(end_date)s;
97
- """
95
+ """
98
96
 
99
97
  @staticmethod
100
98
  def get_top_courses_by_enrollments_query(query_filters: QueryFilters, record_count: int = 10) -> str:
@@ -183,27 +181,28 @@ class FactEnrollmentAdminDashQueries:
183
181
  """
184
182
 
185
183
  @staticmethod
186
- def get_all_completions_query():
184
+ def get_all_completions_query(
185
+ query_filters: QueryFilters,
186
+ ) -> str:
187
187
  """
188
188
  Get the query to fetch all completions.
189
189
  """
190
- return """
190
+ return f"""
191
191
  SELECT email, course_title, course_subject, enroll_type, passed_date
192
192
  FROM fact_enrollment_admin_dash
193
- WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
194
- has_passed=1 AND
195
- passed_date BETWEEN %(start_date)s AND %(end_date)s
193
+ WHERE {query_filters.to_sql()}
196
194
  ORDER BY passed_date DESC LIMIT %(limit)s OFFSET %(offset)s
197
195
  """
198
196
 
199
197
  @staticmethod
200
- def get_top_courses_by_completions_query(record_count=10):
198
+ def get_top_courses_by_completions_query(query_filters: QueryFilters, record_count=10) -> str:
201
199
  """
202
200
  Get the query to fetch the completion count by courses.
203
201
 
204
202
  Query should fetch the top N courses by completion count. Where N is the value of record_count.
205
203
 
206
204
  Arguments:
205
+ query_filters (QueryFilters): List of query filters.
207
206
  record_count (int): Number of records to fetch.
208
207
 
209
208
  Returns:
@@ -217,9 +216,7 @@ class FactEnrollmentAdminDashQueries:
217
216
  enroll_type,
218
217
  passed_date
219
218
  FROM fact_enrollment_admin_dash
220
- WHERE has_passed = 1 AND
221
- enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
222
- passed_date BETWEEN %(start_date)s AND %(end_date)s
219
+ WHERE {query_filters.to_sql()}
223
220
  ),
224
221
  top_10_courses AS (
225
222
  SELECT
@@ -243,13 +240,14 @@ class FactEnrollmentAdminDashQueries:
243
240
  """
244
241
 
245
242
  @staticmethod
246
- def get_top_subjects_by_completions_query(record_count=10):
243
+ def get_top_subjects_by_completions_query(query_filters: QueryFilters, record_count=10) -> str:
247
244
  """
248
245
  Get the query to fetch the completion count by subjects.
249
246
 
250
247
  Query should fetch the top N subjects by completion count. Where N is the value of record_count.
251
248
 
252
249
  Arguments:
250
+ query_filters (QueryFilters): List of query filters.
253
251
  record_count (int): Number of records to fetch.
254
252
 
255
253
  Returns:
@@ -262,9 +260,7 @@ class FactEnrollmentAdminDashQueries:
262
260
  enroll_type,
263
261
  passed_date
264
262
  FROM fact_enrollment_admin_dash
265
- WHERE has_passed = 1 AND
266
- enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
267
- passed_date BETWEEN %(start_date)s AND %(end_date)s
263
+ WHERE {query_filters.to_sql()}
268
264
  ),
269
265
  top_10_subjects AS (
270
266
  SELECT
@@ -287,7 +283,9 @@ class FactEnrollmentAdminDashQueries:
287
283
  """
288
284
 
289
285
  @staticmethod
290
- def get_completions_time_series_data_query():
286
+ def get_completions_time_series_data_query(
287
+ query_filters: QueryFilters,
288
+ ) -> str:
291
289
  """
292
290
  Get the query to fetch the completion time series data.
293
291
 
@@ -296,12 +294,10 @@ class FactEnrollmentAdminDashQueries:
296
294
  Returns:
297
295
  (str): Query to fetch the completion time series data.
298
296
  """
299
- return """
297
+ return f"""
300
298
  SELECT passed_date, enroll_type, count(course_key) as completion_count
301
299
  FROM fact_enrollment_admin_dash
302
- WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
303
- has_passed=1 AND
304
- passed_date BETWEEN %(start_date)s AND %(end_date)s
300
+ WHERE {query_filters.to_sql()}
305
301
  GROUP BY passed_date, enroll_type
306
302
  ORDER BY passed_date;
307
303
  """
@@ -10,7 +10,7 @@ from enterprise_data.cache.decorators import cache_it
10
10
  from enterprise_data.clients import EnterpriseApiClient
11
11
  from enterprise_data.exceptions import EnterpriseApiClientException
12
12
 
13
- from ..filters import FactEnrollmentAdminDashFilters
13
+ from ..filters import FactCompletionAdminDashFilters, FactEnrollmentAdminDashFilters
14
14
  from ..queries import FactEnrollmentAdminDashQueries
15
15
  from ..query_filters import INQueryFilter, QueryFilters
16
16
  from ..utils import run_query
@@ -25,6 +25,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
25
25
  """
26
26
  queries = FactEnrollmentAdminDashQueries()
27
27
  filters = FactEnrollmentAdminDashFilters()
28
+ completion_filters = FactCompletionAdminDashFilters()
28
29
 
29
30
  def __get_enterprise_user_query_filter( # pylint: disable=inconsistent-return-statements
30
31
  self, group_uuid: Optional[UUID],
@@ -52,7 +53,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
52
53
  enterprise_customer_uuid,
53
54
  )
54
55
  else:
55
- params = {f'eu_{i}': i for i in range(len(learners_in_group))}
56
+ params = {f'eu_{i}': enterprise_user_id for i, enterprise_user_id in enumerate(learners_in_group)}
56
57
  return self.filters.enterprise_user_id_in_filter(list(params.keys())), params
57
58
 
58
59
  def __get_common_query_filters(
@@ -92,6 +93,45 @@ class FactEnrollmentAdminDashTable(BaseTable):
92
93
 
93
94
  return query_filters, params
94
95
 
96
+ def __get_common_query_filters_for_completion(
97
+ self, enterprise_customer_uuid: UUID,
98
+ group_uuid: Optional[UUID],
99
+ start_date: date,
100
+ end_date: date,
101
+ ) -> Tuple[QueryFilters, dict]:
102
+ """
103
+ Utility method to get query filters common in most usages below.
104
+
105
+ This will return a tuple containing the query filters list and the dictionary of query parameters that
106
+ will be used in the query.
107
+
108
+ It will contain the following query filters.
109
+ 1. enterprise_customer_uuid filter to filter records for an enterprise customer.
110
+ 2. enrollment_date range filter to filter records by enrollment date.
111
+ 3. group_uuid filter to filter records for learners who belong to the given group.
112
+ 4. has_passed filter to filter records for successful completions.
113
+ """
114
+ query_filters = QueryFilters([
115
+ self.filters.enterprise_customer_uuid_filter('enterprise_customer_uuid'),
116
+ self.completion_filters.passed_date_range_filter('start_date', 'end_date'),
117
+ self.completion_filters.has_passed_filter(),
118
+ ])
119
+ params = {
120
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
121
+ 'start_date': start_date,
122
+ 'end_date': end_date,
123
+ }
124
+
125
+ response = self.__get_enterprise_user_query_filter(
126
+ group_uuid, enterprise_customer_uuid
127
+ )
128
+ if response is not None:
129
+ enterprise_user_id_in_filter, enterprise_user_id_params = response
130
+ query_filters.append(enterprise_user_id_in_filter)
131
+ params.update(enterprise_user_id_params)
132
+
133
+ return query_filters, params
134
+
95
135
  def get_top_enterprises(self, count=10):
96
136
  """
97
137
  Get the top enterprises by enrollments.
@@ -232,27 +272,31 @@ class FactEnrollmentAdminDashTable(BaseTable):
232
272
  return tuple(results[0])
233
273
 
234
274
  @cache_it()
235
- def get_completion_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
275
+ def get_completion_count(
276
+ self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
277
+ ):
236
278
  """
237
279
  Get the completion count for the given enterprise customer.
238
280
 
239
281
  Arguments:
240
282
  enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
283
+ group_uuid (UUID): The UUID of the group.
241
284
  start_date (date): The start date.
242
285
  end_date (date): The end date.
243
286
 
244
287
  Returns:
245
288
  int: The completion count.
246
289
  """
290
+ query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
291
+ enterprise_customer_uuid, group_uuid, start_date, end_date
292
+ )
247
293
  results = run_query(
248
- query=self.queries.get_completion_count_query(),
249
- params={
250
- 'enterprise_customer_uuid': enterprise_customer_uuid,
251
- 'start_date': start_date,
252
- 'end_date': end_date,
253
- }
294
+ query=self.queries.get_completion_count_query(query_filters),
295
+ params=query_filter_params,
296
+ as_dict=False,
254
297
  )
255
- if not results:
298
+ # Handle empty results defensively
299
+ if not results or not results[0] or len(results[0]) == 0:
256
300
  return 0
257
301
 
258
302
  return int(results[0][0] or 0)
@@ -347,7 +391,13 @@ class FactEnrollmentAdminDashTable(BaseTable):
347
391
 
348
392
  @cache_it()
349
393
  def get_all_completions(
350
- self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
394
+ self,
395
+ enterprise_customer_uuid: UUID,
396
+ group_uuid: Optional[UUID],
397
+ start_date: date,
398
+ end_date: date,
399
+ limit: int,
400
+ offset: int,
351
401
  ):
352
402
  """
353
403
  Get all completions for the given enterprise customer.
@@ -355,6 +405,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
355
405
  Arguments:
356
406
  enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
357
407
  start_date (date): The start date.
408
+ group_uuid (UUID): The UUID of the group.
358
409
  end_date (date): The end date.
359
410
  limit (int): The maximum number of records to return.
360
411
  offset (int): The number of records to skip.
@@ -362,12 +413,13 @@ class FactEnrollmentAdminDashTable(BaseTable):
362
413
  Returns:
363
414
  list<dict>: A list of dictionaries containing the completions data.
364
415
  """
416
+ query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
417
+ enterprise_customer_uuid, group_uuid, start_date, end_date
418
+ )
365
419
  return run_query(
366
- query=self.queries.get_all_completions_query(),
420
+ query=self.queries.get_all_completions_query(query_filters),
367
421
  params={
368
- 'enterprise_customer_uuid': enterprise_customer_uuid,
369
- 'start_date': start_date,
370
- 'end_date': end_date,
422
+ **query_filter_params,
371
423
  'limit': limit,
372
424
  'offset': offset,
373
425
  },
@@ -375,7 +427,9 @@ class FactEnrollmentAdminDashTable(BaseTable):
375
427
  )
376
428
 
377
429
  @cache_it()
378
- def get_top_courses_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
430
+ def get_top_courses_by_completions(
431
+ self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
432
+ ):
379
433
  """
380
434
  Get the top courses by completion for the given enterprise customer.
381
435
 
@@ -387,18 +441,19 @@ class FactEnrollmentAdminDashTable(BaseTable):
387
441
  Returns:
388
442
  list<dict>: A list of dictionaries containing the course key, course_title and completion count.
389
443
  """
444
+ query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
445
+ enterprise_customer_uuid, group_uuid, start_date, end_date
446
+ )
390
447
  return run_query(
391
- query=self.queries.get_top_courses_by_completions_query(),
392
- params={
393
- 'enterprise_customer_uuid': enterprise_customer_uuid,
394
- 'start_date': start_date,
395
- 'end_date': end_date,
396
- },
448
+ query=self.queries.get_top_courses_by_completions_query(query_filters),
449
+ params=query_filter_params,
397
450
  as_dict=True,
398
451
  )
399
452
 
400
453
  @cache_it()
401
- def get_top_subjects_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
454
+ def get_top_subjects_by_completions(
455
+ self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
456
+ ):
402
457
  """
403
458
  Get the top subjects by completions for the given enterprise customer.
404
459
 
@@ -410,35 +465,36 @@ class FactEnrollmentAdminDashTable(BaseTable):
410
465
  Returns:
411
466
  list<dict>: A list of dictionaries containing the subject and completion count.
412
467
  """
468
+ query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
469
+ enterprise_customer_uuid, group_uuid, start_date, end_date
470
+ )
413
471
  return run_query(
414
- query=self.queries.get_top_subjects_by_completions_query(),
415
- params={
416
- 'enterprise_customer_uuid': enterprise_customer_uuid,
417
- 'start_date': start_date,
418
- 'end_date': end_date,
419
- },
472
+ query=self.queries.get_top_subjects_by_completions_query(query_filters),
473
+ params=query_filter_params,
420
474
  as_dict=True,
421
475
  )
422
476
 
423
477
  @cache_it()
424
- def get_completions_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
478
+ def get_completions_time_series_data(
479
+ self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
480
+ ):
425
481
  """
426
482
  Get the completions time series data for the given enterprise customer.
427
483
 
428
484
  Arguments:
429
485
  enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
486
+ group_uuid (UUID): The UUID of the group.
430
487
  start_date (date): The start date.
431
488
  end_date (date): The end date.
432
489
 
433
490
  Returns:
434
491
  list<dict>: A list of dictionaries containing the date and completion count.
435
492
  """
493
+ query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
494
+ enterprise_customer_uuid, group_uuid, start_date, end_date
495
+ )
436
496
  return run_query(
437
- query=self.queries.get_completions_time_series_data_query(),
438
- params={
439
- 'enterprise_customer_uuid': enterprise_customer_uuid,
440
- 'start_date': start_date,
441
- 'end_date': end_date,
442
- },
497
+ query=self.queries.get_completions_time_series_data_query(query_filters),
498
+ params=query_filter_params,
443
499
  as_dict=True,
444
500
  )
@@ -262,6 +262,7 @@ class AdminAnalyticsAggregatesQueryParamsSerializer(serializers.Serializer): #
262
262
  response_type = serializers.CharField(required=False)
263
263
  page = serializers.IntegerField(required=False)
264
264
  chart_type = serializers.CharField(required=False)
265
+ group_uuid = serializers.UUIDField(required=False)
265
266
 
266
267
  def validate(self, attrs):
267
268
  """
@@ -51,10 +51,12 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
51
51
  # get values from query params or use default values
52
52
  start_date = serializer.data.get('start_date', min_enrollment_date)
53
53
  end_date = serializer.data.get('end_date', date.today())
54
+ group_uuid = serializer.data.get('group_uuid')
54
55
  page = serializer.data.get('page', 1)
55
56
  page_size = serializer.data.get('page_size', 100)
56
57
  completions = FactEnrollmentAdminDashTable().get_all_completions(
57
58
  enterprise_customer_uuid=enterprise_uuid,
59
+ group_uuid=group_uuid,
58
60
  start_date=start_date,
59
61
  end_date=end_date,
60
62
  limit=page_size,
@@ -62,6 +64,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
62
64
  )
63
65
  total_count = FactEnrollmentAdminDashTable().get_completion_count(
64
66
  enterprise_customer_uuid=enterprise_uuid,
67
+ group_uuid=group_uuid,
65
68
  start_date=start_date,
66
69
  end_date=end_date,
67
70
  )
@@ -79,7 +82,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
79
82
 
80
83
  return StreamingHttpResponse(
81
84
  IndividualCompletionsCSVRenderer().render(self._stream_serialized_data(
82
- enterprise_uuid, start_date, end_date, total_count
85
+ enterprise_uuid, group_uuid, start_date, end_date, total_count
83
86
  )),
84
87
  content_type="text/csv",
85
88
  headers={"Content-Disposition": f'attachment; filename="{filename}"'},
@@ -94,7 +97,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
94
97
  )
95
98
 
96
99
  @staticmethod
97
- def _stream_serialized_data(enterprise_uuid, start_date, end_date, total_count, page_size=50000):
100
+ def _stream_serialized_data(enterprise_uuid, group_uuid, start_date, end_date, total_count, page_size=50000):
98
101
  """
99
102
  Stream the serialized data.
100
103
  """
@@ -102,6 +105,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
102
105
  while offset < total_count:
103
106
  completions = FactEnrollmentAdminDashTable().get_all_completions(
104
107
  enterprise_customer_uuid=enterprise_uuid,
108
+ group_uuid=group_uuid,
105
109
  start_date=start_date,
106
110
  end_date=end_date,
107
111
  limit=page_size,
@@ -133,16 +137,18 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
133
137
  # get values from query params or use default
134
138
  start_date = serializer.data.get('start_date', min_enrollment_date)
135
139
  end_date = serializer.data.get('end_date', date.today())
140
+ group_uuid = serializer.data.get('group_uuid')
141
+
136
142
  with timer('construct_completion_all_stats'):
137
143
  data = {
138
144
  'completions_over_time': FactEnrollmentAdminDashTable().get_completions_time_series_data(
139
- enterprise_uuid, start_date, end_date
145
+ enterprise_uuid, group_uuid, start_date, end_date
140
146
  ),
141
147
  'top_courses_by_completions': FactEnrollmentAdminDashTable().get_top_courses_by_completions(
142
- enterprise_uuid, start_date, end_date,
148
+ enterprise_uuid, group_uuid, start_date, end_date,
143
149
  ),
144
150
  'top_subjects_by_completions': FactEnrollmentAdminDashTable().get_top_subjects_by_completions(
145
- enterprise_uuid, start_date, end_date,
151
+ enterprise_uuid, group_uuid, start_date, end_date,
146
152
  ),
147
153
  }
148
154
  return Response(data)
@@ -108,12 +108,13 @@ class EnterpriseAdminAnalyticsAggregatesView(APIView):
108
108
  'start_date', min_enrollment_date
109
109
  )
110
110
  end_date = serializer.data.get('end_date', datetime.today())
111
+ group_uuid = serializer.data.get('group_uuid', None)
111
112
 
112
113
  enrolls, courses = FactEnrollmentAdminDashTable().get_enrollment_and_course_count(
113
114
  enterprise_id, start_date, end_date,
114
115
  )
115
116
  completions = FactEnrollmentAdminDashTable().get_completion_count(
116
- enterprise_id, start_date, end_date,
117
+ enterprise_id, group_uuid, start_date, end_date,
117
118
  )
118
119
  hours, sessions = FactEngagementAdminDashTable().get_learning_hours_and_daily_sessions(
119
120
  enterprise_id, start_date, end_date,
@@ -56,6 +56,7 @@ class Command(BaseCommand):
56
56
  )
57
57
  enterprise_enrollment_table.get_completion_count(
58
58
  enterprise_customer_uuid=enterprise_customer_uuid,
59
+ group_uuid=None,
59
60
  start_date=start_date,
60
61
  end_date=end_date,
61
62
  )
@@ -95,6 +96,7 @@ class Command(BaseCommand):
95
96
  page_size = 100
96
97
  enterprise_enrollment_table.get_all_completions(
97
98
  enterprise_customer_uuid=enterprise_customer_uuid,
99
+ group_uuid=None,
98
100
  start_date=start_date,
99
101
  end_date=end_date,
100
102
  limit=page_size,
@@ -102,21 +104,25 @@ class Command(BaseCommand):
102
104
  )
103
105
  enterprise_enrollment_table.get_completion_count(
104
106
  enterprise_customer_uuid=enterprise_customer_uuid,
107
+ group_uuid=None,
105
108
  start_date=start_date,
106
109
  end_date=end_date,
107
110
  )
108
111
  enterprise_enrollment_table.get_top_courses_by_completions(
109
112
  enterprise_customer_uuid=enterprise_customer_uuid,
113
+ group_uuid=None,
110
114
  start_date=start_date,
111
115
  end_date=end_date,
112
116
  )
113
117
  enterprise_enrollment_table.get_top_subjects_by_completions(
114
118
  enterprise_customer_uuid=enterprise_customer_uuid,
119
+ group_uuid=None,
115
120
  start_date=start_date,
116
121
  end_date=end_date,
117
122
  )
118
123
  enterprise_enrollment_table.get_completions_time_series_data(
119
124
  enterprise_customer_uuid=enterprise_customer_uuid,
125
+ group_uuid=None,
120
126
  start_date=start_date,
121
127
  end_date=end_date,
122
128
  )
@@ -62,6 +62,10 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
62
62
  """
63
63
  mock implementation of run_query.
64
64
  """
65
+ # Check if this is the completion_count_query being called with query_filters
66
+ if hasattr(query, '__name__') and query.__name__ == 'get_completion_count_query':
67
+ return [[50]]
68
+
65
69
  mock_responses = {
66
70
  self.enrollment_queries.get_enrollment_date_range_query(): [[
67
71
  datetime.strptime('2021-01-01', "%Y-%m-%d"),
@@ -70,15 +74,12 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
70
74
  self.enrollment_queries.get_enrollment_and_course_count_query(): [[
71
75
  100, 10
72
76
  ]],
73
- self.enrollment_queries.get_completion_count_query(): [[
74
- 50
75
- ]],
76
77
  self.engagement_queries.get_learning_hours_and_daily_sessions_query(): [[
77
78
  100, 10
78
79
  ]],
79
80
  'SELECT MAX(created) FROM enterprise_learner_enrollment': [[datetime.strptime('2021-01-01', "%Y-%m-%d")]]
80
81
  }
81
- return mock_responses[query]
82
+ return mock_responses.get(query, [[]])
82
83
 
83
84
  def test_get_admin_analytics_aggregates(self):
84
85
  """
@@ -5,8 +5,8 @@ Test delivery methods.
5
5
  import unittest
6
6
 
7
7
  import ddt
8
+ from mock import MagicMock, patch
8
9
 
9
- from mock import patch, MagicMock
10
10
  from enterprise_reporting.delivery_method import SFTPDeliveryMethod, SMTPDeliveryMethod
11
11
  from enterprise_reporting.utils import encrypt_string
12
12