edx-enterprise-data 10.6.1__tar.gz → 10.7.1__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 (202) hide show
  1. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/CHANGELOG.rst +9 -0
  2. {edx_enterprise_data-10.6.1/edx_enterprise_data.egg-info → edx_enterprise_data-10.7.1}/PKG-INFO +11 -2
  3. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1/edx_enterprise_data.egg-info}/PKG-INFO +11 -2
  4. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/edx_enterprise_data.egg-info/SOURCES.txt +2 -0
  5. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/__init__.py +1 -1
  6. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/serializers.py +17 -3
  7. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/urls.py +5 -0
  8. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/enterprise_admin.py +22 -0
  9. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/enterprise_learner.py +14 -5
  10. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_create_enterprise_learner_enrollment_lpr_v1.py +4 -0
  11. edx_enterprise_data-10.7.1/enterprise_data/migrations/0045_alter_enterpriseexecedlcmoduleperformance_options_and_more.py +27 -0
  12. edx_enterprise_data-10.7.1/enterprise_data/migrations/0046_enterprisegroupmembership.py +36 -0
  13. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/models.py +46 -0
  14. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/renderers.py +3 -3
  15. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/test_models.py +27 -0
  16. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/test_utils.py +26 -0
  17. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/base.txt +14 -13
  18. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/ci.txt +2 -2
  19. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/common_constraints.txt +4 -0
  20. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/dev.txt +22 -21
  21. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/pip.txt +1 -1
  22. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/pip_tools.txt +1 -1
  23. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/quality.txt +24 -23
  24. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/test-master.txt +16 -15
  25. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/test-reporting.txt +12 -11
  26. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/test.txt +16 -15
  27. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/LICENSE +0 -0
  28. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/MANIFEST.in +0 -0
  29. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/README.md +0 -0
  30. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/edx_enterprise_data.egg-info/dependency_links.txt +0 -0
  31. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/edx_enterprise_data.egg-info/not-zip-safe +0 -0
  32. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/edx_enterprise_data.egg-info/requires.txt +0 -0
  33. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/edx_enterprise_data.egg-info/top_level.txt +0 -0
  34. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/__init__.py +0 -0
  35. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/constants.py +0 -0
  36. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/data_loaders.py +0 -0
  37. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/__init__.py +0 -0
  38. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/queries/__init__.py +0 -0
  39. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +0 -0
  40. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +0 -0
  41. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py +0 -0
  42. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/tables/__init__.py +0 -0
  43. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/tables/base.py +0 -0
  44. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +0 -0
  45. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +0 -0
  46. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py +0 -0
  47. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/admin_analytics/database/utils.py +0 -0
  48. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/__init__.py +0 -0
  49. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/urls.py +0 -0
  50. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v0/__init__.py +0 -0
  51. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v0/serializers.py +0 -0
  52. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v0/urls.py +0 -0
  53. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v0/views.py +0 -0
  54. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/__init__.py +0 -0
  55. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/__init__.py +0 -0
  56. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/analytics_completions.py +0 -0
  57. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/analytics_engagements.py +0 -0
  58. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/analytics_enrollments.py +0 -0
  59. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/analytics_leaderboard.py +0 -0
  60. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/base.py +0 -0
  61. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/api/v1/views/enterprise_offers.py +0 -0
  62. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/apps.py +0 -0
  63. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/cache/__init__.py +0 -0
  64. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/cache/decorators.py +0 -0
  65. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/clients.py +0 -0
  66. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/constants.py +0 -0
  67. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/filters.py +0 -0
  68. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/fixtures/enterprise_enrollment.json +0 -0
  69. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/fixtures/enterprise_user.json +0 -0
  70. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/__init__.py +0 -0
  71. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/__init__.py +0 -0
  72. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_dummy_data.py +0 -0
  73. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_dummy_data_lpr_v1.py +0 -0
  74. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_enterprise_enrollment.py +0 -0
  75. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  76. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py +0 -0
  77. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_enterprise_offer.py +0 -0
  78. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/create_enterprise_user.py +0 -0
  79. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/pre_warm_analytics_cache.py +0 -0
  80. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/__init__.py +0 -0
  81. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py +0 -0
  82. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py +0 -0
  83. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_create_enterprise_learner_lpr_v1.py +0 -0
  84. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_create_enterprise_user.py +0 -0
  85. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/management/commands/tests/test_pre_warm_analytics_cache.py +0 -0
  86. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0001_initial.py +0 -0
  87. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0002_auto_20180430_1358.py +0 -0
  88. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0003_auto_20180501_0603.py +0 -0
  89. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0004_auto_20180501_0928.py +0 -0
  90. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0004_auto_20180508_1652.py +0 -0
  91. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0005_auto_20180524_2204.py +0 -0
  92. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0006_auto_20180612_0336.py +0 -0
  93. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0007_auto_20180612_0534.py +0 -0
  94. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0008_auto_20180614_0108.py +0 -0
  95. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0009_auto_20180628_1152.py +0 -0
  96. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0010_enterpriseenrollment_created.py +0 -0
  97. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0011_enterpriseuser.py +0 -0
  98. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0012_auto_20180831_1930.py +0 -0
  99. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0013_auto_20180831_1931.py +0 -0
  100. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0014_enterpriseuser_created.py +0 -0
  101. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0015_auto_20180907_1757.py +0 -0
  102. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0016_auto_20180924_2138.py +0 -0
  103. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0017_enterpriseenrollment_unenrollment_timestamp.py +0 -0
  104. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0018_enterprisedatafeaturerole_enterprisedataroleassignment.py +0 -0
  105. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0019_add_enterprise_data_feature_roles.py +0 -0
  106. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0020_add_role_based_access_control_switch.py +0 -0
  107. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0021_auto_20190329_1241.py +0 -0
  108. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0022_remove_role_based_access_control_switch.py +0 -0
  109. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0023_enterpriselearner_enterpriselearnerenrollment.py +0 -0
  110. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0024_auto_20210602_1811.py +0 -0
  111. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0025_auto_20210703_1854.py +0 -0
  112. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0026_auto_20210916_0414.py +0 -0
  113. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0027_enterpriselearnerenrollment_total_learning_time_seconds.py +0 -0
  114. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0028_enterpriselearnerenrollment_offer_id.py +0 -0
  115. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0029_enterpriseoffer.py +0 -0
  116. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0030_auto_20230609_1353.py +0 -0
  117. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0031_auto_20230615_0705.py +0 -0
  118. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0032_auto_20230704_0818.py +0 -0
  119. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0033_enterpriseadminlearnerprogress_enterpriseadminsummarizeinsights.py +0 -0
  120. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0034_auto_20230907_0834.py +0 -0
  121. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0035_auto_20230907_1154.py +0 -0
  122. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0036_enterprisesubsidybudget_subsidy_access_policy_display_name.py +0 -0
  123. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0037_alter_enterpriseenrollment_consent_granted.py +0 -0
  124. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0038_enterpriseoffer_export_timestamp.py +0 -0
  125. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0039_auto_20240212_1403.py +0 -0
  126. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpriselearnerenrollment_enterprise_enrollment_id.py +0 -0
  127. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py +0 -0
  128. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/migrations/__init__.py +0 -0
  129. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/paginators.py +0 -0
  130. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/settings/__init__.py +0 -0
  131. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/settings/test.py +0 -0
  132. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/signals.py +0 -0
  133. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/__init__.py +0 -0
  134. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/__init__.py +0 -0
  135. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/mock_analytics_data.py +0 -0
  136. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -0
  137. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/test_analytics_engagements.py +0 -0
  138. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +0 -0
  139. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py +0 -0
  140. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/test_data_loaders.py +0 -0
  141. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/admin_analytics/test_enterprise_completions.py +0 -0
  142. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/__init__.py +0 -0
  143. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v0/__init__.py +0 -0
  144. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v0/test_serializers.py +0 -0
  145. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v1/__init__.py +0 -0
  146. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v1/test_serializers.py +0 -0
  147. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v1/test_views.py +0 -0
  148. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v1/views/__init__.py +0 -0
  149. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/api/v1/views/test_enterprise_admin.py +0 -0
  150. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/factories.py +0 -0
  151. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/mixins.py +0 -0
  152. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/test_clients.py +0 -0
  153. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/test_filters.py +0 -0
  154. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/tests/test_views.py +0 -0
  155. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/urls.py +0 -0
  156. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data/utils.py +0 -0
  157. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/__init__.py +0 -0
  158. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/admin.py +0 -0
  159. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/apps.py +0 -0
  160. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/constants.py +0 -0
  161. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0001_initial.py +0 -0
  162. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0002_add_enterprise_data_feature_roles.py +0 -0
  163. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0003_add_role_based_access_control_switch.py +0 -0
  164. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0004_enterprisedataroleassignment_enterprise_id.py +0 -0
  165. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0005_turn_on_role_based_access_control_switch.py +0 -0
  166. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0006_remove_role_based_access_control_switch.py +0 -0
  167. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/0007_enterprisedataroleassignment_applies_to_all_contexts.py +0 -0
  168. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/migrations/__init__.py +0 -0
  169. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/models.py +0 -0
  170. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/rules.py +0 -0
  171. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/tests/__init__.py +0 -0
  172. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/tests/factories.py +0 -0
  173. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_data_roles/tests/test_models.py +0 -0
  174. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/__init__.py +0 -0
  175. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/clients/__init__.py +0 -0
  176. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/clients/enterprise.py +0 -0
  177. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/clients/s3.py +0 -0
  178. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/clients/snowflake.py +0 -0
  179. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/clients/vertica.py +0 -0
  180. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/delivery_method.py +0 -0
  181. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/external_resource_link_report.py +0 -0
  182. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/fixtures/__init__.py +0 -0
  183. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/fixtures/enterprise_customer_reporting.json +0 -0
  184. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/reporter.py +0 -0
  185. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/send_enterprise_reports.py +0 -0
  186. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/__init__.py +0 -0
  187. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_clients.py +0 -0
  188. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_delivery_method.py +0 -0
  189. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_enterprise_client.py +0 -0
  190. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_external_link_report.py +0 -0
  191. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_reporter.py +0 -0
  192. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_send_enterprise_reports.py +0 -0
  193. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_utils.py +0 -0
  194. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/test_vertica_client.py +0 -0
  195. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/tests/utils.py +0 -0
  196. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/enterprise_reporting/utils.py +0 -0
  197. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/base.in +0 -0
  198. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/constraints.txt +0 -0
  199. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/django.txt +0 -0
  200. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/requirements/reporting.in +0 -0
  201. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/setup.cfg +0 -0
  202. {edx_enterprise_data-10.6.1 → edx_enterprise_data-10.7.1}/setup.py +0 -0
