From 68174dc33daf80d8159a6ecec5e4a5f403dc1d50 Mon Sep 17 00:00:00 2001 From: Julia Hansbrough Date: Tue, 10 Dec 2013 20:10:48 +0000 Subject: [PATCH] Initial view --- lms/djangoapps/shoppingcart/models.py | 12 ++++----- .../shoppingcart/tests/test_models.py | 4 +-- .../shoppingcart/tests/test_views.py | 25 ++++++++++++------- lms/djangoapps/shoppingcart/urls.py | 3 ++- lms/djangoapps/shoppingcart/views.py | 13 +++++----- .../shoppingcart/download_report.html | 13 +++++++--- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index de7443c3bb..3063a0b98d 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -636,6 +636,8 @@ class RefundReport(Report): def get_query(self, start_date, end_date): return CertificateItem.objects.filter( status="refunded", + refund_requested_time__gte=start_date, + refund_requested_time__lt=end_date, ) def csv_report_header_row(self): @@ -653,7 +655,7 @@ class RefundReport(Report): item.order_id, item.user.get_full_name(), item.fulfilled_time, - item.refund_requested_time, # TODO actually may need to use refund_fulfilled here + item.refund_requested_time, # TODO Change this torefund_fulfilled once we start recording that value item.line_cost, item.service_fee, ] @@ -707,7 +709,8 @@ 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,is_active=True) + 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() @@ -717,7 +720,6 @@ class CertificateStatusReport(Report): 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="verified", status="refunded") number_of_refunds = refunded_enrollments.count() dollars_refunded_temp = refunded_enrollments.aggregate(Sum('unit_cost')) @@ -735,7 +737,6 @@ class CertificateStatusReport(Report): verified_enrolled, gross_rev, gross_rev_over_min, - num_verified_over_min, number_of_refunds, dollars_refunded ] @@ -753,7 +754,6 @@ class CertificateStatusReport(Report): "Verified Enrollment", "Gross Revenue", "Gross Revenue over the Minimum", - "Number of Verified over the Minimum", "Number of Refunds", "Dollars Refunded", ] @@ -772,7 +772,7 @@ class UniversityRevenueShareReport(Report): cur_course = get_course_by_id(course_id) university = cur_course.org course = cur_course.number + " " + cur_course.display_name - num_transactions = 0 # TODO clarify with building what transactions are included in this (purchases? refunds? etc) + num_transactions = 0 # TODO clarify with billing what transactions are included in this (purchases? refunds? etc) all_paid_certs = CertificateItem.objects.filter(course_id=course_id, status="purchased") diff --git a/lms/djangoapps/shoppingcart/tests/test_models.py b/lms/djangoapps/shoppingcart/tests/test_models.py index cf4ab5dbe7..80dd5a1423 100644 --- a/lms/djangoapps/shoppingcart/tests/test_models.py +++ b/lms/djangoapps/shoppingcart/tests/test_models.py @@ -510,8 +510,8 @@ class ReportTypeTests(ModuleStoreTestCase): """.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 + University,Course,Total Enrolled,Audit Enrollment,Honor Code Enrollment,Verified Enrollment,Gross Revenue,Gross Revenue over the Minimum,Number of Refunds,Dollars Refunded + MITx,999 Robot Super Course,6,3,1,2,80.00,0.00,0,0 """.format(time_str=str(self.test_time))) self.CORRECT_UNI_REVENUE_SHARE_CSV = dedent(""" diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py index d0e59eb680..a08decd05f 100644 --- a/lms/djangoapps/shoppingcart/tests/test_views.py +++ b/lms/djangoapps/shoppingcart/tests/test_views.py @@ -304,6 +304,11 @@ class CSVReportViewsTest(ModuleStoreTestCase): mode_display_name="honor cert", min_price=self.cost) self.course_mode.save() + self.course_mode2 = CourseMode(course_id=self.course_id, + mode_slug="verified", + mode_display_name="verified cert", + min_price=self.cost) + self.course_mode2.save() self.verified_course_id = 'org/test/Test_Course' CourseFactory.create(org='org', number='test', run='course1', display_name='Test Course') self.cart = Order.get_cart_for_user(self.user) @@ -343,13 +348,14 @@ class CSVReportViewsTest(ModuleStoreTestCase): self.assertEqual(template, 'shoppingcart/download_report.html') self.assertFalse(context['total_count_error']) self.assertFalse(context['date_fmt_error']) - self.assertIn(_("Download Purchase Report"), response.content) + self.assertIn(_("Download CSV Reports"), response.content) @patch('shoppingcart.views.render_to_response', render_mock) def test_report_csv_bad_date(self): self.login_user() self.add_to_download_group(self.user) - response = self.client.post(reverse('payment_csv_report'), {'start_date': 'BAD', 'end_date': 'BAD'}) + report_type = "itemized_purchase_report" + response = self.client.post(reverse('payment_csv_report'), {'start_date': 'BAD', 'end_date': 'BAD', 'requested_report': 'itemized_purchase_report'}) ((template, context), unused_kwargs) = render_mock.call_args self.assertEqual(template, 'shoppingcart/download_report.html') @@ -366,7 +372,8 @@ class CSVReportViewsTest(ModuleStoreTestCase): self.login_user() self.add_to_download_group(self.user) response = self.client.post(reverse('payment_csv_report'), {'start_date': '1970-01-01', - 'end_date': '2100-01-01'}) + 'end_date': '2100-01-01', + 'requested_report': 'itemized_purchase_report'}) ((template, context), unused_kwargs) = render_mock.call_args self.assertEqual(template, 'shoppingcart/download_report.html') @@ -376,22 +383,22 @@ class CSVReportViewsTest(ModuleStoreTestCase): # just going to ignored the date in this test, since we already deal with date testing # in test_models.py - CORRECT_CSV_NO_DATE = ",1,purchased,1,40,40,usd,Registration for Course: Robot Super Course," + + CORRECT_CSV_NO_DATE_ITEMIZED_PURCHASE = ",1,purchased,1,40,40,usd,Registration for Course: Robot Super Course," def test_report_csv(self): - # TODO test multiple types - report_type = "itemized_purchase_report" - + report_type = 'itemized_purchase_report' PaidCourseRegistration.add_to_order(self.cart, self.course_id) self.cart.purchase() self.login_user() self.add_to_download_group(self.user) response = self.client.post(reverse('payment_csv_report'), {'start_date': '1970-01-01', - 'end_date': '2100-01-01'}) + 'end_date': '2100-01-01', + 'requested_report': report_type}) self.assertEqual(response['Content-Type'], 'text/csv') report = Report.initialize_report(report_type) self.assertIn(",".join(report.csv_report_header_row()), response.content) - self.assertIn(self.CORRECT_CSV_NO_DATE, response.content) + self.assertIn(self.CORRECT_CSV_NO_DATE_ITEMIZED_PURCHASE, response.content) class UtilFnsTest(TestCase): diff --git a/lms/djangoapps/shoppingcart/urls.py b/lms/djangoapps/shoppingcart/urls.py index b9797e9a5b..ba4119aef7 100644 --- a/lms/djangoapps/shoppingcart/urls.py +++ b/lms/djangoapps/shoppingcart/urls.py @@ -5,6 +5,7 @@ urlpatterns = patterns('shoppingcart.views', # nopep8 url(r'^postpay_callback/$', 'postpay_callback'), # Both the ~accept and ~reject callback pages are handled here url(r'^receipt/(?P[0-9]*)/$', 'show_receipt'), ) + if settings.FEATURES['ENABLE_SHOPPING_CART']: urlpatterns += patterns( 'shoppingcart.views', @@ -19,5 +20,5 @@ if settings.FEATURES.get('ENABLE_PAYMENT_FAKE'): from shoppingcart.tests.payment_fake import PaymentFakeView urlpatterns += patterns( 'shoppingcart.tests.payment_fake', - url(r'^payment_fake', PaymentFakeView.as_view()) + url(r'^payment_fake', PaymentFakeView.as_view()), ) diff --git a/lms/djangoapps/shoppingcart/views.py b/lms/djangoapps/shoppingcart/views.py index 907c0dcbce..b19e2244f7 100644 --- a/lms/djangoapps/shoppingcart/views.py +++ b/lms/djangoapps/shoppingcart/views.py @@ -95,7 +95,6 @@ def postpay_callback(request): return render_to_response('shoppingcart/error.html', {'order': result['order'], 'error_html': result['error_html']}) - @login_required def show_receipt(request, ordernum): """ @@ -156,7 +155,7 @@ def _get_date_from_str(date_input): return datetime.datetime.strptime(date_input.strip(), "%Y-%m-%d").replace(tzinfo=pytz.UTC) -def _render_report_form(start_str, end_str, total_count_error=False, date_fmt_error=False): +def _render_report_form(start_str, end_str, report_type, total_count_error=False, date_fmt_error=False): """ Helper function that renders the purchase form. Reduces repetition """ @@ -165,6 +164,7 @@ def _render_report_form(start_str, end_str, total_count_error=False, date_fmt_er 'date_fmt_error': date_fmt_error, 'start_date': start_str, 'end_date': end_str, + 'requested_report': report_type, } return render_to_response('shoppingcart/download_report.html', context) @@ -174,8 +174,6 @@ def csv_report(request): """ Downloads csv reporting of orderitems """ - # TODO: change this to something modular later - report_type = "itemized_purchase_report" if not _can_download_report(request.user): return HttpResponseForbidden(_('You do not have permission to view this page.')) @@ -183,18 +181,19 @@ def csv_report(request): if request.method == 'POST': start_str = request.POST.get('start_date', '') end_str = request.POST.get('end_date', '') + report_type = request.POST.get('requested_report', '') try: start_date = _get_date_from_str(start_str) end_date = _get_date_from_str(end_str) + datetime.timedelta(days=1) except ValueError: # Error case: there was a badly formatted user-input date string - return _render_report_form(start_str, end_str, date_fmt_error=True) + return _render_report_form(start_str, end_str, report_type, date_fmt_error=True) report = Report.initialize_report(report_type) items = report.get_query(start_date, end_date) if items.count() > settings.PAYMENT_REPORT_MAX_ITEMS: # Error case: too many items would be generated in the report and we're at risk of timeout - return _render_report_form(start_str, end_str, total_count_error=True) + return _render_report_form(start_str, end_str, report_type, total_count_error=True) response = HttpResponse(mimetype='text/csv') filename = "purchases_report_{}.csv".format(datetime.datetime.now(pytz.UTC).strftime("%Y-%m-%d-%H-%M-%S")) @@ -206,7 +205,7 @@ def csv_report(request): elif request.method == 'GET': end_date = datetime.datetime.now(pytz.UTC) start_date = end_date - datetime.timedelta(days=30) - return _render_report_form(start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d")) + return _render_report_form(start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d"), report_type="") else: return HttpResponseBadRequest("HTTP Method Not Supported") diff --git a/lms/templates/shoppingcart/download_report.html b/lms/templates/shoppingcart/download_report.html index 838b07f145..67cdbce913 100644 --- a/lms/templates/shoppingcart/download_report.html +++ b/lms/templates/shoppingcart/download_report.html @@ -2,11 +2,11 @@ <%! from django.core.urlresolvers import reverse %> <%inherit file="../main.html" /> -<%block name="title">${_("Download Purchase Report")} +<%block name="title">${_("Download CSV Reports")}
-

${_("Download CSV of purchase data")}

+

${_("Download CSV Data")}

% if date_fmt_error:
${_("There was an error in your date input. It should be formatted as YYYY-MM-DD")} @@ -24,6 +24,13 @@ - +
+ +
+ +
+ +
+