Skip to content

Commit

Permalink
fix: Added test cases and sorted imports
Browse files Browse the repository at this point in the history
  • Loading branch information
jawad-khan committed Dec 17, 2024
1 parent 670e214 commit 892f9fb
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 31 deletions.
22 changes: 12 additions & 10 deletions ecommerce/extensions/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
)
from ecommerce.extensions.catalogue.utils import attach_vouchers_to_coupon_product
from ecommerce.extensions.checkout.views import ReceiptResponseView
from ecommerce.extensions.iap.api.v1.utils import apply_price_of_inapp_purchase, get_auth_headers, create_ios_product
from ecommerce.extensions.iap.constants import CREATE_APPSTORE_PRODUCTS_FOR_INAPP
from ecommerce.extensions.iap.api.v1.utils import apply_price_of_inapp_purchase, create_ios_product, get_auth_headers
from ecommerce.extensions.iap.constants import ANDROID_SKU_PREFIX, IOS_SKU_PREFIX
from ecommerce.extensions.iap.processors.ios_iap import IOSIAP
from ecommerce.extensions.iap.utils import create_mobile_seat
Expand Down Expand Up @@ -839,16 +840,18 @@ def _update_or_create_mobile_seats(self, course):
if mobile_seats:
self._update_mobile_seats(mobile_seats, web_seat, course)
else:
logger.info("Creating mobile seats for course [%s]", course.id)
create_mobile_seat(ANDROID_SKU_PREFIX, web_seat)
ios_seat = create_mobile_seat(IOS_SKU_PREFIX, web_seat)
partner_short_code = self.context['request'].site.siteconfiguration.partner.short_code
configuration = settings.PAYMENT_PROCESSOR_CONFIG[partner_short_code.lower()][IOSIAP.NAME.lower()]
course_data = {
'price': ios_seat.stockrecords.first().price_excl_tax,
'name': course.name,
'key': course.id
}
create_ios_product(course_data, ios_seat, configuration)
if waffle.switch_is_active(CREATE_APPSTORE_PRODUCTS_FOR_INAPP):
partner_short_code = self.context['request'].site.siteconfiguration.partner.short_code
configuration = settings.PAYMENT_PROCESSOR_CONFIG[partner_short_code.lower()][IOSIAP.NAME.lower()]
course_data = {
'price': ios_seat.price_excl_tax,
'name': course.name,
'key': course.id
}
create_ios_product(course_data, ios_seat, configuration)

def _update_mobile_seats(self, mobile_seats, web_seat, course):
failure_msg = False
Expand Down Expand Up @@ -942,7 +945,6 @@ def save(self): # pylint: disable=arguments-differ

resp_message = course.publish_to_lms()
published = (resp_message is None)

if published:
self._update_or_create_mobile_seats(course)

Expand Down
36 changes: 27 additions & 9 deletions ecommerce/extensions/api/v2/tests/views/test_publication.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from ecommerce.entitlements.utils import create_or_update_course_entitlement
from ecommerce.extensions.api.v2.tests.views import JSON_CONTENT_TYPE
from ecommerce.extensions.catalogue.tests.mixins import DiscoveryTestMixin
from ecommerce.extensions.iap.constants import CREATE_APPSTORE_PRODUCTS_FOR_INAPP
from ecommerce.extensions.iap.utils import create_child_products_for_mobile
from ecommerce.tests.testcases import TestCase

Expand Down Expand Up @@ -158,6 +159,7 @@ def setUp(self):
self.client.login(username=self.user.username, password=self.password)

self.publication_switch = toggle_switch('publish_course_modes_to_lms', True)
self.appstore_product_switch = toggle_switch(CREATE_APPSTORE_PRODUCTS_FOR_INAPP, False)

def _toggle_publication(self, is_enabled):
"""Toggle LMS publication."""
Expand Down Expand Up @@ -233,7 +235,7 @@ def assert_entitlement_saved(self, course, expected):
self.assertEqual(entitlement.attr.UUID, self.course_uuid)
self.assertEqual(entitlement.stockrecords.get(partner=self.partner).price_excl_tax, expected['price'])

def assert_seat_saved(self, course, expected, test_mobile_seats=False):
def assert_seat_saved(self, course, expected, test_mobile_seats=True):
certificate_type = ''
verified_product = False

Expand All @@ -258,17 +260,17 @@ def assert_seat_saved(self, course, expected, test_mobile_seats=False):
self.assertEqual(seat.stockrecords.get(partner=self.partner).price_excl_tax, expected['price'])

if test_mobile_seats and verified_product:
android_seat = course.seat_products.get(title='Android ' + seat_title)
android_seat = course.seat_products.get(title='Android ' + seat_title.lower())
self.assertEqual(android_seat.expires, expires)
self.assertEqual(android_seat.stockrecords.get(partner=self.partner).price_excl_tax, expected['price'])

ios_seat = course.seat_products.get(title='Ios ' + seat_title)
ios_seat = course.seat_products.get(title='Ios ' + seat_title.lower())
self.assertEqual(ios_seat.expires, expires)
self.assertEqual(ios_seat.stockrecords.get(partner=self.partner).price_excl_tax, expected['price'])

return seat

def assert_course_saved(self, course_id, expected, enrollment_code_count=0, test_mobile_seats=False):
def assert_course_saved(self, course_id, expected, enrollment_code_count=0, test_mobile_seats=True):
"""Verify that the expected Course and associated products have been saved."""
# Verify that Course was saved.
self.assertTrue(Course.objects.filter(id=course_id).exists())
Expand Down Expand Up @@ -343,7 +345,7 @@ def test_update(self):
response = self.client.put(self.update_path, json.dumps(updated_data), JSON_CONTENT_TYPE)
self.assertEqual(response.status_code, 500)
self.assertEqual(response.data.get('error'), error_msg)
self.assert_course_saved(self.course_id, expected=self.data)
self.assert_course_saved(self.course_id, expected=self.data, test_mobile_seats=False)

# If publication succeeds, the view should return a 200 and data should be saved.
mock_publish.return_value = None
Expand Down Expand Up @@ -512,8 +514,8 @@ def test_mobile_seats_update(self, _, __):

# Since we are only concerned with expiry date and price
# therefore we are setting title manually here.
android_seat.product.title = 'Android Seat in A New Name with verified certificate'
ios_seat.product.title = 'Ios Seat in A New Name with verified certificate'
android_seat.product.title = 'Android seat in a new name with verified certificate'
ios_seat.product.title = 'Ios seat in a new name with verified certificate'
android_seat.product.save()
ios_seat.product.save()
with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
Expand All @@ -523,5 +525,21 @@ def test_mobile_seats_update(self, _, __):
response = self.client.put(self.update_path, json.dumps(updated_data), JSON_CONTENT_TYPE)

self.assertEqual(response.status_code, 200)
self.assert_course_saved(self.course_id, expected=updated_data,
enrollment_code_count=1, test_mobile_seats=True)
self.assert_course_saved(self.course_id, expected=updated_data, enrollment_code_count=1)

@mock.patch('ecommerce.extensions.api.serializers.create_ios_product')
def test_ios_seat_created(self, mock_create_ios_product):
"""Verify that a Course and associated mobile products can be updated and published."""
self.create_course_and_seats()
updated_data = self.generate_update_payload()

with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
# If publication succeeds, the view should return a 200 and data should be saved.
mock_publish.return_value = None
self.appstore_product_switch.active = True
self.appstore_product_switch.save()

response = self.client.put(self.update_path, json.dumps(updated_data), JSON_CONTENT_TYPE)
mock_create_ios_product.assert_called_once()
self.assertEqual(response.status_code, 200)
self.assert_course_saved(self.course_id, expected=updated_data, enrollment_code_count=1)
27 changes: 15 additions & 12 deletions ecommerce/extensions/iap/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import app_store_notifications_v2_validator as asn2
import httplib2
import waffle
from django.conf import settings
from django.db import transaction
from django.utils.decorators import method_decorator
Expand Down Expand Up @@ -84,6 +85,7 @@
from ecommerce.extensions.iap.api.v1.exceptions import RefundCompletionException
from ecommerce.extensions.iap.api.v1.serializers import MobileOrderSerializer
from ecommerce.extensions.iap.api.v1.utils import create_ios_product, products_in_basket_already_purchased
from ecommerce.extensions.iap.constants import CREATE_APPSTORE_PRODUCTS_FOR_INAPP
from ecommerce.extensions.iap.models import IAPProcessorConfiguration
from ecommerce.extensions.iap.processors.android_iap import AndroidIAP
from ecommerce.extensions.iap.processors.ios_iap import IOSIAP
Expand Down Expand Up @@ -487,18 +489,19 @@ def post(self, request):
course.publish_to_lms()
created_skus[course_run_key] = [mobile_products[0].partner_sku, mobile_products[1].partner_sku]

# create ios product on appstore
partner_short_code = request.site.siteconfiguration.partner.short_code
configuration = settings.PAYMENT_PROCESSOR_CONFIG[partner_short_code.lower()][IOSIAP.NAME.lower()]
ios_product = list((filter(lambda sku: 'ios' in sku.partner_sku, mobile_products)))[0]
course_data = {
'price': ios_product.price_excl_tax,
'name': course.name,
'key': course_run_key
}
error_msg = create_ios_product(course_data, ios_product, configuration)
if error_msg:
failed_ios_products.append(error_msg)
if waffle.switch_is_active(CREATE_APPSTORE_PRODUCTS_FOR_INAPP):
# create ios product on appstore
partner_short_code = request.site.siteconfiguration.partner.short_code
configuration = settings.PAYMENT_PROCESSOR_CONFIG[partner_short_code.lower()][IOSIAP.NAME.lower()]
ios_product = list((filter(lambda sku: 'ios' in sku.partner_sku, mobile_products)))[0]
course_data = {
'price': ios_product.price_excl_tax,
'name': course.name,
'key': course_run_key
}
error_msg = create_ios_product(course_data, ios_product, configuration)
if error_msg:
failed_ios_products.append(error_msg)

result = {
'new_mobile_skus': created_skus,
Expand Down
10 changes: 10 additions & 0 deletions ecommerce/extensions/iap/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
ANDROID_SKU_PREFIX = 'android'
IOS_SKU_PREFIX = 'ios'
MISSING_WEB_SEAT_ERROR = "Couldn't find existing web seat for course [%s]"

# .. toggle_name: create_appstore_products_for_inapp
# .. toggle_type: waffle_switch
# .. toggle_default: False
# .. toggle_description: Create ios products on appstore using Apple in-app apis.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2023-07-25
# .. toggle_tickets: LEARNER-9951
# .. toggle_status: supported
CREATE_APPSTORE_PRODUCTS_FOR_INAPP = 'create_appstore_products_for_inapp'

0 comments on commit 892f9fb

Please sign in to comment.