@@ -16,6 +16,15 @@ Unreleased
16
16
 
17
17
  =========================
18
18
 
19
+ [10.7.1] - 2025-01-07
20
+ ---------------------
21
+ * feat: add group_membership table
22
+ * feat: add APIs to support LPR filtering for enterprise groups
23
+
24
+ [10.7.0] - 2024-12-24
25
+ ---------------------
26
+ * feat: Added user's first and last name in the enterprise enrollments API and related DB table.
27
+
19
28
  [10.6.1] - 2024-12-10
20
29
  ---------------------
21
30
  * feat: add course_title in top courses in enrollments csv
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: edx-enterprise-data
3
- Version: 10.6.1
3
+ Version: 10.7.1
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -39,5 +39,14 @@ Requires-Dist: pyminizip; extra == "reporting"
39
39
  Requires-Dist: snowflake-connector-python; extra == "reporting"
40
40
  Requires-Dist: unicodecsv==0.14.1; extra == "reporting"
41
41
  Requires-Dist: vertica-python; extra == "reporting"
42
+ Dynamic: author
43
+ Dynamic: author-email
44
+ Dynamic: classifier
45
+ Dynamic: description
46
+ Dynamic: home-page
47
+ Dynamic: license
48
+ Dynamic: provides-extra
49
+ Dynamic: requires-dist
50
+ Dynamic: summary
42
51
 
