diff --git a/smash/web/forms.py b/smash/web/forms.py index 5df96b139a5ce82909d37a17021ccff7dca13724..663f68869f6d81e87e02507d16b2f308474919bf 100644 --- a/smash/web/forms.py +++ b/smash/web/forms.py @@ -1,5 +1,5 @@ from django import forms -from django.forms import ModelForm +from django.forms import ModelForm, Form from .models import * from datetime import datetime @@ -156,3 +156,14 @@ class VisitAddForm(ModelForm): if (self.cleaned_data['datetime_begin']>=self.cleaned_data['datetime_end']): self.add_error('datetime_begin', "Start date must be before end date") self.add_error('datetime_end', "Start date must be before end date") + +class KitRequestForm(Form): + start_date = forms.DateField(label="From date", + widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d"), + required=False + ) + + end_date = forms.DateField(label="End date", + widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d"), + required=False + ) diff --git a/smash/web/models.py b/smash/web/models.py index 170690befbed6227eebfec5f2b8a61208187b113..3567021a5adba3c071f3361dc9c76aa3da27c4aa 100644 --- a/smash/web/models.py +++ b/smash/web/models.py @@ -214,6 +214,12 @@ class Item (models.Model): default=False, verbose_name='Is the item fixed?' ) + + disposable = models.BooleanField( + default=False, + verbose_name='Disposable set' + ) + name = models.CharField(max_length=255, verbose_name='Name' ) diff --git a/smash/web/templates/equipment_and_rooms/index.html b/smash/web/templates/equipment_and_rooms/index.html index 6c7a5f4fb99b8217171a0f4d0739cd09df2405e6..95d68215f8a6193d98efb7ef6bf61095c662c7fb 100644 --- a/smash/web/templates/equipment_and_rooms/index.html +++ b/smash/web/templates/equipment_and_rooms/index.html @@ -10,6 +10,7 @@ {% endblock breadcrumb %} {% block maincontent %} +{% comment %} <div class="box box-danger box-solid"> <div class="box-header with-border"> <h3 class="box-title">Not yet implemented</h3> @@ -27,8 +28,12 @@ <!-- /.box-body --> </div> +{% endcomment %} + <div class="row"> + {% comment %} <div class="col-md-3"> + <div class="bg-red-active small-box"> <div class="inner"> <h4>Types of equipment</h4> @@ -71,22 +76,24 @@ </a> </div> </div> + {% endcomment %} <div class="col-md-3"> <div class="bg-yellow-active small-box"> <div class="inner"> - <h4>Equipment requests</h4> + <h4>Kit requests</h4> <p> </p> </div> <div class="icon"> <i class="ion ion-compose"></i> </div> - <a href="#" class="small-box-footer"> - Edit <i class="fa fa-arrow-circle-right"></i> + <a href="{% url 'web.views.kit_requests' %}" class="small-box-footer"> + See <i class="fa fa-arrow-circle-right"></i> </a> </div> + {% comment %} <div class="bg-yellow small-box"> <div class="inner"> <h4>Equipment in rooms</h4> @@ -100,8 +107,10 @@ Edit <i class="fa fa-arrow-circle-right"></i> </a> </div> + {% endcomment %} </div> + {% comment %} <div class="col-md-3"> <div class="bg-green-active small-box"> <div class="inner"> @@ -145,5 +154,7 @@ </a> </div> </div> + {% endcomment %} + </div> {% endblock maincontent %} diff --git a/smash/web/templates/equipment_and_rooms/kit_requests.html b/smash/web/templates/equipment_and_rooms/kit_requests.html new file mode 100644 index 0000000000000000000000000000000000000000..b9881bd23f51782703c9782bd84cf63f094082e3 --- /dev/null +++ b/smash/web/templates/equipment_and_rooms/kit_requests.html @@ -0,0 +1,103 @@ +{% extends "_base.html" %} + +{% block ui_active_tab %}'equipment_and_rooms'{% endblock ui_active_tab %} +{% block page_header %} + Kits required between {{ start_date | date:"Y-m-d" }} and {% if end_date %} {{ end_date | date:"Y-m-d" }} {% else %} end of time {% endif %} +{% endblock page_header %} +{% block page_description %} +{% endblock page_description %} + +{% block styles %} +{{ block.super }} + {% include "includes/datepicker.css.html" %} +{% endblock styles %} + +{% block breadcrumb %} +{% include "equipment_and_rooms/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + +{% block content %} +<div class="box box-info"> + <form method="post" action="" class="form-horizontal"> + {% csrf_token %} + + <div class="box-body"> + <div class="col-sm-6"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %}"> + <label class="col-sm-4 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8"> + {{ field }} + </div> + + {% if field.errors %} + <span class="help-block"> + {{ field.errors }} + </span> + {% endif %} + </div> + {% endfor %} + </div> + </div> + + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">Search</button> + </div> + </div><!-- /.box-footer --> + + </form> + + <div class="box col-md-12"> + <table id="visit_table" class="table table-bordered table-striped"> + <thead> + <tr> + <th>Date</th> + <th>Kits</th> + </tr> + </thead> + <tbody> + {% for appointment in appointments %} + <tr> + <td>{{ appointment.datetime_when | date:"Y-m-d H:i"}} </td> + <td> + {% for type in appointment.appointment_types.all %} + {% for item in type.required_equipment.all %} + {% if item.disposable %} + {{ item.name }}, + {% endif %} + {% endfor %} + {% endfor %} + </td> + </tr> + {% endfor %} + </tbody> + </table> + + <div class="box-footer"> + <div class="col-sm-12"> + {% if end_date == None %} + <a href="{% url 'web.views.kit_requests_send_mail' start_date|date:"Y-m-d" %}" class="btn btn-block btn-default">Show email content</a> + {% else %} + <a href="{% url 'web.views.kit_requests_send_mail' start_date|date:"Y-m-d" end_date|date:"Y-m-d" %}" class="btn btn-block btn-default">Show email content</a> + {% endif %} + </div> + </div><!-- /.box-footer --> + + </div> + + +</div> +{% endblock %} +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + {% include "includes/datepicker.js.html" %} +{% endblock scripts %} diff --git a/smash/web/templates/equipment_and_rooms/kit_requests_send_mail.html b/smash/web/templates/equipment_and_rooms/kit_requests_send_mail.html new file mode 100644 index 0000000000000000000000000000000000000000..1c89a616bcb4c2e997d28b80d126e91908109cec --- /dev/null +++ b/smash/web/templates/equipment_and_rooms/kit_requests_send_mail.html @@ -0,0 +1,26 @@ +<h1>Kits required between {{ start_date }} and {% if end_date %} {{ end_date }} {% else %} end of time {% endif %}</h1> +<table> + <thead> + <tr> + <th>Date</th> + <th>Kits</th> + </tr> + </thead> + <tbody> + + {% for appointment in appointments %} + <tr> + <td>{{ appointment.datetime_when | date:"Y-m-d H:i"}} </td> + <td> + {% for type in appointment.appointment_types.all %} + {% for item in type.required_equipment.all %} + {% if item.disposable %} + {{ item.name }}, + {% endif %} + {% endfor %} + {% endfor %} + </td> + </tr> + {% endfor %} + </tbody> +</table> diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index c8c748908ff4ba8ee947fa06dfcc513efdf5457e..520601b637e923bc3825a17787eccd68caf1a6c7 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -40,13 +40,17 @@ def create_worker(): email='jacob@bla', ) -def create_visit(subject): +def create_visit(subject = None): + if subject == None: + subject= create_subject() return Visit.objects.create(datetime_begin=get_today_midnight_date()+datetime.timedelta(days=-31), datetime_end=get_today_midnight_date()+datetime.timedelta(days=31), subject =subject, is_finished = False) -def create_appointment(visit): +def create_appointment(visit= None): + if visit == None: + visit = create_visit() return Appointment.objects.create( visit = visit, length = 30, diff --git a/smash/web/tests/test_view_kit_request.py b/smash/web/tests/test_view_kit_request.py new file mode 100644 index 0000000000000000000000000000000000000000..6b32ea7e142954bb750a77cf80c40af4fcc39042 --- /dev/null +++ b/smash/web/tests/test_view_kit_request.py @@ -0,0 +1,76 @@ +from django.test import TestCase, RequestFactory +from django.urls import reverse + +from web.views import * + +from web.tests.functions import * + +class ViewFunctionsTests(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user = create_user() + + def test_kit_requests(self): + request = self.factory.get(reverse('web.views.kit_requests')); + request.user = self.user + response = kit_requests(request); + self.assertEqual(response.status_code, 200) + + def test_kit_requests_2(self): + item_name = "Test item to be ordered" + item = Item.objects.create(disposable=True, name=item_name) + appointment_type = create_appointment_type() + appointment_type.required_equipment.add(item) + appointment_type.save() + + appointment = create_appointment() + appointment.datetime_when = get_today_midnight_date() + datetime.timedelta(days=2) + appointment.appointment_types.add(appointment_type) + appointment.save() + + request = self.factory.get(reverse('web.views.kit_requests')); + request.user = self.user + response = kit_requests(request); + self.assertEqual(response.status_code, 200) + + self.assertTrue(item_name in response.content) + + def test_kit_requests_4(self): + item_name = "Test item to be ordered" + item = Item.objects.create(disposable=True, name=item_name) + appointment_type = create_appointment_type() + appointment_type.required_equipment.add(item) + appointment_type.save() + + appointment = create_appointment() + appointment.datetime_when = get_today_midnight_date() + datetime.timedelta(days=2) + appointment.appointment_types.add(appointment_type) + appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED + appointment.save() + + request = self.factory.get(reverse('web.views.kit_requests')); + request.user = self.user + response = kit_requests(request); + self.assertEqual(response.status_code, 200) + + self.assertFalse(item_name in response.content) + + def test_kit_requests_3(self): + item_name = "Test item to be ordered" + item = Item.objects.create(disposable=True, name=item_name) + appointment_type = create_appointment_type() + appointment_type.required_equipment.add(item) + appointment_type.save() + + appointment = create_appointment() + appointment.datetime_when = get_today_midnight_date() + datetime.timedelta(days=2) + appointment.appointment_types.add(appointment_type) + appointment.location = create_location("other_loc") + appointment.save() + + request = self.factory.get(reverse('web.views.kit_requests')); + request.user = self.user + response = kit_requests(request); + self.assertEqual(response.status_code, 200) + + self.assertFalse(not item_name in response.content) diff --git a/smash/web/urls.py b/smash/web/urls.py index 2129f7b67af2873d70618d465c2a5329f09902e8..6712d2a4c1420c5ff8a9376b3af970c1653209fa 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -56,6 +56,10 @@ urlpatterns = [ url(r'^equipment_and_rooms$', views.equipment_and_rooms, name='web.views.equipment_and_rooms'), url(r'^equipment_and_rooms/eqdef$', views.equipment_def, name='web.views.equipment_def'), + url(r'^equipment_and_rooms/kit_requests$', views.kit_requests, name='web.views.kit_requests'), + url(r'^equipment_and_rooms/kit_requests/(?P<start_date>[\w-]+)/$', views.kit_requests_send_mail, name='web.views.kit_requests_send_mail'), + url(r'^equipment_and_rooms/kit_requests/(?P<start_date>[\w-]+)/(?P<end_date>[\w-]+)/$', views.kit_requests_send_mail, name='web.views.kit_requests_send_mail'), + url(r'^mail_templates$', views.mail_templates, name='web.views.mail_templates'), diff --git a/smash/web/views.py b/smash/web/views.py index 0466b85a2d91d14c6653619c31a6280eca8a4197..f86045232d1fe15512965d84493e010f7308d156 100644 --- a/smash/web/views.py +++ b/smash/web/views.py @@ -15,6 +15,7 @@ import datetime from django.db.models import Count from django.db.models import Case from django.db.models import When +from django.utils.dateparse import parse_datetime import csv @@ -76,12 +77,15 @@ class NotificationCount(object): def get_filter_locations(user): worker = None + if isinstance(user, User): workers = Worker.objects.filter(user=user) if len(workers)>0: worker = workers[0] - else: + elif isinstance(user, Worker): worker = user + elif user!=None: + raise TypeError("Unknown class type: "+user.__class__.__name__) if worker==None or worker.locations.count() == 0: return Location.objects.all() @@ -699,3 +703,55 @@ def write_appointments_to_csv(writer): def export(request): return wrap_response(request, 'export/index.html',{}) + +def get_kit_requests(user, start_date = None, end_date = None): + if start_date == None: + start_date = get_today_midnight_date() + datetime.timedelta(days=1) + end_date = start_date + datetime.timedelta(days=7) + else : + if isinstance(start_date, str): + start_date = parse_datetime(start_date) + if (end_date != None) and (isinstance(end_date, str)): + end_date = parse_datetime(end_date) + + appointment_types = AppointmentType.objects.filter(required_equipment__disposable=True) + + appointments = Appointment.objects.filter( + appointment_types__in = appointment_types, + datetime_when__gt = start_date, + location__in = get_filter_locations(user), + status = Appointment.APPOINTMENT_STATUS_SCHEDULED, + ) + if end_date!=None: + appointments = appointments.filter(datetime_when__lt = end_date) + + result = { + 'start_date' : start_date, + 'end_date' : end_date, + 'appointments' : appointments, + } + return result + +def get_kit_requests_data(request, start_date = None, end_date = None): + form = KitRequestForm() + if request.method=='POST': + form = KitRequestForm(request.POST) + if form.is_valid(): + form_data = form.cleaned_data + start_date = form_data.get('start_date') + end_date = form_data.get('end_date') + + params = get_kit_requests(request.user, start_date, end_date) + params.update({ + 'form': form + }) + print "\n\n\n\n" + print params['start_date'] + print "\n\n\n\n" + return params + +def kit_requests(request): + return wrap_response(request, 'equipment_and_rooms/kit_requests.html', get_kit_requests_data(request)) + +def kit_requests_send_mail(request, start_date, end_date = None): + return wrap_response(request, 'equipment_and_rooms/kit_requests_send_mail.html', get_kit_requests_data(request, start_date, end_date))