diff --git a/smash/web/forms/forms.py b/smash/web/forms/forms.py index b33eb52d2f19cde653eb450aa2732a97e241aba6..570db43352dd9935a0ec0f9dc7871d6aaae6c427 100644 --- a/smash/web/forms/forms.py +++ b/smash/web/forms/forms.py @@ -7,7 +7,7 @@ from django.forms import ModelForm, Form from django.utils.dates import MONTHS from web.models import StudySubject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink, \ - Availability, Holiday + Availability, Holiday, VoucherType, VoucherTypePrice from web.models.constants import SUBJECT_TYPE_CHOICES from web.views.notifications import get_filter_locations @@ -385,3 +385,22 @@ class HolidayAddForm(ModelForm): availabilities = worker.availability_set.all() for availability in availabilities: validate_availability_conflict(self, self.cleaned_data, availability) + + +class VoucherTypeForm(ModelForm): + class Meta: + model = VoucherType + exclude = ['study'] + + +class VoucherTypePriceForm(ModelForm): + start_date = forms.DateField(label="Start date", + widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d") + ) + end_date = forms.DateField(label="End date", + widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d") + ) + + class Meta: + model = VoucherTypePrice + exclude = ['voucher_type'] diff --git a/smash/web/models/voucher_type_price.py b/smash/web/models/voucher_type_price.py index d3a8d56b9112f0ff53a3b98dbfd473ad2ca9f9fe..7e9ce9f009b624fb29e9df9217876886ca2b6f2d 100644 --- a/smash/web/models/voucher_type_price.py +++ b/smash/web/models/voucher_type_price.py @@ -16,4 +16,5 @@ class VoucherTypePrice(models.Model): VoucherType, on_delete=models.CASCADE, null=False, + related_name="prices" ) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index b021fad36954a78b967191ff704b42533aeeb37d..a8dd1d750c13fb5c824c11c40f9d9681bf535126 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -66,9 +66,8 @@ </a> <ul class="treeview-menu"> <li><a href="{% url 'web.views.configuration' %}">General</a></li> - <li> - <a href="{% url 'web.views.languages' %}">Languages</a> - </li> + <li><a href="{% url 'web.views.languages' %}">Languages</a></li> + <li><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li> </ul> </li> diff --git a/smash/web/templates/voucher_type_prices/add.html b/smash/web/templates/voucher_type_prices/add.html new file mode 100644 index 0000000000000000000000000000000000000000..2a8827de93410a51c108ee2945180903f0503b22 --- /dev/null +++ b/smash/web/templates/voucher_type_prices/add.html @@ -0,0 +1,9 @@ +{% extends "voucher_type_prices/add_edit.html" %} + +{% block page_header %}New voucher type price{% endblock page_header %} + +{% block title %}{{ block.super }} - Add new voucher type price{% endblock %} + +{% block form-title %}Enter voucher type price details{% endblock %} + +{% block save-button %}Add{% endblock %} diff --git a/smash/web/templates/voucher_type_prices/add_edit.html b/smash/web/templates/voucher_type_prices/add_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..2d7f024f9529bdc4214573ed871a0d04e0f8c920 --- /dev/null +++ b/smash/web/templates/voucher_type_prices/add_edit.html @@ -0,0 +1,82 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/> + {% include "includes/datepicker.css.html" %} + {% include "includes/datetimepicker.css.html" %} + +{% endblock styles %} + +{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block page_description %}{% endblock page_description %} + +{% block breadcrumb %} + {% include "voucher_type_prices/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="row"> + <div class="col-md-12"> + <div class="box box-success"> + <div class="box-header with-border"> + <h3 class="box-title">{% block form-title %}Enter voucher type price details + {% endblock %}</h3> + </div> + + + <form method="post" action="" class="form-horizontal" enctype="multipart/form-data"> + {% csrf_token %} + + <div class="box-body"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %}"> + <label class="col-sm-4 col-lg-offset-1 col-lg-2 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8 col-lg-4"> + {{ field|add_class:'form-control' }} + {% if field.errors %} + <span class="help-block">{{ field.errors }}</span> + {% endif %} + </div> + + + </div> + {% endfor %} + </div><!-- /.box-body --> + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">{% block save-button %} + Add{% endblock %} + </button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.voucher_types' %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + </div> + + </div> + </div> + + {% endblock %} + + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> + {% include "includes/datepicker.js.html" %} + {% include "includes/datetimepicker.js.html" %} + +{% endblock scripts %} \ No newline at end of file diff --git a/smash/web/templates/voucher_type_prices/breadcrumb.html b/smash/web/templates/voucher_type_prices/breadcrumb.html new file mode 100644 index 0000000000000000000000000000000000000000..844971e607ceace28009bea2b53bf6ccd423ba0d --- /dev/null +++ b/smash/web/templates/voucher_type_prices/breadcrumb.html @@ -0,0 +1,2 @@ +<li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +<li class="active"><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li> \ No newline at end of file diff --git a/smash/web/templates/voucher_type_prices/edit.html b/smash/web/templates/voucher_type_prices/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..06d29ce30153ba487840e584d392db2d37b07ffc --- /dev/null +++ b/smash/web/templates/voucher_type_prices/edit.html @@ -0,0 +1,10 @@ +{% extends "voucher_type_prices/add_edit.html" %} + +{% block page_header %}Edit voucher type price {% endblock page_header %} + +{% block title %}{{ block.super }} - Edit voucher type price "{{ voucher_type.code }}"{% endblock %} + +{% block form-title %}Enter voucher type price details{% endblock %} + +{% block save-button %}Save{% endblock %} + diff --git a/smash/web/templates/voucher_types/add.html b/smash/web/templates/voucher_types/add.html new file mode 100644 index 0000000000000000000000000000000000000000..7201197e9aa25881665fd5ac892e8bf9c7b2a10f --- /dev/null +++ b/smash/web/templates/voucher_types/add.html @@ -0,0 +1,9 @@ +{% extends "voucher_types/add_edit.html" %} + +{% block page_header %}New voucher type{% endblock page_header %} + +{% block title %}{{ block.super }} - Add new voucher type{% endblock %} + +{% block form-title %}Enter voucher type details{% endblock %} + +{% block save-button %}Add{% endblock %} diff --git a/smash/web/templates/voucher_types/add_edit.html b/smash/web/templates/voucher_types/add_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..40e6e35c53cc59858bf1f630aefae9c1fe99ffec --- /dev/null +++ b/smash/web/templates/voucher_types/add_edit.html @@ -0,0 +1,114 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/> + +{% endblock styles %} + +{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block page_description %}{% endblock page_description %} + +{% block breadcrumb %} + {% include "voucher_types/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="row"> + <div class="col-md-12"> + <div class="box box-success"> + <div class="box-header with-border"> + <h3 class="box-title">{% block form-title %}Enter voucher type details{% endblock %}</h3> + </div> + + + <form method="post" action="" class="form-horizontal" enctype="multipart/form-data"> + {% csrf_token %} + + <div class="box-body"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %}"> + <label class="col-sm-4 col-lg-offset-1 col-lg-2 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8 col-lg-4"> + {{ field|add_class:'form-control' }} + {% if field.errors %} + <span class="help-block">{{ field.errors }}</span> + {% endif %} + </div> + + + </div> + {% endfor %} + </div><!-- /.box-body --> + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">{% block save-button %} + Add{% endblock %} + </button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.voucher_types' %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + {% if voucher_type.study %} + <div class="box-header with-border"> + <h3>Prices <a title="add a new contact attempt" + id="add-contact-attempt" + href="{% url 'web.views.voucher_type_price_add' voucher_type.id %}" + class="text-primary" + ><i class="fa fa-plus-circle text-success"></i></a></h3> + </div> + <div class="box-body"> + <table class="table table-bordered table-striped"> + <thead> + <tr> + + <th class="text-center">From</th> + <th class="text-center">To</th> + <th class="text-center">Price</th> + <th class="text-center">Edit</th> + </tr> + </thead> + <tbody> + {% for voucher_type_price in voucher_type.prices.all %} + <tr> + <td>{{ voucher_type_price.start_date }}</td> + <td>{{ voucher_type_price.end_date }}</td> + <td>{{ voucher_type_price.price }}</td> + <td><a title="edit price" + href="{% url 'web.views.voucher_type_price_edit' voucher_type.id voucher_type_price.id %}" + type="button" + class="btn btn-block btn-default" + >EDIT</a></td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + {% endif %} + + </div> + + </div> + </div> + + {% endblock %} + + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> + +{% endblock scripts %} \ No newline at end of file diff --git a/smash/web/templates/voucher_types/breadcrumb.html b/smash/web/templates/voucher_types/breadcrumb.html new file mode 100644 index 0000000000000000000000000000000000000000..844971e607ceace28009bea2b53bf6ccd423ba0d --- /dev/null +++ b/smash/web/templates/voucher_types/breadcrumb.html @@ -0,0 +1,2 @@ +<li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li> +<li class="active"><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li> \ No newline at end of file diff --git a/smash/web/templates/voucher_types/edit.html b/smash/web/templates/voucher_types/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..885cc4a2619cfe9b5b425a61d70c570615d6c3fe --- /dev/null +++ b/smash/web/templates/voucher_types/edit.html @@ -0,0 +1,10 @@ +{% extends "voucher_types/add_edit.html" %} + +{% block page_header %}Edit voucher type "{{ voucher_type.code }}"{% endblock page_header %} + +{% block title %}{{ block.super }} - Edit voucher type "{{ voucher_type.code }}"{% endblock %} + +{% block form-title %}Enter voucher type details{% endblock %} + +{% block save-button %}Save{% endblock %} + diff --git a/smash/web/templates/voucher_types/list.html b/smash/web/templates/voucher_types/list.html new file mode 100644 index 0000000000000000000000000000000000000000..dec5cde7cb9c8db00538232581c1ebc6d11bb42a --- /dev/null +++ b/smash/web/templates/voucher_types/list.html @@ -0,0 +1,69 @@ +{% extends "_base.html" %} +{% load static %} + +{% block styles %} + {{ block.super }} + <!-- DataTables --> + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> +{% endblock styles %} + +{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %} +{% block page_header %}Voucher types{% endblock page_header %} +{% block page_description %}{% endblock page_description %} + +{% block breadcrumb %} + {% include "voucher_types/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + <div> + <a class="btn btn-app" href="{% url 'web.views.voucher_type_add' %}"> + <i class="fa fa-plus"></i> Add new voucher type + </a> + </div> + + <div class="box-body"> + <table id="table" class="table table-bordered table-striped"> + <thead> + <tr> + <th>Id</th> + <th>Code</th> + <th>Description</th> + <th>Edit</th> + </tr> + </thead> + <tbody> + {% for voucher_type in voucher_types %} + <tr> + <td>{{ voucher_type.id }}</td> + <td>{{ voucher_type.code }}</td> + <td>{{ voucher_type.description }}</td> + <td><a href="{% url 'web.views.voucher_type_edit' voucher_type.id %}"><i + class="fa fa-edit"></i></a></td> + </tr> + {% endfor %} + </tbody> + </table> + </div> +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> + <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> + + <script> + $(function () { + $('#table').DataTable({ + "paging": true, + "lengthChange": false, + "searching": true, + "ordering": true, + "info": true, + "autoWidth": false + }); + }); + </script> +{% endblock scripts %} diff --git a/smash/web/urls.py b/smash/web/urls.py index 1e97079064f8895f1a7b55dc7651153fe2ba7b72..c2bc3d3bd480fecf6f3977d6c3ed209af04cdb34 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -146,7 +146,6 @@ urlpatterns = [ # DAILY PLANNING # #################### - url(r'^daily_planning$', login_required(TemplateView.as_view(template_name='daily_planning.html')), name='web.views.daily_planning'), @@ -161,6 +160,24 @@ urlpatterns = [ url(r'^languages/(?P<pk>\d+)/edit$', views.language.LanguageEditView.as_view(), name='web.views.language_edit'), + #################### + # VOUCHER TYPES # + #################### + + url(r'^voucher_types$', views.voucher_type.VoucherTypeListView.as_view(), name='web.views.voucher_types'), + url(r'^voucher_types/add$', views.voucher_type.VoucherTypeCreateView.as_view(), name='web.views.voucher_type_add'), + url(r'^voucher_types/(?P<pk>\d+)/edit$', views.voucher_type.VoucherTypeEditView.as_view(), + name='web.views.voucher_type_edit'), + + ####################### + # VOUCHER TYPE PRICES # + ####################### + + url(r'^voucher_types/(?P<voucher_type_id>\d+)/prices/add$', + views.voucher_type_price.VoucherTypePriceCreateView.as_view(), name='web.views.voucher_type_price_add'), + url(r'^voucher_types/(?P<voucher_type_id>\d+)/prices/(?P<pk>\d+)/edit$', + views.voucher_type_price.VoucherTypePriceEditView.as_view(), name='web.views.voucher_type_price_edit'), + #################### # STATISTICS # #################### diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py index 0afadd68d657756ed9faba57c7e8d3925aa8dfea..01bdb13fac46bb895c6e33ebc0b9a78f9089461d 100644 --- a/smash/web/views/__init__.py +++ b/smash/web/views/__init__.py @@ -72,4 +72,6 @@ import export import contact_attempt import configuration_item import language +import voucher_type +import voucher_type_price import redcap diff --git a/smash/web/views/voucher_type.py b/smash/web/views/voucher_type.py new file mode 100644 index 0000000000000000000000000000000000000000..87b13059fb6b2812c22f8aab0e6a0d9e3bb06c29 --- /dev/null +++ b/smash/web/views/voucher_type.py @@ -0,0 +1,39 @@ +# coding=utf-8 +from django.urls import reverse_lazy +from django.views.generic import CreateView +from django.views.generic import ListView +from django.views.generic import UpdateView + +from web.forms.forms import VoucherTypeForm +from web.models import VoucherType +from web.models.constants import GLOBAL_STUDY_ID +from . import WrappedView + + +class VoucherTypeListView(ListView, WrappedView): + model = VoucherType + context_object_name = "voucher_types" + template_name = 'voucher_types/list.html' + + +class VoucherTypeCreateView(CreateView, WrappedView): + form_class = VoucherTypeForm + model = VoucherType + + template_name = "voucher_types/add.html" + success_url = reverse_lazy('web.views.voucher_types') + success_message = "Voucher type created" + + def form_valid(self, form): + form.instance.study_id = GLOBAL_STUDY_ID + return super(VoucherTypeCreateView, self).form_valid(form) + + +class VoucherTypeEditView(UpdateView, WrappedView): + form_class = VoucherTypeForm + model = VoucherType + + success_url = reverse_lazy('web.views.voucher_types') + success_message = "Voucher type edited" + template_name = "voucher_types/edit.html" + context_object_name = "voucher_type" diff --git a/smash/web/views/voucher_type_price.py b/smash/web/views/voucher_type_price.py new file mode 100644 index 0000000000000000000000000000000000000000..f93a045f3d188adc78d2994d5e5e6d135a77f8fc --- /dev/null +++ b/smash/web/views/voucher_type_price.py @@ -0,0 +1,42 @@ +# coding=utf-8 +import logging + +from django.urls import reverse_lazy +from django.views.generic import CreateView +from django.views.generic import UpdateView + +from web.forms.forms import VoucherTypePriceForm +from web.models import VoucherTypePrice +from . import WrappedView + +logger = logging.getLogger(__name__) + + +class VoucherTypePriceCreateView(CreateView, WrappedView): + form_class = VoucherTypePriceForm + model = VoucherTypePrice + + template_name = "voucher_type_prices/add.html" + success_message = "Voucher type created" + + def form_valid(self, form): + # noinspection PyUnresolvedReferences + form.instance.voucher_type_id = self.kwargs['voucher_type_id'] + return super(VoucherTypePriceCreateView, self).form_valid(form) + + def get_success_url(self, **kwargs): + # noinspection PyUnresolvedReferences + return reverse_lazy('web.views.voucher_type_edit', kwargs={'pk': self.kwargs['voucher_type_id']}) + + +class VoucherTypePriceEditView(UpdateView, WrappedView): + form_class = VoucherTypePriceForm + model = VoucherTypePrice + + success_message = "Voucher type edited" + template_name = "voucher_type_prices/edit.html" + context_object_name = "voucher_type" + + def get_success_url(self, **kwargs): + # noinspection PyUnresolvedReferences + return reverse_lazy('web.views.voucher_type_edit', kwargs={'pk': self.kwargs['voucher_type_id']})