diff --git a/smash/web/api_urls.py b/smash/web/api_urls.py index 56f9dc4f46cbac9ca9c7ab622abd000aadbe9aa5..372aa370c6f24960f3122b1c18b24e8494fac9a0 100644 --- a/smash/web/api_urls.py +++ b/smash/web/api_urls.py @@ -16,7 +16,7 @@ Including another URLconf from django.conf.urls import url from web.api_views import worker, location, subject, appointment_type, appointment, configuration, daily_planning, \ - redcap, flying_team, visit + redcap, flying_team, visit, voucher, voucher_type urlpatterns = [ # appointments @@ -53,8 +53,14 @@ urlpatterns = [ # worker data url(r'^specializations$', worker.specializations, name='web.api.specializations'), url(r'^units$', worker.units, name='web.api.units'), - url(r'^workers$', worker.workers_for_daily_planning, name='web.api.workers'), - url(r'^workers/availabilities$', worker.availabilities, name='web.api.workers.availabilities$'), + + # workers + url(r'^workers/(?P<worker_role>[A-z]+)/$', worker.get_workers, name='web.api.workers'), + + # daily planning data + url(r'^daily_planning/workers/$', worker.workers_for_daily_planning, name='web.api.workers.daily_planning'), + url(r'^daily_planning/workers/availabilities$', worker.availabilities, + name='web.api.workers.daily_planning.availabilities$'), # daily planning events url(r'^events/(?P<date>\d{4}-\d{2}-\d{2})/$', daily_planning.events, name='web.api.events'), @@ -67,4 +73,14 @@ urlpatterns = [ url(r'^redcap/missing_subjects/(?P<missing_subject_id>\d+):unignore$', redcap.unignore_missing_subject, name='web.api.redcap.unignore_missing_subject'), + # vouchers data + url(r'^vouchers/$', voucher.get_vouchers, name='web.api.vouchers'), + url(r'^vouchers:columns$', voucher.get_voucher_columns, + name='web.api.vouchers.columns'), + + # voucher types data + url(r'^voucher_types/$', voucher_type.get_voucher_types, name='web.api.voucher_types'), + url(r'^vouchers:columns$', voucher.get_voucher_columns, + name='web.api.vouchers.columns'), + ] diff --git a/smash/web/api_views/voucher.py b/smash/web/api_views/voucher.py new file mode 100644 index 0000000000000000000000000000000000000000..424bf086c60840e7166d793a4099f97b63ceae3f --- /dev/null +++ b/smash/web/api_views/voucher.py @@ -0,0 +1,137 @@ +import logging + +from django.http import JsonResponse + +from web.api_views.serialization_utils import get_filters_for_data_table_request, add_column, \ + serialize_date +from web.models import Voucher + +logger = logging.getLogger(__name__) + + +def get_vouchers_order(vouchers_to_be_ordered, order_column, order_direction): + result = vouchers_to_be_ordered + if order_direction == "asc": + order_direction = "" + else: + order_direction = "-" + if order_column == "first_name": + result = vouchers_to_be_ordered.order_by(order_direction + 'study_subject__subject__first_name') + elif order_column == "last_name": + result = vouchers_to_be_ordered.order_by(order_direction + 'study_subject__subject__last_name') + elif order_column == "number": + result = vouchers_to_be_ordered.order_by(order_direction + 'number') + elif order_column == "expiry_date": + result = vouchers_to_be_ordered.order_by(order_direction + 'expiry_date') + elif order_column == "issue_date": + result = vouchers_to_be_ordered.order_by(order_direction + 'issue_date') + elif order_column == "id": + result = vouchers_to_be_ordered.order_by(order_direction + 'id') + elif order_column == "type": + result = vouchers_to_be_ordered.order_by(order_direction + 'voucher_type__code') + elif order_column == "status": + result = vouchers_to_be_ordered.order_by(order_direction + 'status') + else: + logger.warn("Unknown sort column: " + str(order_column)) + return result + + +def get_vouchers_filtered(vouchers_to_be_filtered, filters): + result = vouchers_to_be_filtered + for row in filters: + column = row[0] + value = row[1] + if column == "first_name": + result = result.filter(study_subject__subject__first_name__icontains=value) + elif column == "last_name": + result = result.filter(study_subject__subject__last_name__icontains=value) + elif column == "number": + result = result.filter(number__icontains=value) + elif column == "type": + result = result.filter(voucher_type=value) + elif column == "status": + result = result.filter(status=value) + elif column == "voucher_partner": + result = result.filter(usage_partner=value) + elif column == "feedback": + result = result.filter(feedback__icontains=value) + elif column == "": + pass + else: + message = "UNKNOWN filter: " + if column is None: + message += "[None]" + else: + message += str(column) + logger.warn(message) + return result + + +# noinspection PyUnusedLocal +def get_voucher_columns(request): + result = [] + add_column(result, "First name", "first_name", None, "string_filter") + add_column(result, "Last name", "last_name", None, "string_filter") + add_column(result, "Number", "number", None, "string_filter") + add_column(result, "Type", "type", None, "voucher_type_filter") + add_column(result, "Status", "status", None, "voucher_status_filter") + add_column(result, "Voucher partner", "voucher_partner", None, "voucher_partner_filter") + add_column(result, "Issue date", "issue_date", None, None) + add_column(result, "Expiry date", "expiry_date", None, None) + add_column(result, "Edit", "edit", None, None, sortable=False) + + return JsonResponse({"columns": result}) + + +def get_vouchers(request): + # id of the query from dataTable: https://datatables.net/manual/server-side + draw = int(request.GET.get("draw", "-1")) + + start = int(request.GET.get("start", "0")) + length = int(request.GET.get("length", "10")) + order = int(request.GET.get("order[0][column]", "0")) + order_dir = request.GET.get("order[0][dir]", "asc") + order_column = request.GET.get("columns[" + str(order) + "][data]", "last_name") + + filters = get_filters_for_data_table_request(request) + + all_vouchers = Voucher.objects.all() + + count = all_vouchers.count() + + ordered_vouchers = get_vouchers_order(all_vouchers, order_column, order_dir) + filtered_vouchers = get_vouchers_filtered(ordered_vouchers, filters) + sliced_vouchers = filtered_vouchers[start:(start + length)] + + result_vouchers = sliced_vouchers + + count_filtered = filtered_vouchers.count() + + data = [] + for voucher in result_vouchers: + data.append(serialize_voucher(voucher)) + + return JsonResponse({ + "draw": draw, + "recordsTotal": count, + "recordsFiltered": count_filtered, + "data": data, + }) + + +def serialize_voucher(voucher): + issue_date = serialize_date(voucher.issue_date) + expiry_date = serialize_date(voucher.expiry_date) + result = { + "first_name": voucher.study_subject.subject.first_name, + "last_name": voucher.study_subject.subject.last_name, + "issue_date": issue_date, + "type": voucher.voucher_type.code, + "status": str(voucher.status), + "voucher_partner": str(voucher.usage_partner), + "feedback": voucher.feedback, + "expiry_date": expiry_date, + "number": voucher.number, + "id": voucher.id, + } + return result diff --git a/smash/web/api_views/voucher_type.py b/smash/web/api_views/voucher_type.py new file mode 100644 index 0000000000000000000000000000000000000000..8cf1c18f3ad80b8fa1bec409f9194d95d4f54823 --- /dev/null +++ b/smash/web/api_views/voucher_type.py @@ -0,0 +1,32 @@ +import logging + +from django.http import JsonResponse + +from web.models import VoucherType + +logger = logging.getLogger(__name__) + + +def get_voucher_types(request): + all_vouchers = VoucherType.objects.all() + + count = all_vouchers.count() + + data = [] + for voucher_type in all_vouchers: + data.append(serialize_voucher_type(voucher_type)) + + return JsonResponse({ + "recordsTotal": count, + "recordsFiltered": count, + "data": data, + }) + + +def serialize_voucher_type(voucher_type): + result = { + "code": voucher_type.code, + "description": voucher_type.description, + "id": voucher_type.id, + } + return result diff --git a/smash/web/api_views/worker.py b/smash/web/api_views/worker.py index bdf249541b8f3ac637b1ca4b35e332806cc7c782..881f15287d969ffaea7a1fb6b58fdb1f23ca78ca 100644 --- a/smash/web/api_views/worker.py +++ b/smash/web/api_views/worker.py @@ -61,3 +61,27 @@ def availabilities(request): return JsonResponse({ "availabilities": result, }) + + +def get_workers(request, worker_role): + all_workers = Worker.get_workers_by_worker_type(worker_role).distinct() + count = all_workers.count() + + data = [] + for voucher_type in all_workers: + data.append(serialize_worker(voucher_type)) + + return JsonResponse({ + "recordsTotal": count, + "recordsFiltered": count, + "data": data, + }) + + +def serialize_worker(worker): + result = { + "first_name": worker.first_name, + "last_name": worker.last_name, + "id": worker.id, + } + return result diff --git a/smash/web/docx_helper.py b/smash/web/docx_helper.py index 49c2fc87105b7722a9ab341dd37f4b90fe67242b..a35bfc83043098f6f13b1a6e3d66980d76aebda4 100644 --- a/smash/web/docx_helper.py +++ b/smash/web/docx_helper.py @@ -19,3 +19,19 @@ def process_file(path_to_docx, path_to_new_docx, changes_to_apply): paragraph.text = paragraph.text.replace(placeholder, replacement) doc.save(path_to_new_docx) + + +def merge_files(files, path_to_new_docx): + merged_document = Document() + + for index, input_file in enumerate(files): + sub_doc = Document(input_file) + + # Don't add a page break if you've reached the last file. + if index < len(files) - 1: + sub_doc.add_page_break() + + for element in sub_doc.element.body: + merged_document.element.body.append(element) + + merged_document.save(path_to_new_docx) diff --git a/smash/web/migrations/0112_auto_20180604_1021.py b/smash/web/migrations/0112_auto_20180604_1021.py new file mode 100644 index 0000000000000000000000000000000000000000..5d99ccd90a40da44049780bf713e00f2267f905c --- /dev/null +++ b/smash/web/migrations/0112_auto_20180604_1021.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-06-04 10:21 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0111_auto_20180601_1318'), + ] + + operations = [ + migrations.AlterField( + model_name='mailtemplate', + name='context', + field=models.CharField(choices=[(b'A', b'Appointment'), (b'S', b'Subject'), (b'V', b'Visit'), (b'C', b'Voucher')], max_length=1), + ), + migrations.AlterField( + model_name='mailtemplate', + name='language', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='web.Language'), + ), + ] diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py index 0ef157f4b99f0f009eec4f5de0cca8f20a651305..865f10ccf3c1c1e17f102a0cdca273c34cdc1014 100644 --- a/smash/web/models/constants.py +++ b/smash/web/models/constants.py @@ -48,14 +48,18 @@ KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_TYPE = "KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_ MAIL_TEMPLATE_CONTEXT_SUBJECT = 'S' MAIL_TEMPLATE_CONTEXT_APPOINTMENT = 'A' MAIL_TEMPLATE_CONTEXT_VISIT = 'V' +MAIL_TEMPLATE_CONTEXT_VOUCHER = 'C' MAIL_TEMPLATE_CONTEXT_CHOICES = ( (MAIL_TEMPLATE_CONTEXT_APPOINTMENT, 'Appointment'), (MAIL_TEMPLATE_CONTEXT_SUBJECT, 'Subject'), (MAIL_TEMPLATE_CONTEXT_VISIT, 'Visit'), + (MAIL_TEMPLATE_CONTEXT_VOUCHER, 'Voucher'), ) LOCALE_CHOICES = [(value, value) for value in sorted(locale.windows_locale.values())] +DEFAULT_LOCALE_NAME = "fr_FR" + MONDAY_AS_DAY_OF_WEEK = 1 TUESDAY_AS_DAY_OF_WEEK = 2 WEDNESDAY_AS_DAY_OF_WEEK = 3 diff --git a/smash/web/models/language.py b/smash/web/models/language.py index 8db4cd2733ebc47242c4bad1e82408e11b45f1b1..5848ace6180745d33749f3140e618803dffcce02 100644 --- a/smash/web/models/language.py +++ b/smash/web/models/language.py @@ -2,7 +2,7 @@ from django.db import models -from .constants import LOCALE_CHOICES +from .constants import LOCALE_CHOICES, DEFAULT_LOCALE_NAME class Language(models.Model): @@ -13,7 +13,8 @@ class Language(models.Model): name = models.CharField(max_length=20) image = models.ImageField() order = models.IntegerField(default=0) - locale = models.CharField(max_length=10, choices=LOCALE_CHOICES, null=False, blank=False, default="fr_FR") + locale = models.CharField(max_length=10, choices=LOCALE_CHOICES, null=False, blank=False, + default=DEFAULT_LOCALE_NAME) windows_locale_name = models.CharField(max_length=10, choices=LOCALE_CHOICES, null=False, blank=False, default="French") diff --git a/smash/web/models/mail_template.py b/smash/web/models/mail_template.py index d4f72d1867a4de358b55957fbf9cb3686f40b960..2089ae1ecf52516051ec5f189ec78ae60576eca3 100644 --- a/smash/web/models/mail_template.py +++ b/smash/web/models/mail_template.py @@ -7,9 +7,9 @@ from contextlib import contextmanager from django.db import models from .constants import MAIL_TEMPLATE_CONTEXT_CHOICES, MAIL_TEMPLATE_CONTEXT_APPOINTMENT, \ - MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VISIT + MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VISIT, MAIL_TEMPLATE_CONTEXT_VOUCHER, DEFAULT_LOCALE_NAME from ..docx_helper import process_file -from ..models import Appointment, Visit, StudySubject, Worker +from ..models import Appointment, Visit, StudySubject, Worker, Voucher DATE_FORMAT_FULL = "%A %d %B %Y" @@ -99,9 +99,26 @@ class MailTemplate(models.Model): ("##A_TYPES##", "Appointment's types", "comma separated"), ] + MAILS_TEMPLATE_VOUCHER_TAGS = [ + ("##C_NUMBER##", "Number", ''), + ("##C_PATIENT_NAME##", "Voucher Partner name", ''), + ("##C_VOUCHER_TYPE##", "Voucher type", ''), + + ("##C_ISSUE_DATE_SHORT##", "Issue date", get_formatted_time(DATE_FORMAT_SHORT)), + ("##C_EXPIRY_START_SHORT##", "Expiry date", get_formatted_time(DATE_FORMAT_SHORT)), + + ("##C_PARTNER_NAME##", "Voucher Partner name", ''), + ("##C_PARTNER_ADDRESS##", "Voucher Partner address", ''), + ("##C_PARTNER_CITY##", "Voucher Partner city", ''), + ("##C_PARTNER_POSTAL_CODE##", "Voucher Partner postal code", ''), + ("##C_PARTNER_COUNTRY##", "Voucher Partner country", ''), + ("##C_PARTNER_PHONE##", "Voucher Partner phone", ''), + ("##C_HOURS##", "Hours", ''), + ] + name = models.CharField(max_length=255) context = models.CharField(max_length=1, choices=MAIL_TEMPLATE_CONTEXT_CHOICES) - language = models.ForeignKey("web.Language", on_delete=models.CASCADE) + language = models.ForeignKey("web.Language", on_delete=models.CASCADE, null=True) template_file = models.FileField(upload_to='templates/') @staticmethod @@ -112,6 +129,10 @@ class MailTemplate(models.Model): def get_subject_mail_templates(languages): return MailTemplate.get_mail_templates_for_context(languages, MAIL_TEMPLATE_CONTEXT_SUBJECT) + @staticmethod + def get_voucher_mail_templates(languages): + return MailTemplate.get_mail_templates_for_context(languages, MAIL_TEMPLATE_CONTEXT_VOUCHER) + @staticmethod def get_visit_mail_templates(languages): return MailTemplate.get_mail_templates_for_context(languages, MAIL_TEMPLATE_CONTEXT_VISIT) @@ -123,17 +144,23 @@ class MailTemplate(models.Model): active_templates = [] disabled_templates = [] for template in templates: - if template.language.name in languages_names: + if template.language is None: + if len(languages) == 0: + active_templates.append(template) + else: + disabled_templates.append(template) + elif template.language.name in languages_names: active_templates.append(template) else: disabled_templates.append(template) - active_templates.sort(key=lambda x: languages_names.index(x.language.name)) + active_templates.sort(key=lambda x: languages_names.index(x.language.name) if x.language is not None else -1) return active_templates, disabled_templates def apply(self, instance, user, stream): appointment = None visit = None study_subject = None + voucher = None if isinstance(instance, Appointment): appointment = instance visit = instance.visit @@ -143,19 +170,29 @@ class MailTemplate(models.Model): study_subject = visit.subject elif isinstance(instance, StudySubject): study_subject = instance + elif isinstance(instance, Voucher): + voucher = instance # set locale to get correct date format - locale_name = self.language.locale - if platform.system() == 'Windows': - locale_name = self.language.windows_locale_name + locale_name = self.get_locale_name() with setlocale(locale_name.encode('utf8')): replacements = {} self._add_generic_replacements(replacements, Worker.get_by_user(user)) self._add_appointment_replacements(replacements, appointment) self._add_visit_replacements(replacements, visit) self._add_subject_replacements(replacements, study_subject) + self._add_voucher_replacements(replacements, voucher) process_file(self.template_file.path, stream, replacements) return stream + def get_locale_name(self): + if self.language is None: + locale_name = DEFAULT_LOCALE_NAME + else: + locale_name = self.language.locale + if platform.system() == 'Windows': + locale_name = self.language.windows_locale_name + return locale_name + def _add_generic_replacements(self, replacements, worker): current_datetime = datetime.datetime.now() replacements.update({ @@ -237,3 +274,21 @@ class MailTemplate(models.Model): '##S_MAIL_LANGUAGE##': str(study_subject.subject.default_written_communication_language), '##S_KNOWN_LANGUAGES##': ", ".join([l.name for l in study_subject.subject.languages.all()]) }) + + def _add_voucher_replacements(self, replacements, voucher): + if voucher is not None: + replacements.update({ + "##C_NUMBER##": voucher.number, + "##C_PATIENT_NAME##": voucher.study_subject.subject.first_name + ' ' + voucher.study_subject.subject.last_name, + "##C_VOUCHER_TYPE##": voucher.voucher_type.description, + "##C_ISSUE_DATE_SHORT##": voucher.issue_date.strftime(DATE_FORMAT_SHORT).decode(date_format_encoding()), + "##C_EXPIRY_START_SHORT##": voucher.expiry_date.strftime(DATE_FORMAT_SHORT).decode( + date_format_encoding()), + "##C_PARTNER_NAME##": voucher.usage_partner.first_name + ' ' + voucher.usage_partner.last_name, + "##C_PARTNER_ADDRESS##": voucher.usage_partner.address, + "##C_PARTNER_POSTAL_CODE##": voucher.usage_partner.postal_code, + "##C_PARTNER_CITY##": voucher.usage_partner.city, + "##C_PARTNER_COUNTRY##": unicode(voucher.usage_partner.country), + "##C_PARTNER_PHONE##": voucher.usage_partner.phone_number, + "##C_HOURS##": str(voucher.hours), + }) diff --git a/smash/web/static/js/smash.js b/smash/web/static/js/smash.js index 6da68884c152b60a3e56823dc4e808d4b604e76c..45122991ee81b1341c86e6e665f1faf113e255d5 100644 --- a/smash/web/static/js/smash.js +++ b/smash/web/static/js/smash.js @@ -215,6 +215,8 @@ function createTable(params) { var flying_teams_url = params.flying_teams_url; var appointment_types_url = params.appointment_types_url; var subjects_url = params.subjects_url; + var voucher_types_url = params.voucher_types_url; + var voucher_partner_url = params.voucher_partner_url; var columnsDefinition = params.columns; tableElement.appendChild(createHeader(columnsDefinition)); @@ -239,6 +241,15 @@ function createTable(params) { $(this).html('<select style="width:60px" >' + options + '</select>'); }); + $(tableElement).find('tfoot div[name="voucher_status_filter"]').each(function () { + $(this).html('<select style="width:60px" ><option value selected="selected">---</option>' + + '<option value="NEW">NEW</option>' + + '<option value="IN_USE">IN USE</option>' + + '<option value="USED">USED</option>' + + '<option value="EXPIRED">EXPIRED</option>' + + '</select>'); + }); + $(tableElement).find('tfoot div[name="visit_filter"]').each(function () { $(this).html('<select style="width:60px" >' + '<option value selected="selected">---</option>' + @@ -265,6 +276,29 @@ function createTable(params) { }); }); + $(tableElement).find('tfoot div[name="voucher_type_filter"]').each(function () { + var obj = $(this); + obj.html('<select style="width:80px"><option value selected="selected">---</option></select>'); + var select = $('select', obj); + $.get(voucher_types_url, function (content) { + $.each(content.data, function (index, voucher_type) { + select.append('<option value="' + voucher_type.id + '">' + voucher_type.code + '</option>'); + }); + }); + }); + + $(tableElement).find('tfoot div[name="voucher_partner_filter"]').each(function () { + var obj = $(this); + obj.html('<select style="width:80px"><option value selected="selected">---</option></select>'); + var select = $('select', obj); + $.get(voucher_partner_url, function (content) { + $.each(content.data, function (index, voucher_partner) { + select.append('<option value="' + voucher_partner.id + '">' + voucher_partner.first_name + ' ' + + voucher_partner.last_name + ' ' + '</option>'); + }); + }); + }); + $(tableElement).find('tfoot div[name="flying_team_filter"]').each(function () { var obj = $(this); obj.html('<select style="width:80px"><option value selected="selected">---</option></select>'); diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html index f7edcc999350542ff409a3ed620a3f6982a9fdaa..ee4b4f0c9bef0184c7192368d76fd369713f1f6f 100644 --- a/smash/web/templates/appointments/index.html +++ b/smash/web/templates/appointments/index.html @@ -157,7 +157,7 @@ events: get_calendar_events_function( "{% url 'web.api.appointments' full_list %}", true, dayHeaders, - "{% url 'web.api.workers.availabilities$' %}") + "{% url 'web.api.workers.daily_planning.availabilities$' %}") }); }); </script> diff --git a/smash/web/templates/daily_planning.html b/smash/web/templates/daily_planning.html index 6054dcf172570251632ad338f0010d9e61355803..c02b5d7d6e7e9262b53a20f90b1eb9c4d4a261d9 100644 --- a/smash/web/templates/daily_planning.html +++ b/smash/web/templates/daily_planning.html @@ -46,7 +46,7 @@ <script src="{% static 'fullcalendar-scheduler/lib/fullcalendar.min.js' %}"></script> <script src="{% static 'fullcalendar-scheduler/scheduler.min.js' %}"></script> <script> - var resources_url = '{% url 'web.api.workers' %}'; + var resources_url = '{% url 'web.api.workers.daily_planning' %}'; var events_url = '{% url 'web.api.events_persist' %}'; </script> {% include "includes/datepicker.js.html" %} diff --git a/smash/web/templates/includes/subject_vouchers_box.html b/smash/web/templates/includes/subject_vouchers_box.html index a17610a2a9e70bf1ff3d106b2a57eeeca09c3211..4cd7c2f4c88d48d3887432691a20cb687721d284 100644 --- a/smash/web/templates/includes/subject_vouchers_box.html +++ b/smash/web/templates/includes/subject_vouchers_box.html @@ -13,6 +13,7 @@ <thead> <tr> + <th class="text-center">Select</th> <th class="text-center">Number</th> <th class="text-center">Type</th> <th class="text-center">Issue date</th> @@ -26,6 +27,7 @@ <tbody> {% for voucher in subject.vouchers.all %} <tr> + <td><input type="checkbox" data-id="{{ voucher.id }}" class="voucher_checkbox"/></td> <td>{{ voucher.number }}</td> <td>{{ voucher.voucher_type }}</td> <td>{{ voucher.issue_date }}</td> @@ -39,6 +41,18 @@ {% endfor %} </tbody> </table> + <a href="#" data-url="{% url "web.views.mail_template_generate_for_vouchers" %}" onclick=' + var checkboxes = $(".voucher_checkbox"); + var url = $(this).data("url")+"?voucher_id="; + + for (var i=0;i<checkboxes.length;i++){ + if ($(checkboxes[i]).is(":checked")) { + url+=$(checkboxes[i]).data("id")+","; + } + } + this.href = url; + '>Print vouchers</a> + </div> </div> diff --git a/smash/web/templates/subjects/edit.html b/smash/web/templates/subjects/edit.html index 669f863086174f60aaca05907bf6713c84725340..73249d4fb51632bdc70a331f60e4dc903927ce05 100644 --- a/smash/web/templates/subjects/edit.html +++ b/smash/web/templates/subjects/edit.html @@ -109,10 +109,6 @@ </div><!-- /.col-md-12 --> </div><!-- /.row --> - {% if study_subject.study.columns.vouchers %} - {% include 'includes/subject_vouchers_box.html' with subject=study_subject %} - {% endif %} - {% include 'includes/mail_templates_box.html' with instance_id=study_subject.id %} {% include 'includes/contact_attempts_box.html' with subject=study_subject contact_attempts=contact_attempts %} @@ -157,6 +153,10 @@ </div><!-- /.modal-dialog --> </div><!-- /.modal --> + {% if study_subject.study.columns.vouchers %} + {% include 'includes/subject_vouchers_box.html' with subject=study_subject %} + {% endif %} + {% endblock %} diff --git a/smash/web/templates/vouchers/add_edit.html b/smash/web/templates/vouchers/add_edit.html index 488467ec25e1bd6a4184b4e60e82ea118bf6a92f..c0083e92cc23d2b666a8a60547a0237e04123da5 100644 --- a/smash/web/templates/vouchers/add_edit.html +++ b/smash/web/templates/vouchers/add_edit.html @@ -90,6 +90,8 @@ </table> </div> + {% include 'includes/mail_templates_box.html' with instance_id=voucher.id %} + {% endif %} </div> </div> diff --git a/smash/web/templates/vouchers/list.html b/smash/web/templates/vouchers/list.html index 1b29b2965c072b85dd28d1342adb9417809791fa..99a39340aec7ed9bd833dd733ee3b5bac9659a89 100644 --- a/smash/web/templates/vouchers/list.html +++ b/smash/web/templates/vouchers/list.html @@ -18,39 +18,12 @@ {% block maincontent %} <div class="box-body"> - <table id="table" class="table table-bordered table-striped"> - <thead> - <tr> - <th>Number</th> - <th>Type</th> - <th>First name</th> - <th>Last name</th> - <th>Issue date</th> - <th>Expiry date</th> - <th>Status</th> - <th>Partner</th> - <th>Feedback</th> - <th>Edit</th> - </tr> - </thead> - <tbody> - {% for voucher in vouchers %} - <tr> - <td>{{ voucher.number }}</td> - <td>{{ voucher.voucher_type }}</td> - <td>{{ voucher.study_subject.subject.first_name }}</td> - <td>{{ voucher.study_subject.subject.last_name }}</td> - <td>{{ voucher.issue_date }}</td> - <td>{{ voucher.expiry_date }}</td> - <td>{{ voucher.status }}</td> - <td>{{ voucher.usage_partner.first_name }} {{ voucher.usage_partner.last_name }}</td> - <td>{{ voucher.feedback }}</td> - <td><a href="{% url 'web.views.voucher_edit' voucher.id %}"><i class="fa fa-edit"></i></a></td> - </tr> - {% endfor %} - </tbody> + <table id="table" class="table table-bordered table-striped table-responsive"> </table> </div> + <h3>Visible columns</h3> + <div id="visible-column-checkboxes" style="display:table; width:100%"> + </div> {% endblock maincontent %} {% block scripts %} @@ -58,17 +31,27 @@ <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> + <script src="{% static 'js/appointment.js' %}"></script> <script> - $(function () { - $('#table').DataTable({ - "paging": true, - "lengthChange": false, - "searching": true, - "ordering": true, - "info": true, - "autoWidth": false - }); + function getVoucherEditUrl(id) { + return "{% url 'web.views.voucher_edit' 1234567 %}".replace(/1234567/, id); + } + + $.get("{% url 'web.api.vouchers.columns' %}", function (data) { + createAppointmentsTable({ + appointment_types_url: "{% url 'web.api.appointment_types' %}", + subject_types_url: "{% url 'web.api.subject_types' %}", + locations_url: "{% url 'web.api.locations' %}", + subjects_url: "{% url 'web.api.vouchers'%}", + voucher_partner_url: "{% url 'web.api.workers' 'VOUCHER_PARTNER' %}", + voucher_types_url: "{% url 'web.api.voucher_types' %}", + flying_teams_url: "{% url 'web.api.flying_teams' %}", + tableElement: document.getElementById("table"), + columns: getColumns(data.columns, getVoucherEditUrl), + checkboxesElement: document.getElementById("visible-column-checkboxes") + }) }); + </script> {% endblock scripts %} diff --git a/smash/web/tests/api_views/test_voucher.py b/smash/web/tests/api_views/test_voucher.py new file mode 100644 index 0000000000000000000000000000000000000000..adbb1fd521058559ef751e5d77b7b521037e2901 --- /dev/null +++ b/smash/web/tests/api_views/test_voucher.py @@ -0,0 +1,204 @@ +# coding=utf-8 +import datetime +import json +import logging + +from django.urls import reverse + +from web.api_views.voucher import get_vouchers_filtered, get_vouchers_order +from web.models import Voucher +from web.models.constants import VOUCHER_STATUS_USED, VOUCHER_STATUS_NEW +from web.tests import LoggedInWithWorkerTestCase +from web.tests.functions import create_get_suffix, create_voucher +from web.views.notifications import get_today_midnight_date + +logger = logging.getLogger(__name__) + + +class TestVoucherApi(LoggedInWithWorkerTestCase): + def setUp(self): + super(TestVoucherApi, self).setUp() + self.voucher = create_voucher() + + def test_vouchers_general(self): + response = self.client.get(reverse('web.api.vouchers')) + self.assertEqual(response.status_code, 200) + + def test_vouchers_general_search(self): + name = "Piotrek" + self.voucher.study_subject.subject.first_name = name + self.voucher.study_subject.subject.save() + + params = { + "columns[0][search][value]": "another_name", + "columns[0][data]": "first_name" + } + url = ("%s" + create_get_suffix(params)) % reverse('web.api.vouchers') + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertFalse(name in response.content) + + params["columns[0][search][value]"] = name + url = ("%s" + create_get_suffix(params)) % reverse('web.api.vouchers') + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertTrue(name in response.content) + + def check_voucher_filtered(self, filters, result): + vouchers = get_vouchers_filtered(Voucher.objects.all(), filters) + self.assertEqual(len(result), vouchers.count()) + for index in range(len(result)): + self.assertEqual(result[index], vouchers[index]) + + def check_voucher_ordered(self, order, result): + vouchers = get_vouchers_order(Voucher.objects.all(), order, "asc") + self.assertEqual(len(result), vouchers.count()) + for index in range(len(result)): + self.assertEqual(result[index], vouchers[index]) + + vouchers = get_vouchers_order(Voucher.objects.all(), order, "desc") + length = len(result) + self.assertEqual(length, vouchers.count()) + for index in range(length): + self.assertEqual(result[length - index - 1], vouchers[index]) + + def test_vouchers_sort_number(self): + voucher = self.voucher + voucher.number = "PPP" + voucher.save() + + voucher2 = create_voucher() + voucher2.number = "QQQ" + voucher2.save() + + self.check_voucher_ordered("number", [voucher, voucher2]) + + def test_subjects_sort_id(self): + voucher = self.voucher + + voucher2 = create_voucher() + + self.check_voucher_ordered("id", [voucher, voucher2]) + + def test_vouchers_sort_issue_date(self): + voucher = self.voucher + voucher.issue_date = get_today_midnight_date() + voucher.save() + + voucher2 = create_voucher() + voucher2.issue_date = get_today_midnight_date() + datetime.timedelta(days=1) + voucher2.save() + + self.check_voucher_ordered("issue_date", [voucher, voucher2]) + + def test_vouchers_sort_expiry_date(self): + voucher = self.voucher + voucher.expiry_date = get_today_midnight_date() + voucher.save() + + voucher2 = create_voucher() + voucher2.expiry_date = get_today_midnight_date() + datetime.timedelta(days=1) + voucher2.save() + + self.check_voucher_ordered("expiry_date", [voucher, voucher2]) + + def test_vouchers_sort_type(self): + voucher = self.voucher + voucher.voucher_type.code = "ZZ" + voucher.voucher_type.save() + + voucher2 = create_voucher() + voucher2.voucher_type.code = "AA" + voucher2.save() + + self.check_voucher_ordered("type", [voucher2, voucher]) + + def test_vouchers_sort_status(self): + voucher = self.voucher + voucher.status = VOUCHER_STATUS_USED + voucher.save() + + voucher2 = create_voucher() + voucher2.status = VOUCHER_STATUS_NEW + voucher2.save() + + self.check_voucher_ordered("status", [voucher2, voucher]) + + def test_vouchers_sort_unknown(self): + self.check_voucher_ordered("unk", [self.voucher]) + + def test_vouchers_filter_nd_number(self): + voucher = self.voucher + voucher.number = "PPP" + voucher.save() + + voucher2 = create_voucher() + voucher2.number = "QQQ" + voucher2.save() + + self.check_voucher_filtered([["number", "P"]], [voucher]) + + def test_vouchers_filter_last_name(self): + voucher = self.voucher + voucher.study_subject.subject.last_name = "PPP" + voucher.study_subject.subject.save() + + create_voucher() + + self.check_voucher_filtered([["last_name", "P"]], [voucher]) + + def test_vouchers_filter_type(self): + voucher = self.voucher + + create_voucher() + + self.check_voucher_filtered([["type", str(voucher.voucher_type.id)]], [voucher]) + + def test_vouchers_filter_status(self): + voucher = self.voucher + voucher.status = VOUCHER_STATUS_NEW + voucher.save() + + voucher2 = create_voucher() + voucher2.status = VOUCHER_STATUS_USED + voucher2.save() + + self.check_voucher_filtered([["status", VOUCHER_STATUS_NEW]], [voucher]) + + def test_vouchers_filter_voucher_partner(self): + voucher = self.voucher + + create_voucher() + + self.check_voucher_filtered([["voucher_partner", str(voucher.usage_partner_id)]], [voucher]) + + def test_vouchers_filter_feedback(self): + voucher = self.voucher + voucher.feedback = "XAS" + voucher.save() + + create_voucher() + + self.check_voucher_filtered([["feedback", "X"]], [voucher]) + + def test_vouchers_filter_unknown(self): + voucher = self.voucher + + self.check_voucher_filtered([["unk", "X"]], [voucher]) + + def test_vouchers_filter_unknown_2(self): + voucher = self.voucher + + self.check_voucher_filtered([[None, "X"]], [voucher]) + + def test_vouchers_filter_empty(self): + voucher = self.voucher + + self.check_voucher_filtered([["", "X"]], [voucher]) + + def test_get_columns(self): + response = self.client.get(reverse('web.api.vouchers.columns')) + self.assertEqual(response.status_code, 200) + + columns = json.loads(response.content)['columns'] + self.assertTrue(len(columns) > 0) diff --git a/smash/web/tests/api_views/test_voucher_type.py b/smash/web/tests/api_views/test_voucher_type.py new file mode 100644 index 0000000000000000000000000000000000000000..c4f799985562877a22965a43368491a2f2a2dd28 --- /dev/null +++ b/smash/web/tests/api_views/test_voucher_type.py @@ -0,0 +1,24 @@ +# coding=utf-8 +import datetime +import logging + +from django.urls import reverse + +from web.api_views.voucher import get_vouchers_filtered, get_vouchers_order +from web.models import Voucher +from web.models.constants import VOUCHER_STATUS_USED, VOUCHER_STATUS_NEW +from web.tests import LoggedInWithWorkerTestCase +from web.tests.functions import create_get_suffix, create_voucher, create_voucher_type +from web.views.notifications import get_today_midnight_date + +logger = logging.getLogger(__name__) + + +class TestVoucherTypeApi(LoggedInWithWorkerTestCase): + def setUp(self): + super(TestVoucherTypeApi, self).setUp() + self.voucher_type = create_voucher_type() + + def test_voucher_types_render(self): + response = self.client.get(reverse('web.api.voucher_types')) + self.assertEqual(response.status_code, 200) diff --git a/smash/web/tests/api_views/test_worker.py b/smash/web/tests/api_views/test_worker.py index 22b8e76eec524117da068ee506cc020ff8bf569f..c146d560acf741436cef1ba93667a994940d8fdb 100644 --- a/smash/web/tests/api_views/test_worker.py +++ b/smash/web/tests/api_views/test_worker.py @@ -4,10 +4,12 @@ import json from django.test import RequestFactory from django.urls import reverse +from web.api_views.worker import availabilities from web.models import Availability from web.models.constants import TUESDAY_AS_DAY_OF_WEEK -from web.api_views.worker import availabilities +from web.models.worker_study_role import WORKER_STAFF from web.tests import LoggedInWithWorkerTestCase +from web.tests.functions import create_voucher_partner class TestWorkerApi(LoggedInWithWorkerTestCase): @@ -48,10 +50,16 @@ class TestWorkerApi(LoggedInWithWorkerTestCase): self.assertTrue(unit_name in units) def test_workers_for_daily_planning(self): - response = self.client.get(reverse('web.api.workers')) + response = self.client.get(reverse('web.api.workers.daily_planning')) self.assertEqual(response.status_code, 200) self.assertTrue(self.worker.first_name in response.content) + def test_voucher_partners(self): + voucher_partner = create_voucher_partner() + response = self.client.get(reverse('web.api.workers', kwargs={'worker_role': WORKER_STAFF})) + self.assertEqual(response.status_code, 200) + self.assertTrue(voucher_partner.first_name in response.content) + def test_empty_availabilities(self): factory = RequestFactory() request = factory.get('/api/workers?start_date=2017-10-20&end_date=2017-11-20') diff --git a/smash/web/tests/data/voucher_test.docx b/smash/web/tests/data/voucher_test.docx new file mode 100644 index 0000000000000000000000000000000000000000..8f263326ba270ab7bfe216c812631225bb1fd105 Binary files /dev/null and b/smash/web/tests/data/voucher_test.docx differ diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index f7da4add1364911a0e51a2015cfe53842f754b06..0164230b3ae50aa50a93cc8979135df6c938670b 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -9,7 +9,7 @@ from web.models import Location, AppointmentType, StudySubject, Worker, Visit, A VoucherType, VoucherTypePrice, Voucher, Room, Item, WorkerStudyRole from web.models.constants import REDCAP_TOKEN_CONFIGURATION_TYPE, REDCAP_BASE_URL_CONFIGURATION_TYPE, \ SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL, CONTACT_TYPES_PHONE, \ - MONDAY_AS_DAY_OF_WEEK, COUNTRY_AFGHANISTAN_ID, VOUCHER_STATUS_NEW, GLOBAL_STUDY_ID + MONDAY_AS_DAY_OF_WEEK, COUNTRY_AFGHANISTAN_ID, VOUCHER_STATUS_NEW, GLOBAL_STUDY_ID, DEFAULT_LOCALE_NAME from web.models.worker_study_role import ROLE_CHOICES_DOCTOR, WORKER_VOUCHER_PARTNER from web.redcap_connector import RedcapSubject from web.views.notifications import get_today_midnight_date @@ -311,7 +311,7 @@ def create_room(owner='Test owner', city='Test city', return room -def create_language(name="French", locale="fr_FR"): +def create_language(name="French", locale=DEFAULT_LOCALE_NAME): language = Language(name=name, locale=locale) language.save() return language diff --git a/smash/web/tests/models/test_mail_template.py b/smash/web/tests/models/test_mail_template.py index 49c84a13962049a563cd007c6a2b819575e33361..500b3a0709ffb1afdb53a0c13b15cdfa71343c96 100644 --- a/smash/web/tests/models/test_mail_template.py +++ b/smash/web/tests/models/test_mail_template.py @@ -5,11 +5,11 @@ from docx import Document from web.models import MailTemplate from web.models.constants import MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VISIT, \ - MAIL_TEMPLATE_CONTEXT_SUBJECT + MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VOUCHER from web.models.mail_template import DATE_FORMAT_SHORT from web.tests.functions import create_language, get_resource_path, create_appointment, create_user, \ create_study_subject, \ - create_visit + create_visit, create_voucher class MailTemplateModelTests(TestCase): @@ -34,6 +34,11 @@ class MailTemplateModelTests(TestCase): function_to_test = MailTemplate.get_subject_mail_templates self.check_get_mail_templates(context, function_to_test) + def test_get_voucher_mail_templates(self): + context = MAIL_TEMPLATE_CONTEXT_VOUCHER + function_to_test = MailTemplate.get_voucher_mail_templates + self.check_get_mail_templates(context, function_to_test) + def check_get_mail_templates(self, context, function_to_test): # create french template template_name_french = "test_fr" @@ -93,6 +98,45 @@ class MailTemplateModelTests(TestCase): self.check_doc_contains(doc, [worker_name, str(subject), str(subject.subject.country), subject.nd_number, subject.get_type_display()]) + def test_apply_voucher(self): + template_name_french = "test_without_language" + subject = create_study_subject() + subject_template_french = MailTemplate(name=template_name_french, language=None, + context=MAIL_TEMPLATE_CONTEXT_VOUCHER, + template_file="voucher_test.docx") + voucher = create_voucher(study_subject=subject) + stream = StringIO.StringIO() + subject_template_french.apply(voucher, self.user, stream) + doc = Document(stream) + worker_name = str(self.user.worker) + + self.check_doc_contains(doc, [worker_name, str(subject), voucher.number, voucher.usage_partner.address, + voucher.expiry_date.strftime(DATE_FORMAT_SHORT), + voucher.issue_date.strftime(DATE_FORMAT_SHORT) + ]) + + def test_get_mail_templates_for_context_without_language(self): + template_name_french = "test_without_language" + MailTemplate(name=template_name_french, language=None, + context=MAIL_TEMPLATE_CONTEXT_VOUCHER, + template_file="voucher_test.docx").save() + + templates = MailTemplate.get_mail_templates_for_context([], context=MAIL_TEMPLATE_CONTEXT_VOUCHER) + self.assertEquals(1, len(templates[0])) + + templates = MailTemplate.get_mail_templates_for_context([self.english_language], + context=MAIL_TEMPLATE_CONTEXT_VOUCHER) + self.assertEquals(0, len(templates[0])) + + def test_get_mail_templates_for_context_without_language_2(self): + template_name_french = "test_without_language" + MailTemplate(name=template_name_french, language=self.english_language, + context=MAIL_TEMPLATE_CONTEXT_VOUCHER, + template_file="voucher_test.docx").save() + + templates = MailTemplate.get_mail_templates_for_context([], context=MAIL_TEMPLATE_CONTEXT_VOUCHER) + self.assertEquals(0, len(templates[0])) + def test_apply_visit(self): template_name_french = "test_fr" visit = create_visit() diff --git a/smash/web/tests/test_process_file.py b/smash/web/tests/test_process_file.py index 61b32c416309e0440feb08020853b6545727dbb6..c2d428d8b822b484fc54631d9f3a921c55c2ae09 100644 --- a/smash/web/tests/test_process_file.py +++ b/smash/web/tests/test_process_file.py @@ -9,7 +9,7 @@ from django.test import TestCase from web.tests.functions import get_resource_path from web.models.mail_template import date_format_encoding -from web.docx_helper import process_file +from web.docx_helper import process_file, merge_files logger = logging.getLogger(__name__) @@ -35,3 +35,13 @@ class TestDocxProcessor(TestCase): process_file(template_path, output_path, changes) self.assertTrue(os.path.isfile(output_path)) os.remove(output_path) + + def test_merge_files(self): + template_path = get_resource_path('template.docx') + template_path_2 = get_resource_path('voucher_test.docx') + + output_path = tempfile.mktemp() + + merge_files([template_path, template_path_2], output_path) + self.assertTrue(os.path.isfile(output_path)) + os.remove(output_path) diff --git a/smash/web/tests/view/test_mail.py b/smash/web/tests/view/test_mail.py new file mode 100644 index 0000000000000000000000000000000000000000..900c84a7bcadf38a37c420308d638eb4f2c74d14 --- /dev/null +++ b/smash/web/tests/view/test_mail.py @@ -0,0 +1,22 @@ +import logging + +from django.urls import reverse + +from web.models import MailTemplate +from web.models.constants import MAIL_TEMPLATE_CONTEXT_VOUCHER +from web.tests.functions import create_voucher, get_resource_path +from web.tests import LoggedInTestCase + +logger = logging.getLogger(__name__) + + +class MailTests(LoggedInTestCase): + def test_generate_vouchers(self): + voucher = create_voucher() + MailTemplate(name="name", language=None, + context=MAIL_TEMPLATE_CONTEXT_VOUCHER, + template_file=get_resource_path('upcoming_appointment_FR.docx')).save() + + page = reverse('web.views.mail_template_generate_for_vouchers') + "?voucher_id=" + str(voucher.id) + response = self.client.get(page) + self.assertEqual(response.status_code, 200) diff --git a/smash/web/urls.py b/smash/web/urls.py index 63496dee167e3951c5c7957bdc0e8c9888609c0d..ff3f13a912ccad5c56f589b19fefa808f8d0c49f 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -164,6 +164,8 @@ urlpatterns = [ name='web.views.mail_template_edit'), url(r'^mail_templates/(?P<mail_template_id>\d+)/generate/(?P<instance_id>\d+)$', views.mails.generate, name="web.views.mail_template_generate"), + url(r'^mail_templates/print_vouchers$', views.mails.generate_for_vouchers, + name="web.views.mail_template_generate_for_vouchers"), #################### # DAILY PLANNING # diff --git a/smash/web/views/mails.py b/smash/web/views/mails.py index 1fc450b3a55b695190667cf55c5eea8b30749df0..32a1f3b0413c30a7eb6f36825f06dda8ba805e68 100644 --- a/smash/web/views/mails.py +++ b/smash/web/views/mails.py @@ -11,16 +11,18 @@ from django.views.generic import DeleteView from django.views.generic import ListView from django.views.generic import UpdateView +from web.docx_helper import merge_files from . import WrappedView -from ..models import StudySubject, Visit, Appointment, MailTemplate +from ..models import StudySubject, Visit, Appointment, MailTemplate, Voucher from ..models.constants import MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VISIT, \ - MAIL_TEMPLATE_CONTEXT_APPOINTMENT + MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VOUCHER MIMETYPE_DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' CONTEXT_TYPES_MAPPING = { MAIL_TEMPLATE_CONTEXT_SUBJECT: StudySubject, MAIL_TEMPLATE_CONTEXT_VISIT: Visit, + MAIL_TEMPLATE_CONTEXT_VOUCHER: Voucher, MAIL_TEMPLATE_CONTEXT_APPOINTMENT: Appointment } @@ -35,6 +37,7 @@ class MailTemplatesListView(ListView, WrappedView): context['explanations'] = {"generic": MailTemplate.MAILS_TEMPLATE_GENERIC_TAGS, "subject": MailTemplate.MAILS_TEMPLATE_SUBJECT_TAGS, "visit": MailTemplate.MAILS_TEMPLATE_VISIT_TAGS, + "voucher": MailTemplate.MAILS_TEMPLATE_VOUCHER_TAGS, "appointment": MailTemplate.MAILS_TEMPLATE_APPOINTMENT_TAGS, } return context @@ -47,6 +50,11 @@ class MailTemplatesCreateView(CreateView, WrappedView): success_url = reverse_lazy('web.views.mail_templates') success_message = "Template created" + def get_form(self, form_class=None): + form = super(MailTemplatesCreateView, self).get_form(form_class) + form.fields['language'].required = False + return form + class MailTemplatesDeleteView(DeleteView, WrappedView): model = MailTemplate @@ -78,3 +86,30 @@ def generate(request, mail_template_id, instance_id): response['Content-Length'] = file_size response['Content-Disposition'] = 'attachment; filename={}.docx'.format(mail_template.name) return response + + +def generate_for_vouchers(request): + ids = request.GET.get('voucher_id', '').split(',') + vouchers = [] + for voucher_id in ids: + if voucher_id.isdigit(): + vouchers.append(Voucher.objects.get(pk=int(voucher_id))) + templates = MailTemplate.get_voucher_mail_templates([])[0] + + output_stream = StringIO.StringIO() + + inputs = [] + for template in templates: + for voucher in vouchers: + input_stream = StringIO.StringIO() + input_stream = template.apply(voucher, request.user, input_stream) + input_stream.seek(0) + inputs.append(input_stream) + + merge_files(inputs, output_stream) + file_size = output_stream.tell() + output_stream.seek(0) + response = HttpResponse(FileWrapper(output_stream), content_type=MIMETYPE_DOCX) + response['Content-Length'] = file_size + response['Content-Disposition'] = 'attachment; filename=vouchers.docx' + return response diff --git a/smash/web/views/voucher.py b/smash/web/views/voucher.py index 45b5a8f4f850aba0e19084b8ebefe3a2a44471dc..3124cc302b93ea9e7329ee427a2e27e5394a7184 100644 --- a/smash/web/views/voucher.py +++ b/smash/web/views/voucher.py @@ -10,7 +10,7 @@ from django_cron import CronJobBase, Schedule from web.views.notifications import get_today_midnight_date from web.forms import VoucherForm -from web.models import Voucher, StudySubject +from web.models import Voucher, StudySubject, MailTemplate from web.models.constants import GLOBAL_STUDY_ID, VOUCHER_STATUS_NEW, VOUCHER_STATUS_EXPIRED from . import WrappedView @@ -67,6 +67,12 @@ class VoucherEditView(SuccessMessageMixin, UpdateView, WrappedView): def get_study_subject_id(self): return Voucher.objects.get(id=self.kwargs['pk']).study_subject.id + def get_context_data(self, *args, **kwargs): + context = super(VoucherEditView, self).get_context_data(*args, **kwargs) + context['mail_templates']= MailTemplate.get_voucher_mail_templates([]) + print context + return context + class ExpireVouchersJob(CronJobBase): RUN_EVERY_MINUTES = 120