From 9b30efde3d6e71c67957342f2fb1b9641d4b05d7 Mon Sep 17 00:00:00 2001 From: Hamzah Ullah Date: Wed, 2 Oct 2024 20:51:09 +0000 Subject: [PATCH] feat: Add field to allow auto-apply without SSO --- license_manager/apps/api/serializers.py | 1 + license_manager/apps/subscriptions/admin.py | 1 + .../apps/subscriptions/constants.py | 8 +++++++ license_manager/apps/subscriptions/forms.py | 15 +++++++++--- ...scriptions_with_universal_link_and_more.py | 23 +++++++++++++++++++ license_manager/apps/subscriptions/models.py | 11 +++++++++ .../apps/subscriptions/tests/factories.py | 1 + .../apps/subscriptions/tests/test_admin.py | 5 +++- .../apps/subscriptions/tests/test_forms.py | 3 ++- pylintrc | 4 ++-- 10 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 license_manager/apps/subscriptions/migrations/0071_customeragreement_enable_auto_applied_subscriptions_with_universal_link_and_more.py diff --git a/license_manager/apps/api/serializers.py b/license_manager/apps/api/serializers.py index 10d7d1a5..38a56e78 100644 --- a/license_manager/apps/api/serializers.py +++ b/license_manager/apps/api/serializers.py @@ -358,6 +358,7 @@ class Meta: 'expired_subscription_modal_messaging', 'hyper_link_text_for_expired_modal', 'url_for_expired_modal', + 'enable_auto_applied_subscriptions_with_universal_link' ] def get_subscription_for_auto_applied_licenses(self, obj): diff --git a/license_manager/apps/subscriptions/admin.py b/license_manager/apps/subscriptions/admin.py index e2924184..0697816a 100644 --- a/license_manager/apps/subscriptions/admin.py +++ b/license_manager/apps/subscriptions/admin.py @@ -421,6 +421,7 @@ class CustomerAgreementAdmin(admin.ModelAdmin): 'expired_subscription_modal_messaging', 'hyper_link_text_for_expired_modal', 'url_for_expired_modal', + 'enable_auto_applied_subscriptions_with_universal_link' ) custom_fields = ('subscription_for_auto_applied_licenses',) diff --git a/license_manager/apps/subscriptions/constants.py b/license_manager/apps/subscriptions/constants.py index 492e3501..8782e9c7 100644 --- a/license_manager/apps/subscriptions/constants.py +++ b/license_manager/apps/subscriptions/constants.py @@ -25,6 +25,14 @@ class LicenseTypesToRenew: ) +class SubscriptionPlanShouldAutoApplyLicensesChoices: + CHOICES = ( + (None, "----------"), + (True, "Yes"), + (False, "No") + ) + + class SubscriptionPlanChangeReasonChoices: NONE = None NEW = "new" diff --git a/license_manager/apps/subscriptions/forms.py b/license_manager/apps/subscriptions/forms.py index e6324795..4e96753e 100644 --- a/license_manager/apps/subscriptions/forms.py +++ b/license_manager/apps/subscriptions/forms.py @@ -19,6 +19,7 @@ MAX_NUM_LICENSES, MIN_NUM_LICENSES, SubscriptionPlanChangeReasonChoices, + SubscriptionPlanShouldAutoApplyLicensesChoices, ) from license_manager.apps.subscriptions.models import ( CustomerAgreement, @@ -40,6 +41,14 @@ class SubscriptionPlanForm(forms.ModelForm): """ Form used for the SubscriptionPlan admin class. """ + + should_auto_apply_licenses = forms.ChoiceField( + choices=SubscriptionPlanShouldAutoApplyLicensesChoices.CHOICES, + required=False, + label="Should auto apply licenses", + help_text="Whether licenses from this Subscription Plan should be auto applied." + ) + # Extra form field to specify the number of licenses to be associated with the subscription plan num_licenses = forms.IntegerField( label="Number of Licenses", @@ -276,15 +285,15 @@ def populate_subscription_for_auto_applied_licenses_choices(self, instance): start_date__lte=now, expiration_date__gte=now ) - current_plan = instance.auto_applicable_subscription - empty_choice = ('', '------') choices = [empty_choice] + [(plan.uuid, plan.title) for plan in active_plans] choice_field = forms.ChoiceField( choices=choices, required=False, - initial=empty_choice if not current_plan else (current_plan.uuid, current_plan.title) + initial=empty_choice if not current_plan else (current_plan.uuid, current_plan.title), + help_text="The subscription plan to be associated with auto apply licenses. Selecting a license" + " will automatically enable the \"Should auto apply licenses\" field on the subscription plan" ) self.fields['subscription_for_auto_applied_licenses'] = choice_field diff --git a/license_manager/apps/subscriptions/migrations/0071_customeragreement_enable_auto_applied_subscriptions_with_universal_link_and_more.py b/license_manager/apps/subscriptions/migrations/0071_customeragreement_enable_auto_applied_subscriptions_with_universal_link_and_more.py new file mode 100644 index 00000000..67d12885 --- /dev/null +++ b/license_manager/apps/subscriptions/migrations/0071_customeragreement_enable_auto_applied_subscriptions_with_universal_link_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.16 on 2024-10-07 15:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('subscriptions', '0070_customeragreement_expired_subscription_modal_messaging_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='customeragreement', + name='enable_auto_applied_subscriptions_with_universal_link', + field=models.BooleanField(default=False, help_text='By default, auto-applied subscriptions are only granted when learners join their enterprise via SSO, checking this box will enable subscription licenses to be applied when a learner joins the enterprise via Universal link as well'), + ), + migrations.AddField( + model_name='historicalcustomeragreement', + name='enable_auto_applied_subscriptions_with_universal_link', + field=models.BooleanField(default=False, help_text='By default, auto-applied subscriptions are only granted when learners join their enterprise via SSO, checking this box will enable subscription licenses to be applied when a learner joins the enterprise via Universal link as well'), + ), + ] diff --git a/license_manager/apps/subscriptions/models.py b/license_manager/apps/subscriptions/models.py index 355f7913..edffda87 100644 --- a/license_manager/apps/subscriptions/models.py +++ b/license_manager/apps/subscriptions/models.py @@ -178,6 +178,15 @@ class CustomerAgreement(TimeStampedModel): ) ) + enable_auto_applied_subscriptions_with_universal_link = models.BooleanField( + default=False, + help_text=_( + "By default, auto-applied subscriptions are only granted when learners join their enterprise via SSO, " + "checking this box will enable subscription licenses to be applied when a learner joins the enterprise via " + "Universal link as well" + ) + ) + history = HistoricalRecords() @property @@ -596,6 +605,7 @@ def num_revocations_remaining(self): num_revocations_allowed = ceil(self.num_licenses * (self.revoke_max_percentage / 100)) return num_revocations_allowed - self.num_revocations_applied + num_revocations_remaining.fget.short_description = "Number of Revocations Remaining" @property @@ -1036,6 +1046,7 @@ class License(TimeStampedModel): .. pii_types: id,email_address .. pii_retirement: local_api """ + class Meta: indexes = [ models.Index(fields=["subscription_plan", "status"], name="subscription_plan_status_idx"), diff --git a/license_manager/apps/subscriptions/tests/factories.py b/license_manager/apps/subscriptions/tests/factories.py index 96db577c..02aa39a7 100644 --- a/license_manager/apps/subscriptions/tests/factories.py +++ b/license_manager/apps/subscriptions/tests/factories.py @@ -54,6 +54,7 @@ class Meta: default_enterprise_catalog_uuid = factory.LazyFunction(uuid4) enterprise_customer_name = factory.LazyAttribute(lambda x: FAKER.company()) disable_onboarding_notifications = False + enable_auto_applied_subscriptions_with_universal_link = False class PlanTypeFactory(factory.django.DjangoModelFactory): diff --git a/license_manager/apps/subscriptions/tests/test_admin.py b/license_manager/apps/subscriptions/tests/test_admin.py index e2bab224..019db949 100644 --- a/license_manager/apps/subscriptions/tests/test_admin.py +++ b/license_manager/apps/subscriptions/tests/test_admin.py @@ -114,7 +114,10 @@ def test_select_subscription_for_auto_applied_licenses(mock_toggle_auto_apply_li request = RequestFactory() request.user = UserFactory() customer_agreement = CustomerAgreementFactory() - subscription_plan = SubscriptionPlanFactory(customer_agreement=customer_agreement) + subscription_plan = SubscriptionPlanFactory( + customer_agreement=customer_agreement, + ) + customer_agreement_uuid = str(customer_agreement.uuid) subscription_uuid = str(subscription_plan.uuid) request.resolver_match = mock.Mock(kwargs={'object_id': customer_agreement_uuid}) diff --git a/license_manager/apps/subscriptions/tests/test_forms.py b/license_manager/apps/subscriptions/tests/test_forms.py index c7154ba8..6563e871 100644 --- a/license_manager/apps/subscriptions/tests/test_forms.py +++ b/license_manager/apps/subscriptions/tests/test_forms.py @@ -241,10 +241,11 @@ def test_populate_subscription_for_auto_applied_licenses_choices(self): field = form.fields['subscription_for_auto_applied_licenses'] choices = field.choices + initial = field.initial self.assertEqual(len(choices), 2) self.assertEqual(choices[0], ('', '------')) self.assertEqual(choices[1], (active_subscription_plan.uuid, active_subscription_plan.title)) - self.assertEqual(field.initial, ('', '------')) + self.assertEqual(initial, ('', '------')) def test_populate_subscription_for_auto_applied_licenses_choices_initial_choice(self): customer_agreement = CustomerAgreementFactory() diff --git a/pylintrc b/pylintrc index fe450ac8..6edf14d3 100644 --- a/pylintrc +++ b/pylintrc @@ -64,7 +64,7 @@ # SERIOUSLY. # # ------------------------------ -# Generated by edx-lint version: 5.3.6 +# Generated by edx-lint version: 5.4.0 # ------------------------------ [MASTER] ignore = ,migrations, settings, wsgi.py @@ -401,4 +401,4 @@ int-import-graph = [EXCEPTIONS] overgeneral-exceptions = builtins.Exception -# fe60e0fc0935adda7e448a1daaa3ef3547352d92 +# ea586deca5871e992466c748232382f9dfadff18