43
52
  Tools and products related to providing access to Enterprise data.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: edx-enterprise-data
3
- Version: 10.6.1
3
+ Version: 10.7.1
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -39,5 +39,14 @@ Requires-Dist: pyminizip; extra == "reporting"
39
39
  Requires-Dist: snowflake-connector-python; extra == "reporting"
40
40
  Requires-Dist: unicodecsv==0.14.1; extra == "reporting"
41
41
  Requires-Dist: vertica-python; extra == "reporting"
42
+ Dynamic: author
43
+ Dynamic: author-email
44
+ Dynamic: classifier
45
+ Dynamic: description
46
+ Dynamic: home-page
47
+ Dynamic: license
48
+ Dynamic: provides-extra
49
+ Dynamic: requires-dist
50
+ Dynamic: summary
42
51
 
43
52
  Tools and products related to providing access to Enterprise data.
@@ -115,6 +115,8 @@ enterprise_data/migrations/0038_enterpriseoffer_export_timestamp.py
115
115
  enterprise_data/migrations/0039_auto_20240212_1403.py
116
116
  enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpriselearnerenrollment_enterprise_enrollment_id.py
117
117
  enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py
118
+ enterprise_data/migrations/0045_alter_enterpriseexecedlcmoduleperformance_options_and_more.py
119
+ enterprise_data/migrations/0046_enterprisegroupmembership.py
118
120
  enterprise_data/migrations/__init__.py
119
121
  enterprise_data/settings/__init__.py
120
122
  enterprise_data/settings/test.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.6.1"
5
+ __version__ = "10.7.1"
@@ -10,6 +10,7 @@ from enterprise_data.models import (
10
10
  EnterpriseAdminLearnerProgress,
11
11
  EnterpriseAdminSummarizeInsights,
12
12
  EnterpriseExecEdLCModulePerformance,
13
+ EnterpriseGroupMembership,
13
14
  EnterpriseLearner,
14
15
  EnterpriseLearnerEnrollment,
15
16
  EnterpriseOffer,
@@ -41,9 +42,9 @@ class EnterpriseLearnerEnrollmentSerializer(serializers.ModelSerializer):
41
42
  'course_primary_program', 'primary_program_type', 'course_primary_subject', 'has_passed',
42
43
  'last_activity_date', 'progress_status', 'passed_date', 'current_grade',
43
44
  'letter_grade', 'enterprise_user_id', 'user_email', 'user_account_creation_date',
44
- 'user_country_code', 'user_username', 'enterprise_name', 'enterprise_customer_uuid',
45
- 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours', 'is_subsidy',
46
- 'course_product_line', 'budget_id', 'enterprise_group_name', 'enterprise_group_uuid',
45
+ 'user_country_code', 'user_username', 'user_first_name', 'user_last_name', 'enterprise_name',
46
+ 'enterprise_customer_uuid', 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours',
47
+ 'is_subsidy', 'course_product_line', 'budget_id', 'enterprise_group_name', 'enterprise_group_uuid',
47
48
  )
