Commits

Luke Plant committed 658670f

Abstracted creation/formatting of spreadsheet in routines exporting booking data.

This will be useful for generating ODS as well as Excel files, but that will
probably have to wait as the most useful library, ezodf, is Python 3 only at
the moment.

Comments (0)

Files changed (5)

cciw/bookings/tests.py

 from cciw.bookings.management.commands.expire_bookings import Command as ExpireBookingsCommand
 from cciw.bookings.models import BookingAccount, Price, Booking, Payment, ChequePayment, RefundPayment, book_basket_now
 from cciw.bookings.models import PRICE_FULL, PRICE_2ND_CHILD, PRICE_3RD_CHILD, PRICE_CUSTOM, PRICE_SOUTH_WALES_TRANSPORT, PRICE_DEPOSIT, BOOKING_APPROVED, BOOKING_INFO_COMPLETE, BOOKING_BOOKED, BOOKING_CANCELLED, BOOKING_CANCELLED_FULL_REFUND, BOOKING_CANCELLED_HALF_REFUND
-from cciw.bookings.utils import camp_bookings_to_xls
+from cciw.bookings.utils import camp_bookings_to_spreadsheet
 from cciw.cciwmain.common import get_thisyear
 from cciw.cciwmain.models import Camp
 from cciw.cciwmain.tests.mailhelpers import read_email_url
 from cciw.officers.tests.references import OFFICER_USERNAME, OFFICER_PASSWORD, BOOKING_SEC_USERNAME, BOOKING_SEC_PASSWORD, BOOKING_SEC
 from cciw.sitecontent.models import HtmlChunk
+from cciw.utils.spreadsheet import ExcelFormatter
 from cciw.utils.tests.twillhelpers import TwillMixin, make_django_url
 
 
         acc = self.get_account()
         acc.bookings.update(state=BOOKING_BOOKED)
 
-        workbook = camp_bookings_to_xls(self.camp)
+        workbook = camp_bookings_to_spreadsheet(self.camp, ExcelFormatter())
         wkbk = xlrd.open_workbook(file_contents=workbook)
         wksh_all = wkbk.sheet_by_index(0)
 
         acc = self.get_account()
         acc.bookings.update(state=BOOKING_BOOKED)
 
-        workbook = camp_bookings_to_xls(self.camp)
+        workbook = camp_bookings_to_spreadsheet(self.camp, ExcelFormatter())
         wkbk = xlrd.open_workbook(file_contents=workbook)
         wksh_bdays = wkbk.sheet_by_index(2)
 

cciw/bookings/utils.py

 from dateutil.relativedelta import relativedelta
-import xlwt
 
-from cciw.utils.xl import add_sheet_with_header_row, workbook_to_string
 
-def camp_bookings_to_xls(camp):
+def camp_bookings_to_spreadsheet(camp, spreadsheet):
     bookings = list(camp.bookings.confirmed().order_by('first_name', 'last_name'))
 
-    wkbk = xlwt.Workbook(encoding='utf8')
     columns = [('First name', lambda b: b.first_name),
                ('Last name', lambda b: b.last_name),
                ('Sex', lambda b: b.get_sex_display()),
                ('Dietary requirements', lambda b: b.dietary_requirements),
                ]
 
-    wksh_campers = add_sheet_with_header_row(wkbk,
-                                             "Summary",
-                                             [n for n, f in columns],
-                                             [[f(b) for n, f in columns]
-                                              for b in bookings])
+    spreadsheet.add_sheet_with_header_row("Summary",
+                                          [n for n, f in columns],
+                                          [[f(b) for n, f in columns]
+                                           for b in bookings])
 
     medical_columns = \
         [('First name', lambda b: b.first_name),
          ('Learning difficulties', lambda b: b.learning_difficulties),
          ]
 
-    wksh_medical = add_sheet_with_header_row(wkbk,
-                                             "Medical",
-                                             [n for n, f in medical_columns],
-                                             [[f(b) for n, f in medical_columns]
-                                              for b in bookings])
+    spreadsheet.add_sheet_with_header_row("Medical",
+                                          [n for n, f in medical_columns],
+                                          [[f(b) for n, f in medical_columns]
+                                           for b in bookings])
 
     def get_birthday(b):
         start = camp.start_date
                     ]
 
 
