-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #526 from openedx/ammar/update-license-assign-view…
…-to-set-license-source feat: update license assign view to set source for assigned licenses
- Loading branch information
Showing
5 changed files
with
163 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,7 @@ | |
from license_manager.apps.subscriptions.exceptions import LicenseRevocationError | ||
from license_manager.apps.subscriptions.models import ( | ||
License, | ||
SubscriptionLicenseSource, | ||
SubscriptionsFeatureRole, | ||
SubscriptionsRoleAssignment, | ||
) | ||
|
@@ -1507,6 +1508,71 @@ def test_assign(self, use_superuser, mock_send_assignment_email_task, mock_link_ | |
self.subscription_plan.customer_agreement.enterprise_customer_uuid | ||
) | ||
|
||
@mock.patch('license_manager.apps.api.v1.views.link_learners_to_enterprise_task.si') | ||
@mock.patch('license_manager.apps.api.v1.views.send_assignment_email_task.si') | ||
@ddt.data(True, False) | ||
def test_assign_with_salesforce_ids(self, use_superuser, *arge, **kwargs): # pylint: disable=unused-argument | ||
""" | ||
Verify the assign endpoint assigns licenses and correct lincese sources are created. | ||
""" | ||
self._setup_request_jwt(user=self.super_user if use_superuser else self.user) | ||
self._create_available_licenses() | ||
user_emails = ['[email protected]', self.test_email, '[email protected]', '[email protected]'] | ||
user_sfids = ['0000qse56709sdfd08', '0000abc34MS67a8907', '', None] | ||
response = self.api_client.post( | ||
self.assign_url, | ||
{'greeting': self.greeting, 'closing': self.closing, 'user_emails': user_emails, 'user_sfids': user_sfids}, | ||
) | ||
assert response.status_code == status.HTTP_200_OK | ||
self._assert_licenses_assigned(user_emails) | ||
|
||
# verify that correct salesforce ids are assigned | ||
emails_and_sfids = dict(zip(user_emails, user_sfids)) | ||
for email, salesforce_id in emails_and_sfids.items(): | ||
assigned_license = self.subscription_plan.licenses.get(user_email=email, status=constants.ASSIGNED) | ||
|
||
if salesforce_id: | ||
assert assigned_license.source.source_id == salesforce_id | ||
else: | ||
with self.assertRaises(ObjectDoesNotExist): | ||
SubscriptionLicenseSource.objects.get(license=assigned_license) | ||
|
||
@ddt.data(True, False) | ||
def test_assign_with_less_salesforce_ids(self, use_superuser): | ||
""" | ||
Verify the assign endpoint raises correct error when user_sfids list has less items then user_emails. | ||
""" | ||
self._setup_request_jwt(user=self.super_user if use_superuser else self.user) | ||
user_emails = ['[email protected]', '[email protected]'] | ||
user_sfids = ['0010abc34MS67a8907'] | ||
response = self.api_client.post( | ||
self.assign_url, | ||
{'greeting': self.greeting, 'closing': self.closing, 'user_emails': user_emails, 'user_sfids': user_sfids}, | ||
) | ||
assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
assert response.json() == { | ||
'non_field_errors': [ | ||
'Number of Salesforce IDs did not match number of provided user emails.' | ||
] | ||
} | ||
assert SubscriptionLicenseSource.objects.count() == 0 | ||
|
||
@ddt.data(True, False) | ||
def test_assign_with_empty_salesforce_ids(self, use_superuser): | ||
""" | ||
Verify the assign endpoint raises correct error when user_sfids is present but empty. | ||
""" | ||
self._setup_request_jwt(user=self.super_user if use_superuser else self.user) | ||
user_emails = ['[email protected]'] | ||
user_sfids = [] | ||
response = self.api_client.post( | ||
self.assign_url, | ||
{'greeting': self.greeting, 'closing': self.closing, 'user_emails': user_emails, 'user_sfids': user_sfids}, | ||
) | ||
assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
assert response.json() == {'user_sfids': ['No Salesforce Ids provided.']} | ||
assert SubscriptionLicenseSource.objects.count() == 0 | ||
|
||
@mock.patch('license_manager.apps.api.v1.views.link_learners_to_enterprise_task.si') | ||
@mock.patch('license_manager.apps.api.v1.views.send_assignment_email_task.si') | ||
@ddt.data(True, False) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,8 @@ | |
from license_manager.apps.subscriptions.models import ( | ||
CustomerAgreement, | ||
License, | ||
SubscriptionLicenseSource, | ||
SubscriptionLicenseSourceType, | ||
SubscriptionPlan, | ||
SubscriptionsRoleAssignment, | ||
) | ||
|
@@ -726,11 +728,36 @@ def _assign_new_licenses(self, subscription_plan, user_emails): | |
) | ||
return licenses | ||
|
||
def _set_source_for_assigned_licenses(self, assigned_licenses, emails_and_sfids): | ||
""" | ||
Set source for each assigned license. | ||
""" | ||
license_source = SubscriptionLicenseSourceType.get_source_type(SubscriptionLicenseSourceType.AMT) | ||
source_objects = [] | ||
for assigned_license in assigned_licenses: | ||
sf_opportunity_id = emails_and_sfids.get(assigned_license.user_email) | ||
if sf_opportunity_id: | ||
source = SubscriptionLicenseSource( | ||
license=assigned_license, | ||
source_id=sf_opportunity_id, | ||
source_type=license_source | ||
) | ||
source_objects.append(source) | ||
|
||
SubscriptionLicenseSource.objects.bulk_create( | ||
source_objects, | ||
batch_size=constants.LICENSE_SOURCE_BULK_OPERATION_BATCH_SIZE | ||
) | ||
|
||
@action(detail=False, methods=['post']) | ||
def assign(self, request, subscription_uuid=None): # pylint: disable=unused-argument | ||
""" | ||
Given a list of emails, assigns a license to those user emails and sends an activation email. | ||
Endpoint will also receive `user_sfids`, an optional list of salesforce ids. If present then | ||
for each assigned license a source object will be created to later identify the source of a | ||
license assignment. | ||
Assignment is intended to be a fully atomic and linearizable operation. We utilize | ||
a cache-based lock to ensure that only one assignment operation can be executed at a | ||
time for the given subscription plan. | ||
|
@@ -743,6 +770,10 @@ def assign(self, request, subscription_uuid=None): # pylint: disable=unused-arg | |
'user_emails': [ | ||
'[email protected]', | ||
'[email protected]' | ||
], | ||
'user_sfids': [ | ||
'001OE000001f26OXZP', | ||
'001OE000001a25WXYZ' | ||
] | ||
} | ||
""" | ||
|
@@ -769,8 +800,19 @@ def _assign(self, request, subscription_plan): | |
# Validate the user_emails and text sent in the data | ||
self._validate_data(request.data) | ||
|
||
# Dedupe all lowercase emails before turning back into a list for indexing | ||
user_emails = list({email.lower() for email in request.data.get('user_emails', [])}) | ||
emails_and_sfids = [] | ||
# remove duplicate emails and convert to lowercase | ||
if 'user_sfids' in request.data: | ||
user_emails = map(str.lower, request.data.get('user_emails')) | ||
user_sfids = request.data.get('user_sfids') | ||
# remove whitespaces if there are any | ||
user_sfids = [sfid and sfid.strip() for sfid in user_sfids] | ||
|
||
emails_and_sfids = dict(zip(user_emails, user_sfids)) | ||
user_emails = list(emails_and_sfids.keys()) | ||
else: | ||
# Dedupe all lowercase emails before turning back into a list for indexing | ||
user_emails = list({email.lower() for email in request.data.get('user_emails', [])}) | ||
|
||
user_emails, already_associated_emails = self._trim_already_associated_emails( | ||
subscription_plan, | ||
|
@@ -795,6 +837,8 @@ def _assign(self, request, subscription_plan): | |
assigned_licenses = self._assign_new_licenses( | ||
subscription_plan, user_emails, | ||
) | ||
if emails_and_sfids: | ||
self._set_source_for_assigned_licenses(assigned_licenses, emails_and_sfids) | ||
except DatabaseError: | ||
error_message = 'Database error occurred while assigning licenses, no assignments were completed' | ||
logger.exception(error_message) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters