Commit 8f5ba011 by asadiqbal Committed by Ayesha Baig

WL-606

parent c7ff473e
...@@ -272,6 +272,7 @@ def create_mode(request, course_id): ...@@ -272,6 +272,7 @@ def create_mode(request, course_id):
`min_price` (int): The minimum price a user must pay to enroll in the new course mode `min_price` (int): The minimum price a user must pay to enroll in the new course mode
`suggested_prices` (str): Comma-separated prices to suggest to the user. `suggested_prices` (str): Comma-separated prices to suggest to the user.
`currency` (str): The currency in which to list prices. `currency` (str): The currency in which to list prices.
`sku` (str): The product SKU value.
By default, this endpoint will create an 'honor' mode for the given course with display name By default, this endpoint will create an 'honor' mode for the given course with display name
'Honor Code', a minimum price of 0, no suggested prices, and using USD as the currency. 'Honor Code', a minimum price of 0, no suggested prices, and using USD as the currency.
...@@ -289,6 +290,7 @@ def create_mode(request, course_id): ...@@ -289,6 +290,7 @@ def create_mode(request, course_id):
'min_price': 0, 'min_price': 0,
'suggested_prices': u'', 'suggested_prices': u'',
'currency': u'usd', 'currency': u'usd',
'sku': None,
} }
# Try pulling querystring parameters out of the request # Try pulling querystring parameters out of the request
......
...@@ -14,7 +14,8 @@ class ModeCreationPage(PageObject): ...@@ -14,7 +14,8 @@ class ModeCreationPage(PageObject):
created for an existing course. created for an existing course.
""" """
def __init__(self, browser, course_id, mode_slug=None, mode_display_name=None, min_price=None, suggested_prices=None, currency=None): def __init__(self, browser, course_id, mode_slug=None, mode_display_name=None, min_price=None,
suggested_prices=None, currency=None, sku=None):
"""The mode creation page is an endpoint for HTTP GET requests. """The mode creation page is an endpoint for HTTP GET requests.
By default, it will create an 'honor' mode for the given course with display name By default, it will create an 'honor' mode for the given course with display name
...@@ -30,6 +31,7 @@ class ModeCreationPage(PageObject): ...@@ -30,6 +31,7 @@ class ModeCreationPage(PageObject):
min_price (int): The minimum price a user must pay to enroll in the new course mode min_price (int): The minimum price a user must pay to enroll in the new course mode
suggested_prices (str): Comma-separated prices to suggest to the user. suggested_prices (str): Comma-separated prices to suggest to the user.
currency (str): The currency in which to list prices. currency (str): The currency in which to list prices.
sku (str): The product SKU value.
""" """
super(ModeCreationPage, self).__init__(browser) super(ModeCreationPage, self).__init__(browser)
...@@ -51,6 +53,9 @@ class ModeCreationPage(PageObject): ...@@ -51,6 +53,9 @@ class ModeCreationPage(PageObject):
if currency is not None: if currency is not None:
self._parameters['currency'] = currency self._parameters['currency'] = currency
if sku is not None:
self._parameters['sku'] = sku
@property @property
def url(self): def url(self):
"""Construct the mode creation URL.""" """Construct the mode creation URL."""
......
...@@ -92,6 +92,15 @@ class InstructorDashboardPage(CoursePage): ...@@ -92,6 +92,15 @@ class InstructorDashboardPage(CoursePage):
email_section.wait_for_page() email_section.wait_for_page()
return email_section return email_section
def select_ecommerce_tab(self):
"""
Selects the E-commerce tab and returns an EcommercePage.
"""
self.q(css='[data-section="e-commerce"]').first.click()
ecommerce_section = EcommercePage(self.browser)
ecommerce_section.wait_for_page()
return ecommerce_section
@staticmethod @staticmethod
def get_asset_path(file_name): def get_asset_path(file_name):
""" """
...@@ -1416,3 +1425,19 @@ class CertificatesPage(PageObject): ...@@ -1416,3 +1425,19 @@ class CertificatesPage(PageObject):
Returns the message (error/success) in "Certificate Invalidation" section. Returns the message (error/success) in "Certificate Invalidation" section.
""" """
return self.get_selector('.certificate-invalidation-container div.message') return self.get_selector('.certificate-invalidation-container div.message')
class EcommercePage(PageObject):
"""
E-commerce section of the Instructor dashboard.
"""
url = None
def is_browser_on_page(self):
return self.q(css='[data-section="e-commerce"].active-section').present
def get_sections_header_values(self):
"""
Returns a list of the headings text under div.
"""
return self.q(css="div.wrap h3").text
...@@ -1202,3 +1202,112 @@ class CertificateInvalidationTest(BaseInstructorDashboardTest): ...@@ -1202,3 +1202,112 @@ class CertificateInvalidationTest(BaseInstructorDashboardTest):
'.certificates-wrapper' '.certificates-wrapper'
]) ])
self.certificates_section.a11y_audit.check_for_accessibility_errors() self.certificates_section.a11y_audit.check_for_accessibility_errors()
@attr(shard=10)
class EcommerceTest(BaseInstructorDashboardTest):
"""
Bok Choy tests for the "E-Commerce" tab.
"""
def setUp(self):
super(EcommerceTest, self).setUp()
def setup_course(self, course_number):
"""
Sets up the course
"""
self.course_info['number'] = course_number
course_fixture = CourseFixture(
self.course_info["org"],
self.course_info["number"],
self.course_info["run"],
self.course_info["display_name"]
)
course_fixture.install()
def log_in_as_unique_user(self):
"""
Log in as a valid lms user.
"""
AutoAuthPage(
self.browser,
username="test_instructor",
email="test_instructor@example.com",
password="password",
course_id=self.course_id
).visit()
def visit_ecommerce_section(self):
"""
Log in to visit Instructor dashboard and click E-commerce tab
"""
self.log_in_as_unique_user()
instructor_dashboard_page = self.visit_instructor_dashboard()
return instructor_dashboard_page.select_ecommerce_tab()
def add_course_mode(self, sku_value=None):
"""
Add an honor mode to the course
"""
ModeCreationPage(browser=self.browser, course_id=self.course_id, mode_slug=u'honor', min_price=10,
sku=sku_value).visit()
def test_enrollment_codes_section_visible_for_non_ecommerce_course(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should be visible in the Instructor Dashboard with non
e-commerce course
"""
# Setup course
non_ecommerce_course_number = "34039497242734583224814321005482849780"
self.setup_course(non_ecommerce_course_number)
# Add an honor mode to the course
self.add_course_mode()
# Log in and visit E-commerce section under Instructor dashboard
self.assertIn(u'Enrollment Codes', self.visit_ecommerce_section().get_sections_header_values())
def test_coupon_codes_section_visible_for_non_ecommerce_course(self):
"""
Test Coupon Codes UI, under E-commerce Tab, should be visible in the Instructor Dashboard with non
e-commerce course
"""
# Setup course
non_ecommerce_course_number = "34039497242734583224814321005482849781"
self.setup_course(non_ecommerce_course_number)
# Add an honor mode to the course
self.add_course_mode()
# Log in and visit E-commerce section under Instructor dashboard
self.assertIn(u'Coupon Code List', self.visit_ecommerce_section().get_sections_header_values())
def test_enrollment_codes_section_not_visible_for_ecommerce_course(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should not be visible in the Instructor Dashboard with
e-commerce course
"""
# Setup course
ecommerce_course_number = "34039497242734583224814321005482849782"
self.setup_course(ecommerce_course_number)
# Add an honor mode to the course with sku value
self.add_course_mode('test_sku')
# Log in and visit E-commerce section under Instructor dashboard
self.assertNotIn(u'Enrollment Codes', self.visit_ecommerce_section().get_sections_header_values())
def test_coupon_codes_section_not_visible_for_ecommerce_course(self):
"""
Test Coupon Codes UI, under E-commerce Tab, should not be visible in the Instructor Dashboard with
e-commerce course
"""
# Setup course
ecommerce_course_number = "34039497242734583224814321005482849783"
self.setup_course(ecommerce_course_number)
# Add an honor mode to the course with sku value
self.add_course_mode('test_sku')
# Log in and visit E-commerce section under Instructor dashboard
self.assertNotIn(u'Coupon Code List', self.visit_ecommerce_section().get_sections_header_values())
[
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "test_instructor",
"email":"test_instructor@example.com",
"password": "password",
"is_staff": true,
"is_active": true
}
},
{
"pk": 1,
"model": "student.userprofile",
"fields": {
"user": 1,
"name": "test instructor",
"courseware": "course.xml"
}
},
{
"pk": 1,
"model": "student.registration",
"fields": {
"user": 1,
"activation_key": "52bfac10384d49219385dcd4cc17177q"
}
},
{
"pk": 1,
"model": "student.courseaccessrole",
"fields": {
"id": "1",
"org": "test_org",
"course_id": "course-v1:test_org+34039497242734583224814321005482849780+test_run",
"role": "finance_admin",
"user_id": "1"
}
},
{
"pk": 2,
"model": "student.courseaccessrole",
"fields": {
"id": "2",
"org": "test_org",
"course_id": "course-v1:test_org+34039497242734583224814321005482849781+test_run",
"role": "finance_admin",
"user_id": "1"
}
},
{
"pk": 3,
"model": "student.courseaccessrole",
"fields": {
"id": "3",
"org": "test_org",
"course_id": "course-v1:test_org+34039497242734583224814321005482849782+test_run",
"role": "finance_admin",
"user_id": "1"
}
},
{
"pk": 4,
"model": "student.courseaccessrole",
"fields": {
"id": "4",
"org": "test_org",
"course_id": "course-v1:test_org+34039497242734583224814321005482849783+test_run",
"role": "finance_admin",
"user_id": "1"
}
}
]
...@@ -30,7 +30,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -30,7 +30,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
# URL for instructor dash # URL for instructor dash
cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course.id.to_deprecated_string()}) cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course.id.to_deprecated_string()})
cls.e_commerce_link = '<button type="button" class="btn-link" data-section="e-commerce">E-Commerce</button>' cls.ecommerce_link = '<button type="button" class="btn-link" data-section="e-commerce">E-Commerce</button>'
def setUp(self): def setUp(self):
super(TestECommerceDashboardViews, self).setUp() super(TestECommerceDashboardViews, self).setUp()
...@@ -50,7 +50,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -50,7 +50,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
Test Pass E-commerce Tab is in the Instructor Dashboard Test Pass E-commerce Tab is in the Instructor Dashboard
""" """
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
# Coupons should show up for White Label sites with priced honor modes. # Coupons should show up for White Label sites with priced honor modes.
self.assertIn('Coupon Code List', response.content) self.assertIn('Coupon Code List', response.content)
...@@ -61,7 +61,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -61,7 +61,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
self.use_site(site=self.site_other) self.use_site(site=self.site_other)
self.client.login(username=self.instructor.username, password="test") self.client.login(username=self.instructor.username, password="test")
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
self.assertIn('Create Enrollment Report', response.content) self.assertIn('Create Enrollment Report', response.content)
def test_reports_section_not_under_e_commerce_tab(self): def test_reports_section_not_under_e_commerce_tab(self):
...@@ -70,12 +70,12 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -70,12 +70,12 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
value value
""" """
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
self.assertNotIn('Create Enrollment Report', response.content) self.assertNotIn('Create Enrollment Report', response.content)
def test_user_has_finance_admin_rights_in_e_commerce_tab(self): def test_user_has_finance_admin_rights_in_e_commerce_tab(self):
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
# Order/Invoice sales csv button text should render in e-commerce page # Order/Invoice sales csv button text should render in e-commerce page
self.assertIn('Total Credit Card Purchases', response.content) self.assertIn('Total Credit Card Purchases', response.content)
...@@ -96,7 +96,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -96,7 +96,7 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
the instructor dashboard the instructor dashboard
""" """
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
# Total amount html should render in e-commerce page, total amount will be 0 # Total amount html should render in e-commerce page, total amount will be 0
course_honor_mode = CourseMode.mode_for_course(self.course.id, 'honor') course_honor_mode = CourseMode.mode_for_course(self.course.id, 'honor')
...@@ -351,6 +351,39 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase): ...@@ -351,6 +351,39 @@ class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
# Get the response value, ensure the Coupon section is not included. # Get the response value, ensure the Coupon section is not included.
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertIn(self.e_commerce_link, response.content) self.assertIn(self.ecommerce_link, response.content)
# Coupons should show up for White Label sites with priced honor modes. # Coupons should show up for White Label sites with priced honor modes.
self.assertNotIn('Coupons List', response.content) self.assertNotIn('Coupons List', response.content)
def test_coupon_code_section_not_under_e_commerce_tab(self):
"""
Test Coupon Creation UI, under E-commerce Tab, should not be available in the Instructor Dashboard with
e-commerce course
"""
# Setup e-commerce course
CourseMode.objects.filter(course_id=self.course.id).update(sku='test_sku')
response = self.client.get(self.url)
self.assertIn(self.ecommerce_link, response.content)
self.assertNotIn('Coupon Code List', response.content)
def test_enrollment_codes_section_not_under_e_commerce_tab(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should not be available in the Instructor Dashboard with
e-commerce course
"""
# Setup e-commerce course
CourseMode.objects.filter(course_id=self.course.id).update(sku='test_sku')
response = self.client.get(self.url)
self.assertIn(self.ecommerce_link, response.content)
self.assertNotIn('<h3 class="hd hd-3">Enrollment Codes</h3>', response.content)
def test_enrollment_codes_section_visible_for_non_ecommerce_course(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should be available in the Instructor Dashboard with non
e-commerce course
"""
response = self.client.get(self.url)
self.assertIn(self.ecommerce_link, response.content)
self.assertIn('<h3 class="hd hd-3">Enrollment Codes</h3>', response.content)
...@@ -285,7 +285,8 @@ def _section_e_commerce(course, access, paid_mode, coupons_enabled, reports_enab ...@@ -285,7 +285,8 @@ def _section_e_commerce(course, access, paid_mode, coupons_enabled, reports_enab
'coupons_enabled': coupons_enabled, 'coupons_enabled': coupons_enabled,
'reports_enabled': reports_enabled, 'reports_enabled': reports_enabled,
'course_price': course_price, 'course_price': course_price,
'total_amount': total_amount 'total_amount': total_amount,
'is_ecommerce_course': is_ecommerce_course(course_key)
} }
return section_data return section_data
...@@ -695,3 +696,12 @@ def _section_metrics(course, access): ...@@ -695,3 +696,12 @@ def _section_metrics(course, access):
'post_metrics_data_csv_url': reverse('post_metrics_data_csv'), 'post_metrics_data_csv_url': reverse('post_metrics_data_csv'),
} }
return section_data return section_data
def is_ecommerce_course(course_key):
"""
Checks if the given course is an e-commerce course or not, by checking its SKU value from
CourseMode records for the course
"""
sku_count = len([mode.sku for mode in CourseMode.modes_for_course(course_key) if mode.sku])
return sku_count > 0
...@@ -14,7 +14,8 @@ import pytz ...@@ -14,7 +14,8 @@ import pytz
<div class="ecommerce-wrapper"> <div class="ecommerce-wrapper">
<div class="error-msgs" id="error-msg"></div> <div class="error-msgs" id="error-msg"></div>
<div id = "accordion"> <div id = "accordion">
<div class="wrap"> %if not section_data['is_ecommerce_course']:
<div class="wrap">
<h3 class="hd hd-3">${_('Enrollment Codes')}</h3> <h3 class="hd hd-3">${_('Enrollment Codes')}</h3>
<div> <div>
%if section_data['sales_admin']: %if section_data['sales_admin']:
...@@ -53,6 +54,7 @@ import pytz ...@@ -53,6 +54,7 @@ import pytz
<a id="registration_code_generation_link-trigger" href="#registration_code_generation_modal" rel="leanModal"></a> <a id="registration_code_generation_link-trigger" href="#registration_code_generation_modal" rel="leanModal"></a>
</div> </div>
</div> </div>
%endif
<!-- end wrap --> <!-- end wrap -->
%if section_data['coupons_enabled']: %if section_data['coupons_enabled']:
<div class="wrap"> <div class="wrap">
...@@ -145,7 +147,7 @@ import pytz ...@@ -145,7 +147,7 @@ import pytz
</div> </div>
</div><!-- end wrap --> </div><!-- end wrap -->
%endif %endif
%if section_data['coupons_enabled']: %if section_data['coupons_enabled'] and not section_data['is_ecommerce_course']:
<div class="wrap"> <div class="wrap">
<h3 class="hd hd-3">${_("Coupon Code List")}</h3> <h3 class="hd hd-3">${_("Coupon Code List")}</h3>
<div> <div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment