From 43a83fa087838f8d42e2d54b631d26de04823a22 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Tue, 4 Jul 2023 17:10:58 +0500 Subject: [PATCH 1/5] feat: add more metadata into `EnterpriseCourseEnrollmentView` --- CHANGELOG.rst | 12 ++++++++---- enterprise/__init__.py | 2 +- enterprise_learner_portal/api/v1/serializers.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3216e1aab4..f32675c71d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,10 @@ Change Log Unreleased ---------- +[3.68.0] +-------- +feat: add more metadata into `EnterpriseCourseEnrollmentView` + [3.67.7] -------- feat: marking orphaned content audits when catalogs are deleted @@ -33,7 +37,7 @@ feat: add button to update customer modified time [3.67.3] -------- -feat: adding managent command to clear error state +feat: adding managent command to clear error state [3.67.2] -------- @@ -99,7 +103,7 @@ fix: making sure unenrollment is saved while revoking fulfillment [3.65.0] -------- -feat: new enterprise endpoint to surface filterable unenrolled subsidized enrollments +feat: new enterprise endpoint to surface filterable unenrolled subsidized enrollments [3.64.1] -------- @@ -108,10 +112,10 @@ fix: Reverted course_run_url for Executive Education courses [3.64.0] -------- feat: Updated course_run_url for Executive Education courses - + [3.63.0] -------- -feat: Hooking enterprise enrollments up to platform signals to write unenrollment records. +feat: Hooking enterprise enrollments up to platform signals to write unenrollment records. New field `unenrolled` on enterprise enrollments to track enrollment status, defaults to `None`. [3.62.7] diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 4eebc337c2..07480c5a95 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,6 +2,6 @@ Your project description goes here. """ -__version__ = "3.67.7" +__version__ = "3.68.0" default_app_config = "enterprise.apps.EnterpriseConfig" diff --git a/enterprise_learner_portal/api/v1/serializers.py b/enterprise_learner_portal/api/v1/serializers.py index affe668139..0b5d39139a 100644 --- a/enterprise_learner_portal/api/v1/serializers.py +++ b/enterprise_learner_portal/api/v1/serializers.py @@ -21,6 +21,11 @@ get_course_run_url = None get_emails_enabled = None +try: + from federated_content_connector.models import CourseDetails +except ImportError: + CourseDetails = None + class EnterpriseCourseEnrollmentSerializer(serializers.Serializer): # pylint: disable=abstract-method """ @@ -73,6 +78,15 @@ def to_representation(self, instance): representation['is_enrollment_active'] = instance.is_active representation['mode'] = instance.mode + if CourseDetails: + course_details = CourseDetails.objects.filter(id=course_run_id) + if course_details: + representation['course_type'] = course_details.course_type + representation['product_source'] = course_details.product_source + representation['start_date'] = course_details.start_date or representation['start_date'] + representation['end_date'] = course_details.end_date or representation['end_date'] + representation['enroll_by'] = course_details.enroll_by + return representation def _get_course_overview(self, course_run_id): From 5273573912e599fda49e958eabeb0ac97302ade3 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Wed, 5 Jul 2023 11:10:07 +0500 Subject: [PATCH 2/5] fix: pick first object from CourseDetails --- CHANGELOG.rst | 4 ++++ enterprise/__init__.py | 2 +- enterprise_learner_portal/api/v1/serializers.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f32675c71d..1de30ba9a4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,10 @@ Change Log Unreleased ---------- +[3.68.1] +-------- +fix: pick first object from CourseDetails + [3.68.0] -------- feat: add more metadata into `EnterpriseCourseEnrollmentView` diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 07480c5a95..ad74471075 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,6 +2,6 @@ Your project description goes here. """ -__version__ = "3.68.0" +__version__ = "3.68.1" default_app_config = "enterprise.apps.EnterpriseConfig" diff --git a/enterprise_learner_portal/api/v1/serializers.py b/enterprise_learner_portal/api/v1/serializers.py index 0b5d39139a..ac4f18a57e 100644 --- a/enterprise_learner_portal/api/v1/serializers.py +++ b/enterprise_learner_portal/api/v1/serializers.py @@ -79,7 +79,7 @@ def to_representation(self, instance): representation['mode'] = instance.mode if CourseDetails: - course_details = CourseDetails.objects.filter(id=course_run_id) + course_details = CourseDetails.objects.filter(id=course_run_id).first() if course_details: representation['course_type'] = course_details.course_type representation['product_source'] = course_details.product_source From a5208a1edb4e251bb84a3d24db8a0c1d7f35d9ff Mon Sep 17 00:00:00 2001 From: Saleem Latif Date: Fri, 7 Jul 2023 13:01:46 +0500 Subject: [PATCH 3/5] refactor: Replaced the deprecated NullBooleanField with BooleanField(null=True) --- CHANGELOG.rst | 4 ++++ consent/migrations/0005_auto_20230707_0755.py | 23 +++++++++++++++++++ consent/models.py | 2 +- enterprise/__init__.py | 2 +- 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 consent/migrations/0005_auto_20230707_0755.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1de30ba9a4..c5c0f55238 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,10 @@ Change Log Unreleased ---------- +[3.69.0] +-------- +refactor: Replaced the deprecated `NullBooleanField` with `BooleanField(null=True)` + [3.68.1] -------- fix: pick first object from CourseDetails diff --git a/consent/migrations/0005_auto_20230707_0755.py b/consent/migrations/0005_auto_20230707_0755.py new file mode 100644 index 0000000000..b76365ce47 --- /dev/null +++ b/consent/migrations/0005_auto_20230707_0755.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.18 on 2023-07-07 07:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('consent', '0004_datasharingconsenttextoverrides'), + ] + + operations = [ + migrations.AlterField( + model_name='datasharingconsent', + name='granted', + field=models.BooleanField(help_text='Whether consent is granted.', null=True), + ), + migrations.AlterField( + model_name='historicaldatasharingconsent', + name='granted', + field=models.BooleanField(help_text='Whether consent is granted.', null=True), + ), + ] diff --git a/consent/models.py b/consent/models.py index 443081c453..abbbd2a72e 100644 --- a/consent/models.py +++ b/consent/models.py @@ -209,7 +209,7 @@ class Meta: null=False, help_text=_("Name of the user whose consent state is stored.") ) - granted = models.NullBooleanField(help_text=_("Whether consent is granted.")) + granted = models.BooleanField(null=True, help_text=_("Whether consent is granted.")) @property def _exists(self): diff --git a/enterprise/__init__.py b/enterprise/__init__.py index ad74471075..a05ed9eb57 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,6 +2,6 @@ Your project description goes here. """ -__version__ = "3.68.1" +__version__ = "3.69.0" default_app_config = "enterprise.apps.EnterpriseConfig" From f4e0fdb46949b70ce3f980a1b3f6d70196775961 Mon Sep 17 00:00:00 2001 From: John Nagro Date: Fri, 7 Jul 2023 11:38:08 -0400 Subject: [PATCH 4/5] fix: add pkg-config to Dockerfile (#1795) --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 88a74ffd3a..0defa963a5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,9 @@ MAINTAINER sre@edx.org # python3-pip; install pip to install application requirements.txt files +# pkg-config +# mysqlclient>=2.2.0 requires this (https://github.com/PyMySQL/mysqlclient/issues/620) + # libmysqlclient-dev; to install header files needed to use native C implementation for # MySQL-python for performance gains. @@ -33,6 +36,7 @@ RUN apt-get update && apt-get -qy install --no-install-recommends \ python3.8 \ python3-pip \ python3.8-venv \ + pkg-config \ libmysqlclient-dev \ libssl-dev \ python3-dev \ From d14b10e92af70f658d00ef9152f25be033ce8e70 Mon Sep 17 00:00:00 2001 From: Yuanyuan <69041977+yuanyuan-git-tech@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:50:38 -0400 Subject: [PATCH 5/5] fix: reorganizing enterprise customer django admin (#1791) * fix: reorganizing enterprise customer django admin and addressing test and lint errors --------- Co-authored-by: Yuanyuan Zhao <1621732550@qq.com> --- enterprise/admin/__init__.py | 46 +++ .../migrations/0175_auto_20230629_2330.py | 296 ++++++++++++++++++ enterprise/models.py | 116 ++++--- tests/test_enterprise/api/test_views.py | 208 ++++++------ 4 files changed, 521 insertions(+), 145 deletions(-) create mode 100644 enterprise/migrations/0175_auto_20230629_2330.py diff --git a/enterprise/admin/__init__.py b/enterprise/admin/__init__.py index c46c994e9e..cfca78fb64 100644 --- a/enterprise/admin/__init__.py +++ b/enterprise/admin/__init__.py @@ -188,6 +188,52 @@ class EnterpriseCustomerAdmin(DjangoObjectActions, SimpleHistoryAdmin): list_filter = ('active',) ordering = ('name',) search_fields = ('name', 'uuid',) + + fieldsets = ( + ('Enterprise info', { + 'fields': ('name', 'active', 'slug', 'auth_org_id', 'country') + }), + ('Subsidy management screens ', { + 'fields': ('enable_portal_learner_credit_management_screen', + 'enable_portal_subscription_management_screen', + 'enable_portal_code_management_screen'), + 'description': ("Select the check boxes below to enable specific subsidy management screens" + "on the organization's administrator portal. If an option is left unchecked," + "the customer administrator will not see the screen in their portal" + "and will not be able to apply the associated configurations via self-service.") + }), + ('Subsidy settings', { + 'fields': ('enable_browse_and_request', 'enable_universal_link'), + 'description': ('Select the check boxes below to enable specific subsidy management settings' + 'for the administrator portal for subscription and codes customers.' + 'These should not be selected for customers that only have learner credit.') + }), + ('Data sharing consent', { + 'fields': ('enable_data_sharing_consent', 'enforce_data_sharing_consent') + }), + ('Email and language ', { + 'fields': ('contact_email', 'reply_to', 'sender_alias', 'default_language', 'hide_labor_market_data') + }), + ('Reporting', { + 'fields': ('enable_portal_reporting_config_screen',) + }), + ('Integration and learning platform settings', { + 'fields': ('enable_portal_lms_configurations_screen', 'enable_portal_saml_configuration_screen', + 'enable_slug_login', 'replace_sensitive_sso_username', 'hide_course_original_price') + }), + ('Recommended default settings for all enterprise customers', { + 'fields': ('site', 'customer_type', 'enable_learner_portal', + 'enable_integrated_customer_learner_portal_search', + 'enable_analytics_screen', 'enable_audit_enrollment', + 'enable_audit_data_reporting', 'enable_learner_portal_offers', + 'enable_executive_education_2U_fulfillment'), + 'description': ('The following default settings should be the same for ' + 'the majority of enterprise customers,' + 'and are either rarely used, unlikely to be sold, ' + 'or unlikely to be changed from the default.') + }), + ) + inlines = [ EnterpriseCustomerBrandingConfigurationInline, EnterpriseCustomerIdentityProviderInline, diff --git a/enterprise/migrations/0175_auto_20230629_2330.py b/enterprise/migrations/0175_auto_20230629_2330.py new file mode 100644 index 0000000000..65410d2f85 --- /dev/null +++ b/enterprise/migrations/0175_auto_20230629_2330.py @@ -0,0 +1,296 @@ +# Generated by Django 3.2.19 on 2023-06-29 23:30 + +from django.db import migrations, models +import django.db.models.deletion +import enterprise.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0002_alter_domain_unique'), + ('enterprise', '0174_auto_20230608_2041'), + ] + + operations = [ + migrations.AlterField( + model_name='enterprisecustomer', + name='active', + field=models.BooleanField(default=True, verbose_name='Active admin portal'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='auth_org_id', + field=models.CharField(blank=True, help_text="Enterprise customer's authentication ID if leveraging a third party platform such as Auth0 for authentication.", max_length=80, null=True, verbose_name='Third Party Auth Org ID:'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='contact_email', + field=models.EmailField(blank=True, help_text='Email address presented on learner portal as public point of contact from customer organization.', max_length=254, null=True, verbose_name='Customer admin contact email:'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='customer_type', + field=models.ForeignKey(default=enterprise.models.get_default_customer_type, on_delete=django.db.models.deletion.CASCADE, to='enterprise.enterprisecustomertype', verbose_name='Customer Type'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='default_language', + field=models.CharField(blank=True, choices=[('en', 'English'), ('es-419', 'Español (Latinoamérica)')], default=None, help_text='Specifies the default language for learners of the organization.', max_length=25, null=True, verbose_name='Learner default language'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_analytics_screen', + field=models.BooleanField(default=True, help_text='Automatically enabled. Displays advanced analytics page on the administrator portal, which includes skill and labor market data.', verbose_name='Display analytics page'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_audit_data_reporting', + field=models.BooleanField(default=False, help_text='Enables transmission of audit enrollment data from learning platform learners.', verbose_name='Enable audit enrollment data reporting for learning platform learners'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_audit_enrollment', + field=models.BooleanField(default=False, help_text='Allows learners enrolling through learning platforms to select the audit track.', verbose_name='Enable audit enrollment for learning platform learners'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_browse_and_request', + field=models.BooleanField(default=False, verbose_name='Display browse and request management settings'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_data_sharing_consent', + field=models.BooleanField(default=False, help_text='Enables data sharing consent prompt for learners each time they enroll in a course. If left unchecked, the prompt will not appear and relevant data will not be shared.', verbose_name='Activate data sharing consent prompt'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_integrated_customer_learner_portal_search', + field=models.BooleanField(default=True, help_text="Automatically enabled. If unchecked, the learners won't be able to search for a course on the learner portal.", verbose_name='Allow course discovery within the learner portal'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_learner_portal', + field=models.BooleanField(default=True, help_text="Automatically enabled. If unchecked, learners won't have access to the learner portal."), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_learner_portal_offers', + field=models.BooleanField(default=False, help_text='Specifies whether enterprise offers will be made known to learners in the learner portal This only applies to customers with “offers”, the old version of learner credit.', verbose_name='Enable learner credit in the learner portal'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_code_management_screen', + field=models.BooleanField(default=False, verbose_name='Display code management screen'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_learner_credit_management_screen', + field=models.BooleanField(default=False, verbose_name='Display learner credit management screen'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_lms_configurations_screen', + field=models.BooleanField(default=False, help_text='Enables the learning platform configuration screen on the administrator portal.', verbose_name='Display learning platform configuration screen'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_reporting_config_screen', + field=models.BooleanField(default=False, help_text='Enables the scheduled reporting configurations screen on the administrator portal.', verbose_name='Display enterprise reporting page'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_saml_configuration_screen', + field=models.BooleanField(default=False, help_text='Enables the Single Sign On (SSO) configuration screen on the administrator portal. ', verbose_name='Display SSO configuration screen'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_portal_subscription_management_screen', + field=models.BooleanField(default=False, verbose_name='Display subscription management screen'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_slug_login', + field=models.BooleanField(default=False, help_text='Allows a learner to input customer slug to identify their org in the SSO process. Should be enabled for customers that leverage SSO.', verbose_name='Allow slug login for SSO'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enable_universal_link', + field=models.BooleanField(default=False, verbose_name='Display universal link settings'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='enforce_data_sharing_consent', + field=models.CharField(choices=[('at_enrollment', 'At Enrollment'), ('externally_managed', 'Managed externally')], default='at_enrollment', help_text='Setting to either require learners to accept data sharing consent at course enrollment, or through an external process.', max_length=25, verbose_name='Data sharing consent enforcement:'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='hide_course_original_price', + field=models.BooleanField(default=False, help_text='Hides course price on learning platform course confirmation screen.', verbose_name='Hide course price on learning platform'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='hide_labor_market_data', + field=models.BooleanField(default=False, help_text='Hides labor market data from learners (populated by features using Lightcast integration). ', verbose_name='Hide labor market data on skill features'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='replace_sensitive_sso_username', + field=models.BooleanField(default=False, help_text='Specifies whether to replace the display of potentially sensitive SSO usernames with a more generic name, e.g. EnterpriseLearner.', verbose_name='Replace sensitive SSO username'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='reply_to', + field=models.EmailField(blank=True, help_text='Email address that will receive learner replies to automated edX emails.', max_length=254, null=True, verbose_name='Customer “reply to” email:'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='sender_alias', + field=models.CharField(blank=True, help_text='Specifies the sender alias for automated emails from the edX system.', max_length=255, null=True, verbose_name='Automated email sender alias'), + ), + migrations.AlterField( + model_name='enterprisecustomer', + name='site', + field=models.ForeignKey(default=enterprise.models.EnterpriseCustomer.get_default_site, on_delete=django.db.models.deletion.CASCADE, related_name='enterprise_customers', to='sites.site'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='active', + field=models.BooleanField(default=True, verbose_name='Active admin portal'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='auth_org_id', + field=models.CharField(blank=True, help_text="Enterprise customer's authentication ID if leveraging a third party platform such as Auth0 for authentication.", max_length=80, null=True, verbose_name='Third Party Auth Org ID:'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='contact_email', + field=models.EmailField(blank=True, help_text='Email address presented on learner portal as public point of contact from customer organization.', max_length=254, null=True, verbose_name='Customer admin contact email:'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='customer_type', + field=models.ForeignKey(blank=True, db_constraint=False, default=enterprise.models.get_default_customer_type, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='enterprise.enterprisecustomertype', verbose_name='Customer Type'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='default_language', + field=models.CharField(blank=True, choices=[('en', 'English'), ('es-419', 'Español (Latinoamérica)')], default=None, help_text='Specifies the default language for learners of the organization.', max_length=25, null=True, verbose_name='Learner default language'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_analytics_screen', + field=models.BooleanField(default=True, help_text='Automatically enabled. Displays advanced analytics page on the administrator portal, which includes skill and labor market data.', verbose_name='Display analytics page'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_audit_data_reporting', + field=models.BooleanField(default=False, help_text='Enables transmission of audit enrollment data from learning platform learners.', verbose_name='Enable audit enrollment data reporting for learning platform learners'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_audit_enrollment', + field=models.BooleanField(default=False, help_text='Allows learners enrolling through learning platforms to select the audit track.', verbose_name='Enable audit enrollment for learning platform learners'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_browse_and_request', + field=models.BooleanField(default=False, verbose_name='Display browse and request management settings'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_data_sharing_consent', + field=models.BooleanField(default=False, help_text='Enables data sharing consent prompt for learners each time they enroll in a course. If left unchecked, the prompt will not appear and relevant data will not be shared.', verbose_name='Activate data sharing consent prompt'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_integrated_customer_learner_portal_search', + field=models.BooleanField(default=True, help_text="Automatically enabled. If unchecked, the learners won't be able to search for a course on the learner portal.", verbose_name='Allow course discovery within the learner portal'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_learner_portal', + field=models.BooleanField(default=True, help_text="Automatically enabled. If unchecked, learners won't have access to the learner portal."), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_learner_portal_offers', + field=models.BooleanField(default=False, help_text='Specifies whether enterprise offers will be made known to learners in the learner portal This only applies to customers with “offers”, the old version of learner credit.', verbose_name='Enable learner credit in the learner portal'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_code_management_screen', + field=models.BooleanField(default=False, verbose_name='Display code management screen'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_learner_credit_management_screen', + field=models.BooleanField(default=False, verbose_name='Display learner credit management screen'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_lms_configurations_screen', + field=models.BooleanField(default=False, help_text='Enables the learning platform configuration screen on the administrator portal.', verbose_name='Display learning platform configuration screen'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_reporting_config_screen', + field=models.BooleanField(default=False, help_text='Enables the scheduled reporting configurations screen on the administrator portal.', verbose_name='Display enterprise reporting page'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_saml_configuration_screen', + field=models.BooleanField(default=False, help_text='Enables the Single Sign On (SSO) configuration screen on the administrator portal. ', verbose_name='Display SSO configuration screen'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_portal_subscription_management_screen', + field=models.BooleanField(default=False, verbose_name='Display subscription management screen'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_slug_login', + field=models.BooleanField(default=False, help_text='Allows a learner to input customer slug to identify their org in the SSO process. Should be enabled for customers that leverage SSO.', verbose_name='Allow slug login for SSO'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enable_universal_link', + field=models.BooleanField(default=False, verbose_name='Display universal link settings'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='enforce_data_sharing_consent', + field=models.CharField(choices=[('at_enrollment', 'At Enrollment'), ('externally_managed', 'Managed externally')], default='at_enrollment', help_text='Setting to either require learners to accept data sharing consent at course enrollment, or through an external process.', max_length=25, verbose_name='Data sharing consent enforcement:'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='hide_course_original_price', + field=models.BooleanField(default=False, help_text='Hides course price on learning platform course confirmation screen.', verbose_name='Hide course price on learning platform'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='hide_labor_market_data', + field=models.BooleanField(default=False, help_text='Hides labor market data from learners (populated by features using Lightcast integration). ', verbose_name='Hide labor market data on skill features'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='replace_sensitive_sso_username', + field=models.BooleanField(default=False, help_text='Specifies whether to replace the display of potentially sensitive SSO usernames with a more generic name, e.g. EnterpriseLearner.', verbose_name='Replace sensitive SSO username'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='reply_to', + field=models.EmailField(blank=True, help_text='Email address that will receive learner replies to automated edX emails.', max_length=254, null=True, verbose_name='Customer “reply to” email:'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='sender_alias', + field=models.CharField(blank=True, help_text='Specifies the sender alias for automated emails from the edX system.', max_length=255, null=True, verbose_name='Automated email sender alias'), + ), + migrations.AlterField( + model_name='historicalenterprisecustomer', + name='site', + field=models.ForeignKey(blank=True, db_constraint=False, default=enterprise.models.EnterpriseCustomer.get_default_site, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='sites.site'), + ), + ] diff --git a/enterprise/models.py b/enterprise/models.py index 811f62ba10..7e9ba45007 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -5,6 +5,7 @@ import collections import itertools import json +import os from decimal import Decimal from urllib.parse import urljoin from uuid import UUID, uuid4 @@ -195,23 +196,43 @@ class Meta: ) ) auth_org_id = models.CharField( + "Third Party Auth Org ID:", max_length=80, blank=True, null=True, help_text=( - "Enterprise Customer auth organization id" + "Enterprise customer's authentication ID " + "if leveraging a third party platform such as Auth0 for authentication." ) ) - active = models.BooleanField(default=True) + active = models.BooleanField("Active admin portal", default=True) country = CountryField(null=True) hide_course_original_price = models.BooleanField( + "Hide course price on learning platform", default=False, help_text=_( - "Specify whether display the course original price on enterprise course landing page or not." + "Hides course price on learning platform course confirmation screen." ) ) history = HistoricalRecords() + + def get_default_site(self): + """ + Get default site id to use when creating a new EnterpriseCustomer model. + The default value depending on what environment the person is in. + In production, it should be 'courses.edx.org'. + It stage it should be 'courses.stage.edx.org'. + """ + ENVIRONMENT = os.getenv('DJANGO_ENVIRONMENT', 'development') + if ENVIRONMENT == 'production': + value = 'courses.edx.org' + else: + value = 'courses.stage.edx.org' + site, __ = Site.objects.get_or_create(domain=value, name=value) + return site.id + site = models.ForeignKey( Site, related_name="enterprise_customers", + default=get_default_site, on_delete=models.deletion.CASCADE ) @@ -223,41 +244,44 @@ class Meta: ) enable_data_sharing_consent = models.BooleanField( + "Activate data sharing consent prompt", default=False, help_text=_( - "Specifies whether data sharing consent is enabled or disabled " - "for learners signing in through this enterprise customer. If " - "disabled, consent will not be requested, and eligible data will " - "not be shared." + "Enables data sharing consent prompt for learners each time they enroll in a course. " + "If left unchecked, the prompt will not appear and relevant data will not be shared." ) ) enforce_data_sharing_consent = models.CharField( + "Data sharing consent enforcement:", max_length=25, blank=False, choices=DATA_SHARING_CONSENT_CHOICES, default=AT_ENROLLMENT, help_text=_( - "Specifies whether data sharing consent is optional, is required " - "at login, or is required at enrollment." + "Setting to either require learners to accept data sharing consent at course enrollment, " + "or through an external process." ) ) enable_audit_enrollment = models.BooleanField( + "Enable audit enrollment for learning platform learners", default=False, help_text=_( - "Specifies whether the audit track enrollment option will be displayed in the course enrollment view." + "Allows learners enrolling through learning platforms to select the audit track." ) ) enable_audit_data_reporting = models.BooleanField( + "Enable audit enrollment data reporting for learning platform learners", default=False, help_text=_( - "Specifies whether to pass-back audit track enrollment data through an integrated channel." + "Enables transmission of audit enrollment data from learning platform learners." ) ) replace_sensitive_sso_username = models.BooleanField( + "Replace sensitive SSO username", default=False, help_text=_( "Specifies whether to replace the display of potentially sensitive SSO usernames " @@ -278,90 +302,92 @@ class Meta: EnterpriseCustomerType, verbose_name=_('Customer Type'), default=get_default_customer_type, - help_text=_( - 'Specifies enterprise customer type.' - ), on_delete=models.CASCADE + on_delete=models.CASCADE ) enable_portal_code_management_screen = models.BooleanField( + "Display code management screen", default=False, - help_text=_("Specifies whether to allow access to the code management screen in the admin portal.") ) enable_portal_reporting_config_screen = models.BooleanField( + "Display enterprise reporting page", default=False, - help_text=_("Specifies whether to allow access to the reporting configurations screen in the admin portal.") + help_text=_("Enables the scheduled reporting configurations screen on the administrator portal.") ) enable_portal_subscription_management_screen = models.BooleanField( + "Display subscription management screen", default=False, - help_text=_("Specifies whether to allow access to the subscription management screen in the admin portal.") ) enable_portal_saml_configuration_screen = models.BooleanField( + "Display SSO configuration screen", default=False, - help_text=_("Specifies whether to allow access to the saml configuration screen in the admin portal") + help_text=_("Enables the Single Sign On (SSO) configuration screen on the administrator portal. ") ) enable_universal_link = models.BooleanField( + "Display universal link settings", default=False, - help_text=_( - "Specifies whether universal link generation is enabled for customer. " - "Managed via admin portal settings UI." - ) ) enable_browse_and_request = models.BooleanField( + "Display browse and request management settings", default=False, - help_text=_( - "Specifies whether browse and request is enabled for this customer. " - "Managed via admin portal settings UI." - ) ) enable_learner_portal = models.BooleanField( - default=False, - help_text=_("Specifies whether the enterprise learner portal site should be made known to the learner.") + default=True, + help_text=_("Automatically enabled. If unchecked, learners won't have access to the learner portal.") ) enable_learner_portal_offers = models.BooleanField( - "Enable Learner Credit in the Learner Portal", + "Enable learner credit in the learner portal", default=False, - help_text=_("Specifies whether enterprise offers will be made known to learners in the learner portal.") + help_text=_("Specifies whether enterprise offers will be made known to learners in the learner portal " + "This only applies to customers with “offers”, the old version of learner credit.") ) enable_portal_learner_credit_management_screen = models.BooleanField( + "Display learner credit management screen", default=False, - help_text=_("Specifies whether to allow access to the learner credit management screen in the admin portal.") ) hide_labor_market_data = models.BooleanField( + "Hide labor market data on skill features", default=False, - help_text=_("Specifies whether the labor market data should be made known to the learner in learner portal.") + help_text=_('Hides labor market data from learners (populated by features using Lightcast integration). ') ) enable_integrated_customer_learner_portal_search = models.BooleanField( - "Enable learner portal search for LMS customers", + "Allow course discovery within the learner portal", default=True, help_text=_( - "Checked by default. When unchecked, learners in organizations with an integrated channel (LMS) will " - "not see the \"Find a Course\" option in the enterprise learner portal." + "Automatically enabled. " + "If unchecked, the learners won't be able to search for a course on the learner portal." ) ) enable_analytics_screen = models.BooleanField( - default=False, - help_text=_("Specifies whether to allow access to the analytics screen in the admin portal.") + "Display analytics page", + default=True, + help_text=_("Automatically enabled. " + "Displays advanced analytics page on the administrator portal, " + "which includes skill and labor market data.") ) enable_portal_lms_configurations_screen = models.BooleanField( + "Display learning platform configuration screen", default=False, - help_text=_("Specifies whether to allow access to the external LMS configuration screen in the admin portal.") + help_text=_("Enables the learning platform configuration screen on the administrator portal.") ) enable_slug_login = models.BooleanField( + "Allow slug login for SSO", default=False, - help_text=_("Specifies whether the learner should be able to login through enterprise's slug login") + help_text=_("Allows a learner to input customer slug to identify their org in the SSO process. " + "Should be enabled for customers that leverage SSO.") ) enable_executive_education_2U_fulfillment = models.BooleanField( @@ -370,9 +396,10 @@ class Meta: ) contact_email = models.EmailField( + "Customer admin contact email:", null=True, blank=True, - help_text=_("Email to be displayed as public point of contact for enterprise.") + help_text=_("Email address presented on learner portal as public point of contact from customer organization.") ) default_contract_discount = models.DecimalField( @@ -388,29 +415,32 @@ class Meta: ) default_language = models.CharField( + "Learner default language", max_length=25, null=True, blank=True, choices=AVAILABLE_LANGUAGES, default=None, help_text=_( - "Specifies the default language for all the learners of this enterprise customer." + "Specifies the default language for learners of the organization." ) ) sender_alias = models.CharField( + "Automated email sender alias", max_length=255, null=True, blank=True, help_text=_( - "Specifies enterprise customized sender alias." + "Specifies the sender alias for automated emails from the edX system." ) ) reply_to = models.EmailField( + "Customer “reply to” email:", null=True, blank=True, - help_text=_("The email address where learner's reply to enterprise emails will be delivered.") + help_text=_("Email address that will receive learner replies to automated edX emails.") ) @property diff --git a/tests/test_enterprise/api/test_views.py b/tests/test_enterprise/api/test_views.py index f9a29ac9a2..a3695d968e 100644 --- a/tests/test_enterprise/api/test_views.py +++ b/tests/test_enterprise/api/test_views.py @@ -1132,39 +1132,42 @@ class TestEnterpriseCustomerViewSet(BaseTestEnterpriseAPIViews): 'modified': '2021-10-20T19:01:31Z', }], [{ - 'uuid': FAKE_UUIDS[0], 'name': 'Test Enterprise Customer', 'slug': TEST_SLUG, - 'admin_users': [], 'active': True, + 'uuid': FAKE_UUIDS[0], 'name': 'Test Enterprise Customer', + 'slug': TEST_SLUG, 'active': True, 'auth_org_id': 'asdf3e2wdas', + 'site': { + 'domain': 'example.com', 'name': 'example.com' + }, 'enable_data_sharing_consent': True, 'enforce_data_sharing_consent': 'at_enrollment', 'branding_configuration': get_default_branding_object(FAKE_UUIDS[0], TEST_SLUG), - 'enable_audit_enrollment': False, 'enable_audit_data_reporting': True, 'identity_provider': None, + 'identity_provider': None, + 'enable_audit_enrollment': False, 'replace_sensitive_sso_username': False, 'enable_portal_code_management_screen': False, - 'enable_portal_reporting_config_screen': False, - 'enable_portal_saml_configuration_screen': False, - 'enable_portal_lms_configurations_screen': False, - 'enable_universal_link': False, - 'enable_browse_and_request': False, - 'site': { - 'domain': 'example.com', 'name': 'example.com' - }, 'sync_learner_profile_data': False, - 'enable_learner_portal': False, + 'enable_audit_data_reporting': True, + 'enable_learner_portal': True, 'enable_learner_portal_offers': False, 'enable_portal_learner_credit_management_screen': False, 'enable_executive_education_2U_fulfillment': False, - 'enable_integrated_customer_learner_portal_search': True, - 'enable_portal_subscription_management_screen': False, - 'enable_analytics_screen': False, + 'enable_portal_reporting_config_screen': False, + 'enable_portal_saml_configuration_screen': False, 'contact_email': 'fake@example.com', - 'reply_to': 'fake_reply@example.com', - 'hide_labor_market_data': False, + 'enable_portal_subscription_management_screen': False, 'hide_course_original_price': False, + 'enable_analytics_screen': True, + 'enable_integrated_customer_learner_portal_search': True, + 'enable_portal_lms_configurations_screen': False, 'sender_alias': 'Test Sender Alias', 'identity_providers': [], 'enterprise_customer_catalogs': [], - 'enterprise_notification_banner': {'text': '', 'title': ''}, + 'reply_to': 'fake_reply@example.com', + 'enterprise_notification_banner': {'title': '', 'text': ''}, + 'hide_labor_market_data': False, 'modified': '2021-10-20T19:01:31Z', + 'enable_universal_link': False, + 'enable_browse_and_request': False, + 'admin_users': [] }], ), ( @@ -1188,44 +1191,39 @@ class TestEnterpriseCustomerViewSet(BaseTestEnterpriseAPIViews): 'enterprise_customer__auth_org_id': 'asdf3e2wdas', }], [{ - 'id': 1, 'user_id': 0, 'user': None, 'active': True, 'created': '2021-10-20T19:01:31Z', - 'invite_key': None, 'role_assignments': [], 'data_sharing_consent_records': [], 'groups': [], + 'id': 1, 'enterprise_customer': { - 'uuid': FAKE_UUIDS[0], 'name': 'Test Enterprise Customer', 'slug': TEST_SLUG, - 'admin_users': [], 'active': True, - 'auth_org_id': 'asdf3e2wdas', + 'uuid': FAKE_UUIDS[0], 'name': 'Test Enterprise Customer', + 'slug': TEST_SLUG, 'active': True, 'auth_org_id': 'asdf3e2wdas', + 'site': { + 'domain': 'example.com', 'name': 'example.com' + }, 'enable_data_sharing_consent': True, 'enforce_data_sharing_consent': 'at_enrollment', 'branding_configuration': get_default_branding_object(FAKE_UUIDS[0], TEST_SLUG), - 'enable_audit_enrollment': False, 'identity_provider': None, + 'identity_provider': None, 'enable_audit_enrollment': False, 'replace_sensitive_sso_username': False, 'enable_portal_code_management_screen': False, - 'enable_portal_reporting_config_screen': False, - 'enable_portal_saml_configuration_screen': False, - 'enable_portal_lms_configurations_screen': False, - 'enable_universal_link': False, - 'enable_browse_and_request': False, - 'enable_audit_data_reporting': False, - 'site': { - 'domain': 'example.com', 'name': 'example.com' - }, - 'sync_learner_profile_data': False, - 'enable_learner_portal': False, - 'enable_learner_portal_offers': False, + 'sync_learner_profile_data': False, 'enable_audit_data_reporting': False, + 'enable_learner_portal': True, 'enable_learner_portal_offers': False, 'enable_portal_learner_credit_management_screen': False, 'enable_executive_education_2U_fulfillment': False, - 'enable_integrated_customer_learner_portal_search': True, - 'enable_portal_subscription_management_screen': False, - 'enable_analytics_screen': False, + 'enable_portal_reporting_config_screen': False, + 'enable_portal_saml_configuration_screen': False, 'contact_email': 'fake@example.com', - 'hide_course_original_price': False, - 'sender_alias': 'Test Sender Alias', - 'identity_providers': [], - 'enterprise_customer_catalogs': [], - 'reply_to': 'fake_reply@example.com', - 'hide_labor_market_data': False, - 'enterprise_notification_banner': {'text': '', 'title': ''}, - 'modified': '2021-10-20T19:01:31Z', - } + 'enable_portal_subscription_management_screen': False, + 'hide_course_original_price': False, 'enable_analytics_screen': True, + 'enable_integrated_customer_learner_portal_search': True, + 'enable_portal_lms_configurations_screen': False, + 'sender_alias': 'Test Sender Alias', 'identity_providers': [], + 'enterprise_customer_catalogs': [], 'reply_to': 'fake_reply@example.com', + 'enterprise_notification_banner': {'title': '', 'text': ''}, + 'hide_labor_market_data': False, 'modified': '2021-10-20T19:01:31Z', + 'enable_universal_link': False, 'enable_browse_and_request': False, + 'admin_users': [], + }, + 'active': True, 'user_id': 0, 'user': None, + 'data_sharing_consent_records': [], 'groups': [], + 'created': '2021-10-20T19:01:31Z', 'invite_key': None, 'role_assignments': [], }], ), ( @@ -1267,35 +1265,31 @@ class TestEnterpriseCustomerViewSet(BaseTestEnterpriseAPIViews): }], [{ 'uuid': FAKE_UUIDS[1], 'name': 'Test Enterprise Customer', 'slug': TEST_SLUG, - 'admin_users': [], 'active': True, + 'active': True, 'auth_org_id': 'asdf3e2wdas', + 'site': { + 'domain': 'example.com', 'name': 'example.com' + }, 'enable_data_sharing_consent': True, 'enforce_data_sharing_consent': 'at_enrollment', 'branding_configuration': get_default_branding_object(FAKE_UUIDS[1], TEST_SLUG), - 'enable_audit_enrollment': False, 'identity_provider': FAKE_UUIDS[0], + 'identity_provider': FAKE_UUIDS[0], 'enable_audit_enrollment': False, 'replace_sensitive_sso_username': False, 'enable_portal_code_management_screen': False, - 'enable_portal_reporting_config_screen': False, - 'enable_portal_saml_configuration_screen': False, - 'enable_portal_lms_configurations_screen': False, - 'enable_universal_link': False, - 'enable_browse_and_request': False, - 'enable_audit_data_reporting': False, - 'site': { - 'domain': 'example.com', 'name': 'example.com' - }, 'sync_learner_profile_data': False, - 'enable_learner_portal': False, + 'enable_audit_data_reporting': False, + 'enable_learner_portal': True, 'enable_learner_portal_offers': False, 'enable_portal_learner_credit_management_screen': False, 'enable_executive_education_2U_fulfillment': False, - 'enable_integrated_customer_learner_portal_search': True, - 'enable_portal_subscription_management_screen': False, - 'enable_analytics_screen': False, + 'enable_portal_reporting_config_screen': False, + 'enable_portal_saml_configuration_screen': False, 'contact_email': 'fake@example.com', + 'enable_portal_subscription_management_screen': False, 'hide_course_original_price': False, + 'enable_analytics_screen': True, + 'enable_integrated_customer_learner_portal_search': True, + 'enable_portal_lms_configurations_screen': False, 'sender_alias': 'Test Sender Alias', - 'reply_to': 'fake_reply@example.com', - 'hide_labor_market_data': False, 'identity_providers': [ { "provider_id": FAKE_UUIDS[0], @@ -1303,8 +1297,13 @@ class TestEnterpriseCustomerViewSet(BaseTestEnterpriseAPIViews): }, ], 'enterprise_customer_catalogs': [], - 'enterprise_notification_banner': {'text': '', 'title': ''}, + 'reply_to': 'fake_reply@example.com', + 'enterprise_notification_banner': {'title': '', 'text': ''}, + 'hide_labor_market_data': False, 'modified': '2021-10-20T19:01:31Z', + 'enable_universal_link': False, + 'enable_browse_and_request': False, + 'admin_users': [], }], ), ( @@ -1330,41 +1329,41 @@ class TestEnterpriseCustomerViewSet(BaseTestEnterpriseAPIViews): }], [{ 'uuid': FAKE_UUIDS[1], 'name': 'Test Enterprise Customer', 'slug': TEST_SLUG, - 'admin_users': [], 'active': True, - 'auth_org_id': 'asdf3e2wdas', + 'active': True, 'auth_org_id': 'asdf3e2wdas', + 'site': { + 'domain': 'example.com', 'name': 'example.com' + }, 'enable_data_sharing_consent': True, 'enforce_data_sharing_consent': 'at_enrollment', 'branding_configuration': get_default_branding_object(FAKE_UUIDS[1], TEST_SLUG), - 'enable_audit_enrollment': False, 'identity_provider': None, + 'enable_audit_enrollment': False, 'replace_sensitive_sso_username': False, 'enable_portal_code_management_screen': False, - 'enable_portal_reporting_config_screen': False, - 'enable_portal_saml_configuration_screen': False, - 'enable_portal_lms_configurations_screen': False, - 'enable_universal_link': False, - 'enable_browse_and_request': False, + 'sync_learner_profile_data': False, + 'enable_audit_data_reporting': False, + 'enable_learner_portal': True, 'enable_learner_portal_offers': False, 'enable_portal_learner_credit_management_screen': False, 'enable_executive_education_2U_fulfillment': False, - 'enable_audit_data_reporting': False, - 'site': { - 'domain': 'example.com', 'name': 'example.com' - }, - 'sync_learner_profile_data': False, - 'enable_learner_portal': False, - 'enable_integrated_customer_learner_portal_search': True, - 'enable_portal_subscription_management_screen': False, - 'enable_analytics_screen': False, + 'enable_portal_reporting_config_screen': False, + 'enable_portal_saml_configuration_screen': False, 'contact_email': 'fake@example.com', + 'enable_portal_subscription_management_screen': False, 'hide_course_original_price': False, + 'enable_analytics_screen': True, + 'enable_integrated_customer_learner_portal_search': True, + 'enable_portal_lms_configurations_screen': False, 'sender_alias': 'Test Sender Alias', - 'reply_to': 'fake_reply@example.com', - 'hide_labor_market_data': False, 'identity_providers': [], 'enterprise_customer_catalogs': [FAKE_UUIDS[0]], - 'enterprise_notification_banner': {'text': '', 'title': ''}, + 'reply_to': 'fake_reply@example.com', + 'enterprise_notification_banner': {'title': '', 'text': ''}, + 'hide_labor_market_data': False, 'modified': '2021-10-20T19:01:31Z', + 'enable_universal_link': False, + 'enable_browse_and_request': False, + 'admin_users': [], }], ), ( @@ -1548,37 +1547,42 @@ def test_enterprise_customer_with_access_to( if has_access_to_enterprise: assert response['results'][0] == { 'uuid': FAKE_UUIDS[0], 'name': 'Test Enterprise Customer', 'slug': TEST_SLUG, - 'admin_users': [], 'active': True, 'enable_data_sharing_consent': True, - 'enforce_data_sharing_consent': 'at_enrollment', - 'branding_configuration': get_default_branding_object(FAKE_UUIDS[0], TEST_SLUG), - 'enable_audit_enrollment': False, 'enable_audit_data_reporting': False, 'identity_provider': None, - 'replace_sensitive_sso_username': False, 'enable_portal_code_management_screen': True, - 'enable_portal_reporting_config_screen': False, - 'enable_portal_saml_configuration_screen': False, - 'enable_portal_lms_configurations_screen': False, - 'enable_universal_link': False, - 'enable_browse_and_request': False, + 'active': True, + 'auth_org_id': enterprise_customer_data.get('auth_org_id'), 'site': { 'domain': 'example.com', 'name': 'example.com' }, + 'enable_data_sharing_consent': True, + 'enforce_data_sharing_consent': 'at_enrollment', + 'branding_configuration': get_default_branding_object(FAKE_UUIDS[0], TEST_SLUG), + 'identity_provider': None, + 'enable_audit_enrollment': False, + 'replace_sensitive_sso_username': False, + 'enable_portal_code_management_screen': True, 'sync_learner_profile_data': False, - 'enable_learner_portal': False, + 'enable_audit_data_reporting': False, + 'enable_learner_portal': True, 'enable_learner_portal_offers': False, 'enable_portal_learner_credit_management_screen': False, 'enable_executive_education_2U_fulfillment': False, - 'enable_integrated_customer_learner_portal_search': True, - 'enable_portal_subscription_management_screen': False, - 'enable_analytics_screen': False, + 'enable_portal_reporting_config_screen': False, + 'enable_portal_saml_configuration_screen': False, 'contact_email': 'fake@example.com', + 'enable_portal_subscription_management_screen': False, 'hide_course_original_price': False, + 'enable_analytics_screen': False, + 'enable_integrated_customer_learner_portal_search': True, + 'enable_portal_lms_configurations_screen': False, 'sender_alias': 'Test Sender Alias', 'identity_providers': [], 'enterprise_customer_catalogs': [], 'reply_to': 'fake_reply@example.com', + 'enterprise_notification_banner': {'title': '', 'text': ''}, 'hide_labor_market_data': False, - 'enterprise_notification_banner': {'text': '', 'title': ''}, 'modified': '2021-10-20T19:32:12Z', - 'auth_org_id': enterprise_customer_data.get('auth_org_id'), + 'enable_universal_link': False, + 'enable_browse_and_request': False, + 'admin_users': [] } else: assert response == expected_error