Files
edx-platform/lms/djangoapps/instructor_analytics/tests/test_basic.py

658 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# coding=utf-8
"""
Tests for instructor.basic
"""
from __future__ import absolute_import
import ddt
import datetime
import json
import pytz
from django.db.models import Q
from django.urls import reverse
from edx_proctoring.api import create_exam
from edx_proctoring.models import ProctoredExamStudentAttempt
from mock import MagicMock, Mock, patch
from opaque_keys.edx.locator import UsageKey
from six import text_type
from six.moves import range, zip
from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory
from lms.djangoapps.courseware.tests.factories import InstructorFactory
from lms.djangoapps.instructor_analytics.basic import (
AVAILABLE_FEATURES,
PROFILE_FEATURES,
STUDENT_FEATURES,
StudentModule,
coupon_codes_features,
course_registration_features,
enrolled_students_features,
get_proctored_exam_results,
get_response_state,
list_may_enroll,
list_problem_responses,
sale_order_record_features,
sale_record_features
)
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from shoppingcart.models import (
Coupon,
CouponRedemption,
CourseRegCodeItem,
CourseRegistrationCode,
CourseRegistrationCodeInvoiceItem,
Invoice,
Order,
RegistrationCodeRedemption
)
from student.models import CourseEnrollment, CourseEnrollmentAllowed
from student.roles import CourseSalesAdminRole
from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@ddt.ddt
class TestAnalyticsBasic(ModuleStoreTestCase):
""" Test basic analytics functions. """
def setUp(self):
super(TestAnalyticsBasic, self).setUp()
self.course_key = self.store.make_course_key('robot', 'course', 'id')
self.users = tuple(UserFactory() for _ in range(30))
self.ces = tuple(CourseEnrollment.enroll(user, self.course_key)
for user in self.users)
self.instructor = InstructorFactory(course_key=self.course_key)
for user in self.users:
user.profile.meta = json.dumps({
"position": u"edX expert {}".format(user.id),
"company": u"Open edX Inc {}".format(user.id),
})
user.profile.save()
self.students_who_may_enroll = list(self.users) + [UserFactory() for _ in range(5)]
for student in self.students_who_may_enroll:
CourseEnrollmentAllowed.objects.create(
email=student.email, course_id=self.course_key
)
@ddt.data(
(u'あなた', u'スの中'),
(u"ГЂіи lіиэ ъэтшээи", u"Ђэаvэи аиↁ Ђэѓэ")
)
@ddt.unpack
def test_get_response_state_with_ora(self, files_descriptions, saved_response):
"""
Tests that ORA response state is transformed expectedly when the problem
state contains unicode characters.
"""
payload_state = json.dumps({
'saved_response': json.dumps({'parts': [{'text': saved_response}]}),
'saved_files_descriptions': json.dumps([files_descriptions]),
})
response = Mock(module_type='openassessment', student=Mock(username='staff'), state=payload_state)
transformed_state = json.loads(get_response_state(response))
self.assertEqual(transformed_state['saved_files_descriptions'][0], files_descriptions)
self.assertEqual(transformed_state['saved_response']['parts'][0]['text'], saved_response)
def test_list_problem_responses(self):
def result_factory(result_id):
"""
Return a dummy StudentModule object that can be queried for
relevant info (student.username and state).
"""
result = Mock(spec=['student', 'state'])
result.student.username.return_value = u'user{}'.format(result_id)
result.state.return_value = u'state{}'.format(result_id)
return result
# Ensure that UsageKey.from_string returns a problem key that list_problem_responses can work with
# (even when called with a dummy location):
mock_problem_key = Mock(return_value=u'')
mock_problem_key.course_key = self.course_key
with patch.object(UsageKey, 'from_string') as patched_from_string:
patched_from_string.return_value = mock_problem_key
# Ensure that StudentModule.objects.filter returns a result set that list_problem_responses can work with
# (this keeps us from having to create fixtures for this test):
mock_results = MagicMock(return_value=[result_factory(n) for n in range(5)])
with patch.object(StudentModule, 'objects') as patched_manager:
patched_manager.filter.return_value = mock_results
mock_problem_location = ''
problem_responses = list_problem_responses(self.course_key, problem_location=mock_problem_location)
# Check if list_problem_responses called UsageKey.from_string to look up problem key:
patched_from_string.assert_called_once_with(mock_problem_location)
# Check if list_problem_responses called StudentModule.objects.filter to obtain relevant records:
patched_manager.filter.assert_called_once_with(
course_id=self.course_key, module_state_key=mock_problem_key
)
# Check if list_problem_responses returned expected results:
self.assertEqual(len(problem_responses), len(mock_results))
for mock_result in mock_results:
self.assertIn(
{'username': mock_result.student.username, 'state': mock_result.state},
problem_responses
)
def test_enrolled_students_features_username(self):
self.assertIn('username', AVAILABLE_FEATURES)
userreports = enrolled_students_features(self.course_key, ['username'])
self.assertEqual(len(userreports), len(self.users))
for userreport in userreports:
self.assertEqual(list(userreport.keys()), ['username'])
self.assertIn(userreport['username'], [user.username for user in self.users])
def test_enrolled_students_features_keys(self):
query_features = ('username', 'name', 'email', 'city', 'country',)
for user in self.users:
user.profile.city = u"Mos Eisley {}".format(user.id)
user.profile.country = u"Tatooine {}".format(user.id)
user.profile.save()
for feature in query_features:
self.assertIn(feature, AVAILABLE_FEATURES)
with self.assertNumQueries(1):
userreports = enrolled_students_features(self.course_key, query_features)
self.assertEqual(len(userreports), len(self.users))
userreports = sorted(userreports, key=lambda u: u["username"])
users = sorted(self.users, key=lambda u: u.username)
for userreport, user in zip(userreports, users):
self.assertEqual(set(userreport.keys()), set(query_features))
self.assertEqual(userreport['username'], user.username)
self.assertEqual(userreport['email'], user.email)
self.assertEqual(userreport['name'], user.profile.name)
self.assertEqual(userreport['city'], user.profile.city)
self.assertEqual(userreport['country'], user.profile.country)
def test_enrolled_student_with_no_country_city(self):
userreports = enrolled_students_features(self.course_key, ('username', 'city', 'country',))
for userreport in userreports:
# This behaviour is somewhat inconsistent: None string fields
# objects are converted to "None", but non-JSON serializable fields
# are converted to an empty string.
self.assertEqual(userreport['city'], "None")
self.assertEqual(userreport['country'], "")
def test_enrolled_students_meta_features_keys(self):
"""
Assert that we can query individual fields in the 'meta' field in the UserProfile
"""
query_features = ('meta.position', 'meta.company')
with self.assertNumQueries(1):
userreports = enrolled_students_features(self.course_key, query_features)
self.assertEqual(len(userreports), len(self.users))
for userreport in userreports:
self.assertEqual(set(userreport.keys()), set(query_features))
self.assertIn(userreport['meta.position'], [u"edX expert {}".format(user.id) for user in self.users])
self.assertIn(userreport['meta.company'], [u"Open edX Inc {}".format(user.id) for user in self.users])
def test_enrolled_students_enrollment_verification(self):
"""
Assert that we can get enrollment mode and verification status
"""
query_features = ('enrollment_mode', 'verification_status')
userreports = enrolled_students_features(self.course_key, query_features)
self.assertEqual(len(userreports), len(self.users))
# by default all users should have "audit" as their enrollment mode
# and "N/A" as their verification status
for userreport in userreports:
self.assertEqual(set(userreport.keys()), set(query_features))
self.assertIn(userreport['enrollment_mode'], ["audit"])
self.assertIn(userreport['verification_status'], ["N/A"])
# make sure that the user report respects whatever value
# is returned by verification and enrollment code
with patch("student.models.CourseEnrollment.enrollment_mode_for_user") as enrollment_patch:
with patch(
"lms.djangoapps.verify_student.services.IDVerificationService.verification_status_for_user"
) as verify_patch:
enrollment_patch.return_value = ["verified"]
verify_patch.return_value = "dummy verification status"
userreports = enrolled_students_features(self.course_key, query_features)
self.assertEqual(len(userreports), len(self.users))
for userreport in userreports:
self.assertEqual(set(userreport.keys()), set(query_features))
self.assertIn(userreport['enrollment_mode'], ["verified"])
self.assertIn(userreport['verification_status'], ["dummy verification status"])
def test_enrolled_students_features_keys_cohorted(self):
course = CourseFactory.create(org="test", course="course1", display_name="run1")
course.cohort_config = {'cohorted': True, 'auto_cohort': True, 'auto_cohort_groups': ['cohort']}
self.store.update_item(course, self.instructor.id)
cohorted_students = [UserFactory.create() for _ in range(10)]
cohort = CohortFactory.create(name='cohort', course_id=course.id, users=cohorted_students)
cohorted_usernames = [student.username for student in cohorted_students]
non_cohorted_student = UserFactory.create()
for student in cohorted_students:
cohort.users.add(student)
CourseEnrollment.enroll(student, course.id)
CourseEnrollment.enroll(non_cohorted_student, course.id)
instructor = InstructorFactory(course_key=course.id)
self.client.login(username=instructor.username, password='test')
query_features = ('username', 'cohort')
# There should be a constant of 2 SQL queries when calling
# enrolled_students_features. The first query comes from the call to
# User.objects.filter(...), and the second comes from
# prefetch_related('course_groups').
with self.assertNumQueries(2):
userreports = enrolled_students_features(course.id, query_features)
self.assertEqual(len([r for r in userreports if r['username'] in cohorted_usernames]), len(cohorted_students))
self.assertEqual(len([r for r in userreports if r['username'] == non_cohorted_student.username]), 1)
for report in userreports:
self.assertEqual(set(report.keys()), set(query_features))
if report['username'] in cohorted_usernames:
self.assertEqual(report['cohort'], cohort.name)
else:
self.assertEqual(report['cohort'], '[unassigned]')
def test_available_features(self):
self.assertEqual(len(AVAILABLE_FEATURES), len(STUDENT_FEATURES + PROFILE_FEATURES))
self.assertEqual(set(AVAILABLE_FEATURES), set(STUDENT_FEATURES + PROFILE_FEATURES))
def test_list_may_enroll(self):
may_enroll = list_may_enroll(self.course_key, ['email'])
self.assertEqual(len(may_enroll), len(self.students_who_may_enroll) - len(self.users))
email_adresses = [student.email for student in self.students_who_may_enroll]
for student in may_enroll:
self.assertEqual(list(student.keys()), ['email'])
self.assertIn(student['email'], email_adresses)
def test_get_student_exam_attempt_features(self):
query_features = [
'email',
'exam_name',
'allowed_time_limit_mins',
'is_sample_attempt',
'started_at',
'completed_at',
'status',
'Suspicious Count',
'Suspicious Comments',
'Rules Violation Count',
'Rules Violation Comments',
'track'
]
proctored_exam_id = create_exam(self.course_key, 'Test Content', 'Test Exam', 1)
ProctoredExamStudentAttempt.create_exam_attempt(
proctored_exam_id, self.users[0].id, '',
'Test Code 1', True, False, 'ad13'
)
ProctoredExamStudentAttempt.create_exam_attempt(
proctored_exam_id, self.users[1].id, '',
'Test Code 2', True, False, 'ad13'
)
ProctoredExamStudentAttempt.create_exam_attempt(
proctored_exam_id, self.users[2].id, '',
'Test Code 3', True, False, 'asd'
)
proctored_exam_attempts = get_proctored_exam_results(self.course_key, query_features)
self.assertEqual(len(proctored_exam_attempts), 3)
for proctored_exam_attempt in proctored_exam_attempts:
self.assertEqual(set(proctored_exam_attempt.keys()), set(query_features))
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
class TestCourseSaleRecordsAnalyticsBasic(ModuleStoreTestCase):
""" Test basic course sale records analytics functions. """
def setUp(self):
"""
Fixtures.
"""
super(TestCourseSaleRecordsAnalyticsBasic, self).setUp()
self.course = CourseFactory.create()
self.cost = 40
self.course_mode = CourseMode(
course_id=self.course.id, mode_slug="honor",
mode_display_name="honor cert", min_price=self.cost
)
self.course_mode.save()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
def test_course_sale_features(self):
query_features = [
'company_name', 'company_contact_name', 'company_contact_email', 'total_codes', 'total_used_codes',
'total_amount', 'created', 'customer_reference_number', 'recipient_name', 'recipient_email',
'created_by', 'internal_reference', 'invoice_number', 'codes', 'course_id'
]
#create invoice
sale_invoice = Invoice.objects.create(
total_amount=1234.32, company_name='Test1', company_contact_name='TestName',
company_contact_email='test@company.com', recipient_name='Testw_1', recipient_email='test2@test.com',
customer_reference_number='2Fwe23S', internal_reference="ABC", course_id=self.course.id
)
invoice_item = CourseRegistrationCodeInvoiceItem.objects.create(
invoice=sale_invoice,
qty=1,
unit_price=1234.32,
course_id=self.course.id
)
for i in range(5):
course_code = CourseRegistrationCode(
code="test_code{}".format(i), course_id=text_type(self.course.id),
created_by=self.instructor, invoice=sale_invoice, invoice_item=invoice_item, mode_slug='honor'
)
course_code.save()
course_sale_records_list = sale_record_features(self.course.id, query_features)
for sale_record in course_sale_records_list:
self.assertEqual(sale_record['total_amount'], sale_invoice.total_amount)
self.assertEqual(sale_record['recipient_email'], sale_invoice.recipient_email)
self.assertEqual(sale_record['recipient_name'], sale_invoice.recipient_name)
self.assertEqual(sale_record['company_name'], sale_invoice.company_name)
self.assertEqual(sale_record['company_contact_name'], sale_invoice.company_contact_name)
self.assertEqual(sale_record['company_contact_email'], sale_invoice.company_contact_email)
self.assertEqual(sale_record['internal_reference'], sale_invoice.internal_reference)
self.assertEqual(sale_record['customer_reference_number'], sale_invoice.customer_reference_number)
self.assertEqual(sale_record['invoice_number'], sale_invoice.id)
self.assertEqual(sale_record['created_by'], self.instructor)
self.assertEqual(sale_record['total_used_codes'], 0)
self.assertEqual(sale_record['total_codes'], 5)
def test_course_sale_no_codes(self):
query_features = [
'company_name', 'company_contact_name', 'company_contact_email', 'total_codes', 'total_used_codes',
'total_amount', 'created', 'customer_reference_number', 'recipient_name', 'recipient_email',
'created_by', 'internal_reference', 'invoice_number', 'codes', 'course_id'
]
#create invoice
sale_invoice = Invoice.objects.create(
total_amount=0.00, company_name='Test1', company_contact_name='TestName',
company_contact_email='test@company.com', recipient_name='Testw_1', recipient_email='test2@test.com',
customer_reference_number='2Fwe23S', internal_reference="ABC", course_id=self.course.id
)
CourseRegistrationCodeInvoiceItem.objects.create(
invoice=sale_invoice,
qty=0,
unit_price=0.00,
course_id=self.course.id
)
course_sale_records_list = sale_record_features(self.course.id, query_features)
for sale_record in course_sale_records_list:
self.assertEqual(sale_record['total_amount'], sale_invoice.total_amount)
self.assertEqual(sale_record['recipient_email'], sale_invoice.recipient_email)
self.assertEqual(sale_record['recipient_name'], sale_invoice.recipient_name)
self.assertEqual(sale_record['company_name'], sale_invoice.company_name)
self.assertEqual(sale_record['company_contact_name'], sale_invoice.company_contact_name)
self.assertEqual(sale_record['company_contact_email'], sale_invoice.company_contact_email)
self.assertEqual(sale_record['internal_reference'], sale_invoice.internal_reference)
self.assertEqual(sale_record['customer_reference_number'], sale_invoice.customer_reference_number)
self.assertEqual(sale_record['invoice_number'], sale_invoice.id)
self.assertEqual(sale_record['created_by'], None)
self.assertEqual(sale_record['total_used_codes'], 0)
self.assertEqual(sale_record['total_codes'], 0)
def test_sale_order_features_with_discount(self):
"""
Test Order Sales Report CSV
"""
query_features = [
('id', 'Order Id'),
('company_name', 'Company Name'),
('company_contact_name', 'Company Contact Name'),
('company_contact_email', 'Company Contact Email'),
('total_amount', 'Total Amount'),
('total_codes', 'Total Codes'),
('total_used_codes', 'Total Used Codes'),
('logged_in_username', 'Login Username'),
('logged_in_email', 'Login User Email'),
('purchase_time', 'Date of Sale'),
('customer_reference_number', 'Customer Reference Number'),
('recipient_name', 'Recipient Name'),
('recipient_email', 'Recipient Email'),
('bill_to_street1', 'Street 1'),
('bill_to_street2', 'Street 2'),
('bill_to_city', 'City'),
('bill_to_state', 'State'),
('bill_to_postalcode', 'Postal Code'),
('bill_to_country', 'Country'),
('order_type', 'Order Type'),
('status', 'Order Item Status'),
('coupon_code', 'Coupon Code'),
('unit_cost', 'Unit Price'),
('list_price', 'List Price'),
('codes', 'Registration Codes'),
('course_id', 'Course Id')
]
# add the coupon code for the course
coupon = Coupon(
code='test_code',
description='test_description',
course_id=self.course.id,
percentage_discount='10',
created_by=self.instructor,
is_active=True
)
coupon.save()
order = Order.get_cart_for_user(self.instructor)
order.order_type = 'business'
order.save()
order.add_billing_details(
company_name='Test Company',
company_contact_name='Test',
company_contact_email='test@123',
recipient_name='R1', recipient_email='',
customer_reference_number='PO#23'
)
CourseRegCodeItem.add_to_order(order, self.course.id, 4)
# apply the coupon code to the item in the cart
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': coupon.code})
self.assertEqual(resp.status_code, 200)
order.purchase()
# get the updated item
item = order.orderitem_set.all().select_subclasses()[0]
# get the redeemed coupon information
coupon_redemption = CouponRedemption.objects.select_related('coupon').filter(order=order)
db_columns = [x[0] for x in query_features]
sale_order_records_list = sale_order_record_features(self.course.id, db_columns)
for sale_order_record in sale_order_records_list:
self.assertEqual(sale_order_record['recipient_email'], order.recipient_email)
self.assertEqual(sale_order_record['recipient_name'], order.recipient_name)
self.assertEqual(sale_order_record['company_name'], order.company_name)
self.assertEqual(sale_order_record['company_contact_name'], order.company_contact_name)
self.assertEqual(sale_order_record['company_contact_email'], order.company_contact_email)
self.assertEqual(sale_order_record['customer_reference_number'], order.customer_reference_number)
self.assertEqual(sale_order_record['unit_cost'], item.unit_cost)
self.assertEqual(sale_order_record['list_price'], item.list_price)
self.assertEqual(sale_order_record['status'], item.status)
self.assertEqual(sale_order_record['coupon_code'], coupon_redemption[0].coupon.code)
def test_sale_order_features_without_discount(self):
"""
Test Order Sales Report CSV
"""
query_features = [
('id', 'Order Id'),
('company_name', 'Company Name'),
('company_contact_name', 'Company Contact Name'),
('company_contact_email', 'Company Contact Email'),
('total_amount', 'Total Amount'),
('total_codes', 'Total Codes'),
('total_used_codes', 'Total Used Codes'),
('logged_in_username', 'Login Username'),
('logged_in_email', 'Login User Email'),
('purchase_time', 'Date of Sale'),
('customer_reference_number', 'Customer Reference Number'),
('recipient_name', 'Recipient Name'),
('recipient_email', 'Recipient Email'),
('bill_to_street1', 'Street 1'),
('bill_to_street2', 'Street 2'),
('bill_to_city', 'City'),
('bill_to_state', 'State'),
('bill_to_postalcode', 'Postal Code'),
('bill_to_country', 'Country'),
('order_type', 'Order Type'),
('status', 'Order Item Status'),
('coupon_code', 'Coupon Code'),
('unit_cost', 'Unit Price'),
('list_price', 'List Price'),
('codes', 'Registration Codes'),
('course_id', 'Course Id'),
('quantity', 'Quantity'),
('total_discount', 'Total Discount'),
('total_amount', 'Total Amount Paid'),
]
# add the coupon code for the course
order = Order.get_cart_for_user(self.instructor)
order.order_type = 'business'
order.save()
order.add_billing_details(
company_name='Test Company',
company_contact_name='Test',
company_contact_email='test@123',
recipient_name='R1', recipient_email='',
customer_reference_number='PO#23'
)
CourseRegCodeItem.add_to_order(order, self.course.id, 4)
order.purchase()
# get the updated item
item = order.orderitem_set.all().select_subclasses()[0]
db_columns = [x[0] for x in query_features]
sale_order_records_list = sale_order_record_features(self.course.id, db_columns)
for sale_order_record in sale_order_records_list:
self.assertEqual(sale_order_record['recipient_email'], order.recipient_email)
self.assertEqual(sale_order_record['recipient_name'], order.recipient_name)
self.assertEqual(sale_order_record['company_name'], order.company_name)
self.assertEqual(sale_order_record['company_contact_name'], order.company_contact_name)
self.assertEqual(sale_order_record['company_contact_email'], order.company_contact_email)
self.assertEqual(sale_order_record['customer_reference_number'], order.customer_reference_number)
self.assertEqual(sale_order_record['unit_cost'], item.unit_cost)
# Make sure list price is not None and matches the unit price since no discount was applied.
self.assertIsNotNone(sale_order_record['list_price'])
self.assertEqual(sale_order_record['list_price'], item.unit_cost)
self.assertEqual(sale_order_record['status'], item.status)
self.assertEqual(sale_order_record['coupon_code'], 'N/A')
self.assertEqual(sale_order_record['total_amount'], item.unit_cost * item.qty)
self.assertEqual(sale_order_record['total_discount'], 0)
self.assertEqual(sale_order_record['quantity'], item.qty)
class TestCourseRegistrationCodeAnalyticsBasic(ModuleStoreTestCase):
""" Test basic course registration codes analytics functions. """
def setUp(self):
"""
Fixtures.
"""
super(TestCourseRegistrationCodeAnalyticsBasic, self).setUp()
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
CourseSalesAdminRole(self.course.id).add_users(self.instructor)
# Create a paid course mode.
mode = CourseModeFactory.create(course_id=self.course.id, min_price=1)
url = reverse('generate_registration_codes',
kwargs={'course_id': text_type(self.course.id)})
data = {
'total_registration_codes': 12, 'company_name': 'Test Group', 'unit_price': 122.45,
'company_contact_name': 'TestName', 'company_contact_email': 'test@company.com', 'recipient_name': 'Test123',
'recipient_email': 'test@123.com', 'address_line_1': 'Portland Street', 'address_line_2': '',
'address_line_3': '', 'city': '', 'state': '', 'zip': '', 'country': '',
'customer_reference_number': '123A23F', 'internal_reference': '', 'invoice': ''
}
response = self.client.post(url, data, **{'HTTP_HOST': 'localhost'})
self.assertEqual(response.status_code, 200, response.content)
def test_course_registration_features(self):
query_features = [
'code', 'redeem_code_url', 'course_id', 'company_name', 'created_by',
'redeemed_by', 'invoice_id', 'purchaser', 'customer_reference_number', 'internal_reference'
]
order = Order(user=self.instructor, status='purchased')
order.save()
registration_code_redemption = RegistrationCodeRedemption(
registration_code_id=1, redeemed_by=self.instructor
)
registration_code_redemption.save()
registration_codes = CourseRegistrationCode.objects.all()
course_registration_list = course_registration_features(query_features, registration_codes, csv_type='download')
self.assertEqual(len(course_registration_list), len(registration_codes))
for course_registration in course_registration_list:
self.assertEqual(set(course_registration.keys()), set(query_features))
self.assertIn(course_registration['code'], [registration_code.code for registration_code in registration_codes])
self.assertIn(
course_registration['course_id'],
[text_type(registration_code.course_id) for registration_code in registration_codes]
)
self.assertIn(
course_registration['company_name'],
[
registration_code.invoice_item.invoice.company_name
for registration_code in registration_codes
]
)
self.assertIn(
course_registration['invoice_id'],
[
registration_code.invoice_item.invoice_id
for registration_code in registration_codes
]
)
def test_coupon_codes_features(self):
query_features = [
'course_id', 'percentage_discount', 'code_redeemed_count', 'description', 'expiration_date',
'total_discounted_amount', 'total_discounted_seats'
]
for i in range(10):
coupon = Coupon(
code='test_code{0}'.format(i),
description='test_description',
course_id=self.course.id, percentage_discount='{0}'.format(i),
created_by=self.instructor,
is_active=True
)
coupon.save()
#now create coupons with the expiration dates
for i in range(5):
coupon = Coupon(
code='coupon{0}'.format(i), description='test_description', course_id=self.course.id,
percentage_discount='{0}'.format(i), created_by=self.instructor, is_active=True,
expiration_date=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=2)
)
coupon.save()
active_coupons = Coupon.objects.filter(
Q(course_id=self.course.id),
Q(is_active=True),
Q(expiration_date__gt=datetime.datetime.now(pytz.UTC)) |
Q(expiration_date__isnull=True)
)
active_coupons_list = coupon_codes_features(query_features, active_coupons, self.course.id)
self.assertEqual(len(active_coupons_list), len(active_coupons))
for active_coupon in active_coupons_list:
self.assertEqual(set(active_coupon.keys()), set(query_features))
self.assertIn(active_coupon['percentage_discount'], [coupon.percentage_discount for coupon in active_coupons])
self.assertIn(active_coupon['description'], [coupon.description for coupon in active_coupons])
if active_coupon['expiration_date']:
self.assertIn(active_coupon['expiration_date'], [coupon.display_expiry_date for coupon in active_coupons])
self.assertIn(
active_coupon['course_id'],
[text_type(coupon.course_id) for coupon in active_coupons]
)