-    wksh_bdays = add_sheet_with_header_row(wkbk,
-                                           "Birthdays on camp",
-                                           [n for n, f in bday_columns],
-                                           [[f(b) for n, f in bday_columns]
-                                            for b in bookings if
-                                            camp.start_date <= get_birthday(b) <= camp.end_date])
+    spreadsheet.add_sheet_with_header_row("Birthdays on camp",
+                                          [n for n, f in bday_columns],
+                                          [[f(b) for n, f in bday_columns]
+                                           for b in bookings if
+                                           camp.start_date <= get_birthday(b) <= camp.end_date])
 
-    return workbook_to_string(wkbk)
+    return spreadsheet.to_string()
 
 

cciw/officers/views.py

 from django.views.generic.base import TemplateView
 
 from cciw.auth import is_camp_admin, is_wiki_user, is_cciw_secretary, is_camp_officer, is_booking_secretary
-from cciw.bookings.utils import camp_bookings_to_xls
+from cciw.bookings.utils import camp_bookings_to_spreadsheet
 from cciw.cciwmain import common
 from cciw.cciwmain.decorators import json_response
 from cciw.cciwmain.models import Camp
 from cciw.officers.models import Application, Reference, ReferenceForm, Invitation, CRBApplication, CRBFormLog
 from cciw.officers.utils import camp_slacker_list, officer_data_to_xls
 from cciw.officers.references import reference_form_info
-from cciw.utils.views import close_window_response, user_passes_test_improved
+from cciw.utils.views import close_window_response, user_passes_test_improved, get_spreadsheet_formatter
 from securedownload.views import access_folder_securely
 
 
 @camp_admin_required
 def export_camper_data(request, year=None, number=None):
     camp = _get_camp_or_404(year, number)
-    response = HttpResponse(camp_bookings_to_xls(camp), mimetype="application/vnd.ms-excel")
-    response['Content-Disposition'] = ('attachment; filename=camp-%d-%d-campers.xls'
-                                       % (camp.year, camp.number))
+    formatter = get_spreadsheet_formatter(request)
+    response = HttpResponse(camp_bookings_to_spreadsheet(camp, formatter),
+                            mimetype=formatter.mimetype)
+    response['Content-Disposition'] = ('attachment; filename=camp-%d-%d-campers.%s'
+                                       % (camp.year, camp.number, formatter.file_ext))
     return response
 
 

cciw/utils/spreadsheet.py

+# Simple spreadsheet abstraction that does what we need for returning data in
+# spreadsheets, supporting .xls and .ods
+
+import xlwt
+
+from cciw.utils import xl
+
+class ExcelFormatter(object):
+    mimetype = "application/vnd.ms-excel"
+    file_ext = "xls"
+
+    def __init__(self):
+        # A formatter is only be used once, so we can create workbook here.
+        self.wkbk = xlwt.Workbook(encoding='utf8')
+
+    def add_sheet_with_header_row(self, name, headers, contents):
+        xl.add_sheet_with_header_row(self.wkbk, name, headers, contents)
+
+    def to_string(self):
+        return xl.workbook_to_string(self.wkbk)

cciw/utils/views.py

 from django.contrib.auth.views import redirect_to_login
 from django.http import HttpResponse, HttpResponseForbidden
 
+from cciw.utils.spreadsheet import ExcelFormatter
+
 
 def close_window_response():
     return HttpResponse("""<!DOCTYPE html><html><head><title>Close</title><script type="text/javascript">window.close()</script></head><body></body></html>""")
             return redirect_to_login(path, login_url, redirect_field_name)
         return _wrapped_view
     return decorator
+
+
+formatters = {'xls': ExcelFormatter}
+
+def get_spreadsheet_formatter(request):
+    format = request.GET.get('format', 'xls')
+    if format not in formatters:
+        raise Http404
+    return formatters[format]()