Change stuff to use excel files

This commit is contained in:
Jan Tuomi
2017-10-31 22:36:31 +02:00
parent 0e3e117f25
commit e709570f22
18 changed files with 248 additions and 118 deletions
Binary file not shown.
+56 -33
View File
@@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"
@@ -323,47 +323,49 @@ msgid ""
"\n"
" Enter member information in CSV format, separate members on "
"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"
Binary file not shown.
+66 -35
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-30 13:41+0100\n"
"PO-Revision-Date: 2017-10-30 14:42+0200\n"
"POT-Creation-Date: 2017-10-31 21:09+0100\n"
"PO-Revision-Date: 2017-10-31 22:11+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fi\n"
@@ -202,7 +202,7 @@ msgid "Place of residence"
msgstr "Asuinpaikka"
#: .\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"
@@ -226,7 +226,7 @@ msgstr "Lähde"
msgid "Cash"
msgstr "Käteinen"
#: .\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 "Tilisiirto"
@@ -283,7 +283,7 @@ msgid "Muista myös maksaa jäsenmaksusi!"
msgstr "Muista myös maksaa jäsenmaksusi!"
#: .\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,49 +322,57 @@ msgid ""
"\n"
" Enter member information in CSV format, separate members on "
"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 ""
"\n"
" Syötä jäsentiedot CSV-formaatissa, erilliset jäsenet omilla "
"riveillään.\n"
" "
" Jos jäsenen tiedot ovat jo tietokannassa, tehdään tälle "
"jäsenelle uusi maksutapahtuma."
#: .\members\templates\member_add_many.html:18
#: .\members\templates\member_add_many.html:21
msgid "Format the member table like this:"
msgstr "Jäsentele taulukko seuraavasti:"
#: .\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 ja place_of_origin ovat "
"merkkijonoja.\n"
" ayy_member ja jas_recipient ovat joko 0 (off) tai 1 (on).\n"
" "
"Kolumnit: Etunimi, sukunimi, sähköpostiosoite, asuinpaikka, AYY:n jäsen, "
"jäsenmailin vastaanottaja"
#: .\members\templates\member_add_many.html:23
msgid "Syntax"
msgstr "Syntaksi"
#: .\members\templates\member_add_many.html:29
msgid "Data"
msgstr "Data"
#: .\members\templates\member_add_many.html:28
msgid "Save the file as CSV"
msgstr "Tallenna tiedosto CSV-formaatissa"
#: .\members\templates\member_add_many.html:33
msgid "Upload file"
msgstr "Lataa tiedosto"
#: .\members\templates\member_add_many.html:37
msgid "Payment source"
msgstr "Maksutapa"
#: .\members\templates\member_add_many.html:37
#: .\members\templates\member_add_many.html:41
msgid "Cash payment"
msgstr "Käteismaksu"
#: .\members\templates\member_add_many.html:41
#: .\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 ""
"Tätä maksutapaa käytetään, kun jo tietokannassa oleville jäsenille luodaan "
"maksutapahtuma."
#: .\members\templates\member_add_many.html:48
msgid "CSV delimiter"
msgstr "CSV-erotin"
#: .\members\templates\member_add_many.html:44
#: .\members\templates\member_add_many.html:51
msgid ""
"The symbol that is used to separate items in one line. Defaults to "
"';' (semicolon)."
@@ -470,11 +478,11 @@ msgstr "Maksutapahtumia:"
msgid "Language"
msgstr "Kieli"
#: .\members\templates\settings.html:20 .\sikweb\base.py:222
#: .\members\templates\settings.html:20 .\sikweb\base.py:226
msgid "Finnish"
msgstr "suomi"
#: .\members\templates\settings.html:21 .\sikweb\base.py:223
#: .\members\templates\settings.html:21 .\sikweb\base.py:227
msgid "English"
msgstr "englanti"
@@ -561,9 +569,9 @@ msgstr "Onnistuneesti päivitettiin maksutapahtuma"
msgid "Could not update payment object"
msgstr "Maksutapahtumaobjektia ei voitu päivittää"
#: .\members\views\utils.py:117
msgid "Missing \"textfield\" POST request field"
msgstr "Puuttuva \"textfield\" POST-kenttä"
#: .\members\views\utils.py:121
msgid "Missing CSV file"
msgstr "Puuttuva CSV-tiedosto"
#: .\templates\admin\base_site.html:43
msgid "Go"
@@ -577,7 +585,7 @@ msgstr "Virhe"
msgid "Back"
msgstr "Takaisin"
#: .\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"
@@ -831,7 +839,7 @@ msgstr "Telegram-kanavat"
msgid "SIK Admin"
msgstr "SIK Hallintapaneeli"
#: .\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"
@@ -1023,5 +1031,28 @@ msgstr "Kaikki haasteet"
msgid "Total challenges:"
msgstr "Haasteita yhteensä:"
#~ 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 ja place_of_origin ovat "
#~ "merkkijonoja.\n"
#~ " ayy_member ja jas_recipient ovat joko 0 (off) tai 1 (on).\n"
#~ " "
#~ msgid "Syntax"
#~ msgstr "Syntaksi"
#~ msgid "Data"
#~ msgstr "Data"
#~ msgid "Missing \"textfield\" POST request field"
#~ msgstr "Puuttuva \"textfield\" POST-kenttä"
#~ msgid "Applied for board"
#~ msgstr "Hakenut hallitukseen"
+5 -1
View File
@@ -46,7 +46,7 @@ class MemberForm(forms.ModelForm):
@staticmethod
def csv_to_models(data, payment_source='AYY', delimiter=','):
clean_data = data.strip().split('\n')
clean_data = [row.rstrip(',') for row in clean_data]
clean_data = [row.rstrip(',').rstrip('\r').strip() for row in clean_data]
csv_reader = csv.DictReader(clean_data, fieldnames=MemberForm.Meta.fields, delimiter=delimiter, quoting=csv.QUOTE_NONE)
members = []
@@ -122,3 +122,7 @@ class ApplicationForm(forms.ModelForm):
self.fields['AYY'].label = _("I'm a member of AYY")
self.fields['jas'].label = _("I want to receive a weekly newsletter")
class UploadFileForm(forms.Form):
file = forms.FileField()
+26
View File
@@ -0,0 +1,26 @@
from import_export import resources
from .models import Member, Payment, Request
class MemberResource(resources.ModelResource):
class Meta:
model = Member
exclude = ['id', 'created']
class PaymentResource(resources.ModelResource):
member = resources.Field()
class Meta:
model = Payment
exclude = ['id']
def dehydrate_member(self, payment):
return '{} {}'.format(payment.member.first_name, payment.member.last_name)
class ApplicationResource(resources.ModelResource):
class Meta:
model = Request
exclude = ['id']
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

