From e709570f2253e8f6b8fe41527ace72551a647bf4 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Tue, 31 Oct 2017 22:36:31 +0200 Subject: [PATCH] Change stuff to use excel files --- locale/en/LC_MESSAGES/django.mo | Bin 9781 -> 9233 bytes locale/en/LC_MESSAGES/django.po | 91 ++++++++++------ locale/fi/LC_MESSAGES/django.mo | Bin 15006 -> 15384 bytes locale/fi/LC_MESSAGES/django.po | 103 ++++++++++++------ members/forms.py | 6 +- members/resources.py | 26 +++++ members/static/img/excel_csv_save_example.PNG | Bin 0 -> 5882 bytes .../static/img/excel_csv_save_tutorial.PNG | Bin 0 -> 5131 bytes members/templates/application_list.html | 4 + members/templates/member_add_many.html | 41 ++++--- members/templates/member_edit.html | 2 +- members/templates/member_list.html | 2 +- members/templates/payment_list.html | 4 + members/templates/upload_form.html | 10 ++ members/urls.py | 11 +- members/views/utils.py | 56 +++++----- requirements.txt | 2 + sikweb/base.py | 8 ++ 18 files changed, 248 insertions(+), 118 deletions(-) create mode 100644 members/resources.py create mode 100644 members/static/img/excel_csv_save_example.PNG create mode 100644 members/static/img/excel_csv_save_tutorial.PNG create mode 100644 members/templates/upload_form.html diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo index ec48ec6d7a5c586861ffcf6c0127edb61ef90fa1..b66103652d23e13da5c789937e3b71d41081e22e 100644 GIT binary patch delta 3126 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 diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 3811b8f..76f0867 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-10-30 13:41+0100\n" +"POT-Creation-Date: 2017-10-31 21:09+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -201,7 +201,7 @@ msgid "Place of residence" msgstr "Place of residence" #: .\members\models.py:19 .\members\models.py:70 -#: .\members\templates\member_add_many.html:35 +#: .\members\templates\member_add_many.html:39 msgid "AYY" msgstr "AYY" @@ -225,7 +225,7 @@ msgstr "Source" msgid "Cash" msgstr "Cash" -#: .\members\models.py:72 .\members\templates\member_add_many.html:36 +#: .\members\models.py:72 .\members\templates\member_add_many.html:40 msgid "Bank transfer" msgstr "Bank transfer" @@ -284,7 +284,7 @@ msgid "Muista myös maksaa jäsenmaksusi!" msgstr "Don't forget to pay your membership fee!" #: .\members\templates\application_index.html:16 -#: .\members\templates\member_add_many.html:48 +#: .\members\templates\member_add_many.html:55 #: .\members\templates\member_add_many_confirm.html:22 #: .\webapp\templates\kaehmy_list.html:48 msgid "Send" @@ -322,48 +322,50 @@ msgstr "" msgid "" "\n" " Enter member information in CSV format, separate members on " -"separate lines.\n" +"separate lines. \n" +" If a new member already exists in the database, a new payment " +"event will be created for that member instead.\n" " " msgstr "" -#: .\members\templates\member_add_many.html:18 +#: .\members\templates\member_add_many.html:21 +msgid "Format the member table like this:" +msgstr "" + +#: .\members\templates\member_add_many.html:25 msgid "" -"\n" -" first_name, last_name, email_address and place_of_origin should " -"be given string values.\n" -" ayy_member and jas_recipient should be given the value 0 (off) " -"or 1 (on).\n" -" " +"Columns: First name, last name, email address, place of origin, AYY member, " +"JAS recipient" msgstr "" -"\n" -" first_name, last_name, email_address and place_of_origin should " -"be given string values.\n" -" ayy_member and jas_recipient should be given the value 0 (off) " -"or 1 (on).\n" -" " -#: .\members\templates\member_add_many.html:23 -msgid "Syntax" -msgstr "Syntax" - -#: .\members\templates\member_add_many.html:29 -msgid "Data" +#: .\members\templates\member_add_many.html:28 +msgid "Save the file as CSV" msgstr "" #: .\members\templates\member_add_many.html:33 -msgid "Payment source" +msgid "Upload file" msgstr "" #: .\members\templates\member_add_many.html:37 -msgid "Cash payment" +msgid "Payment source" msgstr "" #: .\members\templates\member_add_many.html:41 -msgid "CSV delimiter" +msgid "Cash payment" msgstr "" #: .\members\templates\member_add_many.html:44 msgid "" +"This payment source will be used to create any payments for new members that " +"already exist in the database." +msgstr "" + +#: .\members\templates\member_add_many.html:48 +msgid "CSV delimiter" +msgstr "" + +#: .\members\templates\member_add_many.html:51 +msgid "" "The symbol that is used to separate items in one line. Defaults to " "';' (semicolon)." msgstr "" @@ -469,11 +471,11 @@ msgstr "Member register" msgid "Language" msgstr "Language" -#: .\members\templates\settings.html:20 .\sikweb\base.py:222 +#: .\members\templates\settings.html:20 .\sikweb\base.py:226 msgid "Finnish" msgstr "Finnish" -#: .\members\templates\settings.html:21 .\sikweb\base.py:223 +#: .\members\templates\settings.html:21 .\sikweb\base.py:227 msgid "English" msgstr "English" @@ -560,9 +562,9 @@ msgstr "Successfully updated payment" msgid "Could not update payment object" msgstr "Could not update payment object" -#: .\members\views\utils.py:117 -msgid "Missing \"textfield\" POST request field" -msgstr "Missing \"textfield\" POST request field" +#: .\members\views\utils.py:121 +msgid "Missing CSV file" +msgstr "" #: .\templates\admin\base_site.html:43 msgid "Go" @@ -576,7 +578,7 @@ msgstr "Error" msgid "Back" msgstr "Back" -#: .\templates\footer.html:23 +#: .\templates\footer.html:23 .\webapp\templates\kaehmy_footer.html:23 msgid "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" @@ -850,7 +852,7 @@ msgstr "" msgid "SIK Admin" msgstr "SIK Admin" -#: .\webapp\templates\base.html:15 +#: .\webapp\templates\base.html:15 .\webapp\templates\kaehmy_base.html:14 msgid "Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Aalto-yliopiston Sähköinsinöörikilta ry" @@ -1047,5 +1049,26 @@ msgstr "All challenges" msgid "Total challenges:" msgstr "Total challenges:" +#~ msgid "" +#~ "\n" +#~ " first_name, last_name, email_address and place_of_origin " +#~ "should be given string values.\n" +#~ " ayy_member and jas_recipient should be given the value 0 " +#~ "(off) or 1 (on).\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " first_name, last_name, email_address and place_of_origin " +#~ "should be given string values.\n" +#~ " ayy_member and jas_recipient should be given the value 0 " +#~ "(off) or 1 (on).\n" +#~ " " + +#~ msgid "Syntax" +#~ msgstr "Syntax" + +#~ msgid "Missing \"textfield\" POST request field" +#~ msgstr "Missing \"textfield\" POST request field" + #~ msgid "Options" #~ msgstr "Options" diff --git a/locale/fi/LC_MESSAGES/django.mo b/locale/fi/LC_MESSAGES/django.mo index a1860c533edaa77dbc4df160d85f49191ebe7178..9b35184b851d2ef78884cdbada802a4a676b5b67 100644 GIT binary patch delta 5906 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 XQ?hm~4W$dS&f~2)F_xCSrEmNf4;>or delta 5529 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 E2VaX_h5!Hn literal 0 HcmV?d00001 diff --git a/members/static/img/excel_csv_save_tutorial.PNG b/members/static/img/excel_csv_save_tutorial.PNG new file mode 100644 index 0000000000000000000000000000000000000000..1cc02322f40fda289bf9ba4b97d21ad6f0fda652 GIT binary patch literal 5131 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 V3LnxvZlMfdb>8+I@+>&{zX0H+z`+0j literal 0 HcmV?d00001 diff --git a/members/templates/application_list.html b/members/templates/application_list.html index 0fee6ad..ae22bcf 100644 --- a/members/templates/application_list.html +++ b/members/templates/application_list.html @@ -15,6 +15,10 @@ {% endif %} {{ table|safe }} + + {% endblock content %} diff --git a/members/templates/member_add_many.html b/members/templates/member_add_many.html index 148b1b4..15a2c85 100644 --- a/members/templates/member_add_many.html +++ b/members/templates/member_add_many.html @@ -1,7 +1,7 @@ {% extends "members_base.html" %} {% load i18n %} - +{% load static %} {% block content %}
@@ -11,24 +11,28 @@

