From d2e315bd754f36a2d6e4a8629485d2e4f764a797 Mon Sep 17 00:00:00 2001 From: Moeez Zahid Date: Fri, 16 Feb 2024 21:03:52 +0500 Subject: [PATCH] fix: Enable enrollment code purchase with mobile seats (#4130) * fix: Enable enrollment code purchase with mobile seats * test: Add unit test --------- Co-authored-by: Abdul Moeez Zahid --- ecommerce/extensions/fulfillment/modules.py | 2 + .../fulfillment/tests/test_modules.py | 48 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ecommerce/extensions/fulfillment/modules.py b/ecommerce/extensions/fulfillment/modules.py index 33ebe0f0e5f..fb77cbdaf61 100644 --- a/ecommerce/extensions/fulfillment/modules.py +++ b/ecommerce/extensions/fulfillment/modules.py @@ -14,6 +14,7 @@ import requests import waffle from django.conf import settings +from django.db.models import Q from django.urls import reverse from getsmarter_api_clients.geag import GetSmarterEnterpriseApiClient from oscar.core.loading import get_model @@ -553,6 +554,7 @@ def fulfill_product(self, order, lines, email_opt_in=False): attributes__name='course_key', attribute_values__value_text=line.product.attr.course_key ).get( + ~Q(stockrecords__partner_sku__icontains="mobile"), attributes__name='certificate_type', attribute_values__value_text=line.product.attr.seat_type ) diff --git a/ecommerce/extensions/fulfillment/tests/test_modules.py b/ecommerce/extensions/fulfillment/tests/test_modules.py index 60be1a7c036..689845ca07c 100644 --- a/ecommerce/extensions/fulfillment/tests/test_modules.py +++ b/ecommerce/extensions/fulfillment/tests/test_modules.py @@ -672,10 +672,42 @@ def format_hubspot_request_url(self): settings.HUBSPOT_PORTAL_ID, settings.HUBSPOT_SALES_LEAD_FORM_GUID) + def create_mobile_seat_for_course(self, sku_prefix): + """ Create a mobile seat for a course given the sku_prefix """ + web_seat = Product.objects.filter( + parent__isnull=False, + course=self.course, + attributes__name="id_verification_required", + parent__product_class__name="Seat" + ).first() + web_stock_record = web_seat.stockrecords.first() + + mobile_seat = Product.objects.create( + course=self.course, + parent=web_seat.parent, + structure=web_seat.structure, + expires=web_seat.expires, + is_public=web_seat.is_public, + title="{} {}".format(sku_prefix.capitalize(), web_seat.title.lower()) + ) + + mobile_seat.attr.certificate_type = web_seat.attr.certificate_type + mobile_seat.attr.course_key = web_seat.attr.course_key + mobile_seat.attr.id_verification_required = web_seat.attr.id_verification_required + mobile_seat.attr.save() + + StockRecord.objects.create( + partner=web_stock_record.partner, + product=mobile_seat, + partner_sku="mobile.{}.{}".format(sku_prefix.lower(), web_stock_record.partner_sku.lower()), + price_currency=web_stock_record.price_currency, + ) + return mobile_seat + def setUp(self): super(EnrollmentCodeFulfillmentModuleTests, self).setUp() - course = CourseFactory(partner=self.partner) - course.create_or_update_seat('verified', True, 50, create_enrollment_code=True) + self.course = CourseFactory(partner=self.partner) + self.course.create_or_update_seat('verified', True, 50, create_enrollment_code=True) enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) user = UserFactory() basket = factories.BasketFactory(owner=user, site=self.site) @@ -709,6 +741,18 @@ def test_fulfill_product(self): self.assertEqual(OrderLineVouchers.objects.first().vouchers.count(), self.QUANTITY) self.assertIsNotNone(OrderLineVouchers.objects.first().vouchers.first().benefit.range.catalog) + def test_fulfill_product_with_existing_mobile_seats(self): + """Test fulfilling an Enrollment code product with mobile seats for the same course.""" + self.assertEqual(OrderLineVouchers.objects.count(), 0) + lines = self.order.lines.all() + self.create_mobile_seat_for_course('android') + self.create_mobile_seat_for_course('ios') + __, completed_lines = EnrollmentCodeFulfillmentModule().fulfill_product(self.order, lines) + self.assertEqual(completed_lines[0].status, LINE.COMPLETE) + self.assertEqual(OrderLineVouchers.objects.count(), 1) + self.assertEqual(OrderLineVouchers.objects.first().vouchers.count(), self.QUANTITY) + self.assertIsNotNone(OrderLineVouchers.objects.first().vouchers.first().benefit.range.catalog) + def test_revoke_line(self): line = self.order.lines.first() with self.assertRaises(NotImplementedError):