Initial view
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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("""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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<ordernum>[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()),
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%inherit file="../main.html" />
|
||||
|
||||
<%block name="title"><title>${_("Download Purchase Report")}</title></%block>
|
||||
<%block name="title"><title>${_("Download CSV Reports")}</title></%block>
|
||||
|
||||
|
||||
<section class="container">
|
||||
<h2>${_("Download CSV of purchase data")}</h2>
|
||||
<h2>${_("Download CSV Data")}</h2>
|
||||
% if date_fmt_error:
|
||||
<section class="error_msg">
|
||||
${_("There was an error in your date input. It should be formatted as YYYY-MM-DD")}
|
||||
@@ -24,6 +24,13 @@
|
||||
<label for="end_date">${_("End Date: ")}</label>
|
||||
<input id="end_date" type="text" value="${end_date}" name="end_date"/>
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}" />
|
||||
<input type="submit" />
|
||||
<br/>
|
||||
<button type = "submit" name="requested_report" value="itemized_purchase_report">Itemized Purchase Report</button>
|
||||
<br/>
|
||||
<button type = "submit" name="requested_report" value="refund_report">Refund Report</button>
|
||||
<br/>
|
||||
<button type = "submit" name="requested_report" value="university_revenue_share">University Revenue Share</button>
|
||||
<br/>
|
||||
<button type="submit" name="requested_report" value="certificate_status">Certiciate Status</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user