48
49
 
49
50
  def get_course_api_url(self, obj):
@@ -253,6 +254,19 @@ class EnterpriseBudgetSerializer(serializers.ModelSerializer):
253
254
  )
254
255
 
255
256
 
257
+ class EnterpriseGroupMembershipSerializer(serializers.ModelSerializer):
258
+ """
259
+ Serializer for EnterpriseGroupMembership model.
260
+ """
261
+
262
+ class Meta:
263
+ model = EnterpriseGroupMembership
264
+ fields = (
265
+ 'enterprise_group_uuid',
266
+ 'enterprise_group_name',
267
+ )
268
+
269
+
256
270
  class AdvanceAnalyticsQueryParamSerializer(serializers.Serializer): # pylint: disable=abstract-method
257
271
  """Serializer for validating query params"""
258
272
  RESPONSE_TYPES = [
@@ -101,6 +101,11 @@ urlpatterns = [
101
101
  enterprise_admin_views.EnterpriseBudgetView.as_view(),
102
102
  name='enterprise-budgets'
103
103
  ),
104
+ re_path(
105
+ fr'^enterprise/(?P<enterprise_uuid>{UUID4_REGEX})/groups',
106
+ enterprise_admin_views.EnterpriseGroupMembershipView.as_view(),
107
+ name='enterprise-groups'
108
+ ),
104
109
  ]
105
110
 
106
111
  urlpatterns += router.urls
@@ -21,6 +21,7 @@ from enterprise_data.models import (
21
21
  EnterpriseAdminLearnerProgress,
22
22
  EnterpriseAdminSummarizeInsights,
23
23
  EnterpriseExecEdLCModulePerformance,
24
+ EnterpriseGroupMembership,
24
25
  EnterpriseSubsidyBudget,
25
26
  )
26
27
  from enterprise_data.utils import timer
@@ -230,3 +231,24 @@ class EnterpriseBudgetView(APIView):
230
231
 
231
232
  serializer = serializers.EnterpriseBudgetSerializer(budgets, many=True)
232
233
  return Response(serializer.data)
234
+
235
+
236
+ class EnterpriseGroupMembershipView(APIView):
237
+ """
238
+ View for getting Group Memberships information for an enterprise.
239
+ """
240
+ authentication_classes = (JwtAuthentication,)
241
+ http_method_names = ["get"]
242
+
243
+ @permission_required("can_access_enterprise", fn=lambda request, enterprise_uuid: enterprise_uuid)
244
+ def get(self, request, enterprise_uuid):
245
+ """
246
+ Returns the groups and budgets for an enterprise.
247
+ """
248
+ groups = EnterpriseGroupMembership.objects.filter(
249
+ enterprise_customer_id=enterprise_uuid,
250
+ group_type='flex',
251
+ )
252
+
253
+ serializer = serializers.EnterpriseGroupMembershipSerializer(groups, many=True)
254
+ return Response(serializer.data)
@@ -12,7 +12,7 @@ from rest_framework.response import Response
12
12
 
13
13
  from django.conf import settings
14
14
  from django.core.paginator import Paginator
15
- from django.db.models import Count, Max, OuterRef, Prefetch, Q, Subquery, Value
15
+ from django.db.models import Count, Exists, Max, OuterRef, Prefetch, Q, Subquery, Value
16
16
  from django.db.models.fields import IntegerField
17
17
  from django.db.models.functions import Coalesce
18
18
  from django.http import StreamingHttpResponse
@@ -20,7 +20,7 @@ from django.utils import timezone
20
20
 
21
21
  from enterprise_data.admin_analytics.database.utils import LOGGER
22
22
  from enterprise_data.api.v1 import serializers
23
- from enterprise_data.models import EnterpriseLearner, EnterpriseLearnerEnrollment
23
+ from enterprise_data.models import EnterpriseGroupMembership, EnterpriseLearner, EnterpriseLearnerEnrollment
24
24
  from enterprise_data.paginators import EnterpriseEnrollmentsPagination
25
25
  from enterprise_data.renderers import EnrollmentsCSVRenderer
26
26
  from enterprise_data.utils import subtract_one_month