+4
View File
@@ -15,6 +15,10 @@
{% endif %}
{{ table|safe }}
<div>
<a href="/members/export_applications" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
{% endblock content %}
+22 -15
View File
@@ -1,7 +1,7 @@
{% extends "members_base.html" %}
{% load i18n %}
{% load static %}
{% block content %}
<div>
<div>
@@ -12,23 +12,27 @@
<p>
{% blocktrans %}
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 %}
</p>
<p>
{% 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 %}
</p>
<h4>{% trans "Syntax" %}</h4>
<pre>first_name, last_name, email_address, place_of_origin, ayy_member, jas_recipient</pre>
</div>
<div>
<label>{% trans "Format the member table like this:" %}</label>
<div>
<img src="{% static "img/excel_csv_save_example.png" %}">
</div>
<form name="memberTextForm" action="/members/import_csv" method="POST">{% csrf_token %}
<div class="form-group">
<label>{% trans "Data" %}</label>
<textarea name="textfield" class="form-control large-textarea" placeholder="Teemu, Teekkari, teemu.teekkari@notmail.dom, Otaniemi, 0, 0"></textarea>
<p>{% blocktrans %}Columns: First name, last name, email address, place of origin, AYY member, JAS recipient{% endblocktrans %}</p>
</div>
<div>
<label>{% trans "Save the file as CSV" %}</label>
<div><img src="{% static "img/excel_csv_save_tutorial.png" %}"></div>
</div>
<form name="memberTextForm" action="/members/import_csv" enctype="multipart/form-data" method="POST">{% csrf_token %}
<h3>{% trans "Upload file" %}</h3>
<input class="form-control-file" type="file" name="csvFile" />
<div class="form-group">
<label>{% trans "Payment source" %}</label>
<select name="payment_source" class="form-control">
@@ -36,13 +40,16 @@
<option value="bank_transfer">{% trans "Bank transfer" %}</option>
<option value="cash">{% trans "Cash payment" %}</option>
</select>
<small class="form-text text-muted">
{% trans "This payment source will be used to create any payments for new members that already exist in the database." %}
</small>
</div>
<div class="form-group">
<label>{% trans "CSV delimiter" %}</label>
<input type="text" name="delimiter" class="form-control" value=";" />
<p class="form-text text-muted">
<small class="form-text text-muted">
{% blocktrans %}The symbol that is used to separate items in one line. Defaults to ';' (semicolon).{% endblocktrans %}
</p>
</small>
</div>
<div>
<button type="submit" class="btn btn-primary">{% trans "Send" %}</button>
+1 -1
View File
@@ -1,7 +1,7 @@
{% extends "members_base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load bootstrap4 %}
{% block content %}
<div>
+1 -1
View File
@@ -41,7 +41,7 @@
{{ table|safe }}
<div>
<a href="/members/export_csv" class="btn btn-info">{% trans "Download CSV" %}</a>
<a href="/members/export_members" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
{% endblock content %}
+4
View File
@@ -36,5 +36,9 @@
{% endif %}
{{ table|safe }}
<div>
<a href="/members/export_payments" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
{% endblock content %}
+10
View File
@@ -0,0 +1,10 @@
{% extends "members_base.html" %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ header }}</h3>
<form method="POST" action="/members/import_excel" enctype="multipart/form-data">{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary">
</form>
{% endblock %}
+8 -3
View File
@@ -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),
+31 -25
View File
@@ -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)
+2
View File
@@ -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
+8
View File
@@ -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',