{% blocktrans %} - Enter member information in CSV format, separate members on separate lines. + Enter member information in CSV format, separate members on separate lines. + If a new member already exists in the database, a new payment event will be created for that member instead. {% endblocktrans %}

-

- {% blocktrans %} - first_name, last_name, email_address and place_of_origin should be given string values. - ayy_member and jas_recipient should be given the value 0 (off) or 1 (on). - {% endblocktrans %} -

-

{% trans "Syntax" %}

-
first_name, last_name, email_address, place_of_origin, ayy_member, jas_recipient
-
-
{% csrf_token %} -
- - + +
+ +
+
+

{% blocktrans %}Columns: First name, last name, email address, place of origin, AYY member, JAS recipient{% endblocktrans %}

+
+
+ +
+
+ + {% csrf_token %} +

{% trans "Upload file" %}

+ +
+ + {% trans "This payment source will be used to create any payments for new members that already exist in the database." %} +
-

+ {% blocktrans %}The symbol that is used to separate items in one line. Defaults to ';' (semicolon).{% endblocktrans %} -

+
diff --git a/members/templates/member_edit.html b/members/templates/member_edit.html index 4f2c7ea..c8ef05c 100644 --- a/members/templates/member_edit.html +++ b/members/templates/member_edit.html @@ -1,7 +1,7 @@ {% extends "members_base.html" %} {% load i18n %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %}
diff --git a/members/templates/member_list.html b/members/templates/member_list.html index 9c0eb80..2dc38f8 100644 --- a/members/templates/member_list.html +++ b/members/templates/member_list.html @@ -41,7 +41,7 @@ {{ table|safe }}
{% endblock content %} diff --git a/members/templates/payment_list.html b/members/templates/payment_list.html index 1665f0a..bce2421 100644 --- a/members/templates/payment_list.html +++ b/members/templates/payment_list.html @@ -36,5 +36,9 @@ {% endif %} {{ table|safe }} + +
{% endblock content %} diff --git a/members/templates/upload_form.html b/members/templates/upload_form.html new file mode 100644 index 0000000..b028b1d --- /dev/null +++ b/members/templates/upload_form.html @@ -0,0 +1,10 @@ +{% extends "members_base.html" %} + +{% block content %} +

