diff --git a/.gitignore b/.gitignore index 5f846bdc44dc42490d2b3c88d19b3dc0f50533e3..9eca034d61d74660f3cb2fe12292148b84f5e15c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ smash/~/ # Disable python bytecode *.pyc +#vim swap files +*.swp +#vim backup files +*~ # Disable local developer settings local_settings.py diff --git a/requirements.txt b/requirements.txt index fa5a7c14be038ab020a18cf2c7e4201737d76b11..67644e195dd3578eaeba9c357afff56d394170f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,8 @@ python-docx==0.8.6 django-cleanup==0.4.2 django_cron==0.5.0 django-two-factor-auth==1.6.1 -nexmo \ No newline at end of file +nexmo +django-excel==0.0.9 +pyexcel-xls==0.5.0 +pyexcel==0.5.3 + diff --git a/smash/web/static/css/export.css b/smash/web/static/css/export.css new file mode 100644 index 0000000000000000000000000000000000000000..ffab23233d813aab070b92753890709a998839ed --- /dev/null +++ b/smash/web/static/css/export.css @@ -0,0 +1,9 @@ +.cell { + display: table-cell; + border-bottom: 1px solid black; + border: 1px solid #BBBBBB; + padding:4px; + text-align: center; + vertical-align: middle; + +} diff --git a/smash/web/templates/export/index.html b/smash/web/templates/export/index.html index 8c0501149511bc3e7704588e508de4128629503f..a4e8aef298bbe802d4997a9f54f325ca03b8d0c5 100644 --- a/smash/web/templates/export/index.html +++ b/smash/web/templates/export/index.html @@ -3,6 +3,7 @@ {% block styles %} {{ block.super }} + <link rel="stylesheet" href="{% static 'css/export.css' %}"> {% endblock styles %} {% block ui_active_tab %}'export'{% endblock ui_active_tab %} @@ -18,15 +19,21 @@ {% block maincontent %} <div> - <a href="{% url 'web.views.export_to_csv' 'subjects' %}" class="btn btn-app"> - <i class="fa fa-download"></i> - Subjects - </a> - <br/> - <a href="{% url 'web.views.export_to_csv' 'appointments' %}" class="btn btn-app"> - <i class="fa fa-download"></i> - Appointments - </a> + <h3>Subjects</h3> + <ul> + <li><a href="{% url 'web.views.export_to_excel' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS - + Excel</a> + </li> + <li><a href="{% url 'web.views.export_to_excel' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV - + Text based</a></li> + </ul> + <h3>Appointments</h3> + <ul> + <li><a href="{% url 'web.views.export_to_csv' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS - + Excel</a></li> + <li><a href="{% url 'web.views.export_to_csv' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV - + Text based</a></li> + </ul> </div> <div class="box-body"> diff --git a/smash/web/templates/visits/add.html b/smash/web/templates/visits/add.html index 9e03dbec7d16943bfdcbca5cb129b6f1f25d76d4..749641be57b7d9c1e4160a5d7457fff0cbfa5fed 100644 --- a/smash/web/templates/visits/add.html +++ b/smash/web/templates/visits/add.html @@ -25,12 +25,6 @@ <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a> </div> - {% comment %} - <div class="box-header with-border"> - <h3 class="box-title">Details of a visit</h3> - </div> - {% endcomment %} - <form method="post" action="" class="form-horizontal"> {% csrf_token %} diff --git a/smash/web/tests/test_view_export.py b/smash/web/tests/test_view_export.py index 1fc16657a5eb6e098f98869f2ca881c9e2d6ac14..f15c2cf439a9012999ff91ef88a9fc1e928a0679 100644 --- a/smash/web/tests/test_view_export.py +++ b/smash/web/tests/test_view_export.py @@ -6,12 +6,22 @@ from . import LoggedInTestCase class TestExportView(LoggedInTestCase): - def test_export_subjects(self): + def test_export_subjects_to_csv(self): create_subject() response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "subjects"})) self.assertEqual(response.status_code, 200) - def test_export_appointments(self): + def test_export_appointments_to_csv(self): create_appointment() response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "appointments"})) self.assertEqual(response.status_code, 200) + + def test_export_subjects_to_excel(self): + create_subject() + response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "subjects"})) + self.assertEqual(response.status_code, 200) + + def test_export_appointments_to_excel(self): + create_appointment() + response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "appointments"})) + self.assertEqual(response.status_code, 200) diff --git a/smash/web/urls.py b/smash/web/urls.py index c19857fc45b4fee3f2623fa800390c1d204c1025..a2e1a0191019f89ae7f1db70d641c63c9e2fe171 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -160,7 +160,8 @@ urlpatterns = [ #################### url(r'^export$', views.export.export, name='web.views.export'), - url(r'^export/(?P<data_type>[A-z]+)$', views.export.export_to_csv, name='web.views.export_to_csv'), + url(r'^export/csv/(?P<data_type>[A-z]+)$', views.export.export_to_csv, name='web.views.export_to_csv'), + url(r'^export/xls/(?P<data_type>[A-z]+)$', views.export.export_to_excel, name='web.views.export_to_excel'), #################### # CONFIGURATION # diff --git a/smash/web/views/export.py b/smash/web/views/export.py index e5a250536e5d39f6e5c38ddc77623011de253d53..359386c2552b4bd0c7e8afd46bb2353beba5917e 100644 --- a/smash/web/views/export.py +++ b/smash/web/views/export.py @@ -1,6 +1,7 @@ # coding=utf-8 import csv +import django_excel as excel from django.contrib.auth.decorators import login_required from django.http import HttpResponse @@ -24,7 +25,23 @@ def export_to_csv(request, data_type="subjects"): return e500_error(request) writer = csv.writer(response, quotechar=str(u'"'), quoting=csv.QUOTE_ALL) for row in data: - writer.writerow(row) + writer.writerow([s.encode("utf-8") for s in row]) + + return response + + +@login_required +def export_to_excel(request, data_type="subjects"): + filename = data_type + '-' + get_today_midnight_date().strftime("%Y-%m-%d") + ".xls" + if data_type == "subjects": + data = get_subjects_as_array() + elif data_type == "appointments": + data = get_appointments_as_array() + else: + return e500_error(request) + + response = excel.make_response_from_array(data, 'xls', file_name=filename) + response['Content-Disposition'] = 'attachment; filename="' + filename + '"' return response @@ -46,8 +63,11 @@ def get_subjects_as_array(): for subject in subjects: row = [] for field in subject_fields: - row.append(getattr(subject, field.name)) - result.append([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) + cell = getattr(subject, field.name) + if cell is None: + cell = "" + row.append(cell) + result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row]) return result @@ -69,15 +89,18 @@ def get_appointments_as_array(): appointments = Appointment.objects.order_by('-datetime_when') for appointment in appointments: - row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name, - appointment.visit.subject.first_name, appointment.visit.follow_up_title()] + if appointment.visit is not None: + row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name, + appointment.visit.subject.first_name, appointment.visit.follow_up_title()] + else: + row = ["---", "---", "---", "---"] for field in appointments_fields: row.append(getattr(appointment, field.name)) type_string = "" for appointment_type in appointment.appointment_types.all(): type_string += appointment_type.code + "," row.append(type_string) - result.append([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) + result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row]) return result