@@ -59,9 +59,9 @@ class EnterpriseLearnerEnrollmentViewSet(EnterpriseViewSetMixin, viewsets.ReadOn
59
59
  'course_primary_program', 'primary_program_type', 'course_primary_subject', 'has_passed',
60
60
  'last_activity_date', 'progress_status', 'passed_date', 'current_grade',
61
61
  'letter_grade', 'enterprise_user_id', 'user_email', 'user_account_creation_date',
62
- 'user_country_code', 'user_username', 'enterprise_name', 'enterprise_customer_uuid',
63
- 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours', 'is_subsidy',
64
- 'course_product_line', 'budget_id'
62
+ 'user_country_code', 'user_username', 'user_first_name', 'user_last_name', 'enterprise_name',
63
+ 'enterprise_customer_uuid', 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours',
64
+ 'is_subsidy', 'course_product_line', 'budget_id',
65
65
  ]
66
66
 
67
67
  # TODO: Remove after we release the streaming csv changes
@@ -174,6 +174,15 @@ class EnterpriseLearnerEnrollmentViewSet(EnterpriseViewSetMixin, viewsets.ReadOn
174
174
  if is_subsidy:
175
175
  queryset = queryset.filter(is_subsidy=is_subsidy)
176
176
 
177
+ group_uuid = query_filters.get('group_uuid')
178
+ if group_uuid:
179
+ flex_group_exists = EnterpriseGroupMembership.objects.filter(
180
+ enterprise_customer_user_id=OuterRef('enterprise_user_id'),
181
+ enterprise_group_uuid=group_uuid,
182
+ group_type='flex'
183
+ )
184
+ queryset = queryset.filter(Exists(flex_group_exists))
185
+
177
186
  return queryset
178
187
 
179
188
  def filter_by_offer_id(self, queryset, offer_id):
@@ -39,6 +39,8 @@ class TestCreateEnterpriseLearnerEnrollmentCommand(TestCase):
39
39
  assert enterprise_learner_enrollment[0].letter_grade is None
40
40
  assert enterprise_learner_enrollment[0].enterprise_user_id is None
41
41
  assert enterprise_learner_enrollment[0].user_username is None
42
+ assert enterprise_learner_enrollment[0].user_first_name is None
43
+ assert enterprise_learner_enrollment[0].user_last_name is None
42
44
  assert enterprise_learner_enrollment[0].user_email is None
43
45
  assert enterprise_learner_enrollment[0].enterprise_user is None
44
46
 
@@ -62,6 +64,8 @@ class TestCreateEnterpriseLearnerEnrollmentCommand(TestCase):
62
64
  assert enterprise_learner_enrollment[0].progress_status is not None
63
65
  assert enterprise_learner_enrollment[0].enterprise_user_id is not None
64
66
  assert enterprise_learner_enrollment[0].user_username is not None
67
+ assert enterprise_learner_enrollment[0].user_first_name is not None
68
+ assert enterprise_learner_enrollment[0].user_last_name is not None
65
69
  assert enterprise_learner_enrollment[0].enterprise_user is not None
66
70
  assert enterprise_learner_enrollment[0].user_email is not None
67
71
  assert EnterpriseLearner.objects.count() == 1
@@ -0,0 +1,27 @@
1
+ # Generated by Django 4.2.15 on 2024-12-23 12:55
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('enterprise_data', '0044_enterpriseexecedlcmoduleperformance'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterModelOptions(
14
+ name='enterpriseexecedlcmoduleperformance',
15
+ options={'verbose_name': 'Exec Ed LC Module Performance', 'verbose_name_plural': 'Exec Ed LC Module Performance'},
16
+ ),
17
+ migrations.AddField(
18
+ model_name='enterpriselearnerenrollment',
19
+ name='user_first_name',
20
+ field=models.CharField(max_length=255, null=True),
21
+ ),
22
+ migrations.AddField(
23
+ model_name='enterpriselearnerenrollment',
24
+ name='user_last_name',
25
+ field=models.CharField(max_length=255, null=True),
26
+ ),
27
+ ]
@@ -0,0 +1,36 @@
1
+ # Generated by Django 4.2.16 on 2025-01-08 07:31
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('enterprise_data', '0045_alter_enterpriseexecedlcmoduleperformance_options_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name='EnterpriseGroupMembership',
15
+ fields=[
16
+ ('group_membership_unique_id', models.CharField(max_length=64, primary_key=True, serialize=False)),
17
+ ('is_applies_to_all_contexts', models.BooleanField(default=False)),
18
+ ('enterprise_customer_id', models.UUIDField(db_index=True, null=True)),
19
+ ('enterprise_group_name', models.CharField(max_length=255, null=True)),
20
+ ('enterprise_group_uuid', models.UUIDField(null=True)),
21
+ ('group_is_removed', models.BooleanField(default=False)),
22
+ ('group_type', models.CharField(max_length=128, null=True)),
23
+ ('activated_at', models.DateTimeField(null=True)),
24
+ ('enterprise_customer_user_id', models.PositiveIntegerField(null=True)),
25
+ ('membership_is_removed', models.BooleanField(default=False)),
26
+ ('membership_status', models.CharField(max_length=128, null=True)),
27
+ ('enterprise_group_membership_uuid', models.UUIDField(null=True)),
28
+ ],
29
+ options={
30
+ 'verbose_name': 'Group Membership',
31
+ 'verbose_name_plural': 'Group Memberships',
32
+ 'db_table': 'group_membership',
33
+ 'indexes': [models.Index(fields=['enterprise_group_uuid', 'group_type', 'enterprise_customer_user_id'], name='group_membe_enterpr_796f48_idx')],
34
+ },
35
+ ),
36
+ ]
@@ -128,6 +128,8 @@ class EnterpriseLearnerEnrollment(models.Model):
128
128
  user_account_creation_date = models.DateTimeField(null=True)
