diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index 2013067360..39fe69a0cc 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -10,6 +10,7 @@ from boto.exception import BotoServerError # this is a super-class of SESError from django.dispatch import receiver from django.db import models +from django.db.models import Sum from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.mail import send_mail @@ -18,6 +19,8 @@ from django.utils.translation import ugettext as _ from django.db import transaction from django.core.urlresolvers import reverse +from decimal import Decimal + from xmodule.modulestore.django import modulestore from xmodule.course_module import CourseDescriptor from xmodule.modulestore.exceptions import ItemNotFoundError @@ -671,22 +674,27 @@ class ItemizedPurchaseReport(Report): class CertificateStatusReport(Report): def get_query(self, start_date, send_date): results = [] - for course_id in settings.COURSE_LISTINGS: - cur_course = get_course_by_id(course) + for course_id in settings.COURSE_LISTINGS['default']: + cur_course = get_course_by_id(course_id) university = cur_course.org - course = cur_course.number + " " + course.display_name #TODO add term (i.e. Fall 2013)? + course = cur_course.number + " " + cur_course.display_name #TODO add term (i.e. Fall 2013)? enrollments = CourseEnrollment.objects.filter(course_id=course_id) - total_enrolled = enrollments.objects.count() - audit_enrolled = enrollments.objects.filter(mode="audit").count() - honor_enrolled = enrollments.objects.filter(mode="honor").count() - verified_enrollments = enrollments.objects.filter(mode="verified") - verified_enrolled = verified_enrollments.objects.count() - gross_rev = CertificateItem.objects.filter(course_id=course_id, mode="verified").aggregate(Sum('unit_cost')) - gross_rev_over_min = gross_rev - (CourseMode.objects.get('course_id').min_price * verified_enrollments) + total_enrolled = enrollments.count() + audit_enrolled = enrollments.filter(mode="audit").count() + honor_enrolled = enrollments.filter(mode="honor").count() + verified_enrollments = enrollments.filter(mode="verified") + verified_enrolled = verified_enrollments.count() + gross_rev_temp = CertificateItem.objects.filter(course_id=course_id, mode="verified").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") - number_of_refunds = refunded_enrollments.objects.count() - dollars_refunded = refunded_enrollments.objects.aggregate(Sum('unit_cost')) + number_of_refunds = refunded_enrollments.count() + dollars_refunded_temp = refunded_enrollments.aggregate(Sum('unit_cost')) + if dollars_refunded_temp['unit_cost__sum'] is None: + dollars_refunded = Decimal(0.00) + else: + dollars_refunded = dollars_refunded_temp['unit_cost__sum'] result = [ university, @@ -727,8 +735,8 @@ class CertificateStatusReport(Report): class UniversityRevenueShareReport(Report): def get_query(self, start_date, end_date): results = [] - for course_id in settings.COURSE_LISTINGS: - cur_course = get_course_by_id(course) + for course_id in settings.COURSE_LISTINGS['default']: + cur_course = get_course_by_id(course_id) university = cur_course.org course = cur_course.number + " " + course.display_name num_transactions = 0 # TODO clarify with building what transactions are included in this (purchases? refunds? etc) diff --git a/lms/djangoapps/shoppingcart/tests/test_models.py b/lms/djangoapps/shoppingcart/tests/test_models.py index aeb92740a6..7edf06b06f 100644 --- a/lms/djangoapps/shoppingcart/tests/test_models.py +++ b/lms/djangoapps/shoppingcart/tests/test_models.py @@ -490,11 +490,41 @@ class CertificateStatusReportTest(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() + # Need to make a *lot* of users for this one + 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 = "Joe" + self.user3.last_name = "Miller" + self.user3.save() + + self.user4 = UserFactory.create() + self.user4.first_name = "Simon" + self.user4.last_name = "Blackquill" + self.user4.save() + + self.user5 = UserFactory.create() + self.user5.first_name = "Super" + self.user5.last_name = "Mario" + self.user5.save() + + self.user6 = UserFactory.create() + self.user6.first_name = "Princess" + self.user6.last_name = "Peach" + self.user6.save() + + # Two are verified, three are audit, one honor + self.course_id = "MITx/999/Robot_Super_Course" + settings.COURSE_LISTINGS['default'] = [self.course_id] 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, @@ -509,12 +539,33 @@ class CertificateStatusReportTest(ModuleStoreTestCase): 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() + # User 1 & 2 will be verified + self.cart1 = Order.get_cart_for_user(self.user1) + CertificateItem.add_to_order(self.cart1, self.course_id, self.cost, 'verified') + self.cart1.purchase() + + self.cart2 = Order.get_cart_for_user(self.user2) + CertificateItem.add_to_order(self.cart2, self.course_id, self.cost, 'verified') + 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") + + # User 6 is honor + CourseEnrollment.get_or_create_enrollment(self.user6, self.course_id).update_enrollment(mode="honor") self.now = datetime.datetime.now(pytz.UTC) + # bluh need to test some refunds + + 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))) + # TODO finish these tests. This is just a basic test to start with, making sure the regular # flow doesn't throw any strange errors while running def test_basic(self): @@ -523,7 +574,9 @@ class CertificateStatusReportTest(ModuleStoreTestCase): refunded_certs = report.get_query(self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) csv_file = StringIO.StringIO() report.make_report(report_type, csv_file, self.now - self.FIVE_MINS, self.now + self.FIVE_MINS) - # TODO no time restrictions yet + csv = csv_file.getvalue() + self.assertEqual(csv.replace('\r\n', '\n').strip(), self.CORRECT_CSV.strip()) + # TODO no time restrictions ye # TODO: finish this test class @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)