diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index dcc4c22538..de7443c3bb 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -707,17 +707,18 @@ class CertificateStatusReport(Report): cur_course = get_course_by_id(course_id) university = cur_course.org course = cur_course.number + " " + cur_course.display_name # TODO add term (i.e. Fall 2013)? - enrollments = CourseEnrollment.objects.filter(course_id=course_id) + enrollments = CourseEnrollment.objects.filter(course_id=course_id,is_active=True) total_enrolled = enrollments.count() audit_enrolled = enrollments.filter(mode="audit").count() honor_enrolled = enrollments.filter(mode="honor").count() - verified_enrollments = enrollments.filter(mode="verified") + # Since every verified enrollment has 1 and only 1 cert item, let's just query those + verified_enrollments = CertificateItem.objects.filter(course_id=course_id, mode="verified", status="purchased") verified_enrolled = verified_enrollments.count() - gross_rev_temp = CertificateItem.objects.filter(course_id=course_id, mode="verified").aggregate(Sum('unit_cost')) + gross_rev_temp = CertificateItem.objects.filter(course_id=course_id, mode="verified", status="purchased").aggregate(Sum('unit_cost')) gross_rev = gross_rev_temp['unit_cost__sum'] gross_rev_over_min = gross_rev - (CourseMode.objects.get(course_id=course_id, mode_slug="verified").min_price * verified_enrolled) num_verified_over_min = 0 # TODO clarify with billing what exactly this means - refunded_enrollments = CertificateItem.objects.filter(course_id='course_id', mode="refunded") + refunded_enrollments = CertificateItem.objects.filter(course_id='course_id', mode="verified", status="refunded") number_of_refunds = refunded_enrollments.count() dollars_refunded_temp = refunded_enrollments.aggregate(Sum('unit_cost')) if dollars_refunded_temp['unit_cost__sum'] is None: diff --git a/lms/djangoapps/shoppingcart/tests/test_models.py b/lms/djangoapps/shoppingcart/tests/test_models.py index 8ff8284b9c..cf4ab5dbe7 100644 --- a/lms/djangoapps/shoppingcart/tests/test_models.py +++ b/lms/djangoapps/shoppingcart/tests/test_models.py @@ -323,74 +323,6 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase): self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id)) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) -class RefundReportTest(ModuleStoreTestCase): - FIVE_MINS = datetime.timedelta(minutes=5) - - def setUp(self): - self.user = UserFactory.create() - self.user.first_name = "John" - self.user.last_name = "Doe" - self.user.save() - self.course_id = "MITx/999/Robot_Super_Course" - self.cost = 40 - self.course = CourseFactory.create(org='MITx', number='999', display_name=u'Robot Super Course') - course_mode = CourseMode(course_id=self.course_id, - mode_slug="honor", - mode_display_name="honor cert", - min_price=self.cost) - course_mode.save() - - course_mode2 = CourseMode(course_id=self.course_id, - mode_slug="verified", - mode_display_name="verified cert", - min_price=self.cost) - course_mode2.save() - - self.cart = Order.get_cart_for_user(self.user) - CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') - self.cart.purchase() - - # should auto-refund the relevant cert - CourseEnrollment.unenroll(self.user, self.course_id) - - self.cert_item = CertificateItem.objects.get(user=self.user, course_id=self.course_id) - - self.now = datetime.datetime.now(pytz.UTC) - - def test_get_query(self): - report_type = "refund_report" - report = Report.initialize_report(report_type) - refunded_certs = report.get_query(self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) - self.assertEqual(len(refunded_certs), 1) - self.assertIn(self.cert_item, refunded_certs) - - test_time = datetime.datetime.now(pytz.UTC) - - CORRECT_CSV = dedent(""" - Order Number,Customer Name,Date of Original Transaction,Date of Refund,Amount of Refund,Service Fees (if any) - 1,John Doe,{time_str},{time_str},40,0 - """.format(time_str=str(test_time))) - - def test_purchased_csv(self): - """ - Tests that a generated purchase report CSV is as we expect - """ - report_type = "refund_report" - report = Report.initialize_report(report_type) - for item in report.get_query(self.now - self.FIVE_MINS, self.now + self.FIVE_MINS): - item.fulfilled_time = self.test_time - item.refund_requested_time = self.test_time # hm do we want to make these different - item.save() - - csv_file = StringIO.StringIO() - Report.make_report(report_type, csv_file, self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) - csv = csv_file.getvalue() - csv_file.close() - # Using excel mode csv, which automatically ends lines with \r\n, so need to convert to \n - self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_CSV.strip()) - - @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) class ItemizedPurchaseReportTest(ModuleStoreTestCase): """ @@ -474,7 +406,7 @@ class ItemizedPurchaseReportTest(ModuleStoreTestCase): @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) -class CertificateStatusReportTest(ModuleStoreTestCase): +class ReportTypeTests(ModuleStoreTestCase): """ Tests for the models used to generate certificate status reports """ @@ -512,6 +444,16 @@ class CertificateStatusReportTest(ModuleStoreTestCase): self.user6.last_name = "Peach" self.user6.save() + self.user7 = UserFactory.create() + self.user7.first_name = "King" + self.user7.last_name = "Bowser" + self.user7.save() + + self.user8 = UserFactory.create() + self.user8.first_name = "Susan" + self.user8.last_name = "Smith" + self.user8.save() + # Two are verified, three are audit, one honor self.course_id = "MITx/999/Robot_Super_Course" @@ -540,101 +482,84 @@ class CertificateStatusReportTest(ModuleStoreTestCase): self.cart2.purchase() # Users 3, 4, and 5 are audit - CourseEnrollment.get_or_create_enrollment(self.user3, self.course_id).update_enrollment(mode="audit") - CourseEnrollment.get_or_create_enrollment(self.user4, self.course_id).update_enrollment(mode="audit") - CourseEnrollment.get_or_create_enrollment(self.user5, self.course_id).update_enrollment(mode="audit") + CourseEnrollment.enroll(self.user3, self.course_id, "audit") + CourseEnrollment.enroll(self.user4, self.course_id, "audit") + CourseEnrollment.enroll(self.user5, self.course_id, "audit") # User 6 is honor - CourseEnrollment.get_or_create_enrollment(self.user6, self.course_id).update_enrollment(mode="honor") + CourseEnrollment.enroll(self.user6, self.course_id, "honor") self.now = datetime.datetime.now(pytz.UTC) - # bluh need to test some refunds + # Users 7 & 8 are refunds + self.cart = Order.get_cart_for_user(self.user7) + CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') + self.cart.purchase() + CourseEnrollment.unenroll(self.user7, self.course_id) - test_time = datetime.datetime.now(pytz.UTC) - CORRECT_CSV = dedent(""" - University,Course,Total Enrolled,Audit Enrollment,Honor Code Enrollment,Verified Enrollment,Gross Revenue,Gross Revenue over the Minimum,Number of Verified over the Minimum,Number of Refunds,Dollars Refunded - MITx,999 Robot Super Course,6,3,1,2,80.00,0.00,0,0,0 - """.format(time_str=str(test_time))) + self.cart = Order.get_cart_for_user(self.user8) + CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') + self.cart.purchase(self.user8, self.course_id) + CourseEnrollment.unenroll(self.user8, self.course_id) - def test_basic(self): + self.test_time = datetime.datetime.now(pytz.UTC) + self.CORRECT_REFUND_REPORT_CSV = dedent(""" + Order Number,Customer Name,Date of Original Transaction,Date of Refund,Amount of Refund,Service Fees (if any) + 3,King Bowser,{time_str},{time_str},40,0 + 4,Susan Smith,{time_str},{time_str},40,0 + """.format(time_str=str(self.test_time))) + + self.CORRECT_CERT_STATUS_CSV = dedent(""" + University,Course,Total Enrolled,Audit Enrollment,Honor Code Enrollment,Verified Enrollment,Gross Revenue,Gross Revenue over the Minimum,Number of Verified over the Minimum,Number of Refunds,Dollars Refunded + MITx,999 Robot Super Course,6,3,1,2,80.00,0.00,0,0,0 + """.format(time_str=str(self.test_time))) + + self.CORRECT_UNI_REVENUE_SHARE_CSV = dedent(""" + University,Course,Number of Transactions,Total Payments Collected,Service Fees (if any),Number of Successful Refunds,Total Amount of Refunds + MITx,999 Robot Super Course,0,80.00,0.00,2,80.00 + """.format(time_str=str(self.test_time))) + + def test_refund_report_get_query(self): + report_type = "refund_report" + report = Report.initialize_report(report_type) + refunded_certs = report.get_query(self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) + self.assertEqual(len(refunded_certs), 2) + self.assertTrue(CertificateItem.objects.get(user=self.user7, course_id=self.course_id)) + self.assertTrue(CertificateItem.objects.get(user=self.user8, course_id=self.course_id)) + + def test_refund_report_purchased_csv(self): + """ + Tests that a generated purchase report CSV is as we expect + """ + report_type = "refund_report" + report = Report.initialize_report(report_type) + for item in report.get_query(self.now - self.FIVE_MINS, self.now + self.FIVE_MINS): + item.fulfilled_time = self.test_time + item.refund_requested_time = self.test_time # hm do we want to make these different + item.save() + + csv_file = StringIO.StringIO() + Report.make_report(report_type, csv_file, self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) + csv = csv_file.getvalue() + csv_file.close() + # Using excel mode csv, which automatically ends lines with \r\n, so need to convert to \n + self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_REFUND_REPORT_CSV.strip()) + + def test_basic_cert_status_csv(self): report_type = "certificate_status" report = Report.initialize_report(report_type) csv_file = StringIO.StringIO() report.make_report(report_type, csv_file, self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) csv = csv_file.getvalue() - self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_CSV.strip()) + self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_CERT_STATUS_CSV.strip()) - -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) -class UniversityRevenueShareReportTest(ModuleStoreTestCase): - """ - Tests for the models used to generate university revenue share reports - """ - FIVE_MINS = datetime.timedelta(minutes=5) - - def setUp(self): - self.user1 = UserFactory.create() - self.user1.first_name = "John" - self.user1.last_name = "Doe" - self.user1.save() - - self.user2 = UserFactory.create() - self.user2.first_name = "Jane" - self.user2.last_name = "Deer" - self.user2.save() - - self.user3 = UserFactory.create() - self.user3.first_name = "Simon" - self.user3.last_name = "Blackquill" - self.user3.save() - - self.course_id = "MITx/999/Robot_Super_Course" - self.cost = 40 - self.course = CourseFactory.create(org='MITx', number='999', display_name=u'Robot Super Course') - course_mode = CourseMode(course_id=self.course_id, - mode_slug="honor", - mode_display_name="honor cert", - min_price=self.cost) - course_mode.save() - - course_mode2 = CourseMode(course_id=self.course_id, - mode_slug="verified", - mode_display_name="verified cert", - min_price=self.cost) - course_mode2.save() - - # user1 is a verified purchase - self.cart = Order.get_cart_for_user(self.user1) - CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') - self.cart.purchase() - - # user2 & user3 are refunded purchases - self.cart = Order.get_cart_for_user(self.user2) - CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') - self.cart.purchase() - CourseEnrollment.unenroll(self.user2, self.course_id) - - self.cart = Order.get_cart_for_user(self.user3) - CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') - self.cart.purchase() - CourseEnrollment.unenroll(self.user3, self.course_id) - - self.now = datetime.datetime.now(pytz.UTC) - - test_time = datetime.datetime.now(pytz.UTC) - CORRECT_CSV = dedent(""" - University,Course,Number of Transactions,Total Payments Collected,Service Fees (if any),Number of Successful Refunds,Total Amount of Refunds - MITx,999 Robot Super Course,0,40.00,0,2,80.00 - """.format(time_str=str(test_time))) - - def test_basic(self): + def test_basic_uni_revenue_share_csv(self): report_type = "university_revenue_share" report = Report.initialize_report(report_type) csv_file = StringIO.StringIO() report.make_report(report_type, csv_file, self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) csv = csv_file.getvalue() - self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_CSV.strip()) + self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_UNI_REVENUE_SHARE_CSV.strip()) @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)