129
129
  user_country_code = models.CharField(max_length=2, null=True)
130
130
  user_username = models.CharField(max_length=255, null=True)
131
+ user_first_name = models.CharField(max_length=255, null=True)
132
+ user_last_name = models.CharField(max_length=255, null=True)
131
133
  enterprise_name = models.CharField(max_length=255, db_index=True, null=False)
132
134
  enterprise_customer_uuid = models.UUIDField(db_index=True, null=False)
133
135
  enterprise_sso_uid = models.CharField(max_length=255, null=True)
@@ -396,6 +398,50 @@ class EnterpriseSubsidyBudget(models.Model):
396
398
  return self.__str__()
397
399
 
398
400
 
401
+ class EnterpriseGroupMembership(models.Model):
402
+ """
403
+ Details of group memberships in enterprise reports.
404
+ """
405
+
406
+ objects = EnterpriseReportingModelManager()
407
+
408
+ class Meta:
409
+ app_label = 'enterprise_data'
410
+ db_table = 'group_membership'
411
+ verbose_name = _("Group Membership")
412
+ verbose_name_plural = _("Group Memberships")
413
+ indexes = [
414
+ models.Index(fields=['enterprise_group_uuid', 'group_type', 'enterprise_customer_user_id']),
415
+ ]
416
+
417
+ group_membership_unique_id = models.CharField(max_length=64, primary_key=True)
418
+ is_applies_to_all_contexts = models.BooleanField(default=False)
419
+ enterprise_customer_id = models.UUIDField(db_index=True, null=True)
420
+ enterprise_group_name = models.CharField(max_length=255, null=True)
421
+ enterprise_group_uuid = models.UUIDField(null=True)
422
+ group_is_removed = models.BooleanField(default=False)
423
+ group_type = models.CharField(max_length=128, null=True)
424
+ activated_at = models.DateTimeField(null=True)
425
+ enterprise_customer_user_id = models.PositiveIntegerField(null=True)
426
+ membership_is_removed = models.BooleanField(default=False)
427
+ membership_status = models.CharField(max_length=128, null=True)
428
+ enterprise_group_membership_uuid = models.UUIDField(null=True)
429
+
430
+ def __str__(self):
431
+ """
432
+ Return a human-readable string representation of the object.
433
+ """
434
+ return (f'<Enterprise Group Membership: {self.enterprise_group_name} '
435
+ f'(Group UUID: {self.enterprise_group_uuid}) '
436
+ f'for Customer ID {self.enterprise_customer_id}>')
437
+
438
+ def __repr__(self):
439
+ """
440
+ Return uniquely identifying string representation.
441
+ """
442
+ return self.__str__()
443
+
444
+
399
445
  class EnterpriseUser(models.Model):