{{ title }}

+

{{ header }}

+{% csrf_token %} + {{ form }} + + +{% endblock %} \ No newline at end of file diff --git a/members/urls.py b/members/urls.py index 4988f5d..707571e 100644 --- a/members/urls.py +++ b/members/urls.py @@ -7,7 +7,7 @@ from django.views.generic.base import RedirectView # members from members.views import member_list, payment_add, payment_submit from members.views import application_delete_confirm, application_delete -from members.views import application_accept, import_csv, export_csv +from members.views import application_accept, import_csv from members.views import settings_page, payment_edit from members.views import payment_delete_confirm from members.views import payment_delete, payment_update @@ -20,6 +20,9 @@ from members.views import member_delete_confirm from members.views import member_delete from members.views import payment_list from members.views import add_many_confirm +from members.views import export_members_excel +from members.views import export_payments_excel +from members.views import export_applications_excel # autocomplete view from members.views import MemberAutoComplete @@ -108,8 +111,10 @@ urlpatterns = [ # send CSV member data by POST url(r'^import_csv', import_csv), - # download CSV member data - url(r'^export_csv', export_csv), + # export members as excel file + url(r'export_members', export_members_excel), + url(r'export_payments', export_payments_excel), + url(r'export_applications', export_applications_excel), # favourite icon url(r'^favicon\.ico$', favicon_view), diff --git a/members/views/utils.py b/members/views/utils.py index 83727a6..6223cba 100644 --- a/members/views/utils.py +++ b/members/views/utils.py @@ -2,7 +2,7 @@ from django.shortcuts import render from django.contrib.auth.decorators import permission_required, login_required from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest from django.core.mail import send_mail from django.conf import settings from django.utils.translation import ugettext as _ @@ -20,8 +20,9 @@ from rest_framework import generics from rest_framework import permissions from members.models import Member, Request, Payment -from members.forms import MemberForm, PaymentForm, ApplicationForm, CSVValidationError +from members.forms import MemberForm, PaymentForm, ApplicationForm, CSVValidationError, UploadFileForm from members.tables import MemberTable, PaymentTable, RequestTable +from members.resources import MemberResource, PaymentResource, ApplicationResource # Can be used to retrieve single member information via REST API @@ -108,13 +109,16 @@ def settings_page(request, *args, **kwargs): def import_csv(request, *args, **kwargs): """Get csv data imported to page and create members based on that.""" try: - data = request.POST['textfield'] + csv_in_memory_file = request.FILES.get('csvFile') + csv_file = csv_in_memory_file.file + data = csv_file.read().decode('utf-8') + delimiter = request.POST.get('delimiter', ',') payment_source = request.POST['payment_source'] except: return render(request, 'error.html', - {'error': _('Missing "textfield" POST request field')}) + {'error': _('Missing CSV file')}) try: result = MemberForm.csv_to_models(data, payment_source=payment_source, delimiter=delimiter) @@ -149,27 +153,6 @@ def import_csv(request, *args, **kwargs): return render(request, 'member_add_many_confirm.html', context) -@ensure_csrf_cookie -@require_http_methods(["GET"]) -@permission_required('members.read_member', login_url='/login', raise_exception=True) -def export_csv(request, *args, **kwargs): - """Export members as csv.""" - response = HttpResponse() - response['Content-type'] = 'text/csv' - response['Accept'] = 'text/csv' - response['Content-Disposition'] = 'filename; filename=members.csv' - writer = csv.writer(response, csv.excel) - # BOM (optional...Excel needs it to open UTF-8 file properly) - response.write(u'\ufeff'.encode('utf8')) - for obj in Member.objects.all(): - data = obj.as_array() - field_list = list(map(lambda d: str(d), data)) - - writer.writerow(field_list) - - return response - - def send_mail_wrapper(subject, message, email_to): """Send mail to default email.""" send_mail(subject, @@ -177,3 +160,26 @@ def send_mail_wrapper(subject, message, email_to): settings.DEFAULT_EMAIL_FROM, [email_to], fail_silently=False) + + +def make_excel_response(Resource): + res = Resource() + dataset = res.export() + response = HttpResponse(dataset.xlsx, content_type='application/vnd.ms-excel; charset=utf-8') + response['Content-Disposition'] = 'attachment; filename="export.xlsx"' + return response + + +@require_http_methods(['GET']) +def export_members_excel(request, *args, **kwargs): + return make_excel_response(MemberResource) + + +@require_http_methods(['GET']) +def export_payments_excel(request, *args, **kwargs): + return make_excel_response(PaymentResource) + + +@require_http_methods(['GET']) +def export_applications_excel(request, *args, **kwargs): + return make_excel_response(ApplicationResource) diff --git a/requirements.txt b/requirements.txt index bc58902..925b4f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,3 +30,5 @@ django-autocomplete-light==3.2.10 six==1.10.0 django-suit==0.2.25 telepot==12.3 +django-excel==0.0.9 +pyexcel-xls==0.5.2 \ No newline at end of file diff --git a/sikweb/base.py b/sikweb/base.py index c094344..b761136 100644 --- a/sikweb/base.py +++ b/sikweb/base.py @@ -82,11 +82,15 @@ INSTALLED_APPS = [ 'rest_framework', 'django_nose', 'bootstrap3', + 'bootstrap4', 'django_tables2', 'auditlog', 'phonenumber_field', + 'import_export', ] +IMPORT_EXPORT_USE_TRANSACTIONS = True + TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' NOSE_ARGS = [ @@ -255,6 +259,10 @@ MEDIA_URL = '/media/' LOGIN_URL = '/login/' LOGIN_REDIRECT_URL = '/admin' +# for django-excel +FILE_UPLOAD_HANDLERS = ("django_excel.ExcelMemoryFileUploadHandler", + "django_excel.TemporaryExcelFileUploadHandler") + SUIT_CONFIG = { # header 'ADMIN_NAME': 'SIK Admin',