400
446
  """Information includes a mix of the user's meta data.
401
447
 
@@ -25,9 +25,9 @@ class EnrollmentsCSVRenderer(CSVStreamingRenderer):
25
25
  'course_primary_program', 'primary_program_type', 'course_primary_subject', 'has_passed',
26
26
  'last_activity_date', 'progress_status', 'passed_date', 'current_grade',
27
27
  'letter_grade', 'enterprise_user_id', 'user_email', 'user_account_creation_date',
28
- 'user_country_code', 'user_username', 'enterprise_name', 'enterprise_customer_uuid',
29
- 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours', 'is_subsidy',
30
- 'course_product_line', 'budget_id', 'enterprise_group_name', 'enterprise_group_uuid',
28
+ 'user_country_code', 'user_username', 'user_first_name', 'user_last_name', 'enterprise_name',
29
+ 'enterprise_customer_uuid', 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours',
30
+ 'is_subsidy', 'course_product_line', 'budget_id', 'enterprise_group_name', 'enterprise_group_uuid',
31
31
  ]
32
32
 
33
33
 
@@ -10,6 +10,7 @@ from pytest import mark
10
10
 
11
11
  from enterprise_data.tests.test_utils import (
12
12
  EnterpriseEnrollmentFactory,
13
+ EnterpriseGroupMembershipFactory,
13
14
  EnterpriseOfferFactory,
14
15
  EnterpriseSubsidyBudgetFactory,
15
16
  EnterpriseUserFactory,
@@ -91,6 +92,32 @@ class TestEnterpriseSubsidyBudget(unittest.TestCase):
91
92
  assert expected_str == method(self.enterprise_subsidy_budget)
92
93
 
93
94
 
95
+ @mark.django_db
96
+ @ddt.ddt
97
+ class TestEnterpriseGroupMembership(unittest.TestCase):
98
+ """
99
+ Tests for Enterprise Group Membership model
100
+ """
101
+
102
+ def setUp(self):
103
+ self.enterprise_group_membership = EnterpriseGroupMembershipFactory(
104
+ enterprise_customer_id='ee5e6b3a-069a-4947-bb8d-d2dbc323396c',
105
+ enterprise_group_name='Test Group',
106
+ enterprise_group_uuid='ee5e6b3a-069a-4947-bb8d-d2dbc323396d',
107
+ )
108
+ super().setUp()
109
+
110
+ @ddt.data(str, repr)
111
+ def test_string_conversion(self, method):
112
+ """
113
+ Test conversion to string.
114
+ """
115
+ expected_str = ('<Enterprise Group Membership: Test Group '
116
+ '(Group UUID: ee5e6b3a-069a-4947-bb8d-d2dbc323396d) '
117
+ 'for Customer ID ee5e6b3a-069a-4947-bb8d-d2dbc323396c>')
118
+ assert expected_str == method(self.enterprise_group_membership)
119
+
120
+
94
121
  @mark.django_db
95
122
  @ddt.ddt
96
123
  class TestEnterpriseUser(unittest.TestCase):
@@ -14,6 +14,7 @@ from django.contrib.auth import get_user_model
14
14
 
15
15
  from enterprise_data.models import (
16
16
  EnterpriseEnrollment,
17
+ EnterpriseGroupMembership,
17
18
  EnterpriseLearner,
18
19
  EnterpriseLearnerEnrollment,
19
20
  EnterpriseOffer,
@@ -180,6 +181,8 @@ class EnterpriseLearnerEnrollmentFactory(factory.django.DjangoModelFactory):
180
181
  enterprise_user_id = factory.Sequence(lambda n: n)
181
182
  user_email = factory.lazy_attribute(lambda x: FAKER.email()) # pylint: disable=no-member
182
183
  user_username = factory.Sequence('robot{}'.format)
184
+ user_first_name = factory.Sequence('Robot First {}'.format)
185
+ user_last_name = factory.Sequence('Robot Last {}'.format)
183
186
  user_account_creation_date = factory.lazy_attribute(lambda x: '2018-01-01')
184
187
  user_country_code = factory.lazy_attribute(lambda x: FAKER.country_code())
185
188
  is_subsidy = factory.lazy_attribute(lambda x: FAKER.boolean()) # pylint: disable=no-member
@@ -230,6 +233,8 @@ class EnterpriseLearnerEnrollmentFactory(factory.django.DjangoModelFactory):
230
233
  'user_account_creation_date',
231
234
  'user_country_code',
232
235
  'user_username',
236
+ 'user_first_name',
237
+ 'user_last_name',
233
238
  ]
234
239
  if create and not obj.is_consent_granted:
235
240
  for field in dsc_dependent_fields:
@@ -284,6 +289,27 @@ class EnterpriseSubsidyBudgetFactory(factory.django.DjangoModelFactory):
284
289
  )
285
290
 
286
291
 
292
+ class EnterpriseGroupMembershipFactory(factory.django.DjangoModelFactory):
293
+ """
294
+ EnterpriseGroupMembership model Factory.
295
+ """
296
+ class Meta:
297
+ model = EnterpriseGroupMembership
298
+
299
+ enterprise_customer_id = factory.LazyAttribute(lambda _: FAKER.uuid4())
300
+ enterprise_group_name = factory.LazyAttribute(lambda _: ' '.join(FAKER.words(nb=2)).title())
301
+ enterprise_group_uuid = factory.LazyAttribute(lambda _: FAKER.uuid4())
302
+ group_is_removed = factory.LazyAttribute(lambda _: FAKER.boolean())
303
+ group_type = factory.LazyAttribute(lambda _: 'budget')
304
+ activated_at = factory.LazyAttribute(lambda _: FAKER.date_time_this_decade(tzinfo=pytz.UTC))
305
+ enterprise_customer_user_id = factory.LazyAttribute(lambda _: FAKER.random_int(min=1, max=10000))
306
+ membership_is_removed = factory.LazyAttribute(lambda _: FAKER.boolean())
307
+ membership_status = factory.LazyAttribute(lambda _: FAKER.word())
308
+ enterprise_group_membership_uuid = factory.LazyAttribute(lambda _: FAKER.uuid4())
309
+
310
+ is_applies_to_all_contexts = factory.LazyAttribute(lambda _: FAKER.boolean())
311
+
312
+
287
313
  class EnterpriseOfferFactory(factory.django.DjangoModelFactory):
288
314
  """
289
315
  EnterpriseLearner model Factory.
@@ -10,22 +10,22 @@ asgiref==3.8.1
10
10
  # via django
11
11
  asn1crypto==1.5.1
12
12
  # via snowflake-connector-python
13
- awscli==1.36.17
13
+ awscli==1.36.38
14
14
  # via -r requirements/reporting.in
15
15
  bcrypt==4.2.1
16
16
  # via paramiko
17
17
  billiard==4.2.1
18
18
  # via celery
19
- boto3==1.35.76
19
+ boto3==1.35.97
20
20
  # via -r requirements/reporting.in
21
- botocore==1.35.76
21
+ botocore==1.35.97
22
22
  # via
23
23
  # awscli
24
24
  # boto3
25
25
  # s3transfer
26
26
  celery==5.3.6
27
27
  # via -r requirements/reporting.in
28
- certifi==2024.8.30
28
+ certifi==2024.12.14
29
29
  # via
30
30
  # py2neo
31
31
  # requests
@@ -35,11 +35,11 @@ cffi==1.17.1
35
35
  # cryptography
36
36
  # pynacl
37
37
  # snowflake-connector-python
38
- charset-normalizer==3.4.0
38
+ charset-normalizer==3.4.1
39
39
  # via
40
40
  # requests
41
41
  # snowflake-connector-python
42
- click==8.1.7
42
+ click==8.1.8
43
43
  # via
44
44
  # celery
45
45
  # click-didyoumean
@@ -125,7 +125,7 @@ edx-rest-api-client==6.0.0
125
125
  # via -r requirements/base.in
126
126
  factory-boy==3.3.1
127
127
  # via -r requirements/base.in
128
- faker==33.1.0
128
+ faker==33.3.1
129
129
  # via factory-boy
130
130
  filelock==3.16.1
131
131
  # via snowflake-connector-python
@@ -145,9 +145,9 @@ monotonic==1.6
145
145
  # via py2neo
146
146
  mysql-connector-python==9.1.0
147
147
  # via -r requirements/base.in
148
- newrelic==10.3.1
148
+ newrelic==10.4.0
149
149
  # via edx-django-utils
150
- numpy==2.2.0
150
+ numpy==2.2.1
151
151
  # via
152
152
  # -r requirements/base.in
153
153
  # pandas
@@ -165,13 +165,13 @@ pbr==6.1.0
165
165
  # via stevedore
166
166
  pgpy==0.6.0
167
167
  # via -r requirements/reporting.in
168
- pillow==11.0.0
168
+ pillow==11.1.0
169
169
  # via pansi
170
170
  platformdirs==4.3.6
171
171
  # via snowflake-connector-python
172
172
  prompt-toolkit==3.0.48
173
173
  # via click-repl
174
- psutil==6.1.0
174
+ psutil==6.1.1
175
175
  # via edx-django-utils
176
176
  py2neo @ https://github.com/overhangio/py2neo/releases/download/2021.2.3/py2neo-2021.2.3.tar.gz
177
177
  # via -r requirements/reporting.in
@@ -181,7 +181,7 @@ pyasn1==0.6.1
181
181
  # rsa
182
182
  pycparser==2.22
183
183
  # via cffi
184
- pygments==2.18.0
184
+ pygments==2.19.1
185
185
  # via py2neo
186
186
  pyjwt[crypto]==2.10.1
187
187
  # via
@@ -240,7 +240,7 @@ snowflake-connector-python==3.12.4
240
240
  # via -r requirements/reporting.in
241
241
  sortedcontainers==2.4.0
242
242
  # via snowflake-connector-python
243
- sqlparse==0.5.2
243
+ sqlparse==0.5.3
244
244
  # via django
245
245
  stevedore==5.4.0
246
246
  # via
@@ -262,6 +262,7 @@ unicodecsv==0.14.1
262
262
  # via -r requirements/reporting.in
263
263
  urllib3==2.2.3
264
264
  # via
265
+ # -c /home/runner/work/edx-enterprise-data/edx-enterprise-data/requirements/common_constraints.txt
265
266
  # botocore
266
267
  # py2neo
267
268
  # requests
@@ -10,7 +10,7 @@ chardet==5.2.0
10
10
  # via tox
11
11
  colorama==0.4.6
12
12
  # via tox
13
- coverage==7.6.9
13
+ coverage==7.6.10
14
14
  # via -r requirements/ci.in
15
15
  distlib==0.3.9
16
16
  # via virtualenv
@@ -32,5 +32,5 @@ pyproject-api==1.8.0
32
32
  # via tox
33
33
  tox==4.23.2
34
34
  # via -r requirements/ci.in
35
- virtualenv==20.28.0
35
+ virtualenv==20.28.1
36
36
  # via tox
@@ -26,3 +26,7 @@ django-simple-history==3.0.0
26
26
  # Cause: https://github.com/openedx/edx-lint/issues/458
27
27
  # This can be unpinned once https://github.com/openedx/edx-lint/issues/459 has been resolved.
28
28
  pip<24.3
29
+
30
+ # Cause: https://github.com/openedx/edx-lint/issues/475
31
+ # This can be unpinned once https://github.com/openedx/edx-lint/issues/476 has been resolved.
32
+ urllib3<2.3.0